an.library.affordances#

Affordances for the library: the capability registry, re-exported from an.capabilities.

P5 seeded ADR 0002’s affordances(asset) here; P7 moved the tables and the matcher to the core registry, an.capabilities, and this module now re-exports the SAME objects (ANALYSERS is an.capabilities.ANALYSERS), so the library’s facets and find(…, near=True) and the compiler’s method choice are one derivation and one matcher, never two.

The character analyser is the cut-out genre’s: it registers through an.genres.cutout.CUTOUT (its capabilities and analysers fields) when the genres load, which the library’s entry points do (an.library.api.publish(), an.library.api.find()).

>>> import an.capabilities
>>> ANALYSERS is an.capabilities.ANALYSERS and CAPABILITIES is an.capabilities.CAPABILITIES
True
>>> afford = {"swap.view": {"keys": ["front", "side"]}, "limbs.legs": {}}
>>> matches(afford, "swap.view:side"), matches(afford, "swap.view:back"), matches(afford, "limbs.legs")
(True, False, True)

Functions

analyse(kind, doc[, art])

(profile, analysers) of one subject: its capabilities and the analyser versions used.

capability_of(query)

(capability, key) of a query term (the library's find form).

current_affordances(kind, doc, art, *, ...)

The stored snapshot when its analyser version is current, else a fresh derivation.

matches(profile, term)

Whether profile (or the subject of term in a Subjects) meets term.

missing(profile, requires)

The requirement terms profile does not meet, spelled, in the order asked.

register_analyser(kind, *[, version, ...])

Register an analyser.

register_capability(name, *[, description, ...])

Register a capability (or a Capability).

remedy_for(term)

What would add the capability a requirement term asks for.

Classes

Analyser(kind, version, derive[, subject, ...])

The derivation of one kind's profile, versioned.

Capability(name, description, remedy[, ...])

A registered capability: its name, what it means, and how to add it.

class an.library.affordances.Analyser(kind, version, derive, subject='asset', declares=(), overrides=None)[source]#

Bases: object

The derivation of one kind’s profile, versioned.

kind is an asset kind (character) or a subject that has one analyser (engine, environment). Bump version whenever the output can change for the same input: snapshots made under the old one are then recomputed on read. The version is NOT a compile input (consult §5): the derived profile is, so touching an analyser without changing its output re-renders nothing.

declares: tuple[str, ...] = ()#

The document’s declared facts the derivation honours instead of deriving (rest_view, face_overlay) or reads as a request (gait): reported by describe_asset (ADR 0002 decision 2).

overrides: Callable[[Any, Mapping[str, Any]], Iterable[str]] | None = None#

(doc, art) -> declared field names the derivation USED as overrides that do not show on an afforded capability’s params: a declared fact that REMOVES a capability (a character’s occluded, an#381). Those on an afforded capability are already in its overrides param. None: none beyond those. Reporting only: it changes no profile, so adding it does not bump version.

class an.library.affordances.Capability(name, description, remedy, subject='asset', command=None, version='1')[source]#

Bases: object

A registered capability: its name, what it means, and how to add it.

command is the CLI that adds it, when one exists (an character add-views); version bumps when the meaning of the name changes (a persisted name is never redefined in place).

to_json()[source]#

The capability as the generated docs and the MCP surface list it.

Return type:

dict[str, Any]

an.library.affordances.analyse(kind, doc, art=None)[source]#

(profile, analysers) of one subject: its capabilities and the analyser versions used.

A kind with no registered analyser affords nothing derived and records no analyser — an honest empty answer, not a guess.

Return type:

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

>>> analyse("no-such-kind", {})
({}, {})
an.library.affordances.capability_of(query)[source]#

(capability, key) of a query term (the library’s find form).

Return type:

tuple[str, str | None]

>>> capability_of("swap.view:side"), capability_of("limbs.legs")
(('swap.view', 'side'), ('limbs.legs', None))
an.library.affordances.current_affordances(kind, doc, art, *, stored, stored_analysers)[source]#

The stored snapshot when its analyser version is current, else a fresh derivation.

Affordances are derived data, so recomputing them is always safe; trusting a snapshot made by an older analyser is what would make a facet lie.

Return type:

dict[str, dict[str, Any]]

an.library.affordances.matches(profile, term)[source]#

Whether profile (or the subject of term in a Subjects) meets term.

Return type:

bool

an.library.affordances.missing(profile, requires)[source]#

The requirement terms profile does not meet, spelled, in the order asked.

THE matcher (ADR 0002 decision 4): why_not, applicable, resolve and the library’s find(…, near=True) all call it.

Return type:

list[str]

>>> missing({}, ["env.ffmpeg"]), missing(Subjects(environment={"env.ffmpeg": {}}), ["env.ffmpeg"])
(['env.ffmpeg'], [])
an.library.affordances.register_analyser(kind, *, version='', subject='asset', owner='an')[source]#

Register an analyser. Two forms.

register_analyser(Analyser(...), owner=...) registers the object and returns it (a genre’s analysers field goes this way). With a kind string it is a decorator: @register_analyser("character", version="0.1.0") registers the decorated derivation.

Return type:

Any

an.library.affordances.register_capability(name, *, description='', remedy='', subject='asset', command=None, version='1', owner='an')[source]#

Register a capability (or a Capability). Returns it.

Re-registering the same definition is a no-op; a different definition under a name another owner holds raises, because capability names are persisted and two meanings for one name would make a stored facet lie.

Return type:

Capability

>>> cap = register_capability("demo.thing", description="a thing", remedy="add one", owner="demo")
>>> CAPABILITIES["demo.thing"] is cap
True
>>> _ = drop_owner("demo")
an.library.affordances.remedy_for(term)[source]#

What would add the capability a requirement term asks for.

Return type:

str

>>> remedy_for("no.such.capability")
'no registered capability no.such.capability; see vocabulary() for the known names'