pymaiml.query¶
query ¶
pymaiml.query¶
Read-only query utilities for MaiML documents.
get_uuids(), get_keys(), get_insertion_uris(), get_templates(), and get_instances() all read their answer off the maiml_domain object tree that pymaiml.serialization.loads(xml_text) builds -- so xml_text must be schema-valid MaiML for all five (loads() raises otherwise -- typically ValueError, or an lxml parse error for input that is not even well-formed XML -- and these functions do not catch or soften that). Their XXE/entity-expansion/network hardening is therefore whatever loads() does; see pymaiml._xml_security.make_untrusted_input_parser() and tests/test_xml_security.py's loads() coverage.
get_namespaces() is the one exception: namespace declarations are an XML-level concept that maiml_domain's object tree does not represent at all (see pymaiml.serialization's own "Known limitations" -- dumps() re-derives them from extra_namespaces=, no maiml_domain class stores them anywhere), so it parses xml_text directly instead, with the same untrusted-input hardening. xml_text does NOT need to be schema-valid for get_namespaces() specifically.
Two families of functions live here:
- get_uuids(), get_keys(), get_namespaces(), get_insertion_uris() return flat lists of strings (a dict, for get_namespaces()) -- every X used in this file. get_uuids() keeps duplicates (a uuid is meant to identify one object, so a repeated one is itself a fact worth seeing -- see its own docstring); the other three deduplicate, first occurrence kept.
- get_templates() and get_instances() return the actual maiml_domain objects themselves (see the Template/Instance type aliases below), filtered by keyword-only arguments: kind= picks material/condition/ result, instruction_id= narrows by PNML topology (see each function's own docstring for the exact semantics -- they share the same instruction_id= chain via _templates_linked_to_instruction()). This is deliberately extensible: "get everything" is kind=None (the default); "get just ids" is [obj.id for obj in get_templates(xml)] on the caller's side, not a separate function; a new way to narrow the result is a new keyword argument on the existing function, not a new function name.
All five loads()-based functions walk the maiml_domain object tree with the same generic, no-per-class-knowledge helper, _iter_domain_objects(): depth-first through every non-leaf attribute (vars(obj), in each class's own init assignment order) and every list/tuple element. A class maiml_domain adds in the future is automatically covered without this module needing to know about it specifically -- which is also why the "document order" these functions report is only approximate, not guaranteed byte-for-byte identical to the source XML's element order in every edge case.
See CHANGELOG.md for the history of this module (it originally parsed raw XML directly instead of going through maiml_domain).
get_uuids ¶
Every uuid in xml_text's maiml_domain object tree (loads(xml_text).root), in document order, INCLUDING duplicates -- unlike get_keys()/ get_insertion_uris(), this does not deduplicate. A uuid is meant to uniquely identify one object, so a uuid that appears more than once is a fact about the file worth being able to observe (e.g. two distinct objects accidentally sharing an identity), and deduplicating here would hide it. If you want the distinct set instead, wrap the result yourself, e.g. set(get_uuids(xml_text)) or list(dict.fromkeys(get_uuids(xml_text))).
Covers every maiml_domain attribute that carries a uuid: a GlobalObjectContent's own identity uuid (document/creator/vendor/.../ material/.../eventLog...), an InsertionType's uuid (identifying the inserted external file, a distinct concept from the uuid of the object doing the inserting), and a ChainType/ParentType's uuid. Returned as plain str (str(obj.uuid) -- maiml_domain.Uuid is itself a str subclass, this just normalizes the type callers see).
xml_text must be schema-valid MaiML: this calls pymaiml.serialization.loads(xml_text) and raises whatever loads() raises for anything else (see the module docstring).
ソースコード位置: pymaiml/query.py
get_keys ¶
Every key= value in xml_text's maiml_domain object tree (loads(xml_text).root), in document order, with duplicates removed (first occurrence kept).
Covers every maiml_domain attribute that carries a key: every
property/content instance (UncertaintyBaseType.key -- StringType,
FloatType, and every other property/content leaf class this package
defines, including
xml_text must be schema-valid MaiML: this calls pymaiml.serialization.loads(xml_text) and raises whatever loads() raises for anything else (see the module docstring).
ソースコード位置: pymaiml/query.py
get_namespaces ¶
Every custom xmlns:
Unlike get_uuids()/get_keys()/get_insertion_uris(), this does NOT go through pymaiml.serialization.loads() or maiml_domain: namespace declarations are an XML-level concept that no maiml_domain class stores (see the module docstring), so there is nothing to read off the object tree here. This parses xml_text directly instead, with the same pymaiml._xml_security.make_untrusted_input_parser() hardening loads() uses. Because it does not go through loads(), xml_text does NOT need to be schema-valid for get_namespaces() specifically (though calling it on a file you also intend to get_uuids()/get_keys()/ get_insertion_uris() from, or load(), still requires that elsewhere).
Excludes the unprefixed default namespace (MaiML's own http://www.maiml.org/schemas, always implicit and not itself interesting to enumerate) and the xsi: binding, matching pymaiml.serialization.LoadedMaiml.namespaces's existing convention -- the result of this function is suitable to pass straight through as dumps(..., extra_namespaces=get_namespaces(xml_text)).
Unlike LoadedMaiml.namespaces (which only looks at the root
Raises ValueError if the same prefix is bound to two different URIs at different points in the document -- silently keeping one would misrepresent which namespace some tag/key= in the file actually uses.
ソースコード位置: pymaiml/query.py
get_insertion_uris ¶
Every external file URI (InsertionType.uri) in xml_text's maiml_domain object tree (loads(xml_text).root) -- see maiml_domain.core. InsertionType; GlobalObjectContent.insertions is where these live -- in document order, with duplicates removed (first occurrence kept).
xml_text must be schema-valid MaiML: this calls
pymaiml.serialization.loads(xml_text) and raises whatever loads()
raises for anything else (see the module docstring). One direct
consequence: an
ソースコード位置: pymaiml/query.py
get_templates ¶
get_templates(xml_text: Union[str, bytes], *, kind: Optional[str] = None, instruction_id: Optional[str] = None) -> List[Template]
Every material/condition/resultTemplate in xml_text's maiml_domain object tree (loads(xml_text).root), in document order, as the actual maiml_domain objects themselves (MaterialTemplateType/ ConditionTemplateType/ResultTemplateType -- see maiml_domain.protocol), not ids or strings. Want just the ids? [t.id for t in get_templates(xml_text)] -- there is no separate "ids only" function, the object already has everything on it.
kind, if given, must be one of "material"/"condition"/"result" and restricts the result to just that template kind (ValueError for anything else); the default None returns all three kinds together.
A template can be defined at any of three structural levels -- ProgramType, MethodType, or ProtocolType each have their own material_templates/condition_templates/result_templates -- and this walks all of them without distinguishing which level a given result came from (maiml_domain does not tag a template object with that itself); compare returned objects' .id/template_refs, or walk loaded.root directly, if that distinction matters.
instruction_id, if given, restricts the result to templates reachable
from the
xml_text must be schema-valid MaiML: this calls pymaiml.serialization.loads(xml_text) and raises whatever loads() raises for anything else (see the module docstring).
ソースコード位置: pymaiml/query.py
get_instances ¶
get_instances(xml_text: Union[str, bytes], *, kind: Optional[str] = None, instruction_id: Optional[str] = None) -> List[Instance]
Every material/condition/result instance in xml_text's maiml_domain object tree (loads(xml_text).root), in document order, as the actual maiml_domain objects themselves (MaterialType/ConditionType/ ResultType -- see maiml_domain.data; each carries its own .ref back to the template it is an instance of). Want just the ids? [i.id for i in get_instances(xml_text)] -- same as get_templates(), no separate function for that.
kind works exactly like get_templates()'s: one of "material"/ "condition"/"result" to restrict to that kind (ValueError for anything else), or the default None for all three kinds together.
instruction_id, if given, restricts the result to instances reachable
from the
- instruction -> event: every
in xml_text's eventLog, through that event's own results_refs, to the element(s) they refer to, and finally that element's own materials/conditions/results (see maiml_domain.event_log.EventType and maiml_domain.data. ResultsType). This is "which instances were actually recorded as the outcome of running this instruction". - instruction -> PNML topology: the same instruction -> transitionRef -> transition -> arc -> place -> template chain get_templates()'s instruction_id= uses (see its docstring and _templates_linked_to_instruction()), one hop further to every instance whose own .ref names one of those templates. This is "which instances are of a template this instruction's transitions are wired to", independent of whether any event has actually recorded one yet.
instruction_id must name an
A protocolFileRootType document (a protocol-only file -- see
maiml_domain.root.ProtocolFileRootType, which has no data/eventLog at
all) has no instances to find, so get_instances() on one always
returns [] regardless of kind or instruction_id -- a legitimate
instruction_id there still resolves without raising (the
xml_text must be schema-valid MaiML: this calls pymaiml.serialization.loads(xml_text) and raises whatever loads() raises for anything else (see the module docstring).
ソースコード位置: pymaiml/query.py
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | |