Repository navigation
pymetta 0.9.3
pymetta 0.9.3 and all seventeen integration packages at 0.9.3, each pinning pymetta==0.9.3. tsmetta 0.0.1-alpha.2 and cmetta 2.0.0 are released beside it on the same engine.
Before you upgrade
A SWI-Prolog you built yourself has to be rebuilt. A pymetta host now needs 37 patches to SWI-Prolog where 0.9.2's needed 19: the engine requires 35 to swipl-devel itself and pymetta the 2 to janus, and each refuses at boot a host that lacks one, naming each missing patch. On Linux x86_64 under CPython 3.12, 3.13 and 3.14 the wheel carries the patched host, so pip install pymetta is still the whole install; anywhere else, rebuild and redeclare the host as docs/patched-host.md describes. pymetta also checks its two janus patches right after boot and refuses a home that lacks one with EngineError.
The licence is Apache-2.0: pymetta and its seventeen members declared MIT through 0.9.2. The wheel carries LICENSE and NOTICE, and NOTICE keeps the MIT copyright and permission notice of PeTTa, the engine's origin.
These change what an existing program sees:
- Hook verdicts, typing-rule outcomes and translator-rule refusals are capitalized constructors. A pre-add or post-add handler answers
(Accept),(Accept <atom>),(Refuse <words>)or(Drop); anadd-typing-rule!outcome isAccept,(Refuse <reason>)orDefer. The lowercase spellings are refused by name. In Python the builders areAccept,RefuseandDrop, replacingaccept,refuseanddrop. - The Python seat's evaluation options
fuelandunmatchedare gone. Every evaluation runs in the evaluation fuel scope, so(pragma! max-stack-depth N)bounds anevalas it bounds a!form, and answers an unmatched call by the dispatch policy. - The
py-*doors refuse with the platform refusal naming the python capability wherever no Python seat is loaded, under tsmetta and in an engine booted without theextensionstoken, where each call used to answer itself unreduced. - A registration of Prolog that its contract refuses raises
RegistrationError, which is also aValueError, and carriesrequires, what the registration lacks.register_prolog(path=...)of a file that is not there raisesSourceNotFound. lib_process,lib_socketandlib_httpimport on a build without their capability, and only the call that needs it refuses, withPlatformCapabilityError.setup!names its subject by the ruleget-propertyandfromfollow: a bare name is a library under the library root and a relative path is written./x.- An open
get-atomsread of a native space meets the atoms shortest first, in insertion order within one length. MeTTa specifies no order across a space's atoms; a program that relied on the old order, SWI's procedure-table hash order, sees a different one. - A
|->lambda is named by its content,lambda_and 16 hex digits, instead of a process-wide counter, so a saved space names its lambdas the same in every process. - The engine no longer publishes
metta_typed_dispatch_applies/2.
New
- Every seat evaluates through one engine door,
metta_host_evaluate/5, which runs a term in the fuel scope and answers each value as data with its well-founded residue. - Registering Prolog as MeTTa functions is one engine service,
metta_register_prolog/3, which PyMeTTa'sregister_prolog, tsmetta'sregisterPrologand cmetta'smt_register_prologall cross once, so the three refuse the same names before a source loads. Space.copy()restores a space's rows into the copy the way a load restores a program and compiles in the copy exactly what the source had compiled (metta_host_copy_rows/2).- The library pack's page,
lib/README.md, shows a worked example of every one of the 61 libraries again, each quoted from the corpus program that exercises it and held to it by thelibrary-readmelane.
Fixed
- A Prolog source loaded on another thread, or inside an engine of its own, raises the errors it prints, where a syntax error in a source registered from a worker thread was lost.
- A term stored through a Python space provider comes back as the term the engine gave it, so a stored partial application applies as it does in a native space.
- A specialization that fails in one space no longer stops the same call specializing in another, writing a function into one space no longer compiles other spaces' waiting equations of that name, and importing a library no longer fails when an earlier import's function has been specialized in the same space.
- A library head backed by Prolog stays a function in every space still importing the library when the first space that imported it is dropped.
(get-property Subject Key)answers or refuses by name for every subject a program can write, and a library name of..is refused as leaving the library root.unicode-normalize'snfkc-casefoldremoves default-ignorable code points, as Unicode's NFKC_Casefold does.- lib_http's server answers a request whose Accept header carries a wildcard, as curl, browsers and Python's requests send.
@definecompiles a function that reuses a finishedforloop's variable as a later loop's counter.LimitSizeinlib_narsandlib_plnanswers at every size.- Two threads reading one platform capability for the first time no longer read an absent capability as present.
- No callback the garbage collector runs for the Python seat takes a lock, a
watch()iterator collected withoutclose()no longer cancels its subscription from inside the collector, and an abandonedChannelreleases its SWI message queue. CITATION.cffand the README's citation block name the release, where both read 0.8.0 through 0.9.2; a test now holds them, and the changelog's newest heading, to the version the package builds.
The full list, with the development tooling's changes, is the 0.9.3 section of the changelog.
Known issues
Each of these three is fixed after this release.
- A long-lived process that creates and releases many contexts and imports libraries into them grows the engine's predicate registry with its history, so a later import costs far more than the same import in a fresh process. One test run replayed in a single process held 7.7 million predicates, 1.55 million clauses and 4.4 GB by its 5,255th test, and a property test creating a fresh
MeTTa()and importinglib.filefor each example took about 130 s and added about 1.37 million predicates, against 4.8 s and under 500 in a fresh process. What amplifies the growth is still being identified. Each import's shadow repair also sweeps every import receipt the process holds, which costs time but does not add the predicates; a repair that reaches only the import's own names follows this release. - A race pulled through a streaming door, such as
race()or afncall, is counted partly inside that door's held engine, and that part varies with the schedule, so itsm.stats()block is not one integer: 200 races throughSpace.fnread 1,038 to 9,049 inferences, where the same race throughrunreads 1,167 every time. The fix takes a held goal's work through the engine's own accounting, so a stopped branch's discarded work stays out of the block. - Cancelling a spawned future costs the caller 27 inferences more when the task is still queued than when a carrier is already running it, and the schedule decides which, so two equal blocks can differ by 27. The fix charges every branch of the cancel alike.
How this release was checked
These are the files built from the release commit and checked before upload. Every distribution builds an sdist and a pure wheel from a tree holding only committed state, and all of them pass twine check --strict. Each of pymetta's three manylinux wheels passes check_host_bundle.py and boots from a clean virtual environment outside the repository under env -i, answering from its own host. The pure wheel beside PyPI's janus-swi on a stock SWI-Prolog is refused with EngineError. All seventeen members install beside pymetta pinning pymetta==0.9.3 and their entry points load. Every published entry point resolves with each extra it declares: 495 of 495 combinations over Linux x86_64 and aarch64, macOS arm64 and x86_64, and Windows amd64, for CPython 3.12, 3.13 and 3.14.