Skip to content

Source cache

cache

Persist AutoCorrect2 source fingerprints and extracted hotstrings.

The cache is an optimization only. SHA-256 of the exact source bytes is the authoritative content identity; filesystem size and modification time are stored as useful metadata but are never trusted as proof that a same-sized source is unchanged.

Cached hotstrings persist only source-derived state: canonical AHK trigger spelling and canonical option text. Semantic trigger text and the case-insensitive semantic comparison key are reconstructed by the domain model on every load so they always reflect the current trigger-normalization implementation.

LOGGER module-attribute

LOGGER: Final[Logger] = logging.getLogger(__name__)

Module logger used for cache diagnostics.

CACHE_SCHEMA_VERSION module-attribute

CACHE_SCHEMA_VERSION: Final[int] = 2

Persistent-cache compatibility version, including parser semantics.

DEFAULT_SOURCE_CACHE_PATH module-attribute

DEFAULT_SOURCE_CACHE_PATH: Final[Path] = (
    PROJECT_ROOT
    / ".cache"
    / "autocorrect2-source-cache.json"
)

Deterministic project-local path used for the persistent source cache.

CachedHotstring dataclass

Represent the minimal persisted form of one extracted hotstring.

Attributes:

Name Type Description
trigger str

Canonical AHK source-form trigger text.

options str

Canonical hotstring option declaration.

Source code in hotstring\autocorrect2\source_loading\cache.py
41
42
43
44
45
46
47
48
49
50
51
52
53
@dataclass(frozen=True, slots=True)
class CachedHotstring:
    """Represent the minimal persisted form of one extracted hotstring.

    Attributes:
        trigger:
            Canonical AHK source-form trigger text.
        options:
            Canonical hotstring option declaration.
    """

    trigger: str
    options: str

SourceCacheEntry dataclass

Represent cached state for one AutoCorrect2 source file.

Attributes:

Name Type Description
modification_time_ns int

Source modification time recorded when the entry was refreshed.

size int

Source size recorded when the entry was refreshed.

sha256 str

SHA-256 digest of the exact source bytes.

hotstrings tuple[CachedHotstring, ...]

Extracted hotstrings stored in declaration order.

Source code in hotstring\autocorrect2\source_loading\cache.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
@dataclass(frozen=True, slots=True)
class SourceCacheEntry:
    """Represent cached state for one AutoCorrect2 source file.

    Attributes:
        modification_time_ns:
            Source modification time recorded when the entry was refreshed.
        size:
            Source size recorded when the entry was refreshed.
        sha256:
            SHA-256 digest of the exact source bytes.
        hotstrings:
            Extracted hotstrings stored in declaration order.
    """

    modification_time_ns: int
    size: int
    sha256: str
    hotstrings: tuple[CachedHotstring, ...]

SourceCache dataclass

Represent the complete persistent AutoCorrect2 source cache.

Attributes:

Name Type Description
project_dir str

Canonical AutoCorrect2 project directory associated with the cache. This prevents accidental reuse for a different checkout at another path; machine identity is deliberately not part of cache validity.

files dict[str, SourceCacheEntry]

Cache entries keyed by source path relative to the AutoCorrect2 project root.

Source code in hotstring\autocorrect2\source_loading\cache.py
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
@dataclass(slots=True)
class SourceCache:
    """Represent the complete persistent AutoCorrect2 source cache.

    Attributes:
        project_dir:
            Canonical AutoCorrect2 project directory associated with the
            cache. This prevents accidental reuse for a different checkout at
            another path; machine identity is deliberately not part of cache
            validity.
        files:
            Cache entries keyed by source path relative to the AutoCorrect2
            project root.
    """

    project_dir: str
    files: dict[str, SourceCacheEntry] = field(default_factory=dict)

canonical_project_dir

canonical_project_dir(project_dir: Path) -> str

Return the canonical project-directory value stored in the cache.

Parameters:

Name Type Description Default
project_dir Path

AutoCorrect2 project directory.

required

Returns:

Type Description
str

Absolute normalized project-directory string.

Raises:

Type Description
TypeError

If the supplied project directory is not a path.

OSError

If path resolution fails.

Source code in hotstring\autocorrect2\source_loading\cache.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def canonical_project_dir(project_dir: Path) -> str:
    """Return the canonical project-directory value stored in the cache.

    Args:
        project_dir:
            AutoCorrect2 project directory.

    Returns:
        Absolute normalized project-directory string.

    Raises:
        TypeError:
            If the supplied project directory is not a path.
        OSError:
            If path resolution fails.
    """
    if not isinstance(project_dir, Path):
        raise TypeError(
            f"AutoCorrect2 project directory must be a Path, not {type(project_dir).__name__}"
        )
    return str(project_dir.resolve())

source_cache_key

source_cache_key(source: Path) -> str

Return the stable JSON key for a configured source path.

Parameters:

Name Type Description Default
source Path

Source path relative to the AutoCorrect2 project root.

required

Returns:

Type Description
str

POSIX-style relative path suitable for use as a JSON object key.

Raises:

Type Description
TypeError

If the supplied source is not a path.

Source code in hotstring\autocorrect2\source_loading\cache.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def source_cache_key(source: Path) -> str:
    """Return the stable JSON key for a configured source path.

    Args:
        source:
            Source path relative to the AutoCorrect2 project root.

    Returns:
        POSIX-style relative path suitable for use as a JSON object key.

    Raises:
        TypeError:
            If the supplied source is not a path.
    """
    if not isinstance(source, Path):
        raise TypeError(f"Source cache key must be a Path, not {type(source).__name__}")
    return source.as_posix()

compute_content_hash

compute_content_hash(content: bytes) -> str

Compute the SHA-256 digest used as authoritative content identity.

Parameters:

Name Type Description Default
content bytes

Exact source-file bytes.

required

Returns:

Type Description
str

Lowercase hexadecimal SHA-256 digest.

Raises:

Type Description
TypeError

If the supplied content is not bytes.

Source code in hotstring\autocorrect2\source_loading\cache.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def compute_content_hash(content: bytes) -> str:
    """Compute the SHA-256 digest used as authoritative content identity.

    Args:
        content:
            Exact source-file bytes.

    Returns:
        Lowercase hexadecimal SHA-256 digest.

    Raises:
        TypeError:
            If the supplied content is not bytes.
    """
    if not isinstance(content, bytes):
        raise TypeError(f"Source content for hashing must be bytes, not {type(content).__name__}")

    digest = hashlib.sha256(content).hexdigest()
    LOGGER.debug("Computed SHA-256 digest for %d source byte(s).", len(content))
    return digest

create_source_cache_entry

create_source_cache_entry(
    hotstrings: Sequence[ExistingHotstring],
    *,
    modification_time_ns: int,
    size: int,
    sha256: str,
) -> SourceCacheEntry

Create a cache entry from parsed hotstrings and source state.

Cached triggers use each model's canonical ahk_trigger field, not its semantic trigger. Restoring the entry therefore feeds exactly the input representation expected by ExistingHotstring.

Parameters:

Name Type Description Default
hotstrings Sequence[ExistingHotstring]

Parsed hotstrings in declaration order.

required
modification_time_ns int

Current source modification time.

required
size int

Current source size.

required
sha256 str

SHA-256 digest of the exact source bytes.

required

Returns:

Type Description
SourceCacheEntry

Cache entry ready for persistence.

Raises:

Type Description
TypeError

If source metadata or a hotstring has an invalid type.

ValueError

If source metadata or the digest is invalid.

Source code in hotstring\autocorrect2\source_loading\cache.py
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
def create_source_cache_entry(
    hotstrings: Sequence[ExistingHotstring],
    *,
    modification_time_ns: int,
    size: int,
    sha256: str,
) -> SourceCacheEntry:
    """Create a cache entry from parsed hotstrings and source state.

    Cached triggers use each model's canonical `ahk_trigger` field, not its
    semantic trigger. Restoring the entry therefore feeds exactly the input
    representation expected by `ExistingHotstring`.

    Args:
        hotstrings:
            Parsed hotstrings in declaration order.
        modification_time_ns:
            Current source modification time.
        size:
            Current source size.
        sha256:
            SHA-256 digest of the exact source bytes.

    Returns:
        Cache entry ready for persistence.

    Raises:
        TypeError:
            If source metadata or a hotstring has an invalid type.
        ValueError:
            If source metadata or the digest is invalid.
    """
    _validate_metadata(modification_time_ns, size, sha256)

    cached_hotstrings: list[CachedHotstring] = []
    for hotstring in hotstrings:
        if not isinstance(hotstring, ExistingHotstring):
            raise TypeError(
                "Cached hotstrings must contain ExistingHotstring instances, "
                f"not {type(hotstring).__name__}"
            )

        cached_hotstrings.append(
            CachedHotstring(
                trigger=hotstring.ahk_trigger,
                options=hotstring.options.declaration(),
            )
        )

    return SourceCacheEntry(
        modification_time_ns=modification_time_ns,
        size=size,
        sha256=sha256,
        hotstrings=tuple(cached_hotstrings),
    )

restore_hotstrings

restore_hotstrings(
    entry: SourceCacheEntry, *, source: Path
) -> list[ExistingHotstring]

Reconstruct domain hotstrings from one persisted cache entry.

The cached trigger is intentionally fed back to ExistingHotstring as AHK source-form constructor input. Its semantic trigger, canonical source representation, parsed options, and case-insensitive semantic key are therefore rebuilt using the current code.

Parameters:

Name Type Description Default
entry SourceCacheEntry

Cached source entry to reconstruct.

required
source Path

Source identifier assigned to each reconstructed hotstring.

required

Returns:

Type Description
list[ExistingHotstring]

Existing hotstrings in their cached declaration order.

Raises:

Type Description
TypeError

If the cache entry or source identifier has an invalid type.

ValueError

If cached hotstring data is invalid under the current model.

Source code in hotstring\autocorrect2\source_loading\cache.py
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
def restore_hotstrings(
    entry: SourceCacheEntry,
    *,
    source: Path,
) -> list[ExistingHotstring]:
    """Reconstruct domain hotstrings from one persisted cache entry.

    The cached trigger is intentionally fed back to `ExistingHotstring` as
    AHK source-form constructor input. Its semantic trigger, canonical source
    representation, parsed options, and case-insensitive semantic key are therefore
    rebuilt using the current code.

    Args:
        entry:
            Cached source entry to reconstruct.
        source:
            Source identifier assigned to each reconstructed hotstring.

    Returns:
        Existing hotstrings in their cached declaration order.

    Raises:
        TypeError:
            If the cache entry or source identifier has an invalid type.
        ValueError:
            If cached hotstring data is invalid under the current model.
    """
    if not isinstance(entry, SourceCacheEntry):
        raise TypeError(f"Source cache entry must be SourceCacheEntry, not {type(entry).__name__}")
    if not isinstance(source, Path):
        raise TypeError(f"Hotstring source identifier must be a Path, not {type(source).__name__}")

    hotstrings = [
        ExistingHotstring(
            trigger=hotstring.trigger,
            options_input=hotstring.options,
            source=source,
        )
        for hotstring in entry.hotstrings
    ]

    LOGGER.debug(
        "Reconstructed %d hotstring(s) from cached source %s.",
        len(hotstrings),
        source,
    )
    return hotstrings

load_source_cache

load_source_cache(
    cache_path: Path, *, project_dir: Path
) -> SourceCache

Load the persistent source cache or return an empty compatible cache.

Missing, unreadable, malformed, incompatible, or project-mismatched cache files are treated as disposable optimization state. In those cases an empty cache associated with the requested AutoCorrect2 project is returned.

Parameters:

Name Type Description Default
cache_path Path

JSON cache file to load.

required
project_dir Path

AutoCorrect2 project directory expected by the caller.

required

Returns:

Type Description
SourceCache

Loaded compatible cache, or a new empty cache when persisted state

SourceCache

cannot be reused.

Raises:

Type Description
TypeError

If a path argument has an invalid type.

OSError

If canonicalizing the project directory fails.

Source code in hotstring\autocorrect2\source_loading\cache.py
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
def load_source_cache(cache_path: Path, *, project_dir: Path) -> SourceCache:
    """Load the persistent source cache or return an empty compatible cache.

    Missing, unreadable, malformed, incompatible, or project-mismatched cache
    files are treated as disposable optimization state. In those cases an
    empty cache associated with the requested AutoCorrect2 project is returned.

    Args:
        cache_path:
            JSON cache file to load.
        project_dir:
            AutoCorrect2 project directory expected by the caller.

    Returns:
        Loaded compatible cache, or a new empty cache when persisted state
        cannot be reused.

    Raises:
        TypeError:
            If a path argument has an invalid type.
        OSError:
            If canonicalizing the project directory fails.
    """
    if not isinstance(cache_path, Path):
        raise TypeError(f"Cache path must be a Path, not {type(cache_path).__name__}")

    expected_project_dir = canonical_project_dir(project_dir)

    try:
        raw_data: object = json.loads(cache_path.read_text(encoding="utf-8"))
    except FileNotFoundError:
        LOGGER.debug("Source cache does not exist at %s; starting empty.", cache_path)
        return SourceCache(project_dir=expected_project_dir)
    except (OSError, UnicodeError, json.JSONDecodeError):
        LOGGER.debug(
            "Source cache at %s could not be loaded; starting empty.",
            cache_path,
            exc_info=True,
        )
        return SourceCache(project_dir=expected_project_dir)

    if not isinstance(raw_data, dict):
        LOGGER.debug("Source cache at %s is not a JSON object; starting empty.", cache_path)
        return SourceCache(project_dir=expected_project_dir)

    data = cast(dict[str, object], raw_data)
    if data.get("schema_version") != CACHE_SCHEMA_VERSION:
        LOGGER.debug(
            "Source cache schema at %s is incompatible; expected %d and found %r.",
            cache_path,
            CACHE_SCHEMA_VERSION,
            data.get("schema_version"),
        )
        return SourceCache(project_dir=expected_project_dir)

    cached_project_dir = data.get("project_dir")
    if cached_project_dir != expected_project_dir:
        LOGGER.debug(
            "Source cache project mismatch at %s; cached=%r current=%r. Starting empty.",
            cache_path,
            cached_project_dir,
            expected_project_dir,
        )
        return SourceCache(project_dir=expected_project_dir)

    raw_files = data.get("files")
    if not isinstance(raw_files, dict):
        LOGGER.debug("Source cache files section at %s is invalid; starting empty.", cache_path)
        return SourceCache(project_dir=expected_project_dir)

    files: dict[str, SourceCacheEntry] = {}
    for source_key, raw_entry in raw_files.items():
        if not isinstance(source_key, str):
            LOGGER.debug("Ignoring source-cache entry with a non-string key: %r.", source_key)
            continue

        entry = _parse_source_cache_entry(raw_entry)
        if entry is None:
            LOGGER.debug("Ignoring malformed source-cache entry for %s.", source_key)
            continue
        files[source_key] = entry

    LOGGER.debug(
        "Loaded %d source-cache %s from %s.",
        len(files),
        "entry" if len(files) == 1 else "entries",
        cache_path,
    )
    return SourceCache(project_dir=expected_project_dir, files=files)

save_source_cache

save_source_cache(
    cache: SourceCache, cache_path: Path
) -> None

Persist the source cache atomically as UTF-8 JSON.

Each cached hotstring contains exactly trigger and options. The trigger value is the canonical AHK source representation. Source paths are stored once as keys in the surrounding files object.

Parameters:

Name Type Description Default
cache SourceCache

Source cache to persist.

required
cache_path Path

Destination JSON file.

required

Raises:

Type Description
TypeError

If an argument has an invalid type.

OSError

If the cache directory or cache file cannot be written or replaced.

Source code in hotstring\autocorrect2\source_loading\cache.py
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
def save_source_cache(cache: SourceCache, cache_path: Path) -> None:
    """Persist the source cache atomically as UTF-8 JSON.

    Each cached hotstring contains exactly `trigger` and `options`. The trigger
    value is the canonical AHK source representation. Source paths are stored
    once as keys in the surrounding `files` object.

    Args:
        cache:
            Source cache to persist.
        cache_path:
            Destination JSON file.

    Raises:
        TypeError:
            If an argument has an invalid type.
        OSError:
            If the cache directory or cache file cannot be written or replaced.
    """
    if not isinstance(cache, SourceCache):
        raise TypeError(f"Cache must be SourceCache, not {type(cache).__name__}")
    if not isinstance(cache_path, Path):
        raise TypeError(f"Cache path must be a Path, not {type(cache_path).__name__}")

    cache_path.parent.mkdir(parents=True, exist_ok=True)
    payload = (
        json.dumps(
            _serialize_source_cache(cache),
            ensure_ascii=False,
            indent=2,
        )
        + "\n"
    )

    temporary_path: Path | None = None
    try:
        with tempfile.NamedTemporaryFile(
            mode="w",
            encoding="utf-8",
            newline="\n",
            prefix=f".{cache_path.name}.",
            suffix=".tmp",
            dir=cache_path.parent,
            delete=False,
        ) as temporary_file:
            temporary_file.write(payload)
            temporary_path = Path(temporary_file.name)

        os.replace(temporary_path, cache_path)
    except Exception:
        if temporary_path is not None:
            temporary_path.unlink(missing_ok=True)
        raise

    LOGGER.debug(
        "Persisted %d source-cache entr%s to %s.",
        len(cache.files),
        "y" if len(cache.files) == 1 else "ies",
        cache_path,
    )

_parse_source_cache_entry

_parse_source_cache_entry(
    raw_entry: object,
) -> SourceCacheEntry | None

Parse one untrusted JSON cache entry.

Parameters:

Name Type Description Default
raw_entry object

Decoded JSON value representing a source entry.

required

Returns:

Type Description
SourceCacheEntry | None

Validated cache entry, or None when the value is malformed.

Source code in hotstring\autocorrect2\source_loading\cache.py
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
def _parse_source_cache_entry(raw_entry: object) -> SourceCacheEntry | None:
    """Parse one untrusted JSON cache entry.

    Args:
        raw_entry:
            Decoded JSON value representing a source entry.

    Returns:
        Validated cache entry, or `None` when the value is malformed.
    """
    if not isinstance(raw_entry, dict):
        return None

    entry_data = cast(dict[str, object], raw_entry)
    modification_time_ns = entry_data.get("mtime_ns")
    size = entry_data.get("size")
    sha256 = entry_data.get("sha256")
    raw_hotstrings = entry_data.get("hotstrings")

    if not _metadata_is_valid(modification_time_ns, size, sha256):
        return None
    if not isinstance(raw_hotstrings, list):
        return None

    hotstrings: list[CachedHotstring] = []
    for raw_hotstring in raw_hotstrings:
        cached_hotstring = _parse_cached_hotstring(raw_hotstring)
        if cached_hotstring is None:
            return None
        hotstrings.append(cached_hotstring)

    return SourceCacheEntry(
        modification_time_ns=cast(int, modification_time_ns),
        size=cast(int, size),
        sha256=cast(str, sha256),
        hotstrings=tuple(hotstrings),
    )

_parse_cached_hotstring

_parse_cached_hotstring(
    raw_hotstring: object,
) -> CachedHotstring | None

Parse one minimal hotstring record from decoded JSON.

Parameters:

Name Type Description Default
raw_hotstring object

Decoded JSON value representing one cached hotstring.

required

Returns:

Type Description
CachedHotstring | None

Parsed cached hotstring, or None when malformed.

Source code in hotstring\autocorrect2\source_loading\cache.py
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
def _parse_cached_hotstring(raw_hotstring: object) -> CachedHotstring | None:
    """Parse one minimal hotstring record from decoded JSON.

    Args:
        raw_hotstring:
            Decoded JSON value representing one cached hotstring.

    Returns:
        Parsed cached hotstring, or `None` when malformed.
    """
    if not isinstance(raw_hotstring, dict):
        return None

    hotstring_data = cast(dict[str, object], raw_hotstring)
    if set(hotstring_data) != {"trigger", "options"}:
        return None

    trigger = hotstring_data.get("trigger")
    options = hotstring_data.get("options")
    if not isinstance(trigger, str) or not isinstance(options, str):
        return None

    return CachedHotstring(trigger=trigger, options=options)

_serialize_source_cache

_serialize_source_cache(
    cache: SourceCache,
) -> dict[str, object]

Convert the in-memory source cache to JSON-compatible values.

Parameters:

Name Type Description Default
cache SourceCache

Source cache to serialize.

required

Returns:

Type Description
dict[str, object]

JSON-compatible cache document.

Source code in hotstring\autocorrect2\source_loading\cache.py
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
def _serialize_source_cache(cache: SourceCache) -> dict[str, object]:
    """Convert the in-memory source cache to JSON-compatible values.

    Args:
        cache:
            Source cache to serialize.

    Returns:
        JSON-compatible cache document.
    """
    files: dict[str, object] = {}
    for source_key, entry in sorted(cache.files.items()):
        files[source_key] = {
            "mtime_ns": entry.modification_time_ns,
            "size": entry.size,
            "sha256": entry.sha256,
            "hotstrings": [
                {
                    "trigger": hotstring.trigger,
                    "options": hotstring.options,
                }
                for hotstring in entry.hotstrings
            ],
        }

    return {
        "schema_version": CACHE_SCHEMA_VERSION,
        "project_dir": cache.project_dir,
        "files": files,
    }

_validate_metadata

_validate_metadata(
    modification_time_ns: int, size: int, sha256: str
) -> None

Validate metadata used to construct a source-cache entry.

Parameters:

Name Type Description Default
modification_time_ns int

Source modification time.

required
size int

Source size.

required
sha256 str

Source SHA-256 digest.

required

Raises:

Type Description
TypeError

If a metadata value has an invalid type.

ValueError

If a metadata value is outside its valid domain.

Source code in hotstring\autocorrect2\source_loading\cache.py
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
def _validate_metadata(modification_time_ns: int, size: int, sha256: str) -> None:
    """Validate metadata used to construct a source-cache entry.

    Args:
        modification_time_ns:
            Source modification time.
        size:
            Source size.
        sha256:
            Source SHA-256 digest.

    Raises:
        TypeError:
            If a metadata value has an invalid type.
        ValueError:
            If a metadata value is outside its valid domain.
    """
    if isinstance(modification_time_ns, bool) or not isinstance(modification_time_ns, int):
        raise TypeError("Source modification time must be an integer.")
    if isinstance(size, bool) or not isinstance(size, int):
        raise TypeError("Source size must be an integer.")
    if not isinstance(sha256, str):
        raise TypeError("Source SHA-256 digest must be a string.")

    if modification_time_ns < 0:
        raise ValueError("Source modification time cannot be negative.")
    if size < 0:
        raise ValueError("Source size cannot be negative.")
    if not _sha256_is_valid(sha256):
        raise ValueError("Source SHA-256 digest must be 64 hexadecimal characters.")

_metadata_is_valid

_metadata_is_valid(
    modification_time_ns: object,
    size: object,
    sha256: object,
) -> bool

Return whether decoded source metadata has the expected shape.

Parameters:

Name Type Description Default
modification_time_ns object

Decoded modification-time value.

required
size object

Decoded file-size value.

required
sha256 object

Decoded digest value.

required

Returns:

Type Description
bool

Whether all metadata values are valid.

Source code in hotstring\autocorrect2\source_loading\cache.py
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
def _metadata_is_valid(
    modification_time_ns: object,
    size: object,
    sha256: object,
) -> bool:
    """Return whether decoded source metadata has the expected shape.

    Args:
        modification_time_ns:
            Decoded modification-time value.
        size:
            Decoded file-size value.
        sha256:
            Decoded digest value.

    Returns:
        Whether all metadata values are valid.
    """
    return (
        isinstance(modification_time_ns, int)
        and not isinstance(modification_time_ns, bool)
        and modification_time_ns >= 0
        and isinstance(size, int)
        and not isinstance(size, bool)
        and size >= 0
        and isinstance(sha256, str)
        and _sha256_is_valid(sha256)
    )

_sha256_is_valid

_sha256_is_valid(value: str) -> bool

Return whether a string is a lowercase-or-uppercase SHA-256 hex digest.

Parameters:

Name Type Description Default
value str

Candidate digest string.

required

Returns:

Type Description
bool

Whether the value contains exactly 64 hexadecimal characters.

Source code in hotstring\autocorrect2\source_loading\cache.py
577
578
579
580
581
582
583
584
585
586
587
def _sha256_is_valid(value: str) -> bool:
    """Return whether a string is a lowercase-or-uppercase SHA-256 hex digest.

    Args:
        value:
            Candidate digest string.

    Returns:
        Whether the value contains exactly 64 hexadecimal characters.
    """
    return len(value) == 64 and all(character in string.hexdigits for character in value)