loomweave-plugin-python 1.3.1__tar.gz → 1.5.1__tar.gz
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.
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/.gitignore +3 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/PKG-INFO +43 -2
- loomweave_plugin_python-1.5.1/README.md +90 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/plugin.toml +33 -7
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/pyproject.toml +1 -1
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/__init__.py +1 -1
- loomweave_plugin_python-1.5.1/src/loomweave_plugin_python/call_resolver.py +140 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/extractor.py +1210 -40
- loomweave_plugin_python-1.5.1/src/loomweave_plugin_python/interpreter.py +100 -0
- loomweave_plugin_python-1.5.1/src/loomweave_plugin_python/pyright_session.py +2866 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/reference_resolver.py +3 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/server.py +35 -3
- loomweave_plugin_python-1.5.1/src/loomweave_plugin_python/wardline_descriptor.py +365 -0
- loomweave_plugin_python-1.5.1/tests/fixtures/wardline-vocabulary-descriptor.generic-3.preview.yaml +17 -0
- loomweave_plugin_python-1.5.1/tests/fixtures/wardline-vocabulary-descriptor.golden.yaml +14 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/test_extractor.py +1740 -88
- loomweave_plugin_python-1.5.1/tests/test_interpreter.py +193 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/test_package.py +25 -4
- loomweave_plugin_python-1.5.1/tests/test_pyright_session.py +4686 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/test_server.py +243 -4
- loomweave_plugin_python-1.5.1/tests/test_wardline_descriptor.py +560 -0
- loomweave_plugin_python-1.5.1/tests/test_wardline_vocabulary_descriptor_conformance.py +382 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/uv.lock +4 -4
- loomweave_plugin_python-1.3.1/README.md +0 -49
- loomweave_plugin_python-1.3.1/src/loomweave_plugin_python/call_resolver.py +0 -65
- loomweave_plugin_python-1.3.1/src/loomweave_plugin_python/pyright_session.py +0 -1787
- loomweave_plugin_python-1.3.1/src/loomweave_plugin_python/wardline_descriptor.py +0 -212
- loomweave_plugin_python-1.3.1/tests/test_pyright_session.py +0 -1620
- loomweave_plugin_python-1.3.1/tests/test_wardline_descriptor.py +0 -227
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/__main__.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/entity_id.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/py.typed +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/qualname.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/src/loomweave_plugin_python/stdout_guard.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/__init__.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/test_dogfood_uniqueness.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/test_entity_id.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/test_qualname.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/test_round_trip.py +0 -0
- {loomweave_plugin_python-1.3.1 → loomweave_plugin_python-1.5.1}/tests/test_stdout_guard.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: loomweave-plugin-python
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: Loomweave Python language plugin — v1.0 release
|
|
5
5
|
Author-email: John Morrissey <qacona@gmail.com>
|
|
6
6
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -59,6 +59,47 @@ pytest plugins/python
|
|
|
59
59
|
|
|
60
60
|
CI runs the same four gates in the `python-plugin` job.
|
|
61
61
|
|
|
62
|
+
## Interpreter discovery
|
|
63
|
+
|
|
64
|
+
`pyright-langserver` type-checks against whatever `python` it finds — the
|
|
65
|
+
plugin points it at the project's own interpreter deterministically, rather
|
|
66
|
+
than trusting whatever happened to be first on the launching process's
|
|
67
|
+
`PATH` (clarion-5cf9643de9). `discover_project_interpreter`
|
|
68
|
+
(`src/loomweave_plugin_python/interpreter.py`) walks a fixed order and stops
|
|
69
|
+
at the first usable candidate — a **regular** file (`Path.is_file()`) that
|
|
70
|
+
passes `os.access(path, os.X_OK)`:
|
|
71
|
+
|
|
72
|
+
| Rung | Source | Pinned? |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| 1 | `LOOMWEAVE_PYTHON_INTERPRETER` env var names an executable file | yes |
|
|
75
|
+
| 2 | `<project_root>/.venv/bin/python` | yes |
|
|
76
|
+
| 3 | `$VIRTUAL_ENV/bin/python` | yes |
|
|
77
|
+
| 4 | `$CONDA_PREFIX/bin/python` | yes |
|
|
78
|
+
| 5 | first `python` / `python3` on `PATH` | no |
|
|
79
|
+
| 6 | nothing found | no |
|
|
80
|
+
|
|
81
|
+
An empty env value counts as unset at every rung. The returned path is
|
|
82
|
+
absolute and lexically normalised but **never symlink-resolved** — a venv's
|
|
83
|
+
`bin/python` is typically a symlink to the base interpreter, and pyright
|
|
84
|
+
needs the symlink path to stay inside the venv's `site-packages`.
|
|
85
|
+
|
|
86
|
+
This order is a cross-language contract shared with the Rust host
|
|
87
|
+
(`crates/loomweave-core/src/plugin/interpreter.rs`); the host runs the same
|
|
88
|
+
discovery and, for a `[capabilities.runtime.pyright]` plugin, exports its
|
|
89
|
+
pinned answer to the child as `LOOMWEAVE_PYTHON_INTERPRETER` (unless the
|
|
90
|
+
operator already set it). The plugin's own discovery therefore sees the
|
|
91
|
+
host's choice at rung 1 whenever the host found one.
|
|
92
|
+
|
|
93
|
+
When discovery lands on rung 5 or 6 (no project-owned interpreter), an
|
|
94
|
+
otherwise-`complete` calls/references facet is honestly demoted to
|
|
95
|
+
`degraded` with reason `interpreter_unpinned` — cross-module call/reference
|
|
96
|
+
targets may be missing because pyright resolved against a guessed
|
|
97
|
+
interpreter, even though nothing else went wrong. Fix it by creating
|
|
98
|
+
`.venv` in the project root or setting `LOOMWEAVE_PYTHON_INTERPRETER` to the
|
|
99
|
+
project's interpreter. See
|
|
100
|
+
[ADR-058](../../docs/loomweave/adr/ADR-058-project-interpreter-discovery.md)
|
|
101
|
+
for the full design and the `interpreter_unpinned` coverage semantics.
|
|
102
|
+
|
|
62
103
|
## Design references
|
|
63
104
|
|
|
64
105
|
- [WP3 plan](../../docs/implementation/sprint-1/wp3-python-plugin.md) — task
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# loomweave-plugin-python
|
|
2
|
+
|
|
3
|
+
The Python language plugin for [Loomweave](../../README.md). Extracts Python
|
|
4
|
+
entities from source files and serves them to the Loomweave core over the
|
|
5
|
+
JSON-RPC protocol defined in [WP2 L4](../../docs/implementation/sprint-1/wp2-plugin-host.md#l4--json-rpc-method-set--content-length-framing).
|
|
6
|
+
|
|
7
|
+
**Status**: Python structural extractor. It emits modules, classes, functions,
|
|
8
|
+
`contains`, `calls`, `references`, `imports`, and versioned entity signatures
|
|
9
|
+
for Stable Entity Identity (SEI) matching. It also reads Wardline's NG-25
|
|
10
|
+
trust-vocabulary descriptor without importing Wardline and emits source-observed
|
|
11
|
+
Wardline decorator metadata/tags on decorated entities when a descriptor is
|
|
12
|
+
available.
|
|
13
|
+
|
|
14
|
+
## Install (development)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
python -m venv .venv
|
|
18
|
+
source .venv/bin/activate
|
|
19
|
+
pip install -e '.[dev]'
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This places `loomweave-plugin-python` on your `$PATH` and installs the
|
|
23
|
+
dev-time toolchain (`ruff`, `mypy`, `pytest`, `pytest-cov`, `pre-commit`).
|
|
24
|
+
|
|
25
|
+
## ADR-023 tooling gates
|
|
26
|
+
|
|
27
|
+
Every commit must pass all four:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
ruff check plugins/python
|
|
31
|
+
ruff format --check plugins/python
|
|
32
|
+
mypy --strict plugins/python
|
|
33
|
+
pytest plugins/python
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
CI runs the same four gates in the `python-plugin` job.
|
|
37
|
+
|
|
38
|
+
## Interpreter discovery
|
|
39
|
+
|
|
40
|
+
`pyright-langserver` type-checks against whatever `python` it finds — the
|
|
41
|
+
plugin points it at the project's own interpreter deterministically, rather
|
|
42
|
+
than trusting whatever happened to be first on the launching process's
|
|
43
|
+
`PATH` (clarion-5cf9643de9). `discover_project_interpreter`
|
|
44
|
+
(`src/loomweave_plugin_python/interpreter.py`) walks a fixed order and stops
|
|
45
|
+
at the first usable candidate — a **regular** file (`Path.is_file()`) that
|
|
46
|
+
passes `os.access(path, os.X_OK)`:
|
|
47
|
+
|
|
48
|
+
| Rung | Source | Pinned? |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| 1 | `LOOMWEAVE_PYTHON_INTERPRETER` env var names an executable file | yes |
|
|
51
|
+
| 2 | `<project_root>/.venv/bin/python` | yes |
|
|
52
|
+
| 3 | `$VIRTUAL_ENV/bin/python` | yes |
|
|
53
|
+
| 4 | `$CONDA_PREFIX/bin/python` | yes |
|
|
54
|
+
| 5 | first `python` / `python3` on `PATH` | no |
|
|
55
|
+
| 6 | nothing found | no |
|
|
56
|
+
|
|
57
|
+
An empty env value counts as unset at every rung. The returned path is
|
|
58
|
+
absolute and lexically normalised but **never symlink-resolved** — a venv's
|
|
59
|
+
`bin/python` is typically a symlink to the base interpreter, and pyright
|
|
60
|
+
needs the symlink path to stay inside the venv's `site-packages`.
|
|
61
|
+
|
|
62
|
+
This order is a cross-language contract shared with the Rust host
|
|
63
|
+
(`crates/loomweave-core/src/plugin/interpreter.rs`); the host runs the same
|
|
64
|
+
discovery and, for a `[capabilities.runtime.pyright]` plugin, exports its
|
|
65
|
+
pinned answer to the child as `LOOMWEAVE_PYTHON_INTERPRETER` (unless the
|
|
66
|
+
operator already set it). The plugin's own discovery therefore sees the
|
|
67
|
+
host's choice at rung 1 whenever the host found one.
|
|
68
|
+
|
|
69
|
+
When discovery lands on rung 5 or 6 (no project-owned interpreter), an
|
|
70
|
+
otherwise-`complete` calls/references facet is honestly demoted to
|
|
71
|
+
`degraded` with reason `interpreter_unpinned` — cross-module call/reference
|
|
72
|
+
targets may be missing because pyright resolved against a guessed
|
|
73
|
+
interpreter, even though nothing else went wrong. Fix it by creating
|
|
74
|
+
`.venv` in the project root or setting `LOOMWEAVE_PYTHON_INTERPRETER` to the
|
|
75
|
+
project's interpreter. See
|
|
76
|
+
[ADR-058](../../docs/loomweave/adr/ADR-058-project-interpreter-discovery.md)
|
|
77
|
+
for the full design and the `interpreter_unpinned` coverage semantics.
|
|
78
|
+
|
|
79
|
+
## Design references
|
|
80
|
+
|
|
81
|
+
- [WP3 plan](../../docs/implementation/sprint-1/wp3-python-plugin.md) — task
|
|
82
|
+
ledger, lock-ins, and UQ resolutions.
|
|
83
|
+
- [ADR-003](../../docs/loomweave/adr/ADR-003-entity-id-scheme.md) — 3-segment
|
|
84
|
+
`EntityId` format this plugin produces.
|
|
85
|
+
- [ADR-018](../../docs/loomweave/adr/ADR-018-identity-reconciliation.md) —
|
|
86
|
+
cross-product identity join with Wardline.
|
|
87
|
+
- [ADR-022](../../docs/loomweave/adr/ADR-022-core-plugin-ontology.md) —
|
|
88
|
+
manifest schema and ontology-boundary enforcement.
|
|
89
|
+
- [ADR-023](../../docs/loomweave/adr/ADR-023-tooling-baseline.md) — the four
|
|
90
|
+
Python gates and the `pre-commit` setup.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[plugin]
|
|
2
2
|
name = "loomweave-plugin-python"
|
|
3
3
|
plugin_id = "python"
|
|
4
|
-
version = "1.
|
|
4
|
+
version = "1.5.1"
|
|
5
5
|
protocol_version = "1.0"
|
|
6
6
|
# Bare basename per ADR-021 §Layer 1 + WP2 scrub commit eb0a41d — the host
|
|
7
7
|
# refuses manifests whose `executable` carries any path component.
|
|
@@ -10,10 +10,11 @@ language = "python"
|
|
|
10
10
|
extensions = ["py"]
|
|
11
11
|
|
|
12
12
|
[capabilities.runtime]
|
|
13
|
-
# Plugin's declared RSS envelope (MiB).
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
13
|
+
# Plugin's declared RSS envelope (MiB). For plugins declaring
|
|
14
|
+
# [capabilities.runtime.pyright] this documents resident memory only: the
|
|
15
|
+
# host applies its 8 GiB language-server RLIMIT_AS ceiling
|
|
16
|
+
# (LANGUAGE_SERVER_MAX_AS_MIB, ADR-021 §2d amendment) because pyright's
|
|
17
|
+
# Node/V8 process reserves virtual space far beyond its RSS.
|
|
17
18
|
expected_max_rss_mb = 2048
|
|
18
19
|
# Triggers LMWV-INFRA-PLUGIN-ENTITY-OVERRUN-WARNING well before the 500k
|
|
19
20
|
# core cap (warning emission itself is deferred to Tier B — Sprint 1
|
|
@@ -47,16 +48,41 @@ edge_kinds = ["contains", "calls", "references", "imports", "inherits_from", "de
|
|
|
47
48
|
rule_id_prefix = "LMWV-PY-"
|
|
48
49
|
# Bumps per ADR-027 when the entity/edge/rule set shifts. Phase 3 Task 3 is a
|
|
49
50
|
# MINOR bump (additive `imports` edge kind); 0.8.0 is the additive
|
|
50
|
-
# `inherits_from` + `decorates` MINOR bump (clarion-43416be550).
|
|
51
|
+
# `inherits_from` + `decorates` MINOR bump (clarion-43416be550); 0.9.0 is the
|
|
52
|
+
# additive `public-surface` reachability-root tag (clarion-4ec50f3d92) — a
|
|
53
|
+
# no-`__all__` library's public defs/classes are now tagged as roots; 0.10.0
|
|
54
|
+
# adds module-level `exported-api` for explicit `__all__` re-export/imported-name
|
|
55
|
+
# surfaces without double-counting local function/class exports, including
|
|
56
|
+
# literal `__all__ += [...]` extensions; 0.11.0 adds manual main-guard,
|
|
57
|
+
# runner-wrapper, `sys.argv`, and argparse `cli-command` tagging; 0.12.0
|
|
58
|
+
# declares the complete static classifier set so supported-empty results are
|
|
59
|
+
# distinguishable from unsupported classifiers and forces unchanged files to
|
|
60
|
+
# re-dispatch. Classifier declarations do not create entity-tag rows. NOTE:
|
|
51
61
|
# ADR-007's summary-cache key is the 5-tuple (entity_id, content_hash,
|
|
52
62
|
# prompt_template_id, model_tier, guidance_fingerprint) — ontology_version is
|
|
53
63
|
# handshake-validation, NOT a cache-key component. New edge rows miss the
|
|
54
64
|
# cache by component-1 of the 5-tuple organically (no edges live in the
|
|
55
65
|
# 5-tuple yet anyway).
|
|
56
|
-
ontology_version = "0.
|
|
66
|
+
ontology_version = "0.12.0"
|
|
67
|
+
classifier_tags = [
|
|
68
|
+
"cli-command",
|
|
69
|
+
"data-model",
|
|
70
|
+
"entry-point",
|
|
71
|
+
"exported-api",
|
|
72
|
+
"framework-handler",
|
|
73
|
+
"http-route",
|
|
74
|
+
"public-surface",
|
|
75
|
+
"test",
|
|
76
|
+
]
|
|
57
77
|
|
|
58
78
|
[integrations.wardline]
|
|
59
79
|
expected_descriptor_version = "wardline-generic-2"
|
|
80
|
+
# The dual-accept set, as `schema@version` PAIRS. A version-only list would
|
|
81
|
+
# destroy the schema/version association the gate rests on (re-admitting
|
|
82
|
+
# "version alone unlocks v2 parsing"). A space-separated STRING, never a TOML
|
|
83
|
+
# array: manifest.rs:137 deserialises this table as BTreeMap<String, String>,
|
|
84
|
+
# so an array value is a hard manifest-parse failure.
|
|
85
|
+
accepted_descriptors = "wardline.vocabulary/v1@wardline-generic-2 wardline.vocabulary/v2@wardline-generic-3"
|
|
60
86
|
|
|
61
87
|
[ontology.roles]
|
|
62
88
|
file_scope = ["module"]
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING, Literal, NotRequired, Protocol, TypedDict
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CallsEdgeProperties(TypedDict):
|
|
12
|
+
candidates: list[str]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CallsRawEdge(TypedDict):
|
|
16
|
+
kind: Literal["calls"]
|
|
17
|
+
from_id: str
|
|
18
|
+
to_id: str
|
|
19
|
+
source_byte_start: int
|
|
20
|
+
source_byte_end: int
|
|
21
|
+
confidence: Literal["resolved", "ambiguous"]
|
|
22
|
+
properties: NotRequired[CallsEdgeProperties]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Finding(TypedDict):
|
|
26
|
+
subcode: str
|
|
27
|
+
severity: Literal["info", "warning", "error"]
|
|
28
|
+
message: str
|
|
29
|
+
metadata: dict[str, object]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class UnresolvedCallSite(TypedDict):
|
|
33
|
+
caller_entity_id: str
|
|
34
|
+
site_ordinal: int
|
|
35
|
+
source_byte_start: int
|
|
36
|
+
source_byte_end: int
|
|
37
|
+
callee_expr: str
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class FacetCoverageWire(TypedDict):
|
|
41
|
+
"""Wire shape of one resolution facet's coverage claim (host contract)."""
|
|
42
|
+
|
|
43
|
+
status: Literal["complete", "degraded"]
|
|
44
|
+
reason: NotRequired[str]
|
|
45
|
+
transient: bool
|
|
46
|
+
collateral: bool
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class ResolutionCoverageWire(TypedDict):
|
|
50
|
+
calls: FacetCoverageWire
|
|
51
|
+
references: FacetCoverageWire
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(frozen=True)
|
|
55
|
+
class FacetCoverage:
|
|
56
|
+
"""How much of one resolution facet (calls / references) a file received.
|
|
57
|
+
|
|
58
|
+
The resolver degrades to EMPTY evidence -- not an error -- when pyright is
|
|
59
|
+
unavailable, times out, or has been poisoned for the rest of the run. The
|
|
60
|
+
host cannot tell that apart from a genuinely call-free file, so it treated
|
|
61
|
+
the empty result as a completed analysis and its incremental skip pinned
|
|
62
|
+
the hole for as long as the file's bytes stayed unchanged
|
|
63
|
+
(clarion-3e517d4aff). This claim rides every ``analyze_file`` result so the
|
|
64
|
+
host can re-dispatch a ``degraded`` + ``transient`` file next run and name
|
|
65
|
+
the hole on its read surface.
|
|
66
|
+
|
|
67
|
+
``transient`` is True when re-running the unchanged file could plausibly
|
|
68
|
+
recover coverage (resolver timeout, crash, poison, unavailable binary) and
|
|
69
|
+
False for content-determined limits a re-run would hit again (syntax
|
|
70
|
+
error, per-file site cap, nesting too complex).
|
|
71
|
+
|
|
72
|
+
``collateral`` (clarion-7fc41105ea, ADR-057) is decided by which catch-site
|
|
73
|
+
built the claim, never by message text. Self-inflicted (``False``) means
|
|
74
|
+
ONLY: ``pyright_timeout`` on this file's own budget, or
|
|
75
|
+
``pyright_transport_failure`` -- pyright died while THIS file's request was
|
|
76
|
+
in flight (``pyright_local_read_error``, a read error on an unrelated
|
|
77
|
+
target while pyright stayed alive, is also this file's gap). Everything
|
|
78
|
+
else is collateral (``True``): ``pyright_restarting`` (found dead on
|
|
79
|
+
arrival), ``pyright_spawn_failed`` (deferred spawn), and the run-disabled
|
|
80
|
+
tokens ``pyright_unavailable`` / ``pyright_poisoned`` /
|
|
81
|
+
``pyright_restart_cap_exceeded``. The full vocabulary is documented at the
|
|
82
|
+
top of ``pyright_session.py``.
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
status: Literal["complete", "degraded"] = "complete"
|
|
86
|
+
reason: str | None = None
|
|
87
|
+
transient: bool = False
|
|
88
|
+
# The hole predates this file (pyright already dead, spawn deferred, run
|
|
89
|
+
# disabled by an EARLIER file's failure): collateral, not this file's
|
|
90
|
+
# doing. The host dispatches collateral files first so the troublemaker
|
|
91
|
+
# goes last, and keeps a prior self-inflicted mark sticky across a
|
|
92
|
+
# collateral run.
|
|
93
|
+
collateral: bool = False
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def degraded(cls, reason: str, *, transient: bool, collateral: bool = False) -> FacetCoverage:
|
|
97
|
+
return cls(status="degraded", reason=reason, transient=transient, collateral=collateral)
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def is_degraded(self) -> bool:
|
|
101
|
+
return self.status == "degraded"
|
|
102
|
+
|
|
103
|
+
def to_wire(self) -> FacetCoverageWire:
|
|
104
|
+
wire: FacetCoverageWire = {
|
|
105
|
+
"status": self.status,
|
|
106
|
+
"transient": self.transient,
|
|
107
|
+
"collateral": self.collateral,
|
|
108
|
+
}
|
|
109
|
+
if self.reason is not None:
|
|
110
|
+
wire["reason"] = self.reason
|
|
111
|
+
return wire
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@dataclass
|
|
115
|
+
class CallResolutionResult:
|
|
116
|
+
edges: list[CallsRawEdge] = field(default_factory=list)
|
|
117
|
+
unresolved_call_sites_total: int = 0
|
|
118
|
+
unresolved_call_sites: list[UnresolvedCallSite] = field(default_factory=list)
|
|
119
|
+
pyright_query_latency_ms: list[int] = field(default_factory=list)
|
|
120
|
+
pyright_index_parse_latency_ms: list[int] = field(default_factory=list)
|
|
121
|
+
findings: list[Finding] = field(default_factory=list)
|
|
122
|
+
coverage: FacetCoverage = field(default_factory=FacetCoverage)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class CallResolver(Protocol):
|
|
126
|
+
def resolve_calls(
|
|
127
|
+
self,
|
|
128
|
+
file_path: str | Path,
|
|
129
|
+
function_ids: Sequence[str],
|
|
130
|
+
) -> CallResolutionResult: ...
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class NoOpCallResolver:
|
|
134
|
+
def resolve_calls(
|
|
135
|
+
self,
|
|
136
|
+
file_path: str | Path,
|
|
137
|
+
function_ids: Sequence[str],
|
|
138
|
+
) -> CallResolutionResult:
|
|
139
|
+
_ = (file_path, function_ids)
|
|
140
|
+
return CallResolutionResult()
|