query
Description
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 declared 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 ( |
Attributes
Functions
Return the actor parameters in effect for |
||
Return the actor parameters |
||
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 |
||
Find the binding connectors touching |
||
Return the features |
||
Yield every element below |
||
Return the concatenated body text of |
||
Return the types |
||
Return every type reachable from |
||
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 the visible features of |
||
Find an element named |
||
Find the first model element of type |
||
Return the element whose rendered qualified name is exactly |
||
Resolve |
||
Return every element of type |
||
Find the metadata usages within |
||
Return every relationship of type |
||
Return whether |
||
Find every connector one of whose ends attaches to |
||
Find the connectors with |
||
Find the connectors with |
||
Return the core |
||
Return whether |
||
Return |
||
Return all metadata usages owned by |
||
Return the multiplicity bounds |
||
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 classifiers |
||
Return the subject parameter in effect for |
||
Return the |
||
Return the features |
||
Return the classifiers that directly subclassify |
||
Return every type |
||
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 |
Enumerations
Which documents, and which library elements within them, the |
Attributes
- UNBOUNDED: Final = 'Unbounded(...)'
The singleton
Unboundedupper bound (*).
Functions
- actors(element: syside.query._CaseLike) list[syside.PartUsage]
Return the actor parameters in effect for
element, in parameter order.Cost is O(a), where a is the number of actors returned. Reads the core
actor_parametersaccessor, present on requirement and case usages/definitions (and their subtypes: use-case, verification-case, analysis-case, …). The result is the effective list, not a union: actors are parameters, and an actorelementdeclares redefines the inherited actor at the same position and replaces it, while inherited actors beyond the declared ones are kept. Foruse case def Base { subject s; actor driver; actor passenger; }anduse case def Sub :> Base { subject :>> s; actor mech; },actors(Sub)is[Sub::mech, Base::passenger]anddriveris not returned. For only the actorselementdeclares itself, usedeclared_actors().
- declared_actors(element: syside.query._CaseLike) list[syside.PartUsage]
Return the actor parameters
elementdeclares itself, in declaration order.Cost is O(a), where a is the number of actors in effect for
element(the inherited ones are visited and dropped).Only the
actordeclarations written inelement’s own body; inherited actors are left out. For every actor in effect, inherited ones included, useactors().
- 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, *, library_elements: syside.query.LibraryElements = LibraryElements.WORKSPACE) syside.query.MetadataIndex
Build a
MetadataIndexformodelin one pass, linear in model size.Scans every
syside.MetadataUsageof the documentslibrary_elementsselects once, recording it and, when itsmetadata_definitionresolves, indexing it under that definition (by identity) and, when the definition is named, under its simple name.library_elementsis tested against the usage, not against itsmetadata_definition: a@Tagon an ordinary part is indexed underNONEeven whenTagis declared inside alibrary package. Only usages that themselves lie in a library package are dropped. Build the index with the same value the lookups it backs will use.
- build_name_index(model: syside.Model, *, library_elements: syside.query.LibraryElements = LibraryElements.WORKSPACE) syside.query.NameIndex
Build a
NameIndexformodelin one pass, linear in model size.Scans every element of the documents
library_elementsselects once, recording each non-membership element under its renderedqualified_name(when it has one; the first element to claim a qualified name wins, matching core semantics) and appending every element, memberships included, to the per-simple-name bucket (when it has aname). The buckets keep memberships because their consumers filter by type and so ask for one deliberately;by_qualified_namedoes not, for the reason given onNameIndex.Elements
library_elementsexcludes are not indexed at all. Skipping them during the scan (rather than post-filtering) matters: a post-hoc filter could not undo an excluded element having claimed a qualified name ahead of an included namesake. Build the index with the same value the lookups it backs will use.
- build_type_index(model: syside.Model, *, library_elements: syside.query.LibraryElements = LibraryElements.WORKSPACE) syside.query.TypeIndex
Build a
TypeIndexformodelin one pass, linear in model size.Scans every element of the documents
library_elementsselects once and buckets it under its exact runtime class. Build the index with the same value the lookups it backs will use.
- 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 at 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.
- find_bindings_of(model: syside.Model, element: syside.Feature) list[tuple[syside.ConnectorAsUsage, syside.Feature]]
Find the binding connectors touching
elementand the bound counterpart.Every document of the user model is scanned (the same scope as
find_connectors_of()), at a cost linear in the model’s size. Returns one(connector, other)pair persyside.BindingConnectorAsUsagein the model one of whose ends attaches toelement, whereotheris the feature the opposite end references. Ends attach exactly as forfind_connectors_of(), so a chained end (bind a.p = b.p) attaches to every link of its chain, and the same connectors are found byfind_connectors_of(model, element, kind=syside.BindingConnectorAsUsage). For a chained opposite endotheris the chain feature (b.p), whose links are available throughfeature_chain(). A binding both of whose ends attach toelementcontributes a pair withotherbeing the second end’s feature (elementitself forbind x = x).
- 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.
- declared_types_of(feature: syside.Feature) list[syside.Type]
Return the types
featuredeclares, linear in the number of declared typings.Only the targets of
feature’s own feature typings: what is written after:in the declaration (KerMLFeatureTyping). A feature that declares no typing yields[], even when it conforms to types through subsetting or redefinition. For every type the feature conforms to, useall_types_of().
- all_types_of(feature: syside.Feature) list[syside.Type]
Return every type reachable from
feature’s typings, including what those types inherit, linear in its size.Declared typings, plus the types of the features it subsets or redefines, plus everything those types inherit from. A plain
part p : Midtherefore yieldsMidalongsideParts::Partup toBase::Anything, and a feature with no declared typing still yields the types it inherits. This is broader than KerML’s derivedFeature::type(which covers feature typings only, not typing reached through subsetting), yet the subsetted feature itself is not included, even though a KerML feature is a type. For the subsetted/redefined features usesubsets()/redefines(), and for every type inherited from through any heritage kind, which does include them, usesupertypes(). For only the declared typings, usedeclared_types_of().
- 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 the visible features of
type_, linear in the feature count.The core
Type.featuresview:type_’s own features plus the inherited features that remain visible members. A feature that one oftype_’s own features redefines is not included (KerML excludes redefined memberships from a type’s inherited memberships).
- 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 declared members ofscopeare searched (the members ofscope’s own memberships), via the constant-timeNamespace.get_memberaccessor. An alias declared inscoperesolves to its target (whichscopedoes not own, so do not assumeresult.owner is scope); a member thatscopeonly imports does not resolve, andNonefor an imported name does not mean the import is broken. 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.This lookup takes no
library_elements: it descends into alibrary packageunderscopelike any other namespace, and its result may haveis_library_elementset.
- find_by_name_and_type(model: syside.Model, name: str, element_type: type[syside.query.find_by_name_and_type.ElementT], *, library_elements: syside.query.LibraryElements = LibraryElements.WORKSPACE, index: syside.query.NameIndex | None = None) syside.query.find_by_name_and_type.ElementT | None
Find the first model element of type
element_typenamedname.Returns the first (scan-order) element whose simple
nameequalsnameand which is an instance ofelement_type(subtypes included), orNone.library_elementsselects which documents are scanned and which library elements within them are matched (seeLibraryElements). With anindexthis is a single name-bucket read; without one it is amodel.nodesscan overelement_type, linear in the scanned documents’ size.
- find_by_qualified_name(model: syside.Model, qualified_name: str, *, library_elements: syside.query.LibraryElements = LibraryElements.WORKSPACE, index: syside.query.NameIndex | None = None) syside.Element | None
Return the element whose rendered qualified name is exactly
qualified_name.library_elementsselects which documents are searched and which library elements within them can resolve (seeLibraryElements); a name in an environment document, such as"Base::Anything", resolves only underALL, while alibrary packagedeclared inside a workspace document is found underWORKSPACEandALL.The name asked for must be the element’s own: this is the inverse of
Element.qualified_name, so it answers only to the name an element renders as.get_memberfollows analiasto its target, so the walk below can arrive at an element by a name that is not its own, e.g.AP::AreachingP::Athroughalias AP for P. Such a hit is rejected, so that both paths answer the same question;get_by_path()is the lookup that does follow aliases.With an
indexthis is a single dict read. Without one the qualified name is walked segment by segment from each selected document’s root, using the constant-timeNamespace.get_memberaccessor (never a per-elementpathscan), returning the first match in document order orNone. Several matches exist only when documents each declare a same-named rootpackage; for the bare nameDuponly the first such package is returned (seeNameIndex). Their members stay reachable by their own qualified names, since every document root is tried:Dup::BBdeclared in the second document is found. To see all the same-named packages readbuild_name_index(model).by_simple_name[name], which lists every element of a simple name.Named
find_, notget_: the un-indexed lookup tries every document, so its cost is linear in the number of documents, and one document per package is common practice (see the module docstring’s naming note). It reads the tree directly, so it always reflects the current model, including elements created, renamed, or removed since the model was built. The unindexed walk never scans elements, soALLcosts nothing extra here: fetching one known stdlib element this way is independent of both the user model’s size and the stdlib’s (~150k elements). Only the scanning lookups (find_elements_of_type(),find_relationships(), an unindexedfind_by_name_and_type()) and the index builders pay for the widened scan underALL.
- get_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 declared members of the current element (the members of its own memberships: aliases resolve, to a target the element does not own; imported members do not) 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.This lookup takes no
library_elements: a segment naming alibrary packageresolves like any other namespace, and the result may haveis_library_elementset.
- find_elements_of_type(model: syside.Model, element_type: type[syside.query.find_elements_of_type.ElementT], *, include_subtypes: bool = True, library_elements: syside.query.LibraryElements = LibraryElements.WORKSPACE, index: syside.query.TypeIndex | None = None) list[syside.query.find_elements_of_type.ElementT]
Return every element of type
element_typethatlibrary_elementscovers.With
include_subtypes=True(the default) instances of subclasses are included.library_elementsselects which documents are scanned and which library elements within them are returned (seeLibraryElements).With a
TypeIndexthis unions the relevant exact-type buckets; without one it is a singlemodel.nodesscan, linear in the scanned documents’ size.
- find_metadata_usages(scope: syside.Element, *, name: str | None = None, definition: syside.MetadataDefinition | None = None, specializes: syside.Type | None = None, library_elements: syside.query.LibraryElements = LibraryElements.WORKSPACE, index: syside.query.MetadataIndex | None = None) list[syside.MetadataUsage]
Find the metadata usages within
scope, optionally filtered by what defines them.At most one of
name,definition,specializesmay be given; with none, every metadata usage inscopeis returned. The three filters ask about the metadata definition a usage is defined by (SysML@Tagormetadata t defined by Tag; coremetadata_definition):definition=tagkeeps the usages whosemetadata_definitionis that element (identity, not name). This is direct typing only: a@Subusage wheremetadata def Sub :> Tagis defined bySub, notTag, exactly as the spec derives a feature’s types with redundant supertypes removed.specializes=tagkeeps the usages that directly or indirectly specialize that type, in the spec’sType::specializessense (seespecializes()): a@Subusage is kept when asked aboutTag.name="Tag"keeps the usages whosemetadata_definitionhas that simple name. It cannot tell two same-named definitions apart and misses specializations; preferdefinitionorspecializeswhen you hold the element.
For a single usage the same questions are
usage.metadata_definition is tag(direct) andspecializes()(transitive); this function is the bulk form.declared_types_of()on a metadata usage returns[metadata_definition], the same element;all_types_of()is not the per-usage form ofdefinition: it returns the whole implicit type set (MetadataItem,Metaobject, … down toBase::Anything), a strict superset of{metadata_definition}.library_elementsselects which library usages are returned (seeLibraryElements; the document half of its meaning is qualified below). It is tested against each usage, not against itsmetadata_definition: a@Tagusage on an ordinary part is returned underNONEeven when theTagdefinition lives in alibrary package; only usages that themselves lie in a library package are dropped.Unlike the model-scanning lookups, this one walks containment from
scopeand has no model to consult, soNONEandWORKSPACEexclude environment usages only in documents of tierDocumentTier.StandardLibrary; usages in a third-party environment document (tierProject) are kept under every value. Since containment never crosses documents, this matters only whenscopeitself lies in an environment document – and then anindexbuilt underNONEorWORKSPACEnever held those usages, so passALLon both sides.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, library_elements: syside.query.LibraryElements = LibraryElements.WORKSPACE, index: syside.query.TypeIndex | None = None) list[syside.Relationship]
Return every relationship of type
relationship_typethatlibrary_elementscovers.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. Both conditions must hold: a relationship is returned only when it is an instance ofrelationship_typeand not an instance ofexclude_subtypes_of(orexclude_subtypes_of is None).library_elementsselects which documents are scanned and which library relationships within them are returned (seeLibraryElements); it is tested against the relationship itself, not against its related elements.With a
TypeIndexthis unions the matching exact-type buckets; without one it is a singlemodel.nodesscan, linear in the scanned documents’ 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).
- find_connectors_of(model: syside.Model, element: syside.Feature) list[syside.ConnectorAsUsage]
- find_connectors_of(model: syside.Model, element: syside.Feature, *, kind: type[syside.query._ConnectorT]) list[syside.query._ConnectorT]
Find every connector one of whose ends attaches to
element.Every document of the user model is scanned, so a connector in another document that attaches to
element(package B { connect A::x to A::y; }in a second file) is returned. The cost is linear in the model’s size; the result is inmodel.nodesorder. Standard-library connectors are outside the user model and are never returned. Withoutkindthis covers the whole connector family (connectconnections,bindbindings,flowtransfers, and successions); passkindto keep one branch of it, e.g.kind=syside.BindingConnectorAsUsage, and the result is typed accordingly. Subtypes ofkindare included, sokind=syside.FlowUsagealso matchesSuccessionFlowUsage; drop them afterwards with an exacttype(c) istest if only the base kind is wanted. An end attaches to the feature it references and, when that feature is a chain, to every link of the chain:connect a.pa to b.pbis returned for the partsa/band for the portspa/pbalike. This is broader than KerML’srelatedFeature, which names the end features themselves (here the two chains), not their links. Use this for “everything attached toelement”; usefind_connectors_from()/find_connectors_to()when the source/target split matters: for a flow or succession that split is the model’s direction, and merging the two sides here loses it.
- find_connectors_to(model: syside.Model, element: syside.Feature) list[syside.ConnectorAsUsage]
- find_connectors_to(model: syside.Model, element: syside.Feature, *, kind: type[syside.query._ConnectorT]) list[syside.query._ConnectorT]
Find the connectors with
elementon their target side.Every document of the user model is scanned (the same scope as
find_connectors_of()), at a cost linear in the model’s size; the result is inmodel.nodesorder.kindrestricts the result to one connector kind, subtypes included, as forfind_connectors_of(). What the target side means depends on the connector kind: for aflowit is the destination of the payload and for a succession the successor, which is real model semantics.connectconnections andbindbindings are not directed, so theretoreflects only the order the ends were declared (connect a to bandconnect b to amean the same connection, andbind x = yasserts a symmetric equality). A chained end attaches to every link of its chain (seefind_connectors_of()). For every connector touchingelementregardless of side, usefind_connectors_of().
- find_connectors_from(model: syside.Model, element: syside.Feature) list[syside.ConnectorAsUsage]
- find_connectors_from(model: syside.Model, element: syside.Feature, *, kind: type[syside.query._ConnectorT]) list[syside.query._ConnectorT]
Find the connectors with
elementon their source side.Every document of the user model is scanned (the same scope as
find_connectors_of()), at a cost linear in the model’s size; the result is inmodel.nodesorder.kindrestricts the result to one connector kind, subtypes included, as forfind_connectors_of(). What the source side means depends on the connector kind: the origin of aflow’s payload, a succession’s predecessor, or (forconnectconnections andbindbindings, which are not directed) merely the first-declared end; seefind_connectors_to()for the same caveat andfind_connectors_of()for the side-independent set. A chained end attaches to every link of its chain (seefind_connectors_of()).
- inherited_features(type_: syside.Type) list[syside.Feature]
Return the core
Type.inherited_featuresview, linear in its size.Not a subset of
features_of(): this view lists what the supertypes contribute regardless of visibility intype_, so it still contains every feature that one oftype_’s own features redefines – whichfeatures_of(), listing visible members, correctly omits. To enumerate the visible non-owned features, subtracttype_’s own features fromfeatures_of()instead of calling this.
- 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 multiplicity bounds
featureitself declares, orNone.Declared only, no resolution:
Nonemeansfeaturedeclares no multiplicity (or declares one whose bounds the core has not computed), not that the effective multiplicity is absent. In SysML a feature with no declared multiplicity defaults to1..1, and a redefining feature takes the redefined feature’s multiplicity; neither default is applied here, so always branch onNonebefore reading.lower/.upper. Both returned bounds are inclusive (an unbounded*upper bound isUNBOUNDED).
- generalization_names(type_: syside.Type) list[str]
Return the rendered qualified names of the direct heritage targets.
A target with no qualified name is 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, directly or indirectly.True exactly when
candidate_supertypeis one oftype_’s heritage targets, or one of their heritage targets, and so on: the same walk assupertypes(), so it also crosses conjugation.specializes(cp, PD)isTrueforport cp : ~PDalthough KerML has no specialization from~PDtoPD, andcp’sPDfeatures run in the opposite direction. To test KerML specialization alone, check membership ingeneralizations(type_, transitive=True, exclude=syside.Conjugation).
- superclassifiers(type_: syside.Type) list[syside.Classifier]
Return the classifiers
type_directly subclassifies (KerML superclassifiers), linear in their number.Subclassification only: the
:>between classifiers. A feature (anypart/attribute/port/… usage) specializes through subsetting, redefinition, and typing instead, and KerML allows only a classifier as a subclassifier, so for a feature this is always[]; seesubsets(),redefines(), anddeclared_types_of()for those, orsupertypes()for everything inherited from, directly or indirectly, through every heritage kind.
- subject_of(element: syside.query._CaseLike) syside.Usage | None
Return the subject parameter in effect for
element, constant time.Reads the core
subject_parameteraccessor, present on requirement and case usages/definitions (and their subtypes). SysML gives these types exactly one subject, inherited when not declared (the SysMLderive...SubjectParameterconstraints of requirement and case definitions and usages all read the KerMLfeatureMembership, which includes inherited memberships): an element with nosubjectof its own yields the inherited standard-library parameter (e.g.Requirements::RequirementCheck::subj), notNone. To ask whetherelementdeclares a subject itself, usedeclared_subject_of().Noneis only the core accessor’s miss case and does not occur for a well-formed model.
- declared_subject_of(element: syside.query._CaseLike) syside.Usage | None
Return the
subjectelementdeclares itself, orNone, constant time.Nonemeanselementwrites nosubjectin its own body, so its effective subject is inherited (seesubject_of(), which returns that inherited parameter). A declared subject is also the effective one, since SysML has it redefine every inherited subject parameter.
- subsets(feature: syside.Feature) list[syside.Feature]
Return the features
featuresubsets, linear in the number of subsetted features.Follows subsetting heritage including its subtypes: KerML defines redefinition as a kind of subsetting, so a redefined feature appears here as well as in
redefines(); unioning the two counts the redefined feature twice.
- subclassifiers(model: syside.Model, type_: syside.Type) list[syside.Classifier]
Return the classifiers that directly subclassify
type_(KerML subclassifiers).The inverse of subclassification only (the inverse counterpart of
superclassifiers(), not ofsupertypes()): a feature that subsets, redefines, or is typed bytype_is not returned.Linear in model size: the core exposes no inverse index, so this scans the model’s subclassification relationships via
specializations().
- supertypes(type_: syside.Type) list[syside.Type]
Return every type
type_inherits from, directly or indirectly, nearest first.These are
type_’s direct and indirect KerML supertypes (every specialization kind, not only:>between classifiers) plus the types reached by crossing a conjugation. KerML does not make a conjugated type’s original a supertype of it, but this walk includes it: forport cp : ~PD, the result ofsupertypes(cp)containsPDeven though the only edge from~PDtoPDis aConjugation, and the features inherited through it have their directions reversed. Passexclude=syside.Conjugationtogeneralizations()to stop at conjugations.Each type appears once, in the order the walk first reaches it: the direct heritage targets, then theirs, and so on.
Base::Anythingis usually last, but a type that names it as a direct heritage target (part def C :> Base::Anything, Deep;) reaches it first. That istype_’s heritage targets, and their heritage targets, and so on until no new type is reached (the transitive closure of the heritage relationship). Heritage covers every specialization kind (subclassification, feature typing, subsetting, and redefinition) and also conjugation, so for a feature the result includes the features it subsets or redefines (a KerMLFeatureis aType, e.g.Base::things), not only classifiers.For example, given the SysML:
part def Wheel; part wheel : Wheel;
the result includes
Wheeland everything it inherits, plus the library featureswheelsubsets:syside.query.supertypes(wheel) # [Wheel, Parts::parts, Parts::Part, Items::items, Items::Item, ..., # Base::things, Base::Anything]
Because it follows every kind, this is a larger set than repeating
superclassifiers()until nothing new is reached, since that function follows subclassification (:>between classifiers) alone; usesyside.query.generalizations()withvia=to follow one specific kind.
- 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, meaning 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. That is 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.
Enumerations
- class LibraryElements
Which documents, and which library elements within them, the
find_*lookups that take it and the index builders cover (the lookups are listed in thesyside.query._functionsmodule docstring).NONE– the documentsWORKSPACEscans (environment documents are not scanned, exactly as underWORKSPACE, with the samefind_metadata_usages()exception), minus every element withis_library_elementset, including the workspace’s ownlibrary packagenamespaces and their contents – alibrary packageis itself a library element.WORKSPACE(the default everywhere) – every document the model itself loaded (model.documents), including its ownlibrary packagenamespaces. Documents supplied through the model’senvironmentare not scanned: the SysML/KerML standard libraries, and any third-party documents added to the environment (e.g. viaModel.to_environment) alike. Environment membership is the discriminator, notDocumentTier– with one exception:find_metadata_usages()walks containment from ascopeelement and has no model to consult, so it can only recognise the standard library byDocumentTier.StandardLibrary; see its docstring.ALL– workspace and every environment document both.
The value is tested against each element a lookup finds or a builder indexes, never against the elements it reaches through references (see the
syside.query._functionsmodule docstring). A lookup and the index backing it must use the same value; a mismatch is a caller error (see the module docstring’s contract).NONE¶Which documents, and which library elements within them, the
find_*lookups that take it and the index builders cover (the lookups are listed in thesyside.query._functionsmodule docstring).NONE– the documentsWORKSPACEscans (environment documents are not scanned, exactly as underWORKSPACE, with the samefind_metadata_usages()exception), minus every element withis_library_elementset, including the workspace’s ownlibrary packagenamespaces and their contents – alibrary packageis itself a library element.WORKSPACE(the default everywhere) – every document the model itself loaded (model.documents), including its ownlibrary packagenamespaces. Documents supplied through the model’senvironmentare not scanned: the SysML/KerML standard libraries, and any third-party documents added to the environment (e.g. viaModel.to_environment) alike. Environment membership is the discriminator, notDocumentTier– with one exception:find_metadata_usages()walks containment from ascopeelement and has no model to consult, so it can only recognise the standard library byDocumentTier.StandardLibrary; see its docstring.ALL– workspace and every environment document both.
The value is tested against each element a lookup finds or a builder indexes, never against the elements it reaches through references (see the
syside.query._functionsmodule docstring). A lookup and the index backing it must use the same value; a mismatch is a caller error (see the module docstring’s contract).WORKSPACE¶Which documents, and which library elements within them, the
find_*lookups that take it and the index builders cover (the lookups are listed in thesyside.query._functionsmodule docstring).NONE– the documentsWORKSPACEscans (environment documents are not scanned, exactly as underWORKSPACE, with the samefind_metadata_usages()exception), minus every element withis_library_elementset, including the workspace’s ownlibrary packagenamespaces and their contents – alibrary packageis itself a library element.WORKSPACE(the default everywhere) – every document the model itself loaded (model.documents), including its ownlibrary packagenamespaces. Documents supplied through the model’senvironmentare not scanned: the SysML/KerML standard libraries, and any third-party documents added to the environment (e.g. viaModel.to_environment) alike. Environment membership is the discriminator, notDocumentTier– with one exception:find_metadata_usages()walks containment from ascopeelement and has no model to consult, so it can only recognise the standard library byDocumentTier.StandardLibrary; see its docstring.ALL– workspace and every environment document both.
The value is tested against each element a lookup finds or a builder indexes, never against the elements it reaches through references (see the
syside.query._functionsmodule docstring). A lookup and the index backing it must use the same value; a mismatch is a caller error (see the module docstring’s contract).ALL¶Which documents, and which library elements within them, the
find_*lookups that take it and the index builders cover (the lookups are listed in thesyside.query._functionsmodule docstring).NONE– the documentsWORKSPACEscans (environment documents are not scanned, exactly as underWORKSPACE, with the samefind_metadata_usages()exception), minus every element withis_library_elementset, including the workspace’s ownlibrary packagenamespaces and their contents – alibrary packageis itself a library element.WORKSPACE(the default everywhere) – every document the model itself loaded (model.documents), including its ownlibrary packagenamespaces. Documents supplied through the model’senvironmentare not scanned: the SysML/KerML standard libraries, and any third-party documents added to the environment (e.g. viaModel.to_environment) alike. Environment membership is the discriminator, notDocumentTier– with one exception:find_metadata_usages()walks containment from ascopeelement and has no model to consult, so it can only recognise the standard library byDocumentTier.StandardLibrary; see its docstring.ALL– workspace and every environment document both.
The value is tested against each element a lookup finds or a builder indexes, never against the elements it reaches through references (see the
syside.query._functionsmodule docstring). A lookup and the index backing it must use the same value; a mismatch is a caller error (see the module docstring’s contract).Used by: