pytest-revealtype-injector 0.1.1__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- pytest_revealtype_injector/__init__.py +1 -1
- pytest_revealtype_injector/adapter/mypy_.py +16 -2
- pytest_revealtype_injector/adapter/pyright_.py +41 -12
- pytest_revealtype_injector/models.py +2 -0
- {pytest_revealtype_injector-0.1.1.dist-info → pytest_revealtype_injector-0.2.1.dist-info}/METADATA +11 -4
- pytest_revealtype_injector-0.2.1.dist-info/RECORD +15 -0
- {pytest_revealtype_injector-0.1.1.dist-info → pytest_revealtype_injector-0.2.1.dist-info}/WHEEL +1 -1
- pytest_revealtype_injector-0.2.1.dist-info/licenses/COPYING +6 -0
- pytest_revealtype_injector-0.1.1.dist-info/licenses/LICENSE → pytest_revealtype_injector-0.2.1.dist-info/licenses/COPYING.mit +1 -11
- pytest_revealtype_injector-0.1.1.dist-info/RECORD +0 -14
- {pytest_revealtype_injector-0.1.1.dist-info → pytest_revealtype_injector-0.2.1.dist-info}/entry_points.txt +0 -0
|
@@ -17,6 +17,7 @@ from typing import (
|
|
|
17
17
|
|
|
18
18
|
import mypy.api
|
|
19
19
|
import pytest
|
|
20
|
+
import schema as s
|
|
20
21
|
|
|
21
22
|
from ..models import (
|
|
22
23
|
FilePos,
|
|
@@ -124,6 +125,19 @@ class _MypyAdapter(TypeCheckerAdapter):
|
|
|
124
125
|
id = "mypy"
|
|
125
126
|
typechecker_result = {}
|
|
126
127
|
_type_mesg_re = re.compile(r'^Revealed type is "(?P<type>.+?)"$')
|
|
128
|
+
_schema = s.Schema({
|
|
129
|
+
"file": str,
|
|
130
|
+
"line": int,
|
|
131
|
+
"column": int,
|
|
132
|
+
"message": str,
|
|
133
|
+
"hint": s.Or(str, s.Schema(None)),
|
|
134
|
+
"code": str,
|
|
135
|
+
"severity": s.Or(
|
|
136
|
+
s.Schema("note"),
|
|
137
|
+
s.Schema("warning"),
|
|
138
|
+
s.Schema("error"),
|
|
139
|
+
),
|
|
140
|
+
})
|
|
127
141
|
|
|
128
142
|
@classmethod
|
|
129
143
|
def run_typechecker_on(cls, paths: Iterable[pathlib.Path]) -> None:
|
|
@@ -148,8 +162,8 @@ class _MypyAdapter(TypeCheckerAdapter):
|
|
|
148
162
|
# So-called mypy json output is merely a line-by-line
|
|
149
163
|
# transformation of plain text output into json object
|
|
150
164
|
for line in stdout.splitlines():
|
|
151
|
-
|
|
152
|
-
diag = cast(_MypyDiagObj,
|
|
165
|
+
obj = json.loads(line)
|
|
166
|
+
diag = cast(_MypyDiagObj, cls._schema.validate(obj))
|
|
153
167
|
filename = pathlib.Path(diag["file"]).name
|
|
154
168
|
pos = FilePos(filename, diag["line"])
|
|
155
169
|
if diag["severity"] != "note":
|
|
@@ -11,9 +11,13 @@ from collections.abc import (
|
|
|
11
11
|
from typing import (
|
|
12
12
|
Any,
|
|
13
13
|
ForwardRef,
|
|
14
|
+
Literal,
|
|
15
|
+
TypedDict,
|
|
16
|
+
cast,
|
|
14
17
|
)
|
|
15
18
|
|
|
16
19
|
import pytest
|
|
20
|
+
import schema as s
|
|
17
21
|
|
|
18
22
|
from ..models import (
|
|
19
23
|
FilePos,
|
|
@@ -27,6 +31,21 @@ _logger = logging.getLogger(__name__)
|
|
|
27
31
|
_logger.setLevel(logging.INFO)
|
|
28
32
|
|
|
29
33
|
|
|
34
|
+
class _PyrightDiagPosition(TypedDict):
|
|
35
|
+
line: int
|
|
36
|
+
character: int
|
|
37
|
+
|
|
38
|
+
class _PyrightDiagRange(TypedDict):
|
|
39
|
+
start: _PyrightDiagPosition
|
|
40
|
+
end: _PyrightDiagPosition
|
|
41
|
+
|
|
42
|
+
class _PyrightDiagItem(TypedDict):
|
|
43
|
+
file: str
|
|
44
|
+
severity: Literal["information", "warning", "error"]
|
|
45
|
+
message: str
|
|
46
|
+
range: _PyrightDiagRange
|
|
47
|
+
|
|
48
|
+
|
|
30
49
|
class _NameCollector(NameCollectorBase):
|
|
31
50
|
# Pyright inferred type results always contain bare names only,
|
|
32
51
|
# so don't need to bother with visit_Attribute()
|
|
@@ -47,6 +66,21 @@ class _PyrightAdapter(TypeCheckerAdapter):
|
|
|
47
66
|
id = "pyright"
|
|
48
67
|
typechecker_result = {}
|
|
49
68
|
_type_mesg_re = re.compile('^Type of "(?P<var>.+?)" is "(?P<type>.+?)"$')
|
|
69
|
+
# We only care about diagnostic messages that contain type information.
|
|
70
|
+
# Metadata not specified here.
|
|
71
|
+
_schema = s.Schema({
|
|
72
|
+
"file": str,
|
|
73
|
+
"severity": s.Or(
|
|
74
|
+
s.Schema("information"),
|
|
75
|
+
s.Schema("warning"),
|
|
76
|
+
s.Schema("error"),
|
|
77
|
+
),
|
|
78
|
+
"message": str,
|
|
79
|
+
"range": {
|
|
80
|
+
"start": {"line": int, "character": int},
|
|
81
|
+
"end": {"line": int, "character": int},
|
|
82
|
+
},
|
|
83
|
+
})
|
|
50
84
|
|
|
51
85
|
@classmethod
|
|
52
86
|
def run_typechecker_on(cls, paths: Iterable[pathlib.Path]) -> None:
|
|
@@ -67,22 +101,17 @@ class _PyrightAdapter(TypeCheckerAdapter):
|
|
|
67
101
|
if len(proc.stderr):
|
|
68
102
|
raise TypeCheckerError(proc.stderr.decode(), None, None)
|
|
69
103
|
|
|
70
|
-
# TODO Pyright json schema validation
|
|
71
104
|
report = json.loads(proc.stdout)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
continue
|
|
76
|
-
# Pyright report lineno is 0-based,
|
|
77
|
-
# OTOH python frame lineno is 1-based
|
|
78
|
-
lineno = diag["range"]["start"]["line"] + 1
|
|
79
|
-
filename = pathlib.Path(diag["file"]).name
|
|
80
|
-
raise TypeCheckerError(diag["message"], filename, lineno)
|
|
81
|
-
for diag in report["generalDiagnostics"]:
|
|
82
|
-
if diag["severity"] != "information":
|
|
105
|
+
for item in report["generalDiagnostics"]:
|
|
106
|
+
diag = cast(_PyrightDiagItem, cls._schema.validate(item))
|
|
107
|
+
if diag["severity"] != ("error" if proc.returncode else "information"):
|
|
83
108
|
continue
|
|
109
|
+
# Pyright report lineno is 0-based, while
|
|
110
|
+
# python frame lineno is 1-based
|
|
84
111
|
lineno = diag["range"]["start"]["line"] + 1
|
|
85
112
|
filename = pathlib.Path(diag["file"]).name
|
|
113
|
+
if proc.returncode:
|
|
114
|
+
raise TypeCheckerError(diag["message"], filename, lineno)
|
|
86
115
|
if (m := cls._type_mesg_re.match(diag["message"])) is None:
|
|
87
116
|
continue
|
|
88
117
|
pos = FilePos(filename, lineno)
|
|
@@ -15,6 +15,7 @@ from typing import (
|
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
import pytest
|
|
18
|
+
from schema import Schema
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class FilePos(NamedTuple):
|
|
@@ -91,6 +92,7 @@ class TypeCheckerAdapter:
|
|
|
91
92
|
# {('file.py', 10): ('var_name', 'list[str]'), ...}
|
|
92
93
|
typechecker_result: ClassVar[dict[FilePos, VarType]]
|
|
93
94
|
_type_mesg_re: ClassVar[re.Pattern[str]]
|
|
95
|
+
_schema: ClassVar[Schema]
|
|
94
96
|
|
|
95
97
|
@classmethod
|
|
96
98
|
@abc.abstractmethod
|
{pytest_revealtype_injector-0.1.1.dist-info → pytest_revealtype_injector-0.2.1.dist-info}/METADATA
RENAMED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-revealtype-injector
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.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>
|
|
7
|
-
License: MIT
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: COPYING
|
|
9
|
+
License-File: COPYING.mit
|
|
8
10
|
Keywords: annotation,dynamic-typing,pytest,reveal_type,static-typing,stub,stubs,type-checking,types,typing
|
|
9
11
|
Classifier: Development Status :: 4 - Beta
|
|
10
12
|
Classifier: Framework :: Pytest
|
|
11
13
|
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
14
|
Classifier: Programming Language :: Python
|
|
14
15
|
Classifier: Programming Language :: Python :: 3
|
|
15
16
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -23,9 +24,15 @@ Requires-Python: >=3.10
|
|
|
23
24
|
Requires-Dist: mypy>=1.11.2
|
|
24
25
|
Requires-Dist: pyright~=1.1
|
|
25
26
|
Requires-Dist: pytest>=7.0
|
|
27
|
+
Requires-Dist: schema==0.7.7
|
|
26
28
|
Requires-Dist: typeguard~=4.3
|
|
27
29
|
Description-Content-Type: text/markdown
|
|
28
30
|
|
|
31
|
+

|
|
32
|
+

|
|
33
|
+

|
|
34
|
+

|
|
35
|
+
|
|
29
36
|
`pytest-revealtype-injector` is a `pytest` plugin for replacing [`reveal_type()`](https://docs.python.org/3/library/typing.html#typing.reveal_type) calls inside test functions as something more sophisticated. It does the following tasks in parallel:
|
|
30
37
|
|
|
31
38
|
- Launch external static type checkers (`pyright` and `mypy`) and store `reveal_type` results.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
pytest_revealtype_injector/__init__.py,sha256=QWrBXB4AnDHb7ughEzF0sP-1-dZxmRR45Dw0EiLkCrY,211
|
|
2
|
+
pytest_revealtype_injector/hooks.py,sha256=5V2r19I47xQtCDd8ZAzXlqt3nYaBZ4CaMAyGP6w_Y0k,2414
|
|
3
|
+
pytest_revealtype_injector/main.py,sha256=dBlXcGc2NBcEHp0YX75Bp4Q7KY-t1oxlmPQS6o08U24,4490
|
|
4
|
+
pytest_revealtype_injector/models.py,sha256=XsxUQGdv1U4CFi1bB1VeEojPpiwCZp7uxRIWuTGhIaM,3214
|
|
5
|
+
pytest_revealtype_injector/plugin.py,sha256=fkI6yF0dFVba0jEikIrsRp1NUQd2ohWLq4x2lSvFyH0,211
|
|
6
|
+
pytest_revealtype_injector/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
pytest_revealtype_injector/adapter/__init__.py,sha256=wQg3Ply0Xrfe9US_lzgqRgKFE89ZBvDFti6_77X_NKk,339
|
|
8
|
+
pytest_revealtype_injector/adapter/mypy_.py,sha256=5lWExaKWDx_SK2alEsDtjg_vSGLriFgG7E-81TL1bb0,8569
|
|
9
|
+
pytest_revealtype_injector/adapter/pyright_.py,sha256=LGaJcA-HLCE8cxRFCmPQ5TTURud-ZapmdXgoFJXrw78,4755
|
|
10
|
+
pytest_revealtype_injector-0.2.1.dist-info/METADATA,sha256=6dIidtF2B7QYkiFR8ul9FjChh1IW8DTbAKsddamYk3k,4160
|
|
11
|
+
pytest_revealtype_injector-0.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
12
|
+
pytest_revealtype_injector-0.2.1.dist-info/entry_points.txt,sha256=UfOm7y3WQnOoGV1mgTMb42MI6iBRPIl88FJiAOnt6SY,74
|
|
13
|
+
pytest_revealtype_injector-0.2.1.dist-info/licenses/COPYING,sha256=LSYUX8PcSMvHCkhM5oi07eOrSLV89qdEJ-FVZmbcpNE,355
|
|
14
|
+
pytest_revealtype_injector-0.2.1.dist-info/licenses/COPYING.mit,sha256=IzYEFDIOECyuupg_B3O9FvgjnU9i4JtambpbleoYHdQ,1060
|
|
15
|
+
pytest_revealtype_injector-0.2.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
pytest-revealtype-injector is released under MIT license (see COPYING.mit).
|
|
2
|
+
|
|
3
|
+
Original source code comes from part of types-lxml project, which is
|
|
4
|
+
release under Apache-2.0 license. But as the sole author of all source
|
|
5
|
+
code inside this repository, it is at my own discretion to follow pytest
|
|
6
|
+
license because this project is taking shape as a pytest plugin.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2023-
|
|
1
|
+
Copyright (c) 2023-2024 Abel Cheung
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
4
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -17,13 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
17
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
19
|
SOFTWARE.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
---------------------
|
|
23
|
-
|
|
24
|
-
pytest-revealtype-injector is released under MIT license (see above).
|
|
25
|
-
|
|
26
|
-
Original source code comes from part of types-lxml project, which is released
|
|
27
|
-
under Apache-2.0 license. But as the sole author of all relevant source code, it
|
|
28
|
-
is at my own discretion to follow pytest license because this project is taking
|
|
29
|
-
form of a pytest plugin.
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
pytest_revealtype_injector/__init__.py,sha256=-sBG0VW8hqWI1JUSqzgJ6M0nptG5OWWQw9dzjnVpRQ8,211
|
|
2
|
-
pytest_revealtype_injector/hooks.py,sha256=5V2r19I47xQtCDd8ZAzXlqt3nYaBZ4CaMAyGP6w_Y0k,2414
|
|
3
|
-
pytest_revealtype_injector/main.py,sha256=dBlXcGc2NBcEHp0YX75Bp4Q7KY-t1oxlmPQS6o08U24,4490
|
|
4
|
-
pytest_revealtype_injector/models.py,sha256=hWo9Oz2ausmht-QpfMTTiCtdE3980IA2KEuch7mo_jk,3158
|
|
5
|
-
pytest_revealtype_injector/plugin.py,sha256=fkI6yF0dFVba0jEikIrsRp1NUQd2ohWLq4x2lSvFyH0,211
|
|
6
|
-
pytest_revealtype_injector/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
-
pytest_revealtype_injector/adapter/__init__.py,sha256=wQg3Ply0Xrfe9US_lzgqRgKFE89ZBvDFti6_77X_NKk,339
|
|
8
|
-
pytest_revealtype_injector/adapter/mypy_.py,sha256=qXZKppEwPYtCcRVBAvg8cLx2heI673w8cT9VftHNU_c,8237
|
|
9
|
-
pytest_revealtype_injector/adapter/pyright_.py,sha256=SEibrnMa0AAa1M3S4BmwEQ7ZgwQEUttsFOi-GWCrisA,4105
|
|
10
|
-
pytest_revealtype_injector-0.1.1.dist-info/METADATA,sha256=ZNYRvvNfc1Hm5LAPyUvPcJWmqHqdFQxlQwviUovZJAE,3649
|
|
11
|
-
pytest_revealtype_injector-0.1.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
12
|
-
pytest_revealtype_injector-0.1.1.dist-info/entry_points.txt,sha256=UfOm7y3WQnOoGV1mgTMb42MI6iBRPIl88FJiAOnt6SY,74
|
|
13
|
-
pytest_revealtype_injector-0.1.1.dist-info/licenses/LICENSE,sha256=nLEPjqH24l4RByIq0dHIFhblIpcxpDrRX7sT3lBNoeM,1420
|
|
14
|
-
pytest_revealtype_injector-0.1.1.dist-info/RECORD,,
|
|
File without changes
|