diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4d127d3c5..e9a970ca7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,7 @@ repos: hooks: - id: flake8 language_version: python3 - additional_dependencies: [flake8-typing-imports] + additional_dependencies: [flake8-typing-imports==1.3.0] - repo: https://github.com/asottile/reorder_python_imports rev: v1.4.0 hooks: diff --git a/.travis.yml b/.travis.yml index 5de40f3a4..c1f7ad357 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,7 +43,8 @@ jobs: python: 'pypy3' - env: TOXENV=py35-xdist - python: '3.5' + dist: trusty + python: '3.5.0' # Coverage for: # - pytester's LsofFdLeakChecker diff --git a/changelog/5751.bugfix.rst b/changelog/5751.bugfix.rst new file mode 100644 index 000000000..879909c8b --- /dev/null +++ b/changelog/5751.bugfix.rst @@ -0,0 +1 @@ +Fixed ``TypeError`` when importing pytest on Python 3.5.0 and 3.5.1. diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index 7d72234e7..a0f4d15ce 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -591,7 +591,7 @@ class ExceptionInfo(Generic[_E]): ) return fmt.repr_excinfo(self) - def match(self, regexp: Union[str, Pattern]) -> bool: + def match(self, regexp: "Union[str, Pattern]") -> bool: """ Check whether the regular expression 'regexp' is found in the string representation of the exception using ``re.search``. If it matches diff --git a/src/_pytest/compat.py b/src/_pytest/compat.py index 790442b0c..3d1531e77 100644 --- a/src/_pytest/compat.py +++ b/src/_pytest/compat.py @@ -9,6 +9,7 @@ import sys from contextlib import contextmanager from inspect import Parameter from inspect import signature +from typing import overload import attr import py @@ -347,3 +348,9 @@ class FuncargnamesCompatAttr: warnings.warn(FUNCARGNAMES, stacklevel=2) return self.fixturenames + + +if sys.version_info < (3, 5, 2): # pragma: no cover + + def overload(f): # noqa: F811 + return f diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index fbc3d914e..f03d45ab7 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -13,7 +13,6 @@ from typing import Callable from typing import cast from typing import Generic from typing import Optional -from typing import overload from typing import Pattern from typing import Tuple from typing import TypeVar @@ -22,12 +21,14 @@ from typing import Union from more_itertools.more import always_iterable import _pytest._code +from _pytest.compat import overload from _pytest.compat import STRING_TYPES from _pytest.outcomes import fail if False: # TYPE_CHECKING from typing import Type # noqa: F401 (used in type string) + BASE_TYPE = (type, STRING_TYPES) @@ -547,12 +548,12 @@ _E = TypeVar("_E", bound=BaseException) def raises( expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]], *, - match: Optional[Union[str, Pattern]] = ... + match: "Optional[Union[str, Pattern]]" = ... ) -> "RaisesContext[_E]": ... # pragma: no cover -@overload +@overload # noqa: F811 def raises( expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]], func: Callable, @@ -563,10 +564,10 @@ def raises( ... # pragma: no cover -def raises( +def raises( # noqa: F811 expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]], *args: Any, - match: Optional[Union[str, Pattern]] = None, + match: Optional[Union[str, "Pattern"]] = None, **kwargs: Any ) -> Union["RaisesContext[_E]", Optional[_pytest._code.ExceptionInfo[_E]]]: r""" @@ -724,7 +725,7 @@ class RaisesContext(Generic[_E]): self, expected_exception: Union["Type[_E]", Tuple["Type[_E]", ...]], message: str, - match_expr: Optional[Union[str, Pattern]] = None, + match_expr: Optional[Union[str, "Pattern"]] = None, ) -> None: self.expected_exception = expected_exception self.message = message diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index 19e3938c3..58076d66b 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -7,11 +7,11 @@ from typing import Callable from typing import Iterator from typing import List from typing import Optional -from typing import overload from typing import Pattern from typing import Tuple from typing import Union +from _pytest.compat import overload from _pytest.fixtures import yield_fixture from _pytest.outcomes import fail @@ -58,26 +58,26 @@ def deprecated_call(func=None, *args, **kwargs): def warns( expected_warning: Union["Type[Warning]", Tuple["Type[Warning]", ...]], *, - match: Optional[Union[str, Pattern]] = ... + match: "Optional[Union[str, Pattern]]" = ... ) -> "WarningsChecker": ... # pragma: no cover -@overload +@overload # noqa: F811 def warns( expected_warning: Union["Type[Warning]", Tuple["Type[Warning]", ...]], func: Callable, *args: Any, - match: Optional[Union[str, Pattern]] = ..., + match: Optional[Union[str, "Pattern"]] = ..., **kwargs: Any ) -> Union[Any]: ... # pragma: no cover -def warns( +def warns( # noqa: F811 expected_warning: Union["Type[Warning]", Tuple["Type[Warning]", ...]], *args: Any, - match: Optional[Union[str, Pattern]] = None, + match: Optional[Union[str, "Pattern"]] = None, **kwargs: Any ) -> Union["WarningsChecker", Any]: r"""Assert that code raises a particular class of warning. @@ -207,7 +207,7 @@ class WarningsChecker(WarningsRecorder): expected_warning: Optional[ Union["Type[Warning]", Tuple["Type[Warning]", ...]] ] = None, - match_expr: Optional[Union[str, Pattern]] = None, + match_expr: Optional[Union[str, "Pattern"]] = None, ) -> None: super().__init__() diff --git a/testing/python/raises.py b/testing/python/raises.py index 668be57fc..28b0715c0 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -163,9 +163,16 @@ class TestRaises: class T: def __call__(self): + # Early versions of Python 3.5 have some bug causing the + # __call__ frame to still refer to t even after everything + # is done. This makes the test pass for them. + if sys.version_info < (3, 5, 2): # pragma: no cover + del self raise ValueError t = T() + refcount = len(gc.get_referrers(t)) + if method == "function": pytest.raises(ValueError, t) else: @@ -175,14 +182,7 @@ class TestRaises: # ensure both forms of pytest.raises don't leave exceptions in sys.exc_info() assert sys.exc_info() == (None, None, None) - del t - # Make sure this does get updated in locals dict - # otherwise it could keep a reference - locals() - - # ensure the t instance is not stuck in a cyclic reference - for o in gc.get_objects(): - assert type(o) is not T + assert refcount == len(gc.get_referrers(t)) def test_raises_match(self): msg = r"with base \d+"