query
syside.query – read-only queries over a loaded model.
Use this package to ask questions about a model that syside.load_model()
has produced: find elements by name or metadata, walk generalization and
containment hierarchies, and inspect features, connections, and variation
points. No function here modifies the model.
Three kinds of names are exported:
Traversal primitives –
generalizations(),specializations(), andwalk_containment()– which walk the type and ownership hierarchies.Query functions built on those primitives, such as
find_by_name()andfind_elements_of_type().Index types (
NameIndex,TypeIndex,MetadataIndex) with matchingbuild_*_indexbuilders. Without an index, each query scans the model; when you repeat lookups, build the index once and pass it via theindex=parameter to make each later lookup a dictionary read. An index never changes a query’s result, only its cost.
Every function returns a plain, fully materialized value – a list,
set, bool, scalar, or None – never a lazy view of the model.
Index
Classes ¶
A metadata lookup over a model, built once by |
||
The resolved multiplicity bounds of a feature. |
||
A name -> elements lookup over a model, built once by |
||
A concrete-type -> elements lookup, built once by |
||
The unbounded ( |
Functions ¶
Return the actor parameters of |
||
Yield the owner chain above |
||
Return the elements |
||
Build a |
||
Build a |
||
Build a |
||
Return whether |
||
Return the direct contents (owned elements) of |
||
Return the end features of |
||
Return the binding connectors touching |
||
Return the features |
||
Yield every element below |
||
Return the concatenated body text of |
||
Return the types that directly type |
||
Return the documentation elements owned by |
||
Return the enumerated values of |
||
Return the elements exposed by |
||
Return the chaining features of |
||
Return the types that |
||
Return all features of |
||
Find an element named |
||
Find the first model element of type |
||
Resolve |
||
Find the element whose rendered qualified name is exactly |
||
Return every model element of type |
||
Find metadata usages within |
||
Return every relationship of type |
||
Return whether |
||
Return the connectors that have |
||
Return the features |
||
Return whether |
||
Return |
||
Return all metadata usages owned by |
||
Return the resolved multiplicity bounds of |
||
Return the connectors whose source feature is |
||
Return the rendered qualified names of the direct heritage targets. |
||
Return the features that redefine |
||
Return the features |
||
Return the feature referenced by |
||
Return the other direct contents of |
||
Return whether |
||
Return the types |
||
Return the subject parameter(s) of |
||
Return the features |
||
Return the direct subtypes of |
||
Return the transitive closure of |
||
Return the body of |
||
Return the variant usages of a variation |
||
Return the elements declaring a heritage relationship to |
||
Return the heritage targets declared by |
||
Walk the ownership tree from |
Attributes
- UNBOUNDED: Final = 'Unbounded(...)'
The singleton
Unboundedupper bound (*).
Functions
- actors(element: syside.query._CaseLike) list[syside.PartUsage]
Return the actor parameters of
element, linear in the number of actors.Reads the core
actor_parametersaccessor, present on requirement and case usages/definitions (and their subtypes – use-case, verification-case, analysis-case, …).
- containers(element: syside.Element) Iterator[syside.Element]
Yield the owner chain above
element, nearest first.
- annotated_elements(metadata_usage: syside.MetadataUsage) list[syside.Element]
Return the elements
metadata_usageannotates, linear in the number of annotated elements.
- build_metadata_index(model: syside.Model) syside.query.MetadataIndex
Build a
MetadataIndexformodelin one pass, linear in model size.Scans every
syside.MetadataUsageonce, recording it and, when itsmetadata_definitionresolves to a named definition, indexing it under that definition’s simple name.
- build_name_index(model: syside.Model) syside.query.NameIndex
Build a
NameIndexformodelin one pass, linear in model size.Scans
model.nodes(syside.Element, include_subtypes=True)once, recording each element under its renderedqualified_name(when it has one – the first element to claim a qualified name wins, matching core semantics) and appending it to the per-simple-name bucket (when it has aname).
- build_type_index(model: syside.Model) syside.query.TypeIndex
Build a
TypeIndexformodelin one pass, linear in model size.Scans every element once and buckets it under its exact runtime class.
- contains(container: syside.Element, element: syside.Element) bool
Return whether
containercontainselement(at any depth).The inverse reading of
is_contained_in():contains(a, b) == is_contained_in(b, a).
- contents(element: syside.Element) list[syside.Element]
Return the direct contents (owned elements) of
element, linear in the number of owned elements.
- connection_ends(connection: syside.ConnectionUsage) list[syside.Feature]
Return the end features of
connection(itsconnector_ends) as a list.connector_endsis asyside.LazyIterator..collect()drains it into a Python list in a single O(n) pass over the n ends, which is what you want when you need every end materialized — to index it, take its length, hold it, or walk it more than once. (Most connections have only two ends, so the cost is negligible here; the guidance matters for the larger lazy collections these query helpers also wrap.).for_each(callback)on the underlyingconnection.connector_endsis the alternative, but it is worth it only when the callback can stop early: it allocates no list and short-circuits when the callback returns a stop signal, yet it pays a Python call per element where.collect()builds the list in native code. For a full drain it is therefore the slower of the two — measured 561 us against 392 us for.collect()at n=4000. Prefer.collect()unless you genuinely short-circuit, and expect the crossover only on large collections.Do not read the ends back with repeated
.at(i)/[i]indexing in a loop. ALazyIteratorre-seeks from the head on each index, so an index-per-element loop is O(n²) — measured ~67x slower than.collect()at n=4000 (74 ms vs 1.1 ms). ALazyIteratoris not a Python iterable, so.collect()or.for_each()is the only correct way to walk all ends.
- bindings_of(element: syside.Feature) list[tuple[syside.ConnectorAsUsage, syside.Feature]]
Return the binding connectors touching
elementand the bound counterpart.For each
syside.BindingConnectorAsUsageinelement’s owner subtree whose related features includeelement, returns a(connector, other)pair whereotheris the related feature that is notelement. A binding both of whose ends areelementcontributes a pair withother == element.
- cross_subsets(feature: syside.Feature) list[syside.Feature]
Return the features
featurecross-subsets (via cross subsetting), linear in the number of cross-subsetted features.Cross subsetting is the connection/association-end
crosses(=>) relationship; its target is the cross feature, typically a feature chain (the other end followed by that end’s cross feature). An ordinary feature yields[].
- all_contents(element: syside.Element) Iterator[syside.Element]
Yield every element below
elementin ownership, breadth-first.Backed by
walk_containment(); the walk drains eachowned_elementsiterator once and de-duplicates by identity.
- description(element: syside.Element) str | None
Return the concatenated body text of
element’s documentation, orNone.The bodies of every
syside.Documentationowned byelementare joined, in owned order, with a blank line between them – matching the way a VS Code hover concatenates multiple doc comments rather than showing only the first.Noneifelementhas no documentation.
- types_of(feature: syside.Feature) list[syside.Type]
Return the types that directly type
feature(itstypes), linear in the number of declared types.
- documentation(element: syside.Element) list[syside.Documentation]
Return the documentation elements owned by
element, linear in the number of documentation elements.
- enumeration_values(enum_def: syside.EnumerationDefinition) list[syside.EnumerationUsage]
Return the enumerated values of
enum_def, linear in the number of values.
- exposed_elements(view: syside.ViewUsage) list[syside.Element]
Return the elements exposed by
view(itsexposed_elements), linear in the number of exposed elements.
- feature_chain(feature: syside.Feature) list[syside.Feature]
Return the chaining features of
feature(the feature-chain links), linear in the chain length.A feature that is not a chain yields
[].
- featured_in(feature: syside.Feature) list[syside.Type]
Return the types that
featureis featured by (its featuring contexts).Backed by the direct
Feature.featuring_typesaccessor (linear in the number of featuring types). Unlike the other inverse queries this needs no model: type featuring is a forward accessor on the feature, not an inverse model scan.
- features_of(type_: syside.Type) list[syside.Feature]
Return all features of
type_(owned and inherited), linear in the feature count.
- find_by_name(scope: syside.Element, name: str, *, recursive: bool = False) syside.Element | None
Find an element named
namewithinscope.With
recursive=False(the default) only the direct members ofscopeare searched, via the constant-timeNamespace.get_memberaccessor. A non-syside.Namespacescopehas no members and yieldsNone.With
recursive=Truethe whole subtree belowscopeis searched and the first element (breadth-first) whose simplenameequalsnameis returned, orNoneif none matches.
- find_by_name_and_type(model: syside.Model, name: str, element_type: type[syside.query.find_by_name_and_type.ElementT], *, index: syside.query.NameIndex | None = None) syside.query.find_by_name_and_type.ElementT | None
Find the first model element of type
element_typenamedname.Searches the whole model and returns the first (scan-order) element whose simple
nameequalsnameand which is an instance ofelement_type(subtypes included), orNone. With anindexthis is a single name-bucket read; without one it is amodel.nodesscan, linear in model size, overelement_type.
- find_by_path(root: syside.Element, path: list[str]) syside.Element | None
Resolve
path(a list of simple names) starting fromroot.Each segment is looked up among the direct members of the current element with the constant-time
Namespace.get_memberaccessor. Returns the element reached by the final segment, orNoneif any segment does not resolve or a non-namespace is reached mid-path. An emptypathreturnsroot.
- find_by_qualified_name(model: syside.Model, qualified_name: str, *, index: syside.query.NameIndex | None = None) syside.Element | None
Find the element whose rendered qualified name is exactly
qualified_name.With an
indexthis is a single dict read. Without one it walks the qualified name segment by segment from each document root using the constant-timeNamespace.get_memberaccessor (never a per-elementpathscan), returning the first match orNone.
- find_elements_of_type(model: syside.Model, element_type: type[syside.query.find_elements_of_type.ElementT], *, include_subtypes: bool = True, exclude_stdlib: bool = True, index: syside.query.TypeIndex | None = None) list[syside.query.find_elements_of_type.ElementT]
Return every model element of type
element_type.With
include_subtypes=True(the default) instances of subclasses are included. Withexclude_stdlib=True(the default) library elements are dropped (model.nodesalready scopes to the user model, so this only matters for the rare library element reachable through it).With a
TypeIndexthis unions the relevant exact-type buckets; without one it is a singlemodel.nodesscan, linear in model size.
- find_metadata_usages(scope: syside.Element, *, name: str | None = None, metadata_type: type[syside.Element] | None = None, index: syside.query.MetadataIndex | None = None) list[syside.Feature]
Find metadata usages within
scope, filtered by name or type.Exactly one of
nameormetadata_typemust be given.namematches the simple name of a usage’s resolvedmetadata_definition(its metaclass);metadata_typematches usages whosemetadata_definitionis an instance of that type.The search is over the subtree below
scope(scopeincluded), in scan order. Anindex(built withbuild_metadata_index()) is a model-wide pool of usages; it is restricted toscopebefore filtering, so the result is identical to the unindexed subtree walk for anyscope, not only the model root. It pays off whenscopeis large or the lookup is repeated.
- find_relationships(model: syside.Model, relationship_type: type[syside.Relationship], *, exclude_subtypes_of: type[syside.Relationship] | None = None, index: syside.query.TypeIndex | None = None) list[syside.Relationship]
Return every relationship of type
relationship_typein the model.Subtypes of
relationship_typeare included.exclude_subtypes_of, if given, drops any relationship that is also an instance of that type (and its subtypes) – e.g.relationship_type=Specialization, exclude_subtypes_of=Subsettingkeeps specializations that are not subsettings. The two are conjunctive (ANDed): a relationship is returned only when it is an instance ofrelationship_typeand not an instance ofexclude_subtypes_of(orexclude_subtypes_of is None).With a
TypeIndexthis unions the matching exact-type buckets; without one it is a singlemodel.nodesscan, linear in model size.
- has_metadata_prefix(element: syside.Namespace, prefix_name: str) bool
Return whether
elementcarries a metadata prefix namedprefix_name.Matches
prefix_nameagainst the simple name of each prefix usage’s resolvedmetadata_definition(its metaclass).
- incoming_connections(element: syside.Feature) list[syside.ConnectorAsUsage]
Return the connectors that have
elementamong their target features.Searches the connectors owned within
element’s owner subtree (the scope a connector and its ends share) and keeps those whosetarget_featuresincludeelement. Returns the connectors in scan order.
- inherited_features(type_: syside.Type) list[syside.Feature]
Return the features
type_inherits from its supertypes, linear in the inherited-feature count.
- is_contained_in(element: syside.Element, container: syside.Element) bool
Return whether
elementis nested anywhere insidecontainer.True when
containeriselement’s owner, its owner’s owner, and so on – i.e.elementappears (at any depth) withincontainer’s braces.
- metadata_prefixes(element: syside.Namespace) list[syside.MetadataUsage]
Return
element’s prefix metadata usages (the#Nameprefixes), linear in the number of prefixes.The core
prefixesview yields(membership, feature)pairs; onlysyside.MetadataUsagefeatures are returned.
- metadata_usages(element: syside.Element) list[syside.MetadataUsage]
Return all metadata usages owned by
element(prefix and body), linear in the number of metadata usages.Reads the core
metadataview and keeps thesyside.MetadataUsageentries.
- multiplicity_bounds(feature: syside.Feature) syside.query.MultiplicityBounds | None
Return the resolved multiplicity bounds of
feature, orNone.Noneiffeaturedeclares no multiplicity, or if its multiplicity is not asyside.MultiplicityRangewith computed bounds. The corecached_upper_boundis an exclusive end, so the inclusive upper bound returned here iscached_upper_bound - 1(aNonecore bound becomesUNBOUNDED, an unbounded*). The lower bound is taken as-is.
- outgoing_connections(element: syside.Feature) list[syside.ConnectorAsUsage]
Return the connectors whose source feature is
element.Searches the connectors owned within
element’s owner subtree and keeps those whosesource_featureiselement. Returns them in scan order.
- generalization_names(type_: syside.Type) list[str]
Return the rendered qualified names of the direct heritage targets.
Unnamed targets contribute their
str(qualified_name)("None") only if they have one; targets with no qualified name are skipped.
- redefined_by(model: syside.Model, feature: syside.Feature) list[syside.Feature]
Return the features that redefine
feature(inverse of redefinition).Linear in model size: scans the model’s redefinition relationships via
specializations().
- redefines(feature: syside.Feature) list[syside.Feature]
Return the features
featureredefines (via redefinition), linear in the number of redefined features.
- referenced_feature(expression: syside.FeatureReferenceExpression) syside.Feature
Return the feature referenced by
expression.Raises
ValueErrorif the reference is unresolved (the corereferentisNone), so the return type is a non-optionalsyside.Feature.
- siblings(element: syside.Element) list[syside.Element]
Return the other direct contents of
element’s owner.elementitself is excluded. An element with no owner has no siblings.
- specializes(type_: syside.Type, candidate_supertype: syside.Type) bool
Return whether
type_specializescandidate_supertype(transitively).True iff
candidate_supertypeappears in the transitive heritage targets oftype_.
- direct_supertypes(type_: syside.Type) list[syside.Type]
Return the types
type_subclassifies (via subclassification), linear in the number of supertypes.
- subjects(element: syside.query._CaseLike) list[syside.Usage]
Return the subject parameter(s) of
element, constant time.Reads the core
subject_parameteraccessor, present on requirement and case usages/definitions (and their subtypes). The accessor is a single optional parameter, so the result is a list of zero or one element.
- subsets(feature: syside.Feature) list[syside.Feature]
Return the features
featuresubsets (via subsetting heritage), linear in the number of subsetted features.
- subtypes(model: syside.Model, type_: syside.Type) list[syside.Type]
Return the direct subtypes of
type_(the inverse of subclassification).Linear in model size: the core exposes no inverse index, so this scans the model’s subclassification relationships via
specializations().
- supertypes(type_: syside.Type) set[syside.Type]
Return the transitive closure of
type_’s heritage targets (types).
- textual_representation(element: syside.Namespace, language: str) str | None
Return the body of
element’s textual representation inlanguage.Matches
languagecase-insensitively (KerML defines language names as case-insensitive). Returns the body of the first matching representation, orNoneif none matches. Linear in the number of owned textual representations.
- variants(variation: syside.Definition | syside.Usage) list[syside.Element]
Return the variant usages of a variation
variation, linear in the number of variants.Both
syside.Usageandsyside.Definitionexpose avariantsaccessor.
- specializations(model: syside.Model, target: syside.Element, *, via: type[syside.Specialization] | type[syside.Conjugation] | None = None) list[syside.Element]
Return the elements declaring a heritage relationship to
target.This is the inverse of
generalizations()(one direct step): the elementsesuch thattargetappears amonggeneralizations(e). For example, withvia=syside.Subclassificationit returns the direct subtypes oftarget; withvia=syside.Redefinitionthe features that redefinetarget.viafilters by relationship type exactly as ingeneralizations()(subtypes included;Noneaccepts every kind).Cost and scope: the core exposes no inverse-heritage index, so this scans the model’s relationship nodes via
model.nodes(via or syside.Relationship, include_subtypes=True)and keeps those whose resolved target istarget. The scan spans every document of the user model – cross-document subtypes are found – and is keyed on object identity, so the match is exact (no name collisions). Cost is linear in the model’s relationship count. Standard-library documents fall outside theMODELdocument scope and are not searched.Results are de-duplicated by object identity and returned in scan order.
targetitself is never included (a self-referential heritage relationship is ignored).
- generalizations(element: syside.Type, *, via: type[syside.Specialization] | type[syside.Conjugation] | None = None, exclude: type[syside.Specialization] | type[syside.Conjugation] | None = None, transitive: bool = False) list[syside.Element]
Return the heritage targets declared by
element.The heritage of a
syside.Typeis the set of specialization and conjugation relationships it declares; each one points at a target type (thegeneralof a specialization, theoriginal_typeof a conjugation). This returns those targets.viafilters to relationships that are instances of the given relationship type, e.g.syside.FeatureTyping,syside.Subsetting,syside.Redefinition,syside.Subclassificationorsyside.CrossSubsetting. Subtypes of the given type are included (e.g.via=syside.Subsettingalso matchesRedefinitionandCrossSubsetting).via=Noneaccepts every heritage kind. Only heritage relationships – subtypes ofsyside.Specializationorsyside.Conjugation– are valid; a non-heritage kind such assyside.Disjoiningis a static type error (it never appears inheritage, so it could only ever yield[]).excludeis the complement ofvia: relationships that are instances of the given type (and its subtypes) are skipped. A transitive walk does not cross an excluded relationship, so the result is the closure reachable without that heritage kind. For example,exclude=syside.ReferenceSubsettingfollows every other specialization (including plainsyside.Subsetting, of whichReferenceSubsettingis a subtype) but never the reference-subsetting edge a connector introduces – the basis for asking what types a feature has independently of what a connection imposes on it.``via`` and ``exclude`` are conjunctive (ANDed). A relationship is followed if and only if it satisfies both restrictions: it is an instance of
via(orvia is None) and it is not an instance ofexclude(orexclude is None). Passing the same type to both – or aviathat is a subtype ofexclude– therefore matches nothing and yields[].With
transitive=False(the default) only the direct targets are returned. Withtransitive=Truethe chain is followed to its closure: each target’s own heritage targets are added, transitively. Theviaandexcludefilters apply at every step of a transitive walk.Results are de-duplicated by object identity and returned in first-seen order;
elementitself is never included. Cyclic heritage (which a malformed model can contain) terminates rather than looping forever.elementis asyside.Type: only types declare heritage. This is linear in the number of heritage relationships visited (the direct count, or the reachable closure whentransitiveis set), each step constant time.
- walk_containment(element: syside.Element, *, direction: Literal[up, down], max_depth: int | None = None) Iterator[syside.Element]
Walk the ownership tree from
element, yielding the elements reached.With
direction="up"the walk follows theownerchain: it yieldselement’s owner, then that owner’s owner, and so on up to the root namespace. Withdirection="down"it traversesowned_elementsbreadth-first: first the direct contents, then their contents, and so on. In neither direction iselementitself yielded.max_depthbounds the walk.max_depth=1yields only the elements one step away (the owner, or the direct contents);max_depth=None(the default) is unbounded.max_depth=0yields nothing. A negativemax_depthis treated as0.The downward walk de-duplicates by object identity and is cycle-safe: a well-formed ownership tree is acyclic, but a malformed model is still guaranteed to terminate and to yield each element at most once. The upward walk likewise stops if the owner chain ever revisits an element.
Downward traversal drains each
owned_elementsLazyIteratorwith a single.collect()(linear per node), never per-element Python iteration over the live iterator.