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 — a Neo4j push can no longer destroy data it doesn't own, and an artifact's source is now the whole file or nothing. One breaking removal, one silent-data-loss
fix, and L4 gets roughly a third faster.
pip install -U "codeanalyzer-python==1.4.0"
⚠️ Breaking: text_truncated and the artifact byte cap are gone
PyArtifact.text_truncated, the --artifact-text-max-bytes flag, and the Neo4j :Artifact.text_truncated property have been removed. An artifact's source is now
the whole file, or "" because the file is binary or you passed --no-artifact-text.
It is never a prefix.
The cap looked cheap and wasn't. A truncated source read exactly like a complete small
file — nothing in the value said otherwise — so every consumer had to carry the flag
beside the text to know whether the text could be trusted, and one that forgot was
silently reasoning about the first 256 KB of a file. The flag couldn't even express that
cleanly: text_truncated: false meant both "whole file" and "capture is off, source is
empty". For all that, on microsoft/vscode the cap fired on 32 of 4,953 artifacts — 0.6%.
Migration
Reading text_truncated? Delete the check. source is trustworthy whenever non-empty.
Passing --artifact-text-max-bytes? Remove it. Use --no-artifact-text to drop the
text payload entirely — that flag is unchanged, and sha256/size_bytes were always
full-file regardless.
Relying on the dependency-manifest cap exemption? It's gone with the cap; every
decodable file is captured in full now.
This matches codeanalyzer-typescript, which removed both in its #117, so all analyzers
now agree on what source means.
🔒 A Neo4j push no longer deletes other analyzers' graphs
If you push more than one language's graph into the same database, this one matters.
The per-module purge matched MATCH (x {_module: $m}) with no label. _module is a
convention shared across analyzers — codeanalyzer-java and codeanalyzer-typescript set it
on their nodes too — so wherever a python module and a sibling analyzer's module shared a
file key, a python push detach-deleted that sibling's nodes and their relationships. No
error, no log line. Both statements are now anchored on python-owned labels, derived from
the schema catalog so a new node type is covered automatically.
🧯 A push is additive by default; --eager is what deletes
Deletion is now the operator's call. The per-module purge and the full-run orphan prune
both require --eager; a default --lazy push only adds and updates.
The trade-off is explicit: without --eager, a declaration or call edge your source no
longer has will survive in the graph until an eager push reconciles it. If you relied on
an incremental push to remove stale nodes, add --eager. In exchange, a routine push
into a shared database cannot destroy anything.
⚡ L4 solves each function once instead of three times
The L4 serial tail — compute_summaries + assemble_sdg, about 48% of the dataflow
layer — was re-deriving the same per-function solution three times over: singleton SCCs
iterated twice to observe their own convergence, and assemble_sdg threw away the
summaries and re-solved from scratch. On the flask fixture that was 1,158 solves for 386
functions. Now it's one apiece. No output changes.
Also in this release: an _module index per module-owned Neo4j label — the purge had been
an unindexed scan once per changed module, which is quadratic on a full push.
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.0
TL;DR — a Neo4j push can no longer destroy data it doesn't own, and an artifact's
sourceis now the whole file or nothing. One breaking removal, one silent-data-lossfix, and L4 gets roughly a third faster.
text_truncatedand the artifact byte cap are gonePyArtifact.text_truncated, the--artifact-text-max-bytesflag, and the Neo4j:Artifact.text_truncatedproperty have been removed. An artifact'ssourceis nowthe whole file, or
""because the file is binary or you passed--no-artifact-text.It is never a prefix.
The cap looked cheap and wasn't. A truncated
sourceread exactly like a complete smallfile — nothing in the value said otherwise — so every consumer had to carry the flag
beside the text to know whether the text could be trusted, and one that forgot was
silently reasoning about the first 256 KB of a file. The flag couldn't even express that
cleanly:
text_truncated: falsemeant both "whole file" and "capture is off, source isempty". For all that, on
microsoft/vscodethe cap fired on 32 of 4,953 artifacts — 0.6%.Migration
text_truncated? Delete the check.sourceis trustworthy whenever non-empty.--artifact-text-max-bytes? Remove it. Use--no-artifact-textto drop thetext payload entirely — that flag is unchanged, and
sha256/size_byteswere alwaysfull-file regardless.
dependency-manifestcap exemption? It's gone with the cap; everydecodable file is captured in full now.
This matches codeanalyzer-typescript, which removed both in its #117, so all analyzers
now agree on what
sourcemeans.🔒 A Neo4j push no longer deletes other analyzers' graphs
If you push more than one language's graph into the same database, this one matters.
The per-module purge matched
MATCH (x {_module: $m})with no label._moduleis aconvention shared across analyzers — codeanalyzer-java and codeanalyzer-typescript set it
on their nodes too — so wherever a python module and a sibling analyzer's module shared a
file key, a python push detach-deleted that sibling's nodes and their relationships. No
error, no log line. Both statements are now anchored on python-owned labels, derived from
the schema catalog so a new node type is covered automatically.
🧯 A push is additive by default;
--eageris what deletesDeletion is now the operator's call. The per-module purge and the full-run orphan prune
both require
--eager; a default--lazypush only adds and updates.The trade-off is explicit: without
--eager, a declaration or call edge your source nolonger has will survive in the graph until an eager push reconciles it. If you relied on
an incremental push to remove stale nodes, add
--eager. In exchange, a routine pushinto a shared database cannot destroy anything.
⚡ L4 solves each function once instead of three times
The L4 serial tail —
compute_summaries+assemble_sdg, about 48% of the dataflowlayer — was re-deriving the same per-function solution three times over: singleton SCCs
iterated twice to observe their own convergence, and
assemble_sdgthrew away thesummaries and re-solved from scratch. On the flask fixture that was 1,158 solves for 386
functions. Now it's one apiece. No output changes.
Also in this release: an
_moduleindex per module-owned Neo4j label — the purge had beenan unindexed scan once per changed module, which is quadratic on a full push.
Links
Install
All reactions