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.
- codeanalyzer/core.py +2 -2
- codeanalyzer/dataflow/builder.py +3 -0
- codeanalyzer/dataflow/identity.py +3 -3
- codeanalyzer/entrypoints/matching.py +36 -7
- codeanalyzer/entrypoints/pipeline.py +52 -4
- codeanalyzer/entrypoints/rules.py +12 -1
- codeanalyzer/entrypoints/rules.yml +34 -0
- codeanalyzer/neo4j/bolt.py +90 -57
- codeanalyzer/neo4j/cypher.py +19 -5
- codeanalyzer/neo4j/project.py +105 -44
- codeanalyzer/neo4j/rows.py +47 -1
- codeanalyzer/neo4j/schema.py +11 -25
- codeanalyzer/schema/ids.py +57 -10
- codeanalyzer/schema/l1_body.py +2 -0
- codeanalyzer/schema/py_schema.py +8 -2
- {codeanalyzer_python-1.4.0.dist-info → codeanalyzer_python-1.5.0.dist-info}/METADATA +42 -11
- {codeanalyzer_python-1.4.0.dist-info → codeanalyzer_python-1.5.0.dist-info}/RECORD +21 -21
- {codeanalyzer_python-1.4.0.dist-info → codeanalyzer_python-1.5.0.dist-info}/WHEEL +0 -0
- {codeanalyzer_python-1.4.0.dist-info → codeanalyzer_python-1.5.0.dist-info}/entry_points.txt +0 -0
- {codeanalyzer_python-1.4.0.dist-info → codeanalyzer_python-1.5.0.dist-info}/licenses/LICENSE +0 -0
- {codeanalyzer_python-1.4.0.dist-info → codeanalyzer_python-1.5.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: codeanalyzer-python
|
|
3
|
-
Version: 1.
|
|
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.
|
|
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
|
|
520
|
+
"id": "can://<app>",
|
|
517
521
|
"kind": "application",
|
|
518
522
|
"symbol_table": { // relative POSIX path → module
|
|
519
523
|
"pkg/mod.py": {
|
|
520
|
-
"id": "can
|
|
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
|
|
531
|
-
{ "id": "can
|
|
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": { … },
|
|
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
|
|
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
|
|
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/
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
42
|
-
codeanalyzer/entrypoints/pipeline.py,sha256=
|
|
43
|
-
codeanalyzer/entrypoints/rules.py,sha256=
|
|
44
|
-
codeanalyzer/entrypoints/rules.yml,sha256=
|
|
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=
|
|
49
|
-
codeanalyzer/neo4j/cypher.py,sha256
|
|
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=
|
|
52
|
-
codeanalyzer/neo4j/rows.py,sha256=
|
|
53
|
-
codeanalyzer/neo4j/schema.py,sha256=
|
|
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=
|
|
60
|
-
codeanalyzer/schema/l1_body.py,sha256=
|
|
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=
|
|
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.
|
|
74
|
-
codeanalyzer_python-1.
|
|
75
|
-
codeanalyzer_python-1.
|
|
76
|
-
codeanalyzer_python-1.
|
|
77
|
-
codeanalyzer_python-1.
|
|
78
|
-
codeanalyzer_python-1.
|
|
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,,
|
|
File without changes
|
{codeanalyzer_python-1.4.0.dist-info → codeanalyzer_python-1.5.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{codeanalyzer_python-1.4.0.dist-info → codeanalyzer_python-1.5.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|