diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1bbdfcf..5a1c30c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,8 +13,9 @@ jobs: strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10"] - pytest-version: ["~=6.2", "~=7.1"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + # TODO: remove `7.1` in the next release + pytest-version: ["~=6.2", "~=7.1", "~=7.2"] steps: - uses: actions/checkout@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index a4b01a5..2cf40ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,30 @@ # Version history +## Version 1.11.1 + +### Bugfixes + +- Adds `tests/` subfolder to `sdist` package + + +## Version 1.11.0 + +### Features + +- Adds `python3.11` support and promise about `python3.12` support +- Removes `pkg_resources` to use `packaging` instead + + +## Version 1.10.1 + +### Bugfixes + +- Removes unused depenencies for `python < 3.7` +- Fixes compatibility with pytest 7.2, broken due to a private import from + `py._path`. + + ## Version 1.10.0 ### Features diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..d3ceaab --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +graft pytest_mypy_plugins/tests diff --git a/pytest_mypy_plugins/collect.py b/pytest_mypy_plugins/collect.py index a8ad8a0..99a76ef 100644 --- a/pytest_mypy_plugins/collect.py +++ b/pytest_mypy_plugins/collect.py @@ -3,14 +3,24 @@ import platform import sys import tempfile -from typing import TYPE_CHECKING, Any, Dict, Iterator, List, Mapping, Optional, Set - -import pkg_resources +from typing import ( + TYPE_CHECKING, + Any, + Dict, + Hashable, + Iterator, + List, + Mapping, + Optional, + Set, +) + +import py.path import pytest import yaml from _pytest.config.argparsing import Parser from _pytest.nodes import Node -from py._path.local import LocalPath +from packaging.version import Version from pytest_mypy_plugins import utils @@ -63,11 +73,11 @@ def parse_parametrized(params: List[Mapping[str, Any]]) -> List[Mapping[str, Any class SafeLineLoader(yaml.SafeLoader): - def construct_mapping(self, node: yaml.Node, deep: bool = False) -> None: + def construct_mapping(self, node: yaml.MappingNode, deep: bool = False) -> Dict[Hashable, Any]: mapping = super().construct_mapping(node, deep=deep) # Add 1 so line numbering starts at 1 starting_line = node.start_mark.line + 1 - for (title_node, contents_node) in node.value: + for title_node, contents_node in node.value: if title_node.value == "main": starting_line = title_node.start_mark.line + 1 mapping["__line__"] = starting_line @@ -142,7 +152,7 @@ def _eval_skip(self, skip_if: str) -> bool: return eval(skip_if, {"sys": sys, "os": os, "pytest": pytest, "platform": platform}) -if pkg_resources.parse_version(pytest.__version__) >= pkg_resources.parse_version("7.0.0rc1"): +if Version(pytest.__version__) >= Version("7.0.0rc1"): def pytest_collect_file(file_path: pathlib.Path, parent: Node) -> Optional[YamlTestFile]: if file_path.suffix in {".yaml", ".yml"} and file_path.name.startswith(("test-", "test_")): @@ -151,7 +161,7 @@ def pytest_collect_file(file_path: pathlib.Path, parent: Node) -> Optional[YamlT else: - def pytest_collect_file(path: LocalPath, parent: Node) -> Optional[YamlTestFile]: # type: ignore[misc] + def pytest_collect_file(path: py.path.local, parent: Node) -> Optional[YamlTestFile]: # type: ignore[misc] if path.ext in {".yaml", ".yml"} and path.basename.startswith(("test-", "test_")): return YamlTestFile.from_parent(parent, fspath=path) return None diff --git a/pytest_mypy_plugins/item.py b/pytest_mypy_plugins/item.py index 1ffd091..dafd0ac 100644 --- a/pytest_mypy_plugins/item.py +++ b/pytest_mypy_plugins/item.py @@ -87,7 +87,7 @@ class ReturnCodes: FATAL_ERROR = 2 -def run_mypy_typechecking(cmd_options: List[str]) -> int: +def run_mypy_typechecking(cmd_options: List[str]) -> Optional[Union[str, int]]: fscache = FileSystemCache() sources, options = process_options(cmd_options, fscache=fscache) @@ -215,7 +215,7 @@ def typecheck_in_new_subprocess( def typecheck_in_same_process( self, execution_path: Path, mypy_cmd_options: List[Any] - ) -> Tuple[int, Tuple[str, str]]: + ) -> Tuple[Optional[Union[str, int]], Tuple[str, str]]: with utils.temp_environ(), utils.temp_path(), utils.temp_sys_modules(): # add custom environment variables for key, val in self.environment_variables.items(): @@ -241,7 +241,6 @@ def runtest(self) -> None: temp_dir = tempfile.TemporaryDirectory(prefix="pytest-mypy-", dir=self.root_directory) except (FileNotFoundError, PermissionError, NotADirectoryError) as e: - raise TypecheckAssertionError( error_message=f"Testing base directory {self.root_directory} must exist and be writable" ) from e diff --git a/pytest_mypy_plugins/tests/test-parametrized.yml b/pytest_mypy_plugins/tests/test-parametrized.yml index 4df19e2..d69729a 100644 --- a/pytest_mypy_plugins/tests/test-parametrized.yml +++ b/pytest_mypy_plugins/tests/test-parametrized.yml @@ -44,4 +44,4 @@ ... out: | main:2: note: Revealed type is "{{ rt }}" - main:4: error: Unsupported operand types for / ("str" and "int") + main:4: error: Unsupported operand types for / ("str" and "int") [operator] diff --git a/pytest_mypy_plugins/tests/test-paths-from-env.yml b/pytest_mypy_plugins/tests/test-paths-from-env.yml index 62ef522..3990813 100644 --- a/pytest_mypy_plugins/tests/test-paths-from-env.yml +++ b/pytest_mypy_plugins/tests/test-paths-from-env.yml @@ -3,7 +3,7 @@ import extra_module extra_module.extra_fn() - extra_module.missing() # E: Module has no attribute "missing" + extra_module.missing() # E: Module has no attribute "missing" [attr-defined] env: - MYPYPATH=../extras files: diff --git a/pytest_mypy_plugins/tests/test-simple-cases.yml b/pytest_mypy_plugins/tests/test-simple-cases.yml index e324f46..deb220e 100644 --- a/pytest_mypy_plugins/tests/test-simple-cases.yml +++ b/pytest_mypy_plugins/tests/test-simple-cases.yml @@ -57,7 +57,7 @@ - case: error_case main: | a = 1 - a.lower() # E: "int" has no attribute "lower" + a.lower() # E: "int" has no attribute "lower" [attr-defined] - case: custom_mypy_config_strict_optional_true_set @@ -87,7 +87,7 @@ skip: sys.version_info < (0, 0) main: | a = 1 - a.lower() # E: "int" has no attribute "lower" + a.lower() # E: "int" has no attribute "lower" [attr-defined] - case: fail_if_message_does_not_match expect_fail: yes diff --git a/setup.py b/setup.py index 706d140..80c84f3 100644 --- a/setup.py +++ b/setup.py @@ -4,18 +4,18 @@ readme = f.read() dependencies = [ - "pytest>=6.0.0", + "pytest>=6.2.0", "mypy>=0.970", "decorator", "pyyaml", "chevron", "regex", - "dataclasses ; python_version<'3.7'", + "packaging", ] setup( name="pytest-mypy-plugins", - version="1.10.0", + version="1.11.1", description="pytest plugin for writing tests for mypy plugins", long_description=readme, long_description_content_type="text/markdown", @@ -36,11 +36,11 @@ classifiers=[ "Development Status :: 4 - Beta", "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Typing :: Typed", ], )