pytest-revealtype-injector 0.3.0__tar.gz → 0.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/PKG-INFO +2 -1
  2. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/pyproject.toml +1 -0
  3. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/__init__.py +1 -1
  4. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/adapter/__init__.py +1 -0
  5. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/adapter/mypy_.py +4 -3
  6. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/adapter/pyright_.py +16 -3
  7. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/hooks.py +2 -4
  8. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/models.py +10 -2
  9. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/.gitignore +0 -0
  10. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/COPYING +0 -0
  11. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/COPYING.mit +0 -0
  12. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/README.md +0 -0
  13. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/adapter/basedpyright_.py +0 -0
  14. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/log.py +0 -0
  15. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/main.py +0 -0
  16. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/plugin.py +0 -0
  17. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/src/pytest_revealtype_injector/py.typed +0 -0
  18. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/tests/conftest.py +0 -0
  19. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/tests/test_import.py +0 -0
  20. {pytest_revealtype_injector-0.3.0 → pytest_revealtype_injector-0.4.1}/tests/test_options.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytest-revealtype-injector
3
- Version: 0.3.0
3
+ Version: 0.4.1
4
4
  Summary: Pytest plugin for replacing reveal_type() calls inside test functions with static and runtime type checking result comparison, for confirming type annotation validity.
5
5
  Project-URL: homepage, https://github.com/abelcheung/pytest-revealtype-injector
6
6
  Author-email: Abel Cheung <abelcheung@gmail.com>
@@ -27,6 +27,7 @@ Requires-Dist: pyright>=1.1
27
27
  Requires-Dist: pytest<9,>=7.0
28
28
  Requires-Dist: schema==0.7.7
29
29
  Requires-Dist: typeguard>=4.3
30
+ Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
30
31
  Description-Content-Type: text/markdown
31
32
 
32
33
  ![PyPI - Version](https://img.shields.io/pypi/v/pytest-revealtype-injector)
@@ -15,6 +15,7 @@ requires-python = '>=3.10'
15
15
  license = 'MIT'
16
16
  license-files = ['COPYING*']
17
17
  dependencies = [
18
+ 'typing_extensions >= 4.0; python_version < "3.11"',
18
19
  'mypy >= 1.11.2',
19
20
  'pyright >= 1.1',
20
21
  'basedpyright >= 1.0',
@@ -1,3 +1,3 @@
1
1
  """Pytest plugin for replacing reveal_type() calls inside test functions with static and runtime type checking result comparison, for confirming type annotation validity.""" # noqa: E501
2
2
 
3
- __version__ = "0.3.0"
3
+ __version__ = "0.4.1"
@@ -13,6 +13,7 @@ def generate() -> set[TypeCheckerAdapter]:
13
13
  mypy_.generate_adapter(),
14
14
  }
15
15
 
16
+
16
17
  def get_adapter_classes() -> list[type[TypeCheckerAdapter]]:
17
18
  return [
18
19
  basedpyright_.BasedPyrightAdapter,
@@ -143,7 +143,7 @@ class MypyAdapter(TypeCheckerAdapter):
143
143
  "column": int,
144
144
  "message": str,
145
145
  "hint": s.Or(str, s.Schema(None)),
146
- "code": str,
146
+ "code": s.Or(str, s.Schema(None)),
147
147
  "severity": s.Or(
148
148
  s.Schema("note"),
149
149
  s.Schema("warning"),
@@ -199,11 +199,12 @@ class MypyAdapter(TypeCheckerAdapter):
199
199
  # but not mypy.api.run(), as of 1.13.
200
200
  if diag["severity"] != "note":
201
201
  raise TypeCheckerError(
202
- "Mypy {} with exit code {}: {}".format(
203
- diag["severity"], returncode, diag["message"]
202
+ "{} {} with exit code {}: {}".format(
203
+ self.id, diag["severity"], returncode, diag["message"]
204
204
  ),
205
205
  diag["file"],
206
206
  diag["line"],
207
+ diag["code"],
207
208
  )
208
209
  if (m := self._type_mesg_re.fullmatch(diag["message"])) is None:
209
210
  continue
@@ -6,17 +6,22 @@ import pathlib
6
6
  import re
7
7
  import shutil
8
8
  import subprocess
9
+ import sys
9
10
  from collections.abc import (
10
11
  Iterable,
11
12
  )
12
13
  from typing import (
13
14
  ForwardRef,
14
15
  Literal,
15
- TypedDict,
16
16
  TypeVar,
17
17
  cast,
18
18
  )
19
19
 
20
+ if sys.version_info >= (3, 11):
21
+ from typing import NotRequired, TypedDict
22
+ else:
23
+ from typing_extensions import NotRequired, TypedDict
24
+
20
25
  import schema as s
21
26
 
22
27
  from ..log import get_logger
@@ -46,7 +51,7 @@ class _PyrightDiagItem(TypedDict):
46
51
  severity: Literal["information", "warning", "error"]
47
52
  message: str
48
53
  range: _PyrightDiagRange
49
-
54
+ rule: NotRequired[str]
50
55
 
51
56
  class NameCollector(NameCollectorBase):
52
57
  type_checker = "pyright"
@@ -139,7 +144,15 @@ class PyrightAdapter(TypeCheckerAdapter):
139
144
  lineno = diag["range"]["start"]["line"] + 1
140
145
  filename = pathlib.Path(diag["file"]).name
141
146
  if proc.returncode:
142
- raise TypeCheckerError(diag["message"], filename, lineno)
147
+ assert "rule" in diag
148
+ raise TypeCheckerError(
149
+ "{} {} with exit code {}: {}".format(
150
+ self.id, diag["severity"], proc.returncode, diag["message"]
151
+ ),
152
+ filename,
153
+ lineno,
154
+ diag["rule"],
155
+ )
143
156
  if (m := self._type_mesg_re.fullmatch(diag["message"])) is None:
144
157
  continue
145
158
  pos = FilePos(filename, lineno)
@@ -30,9 +30,7 @@ def pytest_pyfunc_call(pyfuncitem: pytest.Function) -> None:
30
30
  "typing_extensions",
31
31
  }:
32
32
  setattr(pyfuncitem.module, name, injected)
33
- _logger.info(
34
- f"Replaced {name}() from global import with {injected}"
35
- )
33
+ _logger.info(f"Replaced {name}() from global import with {injected}")
36
34
  continue
37
35
 
38
36
  if inspect.ismodule(item):
@@ -51,7 +49,7 @@ def pytest_collection_finish(session: pytest.Session) -> None:
51
49
  adp.run_typechecker_on(files)
52
50
  except Exception as e:
53
51
  _logger.error(f"({adp.id}) {e}")
54
- raise e
52
+ pytest.exit(f"({type(e).__name__}) " + str(e), pytest.ExitCode.INTERNAL_ERROR)
55
53
  else:
56
54
  _logger.info(f"({adp.id}) Type checker ran successfully")
57
55
 
@@ -33,16 +33,24 @@ class VarType(NamedTuple):
33
33
 
34
34
  class TypeCheckerError(Exception):
35
35
  # Can be None when type checker dies before any code evaluation
36
- def __init__(self, message: str, filename: str | None, lineno: int | None) -> None:
36
+ def __init__(
37
+ self,
38
+ message: str,
39
+ filename: str | None,
40
+ lineno: int | None,
41
+ rule: str | None = None,
42
+ ) -> None:
37
43
  super().__init__(message)
38
44
  self._filename = filename
39
45
  self._lineno = lineno
46
+ self._rule = rule
40
47
 
41
48
  def __str__(self) -> str:
42
49
  if self._filename:
43
- return '"{}"{}: {}'.format(
50
+ return '"{}"{}{}: {}'.format(
44
51
  self._filename,
45
52
  " line " + str(self._lineno) if self._lineno else "",
53
+ ', violating "' + self._rule + '" rule' if self._rule else "",
46
54
  self.args[0],
47
55
  )
48
56
  else: