You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TL;DR — every node in a callable's body now carries its id in analysis.json, the
Neo4j purge is scoped by identity instead of a shared property, class inheritance edges
are actually emitted, and entrypoint detection works on Odoo and on frameworks the rules
have never heard of. One breaking change in the Neo4j graph, the JSON schema is additive.
pip install -U "codeanalyzer-python==1.4.1"
⚠️ Breaking (Neo4j only): _module is gone; PyAttribute/PyVariable ids changed
Every destructive Neo4j statement — the per-module purge, the full-run orphan prune, the
snapshot wipe — now scopes on the can:// id prefix instead of a label list plus the
internal _module property. The id already carries language, application and file, so x.id STARTS WITH 'can://python/<app>/<file>/' is containment. Two python applications
sharing a module path no longer delete each other's nodes; an empty application id is
refused instead of matching the whole store. _module leaves every node, the catalog and
its six per-label indexes. Every node keyed by a can://python/ id carries a new marker
label :PyCanNode with a range index on id, purely so the prefix predicate seeks.
:PyAttribute and :PyVariable ids are now minted from the owner's can:// id
(<class-id>/<name>, <owner-id>/<name>@<line>). The old signature-minted ids had no
application segment, so two applications merged onto one node.
Migration
A query filtering on x._module = <file> becomes x.id STARTS WITH 'can://python/<app>/<file>/'.
Nothing to do for analysis.json; _module never appeared there.
The graph contract version stays 2.0.0: the v2 line has no released consumer pinning it.
🆔 Body nodes and parameters carry their id in analysis.json
BodyNode.id is the global ordinal <callable-id>@<local> the Neo4j projection already
merged :PyBodyNode on — present at every level the node exists. PyCallableParameter.id
is <callable-id>@formal_in:<i>, the level-4 vertex that carries the parameter. A node is
now addressable the same way in both projections, so consumers stop recomposing the can:// grammar themselves. Additive; schema_version stays 2.0.0.
🔗 PY_EXTENDS is emitted for the first time
The projector handed the written base spelling (Base) to a lookup keyed by signature
(pkg.mod.Base), so every inheritance edge was dropped as dangling and no graph since 2.0.0
had one. Bases now resolve per module — a declared class lands on its can:// id, anything
else on an @external ghost — and relative imports resolve through resolved_module.
🚪 Entrypoints: Odoo, a heuristic tier, and a report you can read from the graph
Odoo's @http.route methods and http.Controller subclasses are detected (534 and 94
on odoo-slim-19, where 1.4.0 found zero). Decorators fall back to the module's import
table when Jedi cannot resolve them, so this works with odoo not installed.
A framework-independent heuristic tier: a decorator spelled route, *.route, or a .get/.post/.put/.patch/.delete/.websocket verb is recorded with confidence: "heuristic" whether or not any framework rule knows the library. Framework
rules still win; filter on confidence if you want only certain hits.
:PyApplication carries entrypoint_frameworks and entrypoint_report_json, always
present, so a graph consumer can tell "no entrypoints" from "the pass found nothing".
PyEntrypointReport.unresolved is finally written, and does not count builtins.
Also
reaching-defs documented as the third DDG prov value (L4 port wiring); code documented
as the exact span.bytes slice.
The Bolt writer's content_hash diff never matched (every module always "changed") and was
application-blind; both fixed.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
codeanalyzer-python (canpy) v1.4.1
TL;DR — every node in a callable's body now carries its
idinanalysis.json, theNeo4j purge is scoped by identity instead of a shared property, class inheritance edges
are actually emitted, and entrypoint detection works on Odoo and on frameworks the rules
have never heard of. One breaking change in the Neo4j graph, the JSON schema is additive.
_moduleis gone;PyAttribute/PyVariableids changedEvery destructive Neo4j statement — the per-module purge, the full-run orphan prune, the
snapshot wipe — now scopes on the
can://id prefix instead of a label list plus theinternal
_moduleproperty. The id already carries language, application and file, sox.id STARTS WITH 'can://python/<app>/<file>/'is containment. Two python applicationssharing a module path no longer delete each other's nodes; an empty application id is
refused instead of matching the whole store.
_moduleleaves every node, the catalog andits six per-label indexes. Every node keyed by a
can://python/id carries a new markerlabel
:PyCanNodewith a range index onid, purely so the prefix predicate seeks.:PyAttributeand:PyVariableids are now minted from the owner'scan://id(
<class-id>/<name>,<owner-id>/<name>@<line>). The old signature-minted ids had noapplication segment, so two applications merged onto one node.
Migration
x._module = <file>becomesx.id STARTS WITH 'can://python/<app>/<file>/'.analysis.json;_modulenever appeared there.2.0.0: the v2 line has no released consumer pinning it.🆔 Body nodes and parameters carry their
idinanalysis.jsonBodyNode.idis the global ordinal<callable-id>@<local>the Neo4j projection alreadymerged
:PyBodyNodeon — present at every level the node exists.PyCallableParameter.idis
<callable-id>@formal_in:<i>, the level-4 vertex that carries the parameter. A node isnow addressable the same way in both projections, so consumers stop recomposing the
can://grammar themselves. Additive;schema_versionstays2.0.0.🔗
PY_EXTENDSis emitted for the first timeThe projector handed the written base spelling (
Base) to a lookup keyed by signature(
pkg.mod.Base), so every inheritance edge was dropped as dangling and no graph since 2.0.0had one. Bases now resolve per module — a declared class lands on its
can://id, anythingelse on an
@externalghost — and relative imports resolve throughresolved_module.🚪 Entrypoints: Odoo, a heuristic tier, and a report you can read from the graph
@http.routemethods andhttp.Controllersubclasses are detected (534 and 94on
odoo-slim-19, where 1.4.0 found zero). Decorators fall back to the module's importtable when Jedi cannot resolve them, so this works with odoo not installed.
route,*.route, or a.get/.post/.put/.patch/.delete/.websocketverb is recorded withconfidence: "heuristic"whether or not any framework rule knows the library. Frameworkrules still win; filter on
confidenceif you want only certain hits.:PyApplicationcarriesentrypoint_frameworksandentrypoint_report_json, alwayspresent, so a graph consumer can tell "no entrypoints" from "the pass found nothing".
PyEntrypointReport.unresolvedis finally written, and does not count builtins.Also
reaching-defsdocumented as the third DDGprovvalue (L4 port wiring);codedocumentedas the exact
span.bytesslice.content_hashdiff never matched (every module always "changed") and wasapplication-blind; both fixed.
[GET, POST].Release: https://github.com/codellm-devkit/codeanalyzer-python/releases/tag/v1.4.1 ·
Changelog: https://github.com/codellm-devkit/codeanalyzer-python/blob/main/CHANGELOG.md
All reactions