cg-code-graph 0.10.1__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.
Files changed (174) hide show
  1. cg_code_graph-0.10.1.dist-info/METADATA +678 -0
  2. cg_code_graph-0.10.1.dist-info/RECORD +174 -0
  3. cg_code_graph-0.10.1.dist-info/WHEEL +5 -0
  4. cg_code_graph-0.10.1.dist-info/entry_points.txt +3 -0
  5. cg_code_graph-0.10.1.dist-info/licenses/LICENSE +21 -0
  6. cg_code_graph-0.10.1.dist-info/top_level.txt +1 -0
  7. codegraph/__init__.py +2 -0
  8. codegraph/aitools.py +129 -0
  9. codegraph/apps.py +76 -0
  10. codegraph/blindspots.py +428 -0
  11. codegraph/bridges.py +1701 -0
  12. codegraph/cli.py +725 -0
  13. codegraph/concepts.py +362 -0
  14. codegraph/config.py +559 -0
  15. codegraph/core/__init__.py +0 -0
  16. codegraph/core/cache.py +375 -0
  17. codegraph/core/detect.py +80 -0
  18. codegraph/core/extractors.py +187 -0
  19. codegraph/core/fsutil.py +61 -0
  20. codegraph/core/generated.py +575 -0
  21. codegraph/core/model.py +174 -0
  22. codegraph/core/paths.py +175 -0
  23. codegraph/core/plugin.py +160 -0
  24. codegraph/core/store.py +80 -0
  25. codegraph/core/syntax_errors.py +132 -0
  26. codegraph/coverage.py +928 -0
  27. codegraph/doctor.py +453 -0
  28. codegraph/external.py +613 -0
  29. codegraph/indexer.py +336 -0
  30. codegraph/link.py +434 -0
  31. codegraph/lint_async.py +524 -0
  32. codegraph/mcp_server.py +1303 -0
  33. codegraph/parity.py +473 -0
  34. codegraph/parity_structure.py +307 -0
  35. codegraph/payload.py +321 -0
  36. codegraph/plans.py +1285 -0
  37. codegraph/platform_scan.py +643 -0
  38. codegraph/platforms.py +1369 -0
  39. codegraph/plugins/__init__.py +0 -0
  40. codegraph/plugins/cfamily/__init__.py +0 -0
  41. codegraph/plugins/cfamily/plugin.py +930 -0
  42. codegraph/plugins/cfamily/syntax.py +881 -0
  43. codegraph/plugins/dart/__init__.py +0 -0
  44. codegraph/plugins/dart/bridges.py +345 -0
  45. codegraph/plugins/dart/extractor/bin/extract.dart +717 -0
  46. codegraph/plugins/dart/extractor/pubspec.lock +149 -0
  47. codegraph/plugins/dart/extractor/pubspec.yaml +7 -0
  48. codegraph/plugins/dart/http.py +904 -0
  49. codegraph/plugins/dart/models.py +308 -0
  50. codegraph/plugins/dart/plugin.py +625 -0
  51. codegraph/plugins/dart/program.py +907 -0
  52. codegraph/plugins/django/__init__.py +0 -0
  53. codegraph/plugins/django/extras.py +378 -0
  54. codegraph/plugins/django/models.py +508 -0
  55. codegraph/plugins/django/plugin.py +728 -0
  56. codegraph/plugins/django/schemas.py +339 -0
  57. codegraph/plugins/django/shapes.py +216 -0
  58. codegraph/plugins/django/urls.py +603 -0
  59. codegraph/plugins/express/__init__.py +0 -0
  60. codegraph/plugins/express/plugin.py +428 -0
  61. codegraph/plugins/flutter/__init__.py +0 -0
  62. codegraph/plugins/flutter/plugin.py +538 -0
  63. codegraph/plugins/kotlin/__init__.py +0 -0
  64. codegraph/plugins/kotlin/exact.py +457 -0
  65. codegraph/plugins/kotlin/plugin.py +1961 -0
  66. codegraph/plugins/kotlin/reparse.py +234 -0
  67. codegraph/plugins/laravel/__init__.py +0 -0
  68. codegraph/plugins/laravel/broadcast.py +351 -0
  69. codegraph/plugins/laravel/plugin.py +863 -0
  70. codegraph/plugins/laravel/tests.py +262 -0
  71. codegraph/plugins/laravel/values.py +728 -0
  72. codegraph/plugins/native/__init__.py +0 -0
  73. codegraph/plugins/native/gates.py +286 -0
  74. codegraph/plugins/native/runner.py +183 -0
  75. codegraph/plugins/native/scipread.py +194 -0
  76. codegraph/plugins/native/ts.py +54 -0
  77. codegraph/plugins/nest/__init__.py +0 -0
  78. codegraph/plugins/nest/plugin.py +654 -0
  79. codegraph/plugins/nextjs/__init__.py +0 -0
  80. codegraph/plugins/nextjs/plugin.py +336 -0
  81. codegraph/plugins/nuxt/__init__.py +0 -0
  82. codegraph/plugins/nuxt/plugin.py +308 -0
  83. codegraph/plugins/php/__init__.py +0 -0
  84. codegraph/plugins/php/extractor/composer.json +5 -0
  85. codegraph/plugins/php/extractor/composer.lock +76 -0
  86. codegraph/plugins/php/extractor/extract.php +743 -0
  87. codegraph/plugins/php/gating.py +573 -0
  88. codegraph/plugins/php/plugin.py +668 -0
  89. codegraph/plugins/php/strings.py +197 -0
  90. codegraph/plugins/python/__init__.py +0 -0
  91. codegraph/plugins/python/aitools.py +664 -0
  92. codegraph/plugins/python/external.py +245 -0
  93. codegraph/plugins/python/fields.py +107 -0
  94. codegraph/plugins/python/plugin.py +1733 -0
  95. codegraph/plugins/python/refs.py +485 -0
  96. codegraph/plugins/python/roots.py +412 -0
  97. codegraph/plugins/python/socketio.py +210 -0
  98. codegraph/plugins/python/subproc.py +864 -0
  99. codegraph/plugins/python/tests.py +1040 -0
  100. codegraph/plugins/python/values.py +179 -0
  101. codegraph/plugins/pyweb/__init__.py +0 -0
  102. codegraph/plugins/pyweb/plugin.py +1334 -0
  103. codegraph/plugins/pyweb/values.py +68 -0
  104. codegraph/plugins/rust/__init__.py +0 -0
  105. codegraph/plugins/rust/cargo.py +226 -0
  106. codegraph/plugins/rust/plugin.py +980 -0
  107. codegraph/plugins/rust/syntax.py +678 -0
  108. codegraph/plugins/scip/__init__.py +0 -0
  109. codegraph/plugins/scip/importer.py +129 -0
  110. codegraph/plugins/scip/scip.proto +962 -0
  111. codegraph/plugins/scip/scip_pb2.py +97 -0
  112. codegraph/plugins/stubs/__init__.py +0 -0
  113. codegraph/plugins/stubs/plugins.py +38 -0
  114. codegraph/plugins/swift/__init__.py +0 -0
  115. codegraph/plugins/swift/baseurl.py +109 -0
  116. codegraph/plugins/swift/exact.py +415 -0
  117. codegraph/plugins/swift/indexstore.py +209 -0
  118. codegraph/plugins/swift/packages.py +174 -0
  119. codegraph/plugins/swift/plugin.py +2890 -0
  120. codegraph/plugins/ts/__init__.py +0 -0
  121. codegraph/plugins/ts/baseurl.py +185 -0
  122. codegraph/plugins/ts/extractor/extract.mjs +2652 -0
  123. codegraph/plugins/ts/extractor/fw.mjs +685 -0
  124. codegraph/plugins/ts/extractor/package-lock.json +205 -0
  125. codegraph/plugins/ts/extractor/package.json +9 -0
  126. codegraph/plugins/ts/plugin.py +480 -0
  127. codegraph/plugins/tsweb/__init__.py +0 -0
  128. codegraph/plugins/tsweb/common.py +290 -0
  129. codegraph/plugins/tsweb/data.py +276 -0
  130. codegraph/presets/__init__.py +146 -0
  131. codegraph/presets/c_cpp.yaml +9 -0
  132. codegraph/presets/common.yaml +66 -0
  133. codegraph/presets/dart.yaml +9 -0
  134. codegraph/presets/django-ninja.yaml +15 -0
  135. codegraph/presets/django.yaml +25 -0
  136. codegraph/presets/djangorestframework.yaml +17 -0
  137. codegraph/presets/express.yaml +17 -0
  138. codegraph/presets/kotlin.yaml +11 -0
  139. codegraph/presets/laravel.yaml +40 -0
  140. codegraph/presets/nest.yaml +11 -0
  141. codegraph/presets/nextjs.yaml +15 -0
  142. codegraph/presets/nuxt.yaml +9 -0
  143. codegraph/presets/php.yaml +5 -0
  144. codegraph/presets/python.yaml +10 -0
  145. codegraph/presets/rust.yaml +5 -0
  146. codegraph/presets/swift.yaml +10 -0
  147. codegraph/presets/typescript.yaml +13 -0
  148. codegraph/process_runs.py +328 -0
  149. codegraph/protocols/__init__.py +299 -0
  150. codegraph/protocols/builtin.py +67 -0
  151. codegraph/protocols/matchers.py +144 -0
  152. codegraph/protocols/view.py +334 -0
  153. codegraph/query.py +2089 -0
  154. codegraph/realtime.py +260 -0
  155. codegraph/roundtrip.py +346 -0
  156. codegraph/routes.py +442 -0
  157. codegraph/starters.py +218 -0
  158. codegraph/tests_index.py +117 -0
  159. codegraph/viz/__init__.py +0 -0
  160. codegraph/viz/graph.py +369 -0
  161. codegraph/viz/server.py +198 -0
  162. codegraph/viz/static/app.css +148 -0
  163. codegraph/viz/static/app.js +1082 -0
  164. codegraph/viz/static/index.html +81 -0
  165. codegraph/viz/static/layered.js +237 -0
  166. codegraph/viz/static/vendor/VERSIONS.txt +4 -0
  167. codegraph/viz/static/vendor/cose-base.js +3214 -0
  168. codegraph/viz/static/vendor/cytoscape-fcose.js +1549 -0
  169. codegraph/viz/static/vendor/cytoscape.min.js +31 -0
  170. codegraph/viz/static/vendor/layout-base.js +5230 -0
  171. codegraph/viz/tools/package-lock.json +303 -0
  172. codegraph/viz/tools/package.json +7 -0
  173. codegraph/viz/tools/shoot.mjs +165 -0
  174. codegraph/xcode.py +251 -0
@@ -0,0 +1,179 @@
1
+ """Enum members and module constants (#84): `enum_case:<module>.<Enum>.<MEMBER>` for the members of a class derived
2
+ from `enum.Enum` (IntEnum, StrEnum, Flag, IntFlag, a project enum base), `constant:<module>.<NAME>` for a module-level
3
+ UPPER_CASE or `Final` name, and USES_VALUE edges where the binding is certain: `Color.RED`, `mod.NAME`, an imported
4
+ `NAME`, or a bare `NAME` of the module that no local binding of the function shadows. Call edges are untouched."""
5
+ from __future__ import annotations
6
+
7
+ import ast
8
+ import re
9
+
10
+ from ...core.model import EXACT
11
+
12
+ CONST_NAME = re.compile(r"^_?[A-Z][A-Z0-9_]*$")
13
+ ENUM_BASES = ("Enum", "IntEnum", "StrEnum", "Flag", "IntFlag", "ReprEnum")
14
+ NOT_CONSTANT_CALLS = {"TypeVar", "ParamSpec", "TypeVarTuple", "NewType", "namedtuple", "NamedTuple", "TypedDict"}
15
+
16
+
17
+ def _final(ann) -> bool:
18
+ if ann is None:
19
+ return False
20
+ a = ann.value if isinstance(ann, ast.Subscript) else ann
21
+ return (isinstance(a, ast.Name) and a.id == "Final") or (isinstance(a, ast.Attribute) and a.attr == "Final")
22
+
23
+
24
+ def _called(v) -> str | None:
25
+ if isinstance(v, ast.Call):
26
+ f = v.func
27
+ return f.id if isinstance(f, ast.Name) else f.attr if isinstance(f, ast.Attribute) else None
28
+ return None
29
+
30
+
31
+ def _top_assigns(body):
32
+ """Module-level assignments, including those under a top-level `if` / `try` (`try: X = 1 except: X = 2`)."""
33
+ for st in body:
34
+ if isinstance(st, (ast.Assign, ast.AnnAssign)):
35
+ yield st
36
+ elif isinstance(st, (ast.If, ast.Try)) or type(st).__name__ == "TryStar":
37
+ yield from _top_assigns(getattr(st, "body", []) + getattr(st, "orelse", []) + getattr(st, "finalbody", []))
38
+ for h in getattr(st, "handlers", []):
39
+ yield from _top_assigns(h.body)
40
+
41
+
42
+ def _targets(st) -> list[str]:
43
+ tg = st.targets if isinstance(st, ast.Assign) else [st.target]
44
+ return [t.id for t in tg if isinstance(t, ast.Name)]
45
+
46
+
47
+ class Values:
48
+ def __init__(self, prog, b):
49
+ self.prog, self.b = prog, b
50
+ self.cases: dict[str, dict[str, str]] = {} # enum class qual -> member -> id
51
+ self.consts: dict[str, dict[str, str]] = {} # module name -> NAME -> id
52
+ self.st = {"enum_cases": 0, "constants": 0, "value_refs": 0}
53
+
54
+ def run(self) -> dict:
55
+ prog = self.prog
56
+ for c in prog.classes.values():
57
+ if c.name in ENUM_BASES or not prog.subclass_of(c, *ENUM_BASES):
58
+ continue
59
+ for st in c.node.body:
60
+ if not isinstance(st, (ast.Assign, ast.AnnAssign)) or getattr(st, "value", None) is None:
61
+ continue
62
+ if isinstance(st.value, (ast.Lambda,)) or _called(st.value) in ("property", "staticmethod", "classmethod"):
63
+ continue
64
+ for nm in _targets(st):
65
+ if nm.startswith("_"):
66
+ continue # `_ignore_`, `_order_`, private names: not members
67
+ self._node("enum_case", c.qual, nm, c.id, c.file, st)
68
+ self.cases.setdefault(c.qual, {})[nm] = f"enum_case:{c.qual}.{nm}"
69
+ for m in prog.modules.values():
70
+ for st in _top_assigns(m.tree.body):
71
+ if getattr(st, "value", None) is None or _called(st.value) in NOT_CONSTANT_CALLS:
72
+ continue
73
+ for nm in _targets(st):
74
+ if nm in m.classes or nm in m.funcs or nm.startswith("__") or \
75
+ not (CONST_NAME.match(nm) or _final(getattr(st, "annotation", None))):
76
+ continue
77
+ if nm in self.consts.get(m.name, {}):
78
+ continue # `X = 1` re-assigned later (or in an `else`): one constant
79
+ self._node("constant", m.name, nm, m.id, m.file, st)
80
+ self.consts.setdefault(m.name, {})[nm] = f"constant:{m.name}.{nm}"
81
+ if self.cases or self.consts:
82
+ self._refs()
83
+ return self.st
84
+
85
+ def _node(self, kind, owner_q, nm, owner_id, file, st):
86
+ nid = self.b.add_node(kind, f"{owner_q}.{nm}", name=nm, fqn=f"{owner_q}.{nm}", file=file, line=st.lineno,
87
+ end_line=getattr(st, "end_lineno", None), lang="python")
88
+ self.b.add_edge(owner_id, nid, "CONTAINS", file, st.lineno, EXACT)
89
+ self.st["enum_cases" if kind == "enum_case" else "constants"] += 1
90
+
91
+ # ------------------------------------------------------------------ references
92
+ def _refs(self):
93
+ prog = self.prog
94
+ for f in list(prog.funcs.values()):
95
+ self._scan(f.id, f.module, f.node, f.file, self._locals(f.node), prog.func_imports(f))
96
+ for m in prog.modules.values():
97
+ self._scan_body(m.id, m, m.tree.body, m.file)
98
+ for c in m.all_classes:
99
+ self._scan_body(c.id, m, c.node.body, m.file, cls=c)
100
+
101
+ def _scan_body(self, owner, m, body, file, cls=None):
102
+ for st in body:
103
+ if isinstance(st, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
104
+ for d in getattr(st, "decorator_list", []):
105
+ self._scan(owner, m, d, file, set(), {})
106
+ continue
107
+ # class body: its own names are class attributes (an enum's members among them), not module constants
108
+ local = {t for s in body if isinstance(s, (ast.Assign, ast.AnnAssign)) for t in _targets(s)} \
109
+ if cls is not None else set()
110
+ self._scan(owner, m, st, file, local, {})
111
+
112
+ @staticmethod
113
+ def _locals(fn) -> set[str]:
114
+ """Names a def binds (Python scoping: a name assigned anywhere in the function is local throughout)."""
115
+ out, glob = set(), set()
116
+ a = fn.args
117
+ for x in a.posonlyargs + a.args + a.kwonlyargs + [a.vararg, a.kwarg]:
118
+ if x is not None:
119
+ out.add(x.arg)
120
+ for n in ast.walk(fn):
121
+ if isinstance(n, ast.Name) and isinstance(n.ctx, (ast.Store, ast.Del)):
122
+ out.add(n.id)
123
+ elif isinstance(n, (ast.Global, ast.Nonlocal)):
124
+ glob.update(n.names)
125
+ elif isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)) and n is not fn:
126
+ out.add(n.name)
127
+ elif isinstance(n, ast.arg):
128
+ out.add(n.arg) # a nested def's / lambda's parameter: shadows conservatively
129
+ elif isinstance(n, (ast.Import, ast.ImportFrom)):
130
+ out.update((al.asname or al.name).split(".")[0] for al in n.names)
131
+ elif isinstance(n, ast.ExceptHandler) and n.name:
132
+ out.add(n.name)
133
+ return out - glob
134
+
135
+ def _resolve(self, m, e, local, fimps, depth=0):
136
+ """What expression `e` names: ("type", ClassInfo) / ("mod", ModInfo) / ("var", ModInfo, name) / None."""
137
+ prog = self.prog
138
+ if depth > 6:
139
+ return None
140
+ if isinstance(e, ast.Name):
141
+ if e.id in local and e.id not in fimps:
142
+ return None
143
+ if e.id in fimps:
144
+ return prog._resolve_import(fimps[e.id])
145
+ return prog.resolve_name(m, e.id)
146
+ if isinstance(e, ast.Attribute):
147
+ base = self._resolve(m, e.value, local, fimps, depth + 1)
148
+ if base is None:
149
+ return None
150
+ if base[0] == "mod":
151
+ return prog.lookup(base[1].name, e.attr)
152
+ if base[0] == "type":
153
+ inner = getattr(base[1], "inner_infos", {}).get(e.attr)
154
+ return ("type", inner) if inner is not None else None
155
+ return None
156
+
157
+ def _value_of(self, r, attr: str | None = None):
158
+ if r is None:
159
+ return None
160
+ if attr is not None:
161
+ if r[0] == "type":
162
+ return self.cases.get(r[1].qual, {}).get(attr)
163
+ if r[0] == "mod":
164
+ return self.consts.get(r[1].name, {}).get(attr)
165
+ return None
166
+ if r[0] == "var":
167
+ return self.consts.get(r[1].name, {}).get(r[2])
168
+ return None
169
+
170
+ def _scan(self, owner, m, node, file, local, fimps):
171
+ for n in ast.walk(node):
172
+ vid = None
173
+ if isinstance(n, ast.Attribute) and isinstance(n.ctx, ast.Load):
174
+ vid = self._value_of(self._resolve(m, n.value, local, fimps), n.attr)
175
+ elif isinstance(n, ast.Name) and isinstance(n.ctx, ast.Load) and (n.id in fimps or n.id not in local):
176
+ vid = self._value_of(self._resolve(m, n, local, fimps))
177
+ if vid is not None and vid != owner:
178
+ self.b.add_edge(owner, vid, "USES_VALUE", file, n.lineno, EXACT)
179
+ self.st["value_refs"] += 1
File without changes