pytest-revealtype-injector 0.8.0__tar.gz → 0.9.0__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 (23) hide show
  1. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/PKG-INFO +1 -1
  2. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/__init__.py +1 -1
  3. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/adapter/pyrefly_.py +6 -4
  4. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/adapter/ty_.py +6 -5
  5. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/hooks.py +1 -1
  6. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/tests/test_marker.py +26 -15
  7. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/.gitignore +0 -0
  8. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/COPYING.mit +0 -0
  9. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/README.md +0 -0
  10. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/pyproject.toml +0 -0
  11. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/adapter/__init__.py +0 -0
  12. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/adapter/basedpyright_.py +0 -0
  13. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/adapter/mypy_.py +0 -0
  14. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/adapter/pyright_.py +0 -0
  15. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/log.py +0 -0
  16. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/main.py +0 -0
  17. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/models.py +0 -0
  18. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/plugin.py +0 -0
  19. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/src/pytest_revealtype_injector/py.typed +0 -0
  20. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/tests/conftest.py +0 -0
  21. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/tests/test_ast_mode.py +0 -0
  22. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/tests/test_import.py +0 -0
  23. {pytest_revealtype_injector-0.8.0 → pytest_revealtype_injector-0.9.0}/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.8.0
3
+ Version: 0.9.0
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>
@@ -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.8.0"
3
+ __version__ = "0.9.0"
@@ -110,10 +110,12 @@ class PyreflyAdapter(TypeCheckerAdapter):
110
110
  try:
111
111
  report = json.loads(proc.stdout)
112
112
  except Exception as e:
113
- raise TypeCheckerError(
114
- f"Failed to parse pyrefly JSON output: {e}", None, None
115
- ) from e
116
-
113
+ # pyrefly (circa 0.47.0) appends github text formatted annotation at the end of json output
114
+ decoder = json.JSONDecoder()
115
+ report, _ = decoder.raw_decode(proc.stdout.decode())
116
+ _logger.warning(
117
+ f"({self.id}) failed to parse json output, extracted partial json: {e}"
118
+ )
117
119
  assert isinstance(report, dict) and "errors" in report
118
120
  items = cast(list[_PyreflyDiagItem], report["errors"])
119
121
 
@@ -63,7 +63,7 @@ class NameCollector(BareNameCollector):
63
63
  class TyAdapter(TypeCheckerAdapter):
64
64
  id = "ty"
65
65
  _executable = "ty"
66
- _type_mesg_re = re.compile(r'Revealed type: `(?P<type>.+?)`')
66
+ _type_mesg_re = re.compile(r"Revealed type: `(?P<type>.+?)`")
67
67
  _namecollector_class = BareNameCollector
68
68
  _schema = s.Schema({
69
69
  "check_name": str,
@@ -78,8 +78,8 @@ class TyAdapter(TypeCheckerAdapter):
78
78
  "path": str,
79
79
  "positions": {
80
80
  "begin": {"line": int, "column": int},
81
- "end" : {"line": int, "column": int},
82
- }
81
+ "end": {"line": int, "column": int},
82
+ },
83
83
  },
84
84
  })
85
85
 
@@ -152,11 +152,12 @@ class TyAdapter(TypeCheckerAdapter):
152
152
  filename, lineno = (
153
153
  pathlib.Path(diag["location"]["path"]).name,
154
154
  diag["location"]["positions"]["begin"]["line"],
155
- )
155
+ )
156
156
  if (m := self._type_mesg_re.search(diag["description"])) is None:
157
157
  continue
158
158
  pos = FilePos(filename, lineno)
159
159
  self.typechecker_result[pos] = VarType(None, ForwardRef(m["type"]))
160
160
 
161
+
161
162
  def generate_adapter() -> TypeCheckerAdapter:
162
- return TyAdapter()
163
+ return TyAdapter()
@@ -49,7 +49,7 @@ def pytest_pyfunc_call(pyfuncitem: pytest.Function) -> Iterator[None]:
49
49
  adapters = {a for a in adp_stash}
50
50
 
51
51
  if not adapters:
52
- pytest.fail("No type checker is enabled.")
52
+ pytest.skip("No type checker is enabled for this test.")
53
53
 
54
54
  # Monkeypatch reveal_type() with our own function, to guarantee
55
55
  # each test func can receive different adapters
@@ -62,7 +62,9 @@ class TestOnlyTypeCheckerMarker:
62
62
  pytester.makeconftest("pytest_plugins = ['pytest_revealtype_injector.plugin']")
63
63
  pytester.makepyprojecttoml(self.PYPROJECT_TOML)
64
64
  pytester.makepyfile( # pyright: ignore[reportUnknownMemberType]
65
- self.TEST_CONTENT.replace("# FUNC MARK", "@pytest.mark.onlytypechecker('mypy')")
65
+ self.TEST_CONTENT.replace(
66
+ "# FUNC MARK", "@pytest.mark.onlytypechecker('mypy')"
67
+ )
66
68
  )
67
69
  result = pytester.runpytest("--tb=short", "-vv")
68
70
  result.assert_outcomes(passed=1, failed=2)
@@ -71,7 +73,9 @@ class TestOnlyTypeCheckerMarker:
71
73
  pytester.makeconftest("pytest_plugins = ['pytest_revealtype_injector.plugin']")
72
74
  pytester.makepyprojecttoml(self.PYPROJECT_TOML)
73
75
  pytester.makepyfile( # pyright: ignore[reportUnknownMemberType]
74
- self.TEST_CONTENT.replace("# CLASS MARK", "@pytest.mark.onlytypechecker('mypy')")
76
+ self.TEST_CONTENT.replace(
77
+ "# CLASS MARK", "@pytest.mark.onlytypechecker('mypy')"
78
+ )
75
79
  )
76
80
  result = pytester.runpytest("--tb=short", "-vv")
77
81
  result.assert_outcomes(passed=2, failed=1)
@@ -80,7 +84,9 @@ class TestOnlyTypeCheckerMarker:
80
84
  pytester.makeconftest("pytest_plugins = ['pytest_revealtype_injector.plugin']")
81
85
  pytester.makepyprojecttoml(self.PYPROJECT_TOML)
82
86
  pytester.makepyfile( # pyright: ignore[reportUnknownMemberType]
83
- self.TEST_CONTENT.replace("# GLOBAL MARK", "pytestmark = pytest.mark.onlytypechecker('mypy')")
87
+ self.TEST_CONTENT.replace(
88
+ "# GLOBAL MARK", "pytestmark = pytest.mark.onlytypechecker('mypy')"
89
+ )
84
90
  )
85
91
  result = pytester.runpytest("--tb=short", "-vv")
86
92
  result.assert_outcomes(passed=3, failed=0)
@@ -143,7 +149,9 @@ class TestNoTypeCheckerMarker:
143
149
  pytester.makeconftest("pytest_plugins = ['pytest_revealtype_injector.plugin']")
144
150
  pytester.makepyprojecttoml(self.PYPROJECT_TOML)
145
151
  pytester.makepyfile( # pyright: ignore[reportUnknownMemberType]
146
- self.TEST_CONTENT.replace("# FUNC MARK", "@pytest.mark.notypechecker('mypy')")
152
+ self.TEST_CONTENT.replace(
153
+ "# FUNC MARK", "@pytest.mark.notypechecker('mypy')"
154
+ )
147
155
  )
148
156
  result = pytester.runpytest("--tb=short", "-vv")
149
157
  result.assert_outcomes(passed=1, failed=2)
@@ -152,7 +160,9 @@ class TestNoTypeCheckerMarker:
152
160
  pytester.makeconftest("pytest_plugins = ['pytest_revealtype_injector.plugin']")
153
161
  pytester.makepyprojecttoml(self.PYPROJECT_TOML)
154
162
  pytester.makepyfile( # pyright: ignore[reportUnknownMemberType]
155
- self.TEST_CONTENT.replace("# CLASS MARK", "@pytest.mark.notypechecker('mypy')")
163
+ self.TEST_CONTENT.replace(
164
+ "# CLASS MARK", "@pytest.mark.notypechecker('mypy')"
165
+ )
156
166
  )
157
167
  result = pytester.runpytest("--tb=short", "-vv")
158
168
  result.assert_outcomes(passed=2, failed=1)
@@ -161,11 +171,14 @@ class TestNoTypeCheckerMarker:
161
171
  pytester.makeconftest("pytest_plugins = ['pytest_revealtype_injector.plugin']")
162
172
  pytester.makepyprojecttoml(self.PYPROJECT_TOML)
163
173
  pytester.makepyfile( # pyright: ignore[reportUnknownMemberType]
164
- self.TEST_CONTENT.replace("# GLOBAL MARK", "pytestmark = pytest.mark.notypechecker('mypy')")
174
+ self.TEST_CONTENT.replace(
175
+ "# GLOBAL MARK", "pytestmark = pytest.mark.notypechecker('mypy')"
176
+ )
165
177
  )
166
178
  result = pytester.runpytest("--tb=short", "-vv")
167
179
  result.assert_outcomes(passed=3, failed=0)
168
180
 
181
+
169
182
  class TestMarkerConflicts:
170
183
  PYPROJECT_TOML = """
171
184
  [tool.pyright]
@@ -178,6 +191,7 @@ class TestMarkerConflicts:
178
191
  def test_foo() -> None:
179
192
  pass
180
193
  """
194
+
181
195
  def test_typechecker_exclusive(self, pytester: pytest.Pytester) -> None:
182
196
  pytester.makeconftest("pytest_plugins = ['pytest_revealtype_injector.plugin']")
183
197
  pytester.makepyprojecttoml(self.PYPROJECT_TOML)
@@ -185,22 +199,19 @@ class TestMarkerConflicts:
185
199
  textwrap.dedent(self.TEST_CONTENT).replace(
186
200
  "# PLACEHOLDER",
187
201
  "@pytest.mark.notypechecker('mypy')\n"
188
- "@pytest.mark.onlytypechecker('pyright')"
202
+ "@pytest.mark.onlytypechecker('pyright')",
189
203
  )
190
204
  )
191
205
  result = pytester.runpytest("--tb=short", "-vv")
192
- assert result.ret == pytest.ExitCode.INTERNAL_ERROR
193
- result.assert_outcomes(passed=0, failed=0)
206
+ assert result.ret == pytest.ExitCode.TESTS_FAILED
207
+ result.assert_outcomes(failed=1)
194
208
 
195
209
  def test_no_typechecker_left(self, pytester: pytest.Pytester) -> None:
196
210
  pytester.makeconftest("pytest_plugins = ['pytest_revealtype_injector.plugin']")
197
211
  pytester.makepyprojecttoml(self.PYPROJECT_TOML)
198
212
  pytester.makepyfile( # pyright: ignore[reportUnknownMemberType]
199
- self.TEST_CONTENT.replace(
200
- "# PLACEHOLDER",
201
- "@pytest.mark.onlytypechecker()"
202
- )
213
+ self.TEST_CONTENT.replace("# PLACEHOLDER", "@pytest.mark.onlytypechecker()")
203
214
  )
204
215
  result = pytester.runpytest("--tb=short", "-vv")
205
- assert result.ret == pytest.ExitCode.INTERNAL_ERROR
206
- result.assert_outcomes(passed=0, failed=0)
216
+ assert result.ret == pytest.ExitCode.OK
217
+ result.assert_outcomes(skipped=1)