hypergumbo-lang-scip-python 9.0.0__tar.gz → 9.2.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.
Files changed (19) hide show
  1. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/.gitignore +1 -0
  2. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/PKG-INFO +3 -3
  3. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/pyproject.toml +3 -3
  4. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/src/hypergumbo_lang_scip_python/__init__.py +3 -2
  5. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/src/hypergumbo_lang_scip_python/analyzer.py +8 -2
  6. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/src/hypergumbo_lang_scip_python/invoke.py +29 -5
  7. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/tests/test_scip_python_analyzer.py +5 -1
  8. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/tests/test_scip_python_invoke.py +23 -1
  9. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/README.md +0 -0
  10. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/recorded/recorded_scip_python_0_6_6.py +0 -0
  11. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/recorded/sample_project/index.scip +0 -0
  12. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/recorded/sample_project/pkg/__init__.py +0 -0
  13. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/recorded/sample_project/pkg/app.py +0 -0
  14. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/recorded/sample_project/pkg/shapes.py +0 -0
  15. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/src/hypergumbo_lang_scip_python/gate.py +0 -0
  16. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/src/hypergumbo_lang_scip_python/translate.py +0 -0
  17. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/tests/test_scip_python_gate.py +0 -0
  18. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/tests/test_scip_python_recorded_fixtures.py +0 -0
  19. {hypergumbo_lang_scip_python-9.0.0 → hypergumbo_lang_scip_python-9.2.0}/tests/test_scip_python_translate.py +0 -0
@@ -15,6 +15,7 @@ build/
15
15
 
16
16
  # hypergumbo
17
17
  .hypergumbo/
18
+ .hypergumbo-examples/
18
19
  hypergumbo_capsule/
19
20
  hypergumbo.results.json
20
21
  hypergumbo.results.*.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hypergumbo-lang-scip-python
3
- Version: 9.0.0
3
+ Version: 9.2.0
4
4
  Summary: SCIP-backed Python analyzer for hypergumbo (scip-python / pyright integration)
5
5
  Author: Hypergumbo contributors
6
6
  License: AGPL-3.0-or-later
@@ -10,8 +10,8 @@ Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or l
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3 :: Only
12
12
  Requires-Python: >=3.10
13
- Requires-Dist: hypergumbo-core==9.0.0
14
- Requires-Dist: hypergumbo-lang-mainstream==9.0.0
13
+ Requires-Dist: hypergumbo-core==9.2.0
14
+ Requires-Dist: hypergumbo-lang-mainstream==9.2.0
15
15
  Description-Content-Type: text/markdown
16
16
 
17
17
  <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hypergumbo-lang-scip-python"
7
- version = "9.0.0"
7
+ version = "9.2.0"
8
8
  description = "SCIP-backed Python analyzer for hypergumbo (scip-python / pyright integration)"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -18,8 +18,8 @@ classifiers = [
18
18
  "Programming Language :: Python :: 3 :: Only",
19
19
  ]
20
20
  dependencies = [
21
- "hypergumbo-core==9.0.0",
22
- "hypergumbo-lang-mainstream==9.0.0",
21
+ "hypergumbo-core==9.2.0",
22
+ "hypergumbo-lang-mainstream==9.2.0",
23
23
  ]
24
24
 
25
25
  [project.entry-points."hypergumbo.analyzers"]
@@ -6,7 +6,8 @@ the analysed repository. Its parts mirror ``hypergumbo_lang_rust_analyzer``:
6
6
 
7
7
  - ``invoke.py`` shells out to ``scip-python index`` to produce a SCIP blob.
8
8
  - ``translate.py`` turns that blob into ``(symbols, edges)`` through the
9
- shared importer, plus the one thing the Rust arm never did: external
9
+ shared importer, plus two things the Rust arm never needed: it drops the
10
+ PARAMETER and META symbols the syntax arm never models, and external
10
11
  callees keep the receiver's MODULE.
11
12
  - ``gate.py`` answers "did the user ask?" — flag > environment > config
12
13
  tiers (a preference, ADR-0045 ruling 5) — and whether the binary is there.
@@ -23,7 +24,7 @@ from hypergumbo_lang_scip_python.invoke import (
23
24
  )
24
25
  from hypergumbo_lang_scip_python.translate import translate_scip_python_to_hg
25
26
 
26
- __version__ = "9.0.0"
27
+ __version__ = "9.2.0"
27
28
 
28
29
  #: Module paths for analyzer discovery via entry-points (ADR-0012 Step 1).
29
30
  ANALYZER_MODULES = [
@@ -19,7 +19,11 @@ with ``backend_disabled``, so the orchestrator records an honest
19
19
  writes no index, the corresponding pass-silence code travels with the skip
20
20
  (``dependency_unavailable`` / ``pass_crashed`` / ``unreported``) — the same
21
21
  discrimination WI-luvud gave the Rust arm. A completed run that produced
22
- nothing is NOT a skip: the pass ran, and says so.
22
+ nothing is NOT a skip: the pass ran, and says so -- as ``unreported`` when
23
+ the tree holds Python, since an empty index of a Python project says the
24
+ indexer saw no files, not that the files held nothing (WI-nijod: every run
25
+ indexed an empty scratch directory, and ``no_candidate_construct``, a
26
+ routine silence, hid it).
23
27
  """
24
28
  from __future__ import annotations
25
29
 
@@ -117,7 +121,9 @@ def analyze_python_with_scip_impl(
117
121
  f"scip-python backend produced no symbols for {repo_root} despite .py "
118
122
  f"files being present — likely a project scip-python could not index.",
119
123
  )
120
- run.silence_reason = silence_reason_for_candidates(symbols)
124
+ run.silence_reason = UNREPORTED
125
+ else:
126
+ run.silence_reason = silence_reason_for_candidates(symbols)
121
127
  return AnalysisResult(run=run, symbols=symbols, edges=edges)
122
128
 
123
129
 
@@ -1,14 +1,24 @@
1
1
  # SPDX-License-Identifier: AGPL-3.0-or-later
2
2
  """Shell-out wrapper for ``scip-python index`` (WI-nanom).
3
3
 
4
- ``scip-python index <project> --project-name NAME --output FILE`` writes a
5
- SCIP index for a Python project; pyright resolves the project's own
4
+ ``scip-python index --cwd <project> --project-name NAME --project-version 0
5
+ --output FILE`` writes a SCIP index for a Python project; pyright resolves the project's own
6
6
  modules and whatever is importable from the invoking interpreter's
7
7
  environment (so a project analysed inside its own virtualenv gets its
8
8
  dependencies typed too). It executes NOTHING from the project — static
9
9
  inference only — which is why this backend's opt-in is a preference and
10
10
  not a trust grant.
11
11
 
12
+ The project goes in ``--cwd``. scip-python 0.6.6 takes no positional
13
+ project: handed one, it ignores it, indexes its own working directory and
14
+ exits 0 -- and the subprocess runs in a scratch directory, so until WI-nijod
15
+ every run indexed that empty directory ("Total Project Files 0") and
16
+ returned a valid, empty index. The version is a constant: left out, it is
17
+ the project's git revision, and outside a git checkout the indexer crashes
18
+ on the first module (``normalizeNameOrVersion``). Nothing downstream reads
19
+ it -- translation keys on the descriptors -- and a constant keeps symbol
20
+ strings identical from one commit to the next.
21
+
12
22
  :func:`run_scip_python_index` confirms the binary resolves, runs it with
13
23
  stdout/stderr captured and a timeout, and returns the index bytes. Failure
14
24
  modes map to three exceptions the analyzer turns into pass-silence codes:
@@ -26,6 +36,14 @@ from typing import Any, Callable, Optional
26
36
  from hypergumbo_core.scip_python_install import SCIP_PYTHON_BINARY
27
37
 
28
38
 
39
+ #: V8's fatal-error text when the heap limit is reached. The default limit
40
+ #: (~4 GB) is too small for a large project: hypergumbo's own tree (1,712
41
+ #: files) aborted at 4.2 GB RSS and indexed in 306 s at 8.4 GB with
42
+ #: ``--max-old-space-size=9000`` (WI-nijod). The limit is the user's to set --
43
+ #: it is memory on their machine -- so the failure names the knob instead.
44
+ _NODE_HEAP_EXHAUSTED = b"JavaScript heap out of memory"
45
+
46
+
29
47
  class ScipPythonError(Exception):
30
48
  """Base class for :func:`run_scip_python_index` failures."""
31
49
 
@@ -77,8 +95,9 @@ def run_scip_python_index(
77
95
  )
78
96
  output = cwd / "index.scip"
79
97
  argv = [
80
- resolved, "index", str(project),
98
+ resolved, "index", "--cwd", str(project),
81
99
  "--project-name", project_name,
100
+ "--project-version", "0",
82
101
  "--output", str(output),
83
102
  ]
84
103
  run = runner if runner is not None else subprocess.run
@@ -92,9 +111,14 @@ def run_scip_python_index(
92
111
  f"scip-python index timed out after {timeout_sec:.0f}s on {project}", stderr,
93
112
  ) from exc
94
113
  if completed.returncode != 0:
114
+ stderr = completed.stderr or b""
115
+ hint = (
116
+ "; node ran out of heap -- raise it with NODE_OPTIONS=--max-old-space-size=<MB>"
117
+ if _NODE_HEAP_EXHAUSTED in stderr else ""
118
+ )
95
119
  raise ScipPythonInvocationFailed(
96
- f"scip-python index exited {completed.returncode} on {project}",
97
- completed.stderr or b"", returncode=completed.returncode,
120
+ f"scip-python index exited {completed.returncode} on {project}{hint}",
121
+ stderr, returncode=completed.returncode,
98
122
  )
99
123
  if not output.is_file():
100
124
  raise ScipPythonNoOutput(
@@ -100,7 +100,11 @@ class TestSuccess:
100
100
  )
101
101
  assert result.skipped is False and result.run is not None and result.symbols == []
102
102
  assert logged and "produced no symbols" in logged[0]
103
- assert result.run.silence_reason # the pass ran and says what it saw
103
+ # Not ``no_candidate_construct``: that says the files were read and held
104
+ # nothing, and it is routine, so the [passes] line never names it. An
105
+ # index with no symbols for a tree with Python in it is CANNOT-DETERMINE
106
+ # (WI-nijod: every run indexed an empty scratch dir and looked clean).
107
+ assert result.run.silence_reason == UNREPORTED
104
108
 
105
109
  def test_the_default_warning_channel_is_a_user_warning(self, tmp_path: Path) -> None:
106
110
  with pytest.warns(UserWarning, match="did not run"):
@@ -45,7 +45,13 @@ def test_a_successful_run_returns_the_index_bytes_and_the_argv_is_pinned(tmp_pat
45
45
  project.mkdir()
46
46
  out = run_scip_python_index(project, cwd=tmp_path, project_name="proj", which=_found, runner=runner)
47
47
  assert out == b"\x00scip"
48
- assert seen["argv"] == ["/fake/bin/scip-python", "index", str(project), "--project-name", "proj",
48
+ # The project travels as ``--cwd``: scip-python 0.6.6 takes no positional
49
+ # project and silently indexes its own working directory -- the scratch dir,
50
+ # which is empty -- when handed one. And the version is given: left out,
51
+ # it is read from git, and outside a git checkout the indexer crashes on
52
+ # the first module (WI-nijod).
53
+ assert seen["argv"] == ["/fake/bin/scip-python", "index", "--cwd", str(project),
54
+ "--project-name", "proj", "--project-version", "0",
49
55
  "--output", str(tmp_path / "index.scip")]
50
56
  assert seen["kwargs"]["cwd"] == str(tmp_path) and seen["kwargs"]["timeout"] == 900.0
51
57
 
@@ -69,3 +75,19 @@ def test_a_timeout_is_an_invocation_failure(tmp_path: Path) -> None:
69
75
  def test_exit_zero_without_an_index_is_no_output(tmp_path: Path) -> None:
70
76
  with pytest.raises(ScipPythonNoOutput, match="wrote no"):
71
77
  run_scip_python_index(tmp_path, cwd=tmp_path, which=_found, runner=lambda argv, **kw: _Completed())
78
+
79
+
80
+ def test_a_node_heap_exhaustion_names_the_remedy(tmp_path: Path) -> None:
81
+ """V8's default heap (~4 GB) is too small for a large project: indexing
82
+ hypergumbo itself (1,712 files) aborted at 4.2 GB RSS and finished with an
83
+ 8 GB heap (WI-nijod). The crash is an exit code 134 and a V8 trace; the
84
+ message says what to set."""
85
+ oom = b"FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory"
86
+ with pytest.raises(ScipPythonInvocationFailed, match="NODE_OPTIONS=--max-old-space-size") as excinfo:
87
+ run_scip_python_index(tmp_path, cwd=tmp_path, which=_found,
88
+ runner=lambda argv, **kw: _Completed(returncode=134, stderr=oom))
89
+ assert excinfo.value.returncode == 134 and excinfo.value.stderr == oom
90
+ with pytest.raises(ScipPythonInvocationFailed) as other:
91
+ run_scip_python_index(tmp_path, cwd=tmp_path, which=_found,
92
+ runner=lambda argv, **kw: _Completed(returncode=1, stderr=b"boom"))
93
+ assert "NODE_OPTIONS" not in str(other.value)