an.library.registry#

The machine’s memory of its libraries: every root ever written, and every statement ever made (an#249).

The rights floor (an.library.floor) must read every statement any library on this machine makes about a blob, not only those it can discover from today’s environment. Discovery finds the package roots under the CURRENT data folder (which follows XDG_DATA_HOME) and the CURRENTLY set <PKG>_HOME roots. A library written at an explicit root= / --root, or under an environment that has since changed, is invisible to discovery, and its private bytes would then publish as free anywhere else.

So this module keeps two records, side by side, at a location that depends on nothing in the environment: the account’s home folder as the operating system records it (the password database on POSIX, never $HOME), under the core package’s default data folder — ~/.local/share/an/registry/ on Linux and macOS, whatever XDG_DATA_HOME, AN_HOME or <PKG>_HOME say. (On Windows the account’s home is Path.home(), which follows USERPROFILE: there the location is as stable as that variable.)

  • The registry of roots (library_roots.jsonl): the first write to any on-disk library records its root, and the floor reads each registered root’s own index. JSON Lines, append-only: an append of one short line is atomic, so racing publishers cannot lose each other’s registration, and a line torn by a crash is skipped (the next append starts on a fresh line). A root that no longer exists is skipped — which is why the second record exists.

  • The memory of statements (statements/<aa>/<sha256>/…json): every statement a version makes about a blob, written at publish beside the library’s own index. The floor reads it in addition to the libraries, so a library that is moved, renamed, unmounted or deleted can never relax a statement it once made: a missing root relaxes nothing. One small file per (blob, library root, asset), replaced only by a later version of the same asset at the same root — so a relicence there still speaks, as in the library’s own index. A file that cannot be parsed counts as unknown.

  • The record of generated bytes (generated/<aa>/<sha256>/…json): the digests the character factory drew on this machine, written only at the end of new_character, for the folder it created empty in that call (record_generated(), deliberately not exported) — never by the public stamping functions, which stamp whatever bytes they are pointed at. It verifies a factory stamp: such bytes are the factory’s cc0 work whatever an older, UNLABELLED asset holding the same bytes fails to say (an#269). It relaxes only unknown, never a statement anyone made.

Deleting the registry folder wholesale deletes that memory with it — nothing left on disk tells a deleted registry from a first use — so whenever the registry is created from nothing, the first write warns (RegistryWarning). Prune it; never delete it.

Both are read fail-closed: a registry or memory that exists but cannot be read raises RegistryError — a floor that silently read less would let private bytes out. Libraries with injected stores (no root on disk: an S3 or in-memory mall) are in neither record; their statements reach the floor only while they are on the search path.

Neither record is a search path: a registered library’s assets are never found, resolved or checked out through them — reads still go through the explicit search path (an.library.federation.search_path()).

Tests and doctests are redirected by the repository’s root conftest.py, which points _account_home() into a temporary folder. A test that runs an in a SUBPROCESS cannot be redirected that way and must not publish.

>>> import tempfile, pathlib
>>> with tempfile.TemporaryDirectory() as d:
...     reg = pathlib.Path(d) / "roots.jsonl"
...     first = register_root("cutan", pathlib.Path(d) / "study", registry=reg)
...     again = register_root("cutan", pathlib.Path(d) / "study", registry=reg)
...     (first, again), [(p, r.name) for p, r in registered_roots(registry=reg)]
((True, False), [('cutan', 'study')])

Module Attributes

REGISTRY_DIRNAME

The sub-folder of the core package's default data root holding the registry (a root holds one sub-folder per kind of data, never files at the top).

REGISTRY_FILENAME

JSON Lines, one {"package", "root", "registered"} per line.

STATEMENTS_DIRNAME

The folder of remembered statements, beside the registry file.

GENERATED_DIRNAME

The folder of the machine's record of bytes a GENERATOR drew here (an#269).

Functions

machine_registry_dir()

The folder holding the registry and the statement memory (independent of the environment).

machine_registry_path()

Where this machine's registry of library roots lives.

register_root(package, root, *[, registry])

Record root (package's library root) in the registry; True if it was new.

registered_roots(*[, registry])

(package, root) for every root ever registered, oldest first, each once.

remember_statements(root, statements)

Remember (digest, asset_key, statement) made by the library at root.

remembered_statements(digest)

(asset_key, statement) for every statement this machine ever recorded about digest.

remembered_statements_by_root(digest)

(root, asset_key, statement): remembered_statements() with the resolved root of the library that made each (None when unreadable).

generated_by(digest)

The generators this machine recorded as having drawn the bytes digest.

Exceptions

RegistryError

The machine's registry or statement memory cannot be read or written; nothing proceeds.

an.library.registry.GENERATED_DIRNAME: str = 'generated'#

The folder of the machine’s record of bytes a GENERATOR drew here (an#269).

an.library.registry.REGISTRY_DIRNAME: str = 'registry'#

The sub-folder of the core package’s default data root holding the registry (a root holds one sub-folder per kind of data, never files at the top).

an.library.registry.REGISTRY_FILENAME: str = 'library_roots.jsonl'#

JSON Lines, one {"package", "root", "registered"} per line.

Type:

The registry file

exception an.library.registry.RegistryError[source]#

Bases: OSError

The machine’s registry or statement memory cannot be read or written; nothing proceeds.

an.library.registry.STATEMENTS_DIRNAME: str = 'statements'#

The folder of remembered statements, beside the registry file.

an.library.registry.generated_by(digest)[source]#

The generators this machine recorded as having drawn the bytes digest.

Read fail-safe for rights: anything unreadable counts as not recorded, so the stamp it would verify is not verified (the stricter reading).

Return type:

frozenset[str]

an.library.registry.machine_registry_dir()[source]#

The folder holding the registry and the statement memory (independent of the environment).

Return type:

Path

>>> machine_registry_dir().name
'registry'
an.library.registry.machine_registry_path()[source]#

Where this machine’s registry of library roots lives.

Return type:

Path

>>> machine_registry_path().name
'library_roots.jsonl'
an.library.registry.register_root(package, root, *, registry=None)[source]#

Record root (package’s library root) in the registry; True if it was new.

Idempotent. Raises RegistryError when the registry cannot be read or written: a library the floor cannot find later must not be written to.

Return type:

bool

an.library.registry.registered_roots(*, registry=None)[source]#

(package, root) for every root ever registered, oldest first, each once.

A line that does not parse (a torn append) is skipped; existence is the caller’s to check. A registry that exists but cannot be read raises RegistryError.

Return type:

Iterator[tuple[str, Path]]

an.library.registry.remember_statements(root, statements)[source]#

Remember (digest, asset_key, statement) made by the library at root.

One file per (digest, root, asset), replaced only by a statement of a later (or the same) version of that asset — the same rule as a library’s own index. Raises RegistryError when it cannot be written.

Return type:

None

an.library.registry.remembered_statements(digest)[source]#

(asset_key, statement) for every statement this machine ever recorded about digest.

A remembered file that cannot be parsed counts as an unknown statement (it said something; what is no longer known). A memory that exists but cannot be listed raises RegistryError.

Return type:

list[tuple[str, dict[str, Any]]]

an.library.registry.remembered_statements_by_root(digest)[source]#

(root, asset_key, statement): remembered_statements() with the resolved root of the library that made each (None when unreadable).

Return type:

list[tuple[str | None, str, dict[str, Any]]]