sourcecode 2.7.0__py3-none-any.whl → 3.0.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
@@ -4,4 +4,4 @@ ASK Engine is the product. ``ask`` is the canonical CLI command; ``sourcecode``
4
4
  the legacy compatibility alias and the Python/PyPI package name. See
5
5
  docs/PRODUCT_IDENTITY.md (normative)."""
6
6
 
7
- __version__ = "2.7.0"
7
+ __version__ = "3.0.0"
sourcecode/cache.py CHANGED
@@ -75,11 +75,52 @@ SCHEMA_VERSION: str = "2"
75
75
  #: Bump to invalidate all L1 core caches (independent of snapshot version).
76
76
  CORE_SCHEMA_VERSION: str = "1"
77
77
 
78
- #: Bump when analysis logic or output schema changes NOT on every package release.
79
- #: This is the stable part of the L1 core cache key. Package version bumps (patch,
80
- #: minor) must NOT bump this value unless the cached data format actually changed.
78
+ #: Manual override for invalidating all L1 core caches. Rarely needed now that the
79
+ #: key carries :func:`analyzer_fingerprint`; kept as an escape hatch for cases the
80
+ #: fingerprint cannot see (a changed dependency, a corrected cache format).
81
+ #: Package version bumps must NOT bump this value.
81
82
  ANALYZER_CACHE_VERSION: str = "1"
82
83
 
84
+
85
+ def analyzer_fingerprint() -> str:
86
+ """Content hash of the analysis code, memoised for the process.
87
+
88
+ A cache key built only from the repository state and a hand-maintained version
89
+ constant cannot notice that the analyzer itself changed. That discipline failed
90
+ exactly as designed-by-humans disciplines do: five consecutive fixes to analysis
91
+ logic shipped without anyone bumping ``ANALYZER_CACHE_VERSION``, so an upgraded
92
+ install kept serving pre-fix results from cache on an unchanged commit — the
93
+ fixes looked inert until the user cleared the cache by hand.
94
+
95
+ Hashing file *content* (not mtime) keeps the key stable across reinstalls and
96
+ identical checkouts on different machines, so caches stay shareable. Any edit to
97
+ any module invalidates every entry: over-invalidation costs a re-analysis,
98
+ under-invalidation reports facts the current code would not produce.
99
+
100
+ Falls back to the package version when the source is unreadable (zipimport,
101
+ frozen builds) — degraded, never wrong-by-silence.
102
+ """
103
+ global _ANALYZER_FINGERPRINT
104
+ if _ANALYZER_FINGERPRINT is not None:
105
+ return _ANALYZER_FINGERPRINT
106
+ digest = hashlib.sha256()
107
+ try:
108
+ pkg_root = Path(__file__).resolve().parent
109
+ sources = sorted(pkg_root.rglob("*.py"))
110
+ if not sources:
111
+ raise OSError("no analyzer sources found")
112
+ for src in sources:
113
+ digest.update(src.relative_to(pkg_root).as_posix().encode("utf-8"))
114
+ digest.update(src.read_bytes())
115
+ _ANALYZER_FINGERPRINT = digest.hexdigest()[:12]
116
+ except Exception:
117
+ from sourcecode import __version__ as _pkg_version
118
+ _ANALYZER_FINGERPRINT = f"pkg-{_pkg_version}"
119
+ return _ANALYZER_FINGERPRINT
120
+
121
+
122
+ _ANALYZER_FINGERPRINT: Optional[str] = None
123
+
83
124
  #: Fields eligible for CAS deduplication (applied to top-level JSON dict keys).
84
125
  _CAS_FIELDS: frozenset[str] = frozenset([
85
126
  "file_paths",