Skip to content

Commit

Permalink
Ruff linter and formatter changes (#1001)
Browse files Browse the repository at this point in the history
* Ruff settings

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* ruff toml added in manifest

* Ruff formatted files

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Flake8 changes removed

* B904 Exception fixes

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* B028 Error code changes

* B023 exception fixes

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* method-assign exception suppressed

* method-assign exception suppressed

* keywords removed

* Mypy error slienced

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Code coverage fixed

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Merge conflicts resolved

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* ruff precommit settings added

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Setup.cfg deleted

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
gagandeepp and pre-commit-ci[bot] authored Oct 10, 2024
1 parent 8910f56 commit 26a63fc
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ target/
.pytest_cache
.mypy_cache
pip-wheel-metadata/
.venv/
16 changes: 9 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ repos:
- id: blacken-docs
args: ["--target-version=py38"]

- repo: https://github.com/PyCQA/flake8
rev: 7.1.1
hooks:
- id: flake8
language_version: python3.9

- repo: https://github.com/PyCQA/isort
rev: 5.13.2
hooks:
Expand Down Expand Up @@ -62,4 +56,12 @@ repos:
hooks:
- id: pyroma

...
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
hooks:
# Run the linter.
- id: ruff
args: [ --fix ]
# Run the formatter.
- id: ruff-format
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ include CHANGELOG.rst
include LICENSE
include README.rst
include SECURITY.md
include ruff.toml
include tox.ini
include jwt/py.typed
graft docs
Expand Down
34 changes: 21 additions & 13 deletions jwt/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def from_jwk(jwk: str | JWKDict) -> bytes:
else:
raise ValueError
except ValueError:
raise InvalidKeyError("Key is not valid JSON")
raise InvalidKeyError("Key is not valid JSON") from None

if obj.get("kty") != "oct":
raise InvalidKeyError("Not an HMAC key")
Expand Down Expand Up @@ -346,7 +346,9 @@ def prepare_key(self, key: AllowedRSAKeys | str | bytes) -> AllowedRSAKeys:
try:
return cast(RSAPublicKey, load_pem_public_key(key_bytes))
except (ValueError, UnsupportedAlgorithm):
raise InvalidKeyError("Could not parse the provided public key.")
raise InvalidKeyError(
"Could not parse the provided public key."
) from None

@overload
@staticmethod
Expand Down Expand Up @@ -409,10 +411,10 @@ def from_jwk(jwk: str | JWKDict) -> AllowedRSAKeys:
else:
raise ValueError
except ValueError:
raise InvalidKeyError("Key is not valid JSON")
raise InvalidKeyError("Key is not valid JSON") from None

if obj.get("kty") != "RSA":
raise InvalidKeyError("Not an RSA key")
raise InvalidKeyError("Not an RSA key") from None

if "d" in obj and "e" in obj and "n" in obj:
# Private key
Expand All @@ -428,7 +430,7 @@ def from_jwk(jwk: str | JWKDict) -> AllowedRSAKeys:
if any_props_found and not all(props_found):
raise InvalidKeyError(
"RSA key must include all parameters if any are present besides d"
)
) from None

public_numbers = RSAPublicNumbers(
from_base64url_uint(obj["e"]),
Expand Down Expand Up @@ -520,7 +522,7 @@ def prepare_key(self, key: AllowedECKeys | str | bytes) -> AllowedECKeys:
):
raise InvalidKeyError(
"Expecting a EllipticCurvePrivateKey/EllipticCurvePublicKey. Wrong key provided for ECDSA algorithms"
)
) from None

return crypto_key

Expand Down Expand Up @@ -605,13 +607,13 @@ def from_jwk(jwk: str | JWKDict) -> AllowedECKeys:
else:
raise ValueError
except ValueError:
raise InvalidKeyError("Key is not valid JSON")
raise InvalidKeyError("Key is not valid JSON") from None

if obj.get("kty") != "EC":
raise InvalidKeyError("Not an Elliptic curve key")
raise InvalidKeyError("Not an Elliptic curve key") from None

if "x" not in obj or "y" not in obj:
raise InvalidKeyError("Not an Elliptic curve key")
raise InvalidKeyError("Not an Elliptic curve key") from None

x = base64url_decode(obj.get("x"))
y = base64url_decode(obj.get("y"))
Expand All @@ -623,17 +625,23 @@ def from_jwk(jwk: str | JWKDict) -> AllowedECKeys:
if len(x) == len(y) == 32:
curve_obj = SECP256R1()
else:
raise InvalidKeyError("Coords should be 32 bytes for curve P-256")
raise InvalidKeyError(
"Coords should be 32 bytes for curve P-256"
) from None
elif curve == "P-384":
if len(x) == len(y) == 48:
curve_obj = SECP384R1()
else:
raise InvalidKeyError("Coords should be 48 bytes for curve P-384")
raise InvalidKeyError(
"Coords should be 48 bytes for curve P-384"
) from None
elif curve == "P-521":
if len(x) == len(y) == 66:
curve_obj = SECP521R1()
else:
raise InvalidKeyError("Coords should be 66 bytes for curve P-521")
raise InvalidKeyError(
"Coords should be 66 bytes for curve P-521"
) from None
elif curve == "secp256k1":
if len(x) == len(y) == 32:
curve_obj = SECP256K1()
Expand Down Expand Up @@ -834,7 +842,7 @@ def from_jwk(jwk: str | JWKDict) -> AllowedOKPKeys:
else:
raise ValueError
except ValueError:
raise InvalidKeyError("Key is not valid JSON")
raise InvalidKeyError("Key is not valid JSON") from None

if obj.get("kty") != "OKP":
raise InvalidKeyError("Not an Octet Key Pair")
Expand Down
4 changes: 3 additions & 1 deletion jwt/api_jws.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def decode_complete(
"and will be removed in pyjwt version 3. "
f"Unsupported kwargs: {tuple(kwargs.keys())}",
RemovedInPyjwt3Warning,
stacklevel=2,
)
if options is None:
options = {}
Expand Down Expand Up @@ -239,6 +240,7 @@ def decode(
"and will be removed in pyjwt version 3. "
f"Unsupported kwargs: {tuple(kwargs.keys())}",
RemovedInPyjwt3Warning,
stacklevel=2,
)
decoded = self.decode_complete(
jwt, key, algorithms, options, detached_payload=detached_payload
Expand Down Expand Up @@ -307,7 +309,7 @@ def _verify_signature(
try:
alg = header["alg"]
except KeyError:
raise InvalidAlgorithmError("Algorithm not specified")
raise InvalidAlgorithmError("Algorithm not specified") from None

if not alg or (algorithms is not None and alg not in algorithms):
raise InvalidAlgorithmError("The specified alg value is not allowed")
Expand Down
15 changes: 11 additions & 4 deletions jwt/api_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def decode_complete(
"and will be removed in pyjwt version 3. "
f"Unsupported kwargs: {tuple(kwargs.keys())}",
RemovedInPyjwt3Warning,
stacklevel=2,
)
options = dict(options or {}) # shallow-copy or initialize an empty dict
options.setdefault("verify_signature", True)
Expand All @@ -135,6 +136,7 @@ def decode_complete(
"The equivalent is setting `verify_signature` to False in the `options` dictionary. "
"This invocation has a mismatch between the kwarg and the option entry.",
category=DeprecationWarning,
stacklevel=2,
)

if not options["verify_signature"]:
Expand Down Expand Up @@ -173,7 +175,7 @@ def _decode_payload(self, decoded: dict[str, Any]) -> Any:
try:
payload = json.loads(decoded["payload"])
except ValueError as e:
raise DecodeError(f"Invalid payload string: {e}")
raise DecodeError(f"Invalid payload string: {e}") from e
if not isinstance(payload, dict):
raise DecodeError("Invalid payload string: must be a json object")
return payload
Expand Down Expand Up @@ -202,6 +204,7 @@ def decode(
"and will be removed in pyjwt version 3. "
f"Unsupported kwargs: {tuple(kwargs.keys())}",
RemovedInPyjwt3Warning,
stacklevel=2,
)
decoded = self.decode_complete(
jwt,
Expand Down Expand Up @@ -269,7 +272,9 @@ def _validate_iat(
try:
iat = int(payload["iat"])
except ValueError:
raise InvalidIssuedAtError("Issued At claim (iat) must be an integer.")
raise InvalidIssuedAtError(
"Issued At claim (iat) must be an integer."
) from None
if iat > (now + leeway):
raise ImmatureSignatureError("The token is not yet valid (iat)")

Expand All @@ -282,7 +287,7 @@ def _validate_nbf(
try:
nbf = int(payload["nbf"])
except ValueError:
raise DecodeError("Not Before claim (nbf) must be an integer.")
raise DecodeError("Not Before claim (nbf) must be an integer.") from None

if nbf > (now + leeway):
raise ImmatureSignatureError("The token is not yet valid (nbf)")
Expand All @@ -296,7 +301,9 @@ def _validate_exp(
try:
exp = int(payload["exp"])
except ValueError:
raise DecodeError("Expiration Time claim (exp) must be an integer.")
raise DecodeError(
"Expiration Time claim (exp) must be an integer."
) from None

if exp <= (now - leeway):
raise ExpiredSignatureError("Signature has expired")
Expand Down
5 changes: 4 additions & 1 deletion jwt/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ def info() -> Dict[str, Dict[str, str]]:
)
if pypy_version_info.releaselevel != "final":
implementation_version = "".join(
[implementation_version, pypy_version_info.releaselevel]
[
implementation_version,
pypy_version_info.releaselevel,
]
)
else:
implementation_version = "Unknown"
Expand Down
6 changes: 4 additions & 2 deletions jwt/jwks_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ def __init__(
if cache_keys:
# Cache signing keys
# Ignore mypy (https://github.com/python/mypy/issues/2427)
self.get_signing_key = lru_cache(maxsize=max_cached_keys)(self.get_signing_key) # type: ignore
self.get_signing_key = lru_cache(maxsize=max_cached_keys)(
self.get_signing_key
) # type: ignore

def fetch_data(self) -> Any:
jwk_set: Any = None
Expand All @@ -58,7 +60,7 @@ def fetch_data(self) -> Any:
except (URLError, TimeoutError) as e:
raise PyJWKClientConnectionError(
f'Fail to fetch data from the url, err: "{e}"'
)
) from e
else:
return jwk_set
finally:
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ profile = "black"
[tool.mypy]
allow_incomplete_defs = true
allow_untyped_defs = true
disable_error_code = [
"method-assign",
"unused-ignore",
]
ignore_missing_imports = true
no_implicit_optional = true
overrides = [
Expand Down
77 changes: 77 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".ipynb_checkpoints",
".mypy_cache",
".nox",
".pants.d",
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
".vscode",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"site-packages",
"venv",
]

# Same as Black.
line-length = 88
indent-width = 4

# Assume Python 3.8
target-version = "py38"

[lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = ["E4", "E7", "E9", "F", "B"]
ignore = ["E501"]

# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"

[format]
# Like Black, use double quotes for strings.
quote-style = "double"

# Like Black, indent with spaces, rather than tabs.
indent-style = "space"

# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false

# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"

# Enable auto-formatting of code examples in docstrings. Markdown,
# reStructuredText code/literal blocks and doctests are all supported.
#
# This is currently disabled by default, but it is planned for this
# to be opt-out in the future.
docstring-code-format = false

# Set the line length limit used when formatting code snippets in
# docstrings.
#
# This only has an effect when the `docstring-code-format` setting is
# enabled.
docstring-code-line-length = "dynamic"
Empty file added tests/keys/jwk_empty.json
Empty file.
7 changes: 7 additions & 0 deletions tests/test_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ def test_hmac_from_jwk_should_raise_exception_if_not_hmac_key(self):
with pytest.raises(InvalidKeyError):
algo.from_jwk(keyfile.read())

def test_hmac_from_jwk_should_raise_exception_if_empty_json(self):
algo = HMACAlgorithm(HMACAlgorithm.SHA256)

with open(key_path("jwk_empty.json")) as keyfile:
with pytest.raises(InvalidKeyError):
algo.from_jwk(keyfile.read())

@crypto_required
def test_rsa_should_parse_pem_public_key(self):
algo = RSAAlgorithm(RSAAlgorithm.SHA256)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_api_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def test_encode_bad_type(self, jwt):
for t in types:
pytest.raises(
TypeError,
lambda: jwt.encode(t, "secret", algorithms=["HS256"]),
lambda t=t: jwt.encode(t, "secret", algorithms=["HS256"]),
)

def test_encode_with_typ(self, jwt):
Expand Down

0 comments on commit 26a63fc

Please sign in to comment.