diff --git a/.travis.yml b/.travis.yml index d915fccc..47f53cb0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,16 +15,12 @@ jobs: cache: pip python: pypy3 - - env: TOXENV=py33 - python: "3.3" + - env: TOXENV=py34 + python: "3.4" after_success: &after_success - pip install coveralls - coveralls - - env: TOXENV=py34 - python: "3.4" - after_success: *after_success - - env: TOXENV=py35 python: "3.5.0" after_success: *after_success @@ -37,6 +33,12 @@ jobs: python: "3.6" after_success: *after_success + - env: TOXENV=py37 + python: "3.7" + dist: xenial + sudo: required + after_success: *after_success + - stage: deploy to pypi install: skip script: skip @@ -49,7 +51,7 @@ jobs: on: tags: true -python: "3.3" +python: "3.4" install: pip install tox diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3f3ebcb8..460ec105 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,11 @@ Version history This library adheres to `Semantic Versioning `_. +**2.2.0** + +- Fixed compatibility with Python 3.7 +- Removed support for Python 3.3 + **2.1.4** (2018-01-07) - Removed support for backports.typing, as it has been removed from PyPI diff --git a/setup.py b/setup.py index a393e32a..74a46dfb 100644 --- a/setup.py +++ b/setup.py @@ -23,20 +23,19 @@ 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6' + 'Programming Language :: Python :: 3.7' ], license='MIT', zip_safe=True, py_modules=['typeguard'], - python_requires='>= 3.3', + python_requires='>= 3.4', setup_requires=[ 'setuptools_scm >= 1.7.0' ], extras_require={ - ':python_version == "3.3"': 'typing >= 3.5', ':python_version == "3.4"': 'typing >= 3.5', 'testing': ['pytest', 'pytest-cov'] } diff --git a/tox.ini b/tox.ini index a2e521e0..2b54c9b9 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.5.0 -envlist = pypy3, py33, py34, py35, py36, flake8 +envlist = pypy3, py34, py35, py36, py37, flake8 skip_missing_interpreters = true [testenv] diff --git a/typeguard.py b/typeguard.py index afc5fa68..b10abdc5 100644 --- a/typeguard.py +++ b/typeguard.py @@ -1,4 +1,4 @@ -import collections +import collections.abc import gc import inspect import sys @@ -284,6 +284,10 @@ def check_class(argname: str, value, expected_type, memo: _CallMemo) -> None: raise TypeError('type of {} must be a type; got {} instead'.format( argname, qualified_name(value))) + # Needed on Python 3.7+ + if expected_type is Type: + return + expected_class = expected_type.__args__[0] if expected_type.__args__ else None if expected_class: if isinstance(expected_class, TypeVar): @@ -338,10 +342,19 @@ def check_number(argname: str, value, expected_type): # Equality checks are applied to these origin_type_checkers = { + Callable: check_callable, + collections.abc.Callable: check_callable, + dict: check_dict, Dict: check_dict, + list: check_list, List: check_list, Sequence: check_sequence, + collections.abc.Sequence: check_sequence, + set: check_set, Set: check_set, + tuple: check_tuple, + Tuple: check_tuple, + type: check_class, Union: check_union } _subclass_check_unions = hasattr(Union, '__union_set_params__') @@ -369,18 +382,14 @@ def check_type(argname: str, value, expected_type, memo: _CallMemo) -> None: # Only happens on < 3.6 expected_type = type(None) - if isclass(expected_type): - origin_type = getattr(expected_type, '__origin__', None) - if origin_type is not None: - checker_func = origin_type_checkers.get(origin_type) - if checker_func: - checker_func(argname, value, expected_type, memo) - return - + origin_type = getattr(expected_type, '__origin__', None) + if origin_type is not None: + checker_func = origin_type_checkers.get(origin_type) + if checker_func: + checker_func(argname, value, expected_type, memo) + elif isclass(expected_type): if issubclass(expected_type, Tuple): check_tuple(argname, value, expected_type, memo) - elif issubclass(expected_type, Callable) and hasattr(expected_type, '__args__'): - check_callable(argname, value, expected_type, memo) elif issubclass(expected_type, (float, complex)): check_number(argname, value, expected_type) elif _subclass_check_unions and issubclass(expected_type, Union): @@ -397,9 +406,6 @@ def check_type(argname: str, value, expected_type, memo: _CallMemo) -> None: elif isinstance(expected_type, TypeVar): # Only happens on < 3.6 check_typevar(argname, value, expected_type, memo) - elif getattr(expected_type, '__origin__', None) is Union: - # Only happens on 3.6+ - check_union(argname, value, expected_type, memo) def check_return_type(retval, memo: _CallMemo) -> bool: