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,221 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Which of the checked files' classes are plain, settled across them all.
|
|
3
|
+
|
|
4
|
+
See `constricter.fix.values.classvars`, which settles one module's.
|
|
5
|
+
|
|
6
|
+
A module alone can't see past a base another file defines: the index can, through imports and
|
|
7
|
+
re-exports, to what that base inherits from and what it declares.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from collections.abc import Mapping, Sequence
|
|
11
|
+
from dataclasses import replace
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import TYPE_CHECKING, Final
|
|
14
|
+
|
|
15
|
+
from constricter.fix.index.modules import SUFFIX, Index, Module, module_name
|
|
16
|
+
from constricter.fix.index.project import CLASS, definition
|
|
17
|
+
from constricter.fix.values import classvars
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from constricter.fix.core.known import Origin
|
|
21
|
+
|
|
22
|
+
_DOT: Final = "."
|
|
23
|
+
# The bases no class's binding of a name can hide: one a class above another binds is in sight.
|
|
24
|
+
_ROOTS: Final = frozenset({classvars.OBJECT, *classvars.BUILTIN_BASES, *classvars.PASSED_OVER})
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def settled(catalog: Index, entries: Sequence[str] = ()) -> Index:
|
|
28
|
+
"""Settle which of the checked files' classes are plain, across them all.
|
|
29
|
+
|
|
30
|
+
As `constricter.fix.values.classvars` has it for one module, a base another checked file defines
|
|
31
|
+
followed there: a class under another file's plain class is plain, and a class that isn't
|
|
32
|
+
makes what it inherits from, in any file, not plain either. A base `entries` list
|
|
33
|
+
(`classvars.listed`) is one a plain class may have even where a checked file defines it, plain
|
|
34
|
+
or not: the framework's own files, checked. So is one passed over (`classvars.PASSED_OVER`).
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
The index, each checked module with its plain classes.
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
found: dict[str, tuple[str, ...]] = {
|
|
41
|
+
f"{module.name}.{name}": tuple(resolved(catalog.modules, module, base) for base in bases)
|
|
42
|
+
for module in catalog.modules.values()
|
|
43
|
+
for name, bases in module.bases.items()
|
|
44
|
+
}
|
|
45
|
+
if not found:
|
|
46
|
+
return catalog
|
|
47
|
+
unlisted: dict[str, tuple[str, ...]] = {
|
|
48
|
+
name: tuple(
|
|
49
|
+
base
|
|
50
|
+
for base in bases
|
|
51
|
+
if base not in classvars.PASSED_OVER and not classvars.listed(base, entries)
|
|
52
|
+
)
|
|
53
|
+
for name, bases in found.items()
|
|
54
|
+
}
|
|
55
|
+
plain: frozenset[str] = classvars.settled(unlisted, classvars.allowed)
|
|
56
|
+
declared: dict[str, Mapping[str, str]] = {
|
|
57
|
+
f"{module.name}.{name}": module.classes.get(name, {})
|
|
58
|
+
for module in catalog.modules.values()
|
|
59
|
+
for name in module.bases
|
|
60
|
+
}
|
|
61
|
+
return _named(
|
|
62
|
+
catalog._replace(
|
|
63
|
+
modules={
|
|
64
|
+
name: replace(
|
|
65
|
+
module,
|
|
66
|
+
plain=frozenset(
|
|
67
|
+
each
|
|
68
|
+
for each in module.bases
|
|
69
|
+
if f"{name}.{each}" in plain and _unheld(f"{name}.{each}", module, found, declared)
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
for name, module in catalog.modules.items()
|
|
73
|
+
},
|
|
74
|
+
),
|
|
75
|
+
found,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _named(catalog: Index, found: Mapping[str, tuple[str, ...]]) -> Index:
|
|
80
|
+
"""Type a plain class's variables bound to a checked file's class by name (see `classvars.named`).
|
|
81
|
+
|
|
82
|
+
`type[Name]`, where no class above or under it in the checked files binds the variable: a type
|
|
83
|
+
checker holds an override to its base's type once both are declared. Only where every class
|
|
84
|
+
above it is a checked file's, or a builtin or `object`: a framework's base, or one only a star
|
|
85
|
+
import re-exports, may bind it out of sight. `found`: each checked class's bases, resolved.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
The index, each such module with them among its `members`.
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
binds: dict[str, frozenset[str]] = {
|
|
92
|
+
f"{module.name}.{name}": names
|
|
93
|
+
for module in catalog.modules.values()
|
|
94
|
+
for name, names in module.bound.items()
|
|
95
|
+
}
|
|
96
|
+
under: dict[str, set[str]] | None = None
|
|
97
|
+
modules: dict[str, Module] = dict(catalog.modules)
|
|
98
|
+
module: Module
|
|
99
|
+
for module in catalog.modules.values():
|
|
100
|
+
added: dict[str, dict[str, str]] = {}
|
|
101
|
+
owner: str
|
|
102
|
+
bound: Mapping[str, str]
|
|
103
|
+
for owner, bound in module.named.items():
|
|
104
|
+
key: str = f"{module.name}.{owner}"
|
|
105
|
+
variable: str
|
|
106
|
+
value: str
|
|
107
|
+
for variable, value in bound.items() if owner in module.plain else ():
|
|
108
|
+
if resolved(catalog.modules, module, value) not in found or not _closed(key, found):
|
|
109
|
+
continue
|
|
110
|
+
under = _under(found) if under is None else under
|
|
111
|
+
if not any(
|
|
112
|
+
variable in binds.get(other, ())
|
|
113
|
+
for other in (*classvars.ancestors(key, found), *under[key])
|
|
114
|
+
):
|
|
115
|
+
added.setdefault(owner, {})[variable] = f"type[{value}]"
|
|
116
|
+
if added:
|
|
117
|
+
typed: dict[str, Mapping[str, str]] = dict(module.members)
|
|
118
|
+
typed.update({owner: {**typed.get(owner, {}), **each} for owner, each in added.items()})
|
|
119
|
+
modules[module.name] = replace(module, members=typed)
|
|
120
|
+
return catalog._replace(modules=modules) if under is not None else catalog
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _closed(key: str, found: Mapping[str, tuple[str, ...]]) -> bool:
|
|
124
|
+
"""Check that every class above `key` is in sight: a checked file's, or a builtin or `object`.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Whether it is.
|
|
128
|
+
|
|
129
|
+
"""
|
|
130
|
+
return all(
|
|
131
|
+
base in found or base in _ROOTS
|
|
132
|
+
for owner in (key, *classvars.ancestors(key, found))
|
|
133
|
+
for base in found[owner]
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _under(found: Mapping[str, tuple[str, ...]]) -> dict[str, set[str]]:
|
|
138
|
+
"""Name every checked class under each one, however far.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
Them, by the class above.
|
|
142
|
+
|
|
143
|
+
"""
|
|
144
|
+
under: dict[str, set[str]] = {name: set() for name in found}
|
|
145
|
+
name: str
|
|
146
|
+
for name in found:
|
|
147
|
+
above: str
|
|
148
|
+
for above in classvars.ancestors(name, found):
|
|
149
|
+
under[above].add(name)
|
|
150
|
+
return under
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _unheld(
|
|
154
|
+
key: str,
|
|
155
|
+
module: Module,
|
|
156
|
+
found: Mapping[str, tuple[str, ...]],
|
|
157
|
+
declared: Mapping[str, Mapping[str, str]],
|
|
158
|
+
) -> bool:
|
|
159
|
+
"""Check that a class's variables are its own to type, whatever other files' classes it inherits from.
|
|
160
|
+
|
|
161
|
+
None hides what a builtin above it has itself, nor what a class above it annotates as another
|
|
162
|
+
type (see `constricter.fix.values.classvars`), which the class's own module can't see past its file.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Whether they are.
|
|
166
|
+
|
|
167
|
+
"""
|
|
168
|
+
typed: Mapping[str, str] = module.members.get(key.rpartition(_DOT)[2], {})
|
|
169
|
+
above: list[Mapping[str, str]] = [declared[each] for each in classvars.ancestors(key, found)]
|
|
170
|
+
return not typed.keys() & classvars.reserved(key, found) and classvars.agreeing(typed, above) == typed
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def resolved(modules: Mapping[str, Module], module: Module, base: str) -> str:
|
|
174
|
+
"""Resolve a class's base, as `module` writes it, to where it's defined (`pkg.models.Row`).
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
The defining module and the class, dotted, through imports and re-exports; as far as it's
|
|
178
|
+
known, for one no indexed module defines (`unittest.TestCase`).
|
|
179
|
+
|
|
180
|
+
"""
|
|
181
|
+
first: str
|
|
182
|
+
rest: str
|
|
183
|
+
first, _, rest = base.partition(_DOT)
|
|
184
|
+
if not rest and first in module.bases:
|
|
185
|
+
return f"{module.name}.{first}"
|
|
186
|
+
origin: Origin | None
|
|
187
|
+
if (origin := module.names.get(first)) is None:
|
|
188
|
+
return base
|
|
189
|
+
path: list[str] = [*([origin[0]] if origin[0] else []), *([origin[1]] if origin[1] else [])]
|
|
190
|
+
path += rest.split(_DOT) if rest else []
|
|
191
|
+
where: Origin = (_DOT.join(path[:-1]), path[-1])
|
|
192
|
+
defined: tuple[Module, str] | None = definition(modules, where, CLASS)
|
|
193
|
+
return _DOT.join(path) if defined is None else f"{defined[0].name}.{defined[1]}"
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def members(catalog: Index, path: Path) -> dict[str, Mapping[str, str]]:
|
|
197
|
+
"""Find what the index types the variables of the plain classes of the file at `path` as.
|
|
198
|
+
|
|
199
|
+
What the file alone types them as, and those bound to a checked file's class by name (`_named`).
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
Each class's, by its name; none for a file `catalog` doesn't have.
|
|
203
|
+
|
|
204
|
+
"""
|
|
205
|
+
target: Module | None = catalog.modules.get(module_name(path)) if path.suffix == SUFFIX else None
|
|
206
|
+
return (
|
|
207
|
+
{}
|
|
208
|
+
if target is None
|
|
209
|
+
else {name: target.members[name] for name in target.plain if name in target.members}
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def classes(catalog: Index, path: Path) -> frozenset[str] | None:
|
|
214
|
+
"""Find which classes of the file at `path` the index settled as plain (see `settled`).
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Their names; `None` for a file `catalog` doesn't have, whose own classes say.
|
|
218
|
+
|
|
219
|
+
"""
|
|
220
|
+
target: Module | None = catalog.modules.get(module_name(path)) if path.suffix == SUFFIX else None
|
|
221
|
+
return None if target is None else target.plain
|
|
Binary file
|