metaflow 2.15.4__py2.py3-none-any.whl → 2.15.6__py2.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.
- metaflow/_vendor/typeguard/_checkers.py +259 -95
- metaflow/_vendor/typeguard/_config.py +4 -4
- metaflow/_vendor/typeguard/_decorators.py +8 -12
- metaflow/_vendor/typeguard/_functions.py +33 -32
- metaflow/_vendor/typeguard/_pytest_plugin.py +40 -13
- metaflow/_vendor/typeguard/_suppression.py +3 -5
- metaflow/_vendor/typeguard/_transformer.py +84 -48
- metaflow/_vendor/typeguard/_union_transformer.py +1 -0
- metaflow/_vendor/typeguard/_utils.py +13 -9
- metaflow/_vendor/typing_extensions.py +1088 -500
- metaflow/_vendor/v3_7/__init__.py +1 -0
- metaflow/_vendor/v3_7/importlib_metadata/__init__.py +1063 -0
- metaflow/_vendor/v3_7/importlib_metadata/_adapters.py +68 -0
- metaflow/_vendor/v3_7/importlib_metadata/_collections.py +30 -0
- metaflow/_vendor/v3_7/importlib_metadata/_compat.py +71 -0
- metaflow/_vendor/v3_7/importlib_metadata/_functools.py +104 -0
- metaflow/_vendor/v3_7/importlib_metadata/_itertools.py +73 -0
- metaflow/_vendor/v3_7/importlib_metadata/_meta.py +48 -0
- metaflow/_vendor/v3_7/importlib_metadata/_text.py +99 -0
- metaflow/_vendor/v3_7/importlib_metadata/py.typed +0 -0
- metaflow/_vendor/v3_7/typeguard/__init__.py +48 -0
- metaflow/_vendor/v3_7/typeguard/_checkers.py +906 -0
- metaflow/_vendor/v3_7/typeguard/_config.py +108 -0
- metaflow/_vendor/v3_7/typeguard/_decorators.py +237 -0
- metaflow/_vendor/v3_7/typeguard/_exceptions.py +42 -0
- metaflow/_vendor/v3_7/typeguard/_functions.py +310 -0
- metaflow/_vendor/v3_7/typeguard/_importhook.py +213 -0
- metaflow/_vendor/v3_7/typeguard/_memo.py +48 -0
- metaflow/_vendor/v3_7/typeguard/_pytest_plugin.py +100 -0
- metaflow/_vendor/v3_7/typeguard/_suppression.py +88 -0
- metaflow/_vendor/v3_7/typeguard/_transformer.py +1207 -0
- metaflow/_vendor/v3_7/typeguard/_union_transformer.py +54 -0
- metaflow/_vendor/v3_7/typeguard/_utils.py +169 -0
- metaflow/_vendor/v3_7/typeguard/py.typed +0 -0
- metaflow/_vendor/v3_7/typing_extensions.py +3072 -0
- metaflow/_vendor/v3_7/zipp.py +329 -0
- metaflow/cmd/develop/stubs.py +1 -1
- metaflow/extension_support/__init__.py +1 -1
- metaflow/plugins/argo/argo_client.py +9 -2
- metaflow/plugins/argo/argo_workflows.py +79 -28
- metaflow/plugins/argo/argo_workflows_cli.py +16 -25
- metaflow/plugins/argo/argo_workflows_deployer_objects.py +5 -2
- metaflow/plugins/cards/card_modules/main.js +52 -50
- metaflow/plugins/metadata_providers/service.py +16 -7
- metaflow/plugins/pypi/utils.py +4 -0
- metaflow/runner/click_api.py +7 -2
- metaflow/runner/deployer.py +3 -2
- metaflow/vendor.py +1 -0
- metaflow/version.py +1 -1
- {metaflow-2.15.4.data → metaflow-2.15.6.data}/data/share/metaflow/devtools/Tiltfile +4 -4
- metaflow-2.15.6.dist-info/METADATA +103 -0
- {metaflow-2.15.4.dist-info → metaflow-2.15.6.dist-info}/RECORD +58 -32
- {metaflow-2.15.4.dist-info → metaflow-2.15.6.dist-info}/WHEEL +1 -1
- metaflow-2.15.4.dist-info/METADATA +0 -110
- {metaflow-2.15.4.data → metaflow-2.15.6.data}/data/share/metaflow/devtools/Makefile +0 -0
- {metaflow-2.15.4.data → metaflow-2.15.6.data}/data/share/metaflow/devtools/pick_services.sh +0 -0
- {metaflow-2.15.4.dist-info → metaflow-2.15.6.dist-info}/LICENSE +0 -0
- {metaflow-2.15.4.dist-info → metaflow-2.15.6.dist-info}/entry_points.txt +0 -0
- {metaflow-2.15.4.dist-info → metaflow-2.15.6.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import sys
|
4
4
|
import warnings
|
5
|
-
from typing import Any, Callable, NoReturn, TypeVar, overload
|
5
|
+
from typing import Any, Callable, NoReturn, TypeVar, Union, overload
|
6
6
|
|
7
7
|
from . import _suppression
|
8
8
|
from ._checkers import BINARY_MAGIC_METHODS, check_type_internal
|
@@ -32,8 +32,7 @@ def check_type(
|
|
32
32
|
forward_ref_policy: ForwardRefPolicy = ...,
|
33
33
|
typecheck_fail_callback: TypeCheckFailCallback | None = ...,
|
34
34
|
collection_check_strategy: CollectionCheckStrategy = ...,
|
35
|
-
) -> T:
|
36
|
-
...
|
35
|
+
) -> T: ...
|
37
36
|
|
38
37
|
|
39
38
|
@overload
|
@@ -44,8 +43,7 @@ def check_type(
|
|
44
43
|
forward_ref_policy: ForwardRefPolicy = ...,
|
45
44
|
typecheck_fail_callback: TypeCheckFailCallback | None = ...,
|
46
45
|
collection_check_strategy: CollectionCheckStrategy = ...,
|
47
|
-
) -> Any:
|
48
|
-
...
|
46
|
+
) -> Any: ...
|
49
47
|
|
50
48
|
|
51
49
|
def check_type(
|
@@ -53,7 +51,7 @@ def check_type(
|
|
53
51
|
expected_type: Any,
|
54
52
|
*,
|
55
53
|
forward_ref_policy: ForwardRefPolicy = TypeCheckConfiguration().forward_ref_policy,
|
56
|
-
typecheck_fail_callback:
|
54
|
+
typecheck_fail_callback: TypeCheckFailCallback | None = (
|
57
55
|
TypeCheckConfiguration().typecheck_fail_callback
|
58
56
|
),
|
59
57
|
collection_check_strategy: CollectionCheckStrategy = (
|
@@ -80,7 +78,7 @@ def check_type(
|
|
80
78
|
corresponding fields in :class:`TypeCheckConfiguration`.
|
81
79
|
|
82
80
|
:param value: value to be checked against ``expected_type``
|
83
|
-
:param expected_type: a class or generic type instance
|
81
|
+
:param expected_type: a class or generic type instance, or a tuple of such things
|
84
82
|
:param forward_ref_policy: see :attr:`TypeCheckConfiguration.forward_ref_policy`
|
85
83
|
:param typecheck_fail_callback:
|
86
84
|
see :attr`TypeCheckConfiguration.typecheck_fail_callback`
|
@@ -90,6 +88,9 @@ def check_type(
|
|
90
88
|
:raises TypeCheckError: if there is a type mismatch
|
91
89
|
|
92
90
|
"""
|
91
|
+
if type(expected_type) is tuple:
|
92
|
+
expected_type = Union[expected_type]
|
93
|
+
|
93
94
|
config = TypeCheckConfiguration(
|
94
95
|
forward_ref_policy=forward_ref_policy,
|
95
96
|
typecheck_fail_callback=typecheck_fail_callback,
|
@@ -244,7 +245,7 @@ def check_variable_assignment(
|
|
244
245
|
value: object, varname: str, annotation: Any, memo: TypeCheckMemo
|
245
246
|
) -> Any:
|
246
247
|
if _suppression.type_checks_suppressed:
|
247
|
-
return
|
248
|
+
return value
|
248
249
|
|
249
250
|
try:
|
250
251
|
check_type_internal(value, annotation, memo)
|
@@ -262,36 +263,36 @@ def check_variable_assignment(
|
|
262
263
|
def check_multi_variable_assignment(
|
263
264
|
value: Any, targets: list[dict[str, Any]], memo: TypeCheckMemo
|
264
265
|
) -> Any:
|
265
|
-
if _suppression.type_checks_suppressed:
|
266
|
-
return
|
267
|
-
|
268
266
|
if max(len(target) for target in targets) == 1:
|
269
267
|
iterated_values = [value]
|
270
268
|
else:
|
271
269
|
iterated_values = list(value)
|
272
270
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
try:
|
287
|
-
check_type_internal(obj, expected_type, memo)
|
288
|
-
except TypeCheckError as exc:
|
289
|
-
qualname = qualified_name(obj, add_class_prefix=True)
|
290
|
-
exc.append_path_element(f"value assigned to {varname} ({qualname})")
|
291
|
-
if memo.config.typecheck_fail_callback:
|
292
|
-
memo.config.typecheck_fail_callback(exc, memo)
|
271
|
+
if not _suppression.type_checks_suppressed:
|
272
|
+
for expected_types in targets:
|
273
|
+
value_index = 0
|
274
|
+
for ann_index, (varname, expected_type) in enumerate(
|
275
|
+
expected_types.items()
|
276
|
+
):
|
277
|
+
if varname.startswith("*"):
|
278
|
+
varname = varname[1:]
|
279
|
+
keys_left = len(expected_types) - 1 - ann_index
|
280
|
+
next_value_index = len(iterated_values) - keys_left
|
281
|
+
obj: object = iterated_values[value_index:next_value_index]
|
282
|
+
value_index = next_value_index
|
293
283
|
else:
|
294
|
-
|
284
|
+
obj = iterated_values[value_index]
|
285
|
+
value_index += 1
|
286
|
+
|
287
|
+
try:
|
288
|
+
check_type_internal(obj, expected_type, memo)
|
289
|
+
except TypeCheckError as exc:
|
290
|
+
qualname = qualified_name(obj, add_class_prefix=True)
|
291
|
+
exc.append_path_element(f"value assigned to {varname} ({qualname})")
|
292
|
+
if memo.config.typecheck_fail_callback:
|
293
|
+
memo.config.typecheck_fail_callback(exc, memo)
|
294
|
+
else:
|
295
|
+
raise
|
295
296
|
|
296
297
|
return iterated_values[0] if len(iterated_values) == 1 else iterated_values
|
297
298
|
|
@@ -2,16 +2,29 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import sys
|
4
4
|
import warnings
|
5
|
-
|
6
|
-
from pytest import Config, Parser
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal
|
7
6
|
|
8
7
|
from metaflow._vendor.typeguard._config import CollectionCheckStrategy, ForwardRefPolicy, global_config
|
9
8
|
from metaflow._vendor.typeguard._exceptions import InstrumentationWarning
|
10
9
|
from metaflow._vendor.typeguard._importhook import install_import_hook
|
11
10
|
from metaflow._vendor.typeguard._utils import qualified_name, resolve_reference
|
12
11
|
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from pytest import Config, Parser
|
14
|
+
|
13
15
|
|
14
16
|
def pytest_addoption(parser: Parser) -> None:
|
17
|
+
def add_ini_option(
|
18
|
+
opt_type: (
|
19
|
+
Literal["string", "paths", "pathlist", "args", "linelist", "bool"] | None
|
20
|
+
),
|
21
|
+
) -> None:
|
22
|
+
parser.addini(
|
23
|
+
group.options[-1].names()[0][2:],
|
24
|
+
group.options[-1].attrs()["help"],
|
25
|
+
opt_type,
|
26
|
+
)
|
27
|
+
|
15
28
|
group = parser.getgroup("typeguard")
|
16
29
|
group.addoption(
|
17
30
|
"--typeguard-packages",
|
@@ -19,11 +32,15 @@ def pytest_addoption(parser: Parser) -> None:
|
|
19
32
|
help="comma separated name list of packages and modules to instrument for "
|
20
33
|
"type checking, or :all: to instrument all modules loaded after typeguard",
|
21
34
|
)
|
35
|
+
add_ini_option("linelist")
|
36
|
+
|
22
37
|
group.addoption(
|
23
38
|
"--typeguard-debug-instrumentation",
|
24
39
|
action="store_true",
|
25
40
|
help="print all instrumented code to stderr",
|
26
41
|
)
|
42
|
+
add_ini_option("bool")
|
43
|
+
|
27
44
|
group.addoption(
|
28
45
|
"--typeguard-typecheck-fail-callback",
|
29
46
|
action="store",
|
@@ -33,6 +50,8 @@ def pytest_addoption(parser: Parser) -> None:
|
|
33
50
|
"handle a TypeCheckError"
|
34
51
|
),
|
35
52
|
)
|
53
|
+
add_ini_option("string")
|
54
|
+
|
36
55
|
group.addoption(
|
37
56
|
"--typeguard-forward-ref-policy",
|
38
57
|
action="store",
|
@@ -42,21 +61,31 @@ def pytest_addoption(parser: Parser) -> None:
|
|
42
61
|
"annotations"
|
43
62
|
),
|
44
63
|
)
|
64
|
+
add_ini_option("string")
|
65
|
+
|
45
66
|
group.addoption(
|
46
67
|
"--typeguard-collection-check-strategy",
|
47
68
|
action="store",
|
48
69
|
choices=list(CollectionCheckStrategy.__members__),
|
49
70
|
help="determines how thoroughly to check collections (list, dict, etc)",
|
50
71
|
)
|
72
|
+
add_ini_option("string")
|
51
73
|
|
52
74
|
|
53
75
|
def pytest_configure(config: Config) -> None:
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
76
|
+
def getoption(name: str) -> Any:
|
77
|
+
return config.getoption(name.replace("-", "_")) or config.getini(name)
|
78
|
+
|
79
|
+
packages: list[str] | None = []
|
80
|
+
if packages_option := config.getoption("typeguard_packages"):
|
81
|
+
packages = [pkg.strip() for pkg in packages_option.split(",")]
|
82
|
+
elif packages_ini := config.getini("typeguard-packages"):
|
83
|
+
packages = packages_ini
|
84
|
+
|
85
|
+
if packages:
|
86
|
+
if packages == [":all:"]:
|
87
|
+
packages = None
|
58
88
|
else:
|
59
|
-
packages = [pkg.strip() for pkg in packages_option.split(",")]
|
60
89
|
already_imported_packages = sorted(
|
61
90
|
package for package in packages if package in sys.modules
|
62
91
|
)
|
@@ -70,11 +99,11 @@ def pytest_configure(config: Config) -> None:
|
|
70
99
|
|
71
100
|
install_import_hook(packages=packages)
|
72
101
|
|
73
|
-
debug_option =
|
102
|
+
debug_option = getoption("typeguard-debug-instrumentation")
|
74
103
|
if debug_option:
|
75
104
|
global_config.debug_instrumentation = True
|
76
105
|
|
77
|
-
fail_callback_option =
|
106
|
+
fail_callback_option = getoption("typeguard-typecheck-fail-callback")
|
78
107
|
if fail_callback_option:
|
79
108
|
callback = resolve_reference(fail_callback_option)
|
80
109
|
if not callable(callback):
|
@@ -85,14 +114,12 @@ def pytest_configure(config: Config) -> None:
|
|
85
114
|
|
86
115
|
global_config.typecheck_fail_callback = callback
|
87
116
|
|
88
|
-
forward_ref_policy_option =
|
117
|
+
forward_ref_policy_option = getoption("typeguard-forward-ref-policy")
|
89
118
|
if forward_ref_policy_option:
|
90
119
|
forward_ref_policy = ForwardRefPolicy.__members__[forward_ref_policy_option]
|
91
120
|
global_config.forward_ref_policy = forward_ref_policy
|
92
121
|
|
93
|
-
collection_check_strategy_option =
|
94
|
-
"typeguard_collection_check_strategy"
|
95
|
-
)
|
122
|
+
collection_check_strategy_option = getoption("typeguard-collection-check-strategy")
|
96
123
|
if collection_check_strategy_option:
|
97
124
|
collection_check_strategy = CollectionCheckStrategy.__members__[
|
98
125
|
collection_check_strategy_option
|
@@ -20,17 +20,15 @@ type_checks_suppress_lock = Lock()
|
|
20
20
|
|
21
21
|
|
22
22
|
@overload
|
23
|
-
def suppress_type_checks(func: Callable[P, T]) -> Callable[P, T]:
|
24
|
-
...
|
23
|
+
def suppress_type_checks(func: Callable[P, T]) -> Callable[P, T]: ...
|
25
24
|
|
26
25
|
|
27
26
|
@overload
|
28
|
-
def suppress_type_checks() -> ContextManager[None]:
|
29
|
-
...
|
27
|
+
def suppress_type_checks() -> ContextManager[None]: ...
|
30
28
|
|
31
29
|
|
32
30
|
def suppress_type_checks(
|
33
|
-
func: Callable[P, T] | None = None
|
31
|
+
func: Callable[P, T] | None = None,
|
34
32
|
) -> Callable[P, T] | ContextManager[None]:
|
35
33
|
"""
|
36
34
|
Temporarily suppress all type checking.
|
@@ -37,6 +37,7 @@ from ast import (
|
|
37
37
|
Module,
|
38
38
|
Mult,
|
39
39
|
Name,
|
40
|
+
NamedExpr,
|
40
41
|
NodeTransformer,
|
41
42
|
NodeVisitor,
|
42
43
|
Pass,
|
@@ -45,7 +46,6 @@ from ast import (
|
|
45
46
|
RShift,
|
46
47
|
Starred,
|
47
48
|
Store,
|
48
|
-
Str,
|
49
49
|
Sub,
|
50
50
|
Subscript,
|
51
51
|
Tuple,
|
@@ -65,9 +65,6 @@ from copy import deepcopy
|
|
65
65
|
from dataclasses import dataclass, field
|
66
66
|
from typing import Any, ClassVar, cast, overload
|
67
67
|
|
68
|
-
if sys.version_info >= (3, 8):
|
69
|
-
from ast import NamedExpr
|
70
|
-
|
71
68
|
generator_names = (
|
72
69
|
"typing.Generator",
|
73
70
|
"collections.abc.Generator",
|
@@ -159,13 +156,12 @@ class TransformMemo:
|
|
159
156
|
if isinstance(child, ImportFrom) and child.module == "__future__":
|
160
157
|
# (module only) __future__ imports must come first
|
161
158
|
continue
|
162
|
-
elif
|
163
|
-
|
164
|
-
|
165
|
-
)
|
166
|
-
|
167
|
-
|
168
|
-
continue # docstring
|
159
|
+
elif (
|
160
|
+
isinstance(child, Expr)
|
161
|
+
and isinstance(child.value, Constant)
|
162
|
+
and isinstance(child.value.value, str)
|
163
|
+
):
|
164
|
+
continue # docstring
|
169
165
|
|
170
166
|
self.code_inject_index = index
|
171
167
|
break
|
@@ -349,15 +345,25 @@ class AnnotationTransformer(NodeTransformer):
|
|
349
345
|
def __init__(self, transformer: TypeguardTransformer):
|
350
346
|
self.transformer = transformer
|
351
347
|
self._memo = transformer._memo
|
348
|
+
self._level = 0
|
352
349
|
|
353
350
|
def visit(self, node: AST) -> Any:
|
351
|
+
# Don't process Literals
|
352
|
+
if isinstance(node, expr) and self._memo.name_matches(node, *literal_names):
|
353
|
+
return node
|
354
|
+
|
355
|
+
self._level += 1
|
354
356
|
new_node = super().visit(node)
|
357
|
+
self._level -= 1
|
358
|
+
|
355
359
|
if isinstance(new_node, Expression) and not hasattr(new_node, "body"):
|
356
360
|
return None
|
357
361
|
|
358
362
|
# Return None if this new node matches a variation of typing.Any
|
359
|
-
if
|
360
|
-
|
363
|
+
if (
|
364
|
+
self._level == 0
|
365
|
+
and isinstance(new_node, expr)
|
366
|
+
and self._memo.name_matches(new_node, *anytype_names)
|
361
367
|
):
|
362
368
|
return None
|
363
369
|
|
@@ -367,10 +373,18 @@ class AnnotationTransformer(NodeTransformer):
|
|
367
373
|
self.generic_visit(node)
|
368
374
|
|
369
375
|
if isinstance(node.op, BitOr):
|
370
|
-
# If either
|
376
|
+
# If either branch of the BinOp has been transformed to `None`, it means
|
377
|
+
# that a type in the union was ignored, so the entire annotation should e
|
378
|
+
# ignored
|
371
379
|
if not hasattr(node, "left") or not hasattr(node, "right"):
|
372
380
|
return None
|
373
381
|
|
382
|
+
# Return Any if either side is Any
|
383
|
+
if self._memo.name_matches(node.left, *anytype_names):
|
384
|
+
return node.left
|
385
|
+
elif self._memo.name_matches(node.right, *anytype_names):
|
386
|
+
return node.right
|
387
|
+
|
374
388
|
if sys.version_info < (3, 10):
|
375
389
|
union_name = self.transformer._get_import("typing", "Union")
|
376
390
|
return Subscript(
|
@@ -395,9 +409,9 @@ class AnnotationTransformer(NodeTransformer):
|
|
395
409
|
|
396
410
|
# The subscript of typing(_extensions).Literal can be any arbitrary string, so
|
397
411
|
# don't try to evaluate it as code
|
398
|
-
if
|
412
|
+
if node.slice:
|
399
413
|
if isinstance(node.slice, Index):
|
400
|
-
# Python 3.
|
414
|
+
# Python 3.8
|
401
415
|
slice_value = node.slice.value # type: ignore[attr-defined]
|
402
416
|
else:
|
403
417
|
slice_value = node.slice
|
@@ -408,20 +422,22 @@ class AnnotationTransformer(NodeTransformer):
|
|
408
422
|
# forward reference
|
409
423
|
items = cast(
|
410
424
|
typing.List[expr],
|
411
|
-
[self.
|
412
|
-
+ slice_value.elts[1:],
|
425
|
+
[self.visit(slice_value.elts[0])] + slice_value.elts[1:],
|
413
426
|
)
|
414
427
|
else:
|
415
428
|
items = cast(
|
416
429
|
typing.List[expr],
|
417
|
-
[self.
|
430
|
+
[self.visit(item) for item in slice_value.elts],
|
418
431
|
)
|
419
432
|
|
420
433
|
# If this is a Union and any of the items is Any, erase the entire
|
421
434
|
# annotation
|
422
435
|
if self._memo.name_matches(node.value, "typing.Union") and any(
|
423
|
-
|
424
|
-
|
436
|
+
item is None
|
437
|
+
or (
|
438
|
+
isinstance(item, expr)
|
439
|
+
and self._memo.name_matches(item, *anytype_names)
|
440
|
+
)
|
425
441
|
for item in items
|
426
442
|
):
|
427
443
|
return None
|
@@ -441,9 +457,11 @@ class AnnotationTransformer(NodeTransformer):
|
|
441
457
|
# If the transformer erased the slice entirely, just return the node
|
442
458
|
# value without the subscript (unless it's Optional, in which case erase
|
443
459
|
# the node entirely
|
444
|
-
if self._memo.name_matches(
|
460
|
+
if self._memo.name_matches(
|
461
|
+
node.value, "typing.Optional"
|
462
|
+
) and not hasattr(node, "slice"):
|
445
463
|
return None
|
446
|
-
|
464
|
+
if sys.version_info >= (3, 9) and not hasattr(node, "slice"):
|
447
465
|
return node.value
|
448
466
|
elif sys.version_info < (3, 9) and not hasattr(node.slice, "value"):
|
449
467
|
return node.value
|
@@ -477,15 +495,6 @@ class AnnotationTransformer(NodeTransformer):
|
|
477
495
|
|
478
496
|
return node
|
479
497
|
|
480
|
-
def visit_Str(self, node: Str) -> Any:
|
481
|
-
# Only used on Python 3.7
|
482
|
-
expression = ast.parse(node.s, mode="eval")
|
483
|
-
new_node = self.visit(expression)
|
484
|
-
if new_node:
|
485
|
-
return copy_location(new_node.body, node)
|
486
|
-
else:
|
487
|
-
return None
|
488
|
-
|
489
498
|
|
490
499
|
class TypeguardTransformer(NodeTransformer):
|
491
500
|
def __init__(
|
@@ -497,11 +506,32 @@ class TypeguardTransformer(NodeTransformer):
|
|
497
506
|
self.target_node: FunctionDef | AsyncFunctionDef | None = None
|
498
507
|
self.target_lineno = target_lineno
|
499
508
|
|
509
|
+
def generic_visit(self, node: AST) -> AST:
|
510
|
+
has_non_empty_body_initially = bool(getattr(node, "body", None))
|
511
|
+
initial_type = type(node)
|
512
|
+
|
513
|
+
node = super().generic_visit(node)
|
514
|
+
|
515
|
+
if (
|
516
|
+
type(node) is initial_type
|
517
|
+
and has_non_empty_body_initially
|
518
|
+
and hasattr(node, "body")
|
519
|
+
and not node.body
|
520
|
+
):
|
521
|
+
# If we have still the same node type after transformation
|
522
|
+
# but we've optimised it's body away, we add a `pass` statement.
|
523
|
+
node.body = [Pass()]
|
524
|
+
|
525
|
+
return node
|
526
|
+
|
500
527
|
@contextmanager
|
501
528
|
def _use_memo(
|
502
529
|
self, node: ClassDef | FunctionDef | AsyncFunctionDef
|
503
530
|
) -> Generator[None, Any, None]:
|
504
531
|
new_memo = TransformMemo(node, self._memo, self._memo.path + (node.name,))
|
532
|
+
old_memo = self._memo
|
533
|
+
self._memo = new_memo
|
534
|
+
|
505
535
|
if isinstance(node, (FunctionDef, AsyncFunctionDef)):
|
506
536
|
new_memo.should_instrument = (
|
507
537
|
self._target_path is None or new_memo.path == self._target_path
|
@@ -553,8 +583,6 @@ class TypeguardTransformer(NodeTransformer):
|
|
553
583
|
if isinstance(node, AsyncFunctionDef):
|
554
584
|
new_memo.is_async = True
|
555
585
|
|
556
|
-
old_memo = self._memo
|
557
|
-
self._memo = new_memo
|
558
586
|
yield
|
559
587
|
self._memo = old_memo
|
560
588
|
|
@@ -563,12 +591,10 @@ class TypeguardTransformer(NodeTransformer):
|
|
563
591
|
return memo.get_import(module, name)
|
564
592
|
|
565
593
|
@overload
|
566
|
-
def _convert_annotation(self, annotation: None) -> None:
|
567
|
-
...
|
594
|
+
def _convert_annotation(self, annotation: None) -> None: ...
|
568
595
|
|
569
596
|
@overload
|
570
|
-
def _convert_annotation(self, annotation: expr) -> expr:
|
571
|
-
...
|
597
|
+
def _convert_annotation(self, annotation: expr) -> expr: ...
|
572
598
|
|
573
599
|
def _convert_annotation(self, annotation: expr | None) -> expr | None:
|
574
600
|
if annotation is None:
|
@@ -591,8 +617,9 @@ class TypeguardTransformer(NodeTransformer):
|
|
591
617
|
return node
|
592
618
|
|
593
619
|
def visit_Module(self, node: Module) -> Module:
|
620
|
+
self._module_memo = self._memo = TransformMemo(node, None, ())
|
594
621
|
self.generic_visit(node)
|
595
|
-
self.
|
622
|
+
self._module_memo.insert_imports(node)
|
596
623
|
|
597
624
|
fix_missing_locations(node)
|
598
625
|
return node
|
@@ -691,14 +718,12 @@ class TypeguardTransformer(NodeTransformer):
|
|
691
718
|
if self.target_lineno == first_lineno:
|
692
719
|
assert self.target_node is None
|
693
720
|
self.target_node = node
|
694
|
-
if node.decorator_list
|
721
|
+
if node.decorator_list:
|
695
722
|
self.target_lineno = node.decorator_list[0].lineno
|
696
723
|
else:
|
697
724
|
self.target_lineno = node.lineno
|
698
725
|
|
699
|
-
all_args = node.args.args + node.args.kwonlyargs
|
700
|
-
if sys.version_info >= (3, 8):
|
701
|
-
all_args.extend(node.args.posonlyargs)
|
726
|
+
all_args = node.args.args + node.args.kwonlyargs + node.args.posonlyargs
|
702
727
|
|
703
728
|
# Ensure that any type shadowed by the positional or keyword-only
|
704
729
|
# argument names are ignored in this function
|
@@ -895,6 +920,22 @@ class TypeguardTransformer(NodeTransformer):
|
|
895
920
|
|
896
921
|
self._memo.insert_imports(node)
|
897
922
|
|
923
|
+
# Special case the __new__() method to create a local alias from the
|
924
|
+
# class name to the first argument (usually "cls")
|
925
|
+
if (
|
926
|
+
isinstance(node, FunctionDef)
|
927
|
+
and node.args
|
928
|
+
and self._memo.parent is not None
|
929
|
+
and isinstance(self._memo.parent.node, ClassDef)
|
930
|
+
and node.name == "__new__"
|
931
|
+
):
|
932
|
+
first_args_expr = Name(node.args.args[0].arg, ctx=Load())
|
933
|
+
cls_name = Name(self._memo.parent.node.name, ctx=Store())
|
934
|
+
node.body.insert(
|
935
|
+
self._memo.code_inject_index,
|
936
|
+
Assign([cls_name], first_args_expr),
|
937
|
+
)
|
938
|
+
|
898
939
|
# Rmove any placeholder "pass" at the end
|
899
940
|
if isinstance(node.body[-1], Pass):
|
900
941
|
del node.body[-1]
|
@@ -1176,11 +1217,6 @@ class TypeguardTransformer(NodeTransformer):
|
|
1176
1217
|
"""
|
1177
1218
|
self.generic_visit(node)
|
1178
1219
|
|
1179
|
-
# Fix empty node body (caused by removal of classes/functions not on the target
|
1180
|
-
# path)
|
1181
|
-
if not node.body:
|
1182
|
-
node.body.append(Pass())
|
1183
|
-
|
1184
1220
|
if (
|
1185
1221
|
self._memo is self._module_memo
|
1186
1222
|
and isinstance(node.test, Name)
|
@@ -5,17 +5,27 @@ import sys
|
|
5
5
|
from importlib import import_module
|
6
6
|
from inspect import currentframe
|
7
7
|
from types import CodeType, FrameType, FunctionType
|
8
|
-
from typing import TYPE_CHECKING, Any, Callable, ForwardRef, Union, cast
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, ForwardRef, Union, cast, final
|
9
9
|
from weakref import WeakValueDictionary
|
10
10
|
|
11
11
|
if TYPE_CHECKING:
|
12
12
|
from ._memo import TypeCheckMemo
|
13
13
|
|
14
|
-
if sys.version_info >= (3,
|
14
|
+
if sys.version_info >= (3, 13):
|
15
15
|
from typing import get_args, get_origin
|
16
16
|
|
17
17
|
def evaluate_forwardref(forwardref: ForwardRef, memo: TypeCheckMemo) -> Any:
|
18
|
-
return forwardref._evaluate(
|
18
|
+
return forwardref._evaluate(
|
19
|
+
memo.globals, memo.locals, type_params=(), recursive_guard=frozenset()
|
20
|
+
)
|
21
|
+
|
22
|
+
elif sys.version_info >= (3, 10):
|
23
|
+
from typing import get_args, get_origin
|
24
|
+
|
25
|
+
def evaluate_forwardref(forwardref: ForwardRef, memo: TypeCheckMemo) -> Any:
|
26
|
+
return forwardref._evaluate(
|
27
|
+
memo.globals, memo.locals, recursive_guard=frozenset()
|
28
|
+
)
|
19
29
|
|
20
30
|
else:
|
21
31
|
from metaflow._vendor.typing_extensions import get_args, get_origin
|
@@ -47,12 +57,6 @@ else:
|
|
47
57
|
raise
|
48
58
|
|
49
59
|
|
50
|
-
if sys.version_info >= (3, 8):
|
51
|
-
from typing import final
|
52
|
-
else:
|
53
|
-
from metaflow._vendor.typing_extensions import final
|
54
|
-
|
55
|
-
|
56
60
|
_functions_map: WeakValueDictionary[CodeType, FunctionType] = WeakValueDictionary()
|
57
61
|
|
58
62
|
|