code-node-graph 0.1.0__py3-none-any.whl → 0.2.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.
code_node/__init__.py CHANGED
@@ -13,7 +13,7 @@ from .libraries import Library, register_library
13
13
  from .platforms import Platform, get_platform, register_platform
14
14
  from .project import EntryPoint, Project, entry_points, read_project
15
15
 
16
- __version__ = "0.1.0"
16
+ __version__ = "0.2.0"
17
17
 
18
18
  __all__ = [
19
19
  "CodeGraph",
code_node/report/graph.py CHANGED
@@ -13,8 +13,8 @@ from typing import Any, Callable
13
13
 
14
14
  from ..kit.blocks import _Report, _draws
15
15
  from ..kit.fmt import _plural
16
- from ..kit.highlight import _python_lines
17
- from ..kit.render import _prose
16
+ from ..kit.highlight import _python_html, _python_lines
17
+ from ..kit.render import _CALL_RE, _prose
18
18
  from ..kit.text import _esc
19
19
 
20
20
  from ..analysis.graph import CodeGraph, GraphEdge, GraphNode
@@ -1081,7 +1081,7 @@ def _node_svg(
1081
1081
  )
1082
1082
  classes = " ".join(["cn", f"k-{n.kind}", f"n-{n.id}", *(f"a-{m}" for m in neighbours)]) + (" warn" if warn else "")
1083
1083
  return (
1084
- f'<g class="{_esc(classes)}" transform="translate({x:.1f},{y:.1f})"><title>{_esc(n.tip or n.label)}</title>'
1084
+ f'<g class="{_esc(classes)}" transform="translate({x:.1f},{y:.1f})">'
1085
1085
  f'<rect class="bg" width="{w:.0f}" height="{h:.0f}" rx="11"/>'
1086
1086
  f'<rect class="fg" x=".5" y=".5" width="{w - 1:.0f}" height="{h - 1:.0f}" rx="10.5"/>{"".join(parts)}</g>'
1087
1087
  )
@@ -1175,6 +1175,153 @@ def _g_panel(n: GraphNode, lines_of: Callable[[str], list[str]], editor: str = "
1175
1175
  )
1176
1176
 
1177
1177
 
1178
+ _G_TIP_W = 420 # a box's hover card, wide
1179
+
1180
+ _G_TIP_SIGNATURE = 6 # lines of a def its hover card shows, at most
1181
+
1182
+ _G_TIP_WARNING = "A warning is about it: "
1183
+
1184
+ # a name in the card's sentences worth setting as code: a dotted or keyed path (Records[].s3.bucket.name,
1185
+ # book:{book_id}, s3:GetObject, orders/handler.py) or a variable in capitals (DB_HOST)
1186
+ _G_CODE_RE = re.compile(
1187
+ r"(?<![\w.\-/])([A-Za-z_][\w\-]*(?:[.:/]+[\w{}\-]+|\[\]|\{\w*\})+|[A-Z][A-Z0-9]*_[A-Z0-9_]*[A-Z0-9])(?![\w{])"
1188
+ )
1189
+
1190
+
1191
+ def _g_tip_text(text: str) -> str:
1192
+ """
1193
+ One of the card's sentences as HTML, its calls coloured as Python and its names set as code, every piece escaped.
1194
+ """
1195
+ out = []
1196
+ for i, piece in enumerate(_CALL_RE.split(text)):
1197
+ if i % 2:
1198
+ out.append(f'<code class="ctk">{_python_html(piece)}</code>')
1199
+ continue
1200
+ for k, part in enumerate(_G_CODE_RE.split(piece)):
1201
+ out.append(f'<code class="ctk ctn">{_esc(part)}</code>' if k % 2 else _esc(part))
1202
+ return "".join(out)
1203
+
1204
+
1205
+ def _g_tip_item(item: str) -> str:
1206
+ """
1207
+ One thing a service box lists, for its card: 'PutItem (dynamodb:PutItem)' as the operation in code and what it
1208
+ needs beside it.
1209
+ """
1210
+ m = re.fullmatch(r"(.+?) \((.+)\)", item)
1211
+ if not m:
1212
+ return f'<li><code class="ctk ctn">{_esc(item)}</code></li>'
1213
+ return (
1214
+ f'<li><code class="ctk ctn">{_esc(m.group(1))}</code> <span class="ctm">{_g_tip_text(m.group(2))}</span></li>'
1215
+ )
1216
+
1217
+
1218
+ def _g_tip_signature(n: GraphNode, lines_of: Callable[[str], list[str]]) -> list[str]:
1219
+ """
1220
+ A function's def as it's written, in colour: its decorators and the lines up to the colon that opens its body.
1221
+ [] when its file wasn't read.
1222
+ """
1223
+ if not n.code:
1224
+ return []
1225
+ span = n.code[0]
1226
+ lines = lines_of(span.file)
1227
+ if not lines or span.start > len(lines):
1228
+ return []
1229
+ start = span.start
1230
+ while start > 1 and lines[start - 2].lstrip().startswith("@"):
1231
+ start -= 1
1232
+ shown = []
1233
+ for k in range(start, min(len(lines), span.end, start + _G_TIP_SIGNATURE - 1) + 1):
1234
+ shown.append(lines[k - 1])
1235
+ if k >= span.start and re.sub(r"<[^>]*>", "", lines[k - 1]).rstrip().endswith(":"):
1236
+ break
1237
+ indent = min((len(line) - len(line.lstrip(" ")) for line in shown if line.strip()), default=0)
1238
+ return [line[indent:] for line in shown]
1239
+
1240
+
1241
+ def _g_tip(n: GraphNode, lines_of: Callable[[str], list[str]], opens: bool) -> tuple[str, float]:
1242
+ """
1243
+ What a box says on hover, as a card: what kind of box it is and its name, a function's def in colour and its
1244
+ docstring, then the rest of its words with the code in them set as code, its warnings apart, and when it has a
1245
+ panel (opens), that a click shows its code. With how tall it is likely to be, to pick whether it goes under the
1246
+ box or over it.
1247
+ """
1248
+ said = [line for line in (n.tip or n.label).split("\n") if line]
1249
+ warnings = [w for line in said if line.startswith(_G_TIP_WARNING) for w in line[len(_G_TIP_WARNING) :].split("; ")]
1250
+ said = [line for line in said if not line.startswith(_G_TIP_WARNING)]
1251
+ mono = n.kind in ("handler", "function")
1252
+ body, tall, sub = [], 80.0 + (20 if n.sub else 0), n.sub
1253
+ if mono and said and _CALL_RE.match(said[0]) and " in " in said[0]: # 'name(args) in file, 3 lines: its doc'
1254
+ head = said.pop(0)
1255
+ signature = _g_tip_signature(n, lines_of) or [_python_html(head.split(" in ", 1)[0])]
1256
+ body.append(f'<pre class="ctc">{chr(10).join(signature)}</pre>')
1257
+ tall += 21 * len(signature) + 34
1258
+ lines = re.search(r", (\d+ lines?)", head)
1259
+ sub = f"{n.sub} · {lines.group(1)}" if lines and n.sub else sub
1260
+ if n.lines and n.lines[0]:
1261
+ body.append(f'<p class="ctd">{_g_tip_text(n.lines[0])}</p>')
1262
+ tall += 23 * math.ceil(len(n.lines[0]) / 42) + 10
1263
+ for line in said:
1264
+ lead, _, rest = line.partition(": ")
1265
+ if rest and lead == n.label: # 'S3: GetObject (s3:GetObject), PutObject (s3:PutObject)': a list
1266
+ items = rest.split(", ")
1267
+ body.append(f'<ul class="ctl">{"".join(_g_tip_item(item) for item in items)}</ul>')
1268
+ tall += 30 * len(items) + 8
1269
+ else:
1270
+ body.append(f'<p class="ctp">{_g_tip_text(line)}</p>')
1271
+ tall += 23 * math.ceil(len(line) / 42) + 10
1272
+ if warnings:
1273
+ body.append(
1274
+ '<div class="ctw"><b>Warning</b><ul>'
1275
+ + "".join(f"<li>{_g_tip_text(w)}</li>" for w in warnings)
1276
+ + "</ul></div>"
1277
+ )
1278
+ tall += 50 + sum(23 * math.ceil(len(w) / 36) + 4 for w in warnings)
1279
+ kind = _G_PANEL_KINDS.get(n.kind, n.kind)
1280
+ name = _python_html(n.label) if mono else _esc(n.label)
1281
+ card = (
1282
+ f'<div class="ctt k-{_esc(n.kind)}{" warn" if warnings else ""}"><div class="cth">'
1283
+ f'<span class="ctkd">{_esc(kind)}</span><b class="ctn{" mono" if mono else ""}">{name}</b>'
1284
+ + (f'<span class="cts{" mono" if mono else ""}">{_esc(sub)}</span>' if sub else "")
1285
+ + f"</div>{''.join(body)}"
1286
+ + ('<div class="cto">Click it to read its code</div>' if opens else "")
1287
+ + "</div>"
1288
+ )
1289
+ return card, tall + (40 if opens else 0)
1290
+
1291
+
1292
+ def _g_tip_svg(
1293
+ n: GraphNode,
1294
+ box: tuple[float, float, float, float],
1295
+ width: float,
1296
+ tall: float,
1297
+ lines_of: Callable[[str], list[str]],
1298
+ opens: bool,
1299
+ ) -> str:
1300
+ """
1301
+ A box's hover card, in the graph so it zooms with it: under the box when it fits there, else over it, else beside
1302
+ it, and inside the graph from left to right. Hidden until the box is pointed at.
1303
+ """
1304
+ card, high = _g_tip(n, lines_of, opens)
1305
+ x, y, w, h = box
1306
+ card_w = min(_G_TIP_W, max(width - 16, 220))
1307
+ left = max(8.0, min(x, width - card_w - 8))
1308
+ below, above = tall - (y + h + 10) - 8, y - 10 - 8
1309
+ if high <= below:
1310
+ top, room, side = y + h + 10, below, "dn"
1311
+ elif high <= above:
1312
+ top, room, side = 8.0, above, "up"
1313
+ else: # beside the box, as high up as keeps all of it in the graph; over the box only when there's no room beside
1314
+ if width - (x + w + 12) - 8 >= card_w:
1315
+ left = x + w + 12
1316
+ elif x - 12 - 8 >= card_w:
1317
+ left = x - 12 - card_w
1318
+ top, room, side = max(8.0, min(y, tall - high - 8)), high, "dn"
1319
+ return (
1320
+ f'<foreignObject class="ctip tp-{_esc(n.id)} {side}" x="{left:.0f}" y="{top:.0f}" width="{card_w:.0f}" '
1321
+ f'height="{room:.0f}" aria-hidden="true"><div class="ctx">{card}</div></foreignObject>'
1322
+ )
1323
+
1324
+
1178
1325
  def _g_captions(graph: CodeGraph, xs: dict[int, float], widths: dict[int, float], column_of: dict[str, int]) -> str:
1179
1326
  """
1180
1327
  The words over the columns: COMES IN, HANDLER, CALLS, REACHES, each over the columns it covers.
@@ -1256,6 +1403,7 @@ def _graph_html(block: _Graph, report: _Report) -> str:
1256
1403
  for n in graph.nodes: # pointing at a box leaves only it, its arrows and the boxes they join in sight
1257
1404
  report.rules.add(f".{root} .cg:has(.n-{n.id}:hover) .ce:not(.s-{n.id}):not(.t-{n.id}){{opacity:.06}}")
1258
1405
  report.rules.add(f".{root} .cg:has(.n-{n.id}:hover) .cn:not(.n-{n.id}):not(.a-{n.id}){{opacity:.28}}")
1406
+ report.rules.add(f".{root} .cg:has(.n-{n.id}:hover) .tp-{n.id}{{display:inline}}")
1259
1407
  report.rules.add(
1260
1408
  f".{root} .cg:has(.n-{n.id}:hover) :is(.s-{n.id},.t-{n.id}) .ln{{stroke-width:2.4;stroke-opacity:1}}"
1261
1409
  )
@@ -1307,6 +1455,7 @@ def _graph_html(block: _Graph, report: _Report) -> str:
1307
1455
  for n in graph.nodes
1308
1456
  for box in [_node_svg(cards[n.id], boxes[n.id], list(dict.fromkeys(near[n.id])), access[n.id])]
1309
1457
  )
1458
+ tips = "".join(_g_tip_svg(n, boxes[n.id], width, tall, lines_of, bool(panels.get(n.id))) for n in graph.nodes)
1310
1459
  kinds = {e.kind for e in graph.edges}
1311
1460
  pills = [f'<span class="kp">{_g_swatch(k)}{_esc(word)}</span>' for k, word in _G_LEGEND if k in kinds]
1312
1461
  if any(e.guessed for e in graph.edges):
@@ -1362,7 +1511,7 @@ def _graph_html(block: _Graph, report: _Report) -> str:
1362
1511
  f'{title}<div class="cgw">{switches}<div class="cgb">{bar}<div class="cg">'
1363
1512
  f'<svg viewBox="0 0 {width:.0f} {tall:.0f}" width="{width:.0f}" height="{tall:.0f}" '
1364
1513
  f'style="--w:{width:.0f}px" role="img" aria-label="{_esc(block.title or "How the code fits together")}">'
1365
- f"{_g_captions(graph, xs, widths, column_of)}{edges}{nodes}{ports}</svg></div>"
1514
+ f"{_g_captions(graph, xs, widths, column_of)}{edges}{nodes}{ports}{tips}</svg></div>"
1366
1515
  f'<div class="cgk">{"".join(pills)}{hidden}{hint}</div></div>{"".join(panels.values())}</div>'
1367
1516
  )
1368
1517
 
code_node/report/style.py CHANGED
@@ -95,12 +95,12 @@ _EXTRA_CSS = """\
95
95
  .cnd .flow .oq{font-style:italic}
96
96
  .cnd .flow .os{display:inline-flex;flex-wrap:wrap;gap:3px 5px}
97
97
  .cnd .flow .ob{margin-left:22px}
98
- .cnd :is(.flow,.cside,.walk) .pk{color:var(--jp-mirror-editor-keyword-color,light-dark(#7c3aed,#c792ea))}
99
- .cnd :is(.flow,.cside,.walk) .pf{color:var(--jp-mirror-editor-def-color,light-dark(#2563eb,#82aaff))}
100
- .cnd :is(.flow,.cside,.walk) :is(.js,.jk){color:var(--jp-mirror-editor-string-color,light-dark(#047857,#a5d6a7))}
101
- .cnd :is(.flow,.cside,.walk) :is(.jn,.jl){color:var(--jp-mirror-editor-number-color,light-dark(#c2410c,#f78c6c))}
102
- .cnd :is(.flow,.cside,.walk) .pa{font-style:italic}
103
- .cnd :is(.flow,.cside,.walk) .pc{opacity:.6;font-style:italic}
98
+ .cnd :is(.flow,.cside,.walk,.ctip) .pk{color:var(--jp-mirror-editor-keyword-color,light-dark(#7c3aed,#c792ea))}
99
+ .cnd :is(.flow,.cside,.walk,.ctip) .pf{color:var(--jp-mirror-editor-def-color,light-dark(#2563eb,#82aaff))}
100
+ .cnd :is(.flow,.cside,.walk,.ctip) :is(.js,.jk){color:var(--jp-mirror-editor-string-color,light-dark(#047857,#a5d6a7))}
101
+ .cnd :is(.flow,.cside,.walk,.ctip) :is(.jn,.jl){color:var(--jp-mirror-editor-number-color,light-dark(#c2410c,#f78c6c))}
102
+ .cnd :is(.flow,.cside,.walk,.ctip) .pa{font-style:italic}
103
+ .cnd :is(.flow,.cside,.walk,.ctip) .pc{opacity:.6;font-style:italic}
104
104
  .cnd .cgb{width:fit-content;max-width:min(100%,1180px)}
105
105
  .cnd .cg{border:1px solid rgba(127,127,127,.2);border-radius:14px;margin:6px 0 8px;overflow:auto;background-color:rgba(127,127,127,.035);background-attachment:local;background-size:18px 18px;
106
106
  background-image:radial-gradient(circle at 1px 1px,rgba(127,127,127,.3) 1px,transparent 0);background-position:9px 9px}
@@ -221,6 +221,34 @@ _EXTRA_CSS = """\
221
221
  .cnd .cgk .kl path{fill:none;stroke:currentColor;stroke-opacity:.8;stroke-width:2.1;stroke-linecap:round;stroke-linejoin:round}
222
222
  .cnd .cg a.cl{cursor:pointer;outline:none}
223
223
  .cnd .cg a.cl:focus-visible .fg{stroke:light-dark(#2563eb,#60a5fa);stroke-opacity:1;stroke-width:2}
224
+ .cnd .cg .ctip{display:none;overflow:visible;pointer-events:none}
225
+ .cnd .cg .ctip .ctx{display:flex;flex-direction:column;height:100%}
226
+ .cnd .cg .ctip.up .ctx{justify-content:flex-end}
227
+ .cnd .cg .ctt{position:relative;box-sizing:border-box;padding:16px 18px;border:1px solid rgba(127,127,127,.3);border-radius:12px;background:var(--jp-layout-color0,var(--vscode-editor-background,Canvas));color:CanvasText;box-shadow:0 2px 6px rgba(15,23,42,.08),0 14px 34px rgba(15,23,42,.18);font-size:14px;line-height:1.6;text-align:left;animation:cnTip .14s ease-out .18s both}
228
+ @keyframes cnTip{from{opacity:0;transform:translateY(3px)}to{opacity:1;transform:none}}
229
+ @media (prefers-reduced-motion:reduce){.cnd .cg .ctt{animation:none}}
230
+ .cnd .cg .ctt.k-function,.cnd .cg .ctt.k-handler{--c:light-dark(#2563eb,#82aaff)}
231
+ .cnd .cg .cth{display:flex;flex-direction:column;gap:3px;margin:0 0 14px}
232
+ .cnd .cg .ctkd{font-size:10.5px;font-weight:650;letter-spacing:.08em;text-transform:uppercase;color:var(--c,currentColor);opacity:.9}
233
+ .cnd .cg .ctt b.ctn{font-size:16px;font-weight:650;overflow-wrap:anywhere}
234
+ .cnd .cg .ctt b.ctn.mono{font:650 15px var(--mono)}
235
+ .cnd .cg .cts{font-size:12.5px;opacity:.65;overflow-wrap:anywhere}
236
+ .cnd .cg .cts.mono{font-family:var(--mono)}
237
+ .cnd .cg .ctt pre.ctc{margin:0 0 12px;padding:10px 12px;border:1px solid rgba(127,127,127,.2);border-radius:8px;background:rgba(127,127,127,.06);font:13px/1.55 var(--mono);white-space:pre-wrap;overflow-wrap:anywhere}
238
+ .cnd .cg .cto{margin:16px -18px -16px;padding:9px 18px;border-top:1px solid rgba(127,127,127,.16);border-radius:0 0 12px 12px;background:rgba(127,127,127,.05);font-size:12px;opacity:.7}
239
+ .cnd .cg .ctt p{margin:0 0 10px;overflow-wrap:anywhere}
240
+ .cnd .cg .ctt p:last-child{margin-bottom:0}
241
+ .cnd .cg .ctt p.ctd{font-style:italic;opacity:.85}
242
+ .cnd .cg .ctt p.ctp{opacity:.88}
243
+ .cnd .cg .ctt code.ctk{font:12.5px var(--mono);padding:1px 5px;border-radius:4px;background:rgba(127,127,127,.12);overflow-wrap:anywhere}
244
+ .cnd .cg .ctt code.ctn{color:light-dark(#0f766e,#7dd3c0)}
245
+ .cnd .cg .ctt ul{margin:0;padding:0;list-style:none}
246
+ .cnd .cg .ctt ul.ctl li{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px;padding:6px 0;border-top:1px solid rgba(127,127,127,.14)}
247
+ .cnd .cg .ctt ul.ctl li:first-child{border-top:none}
248
+ .cnd .cg .ctt .ctm{font-size:12px;opacity:.7}
249
+ .cnd .cg .ctt .ctw{margin:12px 0 0;padding:10px 14px;border-radius:8px;background:rgba(245,158,11,.12);border-left:3px solid #f59e0b}
250
+ .cnd .cg .ctt .ctw b{display:block;margin:0 0 4px;font-size:10.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:light-dark(#b45309,#fbbf24)}
251
+ .cnd .cg .ctt .ctw li{margin:4px 0 0;overflow-wrap:anywhere}
224
252
  .cnd .cside{position:fixed;top:0;right:0;bottom:0;z-index:30;box-sizing:border-box;width:min(660px,94vw);overflow:auto;padding:0 20px 28px;background:var(--jp-layout-color0,var(--vscode-editor-background,Canvas));color:CanvasText;border-left:1px solid rgba(127,127,127,.3);box-shadow:-14px 0 36px rgba(15,23,42,.14);transform:translateX(104%);visibility:hidden;transition:transform .22s ease,visibility 0s linear .22s}
225
253
  .cnd .cside:target{transform:none;visibility:visible;transition:transform .22s ease}
226
254
  .cnd .cside .csh{display:flex;align-items:flex-start;gap:12px;position:sticky;top:0;z-index:1;margin:0 -20px 12px;padding:16px 20px 12px;background:var(--jp-layout-color0,var(--vscode-editor-background,Canvas));border-bottom:1px solid rgba(127,127,127,.2)}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: code-node-graph
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: See how Python code works without running it: a graph of who calls whom from an entry point, and what each path reaches.
5
5
  Project-URL: Homepage, https://github.com/utkarsh5026/code-node
6
6
  Project-URL: Documentation, https://utkarsh5026.github.io/code-node/
@@ -1,4 +1,4 @@
1
- code_node/__init__.py,sha256=P00enhUnqmeAPpAajqOLb8MJQ7ljxA1RS4mSfcurHPU,1106
1
+ code_node/__init__.py,sha256=sfJ6RjFtxsJMr0-zronmOKVpmXZECgEUsWBV3BKfHrA,1106
2
2
  code_node/__main__.py,sha256=0W2bmerF1S96rjlTNJZKVzO4FvVhN6ENzAl451A08sQ,101
3
3
  code_node/cli.py,sha256=GI0vZY1t4Pf7qtZI2coTpWZi-ulQEWNREDJPkTtmxG0,12302
4
4
  code_node/pages.py,sha256=2UOrHUz3G_vAjPO89phJxhF4652FysVLgrLtJ-Iw6p4,3234
@@ -34,9 +34,9 @@ code_node/report/__init__.py,sha256=l3dfZFbLEo-7Fl7O_Rk2lvyAElQnyugSZPI_PzHrG_Q,
34
34
  code_node/report/brands.py,sha256=n32BfFz2d02ZVUHvy8L4wPHBtiD_1FCTKzdR4NyvU88,8372
35
35
  code_node/report/build.py,sha256=F0wdC0ibu3WSAenUsovUWuKwLC0vVxnNYKJVXtU5jRk,4644
36
36
  code_node/report/editor.py,sha256=TRUX6BTB-oe-m5Vf3xM9PppnC99sCLL4PObXkYAGKoU,1466
37
- code_node/report/graph.py,sha256=bLbsB8YxByX7RWH9Hmyc76aq6VHsllgcPyIKQpszW6Y,60090
37
+ code_node/report/graph.py,sha256=YbrVWbymYUL8-KOdsDSRhD2RxCMWbGVEhHD0-MSjX1I,66832
38
38
  code_node/report/outline.py,sha256=3RRxU4FMUZKBVjFDsscKZkvDlj_W4ZeW4DwUztg4wd0,8539
39
- code_node/report/style.py,sha256=rpubo57Qbgp1m4zsn4sfBikkzNSJuRTNXC__07qylEs,31021
39
+ code_node/report/style.py,sha256=zTOZ552sasyRASnm8-P8XNzashtxHe38RkvOZTMDm24,33743
40
40
  code_node/report/tabs.py,sha256=K2XR16owfgEL1kfux61PI9nBcRsgjQurTx1ptMM5Mac,3016
41
41
  code_node/report/walk.py,sha256=jumSV-x1X0D614V7K0zECCSWk69OkHNR7IuDt8K4ggg,27516
42
42
  code_node/report/logos/README.md,sha256=8Evw8eApl_56QJrwY7LAtGgJMZE0mp0-HIpRz9bu1ME,613
@@ -171,8 +171,8 @@ code_node/report/logos/small/aws-systems-manager.svg,sha256=9VzzFdTjaRZO9ulR8Ulp
171
171
  code_node/report/logos/small/aws-timestream.svg,sha256=yKdKIj7pbooFqDKClEQxW9h7dYV5mnDn0RCHnLUDf8Q,639
172
172
  code_node/report/logos/small/aws-waf.svg,sha256=l9ZzBZAl2g8bK1-m6A50ga37l5g1t-9Mj70bxWDykWE,591
173
173
  code_node/report/logos/small/aws-xray.svg,sha256=VKg_QtKGZKDCbZvKBRDn7eReuNVbJpduBUVV8MQrZZU,591
174
- code_node_graph-0.1.0.dist-info/METADATA,sha256=h488K0OzyyEL7CfcJxU8_HOogMK3qIP2Qm_tfK3hwuk,7619
175
- code_node_graph-0.1.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
176
- code_node_graph-0.1.0.dist-info/entry_points.txt,sha256=eEArp-uk7ZzODIWr6l62rI0-mIA0-mLDaqJEyKikPJw,49
177
- code_node_graph-0.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
178
- code_node_graph-0.1.0.dist-info/RECORD,,
174
+ code_node_graph-0.2.0.dist-info/METADATA,sha256=BkbfZl6ViABwgsSH4QAJoGIkbbTNyfAp6FuPyo9JJuA,7619
175
+ code_node_graph-0.2.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
176
+ code_node_graph-0.2.0.dist-info/entry_points.txt,sha256=eEArp-uk7ZzODIWr6l62rI0-mIA0-mLDaqJEyKikPJw,49
177
+ code_node_graph-0.2.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
178
+ code_node_graph-0.2.0.dist-info/RECORD,,