hypergumbo-lang-scip-python 8.1.0__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.
@@ -0,0 +1,117 @@
1
+ # python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ .env
9
+
10
+ # tooling
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ .hypothesis/
15
+
16
+ # hypergumbo
17
+ .hypergumbo/
18
+ hypergumbo_capsule/
19
+ hypergumbo.results.json
20
+ hypergumbo.results.*.json
21
+ slice.json
22
+ slice.*.json
23
+
24
+ # Agent configuration
25
+ **/*.local.json
26
+ **/*.local.md
27
+ **/.claude/cache/
28
+ **/.gemini/cache/
29
+ **/.cursor/state/
30
+ **/*-session/
31
+ AUTONOMOUS_MODE.txt
32
+ autonomous_intent.txt
33
+ .agent/LOOP
34
+ .agent/disabled.LOOP
35
+ .agent/invariant-ledger.md
36
+ # WI-zonur edit-mode log (per-checkout, OS-owned by the human user; the agent
37
+ # can't unlink it, so it MUST never reach git or sync code paths).
38
+ .agent/tracker/.edit-mode/
39
+ .agent/tracker-workspace/.edit-mode/
40
+ # Defense-in-depth: the previous (now-fixed) placement was inside .ops/. Match
41
+ # any stray .edit-mode/ subdir so a stale checkout doesn't re-introduce the
42
+ # files that PR #4045 accidentally committed.
43
+ .agent/tracker/.ops/.edit-mode/
44
+ .agent/tracker-workspace/.ops/.edit-mode/
45
+ # Per-session transcript pipeline (ADR-0018, per-session amendment 2026-04-08).
46
+ # Each session writes per-session-keyed files. The .last_*/.second_to_last_*
47
+ # global slots are written at session END by rotate-on-session-end.sh.
48
+ .agent/.current_session_transcript.*.jsonl
49
+ .agent/.current_injection_history.*.jsonl
50
+ .agent/.transcript-sync.*.pid
51
+ .agent/.transcript-sync-state.*.json
52
+ .agent/.transcript-poll-state.*
53
+ .agent/.transcript-injection-state.*.json
54
+ .agent/.transcript-injection-state.*.lock
55
+ .agent/.last_session_transcript.jsonl
56
+ .agent/.second_to_last_transcript.jsonl
57
+ .agent/.last_injection_history.jsonl
58
+ .agent/.second_to_last_injection_history.jsonl
59
+ .agent/.archived-transcripts/
60
+
61
+ # Plaintext secret list consumed by .agent/hooks/_shared/scrub-secrets.py at
62
+ # every transcript-retention point. Holds real credentials -- never commit it.
63
+ # A committed .example sibling documents the format.
64
+ .secrets_for_scrubbing_upon_archive.txt
65
+
66
+ # Atomic-replace temp files from scrub_secrets.py. A SIGKILL mid-scrub leaves
67
+ # one behind holding transcript content; never commit it.
68
+ .agent/.scrub-*
69
+ .agent/.rotation.lock
70
+ # Legacy paths from before the per-session amendment (ignored for one-time
71
+ # upgrade-cleanup safety; may be removed once no repo still has these).
72
+ .agent/.current_session_transcript.jsonl
73
+ .agent/.transcript-sync.pid
74
+ .agent/.transcript-sync-state.json
75
+ .agent/.transcript-poll-state
76
+ .agent/.transcript-injection-state.json
77
+ .agent/.transcript-session-token
78
+ .agent/.current_injection_history.jsonl
79
+ hook-canary.txt
80
+
81
+ # Coverage
82
+ .coverage
83
+ .coverage.*
84
+ htmlcov/
85
+ coverage-report.txt
86
+
87
+ # Snapshot reports (pytest-textual-snapshot)
88
+ snapshot_report.html
89
+
90
+ # Node (bats testing)
91
+ node_modules/
92
+ package.json
93
+ package-lock.json
94
+
95
+ # htrac-frontend: allow tracked JS/TS project files
96
+ !packages/htrac-frontend/package.json
97
+ !packages/htrac-frontend/package-lock.json
98
+
99
+ # Hypergumbo cache
100
+ .hypergumbo_cache/
101
+ .ci/pytest-output.log
102
+ .ci/pytest-results.xml
103
+ .ci/smart-test-fallback.log
104
+ # Rewritten by the coverage-directed selector on every run (shadow phase).
105
+ .ci/selection-shadow.json
106
+
107
+ # Tracker
108
+ **/config.yaml
109
+ !**/config.yaml.template
110
+ .agent/.cache-*.db
111
+ .agent/.sync-logs/
112
+ .agent/.training-data.jsonl
113
+ .agent/.training-data-selected.jsonl
114
+ .agent/.training-data-v1-snapshot-*.jsonl
115
+ .agent/.deprecated-datasets/
116
+ .agent/finetuned-model/
117
+ .agent/transcript-model.gguf
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.5
2
+ Name: hypergumbo-lang-scip-python
3
+ Version: 8.1.0
4
+ Summary: SCIP-backed Python analyzer for hypergumbo (scip-python / pyright integration)
5
+ Author: Hypergumbo contributors
6
+ License: AGPL-3.0-or-later
7
+ Keywords: code-graph,pyright,python,scip,static-analysis
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3 :: Only
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: hypergumbo-core==8.1.0
14
+ Requires-Dist: hypergumbo-lang-mainstream==8.1.0
15
+ Description-Content-Type: text/markdown
16
+
17
+ <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
18
+ # hypergumbo-lang-scip-python
19
+
20
+ SCIP-backed Python analyzer for hypergumbo, driven by
21
+ [scip-python](https://github.com/sourcegraph/scip-python) (pyright).
22
+
23
+ This optional package is the second opt-in fidelity backend (after
24
+ `hypergumbo-lang-rust-analyzer`) and the first that **executes nothing** from
25
+ the analysed repository: pyright performs static inference only. It runs
26
+ *beside* the ast-based `python` analyzer, never instead of it — the two
27
+ producers' records for one declaration are folded into one node by the
28
+ ADR-0057 merge pass, and every disagreement stays visible in the provenance
29
+ slot.
30
+
31
+ ## What it adds, measured
32
+
33
+ On hypergumbo-core's own 179 source files (2026-09-19, scip-python 0.6.6):
34
+ the syntax arm left 4,133 method-call receivers untyped (`obj.method()` with
35
+ `obj` of unknown module); scip-python typed **3,973 of them (96.1%)** — 3,840
36
+ to the stdlib (`builtins.str`, `dict`, `list`, `pathlib.Path`, `re.Pattern`, …),
37
+ 96 in-repo, 37 third-party. That module is what `hypergumbo verify-claims`'s
38
+ I/O-boundary and taint verdicts key on. The Rust backend measured zero
39
+ receivers typed.
40
+
41
+ ## Enabling it
42
+
43
+ ```
44
+ npm install -g @sourcegraph/scip-python@0.6.6 # the producer (node + npm)
45
+ pipx install 'hypergumbo[scip-python]' # this wrapper
46
+ hypergumbo survey . --backend scip-python # one run
47
+ ```
48
+
49
+ Durably, as a preference in either ADR-0045 config tier (allowed because the
50
+ backend executes nothing):
51
+
52
+ ```toml
53
+ # $XDG_CONFIG_HOME/hypergumbo/config.toml or <repo>/.hypergumbo.toml
54
+ [backends]
55
+ scip_python = true
56
+ ```
57
+
58
+ `HYPERGUMBO_SCIP_PYTHON=1` is the environment spelling; `--backend tree-sitter`
59
+ turns every opt-in backend off for one run. Precedence: flag > environment >
60
+ project config > user config.
61
+
62
+ When enabled but the binary or this package is missing, the CLI exits 2 with
63
+ the install line rather than silently falling through.
64
+
65
+ ## What the translation does with scip-python's output
66
+
67
+ - Global definitions become `Symbol`s through the shared importer
68
+ (`hypergumbo_core.scip`); scip-python declares no `Document.language` and
69
+ no `SymbolInformation.kind`, so the importer reads the file extension and
70
+ the SCIP descriptor grammar instead.
71
+ - Parameter symbols and the per-module `__init__:` declaration are dropped:
72
+ the syntax arm models neither, and a node nothing can pair with is noise.
73
+ - References to in-repo definitions become `calls` / `references` edges.
74
+ - References to **external** callables (stdlib, third-party) become external
75
+ call edges carrying the receiver's module — `python:pathlib.Path:0-0:glob:unresolved`
76
+ with a structured `dst_ref` — the same shape the syntax arm mints when it
77
+ knows the module, so the two arms are comparable at every call site.
78
+
79
+ ## Recorded fixture
80
+
81
+ `recorded/sample_project/` is a three-file package and the `index.scip`
82
+ scip-python 0.6.6 emitted for it (`metadata.project_root` normalised). Every
83
+ cross-backend test reads that recording, never anything derived from the
84
+ syntax arm's own output (ADR-0057 §12).
@@ -0,0 +1,68 @@
1
+ <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
2
+ # hypergumbo-lang-scip-python
3
+
4
+ SCIP-backed Python analyzer for hypergumbo, driven by
5
+ [scip-python](https://github.com/sourcegraph/scip-python) (pyright).
6
+
7
+ This optional package is the second opt-in fidelity backend (after
8
+ `hypergumbo-lang-rust-analyzer`) and the first that **executes nothing** from
9
+ the analysed repository: pyright performs static inference only. It runs
10
+ *beside* the ast-based `python` analyzer, never instead of it — the two
11
+ producers' records for one declaration are folded into one node by the
12
+ ADR-0057 merge pass, and every disagreement stays visible in the provenance
13
+ slot.
14
+
15
+ ## What it adds, measured
16
+
17
+ On hypergumbo-core's own 179 source files (2026-09-19, scip-python 0.6.6):
18
+ the syntax arm left 4,133 method-call receivers untyped (`obj.method()` with
19
+ `obj` of unknown module); scip-python typed **3,973 of them (96.1%)** — 3,840
20
+ to the stdlib (`builtins.str`, `dict`, `list`, `pathlib.Path`, `re.Pattern`, …),
21
+ 96 in-repo, 37 third-party. That module is what `hypergumbo verify-claims`'s
22
+ I/O-boundary and taint verdicts key on. The Rust backend measured zero
23
+ receivers typed.
24
+
25
+ ## Enabling it
26
+
27
+ ```
28
+ npm install -g @sourcegraph/scip-python@0.6.6 # the producer (node + npm)
29
+ pipx install 'hypergumbo[scip-python]' # this wrapper
30
+ hypergumbo survey . --backend scip-python # one run
31
+ ```
32
+
33
+ Durably, as a preference in either ADR-0045 config tier (allowed because the
34
+ backend executes nothing):
35
+
36
+ ```toml
37
+ # $XDG_CONFIG_HOME/hypergumbo/config.toml or <repo>/.hypergumbo.toml
38
+ [backends]
39
+ scip_python = true
40
+ ```
41
+
42
+ `HYPERGUMBO_SCIP_PYTHON=1` is the environment spelling; `--backend tree-sitter`
43
+ turns every opt-in backend off for one run. Precedence: flag > environment >
44
+ project config > user config.
45
+
46
+ When enabled but the binary or this package is missing, the CLI exits 2 with
47
+ the install line rather than silently falling through.
48
+
49
+ ## What the translation does with scip-python's output
50
+
51
+ - Global definitions become `Symbol`s through the shared importer
52
+ (`hypergumbo_core.scip`); scip-python declares no `Document.language` and
53
+ no `SymbolInformation.kind`, so the importer reads the file extension and
54
+ the SCIP descriptor grammar instead.
55
+ - Parameter symbols and the per-module `__init__:` declaration are dropped:
56
+ the syntax arm models neither, and a node nothing can pair with is noise.
57
+ - References to in-repo definitions become `calls` / `references` edges.
58
+ - References to **external** callables (stdlib, third-party) become external
59
+ call edges carrying the receiver's module — `python:pathlib.Path:0-0:glob:unresolved`
60
+ with a structured `dst_ref` — the same shape the syntax arm mints when it
61
+ knows the module, so the two arms are comparable at every call site.
62
+
63
+ ## Recorded fixture
64
+
65
+ `recorded/sample_project/` is a three-file package and the `index.scip`
66
+ scip-python 0.6.6 emitted for it (`metadata.project_root` normalised). Every
67
+ cross-backend test reads that recording, never anything derived from the
68
+ syntax arm's own output (ADR-0057 §12).
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.24"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "hypergumbo-lang-scip-python"
7
+ version = "8.1.0"
8
+ description = "SCIP-backed Python analyzer for hypergumbo (scip-python / pyright integration)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "AGPL-3.0-or-later" }
12
+ authors = [{ name = "Hypergumbo contributors" }]
13
+ keywords = ["static-analysis", "code-graph", "python", "pyright", "scip"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3 :: Only",
19
+ ]
20
+ dependencies = [
21
+ "hypergumbo-core==8.1.0",
22
+ "hypergumbo-lang-mainstream==8.1.0",
23
+ ]
24
+
25
+ [project.entry-points."hypergumbo.analyzers"]
26
+ scip_python = "hypergumbo_lang_scip_python:ANALYZER_MODULES"
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["src/hypergumbo_lang_scip_python"]
30
+
31
+ [tool.ruff]
32
+ target-version = "py310"
33
+ line-length = 100
34
+ src = ["src", "tests"]
35
+
36
+ [tool.ruff.lint]
37
+ select = ["E", "W", "F", "B", "C4", "S", "RUF"]
38
+ ignore = ["E501", "S101", "S105", "S106", "S110", "RUF059", "RUF005", "B028"]
39
+
40
+ [tool.ruff.lint.per-file-ignores]
41
+ "tests/**/*.py" = ["S101", "S105", "S106", "S603", "S108", "E741", "F401", "F841", "RUF005"]
@@ -0,0 +1,152 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ """Recorded producer-shaped output of scip-python 0.6.6 (ADR-0057 §12, WI-nanom).
3
+
4
+ scip-python is an npm package that is not installed in CI, so every
5
+ cross-backend test for the Python arms consumes RECORDED output of the real
6
+ producer rather than anything derived from the syntax arm's own records
7
+ (a control that cannot fail is not a control). This module is the one
8
+ place that recording is exposed; it lives under the scip-python package's
9
+ ``recorded/`` directory (owned by the producer's package, not shipped in
10
+ its wheel) and is on pytest's ``pythonpath`` so core, mainstream and
11
+ scip-python tests import it by its bare name.
12
+
13
+ ONE RECORDING: ``sample_project/`` — a three-file package (``pkg/__init__.py``,
14
+ ``pkg/shapes.py``, ``pkg/app.py``: a class with methods and a property, a
15
+ module constant, a free function, a cross-file import and call, and calls on
16
+ stdlib receivers — ``str.upper``, ``list.append``, ``str.strip``,
17
+ ``Path.glob``, ``re.compile``, ``Pattern.search``, ``Match.group``) beside
18
+ the ``index.scip`` that ``scip-python index . --project-name sample_project
19
+ --project-version 0.1.0`` (v0.6.6, node 20) emitted for it on 2026-09-19.
20
+ The index is committed RAW (protobuf, 10 KB); the one edit is
21
+ ``metadata.project_root``, rewritten from the recording machine's absolute
22
+ path to ``file:///sample_project``. Re-record (2 s) rather than edit.
23
+
24
+ What the recording pins about the producer, read off the bytes:
25
+
26
+ * ``Document.language`` is EMPTY on every document and
27
+ ``SymbolInformation.kind`` is 0 on every symbol — the two silences the
28
+ shared importer now fills from the file extension and the descriptor
29
+ grammar (PR #1082).
30
+ * Every global Definition occurrence's ``range`` is the identifier TOKEN
31
+ (single-line), so this arm's ``span_role`` is ``token``.
32
+ * Parameters are GLOBAL symbols (``main().(argv)``), one per parameter, and
33
+ every module carries a META ``__init__:`` declaration — both dropped by
34
+ ``translate_scip_python_to_hg`` because the syntax arm models neither.
35
+ * Occurrences on stdlib receivers name the DEFINING class:
36
+ ``builtins/str#upper().``, ``pathlib/Path#glob().``, ``re/Pattern#search().``.
37
+ """
38
+ from __future__ import annotations
39
+
40
+ from pathlib import Path
41
+
42
+ _HERE = Path(__file__).resolve().parent
43
+
44
+ PRODUCER_VERSION = "0.6.6"
45
+
46
+
47
+ def sample_project_root() -> Path:
48
+ """The committed package the index was recorded on."""
49
+ return _HERE / "sample_project"
50
+
51
+
52
+ def sample_project_index_bytes() -> bytes:
53
+ """The recorded ``index.scip``, exactly as ``translate_scip_python_to_hg`` reads it."""
54
+ return (_HERE / "sample_project" / "index.scip").read_bytes()
55
+
56
+
57
+ #: Global symbols in the recording, by the descriptor's leaf kind.
58
+ SAMPLE_PROJECT_COUNTS = {
59
+ "documents": 3,
60
+ "global_symbols": 24,
61
+ "parameter_symbols": 9,
62
+ "module_declarations": 3,
63
+ "external_stdlib_occurrences": 29,
64
+ }
65
+
66
+ # What the two Python arms do with the recording (ADR-0057 §3/§5/§13/§14), as
67
+ # the fixture tests pin them and `hypergumbo backend-agreement` reports them.
68
+ # The translation keeps 11 of the 24 global symbols: 9 parameters and 3 module
69
+ # declarations are dropped, and `Shape#tags` (an annotated `self.tags = []`)
70
+ # has no Definition occurrence in the recording, so the importer never mints
71
+ # it. Every one of the syntax arm's 10 non-file records pairs; the SCIP-only
72
+ # leftover is the `name` field (`self.name = name`), which the syntax arm
73
+ # emits no Symbol for.
74
+ SAMPLE_PROJECT_PAIRING = {
75
+ "scip_symbols": 11,
76
+ "paired": 10,
77
+ "ambiguous": 0,
78
+ "unpaired_field": 1,
79
+ }
80
+ # Per attribute over the 10 paired records: (agree, disagree, python only, scip_python only).
81
+ # `name`: the four methods are `Shape.x` here and `x` there. `is_exported`:
82
+ # one-sided to the incumbent on ALL 10 — `py.py` computes exportedness and the
83
+ # SCIP arm computes none, so only the incumbent supplies a value.
84
+ #
85
+ # WAS 6 of 10 UNTIL WI-kohah, and the four missing ones were the METHODS. This
86
+ # comment used to read "for which neither arm has a rule: since INV-kubup the
87
+ # field abstains (`None`)" — an accurate description of a PRODUCER GAP that the
88
+ # fixture had been recording as though it were a property of the comparison.
89
+ # py.py now decides a method's exportedness conjunctively (the enclosing class's
90
+ # verdict AND the method not being private-by-name), so the incumbent supplies
91
+ # all 10 and the count is one-sided for the same reason at every record rather
92
+ # than for two different reasons at six and four.
93
+ # `span`: token vs item, by construction.
94
+ # `stable_id`: contested on all 10, because the arms hash different things. It read 8 / 2-one-sided
95
+ # while the harness skipped the kind backstop a survey runs before the merge:
96
+ # the 2 were the syntax arm's variables, reaching the merge with no id
97
+ # (WI-paluk). This follows from the survey's code path; it is not a live measurement,
98
+ # because scip-python is not installed where this was pinned.
99
+ SAMPLE_PROJECT_ATTRIBUTE_AGREEMENT = {
100
+ "docstring": (0, 0, 2, 0),
101
+ "is_exported": (0, 0, 10, 0),
102
+ "kind": (10, 0, 0, 0),
103
+ "name": (6, 4, 0, 0),
104
+ "qualified_name": (0, 0, 8, 0),
105
+ "signature": (0, 0, 7, 0),
106
+ "span": (0, 10, 0, 0),
107
+ "stable_id": (0, 10, 0, 0),
108
+ }
109
+ # Per (edge type, resolved) after the fold: (both, python only, scip_python only).
110
+ # External `calls` BOTH is 8: the two sites where the syntax arm already knew
111
+ # the module (`pathlib.Path.glob`, `builtins.sorted`) fold on identical ids
112
+ # under §11, and the six module-less stubs are absorbed by their typed twins
113
+ # under §15 — a partial external key matched by a complete one. scip_python-only
114
+ # is 0 BECAUSE of that absorption: before §15 those six twins had no partner,
115
+ # and one call carried two edges.
116
+ SAMPLE_PROJECT_EDGE_OVERLAP = {
117
+ ("calls", True): (3, 0, 1),
118
+ ("calls", False): (8, 5, 0),
119
+ ("imports", True): (0, 2, 0),
120
+ ("imports", False): (0, 2, 0),
121
+ ("instantiates", True): (0, 1, 0),
122
+ ("references", True): (2, 0, 3),
123
+ }
124
+ # The external callees scip-python types, as (caller, dst id, call_construct, line).
125
+ SAMPLE_PROJECT_TYPED_EXTERNALS = [
126
+ ("describe", "python:builtins.str:0-0:join:unresolved", "method", 29),
127
+ ("label", "python:builtins.str:0-0:upper:unresolved", "method", 17),
128
+ ("list_configs", "python:builtins:0-0:sorted:unresolved", "function", 33),
129
+ ("list_configs", "python:pathlib.Path:0-0:glob:unresolved", "method", 33),
130
+ ("main", "python:re.Match:0-0:group:unresolved", "method", 17),
131
+ ("main", "python:re.Pattern:0-0:search:unresolved", "method", 15),
132
+ ("tag", "python:builtins.list:0-0:append:unresolved", "method", 23),
133
+ ("tag", "python:builtins.str:0-0:strip:unresolved", "method", 23),
134
+ ]
135
+ # The syntax arm's module-less stubs (`python:external:0-0:<name>:unresolved`)
136
+ # and what happens to each: six are ABSORBED by the typed twin the SCIP arm
137
+ # emits at the same site (§15, WI-hupod) and survive as one edge carrying the
138
+ # stated module and both origins; `label` is a property the SCIP arm RESOLVES
139
+ # in-repo, so no twin states a module and the stub is superseded instead (§14).
140
+ # Seven stubs in, one sentinel stub out.
141
+ SAMPLE_PROJECT_MODULE_LESS_STUBS = ["append", "group", "join", "label", "search", "strip", "upper"]
142
+ #: What each absorbed stub's survivor states, as (callee, module path). The six
143
+ #: names here are the six of MODULE_LESS_STUBS that a typed twin reaches.
144
+ SAMPLE_PROJECT_ABSORBED = [
145
+ ("append", "builtins.list"), ("group", "re.Match"), ("join", "builtins.str"),
146
+ ("search", "re.Pattern"), ("strip", "builtins.str"), ("upper", "builtins.str"),
147
+ ]
148
+ SAMPLE_PROJECT_SUPERSEDED = 1
149
+ #: §13: the six §15 absorptions pair two distinct pathways, as do the seven
150
+ #: §11 folds on identical ids.
151
+ SAMPLE_PROJECT_CORROBORATED = 13
152
+ SAMPLE_PROJECT_EXTERNAL_FOLDS = 6
@@ -0,0 +1,2 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ """A sample package recorded for the scip-python backend fixture."""
@@ -0,0 +1,18 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ """Cross-file calls: import, instantiate, call methods, and a stdlib receiver."""
3
+ import re
4
+
5
+ from pkg.shapes import Shape, describe
6
+
7
+
8
+ PATTERN = re.compile(r"\d+")
9
+
10
+
11
+ def main(argv: list[str]) -> int:
12
+ shape = Shape(argv[0] if argv else "unit")
13
+ shape.tag(" first ")
14
+ text = describe(shape)
15
+ match = PATTERN.search(text)
16
+ if match is not None:
17
+ return int(match.group(0))
18
+ return len(shape.tags)
@@ -0,0 +1,33 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ """Shapes: a class with methods, a property, a constant and a free function."""
3
+ from pathlib import Path
4
+
5
+ UNIT = 1.0
6
+
7
+
8
+ class Shape:
9
+ """A named shape."""
10
+
11
+ def __init__(self, name: str) -> None:
12
+ self.name = name
13
+ self.tags: list[str] = []
14
+
15
+ @property
16
+ def label(self) -> str:
17
+ return self.name.upper()
18
+
19
+ def area(self) -> float:
20
+ return UNIT
21
+
22
+ def tag(self, value: str) -> None:
23
+ self.tags.append(value.strip())
24
+
25
+
26
+ def describe(shape: Shape) -> str:
27
+ """Free function calling a method and a stdlib method on a typed receiver."""
28
+ parts = [shape.label, str(shape.area())]
29
+ return " ".join(parts)
30
+
31
+
32
+ def list_configs(root: Path) -> list[Path]:
33
+ return sorted(root.glob("*.toml"))
@@ -0,0 +1,42 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ """Hypergumbo SCIP-backed Python analyzer (scip-python / pyright), WI-nanom.
3
+
4
+ The second opt-in fidelity backend and the first that executes nothing from
5
+ the analysed repository. Its parts mirror ``hypergumbo_lang_rust_analyzer``:
6
+
7
+ - ``invoke.py`` shells out to ``scip-python index`` to produce a SCIP blob.
8
+ - ``translate.py`` turns that blob into ``(symbols, edges)`` through the
9
+ shared importer, plus the one thing the Rust arm never did: external
10
+ callees keep the receiver's MODULE.
11
+ - ``gate.py`` answers "did the user ask?" — flag > environment > config
12
+ tiers (a preference, ADR-0045 ruling 5) — and whether the binary is there.
13
+ - ``analyzer.py`` registers ``scip_python`` beside the ``python`` analyzer
14
+ with the merge anchor the ADR-0057 pass pairs on.
15
+ """
16
+ from hypergumbo_lang_scip_python.gate import should_use_scip_python_backend
17
+ from hypergumbo_lang_scip_python.invoke import (
18
+ ScipPythonError,
19
+ ScipPythonInvocationFailed,
20
+ ScipPythonNoOutput,
21
+ ScipPythonNotInstalled,
22
+ run_scip_python_index,
23
+ )
24
+ from hypergumbo_lang_scip_python.translate import translate_scip_python_to_hg
25
+
26
+ __version__ = "8.1.0"
27
+
28
+ #: Module paths for analyzer discovery via entry-points (ADR-0012 Step 1).
29
+ ANALYZER_MODULES = [
30
+ "hypergumbo_lang_scip_python.analyzer",
31
+ ]
32
+
33
+ __all__ = [
34
+ "ANALYZER_MODULES",
35
+ "ScipPythonError",
36
+ "ScipPythonInvocationFailed",
37
+ "ScipPythonNoOutput",
38
+ "ScipPythonNotInstalled",
39
+ "run_scip_python_index",
40
+ "should_use_scip_python_backend",
41
+ "translate_scip_python_to_hg",
42
+ ]