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.
- hypergumbo_lang_scip_python-8.1.0/.gitignore +117 -0
- hypergumbo_lang_scip_python-8.1.0/PKG-INFO +84 -0
- hypergumbo_lang_scip_python-8.1.0/README.md +68 -0
- hypergumbo_lang_scip_python-8.1.0/pyproject.toml +41 -0
- hypergumbo_lang_scip_python-8.1.0/recorded/recorded_scip_python_0_6_6.py +152 -0
- hypergumbo_lang_scip_python-8.1.0/recorded/sample_project/index.scip +0 -0
- hypergumbo_lang_scip_python-8.1.0/recorded/sample_project/pkg/__init__.py +2 -0
- hypergumbo_lang_scip_python-8.1.0/recorded/sample_project/pkg/app.py +18 -0
- hypergumbo_lang_scip_python-8.1.0/recorded/sample_project/pkg/shapes.py +33 -0
- hypergumbo_lang_scip_python-8.1.0/src/hypergumbo_lang_scip_python/__init__.py +42 -0
- hypergumbo_lang_scip_python-8.1.0/src/hypergumbo_lang_scip_python/analyzer.py +141 -0
- hypergumbo_lang_scip_python-8.1.0/src/hypergumbo_lang_scip_python/gate.py +56 -0
- hypergumbo_lang_scip_python-8.1.0/src/hypergumbo_lang_scip_python/invoke.py +103 -0
- hypergumbo_lang_scip_python-8.1.0/src/hypergumbo_lang_scip_python/translate.py +133 -0
- hypergumbo_lang_scip_python-8.1.0/tests/test_scip_python_analyzer.py +110 -0
- hypergumbo_lang_scip_python-8.1.0/tests/test_scip_python_gate.py +44 -0
- hypergumbo_lang_scip_python-8.1.0/tests/test_scip_python_invoke.py +71 -0
- hypergumbo_lang_scip_python-8.1.0/tests/test_scip_python_recorded_fixtures.py +243 -0
- hypergumbo_lang_scip_python-8.1.0/tests/test_scip_python_translate.py +104 -0
|
@@ -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
|
|
Binary file
|
|
@@ -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
|
+
]
|