codeanalyzer-python 1.4.0__py3-none-any.whl → 1.5.0__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: codeanalyzer-python
3
- Version: 1.4.0
3
+ Version: 1.5.0
4
4
  Summary: Static analysis for Python — canonical schema v2 (symbol table, call graph, and native CFG/PDG/SDG dataflow) as analysis.json or a Neo4j property graph.
5
5
  Author-email: Rahul Krishna <i.m.ralk@gmail.com>
6
6
  License-File: LICENSE
@@ -459,7 +459,7 @@ levels are cumulative and additive — `analysis.json(-a 1) ⊆ … ⊆ analysis
459
459
  | **1** | `-a 1` (default) | Symbol table, Jedi call graph, and `call` nodes in each callable's `body` | `body` calls (`callee: null`) |
460
460
  | **2** | `-a 2` | Defuse-linker call-graph enrichment; each call's `callee` backfilled to a `can://` id | `call_graph`, `body` callees |
461
461
  | **3** | `-a 3` | Native **intraprocedural** CFG/CDG/DDG (syntactic, name-equality, `prov: ["ssa"]`) | `cfg`, `cdg`, `ddg`, `@entry`/`@exit` on each callable |
462
- | **4** | `-a 4` | **Interprocedural** SDG: synthetic param vertices, alias-aware DDG (`prov: ["points-to"]`) | `param_in`, `param_out`, `summary`, semantic `ddg` |
462
+ | **4** | `-a 4` | **Interprocedural** SDG: synthetic param vertices, alias-aware DDG (`prov: ["points-to"]`), port-wiring DDG between statements and param vertices (`prov: ["reaching-defs"]`) | `param_in`, `param_out`, `summary`, semantic `ddg` |
463
463
 
464
464
  `-a 1`/`-a 2` timings and output are unaffected by the heavier levels — nothing at level 3+ runs
465
465
  unless requested. Flag gating: `--graphs sdg` requires `-a 4`; `--graphs cfg,dfg,pdg` and
@@ -481,7 +481,11 @@ symbol-table signature by construction
481
481
  - **Points-to oracle (level 4):** the **Scalpel** may-alias oracle — `ScalpelAliasOracle`
482
482
  (`codeanalyzer/dataflow/scalpel_oracle.py`) — consumes Scalpel's SSA copy/const facts to answer
483
483
  `may_alias(path_a, path_b)`, adding the alias-aware DDG edges (`prov: ["points-to"]`) and the
484
- interprocedural summaries. Scalpel is **vendored** a `typed_ast`-free slice built into the
484
+ interprocedural summaries. Level 4 also wires the statement-level DDG to the param
485
+ vertices (def → `actual_in`, `actual_out` → call site, `formal_in` → use, def → `formal_out`)
486
+ with `prov: ["reaching-defs"]`; without those the SDG would be two disconnected graphs. So
487
+ `prov` takes three values: `ssa` (syntactic, L3), `reaching-defs` (port wiring, L4) and
488
+ `points-to` (alias-derived, L4). Scalpel is **vendored** — a `typed_ast`-free slice built into the
485
489
  package under `codeanalyzer/dataflow/scalpel/` — so it is the **default** level-4 oracle with no
486
490
  external dependency to install; the analyzer falls back to the built-in `TypeBasedAliasOracle`
487
491
  (Jedi-inferred types; unknown types conservatively alias) only when Scalpel can't resolve a
@@ -513,11 +517,11 @@ just populate more of the same tree:
513
517
  "k_limit": 3, // access-path depth bound (--graph-field-depth); L3+ only
514
518
  "analyzer": { "name": "codeanalyzer-python", "version": "1.0.0" },
515
519
  "application": {
516
- "id": "can://python/<app>",
520
+ "id": "can://<app>",
517
521
  "kind": "application",
518
522
  "symbol_table": { // relative POSIX path → module
519
523
  "pkg/mod.py": {
520
- "id": "can://python/<app>/pkg/mod.py",
524
+ "id": "can://<app>/python/pkg/mod.py",
521
525
  "kind": "module",
522
526
  "source": "…full file text, stored once per module…",
523
527
  "types": { "<Class>": { "id": "…", "kind": "class", "callables": { /* methods */ } } },
@@ -527,8 +531,8 @@ just populate more of the same tree:
527
531
  "call_graph": [ { "src": "can://…/main(a)", "dst": "can://…/helper(x)",
528
532
  "weight": 1, "prov": ["defuse", "jedi"] } ],
529
533
  "external_symbols": { // imported/builtin call targets, keyed by id
530
- "can://python/<app>/@external/os/getcwd":
531
- { "id": "can://python/<app>/@external/os/getcwd", "kind": "external",
534
+ "can://<app>/@external/os/getcwd":
535
+ { "id": "can://<app>/@external/os/getcwd", "kind": "external",
532
536
  "name": "getcwd", "module": "os" }
533
537
  },
534
538
  "param_in": [ { "src": "can://…/main(a)@6:4/actual_in:0", "dst": "can://…/helper(x)@formal_in:0" } ],
@@ -546,7 +550,8 @@ A **callable** (function or method) carries its own CPG, keyed by node id:
546
550
  "body": { // node id → node
547
551
  "@entry": { "kind": "entry" },
548
552
  "6:4": { "kind": "statement", "span": { … } },
549
- "6:8": { "kind": "call", "span": { … }, "callee": "can://…/helper(x)" }, // callee null until L2
553
+ "6:8": { "id": "can://…/main()@6:8", "kind": "call", "span": { … },
554
+ "callee": "can://…/helper(x)" }, // callee null until L2
550
555
  "@formal_in:0": { "kind": "formal_in", "of": "a" }, // L4 param vertices
551
556
  "6:4/actual_in:0": { "kind": "actual_in", "of": "a", "parent": "6:4" },
552
557
  "@exit": { "kind": "exit" }
@@ -563,7 +568,7 @@ The application envelope also contains three substrate sections:
563
568
  - **`artifacts`** — discovered non-code files (manifests, configs, Docker files, CI workflows,
564
569
  packaging files, scripts, docs, and legal files) with extraction status (`none`, `partial`, or
565
570
  `full`; default `none`), keyed by relative path; each artifact carries the
566
- `can://artifact/<app>/<path>` id namespace. Config files carry extracted `config_keys`
571
+ `can://<app>/artifact/<path>` id namespace. Config files carry extracted `config_keys`
567
572
  (keys, values, namespaces, and references) and `DEFINES_CONFIG` Neo4j edges.
568
573
  - **`dependencies`** — declared packages with kind (`runtime`/`dev`/`optional`/`build`), spec,
569
574
  locked version, and provenance (`prov`): where each binding came from (manifest file, lock file,
@@ -574,7 +579,7 @@ The application envelope also contains three substrate sections:
574
579
  Notable properties:
575
580
 
576
581
  - **Durable `can://` ids** identify every node at callable granularity and above
577
- (`can://python/<app>/<file>/<callable-sig>`); nodes below a callable use ordinal ids
582
+ (`can://<app>/python/<file>/<callable-sig>`); nodes below a callable use ordinal ids
578
583
  (`@entry`, `@exit`, `line:col`, `@formal_in:N`, `line:col/actual_in:N`).
579
584
  - **`source` lives once per module**; every node's text is the `module.source[span.bytes]` slice.
580
585
  - **Cross-function edges** — `call_graph`, `param_in`, `param_out`, `config_uses` — live at **application** scope;
@@ -686,13 +691,17 @@ RETURN DISTINCT c.id
686
691
  MATCH (m:PyCallable {is_entrypoint: true})
687
692
  RETURN m.id, m.entrypoint_frameworks
688
693
 
694
+ // did the entrypoint pass find anything? (no entrypoints vs. nothing detected)
695
+ MATCH (a:PyApplication)
696
+ RETURN a.entrypoint_frameworks, a.entrypoint_report_json
697
+
689
698
  // data dependences into one statement (level 3+)
690
699
  MATCH (s:PyBodyNode {id: $stmt})<-[d:PY_DDG]-(src:PyBodyNode)
691
700
  RETURN src.id, d.var, d.prov
692
701
 
693
702
  // interprocedural flow through a parameter (level 4)
694
703
  MATCH (a:PyBodyNode)-[:PY_PARAM_IN]->(f:PyBodyNode)
695
- WHERE f.id STARTS WITH "can://python/myapp/src/api.py"
704
+ WHERE f.id STARTS WITH "can://myapp/python/src/api.py"
696
705
  RETURN a.id, f.id
697
706
  ```
698
707
 
@@ -721,3 +730,25 @@ RETURN f.id, l.version
721
730
  ## License
722
731
 
723
732
  Apache 2.0 — see [LICENSE](./LICENSE).
733
+
734
+ ## Polyglot applications: all languages, or none
735
+
736
+ A `--emit neo4j` push is **destructive**. It sweeps everything under `can://<app>/` that this
737
+ analyzer marked, then rewrites what it found. Since the id grammar puts the application outermost,
738
+ every analyzer over the same `<app>` shares that prefix — so a push reclaims stale rows belonging to
739
+ *this* analyzer and, in the shared namespaces, sweeps rows a sibling wrote.
740
+
741
+ For most of what is shared that is harmless: the artifact walk is a whole-repo inventory, so an
742
+ `:Artifact` a sibling wrote is re-created by this push (with a thinner view of it — `roles` falls
743
+ back to `unknown` and its config keys and dependency edges are gone until that sibling pushes
744
+ again). `@external` ghosts are not inventoried that way: they are per-language, so a sibling's
745
+ ghosts are swept and not restored.
746
+
747
+ **So for an application analysed in more than one language, run every analyzer or none.** Running
748
+ one in isolation leaves the others' derived rows missing until they run again. Running them
749
+ together is always correct, in any order, because the last push restores everything the batch
750
+ swept.
751
+
752
+ Nothing here corrupts a graph: what is lost is derived and regenerates. But a partial run leaves a
753
+ partial answer, and nothing in the data says so.
754
+
@@ -1,6 +1,6 @@
1
1
  codeanalyzer/__init__.py,sha256=BZ3Kuwl-F_F-8H8cepLnVJ4Ku4NNUjjqg0Y6ujPQSsI,108
2
2
  codeanalyzer/__main__.py,sha256=o5_9ct61l3T7ryIsag8bz304NabVV-el_ooGD8tnbhA,15968
3
- codeanalyzer/core.py,sha256=tk_3dz81ECXXv8CEciWTIVfBAHHIfTVCsZte1GAZ080,46620
3
+ codeanalyzer/core.py,sha256=JfSsQEacBiVn38tQP34QWdJqQx7ecE70EXI8obISZN4,46598
4
4
  codeanalyzer/provenance.py,sha256=DT-DqwdVwO7g-GyK3sC0_4vDNCUjZYEY1fyYCt-7VRM,2306
5
5
  codeanalyzer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  codeanalyzer/artifacts/__init__.py,sha256=317sEeZLS1AYsfYDYIk7tLR3AdDFwWw_cmkeZDabkJo,906
@@ -13,11 +13,11 @@ codeanalyzer/artifacts/parsers.py,sha256=xOjC53tT0Mv0k7ONGwzl5XUvpBLnZlEcGmyrX5D
13
13
  codeanalyzer/dataflow/__init__.py,sha256=HCNOH24rAGLUMG94N9aC-2SsAWSntk3uys7e39ipU5o,1725
14
14
  codeanalyzer/dataflow/access_paths.py,sha256=wC8Q9qD-RZzkoFWMVvu_6uNNmYP8z48OGp9h9v3F1d4,23623
15
15
  codeanalyzer/dataflow/alias.py,sha256=ZYKY0DiR3GHv6YJr7C001Lode9rZsk6-gxdomUyIvwg,3928
16
- codeanalyzer/dataflow/builder.py,sha256=KiISa2bIuBf_0N0v_PzlgMGm0sFtMICEwA-Y6DFXiM4,32687
16
+ codeanalyzer/dataflow/builder.py,sha256=kUjI_oBHn5H8cfcSYxj40OHxiqXX-IbxXqahNLgffyQ,32812
17
17
  codeanalyzer/dataflow/cfg.py,sha256=u5YXJjAaDshdgv-9kWWITbBJFP-MwXKq6hbNh0fhDm8,25307
18
18
  codeanalyzer/dataflow/defuse.py,sha256=LrX1ToOZzR79NlAGg5T647UAFkpiEqEnT7t0K5RXOiI,4377
19
19
  codeanalyzer/dataflow/dominance.py,sha256=X7Ki1QRdVqaseYsJtiUL7m9MbcC2WHEv9b8bczSLFUA,5086
20
- codeanalyzer/dataflow/identity.py,sha256=WAIal6XchmQqdnXbvbEgu8J6vJdXNRdie1KHz1vJBl8,3906
20
+ codeanalyzer/dataflow/identity.py,sha256=6aAz3iPSOpoS7l_moC7XGr2RS_GqJp_FlsWGglMJDjM,3812
21
21
  codeanalyzer/dataflow/pdg.py,sha256=1Bm7AnoRqXBryZulII2idPw0feV8eZQ1VqqprQ8PW-g,3731
22
22
  codeanalyzer/dataflow/scalpel_oracle.py,sha256=FxRadKrTWar0VKHyQJM40n3cq25sld3Sj4lMdOm5NFk,11494
23
23
  codeanalyzer/dataflow/scc.py,sha256=Doa_0-5f3agCu_5UmeEDlCUErg34TtniKIv8Uqd7Jiw,3493
@@ -38,28 +38,28 @@ codeanalyzer/dataflow/scalpel/core/func_call_visitor.py,sha256=ps0snjTchBXilhor3
38
38
  codeanalyzer/dataflow/scalpel/core/vars_visitor.py,sha256=gE5fNyJS6jslD6vsMRbFLoy3n1xTwH-b54mBcNYO72M,5660
39
39
  codeanalyzer/entrypoints/__init__.py,sha256=VaMd4mSEPLuPlRxxAve_nTJ9ZH62stXZGTPNwU_BQ50,99
40
40
  codeanalyzer/entrypoints/detect.py,sha256=fsWRQz1njvB9d3LIJEHxsNFE1GrB7q52KCvozw_UIUQ,4594
41
- codeanalyzer/entrypoints/matching.py,sha256=vXrhCsPOeaYHp8tYyILk5kNh9_3rwV_1wi6Z47PqG80,6427
42
- codeanalyzer/entrypoints/pipeline.py,sha256=PDptL_o105BpofpnQHWZYOtFYVelqTB4zktp0PVPbEc,5540
43
- codeanalyzer/entrypoints/rules.py,sha256=aYwCiX-J3tvj8qJrrb-tph5zovin5wIdmzc49iR3h2U,5318
44
- codeanalyzer/entrypoints/rules.yml,sha256=rgDglVOcUNXnQ5FXLMfnJbfI7xHRiRmegTP5bmiemSQ,3112
41
+ codeanalyzer/entrypoints/matching.py,sha256=rQeY_w2dyG36DBUjle7GLXxqDKsoMhJYPjN4s11OGtM,7948
42
+ codeanalyzer/entrypoints/pipeline.py,sha256=vVSdttMfSAWour2fsC3LomMtwFLzRqmJHixJS82VY1I,7828
43
+ codeanalyzer/entrypoints/rules.py,sha256=yG772JHmNc2L10jIpxfg1xTh-QouJa6lNU9ubo3EZYg,6003
44
+ codeanalyzer/entrypoints/rules.yml,sha256=sguICRfDDNGjJPfZz-JSwkI_hzbTJaau1liHV_y4rTA,4637
45
45
  codeanalyzer/jedi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  codeanalyzer/jedi/jedi.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  codeanalyzer/neo4j/__init__.py,sha256=8Ei6uThTOqmul6GhnKoGOjLXJZbyDwF5Jo-8I8NxnAk,1574
48
- codeanalyzer/neo4j/bolt.py,sha256=wobEBSQn5z9uCER3fNtTl98Q1z5WuXG-O1rPRoFwFWI,11949
49
- codeanalyzer/neo4j/cypher.py,sha256=a7YSmxxDbPcYc5gI4TW9sM6_WOE3RgLXTGBR9K8W8kw,5321
48
+ codeanalyzer/neo4j/bolt.py,sha256=8l70iGDjY3Kdm-W1sb3b3O1uqLjDrVPYTpXhnkXdZOY,13694
49
+ codeanalyzer/neo4j/cypher.py,sha256=-wledvXVrcLJRtSC5MCn1N3tqgC06rNfPBn0w6POqHo,6239
50
50
  codeanalyzer/neo4j/emit.py,sha256=OBCO77TDTaNpqk9Di3JIQzBouLpHPdgoXuPSs44iJuU,3587
51
- codeanalyzer/neo4j/project.py,sha256=U-2ZurR3aYFY0k8WGpEIYTE4YEET2pJeOyxqb9i_Xyo,35044
52
- codeanalyzer/neo4j/rows.py,sha256=med0XFa63PPUVUhJMq1TtVcJxgaVW39sgxBRZJDIJ_w,7811
53
- codeanalyzer/neo4j/schema.py,sha256=88F_biHRhd4NV1RSNvFCwLa062gKJb12_P_-vV6L-rE,15379
51
+ codeanalyzer/neo4j/project.py,sha256=gw4qmoIyOy6LabbpmBawvvb7yGEvgDV4fdmoV128eJA,38774
52
+ codeanalyzer/neo4j/rows.py,sha256=n_J3NVIusLPsHMjPCWaYvlL5sFm6V-kl_Z6B_BTH8Fk,10140
53
+ codeanalyzer/neo4j/schema.py,sha256=ZRjBxpagBsQrPbD5BbeAZlj3ilTeYe4AsquztRDaH4M,14735
54
54
  codeanalyzer/options/__init__.py,sha256=6NewN0a-1HAEgKcxQjYyVn2WEDLrhax8h3WLgZddeqI,94
55
55
  codeanalyzer/options/options.py,sha256=2jDCcs74iSEOhz90LoRGts6PC8yV9IDPVxnLPNmonOA,1609
56
56
  codeanalyzer/schema/__init__.py,sha256=hIyz02abUJNPW8yUgguaeKflZjTmOZWbDiKICNBD7yk,4141
57
57
  codeanalyzer/schema/assign_ids.py,sha256=pQHluLaO5a6hFREp3vjVRsUeAfTYSJ95RXS9TZvnoys,1590
58
58
  codeanalyzer/schema/call_graph_ids.py,sha256=mWAhJDBsW8i-siJiINOHCXEm4qM6F_5se9-HuHWIFqU,568
59
- codeanalyzer/schema/ids.py,sha256=aOzsgVaOo6x72dnRgNxlnt6b5wbZzhTm0JOz6pdI57I,1672
60
- codeanalyzer/schema/l1_body.py,sha256=5Su347kwAPNflJDf7SvBR3sNXx9PVdGEml2pOpQCwo0,1684
59
+ codeanalyzer/schema/ids.py,sha256=YuioNK3Y-M2NcCBiGH4AB4rDezlqu6ycNO0R3O-Jxho,4388
60
+ codeanalyzer/schema/l1_body.py,sha256=_sca0mTkMRb-5lasep87faGjDxZJd9jGB0hmBx3uCgk,1757
61
61
  codeanalyzer/schema/l2_callees.py,sha256=CTcBeGoO04DstDC6h-1sHMbbIrHDEOMxP01U9VLBcfc,2327
62
- codeanalyzer/schema/py_schema.py,sha256=5G8K6uqBopU5iLwlUW30AE5A8jgTEdNaQmOeizhccag,23885
62
+ codeanalyzer/schema/py_schema.py,sha256=Ujre6PoBQZ3DUn9tjoPsqoYBPtAcYW-WI2JphLaMKyU,24231
63
63
  codeanalyzer/semantic_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
64
  codeanalyzer/semantic_analysis/call_graph.py,sha256=6YEB_wTn5-oQYLrbIhJYE0BsHl4fpWPoy5Hwd9mTnGc,11918
65
65
  codeanalyzer/semantic_analysis/defuse_linker.py,sha256=bSn1rCun28OQqSd2NOc9aVBSm47Gt9Iul4r_gwfqO1w,64930
@@ -70,9 +70,9 @@ codeanalyzer/syntactic_analysis/symbol_table_builder.py,sha256=eTknBDlUuuQd3JEwb
70
70
  codeanalyzer/utils/__init__.py,sha256=hC6VWdR5rerSqBxzu9KQHTASWqwrrYJv-CMDwrTlzkc,137
71
71
  codeanalyzer/utils/logging.py,sha256=Fw0tattPAOMs3o0JMjjXhRVLIF64f-SCcygUXF9jqeg,904
72
72
  codeanalyzer/utils/progress_bar.py,sha256=C9JtzVdd10lIxTv-KA6PebqjKWueC_vMGwVzAtHuHIw,2818
73
- codeanalyzer_python-1.4.0.dist-info/METADATA,sha256=DJKj-64VCcSuUoxUbwsesDi7jSkBv69YSrsePcgAzGM,42786
74
- codeanalyzer_python-1.4.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
75
- codeanalyzer_python-1.4.0.dist-info/entry_points.txt,sha256=v4Vux0Nnx7sOntVk_CH7W9RX6SkIkvR1FQYq73oVlCQ,105
76
- codeanalyzer_python-1.4.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
77
- codeanalyzer_python-1.4.0.dist-info/licenses/NOTICE,sha256=MdVkNYqHJ20on2FmWvgD4WpMsX5mir33xdyPvTXd0A0,1223
78
- codeanalyzer_python-1.4.0.dist-info/RECORD,,
73
+ codeanalyzer_python-1.5.0.dist-info/METADATA,sha256=X4LXZPtqeXauN-M0hAsMBJCjJxqgOTeCj_KtYOBTgtI,44750
74
+ codeanalyzer_python-1.5.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
75
+ codeanalyzer_python-1.5.0.dist-info/entry_points.txt,sha256=v4Vux0Nnx7sOntVk_CH7W9RX6SkIkvR1FQYq73oVlCQ,105
76
+ codeanalyzer_python-1.5.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
77
+ codeanalyzer_python-1.5.0.dist-info/licenses/NOTICE,sha256=MdVkNYqHJ20on2FmWvgD4WpMsX5mir33xdyPvTXd0A0,1223
78
+ codeanalyzer_python-1.5.0.dist-info/RECORD,,