metta.spaces
Source: extensions/python/metta/spaces.py.
Space views and combinators on the public interface. Object views, union, readonly, mapped, and overlay are ordinary SpaceProvider instances; the same engine route therefore matches a live object or composes existing spaces without hardcoded integration paths.
The entries below reproduce the source signatures and docstrings.
view
def view(obj: Any):Return an attached live space over a dict, set, or sequence.
Dictionaries image as
(kv key value). Sequences use that same relation with zero-based integer keys, matching Python's indices; a value-bound query therefore answers every matching index. Sets image as raw members. External mutations are visible on the next query.
ObjectView
class ObjectView(SpaceProvider):One live Python object presented as
(py-field obj name value).Enumeration names the object's public fields. A bound field may also be served through
getattr, which lets an object with__getattr__answer the mode it actually supports without pretending it can enumerate. Adding the same atom shape writes the value withsetattr.
ObjectView.atoms
def atoms(self) -> Iterator[Atom]:Yield one field atom per readable public field of the object.
ObjectView.match
def match(self, pattern: Atom) -> Iterator[Atom]:Yield candidate field atoms for pattern, narrowed by root and field name.
ObjectView.add
def add(self, atom: Atom) -> None:Write one
(relation <object> <field> <value>)atom viasetattr.
object_view
def object_view(obj: Any, *, relation: str | Symbol = 'py-field') -> ObjectView:Present one object as a live, writable provider.
Compose it with stored facts through
spaces.union(stored, view)and register the result like any other provider. Register the view itself when MeTTa should write its fields throughadd-atom.
union
def union(*spaces: Any) -> _Union:A set of spaces read as one, writes refused by capability.
m._register_space(metta.spaces.union(kb, rules), "&all") m.run("!(match &all (edge $a $b) $b)")Every member's candidates answer; duplicates across members are answers twice, the multiset reading a union of multisets has.
readonly
def readonly(inner: Any) -> _ReadOnly:The inner space, reads only; writes meet the capability refusal.
mapped
def mapped(inner: Any, declaration: Any) -> _Mapped:A shape view over ANY space, from one declaration:
view = metta.spaces.mapped(kb, "(bridge (edge $a $b) (triple $a linked-to $b))")presents the inner space's (triple ...) atoms as (edge ...) atoms, both directions derived from the pattern pair by unification, the tables bridge with WHERE replaced by unify. Renames, projections, and legacy-shape adapters stop being custom providers and become this one line. Adds map right-to-left; removal maps the pattern through; atoms the declaration does not map are invisible here and untouched there.
overlay
def overlay(front: Any, back: Any) -> _Overlay:Both layers read as one; every write lands on front. The explicitly chosen form union() refuses to be: ChainMap semantics for spaces, deletes not forwarded to back.
diff
def diff(a: Any, b: Any) -> tuple[list[Atom], list[Atom]]:What digest() cannot say: HOW two spaces differ.
Answers (only_in_a, only_in_b), the multiset difference over enumeration, so a space holding an atom twice against one holding it once differs by the one copy. Alpha-equivalent atoms count as the same atom, digest()'s own equivalence, and each side's extras come back in that side's enumeration order. Both arguments are anything the combinators accept: a MeTTa handle or a provider. Each side is enumerated exactly once, so a live space is compared at one moment.