sourcecode 1.57.0__py3-none-any.whl → 1.58.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.
sourcecode/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "1.57.0"
3
+ __version__ = "1.58.0"
@@ -70,6 +70,17 @@ _SEVERITY_WEIGHT: dict[str, float] = {
70
70
  "low": 1.0,
71
71
  }
72
72
 
73
+ # Maps the categorical confidence to a numeric score so impact-chain output
74
+ # carries the same `confidence_score`/`confidence_level` pair as the `impact`
75
+ # command. Deterministic — mirrors impact's confidence banding (high≥0.75,
76
+ # medium≥0.45).
77
+ _CONFIDENCE_SCORE: dict[str, float] = {
78
+ "high": 0.9,
79
+ "medium": 0.6,
80
+ "low": 0.3,
81
+ "unknown": 0.0,
82
+ }
83
+
73
84
 
74
85
  # ---------------------------------------------------------------------------
75
86
  # Output model
@@ -117,10 +128,16 @@ class ImpactChainResult:
117
128
  impact_findings: list[dict] = field(default_factory=list) # SpringFinding.to_dict() filtered
118
129
  analysis_warnings: list[str] = field(default_factory=list)
119
130
  risk_level: str = "unknown" # "critical" | "high" | "medium" | "low" | "unknown"
120
- confidence: str = "high" # "high" | "medium" | "low"
131
+ risk_score: float = 0.0 # numeric score behind risk_level (parity with `impact`)
132
+ confidence: str = "high" # "high" | "medium" | "low" (legacy field, kept)
133
+ explanation: str = "" # human-readable rationale (parity with `impact`)
121
134
  metadata: dict = field(default_factory=dict)
122
135
 
123
136
  def to_dict(self) -> dict:
137
+ # `confidence_level`/`confidence_score` mirror the `impact` command's schema
138
+ # so AI agents parse both commands with one shape. `confidence` (string) is
139
+ # retained for backward compatibility — it equals `confidence_level`.
140
+ confidence_level = self.confidence
124
141
  d: dict = {
125
142
  "schema_version": self.schema_version,
126
143
  "symbol": self.symbol,
@@ -134,7 +151,11 @@ class ImpactChainResult:
134
151
  "impact_findings": self.impact_findings,
135
152
  "analysis_warnings": self.analysis_warnings,
136
153
  "risk_level": self.risk_level,
154
+ "risk_score": self.risk_score,
137
155
  "confidence": self.confidence,
156
+ "confidence_level": confidence_level,
157
+ "confidence_score": _CONFIDENCE_SCORE.get(confidence_level, 0.0),
158
+ "explanation": self.explanation,
138
159
  "metadata": self.metadata,
139
160
  }
140
161
  return d
@@ -680,6 +701,33 @@ def _compute_risk(
680
701
  return level, round(total, 2)
681
702
 
682
703
 
704
+ def _build_chain_explanation(
705
+ risk_level: str,
706
+ direct_callers: int,
707
+ indirect_callers: int,
708
+ endpoints_affected: int,
709
+ findings: int,
710
+ confidence: str,
711
+ ) -> str:
712
+ """Human-readable rationale, phrased to match the `impact` command's
713
+ explanation so both surfaces read consistently."""
714
+ if not direct_callers and not indirect_callers and not endpoints_affected:
715
+ return "No callers or endpoints found in the impact chain. Low-risk isolated change."
716
+ parts: list[str] = []
717
+ if direct_callers:
718
+ parts.append(f"{direct_callers} direct caller{'s' if direct_callers != 1 else ''}")
719
+ if indirect_callers:
720
+ parts.append(f"{indirect_callers} indirect caller{'s' if indirect_callers != 1 else ''}")
721
+ if endpoints_affected:
722
+ parts.append(f"{endpoints_affected} endpoint{'s' if endpoints_affected != 1 else ''} exposed")
723
+ if findings:
724
+ parts.append(f"{findings} TX/SEC finding{'s' if findings != 1 else ''} in chain")
725
+ text = f"Risk={risk_level.upper()}: {'; '.join(parts)}."
726
+ if confidence != "high":
727
+ text += f" (confidence={confidence}: IR may be incomplete)"
728
+ return text
729
+
730
+
683
731
  # ---------------------------------------------------------------------------
684
732
  # Security surface aggregation
685
733
  # ---------------------------------------------------------------------------
@@ -762,6 +810,7 @@ class ImpactOrchestrator:
762
810
  analysis_warnings=warnings or [f"Symbol '{symbol}' not found in CIR."],
763
811
  risk_level="unknown",
764
812
  confidence="low",
813
+ explanation=f"Symbol {symbol!r} not found in the IR.",
765
814
  metadata={"analysis_depth": depth},
766
815
  )
767
816
 
@@ -1041,7 +1090,16 @@ class ImpactOrchestrator:
1041
1090
  impact_findings=impact_findings,
1042
1091
  analysis_warnings=warnings,
1043
1092
  risk_level=risk_level,
1093
+ risk_score=risk_score,
1044
1094
  confidence=confidence,
1095
+ explanation=_build_chain_explanation(
1096
+ risk_level,
1097
+ len(direct_callers),
1098
+ len(indirect_callers),
1099
+ len(endpoints_affected),
1100
+ len(impact_findings),
1101
+ confidence,
1102
+ ),
1045
1103
  metadata={
1046
1104
  "analysis_depth": depth,
1047
1105
  "callers_total": len(direct_callers) + len(indirect_callers),
@@ -1132,4 +1190,5 @@ def run_impact_chain(
1132
1190
  analysis_warnings=[f"Internal error: {type(exc).__name__}: {exc}"],
1133
1191
  risk_level="unknown",
1134
1192
  confidence="low",
1193
+ explanation=f"Internal error during analysis: {type(exc).__name__}.",
1135
1194
  )
@@ -180,6 +180,226 @@ def discover_custom_validators(root: Path) -> "dict[str, CustomConstraint]":
180
180
  return catalog
181
181
 
182
182
 
183
+ # ---------------------------------------------------------------------------
184
+ # Source-derived constraints (no OpenAPI spec)
185
+ #
186
+ # When a repo ships no OpenAPI spec, declarative DTO constraints still live in
187
+ # the Java source as bean-validation annotations. We recover them directly:
188
+ # locate the handler's validated body parameter (@Valid/@Validated), resolve
189
+ # that DTO class in-repo, and read its fields' constraint annotations. This is
190
+ # pure extraction — it never fabricates constraints, and it is reported with
191
+ # source="source-derived" + a lower confidence than spec-carried constraints.
192
+ # ---------------------------------------------------------------------------
193
+
194
+ # jakarta/javax bean-validation built-in constraints. @Valid marks nested
195
+ # validation, which still means "this field is validated".
196
+ _BEAN_CONSTRAINTS = frozenset({
197
+ "NotNull", "NotEmpty", "NotBlank", "Null", "AssertTrue", "AssertFalse",
198
+ "Min", "Max", "DecimalMin", "DecimalMax", "Digits", "Positive",
199
+ "PositiveOrZero", "Negative", "NegativeOrZero", "Size", "Pattern", "Email",
200
+ "Past", "PastOrPresent", "Future", "FutureOrPresent", "Valid",
201
+ })
202
+ _VALIDATE_MARKERS = frozenset({"Valid", "Validated"})
203
+ # A class-typed identifier (starts uppercase) — heuristic for "a DTO type".
204
+ _CLASS_TYPE_RE = re.compile(r"^[A-Z][\w]*$")
205
+ _ANN_TOKEN_RE = re.compile(r"@(\w+)\s*(?:\(([^)]*)\))?")
206
+ _FIELD_DECL_RE = re.compile(
207
+ r"^\s*(?:private|protected|public)\s+"
208
+ r"(?:final\s+|static\s+|transient\s+|volatile\s+)*"
209
+ r"[\w.$<>\[\], ]+?\s+(\w+)\s*[;=]"
210
+ )
211
+ _CLASS_EXTENDS_RE = re.compile(r"\bclass\s+\w+\s+extends\s+(\w+)")
212
+
213
+
214
+ def _index_repo_classes(root: Path) -> "dict[str, Path]":
215
+ """Map a class's simple name → its source file (first non-test match)."""
216
+ index: "dict[str, Path]" = {}
217
+ count = 0
218
+ for jf in root.rglob("*.java"):
219
+ rel = str(jf).replace("\\", "/")
220
+ if is_test_path(rel) or "/target/" in rel:
221
+ continue
222
+ count += 1
223
+ if count > _SCAN_CAP:
224
+ break
225
+ index.setdefault(jf.stem, jf)
226
+ return index
227
+
228
+
229
+ def _balanced_parens(src: str, open_idx: int) -> "Optional[str]":
230
+ """Given the index of a '(', return the inner text up to its matching ')'."""
231
+ depth = 0
232
+ for i in range(open_idx, len(src)):
233
+ c = src[i]
234
+ if c == "(":
235
+ depth += 1
236
+ elif c == ")":
237
+ depth -= 1
238
+ if depth == 0:
239
+ return src[open_idx + 1:i]
240
+ return None
241
+
242
+
243
+ def _split_top_level(params: str) -> "list[str]":
244
+ """Split a parameter list on top-level commas (ignoring generics/parens)."""
245
+ out: "list[str]" = []
246
+ depth = 0
247
+ buf: "list[str]" = []
248
+ for c in params:
249
+ if c in "<(":
250
+ depth += 1
251
+ elif c in ">)":
252
+ depth -= 1
253
+ if c == "," and depth == 0:
254
+ out.append("".join(buf))
255
+ buf = []
256
+ else:
257
+ buf.append(c)
258
+ if buf:
259
+ out.append("".join(buf))
260
+ return out
261
+
262
+
263
+ def _handler_body_dto(controller_src: str, handler: str) -> "Optional[tuple[str, str]]":
264
+ """Find ``handler``'s validated body parameter. Returns (dto_simple, binding)
265
+ where binding is 'body' (@RequestBody), 'form' (@ModelAttribute / implicit),
266
+ or None when the handler has no @Valid/@Validated DTO parameter."""
267
+ for m in re.finditer(r"\b" + re.escape(handler) + r"\s*\(", controller_src):
268
+ params = _balanced_parens(controller_src, m.end() - 1)
269
+ if params is None:
270
+ continue
271
+ for raw in _split_top_level(params):
272
+ raw = raw.strip()
273
+ if not raw:
274
+ continue
275
+ anns = {a.group(1) for a in _ANN_TOKEN_RE.finditer(raw)}
276
+ if not (anns & _VALIDATE_MARKERS):
277
+ continue
278
+ # Strip annotations, then read the parameter's declared type.
279
+ without_ann = _ANN_TOKEN_RE.sub("", raw).strip()
280
+ without_ann = re.sub(r"^final\s+", "", without_ann)
281
+ parts = without_ann.split()
282
+ if not parts:
283
+ continue
284
+ dto = re.sub(r"<.*", "", parts[0]).strip()
285
+ if not _CLASS_TYPE_RE.match(dto):
286
+ continue
287
+ binding = "body" if "RequestBody" in anns else "form"
288
+ return dto, binding
289
+ return None
290
+
291
+
292
+ def _dto_field_constraints(
293
+ dto: str,
294
+ class_index: "dict[str, Path]",
295
+ catalog: "dict[str, CustomConstraint]",
296
+ _seen: "Optional[set[str]]" = None,
297
+ ) -> "list[dict[str, Any]]":
298
+ """Read a DTO's validated fields (own file + in-repo supertypes, depth-guarded)."""
299
+ if _seen is None:
300
+ _seen = set()
301
+ if dto in _seen or dto not in class_index:
302
+ return []
303
+ _seen.add(dto)
304
+ try:
305
+ src = class_index[dto].read_text(encoding="utf-8", errors="replace")
306
+ except OSError:
307
+ return []
308
+
309
+ fields: "list[dict[str, Any]]" = []
310
+ pending: "list[tuple[str, str]]" = [] # (annotation, args)
311
+ for line in src.splitlines():
312
+ stripped = line.strip()
313
+ if stripped.startswith("@"):
314
+ mt = _ANN_TOKEN_RE.match(stripped)
315
+ if mt:
316
+ pending.append((mt.group(1), (mt.group(2) or "").strip()))
317
+ continue
318
+ fm = _FIELD_DECL_RE.match(line)
319
+ if fm:
320
+ rules: "list[dict[str, Any]]" = []
321
+ customs: "list[dict[str, Any]]" = []
322
+ for ann, args in pending:
323
+ if ann in _BEAN_CONSTRAINTS:
324
+ rule: "dict[str, Any]" = {"kind": ann}
325
+ if args:
326
+ rule["value"] = args
327
+ rules.append(rule)
328
+ elif ann in catalog:
329
+ customs.append({"annotation": ann, "resolved": True})
330
+ if rules or customs:
331
+ entry: "dict[str, Any]" = {"name": fm.group(1)}
332
+ if rules:
333
+ entry["rules"] = rules
334
+ if customs:
335
+ entry["customValidators"] = customs
336
+ fields.append(entry)
337
+ pending = []
338
+ elif stripped and not stripped.startswith("//") and not stripped.startswith("*"):
339
+ # Any other meaningful line breaks the annotation→field adjacency.
340
+ pending = []
341
+
342
+ # Follow a single in-repo supertype so inherited constraints are not lost.
343
+ ext = _CLASS_EXTENDS_RE.search(src)
344
+ if ext:
345
+ seen_names = {f["name"] for f in fields}
346
+ for inherited in _dto_field_constraints(ext.group(1), class_index, catalog, _seen):
347
+ if inherited["name"] not in seen_names:
348
+ fields.append(inherited)
349
+ return fields
350
+
351
+
352
+ def _recover_source_endpoints(
353
+ root: Path,
354
+ endpoints: "list[dict[str, Any]]",
355
+ catalog: "dict[str, CustomConstraint]",
356
+ ) -> "tuple[list[dict[str, Any]], int]":
357
+ """Build validation routes for source endpoints whose handler validates a
358
+ DTO. Returns (routes, validated_field_count). Only body-shaped verbs are
359
+ considered, matching the OpenAPI path's scope."""
360
+ class_index = _index_repo_classes(root)
361
+ controller_cache: "dict[str, Optional[str]]" = {}
362
+ routes: "list[dict[str, Any]]" = []
363
+ total = 0
364
+ for ep in endpoints:
365
+ if not _is_body_endpoint(ep):
366
+ continue
367
+ controller = ep.get("controller")
368
+ handler = ep.get("handler")
369
+ if not controller or not handler or controller not in class_index:
370
+ continue
371
+ if controller not in controller_cache:
372
+ try:
373
+ controller_cache[controller] = class_index[controller].read_text(
374
+ encoding="utf-8", errors="replace"
375
+ )
376
+ except OSError:
377
+ controller_cache[controller] = None
378
+ csrc = controller_cache[controller]
379
+ if csrc is None:
380
+ continue
381
+ dto_binding = _handler_body_dto(csrc, str(handler))
382
+ if dto_binding is None:
383
+ continue
384
+ dto, binding = dto_binding
385
+ validated = _dto_field_constraints(dto, class_index, catalog)
386
+ if not validated:
387
+ continue
388
+ total += len(validated)
389
+ routes.append({
390
+ "method": ep.get("method"),
391
+ "path": ep.get("path"),
392
+ "controller": controller,
393
+ "handler": handler,
394
+ "schema": dto,
395
+ "binding": binding,
396
+ "source": "source-derived",
397
+ "confidence": "medium",
398
+ "validatedFields": validated,
399
+ })
400
+ return routes, total
401
+
402
+
183
403
  def _field_rules(fieldc: "dict[str, Any]") -> "list[dict[str, Any]]":
184
404
  """Render a constraint dict's built-in rules as a list of {kind, value}."""
185
405
  rules: "list[dict[str, Any]]" = []
@@ -303,18 +523,44 @@ def build_validation_surface(
303
523
  if spec_path:
304
524
  result["openapi_spec"] = spec_path
305
525
  else:
306
- # No OpenAPI spec on disk / under target/generated-sources. Declarative
307
- # DTO constraints cannot be recovered, so a sea of zeros here is expected
308
- # and NOT a sign the repo lacks validation it just isn't OpenAPI-driven.
309
- # Surface this explicitly so the result is not silently misread as
310
- # "no validation anywhere".
526
+ # No OpenAPI spec on disk / under target/generated-sources. Recover
527
+ # declarative constraints directly from the Java DTOs that handlers
528
+ # validate (@Valid/@Validated body params), so a repo without a spec is
529
+ # no longer reported as a sea of zeros.
311
530
  result["openapi_spec"] = None
312
- result["note"] = (
313
- "No OpenAPI spec found (no spec on disk or under "
314
- "target/generated-sources). Declarative DTO constraints cannot be "
315
- "recovered; only source-declared custom validators are reported. "
316
- "Body-endpoint and validated-field counts will read zero unless an "
317
- "OpenAPI spec is present — this is expected, not a missing-validation "
318
- "finding."
531
+ source_routes, source_fields = _recover_source_endpoints(
532
+ root, endpoints_data.get("endpoints", []), catalog
319
533
  )
534
+ if source_routes:
535
+ existing = {(r.get("method"), r.get("path")) for r in out_endpoints}
536
+ for r in source_routes:
537
+ if (r.get("method"), r.get("path")) not in existing:
538
+ out_endpoints.append(r)
539
+ total_validated_fields += source_fields
540
+ # Recompute the gaps that depended on the now-recovered routes.
541
+ recovered = {(r.get("method"), r.get("path")) for r in source_routes}
542
+ gaps = [
543
+ g for g in gaps
544
+ if (g.get("method"), g.get("path")) not in recovered
545
+ ]
546
+ result["endpoints"] = out_endpoints
547
+ result["gaps"] = gaps
548
+ result["summary"]["endpoints_with_body"] = len(out_endpoints)
549
+ result["summary"]["validated_fields"] = total_validated_fields
550
+ result["summary"]["gaps"] = len(gaps)
551
+ result["summary"]["source_derived_routes"] = len(source_routes)
552
+ result["note"] = (
553
+ "No OpenAPI spec found; constraints were recovered from Java DTO "
554
+ "source (bean-validation annotations on @Valid/@Validated handler "
555
+ "bodies). Routes carry source=\"source-derived\" at medium "
556
+ "confidence. Custom-validator linkage and nested generics may be "
557
+ "partial; OpenAPI-carried constraints would be more complete."
558
+ )
559
+ else:
560
+ result["note"] = (
561
+ "No OpenAPI spec found and no source DTO constraints recovered "
562
+ "(no handler validates an in-repo DTO via @Valid/@Validated, or "
563
+ "the DTOs declare no bean-validation annotations). This is "
564
+ "expected for such repos, not a missing-validation finding."
565
+ )
320
566
  return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.57.0
3
+ Version: 1.58.0
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  License-File: LICENSE
6
6
  Keywords: agents,ai,codebase,context,developer-tools,llm
@@ -40,7 +40,7 @@ Description-Content-Type: text/markdown
40
40
 
41
41
  **Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
42
42
 
43
- ![Version](https://img.shields.io/badge/version-1.57.0-blue)
43
+ ![Version](https://img.shields.io/badge/version-1.58.0-blue)
44
44
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
45
45
 
46
46
  ---
@@ -114,7 +114,7 @@ pipx install sourcecode
114
114
 
115
115
  ```bash
116
116
  sourcecode version
117
- # sourcecode 1.53.0
117
+ # sourcecode 1.58.0
118
118
  ```
119
119
 
120
120
  ---
@@ -150,6 +150,8 @@ sourcecode impact-chain OrderPlacedEvent /path/to/repo --type events
150
150
  sourcecode endpoints /path/to/repo
151
151
 
152
152
  # Request-body validation per endpoint: constraints + custom validators (free)
153
+ # Recovers constraints from the OpenAPI spec, or directly from Java DTO
154
+ # bean-validation annotations when no spec is present.
153
155
  sourcecode validation /path/to/repo
154
156
 
155
157
  # Onboard to an unfamiliar codebase
@@ -1,4 +1,4 @@
1
- sourcecode/__init__.py,sha256=TrDqUl3QPap22po5ZZVSMV_lWRZibeQ0Vv3MgrCN2Wk,103
1
+ sourcecode/__init__.py,sha256=zPgb29z23K85U3nCKBwXfaqA7j0bV7r7tMzxrVDP-9w,103
2
2
  sourcecode/adaptive_scanner.py,sha256=XffluXKzJUXrMtjEiAOnSNPZnztdIcts17T9ouHeID0,10521
3
3
  sourcecode/architecture_analyzer.py,sha256=liCwQmLgb5vplohy8arjYxs_HOIv5C9MjLh_gY6bc5Q,44115
4
4
  sourcecode/architecture_summary.py,sha256=z34_6v7cSwy98cof2UVciGho7SCrZ93tiqMmq5WNzRQ,20405
@@ -55,14 +55,14 @@ sourcecode/semantic_analyzer.py,sha256=4OdG6tTSnTvq3_dSWMbQu8Ad1ndSCKeG-b9qM4hIx
55
55
  sourcecode/serializer.py,sha256=TGzftrSKitZrtl6Hh-R05s4KdTOxwTmph_lGDbo2Wzg,125015
56
56
  sourcecode/spring_event_topology.py,sha256=5_ON_21Le5zbG-1GRc5GLIi5HJfy_QjcXLVPC5WeUGQ,18055
57
57
  sourcecode/spring_findings.py,sha256=G7Or2lKBUQbcTDqudLvSs9XvNg_YoAa-_lBOG_ULs8E,5457
58
- sourcecode/spring_impact.py,sha256=f8XJtOG41f7EHQCs64BBZ0mdMTwU40DRcMoQ59SVprg,53296
58
+ sourcecode/spring_impact.py,sha256=qLwLfItX_o9LU-k_qjhD2hFpTX3PpEQ85TsYTAArzvg,56016
59
59
  sourcecode/spring_model.py,sha256=zOAgFmrRbG4a6KLm1TJl55aWMyPNsz3OS3FSczqPG6A,16594
60
60
  sourcecode/spring_security_audit.py,sha256=XtPJ1SXlZJ8k6VYmaWuAp7Bbir4UmreAL7doIGQ5I7o,20595
61
61
  sourcecode/spring_semantic.py,sha256=O1nKSGVzlukuxLHQVuCPxc-XrcrMFxwlHA20_dmEGgM,13307
62
62
  sourcecode/spring_tx_analyzer.py,sha256=FdFcyqPp3aT9oJ-PKrnXcTA6s69wdvzG-NBm0GMGPTU,30717
63
63
  sourcecode/summarizer.py,sha256=zgdps7yS2IktAbWe7IWz0oUcr3QIuNPRGrsScbZ4R1g,21797
64
64
  sourcecode/tree_utils.py,sha256=8GAkIfQAsvtEudIeW1l4ooH_oRtrWR8cpJQJsEa_Pfw,2093
65
- sourcecode/validation_surface.py,sha256=_HiKeUuN8wk8V2pWp1TRcwB_BwxsxyFWTqzCKGx1B8M,12747
65
+ sourcecode/validation_surface.py,sha256=2Ojfzhw9R4XpemAFqb9RXf4FKyI3DYjGo4Dp0AHZMQo,22600
66
66
  sourcecode/version_check.py,sha256=CHp6ZxTIfo8kyHPCBgJA1uFC0xQCoXMuuOfrW8QTL8o,4942
67
67
  sourcecode/workspace.py,sha256=X_6NmNnitvT3_38V-JDChydo_sR68s249hLFlrQskU0,8271
68
68
  sourcecode/detectors/__init__.py,sha256=A0AACJFF6HWf_RgatNtWu3PUzstcKtIGM9f1PoFcJug,1987
@@ -102,8 +102,8 @@ sourcecode/telemetry/consent.py,sha256=wLMvGNJeSSyZoNkQXpoUioY6mMv4Qdvuw7S9jAEWn
102
102
  sourcecode/telemetry/events.py,sha256=LtzYfaX9Ilckj5PTvAcTpDa9mLqDsYPDUiDkRa58piY,2580
103
103
  sourcecode/telemetry/filters.py,sha256=NHa5T-6DaZduQPFuC34jOqHWQgSizM-Ygq8aZ4j19ng,5834
104
104
  sourcecode/telemetry/transport.py,sha256=4gGHsq0WeY9VywEZXA3vUxykfiYnw9uuqfjAAec7F8o,1681
105
- sourcecode-1.57.0.dist-info/METADATA,sha256=MllfgzFIxub5-5P1bTKKkF0ifSPQVoCD3XNMqS5V4-U,38704
106
- sourcecode-1.57.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
107
- sourcecode-1.57.0.dist-info/entry_points.txt,sha256=ex3F9rmbXeyDIoFQHtkEqTsKSaJow8F0LrVu8XfIktQ,57
108
- sourcecode-1.57.0.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
109
- sourcecode-1.57.0.dist-info/RECORD,,
105
+ sourcecode-1.58.0.dist-info/METADATA,sha256=hmIYx5s3UECwA6NNlKD6HEetY1pl-6t76_KF0YKZysA,38831
106
+ sourcecode-1.58.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
107
+ sourcecode-1.58.0.dist-info/entry_points.txt,sha256=ex3F9rmbXeyDIoFQHtkEqTsKSaJow8F0LrVu8XfIktQ,57
108
+ sourcecode-1.58.0.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
109
+ sourcecode-1.58.0.dist-info/RECORD,,