Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run tests with mypy 0.971 #27

Merged
merged 1 commit into from
Jul 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install -c constraints.txt flake8 flake8-isort black mypy
python -m pip install -c constraints.txt black flake8 flake8-isort mypy pytest
pip list
- name: Run black
run: |
Expand Down
14 changes: 9 additions & 5 deletions constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ distlib==0.3.4
docutils==0.18.1
filelock==3.7.0
flake8==4.0.1
flake8-black==0.3.3
flake8-isort==4.1.1
flake8-bugbear==22.7.1
flake8-comprehensions==3.10.0
flake8-html==0.4.2
flake8-logging-format==0.6.0
flake8-mutable==1.2.0
flake8-pyi==22.7.0
fsfe-reuse==1.0.0
idna==3.3
iniconfig==1.1.1
Expand All @@ -31,7 +35,7 @@ jinja2==3.1.2
license-expression==30.0.0
markupsafe==2.1.1
mccabe==0.6.1
mypy==0.931
mypy==0.971
mypy-extensions==0.4.3
packaging==21.3
pathspec==0.9.0
Expand All @@ -42,8 +46,9 @@ pluggy==1.0.0
py==1.11.0
pycodestyle==2.8.0
pyflakes==2.4.0
pygments==2.12.0
pyparsing==3.0.9
pytest==7.0.1
pytest==7.1.2
pytest-cov==3.0.0
pytest-html==3.1.1
pytest-metadata==2.0.1
Expand All @@ -52,7 +57,6 @@ pytoml==0.1.21
requests==2.27.1
reuse==1.0.0
six==1.16.0
testfixtures==6.18.5
toml==0.10.2
tomli==2.0.1
tox==3.25.0
Expand Down
9 changes: 0 additions & 9 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,3 @@ warn_return_any = True
# Strict Optional checks.
# If False, mypy treats None as compatible with every type. (default True)
strict_optional = True

[mypy-py.*]
ignore_missing_imports = True

[mypy-pytest]
ignore_missing_imports = True

[mypy-_pytest.*]
ignore_missing_imports = True
13 changes: 9 additions & 4 deletions requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@ black<23
bump2version
coverage[toml]
dflit
flake8-black
flake8-isort
flake8-bugbear
flake8-comprehensions
flake8-html
flake8-logging-format
flake8-mutable
flake8-pyi
fsfe-reuse
invoke
mypy==0.931
isort
mypy==0.971
pip-tools
pip>=19.3
pytest-cov
pytest-html
pytest~=7.0.1
pytest~=7.1.2
setuptools>=43
tox-pyenv
tox>=3.14.3
46 changes: 30 additions & 16 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
# pip-compile --allow-unsafe --no-emit-index-url
#
attrs==21.4.0
# via pytest
# via
# flake8-bugbear
# pytest
binaryornot==0.4.4
# via reuse
black==22.3.0
# via
# -r requirements.in
# flake8-black
# via -r requirements.in
boolean-py==4.0
# via
# license-expression
Expand Down Expand Up @@ -48,11 +48,22 @@ filelock==3.7.0
# virtualenv
flake8==4.0.1
# via
# flake8-black
# flake8-isort
flake8-black==0.3.3
# flake8-bugbear
# flake8-comprehensions
# flake8-html
# flake8-mutable
# flake8-pyi
flake8-bugbear==22.7.1
# via -r requirements.in
flake8-comprehensions==3.10.0
# via -r requirements.in
flake8-html==0.4.2
# via -r requirements.in
flake8-isort==4.1.1
flake8-logging-format==0.6.0
# via -r requirements.in
flake8-mutable==1.2.0
# via -r requirements.in
flake8-pyi==22.7.0
# via -r requirements.in
fsfe-reuse==1.0.0
# via -r requirements.in
Expand All @@ -63,16 +74,18 @@ iniconfig==1.1.1
invoke==1.7.1
# via -r requirements.in
isort==5.10.1
# via flake8-isort
# via -r requirements.in
jinja2==3.1.2
# via reuse
# via
# flake8-html
# reuse
license-expression==30.0.0
# via reuse
markupsafe==2.1.1
# via jinja2
mccabe==0.6.1
# via flake8
mypy==0.931
mypy==0.971
# via -r requirements.in
mypy-extensions==0.4.3
# via
Expand Down Expand Up @@ -103,10 +116,14 @@ py==1.11.0
pycodestyle==2.8.0
# via flake8
pyflakes==2.4.0
# via flake8
# via
# flake8
# flake8-pyi
pygments==2.12.0
# via flake8-html
pyparsing==3.0.9
# via packaging
pytest==7.0.1
pytest==7.1.2
# via
# -r requirements.in
# pytest-cov
Expand Down Expand Up @@ -134,15 +151,12 @@ six==1.16.0
# via
# tox
# virtualenv
testfixtures==6.18.5
# via flake8-isort
toml==0.10.2
# via tox
tomli==2.0.1
# via
# black
# coverage
# flake8-black
# mypy
# pep517
# pytest
Expand Down
9 changes: 6 additions & 3 deletions src/pytest_mypy_testing/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import dataclasses
import enum
import os
import pathlib
import re
from typing import Optional, Tuple
from typing import Optional, Tuple, Union


__all__ = [
Expand Down Expand Up @@ -166,7 +167,9 @@ def __str__(self) -> str:
return f"{self._prefix} {self.severity.name.lower()}: {self.message}"

@classmethod
def from_comment(cls, filename: str, lineno: int, comment: str) -> "Message":
def from_comment(
cls, filename: Union[pathlib.Path, str], lineno: int, comment: str
) -> "Message":
"""Create message object from Python *comment*.

>>> Message.from_comment("foo.py", 1, "R: foo")
Expand All @@ -183,7 +186,7 @@ def from_comment(cls, filename: str, lineno: int, comment: str) -> "Message":
else:
revealed_type = None
return Message(
filename,
str(filename),
lineno=lineno,
colno=colno,
severity=Severity.from_string(m.group("severity")),
Expand Down
26 changes: 15 additions & 11 deletions src/pytest_mypy_testing/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import io
import itertools
import os
import pathlib
import sys
import tokenize
from typing import Iterable, Iterator, List, Optional, Set, Tuple
from typing import Iterable, Iterator, List, Optional, Set, Tuple, Union

from .message import Message

Expand Down Expand Up @@ -71,7 +72,7 @@ class MypyTestFile:


def iter_comments(
filename: str, token_lists: List[List[tokenize.TokenInfo]]
filename: Union[pathlib.Path, str], token_lists: List[List[tokenize.TokenInfo]]
) -> Iterator[tokenize.TokenInfo]:
for toks in token_lists:
for tok in toks:
Expand All @@ -80,7 +81,7 @@ def iter_comments(


def iter_mypy_comments(
filename: str, tokens: List[List[tokenize.TokenInfo]]
filename: Union[pathlib.Path, str], tokens: List[List[tokenize.TokenInfo]]
) -> Iterator[Message]:
for tok in iter_comments(filename, tokens):
try:
Expand All @@ -103,17 +104,17 @@ def generate_per_line_token_lists(source: str) -> Iterator[List[tokenize.TokenIn
i += 1


def parse_file(filename: str, config) -> MypyTestFile:
def parse_file(filename: Union[os.PathLike, str, pathlib.Path], config) -> MypyTestFile:
"""Parse *filename* and return information about mypy test cases."""
filename = os.path.abspath(filename)
filename = pathlib.Path(filename).resolve()
with open(filename, "r", encoding="utf-8") as f:
source_text = f.read()

source_lines = source_text.splitlines()
token_lists = list(generate_per_line_token_lists(source_text))
messages = list(iter_mypy_comments(filename, token_lists))

tree = ast.parse(source_text, filename=filename)
tree = ast.parse(source_text, filename=str(filename))
if sys.version_info < (3, 8):
_add_end_lineno_if_missing(tree, len(source_lines))

Expand All @@ -131,7 +132,10 @@ def parse_file(filename: str, config) -> MypyTestFile:
)

return MypyTestFile(
filename=filename, source_lines=source_lines, items=items, messages=messages
filename=str(filename),
source_lines=source_lines,
items=items,
messages=messages,
)


Expand All @@ -140,18 +144,18 @@ def _add_end_lineno_if_missing(tree, line_count: int):
prev_node: Optional[ast.AST] = None
for node in ast.iter_child_nodes(tree):
if prev_node is not None:
setattr(prev_node, "end_lineno", node.lineno)
setattr(prev_node, "end_lineno", node.lineno) # noqa: B010
prev_node = node
if prev_node:
setattr(prev_node, "end_lineno", line_count)
setattr(prev_node, "end_lineno", line_count) # noqa: B010


def _find_marks(func_node: ast.FunctionDef) -> Set[str]:
return set(
return {
name.split(".", 2)[2]
for name, _ in _iter_func_decorators(func_node)
if name.startswith("pytest.mark.")
)
}


def _iter_func_decorators(func_node: ast.FunctionDef) -> Iterator[Tuple[str, ast.AST]]:
Expand Down
22 changes: 11 additions & 11 deletions src/pytest_mypy_testing/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
# SPDX-License-Identifier: Apache-2.0 OR MIT

import os
import pathlib
import tempfile
from typing import Iterable, Iterator, List, NamedTuple, Optional, Tuple
from typing import Iterable, Iterator, List, NamedTuple, Optional, Tuple, Union

import mypy.api
import pytest
from _pytest._code.code import ReprEntry, ReprFileLocation
from _pytest.config import Config
from py._path.local import LocalPath

from .message import Message, Severity
from .output_processing import OutputMismatch, diff_message_sequences
Expand All @@ -36,6 +36,8 @@ def __init__(self, item, errors: Iterable[OutputMismatch]):


class PytestMypyTestItem(pytest.Item):
parent: "PytestMypyFile"

def __init__(
self,
name: str,
Expand Down Expand Up @@ -72,7 +74,7 @@ def runtest(self) -> None:
if errors:
raise MypyAssertionError(item=self, errors=errors)

def reportinfo(self) -> Tuple[str, Optional[int], str]:
def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]:
return self.parent.fspath, self.mypy_item.lineno, self.name

def repr_failure(self, excinfo, style=None):
Expand Down Expand Up @@ -153,7 +155,8 @@ def run_mypy(self, item: MypyTestItem) -> Tuple[int, List[Message]]:
),
)

def _run_mypy(self, filename: str) -> MypyResult:
def _run_mypy(self, filename: Union[pathlib.Path, os.PathLike, str]) -> MypyResult:
filename = pathlib.Path(filename)
with tempfile.TemporaryDirectory(prefix="pytest-mypy-testing-") as tmp_dir_name:

mypy_cache_dir = os.path.join(tmp_dir_name, "mypy_cache")
Expand All @@ -178,9 +181,6 @@ def _run_mypy(self, filename: str) -> MypyResult:

lines = (out + err).splitlines()

# for line in lines:
# print("%%%%", line)

file_messages = [
msg
for msg in map(Message.from_output, lines)
Expand Down Expand Up @@ -213,7 +213,7 @@ def _run_mypy(self, filename: str) -> MypyResult:

if PYTEST_VERSION_INFO < (7,):

def pytest_collect_file(path: LocalPath, parent):
def pytest_collect_file(path, parent):
if path.ext == ".mypy-testing" or _is_pytest_test_file(path, parent):
file = PytestMypyFile.from_parent(parent=parent, fspath=path)
if file.mypy_file.items:
Expand All @@ -222,15 +222,15 @@ def pytest_collect_file(path: LocalPath, parent):

else:

def pytest_collect_file(file_path, path: LocalPath, parent): # type: ignore
def pytest_collect_file(file_path, path, parent): # type: ignore
if path.ext == ".mypy-testing" or _is_pytest_test_file(path, parent):
file = PytestMypyFile.from_parent(parent=parent, path=file_path)
if file.mypy_file.items:
return file
return None


def _is_pytest_test_file(path: LocalPath, parent):
def _is_pytest_test_file(path, parent):
"""Return `True` if *path* is considered to be a pytest test file."""
# Based on _pytest/python.py::pytest_collect_file
fn_patterns = parent.config.getini("python_files") + ["__init__.py"]
Expand Down Expand Up @@ -259,4 +259,4 @@ def _add_reveal_type_to_builtins():
import builtins

if not hasattr(builtins, "reveal_type"):
setattr(builtins, "reveal_type", lambda x: x)
setattr(builtins, "reveal_type", lambda x: x) # noqa: B010
Loading