From 9c755bf5adfd66bd0faa2a8f5d2c06dfb90eb026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?= <16805946+edgarrmondragon@users.noreply.github.com> Date: Wed, 10 Jul 2024 18:47:27 -0600 Subject: [PATCH] refactor!: Make `PyJWT` and `cryptography` dependencies optional (#2525) * chore!: Make `PyJWT` and `cryptography` dependencies optional * Catch exception when jwt deps are missing * Add `pragma: no cover --- poetry.lock | 8 ++++---- pyproject.toml | 19 +++++++++++-------- singer_sdk/authenticators.py | 13 +++++++++---- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/poetry.lock b/poetry.lock index 5a970fc6f..f5543103b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -469,7 +469,7 @@ toml = ["tomli"] name = "cryptography" version = "42.0.8" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, @@ -1528,7 +1528,7 @@ windows-terminal = ["colorama (>=0.4.6)"] name = "pyjwt" version = "2.8.0" description = "JSON Web Token implementation in Python" -optional = false +optional = true python-versions = ">=3.7" files = [ {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, @@ -2666,7 +2666,7 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [extras] docs = ["furo", "myst-parser", "pytest", "sphinx", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinx-reredirects"] faker = ["faker"] -jwt = [] +jwt = ["PyJWT", "cryptography"] parquet = ["numpy", "numpy", "pyarrow"] s3 = ["fs-s3fs"] testing = ["pytest", "pytest-durations"] @@ -2674,4 +2674,4 @@ testing = ["pytest", "pytest-durations"] [metadata] lock-version = "2.0" python-versions = ">=3.8" -content-hash = "1316397863d23f10b9f8ec4b5647d4b95311ef90e98618dc3833cacf9ba1ef64" +content-hash = "82c4b9443a3fed513d597831da8a953b3b2989e4859895939a31db30959a19d9" diff --git a/pyproject.toml b/pyproject.toml index 8734abe9a..990fb97f0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ python = ">=3.8" backoff = { version = ">=2.0.0", python = "<4" } backports-datetime-fromisoformat = { version = ">=2.0.1", python = "<3.11" } click = "~=8.0" -cryptography = ">=3.4.6" fs = ">=2.4.16" importlib-metadata = {version = "<9.0.0", python = "<3.12"} importlib-resources = {version = ">=5.12.0,!=6.2.0,!=6.3.0,!=6.3.1", python = "<3.9"} @@ -52,7 +51,6 @@ jsonpath-ng = ">=1.5.3" jsonschema = ">=4.16.0" packaging = ">=23.1" pendulum = ">=2.1.0,<4" -PyJWT = "~=2.4" python-dateutil = ">=2.8.2" python-dotenv = ">=0.20" PyYAML = ">=6.0" @@ -93,10 +91,15 @@ pytest-durations = {version = ">=1.2.0", optional = true} # installed as optional 'faker' extra faker = {version = ">=22.5,<27.0", optional = true} +# Crypto extras +cryptography = { version = ">=3.4.6", optional = true } +PyJWT = { version = "~=2.4", optional = true } + [tool.poetry.extras] -# TODO: Add 'cryptography' and 'PyJWT' to the 'jwt' when we want to remove them -# from the main dependencies -jwt = [] +jwt = [ + "cryptography", + "PyJWT", +] docs = [ "furo", "myst-parser", @@ -273,9 +276,9 @@ warn_unused_ignores = true ignore_missing_imports = true module = [ "backports.datetime_fromisoformat.*", - "joblib.*", # TODO: Remove when https://github.com/joblib/joblib/issues/1516 is shipped - "jsonpath_ng.*", - "pyarrow.*", # TODO: Remove when https://github.com/apache/arrow/issues/32609 if implemented and released + "joblib.*", # TODO: Remove when https://github.com/joblib/joblib/issues/1516 is shipped + "jsonpath_ng.*", # TODO: Remove when https://github.com/h2non/jsonpath-ng/issues/152 is implemented and released + "pyarrow.*", # TODO: Remove when https://github.com/apache/arrow/issues/32609 if implemented and released ] [tool.poetry-dynamic-versioning] diff --git a/singer_sdk/authenticators.py b/singer_sdk/authenticators.py index 09f42efee..21ef1ba22 100644 --- a/singer_sdk/authenticators.py +++ b/singer_sdk/authenticators.py @@ -568,13 +568,18 @@ def oauth_request_payload(self) -> dict: Payload object for OAuth. Raises: + RuntimeError: If the JWT dependencies are not installed. ValueError: If the private key is not set. """ - import jwt # noqa: PLC0415 - from cryptography.hazmat.backends import default_backend # noqa: PLC0415 - from cryptography.hazmat.primitives import serialization # noqa: PLC0415 + try: + import jwt # noqa: PLC0415 + from cryptography.hazmat.backends import default_backend # noqa: PLC0415 + from cryptography.hazmat.primitives import serialization # noqa: PLC0415 + except ModuleNotFoundError as ex: # pragma: no cover + msg = "Install singer-sdk[jwt] to use OAuthJWTAuthenticator." + raise RuntimeError(msg) from ex - if not self.private_key: + if not self.private_key: # pragma: no cover msg = "Missing 'private_key' property for OAuth payload." raise ValueError(msg)