Skip to content

Commit

Permalink
Update typing syntax and usage for Python 3.6+ (#535)
Browse files Browse the repository at this point in the history
Now that Python 2 is not supported, can move away from type comments to
type annotation 🎉.

The typing module is always available, so remove the guards.

Specify the supported Python in the mypy configuration.

Move other mypy configurations to one place. This way, whether tox is
used or not, the same mypy errors appear.

Distribute and install PEP-561 compliant py.typed file. When PyJWT is a
imported as a library, this tells mypy to use the provided type
annotations rather than going through typeshed. This way, the types are
always up to date when running mypy.

Remove outdated ignores since dropping Python 2.
  • Loading branch information
jdufresne authored Dec 16, 2020
1 parent 3ab6583 commit b8cace5
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 38 deletions.
27 changes: 11 additions & 16 deletions jwt/api_jws.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import binascii
import json
from collections.abc import Mapping
from typing import Dict, List, Optional, Type, Union

from .algorithms import requires_cryptography # NOQA
from .algorithms import Algorithm, get_default_algorithms, has_crypto
Expand All @@ -12,12 +13,6 @@
)
from .utils import base64url_decode, base64url_encode, force_bytes, merge_dict

try:
# import required by mypy to perform type checking, not used for normal execution
from typing import Callable, Dict, List, Optional, Type, Union # NOQA
except ImportError:
pass


class PyJWS:
header_typ = "JWT"
Expand Down Expand Up @@ -79,11 +74,11 @@ def get_algorithms(self):

def encode(
self,
payload, # type: Union[Dict, bytes]
key, # type: str
algorithm="HS256", # type: str
headers=None, # type: Optional[Dict]
json_encoder=None, # type: Optional[Type[json.JSONEncoder]]
payload: Union[Dict, bytes],
key: str,
algorithm: str = "HS256",
headers: Optional[Dict] = None,
json_encoder: Optional[Type[json.JSONEncoder]] = None,
):
segments = []

Expand Down Expand Up @@ -131,11 +126,11 @@ def encode(

def decode(
self,
jwt, # type: str
key="", # type: str
algorithms=None, # type: List[str]
options=None, # type: Dict
complete=False, # type: bool
jwt: str,
key: str = "",
algorithms: List[str] = None,
options: Dict = None,
complete: bool = False,
**kwargs
):

Expand Down
34 changes: 14 additions & 20 deletions jwt/api_jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from calendar import timegm
from collections.abc import Iterable, Mapping
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional, Type, Union

from .algorithms import Algorithm, get_default_algorithms # NOQA
from .api_jws import PyJWS
Expand All @@ -16,19 +17,12 @@
)
from .utils import merge_dict

try:
# import required by mypy to perform type checking, not used for normal execution
from typing import Any, Callable, Dict, List, Optional, Type, Union # NOQA
except ImportError:
pass


class PyJWT(PyJWS):
header_type = "JWT"

@staticmethod
def _get_default_options():
# type: () -> Dict[str, Union[bool, List[str]]]
def _get_default_options() -> Dict[str, Union[bool, List[str]]]:
return {
"verify_signature": True,
"verify_exp": True,
Expand All @@ -41,11 +35,11 @@ def _get_default_options():

def encode(
self,
payload, # type: Union[Dict, bytes]
key, # type: str
algorithm="HS256", # type: str
headers=None, # type: Optional[Dict]
json_encoder=None, # type: Optional[Type[json.JSONEncoder]]
payload: Union[Dict, bytes],
key: str,
algorithm: str = "HS256",
headers: Optional[Dict] = None,
json_encoder: Optional[Type[json.JSONEncoder]] = None,
):
# Check that we get a mapping
if not isinstance(payload, Mapping):
Expand All @@ -60,7 +54,7 @@ def encode(
if isinstance(payload.get(time_claim), datetime):
payload[time_claim] = timegm(
payload[time_claim].utctimetuple()
) # type: ignore
)

json_payload = json.dumps(
payload, separators=(",", ":"), cls=json_encoder
Expand All @@ -72,13 +66,13 @@ def encode(

def decode(
self,
jwt, # type: str
key="", # type: str
algorithms=None, # type: List[str]
options=None, # type: Dict
complete=False, # type: bool
jwt: str,
key: str = "",
algorithms: List[str] = None,
options: Dict = None,
complete: bool = False,
**kwargs
): # type: (...) -> Dict[str, Any]
) -> Dict[str, Any]:

if options is None:
options = {"verify_signature": True}
Expand Down
2 changes: 1 addition & 1 deletion jwt/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from . import __version__ as pyjwt_version

try:
import cryptography # type: ignore
import cryptography
except ImportError:
cryptography = None # type: ignore

Expand Down
Empty file added jwt/py.typed
Empty file.
10 changes: 10 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,14 @@ classifiers =
Topic :: Utilities

[options]
zip_safe = false
include_package_data = true
python_requires = >=3.6
packages = find:

[options.package_data]
* = py.typed

[options.extras_require]
docs =
sphinx
Expand Down Expand Up @@ -61,3 +66,8 @@ jwks-client =
exclude =
tests
tests.*

[mypy]
python_version = 3.6
ignore_missing_imports = true
warn_unused_ignores = true
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ commands =
[testenv:typing]
basepython = python3.8
extras = dev
commands = mypy --ignore-missing-imports jwt
commands = mypy jwt


[testenv:lint]
Expand Down

0 comments on commit b8cace5

Please sign in to comment.