python-constricter 0.4.1__cp312-cp312-win32.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.
- constricter/__init__.py +55 -0
- constricter/__main__.py +26 -0
- constricter/_version.py +4 -0
- constricter/cli/__init__.py +2 -0
- constricter/cli/baseline.py +107 -0
- constricter/cli/collecting.py +54 -0
- constricter/cli/command.py +547 -0
- constricter/cli/config.py +322 -0
- constricter/cli/explain.py +104 -0
- constricter/cli/lsp/__init__.py +2 -0
- constricter/cli/lsp/connection.py +475 -0
- constricter/cli/lsp/edits.py +188 -0
- constricter/cli/lsp/guard.py +133 -0
- constricter/cli/lsp/hints.py +391 -0
- constricter/cli/lsp/protocol.py +192 -0
- constricter/cli/lsp/remembered.py +81 -0
- constricter/cli/lsp/stored.py +200 -0
- constricter/cli/options.py +799 -0
- constricter/cli/paths.py +151 -0
- constricter/cli/reading.py +36 -0
- constricter/cli/report.py +397 -0
- constricter/cli/rounds.py +328 -0
- constricter/cli/runs.py +90 -0
- constricter/cli/schedule.py +463 -0
- constricter/cli/traced.py +401 -0
- constricter/cli/workers.py +286 -0
- constricter/empty.py +66 -0
- constricter/fix/__init__.cp312-win32.pyd +0 -0
- constricter/fix/__init__.py +2 -0
- constricter/fix/core/__init__.cp312-win32.pyd +0 -0
- constricter/fix/core/__init__.py +2 -0
- constricter/fix/core/asked.cp312-win32.pyd +0 -0
- constricter/fix/core/asked.py +56 -0
- constricter/fix/core/fixes.cp312-win32.pyd +0 -0
- constricter/fix/core/fixes.py +317 -0
- constricter/fix/core/imports.cp312-win32.pyd +0 -0
- constricter/fix/core/imports.py +580 -0
- constricter/fix/core/inherited.cp312-win32.pyd +0 -0
- constricter/fix/core/inherited.py +311 -0
- constricter/fix/core/known.cp312-win32.pyd +0 -0
- constricter/fix/core/known.py +730 -0
- constricter/fix/core/signatures.cp312-win32.pyd +0 -0
- constricter/fix/core/signatures.py +132 -0
- constricter/fix/index/__init__.cp312-win32.pyd +0 -0
- constricter/fix/index/__init__.py +2 -0
- constricter/fix/index/awaits.cp312-win32.pyd +0 -0
- constricter/fix/index/awaits.py +90 -0
- constricter/fix/index/beyond.cp312-win32.pyd +0 -0
- constricter/fix/index/beyond.py +149 -0
- constricter/fix/index/callers.cp312-win32.pyd +0 -0
- constricter/fix/index/callers.py +155 -0
- constricter/fix/index/crossed.cp312-win32.pyd +0 -0
- constricter/fix/index/crossed.py +327 -0
- constricter/fix/index/decorated.cp312-win32.pyd +0 -0
- constricter/fix/index/decorated.py +140 -0
- constricter/fix/index/fixtures.cp312-win32.pyd +0 -0
- constricter/fix/index/fixtures.py +176 -0
- constricter/fix/index/linked.cp312-win32.pyd +0 -0
- constricter/fix/index/linked.py +142 -0
- constricter/fix/index/loose.cp312-win32.pyd +0 -0
- constricter/fix/index/loose.py +103 -0
- constricter/fix/index/managed.cp312-win32.pyd +0 -0
- constricter/fix/index/managed.py +63 -0
- constricter/fix/index/modules.cp312-win32.pyd +0 -0
- constricter/fix/index/modules.py +741 -0
- constricter/fix/index/offers.cp312-win32.pyd +0 -0
- constricter/fix/index/offers.py +252 -0
- constricter/fix/index/order.cp312-win32.pyd +0 -0
- constricter/fix/index/order.py +155 -0
- constricter/fix/index/origins.cp312-win32.pyd +0 -0
- constricter/fix/index/origins.py +238 -0
- constricter/fix/index/own_methods.cp312-win32.pyd +0 -0
- constricter/fix/index/own_methods.py +91 -0
- constricter/fix/index/own_overloads.cp312-win32.pyd +0 -0
- constricter/fix/index/own_overloads.py +70 -0
- constricter/fix/index/own_types.cp312-win32.pyd +0 -0
- constricter/fix/index/own_types.py +330 -0
- constricter/fix/index/params.cp312-win32.pyd +0 -0
- constricter/fix/index/params.py +81 -0
- constricter/fix/index/plain.cp312-win32.pyd +0 -0
- constricter/fix/index/plain.py +221 -0
- constricter/fix/index/project.cp312-win32.pyd +0 -0
- constricter/fix/index/project.py +797 -0
- constricter/fix/index/sides.cp312-win32.pyd +0 -0
- constricter/fix/index/sides.py +160 -0
- constricter/fix/index/strings.cp312-win32.pyd +0 -0
- constricter/fix/index/strings.py +46 -0
- constricter/fix/index/stubs/__init__.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/__init__.py +2 -0
- constricter/fix/index/stubs/atoms.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/atoms.py +425 -0
- constricter/fix/index/stubs/chained.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/chained.py +69 -0
- constricter/fix/index/stubs/classnames.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/classnames.py +124 -0
- constricter/fix/index/stubs/declared.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/declared.py +508 -0
- constricter/fix/index/stubs/installed.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/installed.py +425 -0
- constricter/fix/index/stubs/names.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/names.py +200 -0
- constricter/fix/index/stubs/read.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/read.py +70 -0
- constricter/fix/index/stubs/signatures.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/signatures.py +656 -0
- constricter/fix/index/stubs/stubbed.cp312-win32.pyd +0 -0
- constricter/fix/index/stubs/stubbed.py +208 -0
- constricter/fix/index/taken.cp312-win32.pyd +0 -0
- constricter/fix/index/taken.py +45 -0
- constricter/fix/index/tuples.cp312-win32.pyd +0 -0
- constricter/fix/index/tuples.py +112 -0
- constricter/fix/libraries/__init__.cp312-win32.pyd +0 -0
- constricter/fix/libraries/__init__.py +2 -0
- constricter/fix/libraries/library.cp312-win32.pyd +0 -0
- constricter/fix/libraries/library.py +420 -0
- constricter/fix/libraries/opened.cp312-win32.pyd +0 -0
- constricter/fix/libraries/opened.py +147 -0
- constricter/fix/libraries/overloads.cp312-win32.pyd +0 -0
- constricter/fix/libraries/overloads.py +960 -0
- constricter/fix/libraries/receivers.cp312-win32.pyd +0 -0
- constricter/fix/libraries/receivers.py +274 -0
- constricter/fix/libraries/stdlib.cp312-win32.pyd +0 -0
- constricter/fix/libraries/stdlib.py +752 -0
- constricter/fix/libraries/walks.cp312-win32.pyd +0 -0
- constricter/fix/libraries/walks.py +49 -0
- constricter/fix/tables/aliases.json +147 -0
- constricter/fix/tables/attributes.json +700 -0
- constricter/fix/tables/awaited.json +69 -0
- constricter/fix/tables/awaited_overloads.json +14 -0
- constricter/fix/tables/bases.json +888 -0
- constricter/fix/tables/classes.json +1941 -0
- constricter/fix/tables/elements.json +156 -0
- constricter/fix/tables/functions.json +58 -0
- constricter/fix/tables/generic_attributes.json +254 -0
- constricter/fix/tables/method_overloads.json +461 -0
- constricter/fix/tables/method_signatures.json +954 -0
- constricter/fix/tables/methods.json +954 -0
- constricter/fix/tables/overloads.json +540 -0
- constricter/fix/tables/platform.json +37 -0
- constricter/fix/tables/returns.json +1362 -0
- constricter/fix/tables/scalar_members.json +16 -0
- constricter/fix/tables/scalars.json +2707 -0
- constricter/fix/tables/source.json +28 -0
- constricter/fix/tables/subscriptable.json +77 -0
- constricter/fix/tables/type_parameters.json +178 -0
- constricter/fix/tables/variables.json +2962 -0
- constricter/fix/values/__init__.cp312-win32.pyd +0 -0
- constricter/fix/values/__init__.py +2 -0
- constricter/fix/values/aliased.cp312-win32.pyd +0 -0
- constricter/fix/values/aliased.py +195 -0
- constricter/fix/values/bodies.cp312-win32.pyd +0 -0
- constricter/fix/values/bodies.py +76 -0
- constricter/fix/values/callables.cp312-win32.pyd +0 -0
- constricter/fix/values/callables.py +323 -0
- constricter/fix/values/called.cp312-win32.pyd +0 -0
- constricter/fix/values/called.py +194 -0
- constricter/fix/values/classvars.cp312-win32.pyd +0 -0
- constricter/fix/values/classvars.py +629 -0
- constricter/fix/values/decided.cp312-win32.pyd +0 -0
- constricter/fix/values/decided.py +429 -0
- constricter/fix/values/displays.cp312-win32.pyd +0 -0
- constricter/fix/values/displays.py +101 -0
- constricter/fix/values/doubts.cp312-win32.pyd +0 -0
- constricter/fix/values/doubts.py +677 -0
- constricter/fix/values/entered.cp312-win32.pyd +0 -0
- constricter/fix/values/entered.py +332 -0
- constricter/fix/values/fills.cp312-win32.pyd +0 -0
- constricter/fix/values/fills.py +446 -0
- constricter/fix/values/guesses.cp312-win32.pyd +0 -0
- constricter/fix/values/guesses.py +376 -0
- constricter/fix/values/hinted.cp312-win32.pyd +0 -0
- constricter/fix/values/hinted.py +811 -0
- constricter/fix/values/inference.cp312-win32.pyd +0 -0
- constricter/fix/values/inference.py +698 -0
- constricter/fix/values/loops.cp312-win32.pyd +0 -0
- constricter/fix/values/loops.py +335 -0
- constricter/fix/values/members.cp312-win32.pyd +0 -0
- constricter/fix/values/members.py +578 -0
- constricter/fix/values/narrowed.cp312-win32.pyd +0 -0
- constricter/fix/values/narrowed.py +220 -0
- constricter/fix/values/operated.cp312-win32.pyd +0 -0
- constricter/fix/values/operated.py +202 -0
- constricter/fix/values/ordered.cp312-win32.pyd +0 -0
- constricter/fix/values/ordered.py +74 -0
- constricter/fix/values/returned.cp312-win32.pyd +0 -0
- constricter/fix/values/returned.py +479 -0
- constricter/fix/values/returns.cp312-win32.pyd +0 -0
- constricter/fix/values/returns.py +237 -0
- constricter/fix/values/shapes.cp312-win32.pyd +0 -0
- constricter/fix/values/shapes.py +654 -0
- constricter/fix/values/stored.cp312-win32.pyd +0 -0
- constricter/fix/values/stored.py +564 -0
- constricter/fix/values/targets.cp312-win32.pyd +0 -0
- constricter/fix/values/targets.py +419 -0
- constricter/fix/values/unchecked.cp312-win32.pyd +0 -0
- constricter/fix/values/unchecked.py +278 -0
- constricter/jsonc.py +50 -0
- constricter/noqa.py +47 -0
- constricter/notebook.py +115 -0
- constricter/offences.py +436 -0
- constricter/overrides.py +24 -0
- constricter/plugins/__init__.py +2 -0
- constricter/plugins/flake8.py +133 -0
- constricter/plugins/pylint.py +186 -0
- constricter/py.typed +0 -0
- constricter/recording.py +660 -0
- constricter/rules/__init__.cp312-win32.pyd +0 -0
- constricter/rules/__init__.py +2 -0
- constricter/rules/annotations.cp312-win32.pyd +0 -0
- constricter/rules/annotations.py +296 -0
- constricter/rules/binding.cp312-win32.pyd +0 -0
- constricter/rules/binding.py +652 -0
- constricter/rules/calls.cp312-win32.pyd +0 -0
- constricter/rules/calls.py +460 -0
- constricter/rules/checker.cp312-win32.pyd +0 -0
- constricter/rules/checker.py +536 -0
- constricter/rules/declarations.cp312-win32.pyd +0 -0
- constricter/rules/declarations.py +730 -0
- constricter/rules/decorators.cp312-win32.pyd +0 -0
- constricter/rules/decorators.py +351 -0
- constricter/rules/flow.cp312-win32.pyd +0 -0
- constricter/rules/flow.py +502 -0
- constricter/rules/keys.cp312-win32.pyd +0 -0
- constricter/rules/keys.py +79 -0
- constricter/rules/late.cp312-win32.pyd +0 -0
- constricter/rules/late.py +969 -0
- constricter/rules/narrowing.cp312-win32.pyd +0 -0
- constricter/rules/narrowing.py +98 -0
- constricter/rules/parsed.cp312-win32.pyd +0 -0
- constricter/rules/parsed.py +136 -0
- constricter/rules/quoted.cp312-win32.pyd +0 -0
- constricter/rules/quoted.py +141 -0
- constricter/rules/rebinding.cp312-win32.pyd +0 -0
- constricter/rules/rebinding.py +169 -0
- constricter/rules/recorded.cp312-win32.pyd +0 -0
- constricter/rules/recorded.py +168 -0
- constricter/rules/redundant.cp312-win32.pyd +0 -0
- constricter/rules/redundant.py +160 -0
- constricter/rules/scope.cp312-win32.pyd +0 -0
- constricter/rules/scope.py +802 -0
- constricter/rules/scoped.cp312-win32.pyd +0 -0
- constricter/rules/scoped.py +232 -0
- constricter/rules/scoping.cp312-win32.pyd +0 -0
- constricter/rules/scoping.py +346 -0
- constricter/rules/settings.cp312-win32.pyd +0 -0
- constricter/rules/settings.py +189 -0
- constricter/rules/syntax.cp312-win32.pyd +0 -0
- constricter/rules/syntax.py +472 -0
- constricter/rules/tables.cp312-win32.pyd +0 -0
- constricter/rules/tables.py +169 -0
- constricter/rules/walked.cp312-win32.pyd +0 -0
- constricter/rules/walked.py +127 -0
- constricter/rules/widened.cp312-win32.pyd +0 -0
- constricter/rules/widened.py +322 -0
- constricter/trace.py +374 -0
- e45ce06b2fdd5c43f782__mypyc.cp312-win32.pyd +0 -0
- python_constricter-0.4.1.dist-info/METADATA +400 -0
- python_constricter-0.4.1.dist-info/RECORD +261 -0
- python_constricter-0.4.1.dist-info/WHEEL +4 -0
- python_constricter-0.4.1.dist-info/entry_points.txt +5 -0
- python_constricter-0.4.1.dist-info/licenses/LICENSE.md +21 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Return types the language fixes: builtins', and `str`, `bytes`, `list`, `set` and `dict` methods'."""
|
|
3
|
+
|
|
4
|
+
import ast
|
|
5
|
+
from typing import Final
|
|
6
|
+
|
|
7
|
+
from constricter.fix.values.targets import sole
|
|
8
|
+
|
|
9
|
+
# Builtins whose return type is fixed by the language, whatever their argument: safe to infer, not
|
|
10
|
+
# a guess (unlike a capitalised call, which could really be a generic class or a factory function).
|
|
11
|
+
BUILTIN_RETURNS: Final = {
|
|
12
|
+
"all": "bool",
|
|
13
|
+
"any": "bool",
|
|
14
|
+
"ascii": "str",
|
|
15
|
+
"bin": "str",
|
|
16
|
+
"bool": "bool",
|
|
17
|
+
"bytearray": "bytearray",
|
|
18
|
+
"bytes": "bytes",
|
|
19
|
+
"callable": "bool",
|
|
20
|
+
"chr": "str",
|
|
21
|
+
"complex": "complex",
|
|
22
|
+
"dir": "list[str]",
|
|
23
|
+
"float": "float",
|
|
24
|
+
"format": "str",
|
|
25
|
+
"hasattr": "bool",
|
|
26
|
+
"hash": "int",
|
|
27
|
+
"hex": "str",
|
|
28
|
+
"id": "int",
|
|
29
|
+
"input": "str",
|
|
30
|
+
"int": "int",
|
|
31
|
+
"isinstance": "bool",
|
|
32
|
+
"issubclass": "bool",
|
|
33
|
+
"len": "int",
|
|
34
|
+
"object": "object",
|
|
35
|
+
"oct": "str",
|
|
36
|
+
"ord": "int",
|
|
37
|
+
"range": "range",
|
|
38
|
+
"repr": "str",
|
|
39
|
+
"str": "str",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# `str`/`bytes` methods whose return type is fixed by the language, whatever their arguments: safe
|
|
44
|
+
# to infer for a call on an already-typed local, not a guess.
|
|
45
|
+
_STR_METHODS: Final = {
|
|
46
|
+
"capitalize": "str",
|
|
47
|
+
"casefold": "str",
|
|
48
|
+
"center": "str",
|
|
49
|
+
"count": "int",
|
|
50
|
+
"encode": "bytes",
|
|
51
|
+
"endswith": "bool",
|
|
52
|
+
"expandtabs": "str",
|
|
53
|
+
"find": "int",
|
|
54
|
+
"format": "str",
|
|
55
|
+
"format_map": "str",
|
|
56
|
+
"index": "int",
|
|
57
|
+
"isalnum": "bool",
|
|
58
|
+
"isalpha": "bool",
|
|
59
|
+
"isascii": "bool",
|
|
60
|
+
"isdecimal": "bool",
|
|
61
|
+
"isdigit": "bool",
|
|
62
|
+
"isidentifier": "bool",
|
|
63
|
+
"islower": "bool",
|
|
64
|
+
"isnumeric": "bool",
|
|
65
|
+
"isprintable": "bool",
|
|
66
|
+
"isspace": "bool",
|
|
67
|
+
"istitle": "bool",
|
|
68
|
+
"isupper": "bool",
|
|
69
|
+
"join": "str",
|
|
70
|
+
"ljust": "str",
|
|
71
|
+
"lower": "str",
|
|
72
|
+
"lstrip": "str",
|
|
73
|
+
"partition": "tuple[str, str, str]",
|
|
74
|
+
"removeprefix": "str",
|
|
75
|
+
"removesuffix": "str",
|
|
76
|
+
"replace": "str",
|
|
77
|
+
"rfind": "int",
|
|
78
|
+
"rindex": "int",
|
|
79
|
+
"rjust": "str",
|
|
80
|
+
"rpartition": "tuple[str, str, str]",
|
|
81
|
+
"rsplit": "list[str]",
|
|
82
|
+
"rstrip": "str",
|
|
83
|
+
"split": "list[str]",
|
|
84
|
+
"splitlines": "list[str]",
|
|
85
|
+
"startswith": "bool",
|
|
86
|
+
"strip": "str",
|
|
87
|
+
"swapcase": "str",
|
|
88
|
+
"title": "str",
|
|
89
|
+
"translate": "str",
|
|
90
|
+
"upper": "str",
|
|
91
|
+
"zfill": "str",
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
_BYTES_METHODS: Final = {
|
|
96
|
+
"capitalize": "bytes",
|
|
97
|
+
"center": "bytes",
|
|
98
|
+
"count": "int",
|
|
99
|
+
"decode": "str",
|
|
100
|
+
"endswith": "bool",
|
|
101
|
+
"expandtabs": "bytes",
|
|
102
|
+
"find": "int",
|
|
103
|
+
"hex": "str",
|
|
104
|
+
"index": "int",
|
|
105
|
+
"isalnum": "bool",
|
|
106
|
+
"isalpha": "bool",
|
|
107
|
+
"isascii": "bool",
|
|
108
|
+
"isdigit": "bool",
|
|
109
|
+
"islower": "bool",
|
|
110
|
+
"isspace": "bool",
|
|
111
|
+
"istitle": "bool",
|
|
112
|
+
"isupper": "bool",
|
|
113
|
+
"join": "bytes",
|
|
114
|
+
"ljust": "bytes",
|
|
115
|
+
"lower": "bytes",
|
|
116
|
+
"lstrip": "bytes",
|
|
117
|
+
"partition": "tuple[bytes, bytes, bytes]",
|
|
118
|
+
"removeprefix": "bytes",
|
|
119
|
+
"removesuffix": "bytes",
|
|
120
|
+
"replace": "bytes",
|
|
121
|
+
"rfind": "int",
|
|
122
|
+
"rindex": "int",
|
|
123
|
+
"rjust": "bytes",
|
|
124
|
+
"rpartition": "tuple[bytes, bytes, bytes]",
|
|
125
|
+
"rsplit": "list[bytes]",
|
|
126
|
+
"rstrip": "bytes",
|
|
127
|
+
"split": "list[bytes]",
|
|
128
|
+
"splitlines": "list[bytes]",
|
|
129
|
+
"startswith": "bool",
|
|
130
|
+
"strip": "bytes",
|
|
131
|
+
"swapcase": "bytes",
|
|
132
|
+
"title": "bytes",
|
|
133
|
+
"translate": "bytes",
|
|
134
|
+
"upper": "bytes",
|
|
135
|
+
"zfill": "bytes",
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
_INT_METHODS: Final = {
|
|
140
|
+
"as_integer_ratio": "tuple[int, int]",
|
|
141
|
+
"bit_count": "int",
|
|
142
|
+
"bit_length": "int",
|
|
143
|
+
"conjugate": "int",
|
|
144
|
+
"to_bytes": "bytes",
|
|
145
|
+
}
|
|
146
|
+
_FLOAT_METHODS: Final = {
|
|
147
|
+
"as_integer_ratio": "tuple[int, int]",
|
|
148
|
+
"conjugate": "float",
|
|
149
|
+
"hex": "str",
|
|
150
|
+
"is_integer": "bool",
|
|
151
|
+
}
|
|
152
|
+
METHOD_RETURNS: Final = {
|
|
153
|
+
"str": _STR_METHODS,
|
|
154
|
+
"bytes": _BYTES_METHODS,
|
|
155
|
+
"int": _INT_METHODS,
|
|
156
|
+
"float": _FLOAT_METHODS,
|
|
157
|
+
}
|
|
158
|
+
# Methods that give the same type whatever their container holds, and whatever they're passed.
|
|
159
|
+
_COUNTS: Final = frozenset({"count", "index"}) # a `list`'s or a `tuple`'s: an `int`
|
|
160
|
+
_SET_TESTS: Final = frozenset({"isdisjoint", "issubset", "issuperset"}) # a `bool`
|
|
161
|
+
_SET_KEEPS: Final = frozenset({"difference", "intersection"}) # the receiver's own type
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def element_method(root: ast.expr, receiver: str, call: ast.Call, method: str) -> str | None:
|
|
165
|
+
"""Infer a `list`, `set` or `dict` method call's type from the receiver's own type parameters.
|
|
166
|
+
|
|
167
|
+
`receiver` is the receiver's type as text, and `root` that parsed.
|
|
168
|
+
|
|
169
|
+
`copy()` is the receiver's type; `pop()` a `list`'s or `set`'s element (with an optional index
|
|
170
|
+
for a `list`); `pop(key)`, `setdefault(key, value)` and `get(key)` a `dict`'s value (`get` as
|
|
171
|
+
`V | None`); `popitem()` its `tuple[K, V]`. A call with any other arguments (`pop(key, default)`,
|
|
172
|
+
a keyword) can return something else, so it decides nothing.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
The annotation as source text, or `None` if the call doesn't decide one.
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
call_shape: tuple[str, int | None] = (method, None if call.keywords else len(call.args))
|
|
179
|
+
element: ast.expr
|
|
180
|
+
key: ast.expr
|
|
181
|
+
match root:
|
|
182
|
+
case ast.Subscript(value=ast.Name(id="list" | "List" | "set" | "Set" | "dict" | "Dict")) if (
|
|
183
|
+
call_shape == ("copy", 0)
|
|
184
|
+
):
|
|
185
|
+
return receiver
|
|
186
|
+
case ast.Subscript(value=ast.Name(id="list" | "List"), slice=element) if call_shape in {
|
|
187
|
+
("pop", 0),
|
|
188
|
+
("pop", 1),
|
|
189
|
+
}:
|
|
190
|
+
return ast.unparse(sole(element))
|
|
191
|
+
case ast.Subscript(value=ast.Name(id="set" | "Set"), slice=element) if call_shape == ("pop", 0):
|
|
192
|
+
return ast.unparse(sole(element))
|
|
193
|
+
case ast.Subscript(value=ast.Name(id="dict" | "Dict"), slice=ast.Tuple(elts=[key, element])):
|
|
194
|
+
return _dict_method(call_shape, key, element)
|
|
195
|
+
case _:
|
|
196
|
+
return None
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def uniform_method(root: ast.expr, receiver: str, method: str) -> str | None:
|
|
200
|
+
"""Infer a builtin container's method call that gives one type whatever it holds, or is passed.
|
|
201
|
+
|
|
202
|
+
A `list`'s or `tuple`'s `count` and `index` are `int`s, a `set`'s or `frozenset`'s `issubset`
|
|
203
|
+
and its like `bool`s, and its `difference` and `intersection` the receiver's own type.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
The annotation as source text, or `None` for any other method or receiver.
|
|
207
|
+
|
|
208
|
+
"""
|
|
209
|
+
match root:
|
|
210
|
+
case ast.Subscript(value=ast.Name(id="list" | "List" | "tuple" | "Tuple")) if method in _COUNTS:
|
|
211
|
+
return "int"
|
|
212
|
+
case ast.Subscript(value=ast.Name(id="set" | "Set" | "frozenset" | "FrozenSet")) if (
|
|
213
|
+
method in _SET_TESTS | _SET_KEEPS
|
|
214
|
+
):
|
|
215
|
+
return "bool" if method in _SET_TESTS else receiver
|
|
216
|
+
case _:
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _dict_method(call_shape: tuple[str, int | None], key: ast.expr, value: ast.expr) -> str | None:
|
|
221
|
+
"""Infer a `dict[key, value]` method call's type, by its name and positional argument count.
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
The annotation as source text, or `None` if the call doesn't decide one.
|
|
225
|
+
|
|
226
|
+
"""
|
|
227
|
+
match call_shape:
|
|
228
|
+
case ("pop", 1) | ("setdefault", 2):
|
|
229
|
+
return ast.unparse(value)
|
|
230
|
+
case ("get", 1) if not any(
|
|
231
|
+
isinstance(node, ast.Constant) and isinstance(node.value, str) for node in ast.walk(value)
|
|
232
|
+
): # a string (forward-reference) value type can't take `| None` where it's evaluated
|
|
233
|
+
return f"{ast.unparse(value)} | None"
|
|
234
|
+
case ("popitem", 0):
|
|
235
|
+
return f"tuple[{ast.unparse(key)}, {ast.unparse(value)}]"
|
|
236
|
+
case _:
|
|
237
|
+
return None
|
|
Binary file
|