pytest-revealtype-injector 0.2.1__py3-none-any.whl → 0.2.3__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 +11 -6
- pytest_revealtype_injector/adapter/pyright_.py +18 -6
- pytest_revealtype_injector/hooks.py +3 -4
- pytest_revealtype_injector/log.py +19 -0
- pytest_revealtype_injector/main.py +18 -12
- pytest_revealtype_injector/models.py +7 -6
- {pytest_revealtype_injector-0.2.1.dist-info → pytest_revealtype_injector-0.2.3.dist-info}/METADATA +26 -1
- pytest_revealtype_injector-0.2.3.dist-info/RECORD +16 -0
- pytest_revealtype_injector-0.2.1.dist-info/RECORD +0 -15
- {pytest_revealtype_injector-0.2.1.dist-info → pytest_revealtype_injector-0.2.3.dist-info}/WHEEL +0 -0
- {pytest_revealtype_injector-0.2.1.dist-info → pytest_revealtype_injector-0.2.3.dist-info}/entry_points.txt +0 -0
- {pytest_revealtype_injector-0.2.1.dist-info → pytest_revealtype_injector-0.2.3.dist-info}/licenses/COPYING +0 -0
- {pytest_revealtype_injector-0.2.1.dist-info → pytest_revealtype_injector-0.2.3.dist-info}/licenses/COPYING.mit +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
import importlib
|
|
3
3
|
import json
|
|
4
|
-
import logging
|
|
5
4
|
import pathlib
|
|
6
5
|
import re
|
|
7
6
|
from collections.abc import (
|
|
@@ -19,6 +18,7 @@ import mypy.api
|
|
|
19
18
|
import pytest
|
|
20
19
|
import schema as s
|
|
21
20
|
|
|
21
|
+
from ..log import get_logger
|
|
22
22
|
from ..models import (
|
|
23
23
|
FilePos,
|
|
24
24
|
NameCollectorBase,
|
|
@@ -27,8 +27,7 @@ from ..models import (
|
|
|
27
27
|
VarType,
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
-
_logger =
|
|
31
|
-
_logger.setLevel(logging.INFO)
|
|
30
|
+
_logger = get_logger()
|
|
32
31
|
|
|
33
32
|
|
|
34
33
|
class _MypyDiagObj(TypedDict):
|
|
@@ -68,7 +67,9 @@ class _NameCollector(NameCollectorBase):
|
|
|
68
67
|
_ = self.visit(node.value)
|
|
69
68
|
|
|
70
69
|
if resolved := getattr(self.collected[prefix], name, False):
|
|
71
|
-
|
|
70
|
+
code = ast.unparse(node)
|
|
71
|
+
self.collected[code] = resolved
|
|
72
|
+
_logger.debug(f"Mypy NameCollector resolved '{code}' as {resolved}")
|
|
72
73
|
return node
|
|
73
74
|
|
|
74
75
|
# For class defined in local scope, mypy just prepends test
|
|
@@ -101,10 +102,13 @@ class _NameCollector(NameCollectorBase):
|
|
|
101
102
|
pass
|
|
102
103
|
else:
|
|
103
104
|
self.collected[name] = mod
|
|
105
|
+
_logger.debug(f"Mypy NameCollector resolved '{name}' as {mod}")
|
|
104
106
|
return node
|
|
105
107
|
|
|
106
108
|
if hasattr(self.collected["typing"], name):
|
|
107
|
-
|
|
109
|
+
obj = getattr(self.collected["typing"], name)
|
|
110
|
+
self.collected[name] = obj
|
|
111
|
+
_logger.debug(f"Mypy NameCollector resolved '{name}' as {obj}")
|
|
108
112
|
return node
|
|
109
113
|
|
|
110
114
|
raise NameError(f'Cannot resolve "{name}"')
|
|
@@ -162,6 +166,8 @@ class _MypyAdapter(TypeCheckerAdapter):
|
|
|
162
166
|
# So-called mypy json output is merely a line-by-line
|
|
163
167
|
# transformation of plain text output into json object
|
|
164
168
|
for line in stdout.splitlines():
|
|
169
|
+
if len(line) <= 2 or line[0] != "{":
|
|
170
|
+
continue
|
|
165
171
|
obj = json.loads(line)
|
|
166
172
|
diag = cast(_MypyDiagObj, cls._schema.validate(obj))
|
|
167
173
|
filename = pathlib.Path(diag["file"]).name
|
|
@@ -210,7 +216,6 @@ class _MypyAdapter(TypeCheckerAdapter):
|
|
|
210
216
|
|
|
211
217
|
@classmethod
|
|
212
218
|
def set_config_file(cls, config: pytest.Config) -> None:
|
|
213
|
-
# Mypy doesn't have a default config file
|
|
214
219
|
if (path_str := config.option.revealtype_mypy_config) is None:
|
|
215
220
|
_logger.info("Using default mypy configuration")
|
|
216
221
|
return
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
import json
|
|
3
|
-
import logging
|
|
4
3
|
import pathlib
|
|
5
4
|
import re
|
|
6
5
|
import shutil
|
|
@@ -13,12 +12,14 @@ from typing import (
|
|
|
13
12
|
ForwardRef,
|
|
14
13
|
Literal,
|
|
15
14
|
TypedDict,
|
|
15
|
+
TypeVar,
|
|
16
16
|
cast,
|
|
17
17
|
)
|
|
18
18
|
|
|
19
19
|
import pytest
|
|
20
20
|
import schema as s
|
|
21
21
|
|
|
22
|
+
from ..log import get_logger
|
|
22
23
|
from ..models import (
|
|
23
24
|
FilePos,
|
|
24
25
|
NameCollectorBase,
|
|
@@ -27,18 +28,19 @@ from ..models import (
|
|
|
27
28
|
VarType,
|
|
28
29
|
)
|
|
29
30
|
|
|
30
|
-
_logger =
|
|
31
|
-
_logger.setLevel(logging.INFO)
|
|
31
|
+
_logger = get_logger()
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
class _PyrightDiagPosition(TypedDict):
|
|
35
35
|
line: int
|
|
36
36
|
character: int
|
|
37
37
|
|
|
38
|
+
|
|
38
39
|
class _PyrightDiagRange(TypedDict):
|
|
39
40
|
start: _PyrightDiagPosition
|
|
40
41
|
end: _PyrightDiagPosition
|
|
41
42
|
|
|
43
|
+
|
|
42
44
|
class _PyrightDiagItem(TypedDict):
|
|
43
45
|
file: str
|
|
44
46
|
severity: Literal["information", "warning", "error"]
|
|
@@ -47,6 +49,13 @@ class _PyrightDiagItem(TypedDict):
|
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
class _NameCollector(NameCollectorBase):
|
|
52
|
+
# Pre-register common used bare names from typing
|
|
53
|
+
collected = NameCollectorBase.collected | {
|
|
54
|
+
k: v
|
|
55
|
+
for k, v in NameCollectorBase.collected["typing"].__dict__.items()
|
|
56
|
+
if k[0].isupper() and not isinstance(v, TypeVar)
|
|
57
|
+
}
|
|
58
|
+
|
|
50
59
|
# Pyright inferred type results always contain bare names only,
|
|
51
60
|
# so don't need to bother with visit_Attribute()
|
|
52
61
|
def visit_Name(self, node: ast.Name) -> ast.Name:
|
|
@@ -55,9 +64,12 @@ class _NameCollector(NameCollectorBase):
|
|
|
55
64
|
eval(name, self._globalns, self._localns | self.collected)
|
|
56
65
|
except NameError:
|
|
57
66
|
for m in ("typing", "typing_extensions"):
|
|
58
|
-
if hasattr(self.collected[m], name):
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
if not hasattr(self.collected[m], name):
|
|
68
|
+
continue
|
|
69
|
+
obj = getattr(self.collected[m], name)
|
|
70
|
+
self.collected[name] = obj
|
|
71
|
+
_logger.debug(f"Pyright NameCollector resolved '{name}' as {obj}")
|
|
72
|
+
return node
|
|
61
73
|
raise
|
|
62
74
|
return node
|
|
63
75
|
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import inspect
|
|
4
|
-
import logging
|
|
5
4
|
|
|
6
5
|
import pytest
|
|
7
6
|
|
|
8
|
-
from . import adapter
|
|
7
|
+
from . import adapter, log
|
|
9
8
|
from .main import revealtype_injector
|
|
10
9
|
|
|
11
|
-
_logger =
|
|
12
|
-
_logger.setLevel(logging.INFO)
|
|
10
|
+
_logger = log.get_logger()
|
|
13
11
|
|
|
14
12
|
|
|
15
13
|
def pytest_pyfunc_call(pyfuncitem: pytest.Function) -> None:
|
|
@@ -65,6 +63,7 @@ def pytest_addoption(parser: pytest.Parser) -> None:
|
|
|
65
63
|
|
|
66
64
|
|
|
67
65
|
def pytest_configure(config: pytest.Config) -> None:
|
|
66
|
+
_logger.setLevel(config.get_verbosity(config.VERBOSITY_TEST_CASES))
|
|
68
67
|
# Forget config stash, it can't store collection of unserialized objects
|
|
69
68
|
for adp in adapter.discovery():
|
|
70
69
|
if config.option.revealtype_disable_adapter == adp.id:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
LOGGER_NAME = "revealtype-injector"
|
|
4
|
+
|
|
5
|
+
_logger = logging.getLogger(LOGGER_NAME)
|
|
6
|
+
|
|
7
|
+
# Mapping of pytest.Config.VERBOSITY_TEST_CASES to logging levels
|
|
8
|
+
_verbosity_map = {
|
|
9
|
+
0: logging.WARNING,
|
|
10
|
+
1: logging.INFO,
|
|
11
|
+
2: logging.DEBUG,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
def get_logger() -> logging.Logger:
|
|
15
|
+
return _logger
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def set_verbosity(verbosity: int) -> None:
|
|
19
|
+
_logger.setLevel(_verbosity_map.get(verbosity, logging.DEBUG))
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import ast
|
|
2
2
|
import inspect
|
|
3
|
-
import logging
|
|
4
3
|
import pathlib
|
|
5
4
|
import sys
|
|
6
5
|
from typing import (
|
|
@@ -15,7 +14,7 @@ from typeguard import (
|
|
|
15
14
|
check_type_internal,
|
|
16
15
|
)
|
|
17
16
|
|
|
18
|
-
from . import adapter
|
|
17
|
+
from . import adapter, log
|
|
19
18
|
from .models import (
|
|
20
19
|
FilePos,
|
|
21
20
|
TypeCheckerError,
|
|
@@ -24,8 +23,7 @@ from .models import (
|
|
|
24
23
|
|
|
25
24
|
_T = TypeVar("_T")
|
|
26
25
|
|
|
27
|
-
_logger =
|
|
28
|
-
_logger.setLevel(logging.WARN)
|
|
26
|
+
_logger = log.get_logger()
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
class RevealTypeExtractor(ast.NodeVisitor):
|
|
@@ -42,8 +40,15 @@ class RevealTypeExtractor(ast.NodeVisitor):
|
|
|
42
40
|
|
|
43
41
|
|
|
44
42
|
def _get_var_name(frame: inspect.Traceback) -> str | None:
|
|
43
|
+
filename = pathlib.Path(frame.filename)
|
|
44
|
+
if not filename.exists():
|
|
45
|
+
_logger.warning(
|
|
46
|
+
f"Stack frame points to file '{filename}' "
|
|
47
|
+
"which doesn't exist on local system."
|
|
48
|
+
)
|
|
45
49
|
ctxt, idx = frame.code_context, frame.index
|
|
46
|
-
assert ctxt is not None
|
|
50
|
+
assert ctxt is not None
|
|
51
|
+
assert idx is not None
|
|
47
52
|
code = ctxt[idx].strip()
|
|
48
53
|
|
|
49
54
|
walker = RevealTypeExtractor()
|
|
@@ -51,7 +56,9 @@ def _get_var_name(frame: inspect.Traceback) -> str | None:
|
|
|
51
56
|
# as much restriction on test code as 'eval' mode does.
|
|
52
57
|
walker.visit(ast.parse(code, mode="eval"))
|
|
53
58
|
assert walker.target is not None
|
|
54
|
-
|
|
59
|
+
result = ast.get_source_segment(code, walker.target)
|
|
60
|
+
_logger.debug(f"Extraction OK: {code=}, {result=}")
|
|
61
|
+
return result
|
|
55
62
|
|
|
56
63
|
|
|
57
64
|
def revealtype_injector(var: _T) -> _T:
|
|
@@ -119,22 +126,21 @@ def revealtype_injector(var: _T) -> _T:
|
|
|
119
126
|
adp.typechecker_result[pos] = VarType(var_name, tc_result.type)
|
|
120
127
|
|
|
121
128
|
ref = tc_result.type
|
|
129
|
+
walker = adp.create_collector(globalns, localns)
|
|
122
130
|
try:
|
|
123
|
-
_ = eval(ref.__forward_arg__, globalns, localns)
|
|
131
|
+
_ = eval(ref.__forward_arg__, globalns, localns | walker.collected)
|
|
124
132
|
except (TypeError, NameError):
|
|
125
133
|
ref_ast = ast.parse(ref.__forward_arg__, mode="eval")
|
|
126
|
-
walker = adp.create_collector(globalns, localns)
|
|
127
134
|
new_ast = walker.visit(ref_ast)
|
|
128
135
|
if walker.modified:
|
|
129
136
|
ref = ForwardRef(ast.unparse(new_ast))
|
|
130
|
-
|
|
131
|
-
else:
|
|
132
|
-
memo = TypeCheckMemo(globalns, localns)
|
|
137
|
+
memo = TypeCheckMemo(globalns, localns | walker.collected)
|
|
133
138
|
|
|
134
139
|
try:
|
|
135
140
|
check_type_internal(var, ref, memo)
|
|
136
141
|
except TypeCheckError as e:
|
|
137
|
-
|
|
142
|
+
# Only args[0] contains message
|
|
143
|
+
e.args = (e.args[0] + f" (from {adp.id})",) + e.args[1:]
|
|
138
144
|
raise
|
|
139
145
|
|
|
140
146
|
return var
|
|
@@ -47,6 +47,12 @@ class TypeCheckerError(Exception):
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
class NameCollectorBase(ast.NodeTransformer):
|
|
50
|
+
# typing_extensions guaranteed to be present,
|
|
51
|
+
# as a dependency of typeguard
|
|
52
|
+
collected: dict[str, Any] = {
|
|
53
|
+
m: importlib.import_module(m)
|
|
54
|
+
for m in ("builtins", "typing", "typing_extensions")
|
|
55
|
+
}
|
|
50
56
|
def __init__(
|
|
51
57
|
self,
|
|
52
58
|
globalns: dict[str, Any],
|
|
@@ -56,12 +62,7 @@ class NameCollectorBase(ast.NodeTransformer):
|
|
|
56
62
|
self._globalns = globalns
|
|
57
63
|
self._localns = localns
|
|
58
64
|
self.modified: bool = False
|
|
59
|
-
|
|
60
|
-
# as a dependency of typeguard
|
|
61
|
-
self.collected: dict[str, Any] = {
|
|
62
|
-
m: importlib.import_module(m)
|
|
63
|
-
for m in ("builtins", "typing", "typing_extensions")
|
|
64
|
-
}
|
|
65
|
+
self.collected = type(self).collected.copy()
|
|
65
66
|
|
|
66
67
|
def visit_Subscript(self, node: ast.Subscript) -> ast.expr:
|
|
67
68
|
node.value = cast("ast.expr", self.visit(node.value))
|
{pytest_revealtype_injector-0.2.1.dist-info → pytest_revealtype_injector-0.2.3.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-revealtype-injector
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
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>
|
|
@@ -84,6 +84,31 @@ def test_something():
|
|
|
84
84
|
|
|
85
85
|
2. `reveal_type()` calls have to stay in a single line, without anything else. This limitation comes from using [`eval` mode in AST parsing](https://docs.python.org/3/library/ast.html#ast.Expression).
|
|
86
86
|
|
|
87
|
+
## Logging
|
|
88
|
+
|
|
89
|
+
This plugin uses standard [`logging`](https://docs.python.org/3/library/logging.html) internally. `pytest -v` can be used to reveal `INFO` and `DEBUG` logs. Given following example:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
def test_superfluous(self) -> None:
|
|
93
|
+
x: list[str] = ['a', 'b', 'c', 1] # type: ignore # pyright: ignore
|
|
94
|
+
reveal_type(x)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Something like this will be shown as test result:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
...
|
|
101
|
+
raise TypeCheckError(f"is not an instance of {qualified_name(origin_type)}")
|
|
102
|
+
E typeguard.TypeCheckError: item 3 is not an instance of str (from pyright)
|
|
103
|
+
------------------------------------------------------------- Captured log call -------------------------------------------------------------
|
|
104
|
+
INFO revealtype-injector:hooks.py:26 Replaced reveal_type() from global import with <function revealtype_injector at 0x00000238DB923D00>
|
|
105
|
+
DEBUG revealtype-injector:main.py:60 Extraction OK: code='reveal_type(x)', result='x'
|
|
106
|
+
========================================================== short test summary info ==========================================================
|
|
107
|
+
FAILED tests/runtime/test_attrib.py::TestAttrib::test_superfluous - typeguard.TypeCheckError: item 3 is not an instance of str (from pyright)
|
|
108
|
+
============================================================= 1 failed in 3.38s =============================================================
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
|
|
87
112
|
## History
|
|
88
113
|
|
|
89
114
|
This pytest plugin starts its life as part of testsuite related utilities within [`types-lxml`](https://github.com/abelcheung/types-lxml). As `lxml` is a `cython` project and probably never incorporate inline python annotation in future, there is need to compare runtime result to static type checker output for discrepancy. As time goes by, it starts to make sense to manage as an independent project.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
pytest_revealtype_injector/__init__.py,sha256=I8FXkeB3TED-tbJ3KWZ60nazA1c8pSsF_10q0NGof-I,211
|
|
2
|
+
pytest_revealtype_injector/hooks.py,sha256=cj1iXJJrVtqylXvvdLfjZ61HGBt5wsGBUe-iAgu9WiU,2434
|
|
3
|
+
pytest_revealtype_injector/log.py,sha256=U9IvsoZzhFQcdFmVtuSmt2OTYxxFuIP5o321dyE4hiA,417
|
|
4
|
+
pytest_revealtype_injector/main.py,sha256=ZNb_hDeuEIWDC_eSCLmXXfGCarHF1lsXIOE_BWL-940,4731
|
|
5
|
+
pytest_revealtype_injector/models.py,sha256=FKYznMaNP9a4_AUN3vMdRQBvQUkbdCYTYjDccgdrV6w,3238
|
|
6
|
+
pytest_revealtype_injector/plugin.py,sha256=fkI6yF0dFVba0jEikIrsRp1NUQd2ohWLq4x2lSvFyH0,211
|
|
7
|
+
pytest_revealtype_injector/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
pytest_revealtype_injector/adapter/__init__.py,sha256=wQg3Ply0Xrfe9US_lzgqRgKFE89ZBvDFti6_77X_NKk,339
|
|
9
|
+
pytest_revealtype_injector/adapter/mypy_.py,sha256=q-stxOY2bffTAm2SoHiCAb7VA_f9jXc4UxlyimXV-RY,8840
|
|
10
|
+
pytest_revealtype_injector/adapter/pyright_.py,sha256=Um_HiYDehffci2l9DYXvOfxHNEVuKQsQ9MOsO5mXal4,5126
|
|
11
|
+
pytest_revealtype_injector-0.2.3.dist-info/METADATA,sha256=zrqkK8CDEbkQi2yI1rCnRAf41QAsPkgNIx-dV9UzBvU,5520
|
|
12
|
+
pytest_revealtype_injector-0.2.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
13
|
+
pytest_revealtype_injector-0.2.3.dist-info/entry_points.txt,sha256=UfOm7y3WQnOoGV1mgTMb42MI6iBRPIl88FJiAOnt6SY,74
|
|
14
|
+
pytest_revealtype_injector-0.2.3.dist-info/licenses/COPYING,sha256=LSYUX8PcSMvHCkhM5oi07eOrSLV89qdEJ-FVZmbcpNE,355
|
|
15
|
+
pytest_revealtype_injector-0.2.3.dist-info/licenses/COPYING.mit,sha256=IzYEFDIOECyuupg_B3O9FvgjnU9i4JtambpbleoYHdQ,1060
|
|
16
|
+
pytest_revealtype_injector-0.2.3.dist-info/RECORD,,
|
|
@@ -1,15 +0,0 @@
|
|
|
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,,
|
{pytest_revealtype_injector-0.2.1.dist-info → pytest_revealtype_injector-0.2.3.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|