Analysis venv (uv + Jedi wiring), external_symbols, app-scoped prune, --no-venv (#44 #45 #46 #47)#48
Merged
Merged
Conversation
Closes #47 The per-project analysis venv was built and populated but never used: __init__ left self.virtualenv = None and never reassigned it, so SymbolTableBuilder got virtualenv=None and Jedi resolved against the default environment, ignoring the installed dependencies. Set self.virtualenv to the venv path on both a fresh build and a lazy reuse so Jedi resolves the project's third-party imports. Also install dependencies with uv (uv pip install --python <venv>) instead of pip: uv resolves and downloads in parallel with a shared global cache, which is dramatically faster for large dependency trees (e.g. Odoo). uv ships as a self-contained binary in its wheel, so it is present wherever canpy is installed (including Docker); fall back to python -m pip when uv cannot be located.
…ges (#44) Closes #44 Adopt the model codeanalyzer-typescript uses: external call targets are now first-class in the IR instead of being re-derived ad hoc during Neo4j projection. - schema: add PyExternalSymbol{name, module} and PyApplication.external_symbols, keyed by signature (mirrors TSExternalSymbol). - core: _compute_external_symbols() classifies every call-graph endpoint not declared in the symbol table as an external (name/module from the signature), so analysis.json carries external info that was previously a bare target string. - neo4j: :PyExternal gains a `module` property (SCHEMA_VERSION 1.0.0 -> 1.1.0, additive). project()'s _call_endpoint classifies authoritatively from external_symbols rather than a "present in the graph" heuristic, so an imported module name (a :PyPackage) can no longer shadow a call target and silently drop the PY_CALLS edge. - rows: track node identity by (merge_label, value) so deferred PY_EXTENDS / PY_RESOLVES_TO edges can't be shadowed either. Fixes the ~3.7% of call edges (e.g. targets os/re/json) that were dropped from the emitted graph. Adds a regression test and exercises external_symbols in the sample app; regenerates schema.neo4j.json.
Closes #45 The full-run prune deleted any :PyModule whose file_key was not in the current emit across the ENTIRE database -- not just the application being written -- so a full-run push for application B wiped application A's modules, leaving an orphaned :PyApplication with zero PY_HAS_MODULE edges. A single Neo4j database therefore could not hold multiple applications via full-run --emit neo4j. Anchor the prune to the :PyApplication {name} being emitted (MATCH (:PyApplication {name:$app})-[:PY_HAS_MODULE]->(m:PyModule) WHERE NOT m.file_key IN $present ...), so it only removes that application's vanished modules. Adds a container regression test (app-b push leaves app-a intact).
…ent env Closes #46 Add a --no-venv flag (AnalysisOptions.no_venv) that skips virtualenv creation and dependency installation and resolves imports against the ambient interpreter (self.virtualenv stays None, so Jedi uses the default environment). Useful in CI / containers where the project's dependencies are already installed, for sandboxed runs where network installs are disallowed, and for speed. Tradeoff: import / call-resolution quality then depends on what is installed in the ambient env. Regenerates the README --help block; adds a CLI regression test (no virtualenv is created and analysis.json is still produced).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes four issues on the Neo4j / analysis pipeline.
Changes
#47 -- install the analysis venv with uv and wire it to Jedi
The per-project analysis venv was built and populated but never used:
__init__left
self.virtualenv = Noneand never reassigned it, soSymbolTableBuildergotNoneand Jedi resolved against the default environment, ignoring the installeddependencies. Now
self.virtualenvis set on both a fresh build and a lazy reuse.Dependency installation uses
uv(uv pip install --python <venv>) instead ofpipfor speed (parallel + shared cache); uv ships in its wheel so it is present
wherever canpy is installed, including Docker, with a pip fallback.
#44 -- first-class external_symbols (codeanalyzer-typescript parity)
External call targets are now first-class in the IR instead of being re-derived
ad hoc in the projection. Adds PyExternalSymbol{name, module} and
PyApplication.external_symbols (mirrors TSExternalSymbol). The analyzer
classifies every call-graph endpoint not declared in the symbol table as an
external. The Neo4j projection emits :PyExternal authoritatively from that set,
so an imported module name (a :PyPackage) can no longer shadow a call target and
silently drop the PY_CALLS edge. :PyExternal gains a module property
(SCHEMA_VERSION 1.0.0 -> 1.1.0, additive). Node identity is also keyed by
(merge_label, value) so deferred PY_EXTENDS / PY_RESOLVES_TO edges cannot be
shadowed. Fixes the ~3.7% of call edges (targets like os/re/json) that were
dropped from the emitted graph.
#45 -- scope the bolt full-run prune to the application anchor
The full-run orphan prune deleted any :PyModule not in the current emit across
the entire database, so a push for application B wiped application A's modules.
The prune is now anchored:
so it only removes that application's vanished modules. A single Neo4j database
can now hold multiple applications via full-run --emit neo4j.
#46 -- add --no-venv
New --no-venv/--venv flag (AnalysisOptions.no_venv). When set, skip venv
creation and dependency installation and resolve imports against the ambient
interpreter (self.virtualenv stays None). Useful in CI / containers where the
deps are already installed, for sandboxed runs without network, and for speed.
Testing
preserved as a :PyExternal) -- pass.
(a full-run push for app-b leaves app-a intact) -- 4 pass against real Neo4j.
pass.
external_symbols: {os: {name: os, module: os}} and the projection preserves the
PY_CALLS edge to a :PyExternal {module: os}.
Closes
Closes #44
Closes #45
Closes #46
Closes #47