- synthgen/config.py: Config, load_config (YAML + --set), dump_config, проверки диапазонов §3 - synthgen/rng.py: rng_for (SHA-256 → Random), stable_hash - synthgen/__main__.py: разбор --config/--set/--out/--force, ошибка конфигурации → код 2 - synthgen/examples/default.yaml: все ключи §3 со значениями по умолчанию - копии из synthetic-group/gen (#35): inn, xlsx, ledger, chart (+80.09, 91.09 из seed arm-core) - тесты: config, inn, ledger; conftest с маркерами parser/slow - .gitignore: out/ - спека: решения 15–16 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
20 lines
1.1 KiB
Python
20 lines
1.1 KiB
Python
"""Детерминированная случайность: одно зерно на каждую подсистему.
|
|
|
|
Любая случайность в генераторе — только через `rng_for(seed, *keys)`; модульный `random` запрещён.
|
|
Ключи должны иметь стабильный `repr` (строки, числа, даты, кортежи из них).
|
|
"""
|
|
|
|
import hashlib
|
|
import random
|
|
|
|
|
|
def rng_for(seed: int, *keys: object) -> random.Random:
|
|
"""Генератор, зерно = первые 8 байт SHA-256 от repr((seed, *keys)) (порядок байт — big-endian)."""
|
|
digest = hashlib.sha256(repr((seed, *keys)).encode("utf-8")).digest()
|
|
return random.Random(int.from_bytes(digest[:8], "big"))
|
|
|
|
|
|
def stable_hash(text: str, modulo: int) -> int:
|
|
"""Стабильный хеш строки (SHA-256 → целое → остаток); в отличие от hash() не зависит от PYTHONHASHSEED."""
|
|
return int.from_bytes(hashlib.sha256(text.encode("utf-8")).digest(), "big") % modulo
|