From 26a272b676ed711ab60e3c2540eea24014967e30 Mon Sep 17 00:00:00 2001 From: Omer Abuddi Date: Thu, 10 Aug 2023 11:32:05 +0300 Subject: [PATCH 1/6] Upgrade to sqlalchemy 1.4.0 --- jwthenticator/keys.py | 20 ++--- jwthenticator/tokens.py | 15 ++-- jwthenticator/utils.py | 18 +++- poetry.lock | 186 +++++++++++++++++++++++++++------------- pyproject.toml | 5 +- 5 files changed, 161 insertions(+), 83 deletions(-) diff --git a/jwthenticator/keys.py b/jwthenticator/keys.py index 6ae11b3..bd5be7e 100644 --- a/jwthenticator/keys.py +++ b/jwthenticator/keys.py @@ -5,8 +5,7 @@ from hashlib import sha512 from uuid import UUID -from asyncalchemy import create_session_factory - +from jwthenticator.utils import create_async_session_factory from jwthenticator.schemas import KeyData from jwthenticator.models import Base, KeyInfo from jwthenticator.exceptions import InvalidKeyError @@ -19,7 +18,7 @@ class KeyManager: """ def __init__(self) -> None: - self.session_factory = create_session_factory(DB_URI, Base) + self.async_session_factory = create_async_session_factory(DB_URI, Base) self.key_schema = KeyData.Schema() @@ -43,8 +42,9 @@ async def create_key(self, key: str, identifier: UUID, expires_at: Optional[date key_hash=key_hash, identifier=identifier ) - async with self.session_factory() as session: - await session.add(key_obj) + async with self.async_session_factory() as session: + async with session.begin(): + await session.add(key_obj) return True @@ -52,10 +52,8 @@ async def check_key_exists(self, key_hash: str) -> bool: """ Check if a key exists in DB. """ - async with self.session_factory() as session: - if await session.query(KeyInfo).filter_by(key_hash=key_hash).count() == 1: - return True - return False + async with self.async_session_factory() as session: + return await session.query(KeyInfo).filter_by(key_hash=key_hash).count() == 1 async def update_key_expiry(self, key_hash: str, expires_at: datetime) -> bool: @@ -64,7 +62,7 @@ async def update_key_expiry(self, key_hash: str, expires_at: datetime) -> bool: """ if not await self.check_key_exists(key_hash): raise InvalidKeyError("Invalid key") - async with self.session_factory() as session: + async with self.async_session_factory() as session: key_info_obj = await session.query(KeyInfo).filter_by(key_hash=key_hash).first() key_info_obj.expires_at = expires_at return True @@ -76,7 +74,7 @@ async def get_key(self, key_hash: str) -> KeyData: """ if not await self.check_key_exists(key_hash): raise InvalidKeyError("Invalid key") - async with self.session_factory() as session: + async with self.async_session_factory() as session: key_info_obj = await session.query(KeyInfo).filter_by(key_hash=key_hash).first() key_data_obj = self.key_schema.load((self.key_schema.dump(key_info_obj))) return key_data_obj diff --git a/jwthenticator/tokens.py b/jwthenticator/tokens.py index e108145..77f0adf 100644 --- a/jwthenticator/tokens.py +++ b/jwthenticator/tokens.py @@ -6,8 +6,8 @@ from uuid import UUID, uuid4 import jwt -from asyncalchemy import create_session_factory +from jwthenticator.utils import create_async_session_factory from jwthenticator.models import Base, RefreshTokenInfo from jwthenticator.schemas import JWTPayloadData, RefreshTokenData from jwthenticator.exceptions import InvalidTokenError, MissingJWTError @@ -39,8 +39,7 @@ def __init__(self, public_key: str, private_key: Optional[str] = None, algorithm self.refresh_token_schema = RefreshTokenData.Schema() self.jwt_payload_data_schema = JWTPayloadData.Schema() - self.session_factory = create_session_factory(DB_URI, Base) - + self.async_session_factory = create_async_session_factory(DB_URI, Base) async def create_access_token(self, identifier: UUID) -> str: """ @@ -87,7 +86,7 @@ async def create_refresh_token(self, key_id: int, expires_at: Optional[datetime] raise Exception("Refresh token can't be created in the past") refresh_token_str = sha512(uuid4().bytes).hexdigest() - async with self.session_factory() as session: + async with self.async_session_factory() as session: refresh_token_info_obj = RefreshTokenInfo( expires_at=expires_at, token=refresh_token_str, @@ -102,10 +101,8 @@ async def check_refresh_token_exists(self, refresh_token: str) -> bool: """ Check if a refresh token exists in DB. """ - async with self.session_factory() as session: - if await session.query(RefreshTokenInfo).filter_by(token=refresh_token).count() == 1: - return True - return False + async with self.async_session_factory() as session: + return await session.query(RefreshTokenInfo).filter_by(token=refresh_token).count() == 1 async def load_refresh_token(self, refresh_token: str) -> RefreshTokenData: @@ -114,7 +111,7 @@ async def load_refresh_token(self, refresh_token: str) -> RefreshTokenData: """ if not await self.check_refresh_token_exists(refresh_token): raise InvalidTokenError("Invalid refresh token") - async with self.session_factory() as session: + async with self.async_session_factory() as session: refresh_token_info_obj = await session.query(RefreshTokenInfo).filter_by(token=refresh_token).first() refresh_token_data_obj = self.refresh_token_schema.load(self.refresh_token_schema.dump(refresh_token_info_obj)) return refresh_token_data_obj diff --git a/jwthenticator/utils.py b/jwthenticator/utils.py index d18936c..1b40525 100644 --- a/jwthenticator/utils.py +++ b/jwthenticator/utils.py @@ -1,12 +1,15 @@ from __future__ import absolute_import from os.path import isfile -from typing import Tuple, Optional +from typing import Any, Dict, Tuple, Optional from urllib.parse import urlparse from jwt.utils import base64url_encode from Cryptodome.PublicKey import RSA from Cryptodome.Hash import SHA1 +from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.declarative import DeclarativeMeta +from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from jwthenticator.consts import RSA_KEY_STRENGTH, RSA_PUBLIC_KEY, RSA_PRIVATE_KEY, RSA_PUBLIC_KEY_PATH, RSA_PRIVATE_KEY_PATH @@ -96,3 +99,16 @@ def fix_url_path(url: str) -> str: the path will be removed by urljoin. """ return url if url.endswith("/") else url + "/" + + +def create_async_session_factory(uri: str, base: Optional[DeclarativeMeta] = None, **engine_kwargs: Dict[Any, Any]) -> sessionmaker: + """ + :param uri: Database uniform resource identifier + :param base: Declarative SQLAlchemy class to base off table initialization + :param engine_kwargs: Arguements to pass to SQLAlchemy's engine initialization + :returns: :class:`.AsyncSession` factory + """ + engine = create_async_engine(uri, **engine_kwargs) + if base is not None: + base.metadata.create_all(engine) # Create tables + return sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) diff --git a/poetry.lock b/poetry.lock index 9a9b900..07c47ba 100644 --- a/poetry.lock +++ b/poetry.lock @@ -159,20 +159,6 @@ files = [ {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] -[[package]] -name = "asyncalchemy" -version = "1.1.4" -description = "A thin async wrapper for SQLAlchemy sessions." -optional = false -python-versions = ">=3.6,<4.0" -files = [ - {file = "asyncalchemy-1.1.4-py3-none-any.whl", hash = "sha256:4d56fa01b8a351d74b7074188783e2fd06f3457e14c0d30655fb39060d758c1c"}, - {file = "asyncalchemy-1.1.4.tar.gz", hash = "sha256:b1e6a8493954e5bbf7a4e6cc603975e13b87424b412c57d00641be52dbec8236"}, -] - -[package.dependencies] -sqlalchemy = ">=1.2.0,<1.4.0" - [[package]] name = "atomicwrites" version = "1.4.1" @@ -494,6 +480,79 @@ dev = ["flake8", "pep8-naming", "tox (>=3.0)", "twine", "wheel"] docs = ["sphinx (>=1.7)", "sphinx-rtd-theme"] test = ["mock (>=2)", "pytest (>=3.4,!=3.10.0)", "pytest-cov", "pytest-mock (>=1.8)"] +[[package]] +name = "greenlet" +version = "2.0.2" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +files = [ + {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, + {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, + {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, + {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, + {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, + {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, + {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, + {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, + {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, + {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, + {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, + {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, + {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, + {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, + {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, + {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, + {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, + {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, + {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, + {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, + {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, + {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, +] + +[package.extras] +docs = ["Sphinx", "docutils (<0.18)"] +test = ["objgraph", "psutil"] + [[package]] name = "idna" version = "3.4" @@ -841,13 +900,13 @@ pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "pg8000" -version = "1.16.5" +version = "1.16.6" description = "PostgreSQL interface library" optional = false python-versions = ">=3.5" files = [ - {file = "pg8000-1.16.5-py3-none-any.whl", hash = "sha256:3d646b11227d94a3130a765a981dc6323bc959a3cd6ed54421d174b2ef256087"}, - {file = "pg8000-1.16.5.tar.gz", hash = "sha256:8af70cdfcc1fadafa32468a6af563e1c0b5271c4dcc99a4490030a128cb295a3"}, + {file = "pg8000-1.16.6-py3-none-any.whl", hash = "sha256:66fa16a402f38f8ba664206b4ba4040f24ea9641c4205b2b96a1ff3a613de3be"}, + {file = "pg8000-1.16.6.tar.gz", hash = "sha256:8fc1e6a62ccb7c9830f1e7e9288e2d20eaf373cc8875b5c55b7d5d9b7717be91"}, ] [package.dependencies] @@ -1111,56 +1170,65 @@ files = [ ] [[package]] -name = "SQLAlchemy" -version = "1.3.24" +name = "sqlalchemy" +version = "1.4.0" description = "Database Abstraction Library" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "SQLAlchemy-1.3.24-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e"}, - {file = "SQLAlchemy-1.3.24-cp27-cp27m-win32.whl", hash = "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79"}, - {file = "SQLAlchemy-1.3.24-cp27-cp27m-win_amd64.whl", hash = "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-win32.whl", hash = "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-win_amd64.whl", hash = "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-win32.whl", hash = "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-win_amd64.whl", hash = "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-win32.whl", hash = "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-win_amd64.whl", hash = "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-win32.whl", hash = "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-win_amd64.whl", hash = "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-win32.whl", hash = "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-win_amd64.whl", hash = "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b"}, - {file = "SQLAlchemy-1.3.24.tar.gz", hash = "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519"}, + {file = "SQLAlchemy-1.4.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:364b3d46be78eeaa0efc8771d86bd4e66e0e24bc998610ae9b07ab0630a2e0f2"}, + {file = "SQLAlchemy-1.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:e7902051dc747cc96b552230464ddb2c96407e7f07680c71c1923dca2f3a6d9d"}, + {file = "SQLAlchemy-1.4.0-cp27-cp27m-win32.whl", hash = "sha256:38a50d4d657bd7aa5a8ddeb06eb4f099c29f9ca7b50295ea0f98793007d448b5"}, + {file = "SQLAlchemy-1.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:9613ae722a818d231b47fe03c7ff60ce2cd9a54c7a3fb927db9e5df6683c438a"}, + {file = "SQLAlchemy-1.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5f326c4264d2f1614f471b6f04e96522f7cc94843172e099bf2fb22079891c20"}, + {file = "SQLAlchemy-1.4.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:6a144c87df1eeeb604e20deb074b9252e7f63b5f528a61b7d9d509c2e67adfb0"}, + {file = "SQLAlchemy-1.4.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:56d33a788c427f29a54600374bb3e435331238e7551c1ce738da5186c20f6c68"}, + {file = "SQLAlchemy-1.4.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7fdec39fe2495a1c833b917d7c0c8b9d06c0b1b91df74e45be7dc7af325a40fa"}, + {file = "SQLAlchemy-1.4.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:5beadd632440aa67f3cb3ec235246c3753f8b3d72b254ee5a87c1e87619952f4"}, + {file = "SQLAlchemy-1.4.0-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:bd73da5de31118a8130540297779d36bf4d7414c6cca8d7f769b1550dafce78d"}, + {file = "SQLAlchemy-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:a595fe93ef2722c4877e1db80aabbe172b0af7846c61b2852388780a53203855"}, + {file = "SQLAlchemy-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:90a8529f04f25051357fc149bc7815b515d018598ff6f1f91038dad665a7ac61"}, + {file = "SQLAlchemy-1.4.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:ce33a952476f9100daa76fb8228fdc99ac11df3c316be2eb946ba31fbe845ba6"}, + {file = "SQLAlchemy-1.4.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bc626e44fec23d9ea92aeecd2359720e8620c1f963c8e24bfdd27e757ed0548c"}, + {file = "SQLAlchemy-1.4.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0b77e40d63147cd322307a10905f2690661acaa6f21eb1168a6e6de144c97a12"}, + {file = "SQLAlchemy-1.4.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:1373b38a8bba90b54f21ff6b8ec7561d7e4fcc44a1fd70a845ece1014b554f9b"}, + {file = "SQLAlchemy-1.4.0-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:506ff11bc52426bedb66618d10ec1e41c64667ee685fbffb6a3057e5d9513129"}, + {file = "SQLAlchemy-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:e04efa8dd75b9bfc16a6bc174e715678c6e99f52c633eccef76e156e408a5432"}, + {file = "SQLAlchemy-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:befa0b60b663fdbc1bb1bde60d3788ff5a64700f253f7981a22081f3b44239f2"}, + {file = "SQLAlchemy-1.4.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:c272f0340a40d178461b2b54f27360289e063f70db495daa852c2f318fc00640"}, + {file = "SQLAlchemy-1.4.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8319413aaf11e777ed328a763038c85faf4ff4461a14c09f8c2bf5e46954ea8b"}, + {file = "SQLAlchemy-1.4.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ddb17736fc2999dc4e550f02e05add7a2197668cde059269b23989d8730ef71a"}, + {file = "SQLAlchemy-1.4.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:682961ff4e9fcd9803ab3918c7f8c44ab4076566a0385606377723caf18c371a"}, + {file = "SQLAlchemy-1.4.0-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:b8bdfb73d07467f2e21e7ff3abc823d52f88b1e5c377fc14da625b30469350ab"}, + {file = "SQLAlchemy-1.4.0-cp38-cp38-win32.whl", hash = "sha256:a75ac5cdac68c10b71f00aff2f4179168abcf462e73d0289d806293b44abfce6"}, + {file = "SQLAlchemy-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c101e9f57d8a67a4b613852d4a5ee850cd2e8b4791ddba2a90ced4dbc66e5fa2"}, + {file = "SQLAlchemy-1.4.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:dd940003b5724e7376dd627b13086798076c5bc124d562163224334854bdd0ca"}, + {file = "SQLAlchemy-1.4.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:faad6bcbc1af9dfb2b2e02be988f992989d99e3eae0c5b21fce818d47aab5181"}, + {file = "SQLAlchemy-1.4.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:02a77eef48da7a5239c003a18afa05c964f1e3001cb2039f69b912b0e0d69c61"}, + {file = "SQLAlchemy-1.4.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:441788cdc1617fe3e43565399c95098d54e91422a049df08acb3709854e7cec0"}, + {file = "SQLAlchemy-1.4.0-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:308968eb85969ca3025452cebff7e3d9af5f5c0771b6e19df3c68b1a3c6918ae"}, + {file = "SQLAlchemy-1.4.0-cp39-cp39-win32.whl", hash = "sha256:1293cbcaf556f3de5a3eb143012e830a7d78952796f5ba9d2a8286d808e158f1"}, + {file = "SQLAlchemy-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6fd3bfc212f68913fe42e9a7b5a39fb259e40e927fe5e813f27c6a692bd624e7"}, + {file = "SQLAlchemy-1.4.0.tar.gz", hash = "sha256:9cfef2ad30c5ee1d494d98f3c55a9ac29ec6d294b70849c541d139e4fe1a74e6"}, ] +[package.dependencies] +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\""} + [package.extras] +aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] +asyncio = ["greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] -mysql = ["mysqlclient"] -oracle = ["cx-oracle"] -postgresql = ["psycopg2"] -postgresql-pg8000 = ["pg8000 (<1.16.6)"] +mypy = ["mypy (>=0.800)", "sqlalchemy2-stubs"] +mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] +mysql-connector = ["mysqlconnector"] +oracle = ["cx-oracle (>=7)", "cx-oracle (>=7,<8)"] +postgresql = ["psycopg2 (>=2.7)"] +postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6)"] postgresql-psycopg2binary = ["psycopg2-binary"] postgresql-psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql", "pymysql (<1)"] @@ -1440,4 +1508,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "017d1597746e97874ed6bafb2730c679bc585aa126e0fd364f1bedbb14cbfcc1" +content-hash = "95d9a31dad4393562a102e9d06970782d3c4473f7bf8595417d3291c8a708d23" diff --git a/pyproject.toml b/pyproject.toml index 164d01a..d379246 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,10 +12,9 @@ exclude = ["jwthenticator/tests"] [tool.poetry.dependencies] python = "^3.9" -sqlalchemy = ">= 1.2.19, < 1.4.0" -asyncalchemy = "^1.1.1" +sqlalchemy = "1.4.0" sqlalchemy-utils = ">=0.33.0, < 1.0.0" -pg8000 = "1.16.5" # Constant due to - https://github.com/tlocke/pg8000/issues/53 +pg8000 = "1.16.6" # Constant due to - https://github.com/tlocke/pg8000/issues/53 aiohttp = "^3.6.0" pyjwt = ">= 1.7, < 3.0.0" cryptography = ">=37,<42" # Required for pyjwt From 2a7409e44c6318206dc9df0c699515982c741908 Mon Sep 17 00:00:00 2001 From: Omer Abuddi Date: Thu, 10 Aug 2023 15:02:30 +0300 Subject: [PATCH 2/6] Add asyncpg as async connector --- jwthenticator/consts.py | 2 ++ jwthenticator/keys.py | 4 +-- jwthenticator/tokens.py | 4 +-- poetry.lock | 55 ++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 5 files changed, 61 insertions(+), 5 deletions(-) diff --git a/jwthenticator/consts.py b/jwthenticator/consts.py index d83312c..b5823b3 100644 --- a/jwthenticator/consts.py +++ b/jwthenticator/consts.py @@ -35,9 +35,11 @@ def days_to_seconds(days: int) -> int: # DB consts DB_CONNECTOR = env.str("DB_CONNECTOR", "postgresql+pg8000") +ASYNC_DB_CONNECTOR = env.str("ASYNC_DB_CONNECTOR", "postgresql+asyncpg") DB_USER = env.str("DB_USER", "postgres") DB_PASS = env.str("DB_PASS", "") DB_HOST = env.str("DB_HOST", "localhost") DB_NAME = env.str("DB_NAME", "jwthenticator") DB_URI = env.str("DB_URI", f"{DB_CONNECTOR}://{DB_USER}:{DB_PASS}@{DB_HOST}/{DB_NAME}") +ASYNC_DB_URI = env.str("ASYNC_URI", f"{ASYNC_DB_CONNECTOR}://{DB_USER}:{DB_PASS}@{DB_HOST}/{DB_NAME}") diff --git a/jwthenticator/keys.py b/jwthenticator/keys.py index bd5be7e..04408ce 100644 --- a/jwthenticator/keys.py +++ b/jwthenticator/keys.py @@ -9,7 +9,7 @@ from jwthenticator.schemas import KeyData from jwthenticator.models import Base, KeyInfo from jwthenticator.exceptions import InvalidKeyError -from jwthenticator.consts import KEY_EXPIRY, DB_URI +from jwthenticator.consts import KEY_EXPIRY, ASYNC_DB_URI class KeyManager: @@ -18,7 +18,7 @@ class KeyManager: """ def __init__(self) -> None: - self.async_session_factory = create_async_session_factory(DB_URI, Base) + self.async_session_factory = create_async_session_factory(ASYNC_DB_URI, Base) self.key_schema = KeyData.Schema() diff --git a/jwthenticator/tokens.py b/jwthenticator/tokens.py index 77f0adf..182bdb7 100644 --- a/jwthenticator/tokens.py +++ b/jwthenticator/tokens.py @@ -11,7 +11,7 @@ from jwthenticator.models import Base, RefreshTokenInfo from jwthenticator.schemas import JWTPayloadData, RefreshTokenData from jwthenticator.exceptions import InvalidTokenError, MissingJWTError -from jwthenticator.consts import JWT_ALGORITHM, REFRESH_TOKEN_EXPIRY, JWT_LEASE_TIME, JWT_AUDIENCE, DB_URI +from jwthenticator.consts import JWT_ALGORITHM, REFRESH_TOKEN_EXPIRY, JWT_LEASE_TIME, JWT_AUDIENCE, ASYNC_DB_URI class TokenManager: """ @@ -39,7 +39,7 @@ def __init__(self, public_key: str, private_key: Optional[str] = None, algorithm self.refresh_token_schema = RefreshTokenData.Schema() self.jwt_payload_data_schema = JWTPayloadData.Schema() - self.async_session_factory = create_async_session_factory(DB_URI, Base) + self.async_session_factory = create_async_session_factory(ASYNC_DB_URI, Base) async def create_access_token(self, identifier: UUID) -> str: """ diff --git a/poetry.lock b/poetry.lock index 07c47ba..b244bda 100644 --- a/poetry.lock +++ b/poetry.lock @@ -159,6 +159,59 @@ files = [ {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] +[[package]] +name = "asyncpg" +version = "0.28.0" +description = "An asyncio PostgreSQL driver" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "asyncpg-0.28.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a6d1b954d2b296292ddff4e0060f494bb4270d87fb3655dd23c5c6096d16d83"}, + {file = "asyncpg-0.28.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0740f836985fd2bd73dca42c50c6074d1d61376e134d7ad3ad7566c4f79f8184"}, + {file = "asyncpg-0.28.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e907cf620a819fab1737f2dd90c0f185e2a796f139ac7de6aa3212a8af96c050"}, + {file = "asyncpg-0.28.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b339984d55e8202e0c4b252e9573e26e5afa05617ed02252544f7b3e6de3e9"}, + {file = "asyncpg-0.28.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c402745185414e4c204a02daca3d22d732b37359db4d2e705172324e2d94e85"}, + {file = "asyncpg-0.28.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c88eef5e096296626e9688f00ab627231f709d0e7e3fb84bb4413dff81d996d7"}, + {file = "asyncpg-0.28.0-cp310-cp310-win32.whl", hash = "sha256:90a7bae882a9e65a9e448fdad3e090c2609bb4637d2a9c90bfdcebbfc334bf89"}, + {file = "asyncpg-0.28.0-cp310-cp310-win_amd64.whl", hash = "sha256:76aacdcd5e2e9999e83c8fbcb748208b60925cc714a578925adcb446d709016c"}, + {file = "asyncpg-0.28.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a0e08fe2c9b3618459caaef35979d45f4e4f8d4f79490c9fa3367251366af207"}, + {file = "asyncpg-0.28.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b24e521f6060ff5d35f761a623b0042c84b9c9b9fb82786aadca95a9cb4a893b"}, + {file = "asyncpg-0.28.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99417210461a41891c4ff301490a8713d1ca99b694fef05dabd7139f9d64bd6c"}, + {file = "asyncpg-0.28.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f029c5adf08c47b10bcdc857001bbef551ae51c57b3110964844a9d79ca0f267"}, + {file = "asyncpg-0.28.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ad1d6abf6c2f5152f46fff06b0e74f25800ce8ec6c80967f0bc789974de3c652"}, + {file = "asyncpg-0.28.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d7fa81ada2807bc50fea1dc741b26a4e99258825ba55913b0ddbf199a10d69d8"}, + {file = "asyncpg-0.28.0-cp311-cp311-win32.whl", hash = "sha256:f33c5685e97821533df3ada9384e7784bd1e7865d2b22f153f2e4bd4a083e102"}, + {file = "asyncpg-0.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:5e7337c98fb493079d686a4a6965e8bcb059b8e1b8ec42106322fc6c1c889bb0"}, + {file = "asyncpg-0.28.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1c56092465e718a9fdcc726cc3d9dcf3a692e4834031c9a9f871d92a75d20d48"}, + {file = "asyncpg-0.28.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4acd6830a7da0eb4426249d71353e8895b350daae2380cb26d11e0d4a01c5472"}, + {file = "asyncpg-0.28.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63861bb4a540fa033a56db3bb58b0c128c56fad5d24e6d0a8c37cb29b17c1c7d"}, + {file = "asyncpg-0.28.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a93a94ae777c70772073d0512f21c74ac82a8a49be3a1d982e3f259ab5f27307"}, + {file = "asyncpg-0.28.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d14681110e51a9bc9c065c4e7944e8139076a778e56d6f6a306a26e740ed86d2"}, + {file = "asyncpg-0.28.0-cp37-cp37m-win32.whl", hash = "sha256:8aec08e7310f9ab322925ae5c768532e1d78cfb6440f63c078b8392a38aa636a"}, + {file = "asyncpg-0.28.0-cp37-cp37m-win_amd64.whl", hash = "sha256:319f5fa1ab0432bc91fb39b3960b0d591e6b5c7844dafc92c79e3f1bff96abef"}, + {file = "asyncpg-0.28.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b337ededaabc91c26bf577bfcd19b5508d879c0ad009722be5bb0a9dd30b85a0"}, + {file = "asyncpg-0.28.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4d32b680a9b16d2957a0a3cc6b7fa39068baba8e6b728f2e0a148a67644578f4"}, + {file = "asyncpg-0.28.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f62f04cdf38441a70f279505ef3b4eadf64479b17e707c950515846a2df197"}, + {file = "asyncpg-0.28.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f20cac332c2576c79c2e8e6464791c1f1628416d1115935a34ddd7121bfc6a4"}, + {file = "asyncpg-0.28.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:59f9712ce01e146ff71d95d561fb68bd2d588a35a187116ef05028675462d5ed"}, + {file = "asyncpg-0.28.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fc9e9f9ff1aa0eddcc3247a180ac9e9b51a62311e988809ac6152e8fb8097756"}, + {file = "asyncpg-0.28.0-cp38-cp38-win32.whl", hash = "sha256:9e721dccd3838fcff66da98709ed884df1e30a95f6ba19f595a3706b4bc757e3"}, + {file = "asyncpg-0.28.0-cp38-cp38-win_amd64.whl", hash = "sha256:8ba7d06a0bea539e0487234511d4adf81dc8762249858ed2a580534e1720db00"}, + {file = "asyncpg-0.28.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d009b08602b8b18edef3a731f2ce6d3f57d8dac2a0a4140367e194eabd3de457"}, + {file = "asyncpg-0.28.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ec46a58d81446d580fb21b376ec6baecab7288ce5a578943e2fc7ab73bf7eb39"}, + {file = "asyncpg-0.28.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b48ceed606cce9e64fd5480a9b0b9a95cea2b798bb95129687abd8599c8b019"}, + {file = "asyncpg-0.28.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8858f713810f4fe67876728680f42e93b7e7d5c7b61cf2118ef9153ec16b9423"}, + {file = "asyncpg-0.28.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5e18438a0730d1c0c1715016eacda6e9a505fc5aa931b37c97d928d44941b4bf"}, + {file = "asyncpg-0.28.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e9c433f6fcdd61c21a715ee9128a3ca48be8ac16fa07be69262f016bb0f4dbd2"}, + {file = "asyncpg-0.28.0-cp39-cp39-win32.whl", hash = "sha256:41e97248d9076bc8e4849da9e33e051be7ba37cd507cbd51dfe4b2d99c70e3dc"}, + {file = "asyncpg-0.28.0-cp39-cp39-win_amd64.whl", hash = "sha256:3ed77f00c6aacfe9d79e9eff9e21729ce92a4b38e80ea99a58ed382f42ebd55b"}, + {file = "asyncpg-0.28.0.tar.gz", hash = "sha256:7252cdc3acb2f52feaa3664280d3bcd78a46bd6c10bfd681acfffefa1120e278"}, +] + +[package.extras] +docs = ["Sphinx (>=5.3.0,<5.4.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["flake8 (>=5.0,<6.0)", "uvloop (>=0.15.3)"] + [[package]] name = "atomicwrites" version = "1.4.1" @@ -1508,4 +1561,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "95d9a31dad4393562a102e9d06970782d3c4473f7bf8595417d3291c8a708d23" +content-hash = "364517608e589ad48aff63973e8d4570c855bf21fea5c4a1cca11a736dd4eee4" diff --git a/pyproject.toml b/pyproject.toml index d379246..9456269 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ marshmallow = "^3.9" marshmallow-dataclass = "^8.3" pycryptodomex = "^3.9" environs = "^9.3.1" +asyncpg = "^0.28.0" [tool.poetry.dev-dependencies] From 8c36737a633cb5403b228336dc195f611c9e569b Mon Sep 17 00:00:00 2001 From: Omer Abuddi Date: Thu, 10 Aug 2023 15:11:51 +0300 Subject: [PATCH 3/6] Change table creation to asyncio --- jwthenticator/utils.py | 15 ++++++++++++--- poetry.lock | 15 ++++++++++++++- pyproject.toml | 1 + 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/jwthenticator/utils.py b/jwthenticator/utils.py index 1b40525..883fcbc 100644 --- a/jwthenticator/utils.py +++ b/jwthenticator/utils.py @@ -1,5 +1,7 @@ from __future__ import absolute_import +import asyncio +from asyncio import events from os.path import isfile from typing import Any, Dict, Tuple, Optional from urllib.parse import urlparse @@ -9,7 +11,7 @@ from Cryptodome.Hash import SHA1 from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import DeclarativeMeta -from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession +from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, AsyncEngine from jwthenticator.consts import RSA_KEY_STRENGTH, RSA_PUBLIC_KEY, RSA_PRIVATE_KEY, RSA_PUBLIC_KEY_PATH, RSA_PRIVATE_KEY_PATH @@ -101,14 +103,21 @@ def fix_url_path(url: str) -> str: return url if url.endswith("/") else url + "/" +async def init_models(engine: AsyncEngine, base: DeclarativeMeta) -> None: + async with engine.begin() as conn: + await conn.run_sync(base.metadata.drop_all) + await conn.run_sync(base.metadata.create_all) + + def create_async_session_factory(uri: str, base: Optional[DeclarativeMeta] = None, **engine_kwargs: Dict[Any, Any]) -> sessionmaker: """ :param uri: Database uniform resource identifier :param base: Declarative SQLAlchemy class to base off table initialization - :param engine_kwargs: Arguements to pass to SQLAlchemy's engine initialization + :param engine_kwargs: Arguments to pass to SQLAlchemy's engine initialization :returns: :class:`.AsyncSession` factory """ engine = create_async_engine(uri, **engine_kwargs) if base is not None: - base.metadata.create_all(engine) # Create tables + print(events.get_running_loop()) + asyncio.run(init_models(engine=engine, base=base)) # Create tables return sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) diff --git a/poetry.lock b/poetry.lock index b244bda..42b6173 100644 --- a/poetry.lock +++ b/poetry.lock @@ -159,6 +159,19 @@ files = [ {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] +[[package]] +name = "asyncio" +version = "3.4.3" +description = "reference implementation of PEP 3156" +optional = false +python-versions = "*" +files = [ + {file = "asyncio-3.4.3-cp33-none-win32.whl", hash = "sha256:b62c9157d36187eca799c378e572c969f0da87cd5fc42ca372d92cdb06e7e1de"}, + {file = "asyncio-3.4.3-cp33-none-win_amd64.whl", hash = "sha256:c46a87b48213d7464f22d9a497b9eef8c1928b68320a2fa94240f969f6fec08c"}, + {file = "asyncio-3.4.3-py3-none-any.whl", hash = "sha256:c4d18b22701821de07bd6aea8b53d21449ec0ec5680645e5317062ea21817d2d"}, + {file = "asyncio-3.4.3.tar.gz", hash = "sha256:83360ff8bc97980e4ff25c964c7bd3923d333d177aa4f7fb736b019f26c7cb41"}, +] + [[package]] name = "asyncpg" version = "0.28.0" @@ -1561,4 +1574,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "364517608e589ad48aff63973e8d4570c855bf21fea5c4a1cca11a736dd4eee4" +content-hash = "fee8cb9cdc8414e89c8f849d1199a9c3443a8dda4d83e7fd004c2237926f512f" diff --git a/pyproject.toml b/pyproject.toml index 9456269..b5b8659 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ marshmallow-dataclass = "^8.3" pycryptodomex = "^3.9" environs = "^9.3.1" asyncpg = "^0.28.0" +asyncio = "^3.4.3" [tool.poetry.dev-dependencies] From 1be7a121d25ef4f08a672c03903e469f0a2d0116 Mon Sep 17 00:00:00 2001 From: Omer Abuddi Date: Wed, 16 Aug 2023 14:09:18 +0300 Subject: [PATCH 4/6] Fix tests and queries to work with sqlalchemy 1.4.0 async --- jwthenticator/keys.py | 11 ++++++++--- jwthenticator/tokens.py | 14 ++++++++++---- jwthenticator/utils.py | 10 ++++------ poetry.lock | 13 ++++++++++++- pyproject.toml | 1 + 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/jwthenticator/keys.py b/jwthenticator/keys.py index 04408ce..254ea65 100644 --- a/jwthenticator/keys.py +++ b/jwthenticator/keys.py @@ -5,6 +5,8 @@ from hashlib import sha512 from uuid import UUID +from sqlalchemy import select + from jwthenticator.utils import create_async_session_factory from jwthenticator.schemas import KeyData from jwthenticator.models import Base, KeyInfo @@ -44,7 +46,7 @@ async def create_key(self, key: str, identifier: UUID, expires_at: Optional[date ) async with self.async_session_factory() as session: async with session.begin(): - await session.add(key_obj) + session.add(key_obj) return True @@ -53,7 +55,9 @@ async def check_key_exists(self, key_hash: str) -> bool: Check if a key exists in DB. """ async with self.async_session_factory() as session: - return await session.query(KeyInfo).filter_by(key_hash=key_hash).count() == 1 + query = select(KeyInfo.id).where(KeyInfo.key_hash == key_hash) + result = await session.execute(query) + return len(result.all()) == 1 async def update_key_expiry(self, key_hash: str, expires_at: datetime) -> bool: @@ -75,6 +79,7 @@ async def get_key(self, key_hash: str) -> KeyData: if not await self.check_key_exists(key_hash): raise InvalidKeyError("Invalid key") async with self.async_session_factory() as session: - key_info_obj = await session.query(KeyInfo).filter_by(key_hash=key_hash).first() + query = select(KeyInfo).where(KeyInfo.key_hash == key_hash) + key_info_obj = (await session.execute(query)).scalars().first() key_data_obj = self.key_schema.load((self.key_schema.dump(key_info_obj))) return key_data_obj diff --git a/jwthenticator/tokens.py b/jwthenticator/tokens.py index 182bdb7..294c571 100644 --- a/jwthenticator/tokens.py +++ b/jwthenticator/tokens.py @@ -6,6 +6,7 @@ from uuid import UUID, uuid4 import jwt +from sqlalchemy import select from jwthenticator.utils import create_async_session_factory from jwthenticator.models import Base, RefreshTokenInfo @@ -92,7 +93,9 @@ async def create_refresh_token(self, key_id: int, expires_at: Optional[datetime] token=refresh_token_str, key_id=key_id ) - await session.add(refresh_token_info_obj) + session.add(refresh_token_info_obj) + await session.commit() + await session.refresh(refresh_token_info_obj) await session.flush() return refresh_token_str @@ -102,7 +105,9 @@ async def check_refresh_token_exists(self, refresh_token: str) -> bool: Check if a refresh token exists in DB. """ async with self.async_session_factory() as session: - return await session.query(RefreshTokenInfo).filter_by(token=refresh_token).count() == 1 + query = select(RefreshTokenInfo).where(RefreshTokenInfo.token == refresh_token) + result = (await session.execute(query)) + return len(result.all()) == 1 async def load_refresh_token(self, refresh_token: str) -> RefreshTokenData: @@ -112,6 +117,7 @@ async def load_refresh_token(self, refresh_token: str) -> RefreshTokenData: if not await self.check_refresh_token_exists(refresh_token): raise InvalidTokenError("Invalid refresh token") async with self.async_session_factory() as session: - refresh_token_info_obj = await session.query(RefreshTokenInfo).filter_by(token=refresh_token).first() - refresh_token_data_obj = self.refresh_token_schema.load(self.refresh_token_schema.dump(refresh_token_info_obj)) + query = select(RefreshTokenInfo).where(RefreshTokenInfo.token == refresh_token) + refresh_token_info_obj = (await session.execute(query)).first() + refresh_token_data_obj = self.refresh_token_schema.load(self.refresh_token_schema.dump(refresh_token_info_obj[0])) return refresh_token_data_obj diff --git a/jwthenticator/utils.py b/jwthenticator/utils.py index 883fcbc..31f9d13 100644 --- a/jwthenticator/utils.py +++ b/jwthenticator/utils.py @@ -1,7 +1,6 @@ from __future__ import absolute_import import asyncio -from asyncio import events from os.path import isfile from typing import Any, Dict, Tuple, Optional from urllib.parse import urlparse @@ -12,6 +11,7 @@ from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import DeclarativeMeta from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, AsyncEngine +from sqlalchemy.pool import NullPool from jwthenticator.consts import RSA_KEY_STRENGTH, RSA_PUBLIC_KEY, RSA_PRIVATE_KEY, RSA_PUBLIC_KEY_PATH, RSA_PRIVATE_KEY_PATH @@ -103,9 +103,8 @@ def fix_url_path(url: str) -> str: return url if url.endswith("/") else url + "/" -async def init_models(engine: AsyncEngine, base: DeclarativeMeta) -> None: +async def create_base(engine: AsyncEngine, base: DeclarativeMeta) -> None: async with engine.begin() as conn: - await conn.run_sync(base.metadata.drop_all) await conn.run_sync(base.metadata.create_all) @@ -116,8 +115,7 @@ def create_async_session_factory(uri: str, base: Optional[DeclarativeMeta] = Non :param engine_kwargs: Arguments to pass to SQLAlchemy's engine initialization :returns: :class:`.AsyncSession` factory """ - engine = create_async_engine(uri, **engine_kwargs) + engine = create_async_engine(uri, **engine_kwargs, poolclass=NullPool) if base is not None: - print(events.get_running_loop()) - asyncio.run(init_models(engine=engine, base=base)) # Create tables + asyncio.get_event_loop().run_until_complete(create_base(engine, base)) return sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) diff --git a/poetry.lock b/poetry.lock index 42b6173..613e3f1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -950,6 +950,17 @@ files = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] +[[package]] +name = "nest-asyncio" +version = "1.5.7" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.5.7-py3-none-any.whl", hash = "sha256:5301c82941b550b3123a1ea772ba9a1c80bad3a182be8c1a5ae6ad3be57a9657"}, + {file = "nest_asyncio-1.5.7.tar.gz", hash = "sha256:6a80f7b98f24d9083ed24608977c09dd608d83f91cccc24c9d2cba6d10e01c10"}, +] + [[package]] name = "packaging" version = "21.3" @@ -1574,4 +1585,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "fee8cb9cdc8414e89c8f849d1199a9c3443a8dda4d83e7fd004c2237926f512f" +content-hash = "50ee5ccbc0838175867c1f1bc6b091ab4cda42a07253e36b403f85f2bedf7097" diff --git a/pyproject.toml b/pyproject.toml index b5b8659..5dbd50c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ pycryptodomex = "^3.9" environs = "^9.3.1" asyncpg = "^0.28.0" asyncio = "^3.4.3" +nest-asyncio = "^1.5.7" [tool.poetry.dev-dependencies] From f51dc1ae1b02125482f9de41634156a7e57e39e4 Mon Sep 17 00:00:00 2001 From: Omer Abuddi Date: Wed, 16 Aug 2023 15:32:31 +0300 Subject: [PATCH 5/6] fix server tests --- jwthenticator/keys.py | 3 ++- jwthenticator/tests/test_integration.py | 2 ++ jwthenticator/tests/test_server.py | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/jwthenticator/keys.py b/jwthenticator/keys.py index 254ea65..7137d57 100644 --- a/jwthenticator/keys.py +++ b/jwthenticator/keys.py @@ -67,7 +67,8 @@ async def update_key_expiry(self, key_hash: str, expires_at: datetime) -> bool: if not await self.check_key_exists(key_hash): raise InvalidKeyError("Invalid key") async with self.async_session_factory() as session: - key_info_obj = await session.query(KeyInfo).filter_by(key_hash=key_hash).first() + query = select(KeyInfo).where(KeyInfo.key_hash == key_hash) + key_info_obj = (await session.execute(query)).scalars().first() key_info_obj.expires_at = expires_at return True diff --git a/jwthenticator/tests/test_integration.py b/jwthenticator/tests/test_integration.py index e50ea5a..d22771f 100644 --- a/jwthenticator/tests/test_integration.py +++ b/jwthenticator/tests/test_integration.py @@ -8,6 +8,7 @@ from typing import Union from unittest.mock import patch +import nest_asyncio from aiohttp import web, ClientSession from aiohttp.client import ClientSession as ClientSessionType from aiohttp.test_utils import AioHTTPTestCase, TestClient @@ -21,6 +22,7 @@ SERVER_HOST = "127.0.0.1" SERVER_URL = f"http://{SERVER_HOST}:{SERVER_PORT}" CLIENT_PATCH_FILES = ["client.py"] +nest_asyncio.apply() @authenticate(SERVER_URL) diff --git a/jwthenticator/tests/test_server.py b/jwthenticator/tests/test_server.py index 6389b87..4d25ea1 100644 --- a/jwthenticator/tests/test_server.py +++ b/jwthenticator/tests/test_server.py @@ -5,6 +5,7 @@ from http import HTTPStatus from unittest.mock import MagicMock +import nest_asyncio from aiohttp.test_utils import AioHTTPTestCase from aiohttp.web import Application from jwt import PyJWKClient @@ -36,6 +37,7 @@ async def get_application(self) -> Application: def setup_class(self) -> None: + nest_asyncio.apply() self.auth_request_schema = AuthRequest.Schema() self.token_response_schema = TokenResponse.Schema() self.refresh_request_schema = RefreshRequest.Schema() From a2e28fc466862c04a3175dcefd32349f5b104a90 Mon Sep 17 00:00:00 2001 From: Omer Abuddi Date: Thu, 17 Aug 2023 11:41:18 +0300 Subject: [PATCH 6/6] Fixed CR --- jwthenticator/keys.py | 11 +++++------ jwthenticator/tokens.py | 7 +++---- poetry.lock | 15 +-------------- pyproject.toml | 5 +++-- 4 files changed, 12 insertions(+), 26 deletions(-) diff --git a/jwthenticator/keys.py b/jwthenticator/keys.py index 7137d57..99be0d8 100644 --- a/jwthenticator/keys.py +++ b/jwthenticator/keys.py @@ -5,7 +5,7 @@ from hashlib import sha512 from uuid import UUID -from sqlalchemy import select +from sqlalchemy import select, func from jwthenticator.utils import create_async_session_factory from jwthenticator.schemas import KeyData @@ -55,9 +55,8 @@ async def check_key_exists(self, key_hash: str) -> bool: Check if a key exists in DB. """ async with self.async_session_factory() as session: - query = select(KeyInfo.id).where(KeyInfo.key_hash == key_hash) - result = await session.execute(query) - return len(result.all()) == 1 + query = select(func.count(KeyInfo.id)).where(KeyInfo.key_hash == key_hash) + return (await session.scalar(query)) == 1 async def update_key_expiry(self, key_hash: str, expires_at: datetime) -> bool: @@ -68,7 +67,7 @@ async def update_key_expiry(self, key_hash: str, expires_at: datetime) -> bool: raise InvalidKeyError("Invalid key") async with self.async_session_factory() as session: query = select(KeyInfo).where(KeyInfo.key_hash == key_hash) - key_info_obj = (await session.execute(query)).scalars().first() + key_info_obj = await session.scalar(query) key_info_obj.expires_at = expires_at return True @@ -81,6 +80,6 @@ async def get_key(self, key_hash: str) -> KeyData: raise InvalidKeyError("Invalid key") async with self.async_session_factory() as session: query = select(KeyInfo).where(KeyInfo.key_hash == key_hash) - key_info_obj = (await session.execute(query)).scalars().first() + key_info_obj = await session.scalar(query) key_data_obj = self.key_schema.load((self.key_schema.dump(key_info_obj))) return key_data_obj diff --git a/jwthenticator/tokens.py b/jwthenticator/tokens.py index 294c571..ff9fd1a 100644 --- a/jwthenticator/tokens.py +++ b/jwthenticator/tokens.py @@ -6,7 +6,7 @@ from uuid import UUID, uuid4 import jwt -from sqlalchemy import select +from sqlalchemy import select, func from jwthenticator.utils import create_async_session_factory from jwthenticator.models import Base, RefreshTokenInfo @@ -105,9 +105,8 @@ async def check_refresh_token_exists(self, refresh_token: str) -> bool: Check if a refresh token exists in DB. """ async with self.async_session_factory() as session: - query = select(RefreshTokenInfo).where(RefreshTokenInfo.token == refresh_token) - result = (await session.execute(query)) - return len(result.all()) == 1 + query = select(func.count(RefreshTokenInfo.id)).where(RefreshTokenInfo.token == refresh_token) + return (await session.scalar(query)) == 1 async def load_refresh_token(self, refresh_token: str) -> RefreshTokenData: diff --git a/poetry.lock b/poetry.lock index 613e3f1..461d007 100644 --- a/poetry.lock +++ b/poetry.lock @@ -159,19 +159,6 @@ files = [ {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] -[[package]] -name = "asyncio" -version = "3.4.3" -description = "reference implementation of PEP 3156" -optional = false -python-versions = "*" -files = [ - {file = "asyncio-3.4.3-cp33-none-win32.whl", hash = "sha256:b62c9157d36187eca799c378e572c969f0da87cd5fc42ca372d92cdb06e7e1de"}, - {file = "asyncio-3.4.3-cp33-none-win_amd64.whl", hash = "sha256:c46a87b48213d7464f22d9a497b9eef8c1928b68320a2fa94240f969f6fec08c"}, - {file = "asyncio-3.4.3-py3-none-any.whl", hash = "sha256:c4d18b22701821de07bd6aea8b53d21449ec0ec5680645e5317062ea21817d2d"}, - {file = "asyncio-3.4.3.tar.gz", hash = "sha256:83360ff8bc97980e4ff25c964c7bd3923d333d177aa4f7fb736b019f26c7cb41"}, -] - [[package]] name = "asyncpg" version = "0.28.0" @@ -1585,4 +1572,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "50ee5ccbc0838175867c1f1bc6b091ab4cda42a07253e36b403f85f2bedf7097" +content-hash = "edce9deb83ccdaa112fdc56360593998bf4ef4a27cfd5609351274ea16b3e88d" diff --git a/pyproject.toml b/pyproject.toml index 5dbd50c..b18dba7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,8 +23,6 @@ marshmallow-dataclass = "^8.3" pycryptodomex = "^3.9" environs = "^9.3.1" asyncpg = "^0.28.0" -asyncio = "^3.4.3" -nest-asyncio = "^1.5.7" [tool.poetry.dev-dependencies] @@ -42,6 +40,9 @@ aiofiles = "^0.7.0" typing-inspect = "0.7.1" # https://github.com/lovasoa/marshmallow_dataclass/issues/206 +[tool.poetry.group.dev.dependencies] +nest-asyncio = "^1.5.7" + [tool.pylint.message_control] disable = [ "missing-class-docstring",