Skip to content

Element

The element module presented here provides a comprehensive framework for representing and manipulating a hierarchy of elements, designed to facilitate the creation and management of complex data models within a software application. It includes a rich set of functions to handle relationships and properties among elements, such as ownership and association management, type checking, element searching, and more. The module also defines an Element class, which serves as the base class for all elements within the hierarchy, and it is used to instantiate and define new elements with unique identities, owned elements, and various other attributes.

Key Functionalities:

  • Identities and Types: Utilize id_of and type_of to acquire the unique identifier and type of an element, respectively.
  • Ownership Management: Employ functions like owned_elements_of, add_owned_element_to, remove_owned_element_from to manage which elements are owned by others.
  • Hierarchy Navigation: Use ancestors_of, descendants_of, is_ancestor_of, is_descendant_of to traverse and verify relationships in the hierarchy.
  • Associations Management: Leverage add_association_to, remove_association_from, associations_of to manage named associations between elements.
  • Search and Filter: Functions like find_owned_elements_of, find_ancestors_of, find_descendants_of to find elements based on specified conditions.
  • Redefinition and Specialization: The redefine and specialize functions are provided to create specialized or redefined versions of existing elements.
  • Attribute Handling: set_attribute, attributes_of allow for setting and accessing custom attributes on elements.
  • Utility Functions: Various helper functions such as is_type, is_subtype, is_element, name_of, qualified_name_of support common operations needed for working with elements.

The Element class encapsulates common functionality needed for all elements in the model, including the initialization and management of class variables that track owned elements, associations, and other class-specific information. It also defines special class methods for defining, redefining, and creating instances of element classes.

This module offers a robust infrastructure for modeling relationships and hierarchies within complex systems and serves as a foundational tool for developers handling structured data within object-oriented paradigms.

ElementType = typing.TypeVar('ElementType', bound=typing.Union[type['Element'], 'Element']) module-attribute

Element

Bases: Generic[T]

A generic base class for modeling elements within a custom framework. This class serves as a template for defining various model elements by providing mechanisms to handle attributes, ownership, associations, and element specialization through subclassing. It implements a registry for all elements, associates unique identifiers, and handles element creation, definition, redefinition, and ownership. When a subclass is created, it automatically registers itself, allocates a new ID, and sets up its model, owner, and type information. Subclasses can further define or redefine their structure by providing additional attributes and owned elements via the __define__ or __redefine__ methods. The __create__ and __create_owned_elements__ methods are responsible for instance creation, and ensuring that all elements within the namespace of the created element are properly initialized. The constructor 'new' is overridden to integrate this creation process and to manage the initialization flow of the newly created elements.

Attributes:

Name Type Description
__all_elements__ dict[int, Element]

A class attribute that acts as a registry of all c reated element instances, mapped by their unique IDs.

__id__ int

A class-level unique identifier for elements.

__owned_elements__ list[int]

A list of IDs representing elements owned by this class.

__redefined_element__ Optional[Element]

An element that this class may redefine.

__associations__ dict[str, int]

A dictionary mapping association names to their respective IDs.

__owner__ Optional[int]

The ID of the owner element, if any.

__type__ Type[Element]

The type of the class, typically set to the subclass itself.

__model__ Optional[int]

The ID of the model element, if any.

__init__ Callable[..., None]

The initialization method for the element, with a default noop implemmentation.

model Optional[Element]

The model element associated with an instance of this class.

Class Methods
__init_subclass__(cls, **kwargs

Automatically called when a subclass is defined, used to initialize class-level attributes nd register the new element.

__define__(cls, **kwargs

Handles the definition of new elements by associating owned_elements and configuring the amespace.

__redefine__(cls, **kwargs

Designed to be overridden in subclasses to handle element redefinition.

__create__(cls, **kwargs) -> 'Element'

Responsible for creating a new instance of the class, including initializing ownership and ll elements within its namespace.

__new__(cls **kwargs) -> 'Element'

type['Element'], args: typing.Any, *kwargs) -> Union['Element', Callable[[], 'Element']]: Overrides the default object instantiation process to integrate element creation and nitialization management.

__create_owned_elements__(cls, (self, all_elements)

dict[int, 'Element']): Instantiates owned elements and ensures they are added to the current element's namespace.

Source code in stateforward/model/element.py
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
class Element(typing.Generic[T]):
    """
    A generic base class for modeling elements within a custom framework.
    This class serves as a template for defining various model elements by providing mechanisms to handle
    attributes, ownership, associations, and element specialization through subclassing. It implements a
    registry for all elements, associates unique identifiers, and handles element creation, definition,
    redefinition, and ownership.
    When a subclass is created, it automatically registers itself, allocates a new ID, and sets up its
    model, owner, and type information. Subclasses can further define or redefine their structure by
    providing additional attributes and owned elements via the `__define__` or `__redefine__` methods.
    The `__create__` and `__create_owned_elements__` methods are responsible for instance creation,
    and ensuring that all elements within the namespace of the created element are properly initialized.
    The constructor '__new__' is overridden to integrate this creation process and to manage the
    initialization flow of the newly created elements.

    Attributes:
        __all_elements__ (dict[int, 'Element']):
             A class attribute that acts as a registry of all
            c        reated element instances, mapped by their unique IDs.
        __id__ (int):
             A class-level unique identifier for elements.
        __owned_elements__ (list[int]):
             A list of IDs representing elements owned by this class.
        __redefined_element__ (Optional['Element']):
             An element that this class may redefine.
        __associations__ (dict[str, int]):
             A dictionary mapping association names to their respective IDs.
        __owner__ (Optional[int]):
             The ID of the owner element, if any.
        __type__ (Type['Element']):
             The type of the class, typically set to the subclass itself.
        __model__ (Optional[int]):
             The ID of the model element, if any.
        __init__ (Callable[..., None]):
             The initialization method for the element, with a default noop
            implemmentation.
        model (Optional['Element']):
             The model element associated with an instance of this class.
        Class Methods:
        __init_subclass__(cls, **kwargs):
            Automatically called when a subclass is defined, used to initialize class-level attributes
            nd register the new element.
        __define__(cls, **kwargs):
            Handles the definition of new elements by associating owned_elements and configuring the
            amespace.
        __redefine__(cls, **kwargs):
            Designed to be overridden in subclasses to handle element redefinition.
        __create__(cls, **kwargs) -> 'Element':
            Responsible for creating a new instance of the class, including initializing ownership and
            ll elements within its namespace.
        __new__(cls:
             type['Element'], *args: typing.Any, **kwargs) -> Union['Element', Callable[[], 'Element']]:
            Overrides the default object instantiation process to integrate element creation and
            nitialization management.
        __create_owned_elements__(cls, self, all_elements:
             dict[int, 'Element']):
            Instantiates owned elements and ensures they are added to the current element's namespace.

    """

    __all_elements__: dict[int, "ElementType"] = {}
    __id__: typing.ClassVar[int] = 0
    __owned_elements__: list[int] = None
    __redefined_element__: typing.Optional["Element"] = None
    __associations__: dict[str, int] = None
    __owner__: typing.Optional[int] = None
    __type__: typing.ClassVar[type["Element"]] = None
    __model__: typing.Optional[int] = None
    __init__: typing.Callable[P, None] = lambda *args, **kwargs: None
    model: typing.Optional["Element"] = None

    def __init_subclass__(cls, **kwargs):
        """
        Initializes a subclass.
        This method is called when a new subclass of the `Element` base class is created, and it
        performs essential setup for the new subclass, including assigning unique identifiers,
        establishing element relationships, and initializing annotations.

        Attributes for the subclass, such as owned elements, model associations, and type definitions, are

        Args:
            **kwargs:
                 Arbitrary keyword arguments. These can include:
            name (str):
                 The name to assign to the subclass. If not provided, the default name of the
                subclass will be used.
            redefined_element (Element):
                 An optional argument specifying an element that the subclass
                is redefining. If not provided, it is assumed this is an original definition rather than
                a redefinition.

        Raises:
            TypeError:
                 If the subclass does not properly specify the base type for an `Element`.

        """
        cls.__owned_elements__ = []
        cls.__id__ = Element.__id__ = Element.__id__ + 1
        cls.__model__ = cls.__id__
        cls.__all_elements__[cls.__id__] = cls
        cls.__associations__ = {}
        cls.__type__ = cls
        cls.__owner__ = None
        cls.__name__ = kwargs.pop("name", cls.__name__)
        redefined_element = cls.__redefined_element__ = kwargs.pop(
            "redefined_element", None
        )
        if is_subtype(cls.__base__, Element):
            cls.__annotations__.update(cls.__base__.__annotations__)
            specialize(cls.__base__, cls)
        if redefined_element is None:
            cls.__define__(**kwargs)
        else:
            cls.__redefine__(**kwargs)

    @classmethod
    def __define__(cls, **kwargs):
        """
        Class method to define extra owned elements and attributes for an Element class based on provided keyword arguments.
        This method is used to define additional owned elements and set attributes for an Element class by processing
        keyword arguments passed to the method. Each owned element is added to the class through the
        `add_owned_element_to` function. Subsequently, the namespace is sorted to distinguish owned elements,
        orphans, and attributes. Attributes are set using the `set_attribute` function according to their respective sorted order.

        Args:
            **kwargs:
                 Arbitrary keyword arguments where the key is the attribute name or owned element, and the value is its corresponding value or owned element instance.
                The 'owned_elements' keyword argument is expected to be an iterable of owned elements that are to be added to this class.
                Any other keyword argument corresponds to an attribute or owned element of the class that will be set or added respectively based on the type of the value provided. Attributes are set directly, whereas owned elements are added using pre-defined mechanisms while respecting ownership rules.
                Sorting of the namespace involves determining the owned elements, orphan elements (elements without an owner), and attributes that need to be set on the class. This is performed by 'sort_namespace' nested function.

        """
        for owned_element in kwargs.get("owned_elements", ()):
            add_owned_element_to(cls, owned_element)

        def sort_namespace(namespace: dict[str, typing.Any]) -> dict[str, typing.Any]:
            """
            Sorts the provided namespace dictionary into a consistently ordered mapping.
            The function segregates keys based on whether they are owned, orphaned, or regular attributes.
            Elements in the namespace which are considered 'owned' are those where an owner is identifiable.
            Orphaned elements have no identifiable owner, and attributes include all other elements.
            The sorting is done based on a calculated identity for each item.

            Args:
                namespace (dict[str, typing.Any]):
                     A dictionary representing the namespace to be sorted.

            Returns:
                dict[str, typing.Any]:
                     A dictionary with keys sorted into orphans, owned, and attributes in that order.
                    The resultant dictionary contains all elements from orphans first, followed by owned elements, and then the regular attributes, each sorted by their calculated identities.

            """
            owned = {}
            orphans = {}
            attributes = {}
            for key, item in namespace.items():
                if key not in Element.__dict__:
                    item_id = id_of(item)
                    if is_element(item):
                        if owner_of(item) is None:
                            orphans[key] = (item_id, item)
                        else:
                            owned[key] = (item_id, item)
                    else:
                        attributes[key] = (item_id, item)

            return {**orphans, **owned, **attributes}

        sorted_namespace = sort_namespace(
            {
                **cls.__dict__,
                **dict(
                    (name, kwargs.get(name, getattr(cls, name, None)))
                    for name in cls.__annotations__
                ),
            },
        )
        for name, (item_id, item) in sorted_namespace.items():
            set_attribute(cls, name, item)

    @classmethod
    def __redefine__(cls, **kwargs):
        """
        A class method to redefine properties of the class based on provided keyword arguments.
        This method allows dynamic modification of class attributes, altering the class' behaviour
        at runtime. The kwargs dictionary should contain attribute names and their new values.

        Args:
            **kwargs:
                 Variable length keyword arguments. Each key corresponds to an attribute
                name of the class, and each value is the new value to set for that
                attribute.

        Returns:
            None:
                 This method does not return anything.

        """
        for key, item in kwargs.items():
            set_attribute(cls, key, item)
        pass

    @classmethod
    def __create__(cls, **kwargs) -> "Element":
        """
        Creates an instance of the Element class with provided keyword arguments.
        This method populates the new object's attributes, creating a namespace for the
        core in the element. The `owner` and `all_elements` attributes are set from keyword
        arguments if provided, otherwise, default values are assumed. Any elements owned by
        the instance are initialized in this method.

        Args:
            **kwargs:
                 Variable length keyword arguments.
            - 'owner' (optional):
                 The owner of the element. Defaults to None.
            - 'id' (optional):
                 The identifier for the element. Defaults to the object id.
            - 'all_elements' (optional):
                 A dictionary of all element instances keyed by their ids.
                Defaults to a dictionary with the current class's id_of as the key and `self` as the value.

        Returns:
            Element:
                 A new instance of the Element class or its subclass with initialized attributes.

        Raises:
            TypeError:
                 If super().__new__(cls) does not return an instance of cls.

        """
        self = super().__new__(cls)
        owner = self.__owner__ = kwargs.pop("owner", None)
        self.__owned_elements__ = []
        self.__id__ = kwargs.pop("id", id(self))
        self.model = typing.cast(Element, owner).model if owner is not None else self
        all_elements = self.__all_elements__ = kwargs.pop(
            "all_elements", {id_of(cls): self}
        )  # create a namespace for the core in the element
        cls.__create_owned_elements__(self, all_elements)
        return self

    @staticmethod
    def __new__(
        cls: type["Element"], *args: typing.Any, **kwargs
    ) -> typing.Union["Element", typing.Callable[[], "Element"]]:
        """
        Creates a new instance of the Element class or returns a callable that creates an instance when invoked.
        This static method is a custom constructor for creating instances of the given `Element` class or its subclasses. It uses the private `__create__` method to construct an instance with the provided keyword arguments. If the created instance does not have an owner, it iterates through all associated elements to set their attributes based on existing associations and initializes them with the corresponding kwargs.
        For the root element of the element tree, this method finalizes its creation and returns the new instance directly. If the instance being created is not the root element, this method returns a lambda function that, when called, returns the created instance without invoking the `__init__` method.

        Args:
            cls (type[Element]):
                 The class of the element to create an instance of.
            *args (typing.Any):
                 Variable length argument list, currently not utilized in the method body.
            **kwargs (typing.Any):
                 Variable keyword arguments used for initializing the instance attributes.

        Returns:
            typing.Union[Element, typing.Callable[[], Element]]:
                 An instance of the `Element` class if it is the root element, or a lambda function that returns the new instance for non-root elements.

        """
        self = cls.__create__(**kwargs)
        if owner_of(self) is None:
            for element in reversed(self.__all_elements__.values()):
                for name, value in associations_of(element).items():
                    value = self.__all_elements__[id_of(type(value))]
                    setattr(element, str(name), value)
                if element is not self:
                    element.__init__(**kwargs.pop(qualified_name_of(element), {}))
            # this is the root element of the element, so we can start initializing
            return self
        # a hack to prevent __init__ from being called
        return lambda _self=self: _self

    @classmethod
    def __create_owned_elements__(cls, self, all_elements: dict[int, "Element"]):
        """
        Class method to instantiate and associate owned elements with a class instance.
        This method loops through the class-level collection of owned element IDs, retrieves the corresponding element from a shared class-level dictionary, instantiates it by preventing the direct call of its constructor, and finally stores the instance in a provided dictionary. This method modifies the provided dictionary in place by adding the new instances and also appends the element IDs to the instance specific owned elements list.

        Args:
            cls (type):
                 The class from which the method is called.
            self (object):
                 The instance of the class owning the new elements.
            all_elements (dict[int, 'Element']):
                 A dictionary mapping element IDs to their corresponding 'Element' instances.

        Notes:

        """
        for owned_element_id in cls.__owned_elements__:
            owned_element = cls.__all_elements__[owned_element_id]
            instance = owned_element(
                owner=self,
                all_elements=all_elements,
            )()  # using the extra function call to prevent __init__ from being called
            all_elements[owned_element_id] = instance
            self.__owned_elements__.append(owned_element_id)

__create__(**kwargs) classmethod

Creates an instance of the Element class with provided keyword arguments. This method populates the new object's attributes, creating a namespace for the core in the element. The owner and all_elements attributes are set from keyword arguments if provided, otherwise, default values are assumed. Any elements owned by the instance are initialized in this method.

Parameters:

Name Type Description Default
**kwargs

Variable length keyword arguments.

{}
- 'owner' (optional

The owner of the element. Defaults to None.

required
- 'id' (optional

The identifier for the element. Defaults to the object id.

required
- 'all_elements' (optional

A dictionary of all element instances keyed by their ids. Defaults to a dictionary with the current class's id_of as the key and self as the value.

required

Returns:

Name Type Description
Element Element

A new instance of the Element class or its subclass with initialized attributes.

Raises:

Type Description
TypeError

If super().new(cls) does not return an instance of cls.

Source code in stateforward/model/element.py
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
@classmethod
def __create__(cls, **kwargs) -> "Element":
    """
    Creates an instance of the Element class with provided keyword arguments.
    This method populates the new object's attributes, creating a namespace for the
    core in the element. The `owner` and `all_elements` attributes are set from keyword
    arguments if provided, otherwise, default values are assumed. Any elements owned by
    the instance are initialized in this method.

    Args:
        **kwargs:
             Variable length keyword arguments.
        - 'owner' (optional):
             The owner of the element. Defaults to None.
        - 'id' (optional):
             The identifier for the element. Defaults to the object id.
        - 'all_elements' (optional):
             A dictionary of all element instances keyed by their ids.
            Defaults to a dictionary with the current class's id_of as the key and `self` as the value.

    Returns:
        Element:
             A new instance of the Element class or its subclass with initialized attributes.

    Raises:
        TypeError:
             If super().__new__(cls) does not return an instance of cls.

    """
    self = super().__new__(cls)
    owner = self.__owner__ = kwargs.pop("owner", None)
    self.__owned_elements__ = []
    self.__id__ = kwargs.pop("id", id(self))
    self.model = typing.cast(Element, owner).model if owner is not None else self
    all_elements = self.__all_elements__ = kwargs.pop(
        "all_elements", {id_of(cls): self}
    )  # create a namespace for the core in the element
    cls.__create_owned_elements__(self, all_elements)
    return self

__create_owned_elements__(self, all_elements) classmethod

Class method to instantiate and associate owned elements with a class instance. This method loops through the class-level collection of owned element IDs, retrieves the corresponding element from a shared class-level dictionary, instantiates it by preventing the direct call of its constructor, and finally stores the instance in a provided dictionary. This method modifies the provided dictionary in place by adding the new instances and also appends the element IDs to the instance specific owned elements list.

Parameters:

Name Type Description Default
cls type

The class from which the method is called.

required
self object

The instance of the class owning the new elements.

required
all_elements dict[int, Element]

A dictionary mapping element IDs to their corresponding 'Element' instances.

required

Notes:

Source code in stateforward/model/element.py
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
@classmethod
def __create_owned_elements__(cls, self, all_elements: dict[int, "Element"]):
    """
    Class method to instantiate and associate owned elements with a class instance.
    This method loops through the class-level collection of owned element IDs, retrieves the corresponding element from a shared class-level dictionary, instantiates it by preventing the direct call of its constructor, and finally stores the instance in a provided dictionary. This method modifies the provided dictionary in place by adding the new instances and also appends the element IDs to the instance specific owned elements list.

    Args:
        cls (type):
             The class from which the method is called.
        self (object):
             The instance of the class owning the new elements.
        all_elements (dict[int, 'Element']):
             A dictionary mapping element IDs to their corresponding 'Element' instances.

    Notes:

    """
    for owned_element_id in cls.__owned_elements__:
        owned_element = cls.__all_elements__[owned_element_id]
        instance = owned_element(
            owner=self,
            all_elements=all_elements,
        )()  # using the extra function call to prevent __init__ from being called
        all_elements[owned_element_id] = instance
        self.__owned_elements__.append(owned_element_id)

__define__(**kwargs) classmethod

Class method to define extra owned elements and attributes for an Element class based on provided keyword arguments. This method is used to define additional owned elements and set attributes for an Element class by processing keyword arguments passed to the method. Each owned element is added to the class through the add_owned_element_to function. Subsequently, the namespace is sorted to distinguish owned elements, orphans, and attributes. Attributes are set using the set_attribute function according to their respective sorted order.

Parameters:

Name Type Description Default
**kwargs

Arbitrary keyword arguments where the key is the attribute name or owned element, and the value is its corresponding value or owned element instance. The 'owned_elements' keyword argument is expected to be an iterable of owned elements that are to be added to this class. Any other keyword argument corresponds to an attribute or owned element of the class that will be set or added respectively based on the type of the value provided. Attributes are set directly, whereas owned elements are added using pre-defined mechanisms while respecting ownership rules. Sorting of the namespace involves determining the owned elements, orphan elements (elements without an owner), and attributes that need to be set on the class. This is performed by 'sort_namespace' nested function.

{}
Source code in stateforward/model/element.py
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
@classmethod
def __define__(cls, **kwargs):
    """
    Class method to define extra owned elements and attributes for an Element class based on provided keyword arguments.
    This method is used to define additional owned elements and set attributes for an Element class by processing
    keyword arguments passed to the method. Each owned element is added to the class through the
    `add_owned_element_to` function. Subsequently, the namespace is sorted to distinguish owned elements,
    orphans, and attributes. Attributes are set using the `set_attribute` function according to their respective sorted order.

    Args:
        **kwargs:
             Arbitrary keyword arguments where the key is the attribute name or owned element, and the value is its corresponding value or owned element instance.
            The 'owned_elements' keyword argument is expected to be an iterable of owned elements that are to be added to this class.
            Any other keyword argument corresponds to an attribute or owned element of the class that will be set or added respectively based on the type of the value provided. Attributes are set directly, whereas owned elements are added using pre-defined mechanisms while respecting ownership rules.
            Sorting of the namespace involves determining the owned elements, orphan elements (elements without an owner), and attributes that need to be set on the class. This is performed by 'sort_namespace' nested function.

    """
    for owned_element in kwargs.get("owned_elements", ()):
        add_owned_element_to(cls, owned_element)

    def sort_namespace(namespace: dict[str, typing.Any]) -> dict[str, typing.Any]:
        """
        Sorts the provided namespace dictionary into a consistently ordered mapping.
        The function segregates keys based on whether they are owned, orphaned, or regular attributes.
        Elements in the namespace which are considered 'owned' are those where an owner is identifiable.
        Orphaned elements have no identifiable owner, and attributes include all other elements.
        The sorting is done based on a calculated identity for each item.

        Args:
            namespace (dict[str, typing.Any]):
                 A dictionary representing the namespace to be sorted.

        Returns:
            dict[str, typing.Any]:
                 A dictionary with keys sorted into orphans, owned, and attributes in that order.
                The resultant dictionary contains all elements from orphans first, followed by owned elements, and then the regular attributes, each sorted by their calculated identities.

        """
        owned = {}
        orphans = {}
        attributes = {}
        for key, item in namespace.items():
            if key not in Element.__dict__:
                item_id = id_of(item)
                if is_element(item):
                    if owner_of(item) is None:
                        orphans[key] = (item_id, item)
                    else:
                        owned[key] = (item_id, item)
                else:
                    attributes[key] = (item_id, item)

        return {**orphans, **owned, **attributes}

    sorted_namespace = sort_namespace(
        {
            **cls.__dict__,
            **dict(
                (name, kwargs.get(name, getattr(cls, name, None)))
                for name in cls.__annotations__
            ),
        },
    )
    for name, (item_id, item) in sorted_namespace.items():
        set_attribute(cls, name, item)

__init_subclass__(**kwargs)

Initializes a subclass. This method is called when a new subclass of the Element base class is created, and it performs essential setup for the new subclass, including assigning unique identifiers, establishing element relationships, and initializing annotations.

Attributes for the subclass, such as owned elements, model associations, and type definitions, are

Parameters:

Name Type Description Default
**kwargs

Arbitrary keyword arguments. These can include:

{}
name str

The name to assign to the subclass. If not provided, the default name of the subclass will be used.

required
redefined_element Element

An optional argument specifying an element that the subclass is redefining. If not provided, it is assumed this is an original definition rather than a redefinition.

required

Raises:

Type Description
TypeError

If the subclass does not properly specify the base type for an Element.

Source code in stateforward/model/element.py
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
def __init_subclass__(cls, **kwargs):
    """
    Initializes a subclass.
    This method is called when a new subclass of the `Element` base class is created, and it
    performs essential setup for the new subclass, including assigning unique identifiers,
    establishing element relationships, and initializing annotations.

    Attributes for the subclass, such as owned elements, model associations, and type definitions, are

    Args:
        **kwargs:
             Arbitrary keyword arguments. These can include:
        name (str):
             The name to assign to the subclass. If not provided, the default name of the
            subclass will be used.
        redefined_element (Element):
             An optional argument specifying an element that the subclass
            is redefining. If not provided, it is assumed this is an original definition rather than
            a redefinition.

    Raises:
        TypeError:
             If the subclass does not properly specify the base type for an `Element`.

    """
    cls.__owned_elements__ = []
    cls.__id__ = Element.__id__ = Element.__id__ + 1
    cls.__model__ = cls.__id__
    cls.__all_elements__[cls.__id__] = cls
    cls.__associations__ = {}
    cls.__type__ = cls
    cls.__owner__ = None
    cls.__name__ = kwargs.pop("name", cls.__name__)
    redefined_element = cls.__redefined_element__ = kwargs.pop(
        "redefined_element", None
    )
    if is_subtype(cls.__base__, Element):
        cls.__annotations__.update(cls.__base__.__annotations__)
        specialize(cls.__base__, cls)
    if redefined_element is None:
        cls.__define__(**kwargs)
    else:
        cls.__redefine__(**kwargs)

__new__(*args, **kwargs) staticmethod

Creates a new instance of the Element class or returns a callable that creates an instance when invoked. This static method is a custom constructor for creating instances of the given Element class or its subclasses. It uses the private __create__ method to construct an instance with the provided keyword arguments. If the created instance does not have an owner, it iterates through all associated elements to set their attributes based on existing associations and initializes them with the corresponding kwargs. For the root element of the element tree, this method finalizes its creation and returns the new instance directly. If the instance being created is not the root element, this method returns a lambda function that, when called, returns the created instance without invoking the __init__ method.

Parameters:

Name Type Description Default
cls type[Element]

The class of the element to create an instance of.

required
*args Any

Variable length argument list, currently not utilized in the method body.

()
**kwargs Any

Variable keyword arguments used for initializing the instance attributes.

{}

Returns:

Type Description
Union[Element, Callable[[], Element]]

typing.Union[Element, typing.Callable[[], Element]]: An instance of the Element class if it is the root element, or a lambda function that returns the new instance for non-root elements.

Source code in stateforward/model/element.py
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
@staticmethod
def __new__(
    cls: type["Element"], *args: typing.Any, **kwargs
) -> typing.Union["Element", typing.Callable[[], "Element"]]:
    """
    Creates a new instance of the Element class or returns a callable that creates an instance when invoked.
    This static method is a custom constructor for creating instances of the given `Element` class or its subclasses. It uses the private `__create__` method to construct an instance with the provided keyword arguments. If the created instance does not have an owner, it iterates through all associated elements to set their attributes based on existing associations and initializes them with the corresponding kwargs.
    For the root element of the element tree, this method finalizes its creation and returns the new instance directly. If the instance being created is not the root element, this method returns a lambda function that, when called, returns the created instance without invoking the `__init__` method.

    Args:
        cls (type[Element]):
             The class of the element to create an instance of.
        *args (typing.Any):
             Variable length argument list, currently not utilized in the method body.
        **kwargs (typing.Any):
             Variable keyword arguments used for initializing the instance attributes.

    Returns:
        typing.Union[Element, typing.Callable[[], Element]]:
             An instance of the `Element` class if it is the root element, or a lambda function that returns the new instance for non-root elements.

    """
    self = cls.__create__(**kwargs)
    if owner_of(self) is None:
        for element in reversed(self.__all_elements__.values()):
            for name, value in associations_of(element).items():
                value = self.__all_elements__[id_of(type(value))]
                setattr(element, str(name), value)
            if element is not self:
                element.__init__(**kwargs.pop(qualified_name_of(element), {}))
        # this is the root element of the element, so we can start initializing
        return self
    # a hack to prevent __init__ from being called
    return lambda _self=self: _self

__redefine__(**kwargs) classmethod

A class method to redefine properties of the class based on provided keyword arguments. This method allows dynamic modification of class attributes, altering the class' behaviour at runtime. The kwargs dictionary should contain attribute names and their new values.

Parameters:

Name Type Description Default
**kwargs

Variable length keyword arguments. Each key corresponds to an attribute name of the class, and each value is the new value to set for that attribute.

{}

Returns:

Name Type Description
None

This method does not return anything.

Source code in stateforward/model/element.py
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
@classmethod
def __redefine__(cls, **kwargs):
    """
    A class method to redefine properties of the class based on provided keyword arguments.
    This method allows dynamic modification of class attributes, altering the class' behaviour
    at runtime. The kwargs dictionary should contain attribute names and their new values.

    Args:
        **kwargs:
             Variable length keyword arguments. Each key corresponds to an attribute
            name of the class, and each value is the new value to set for that
            attribute.

    Returns:
        None:
             This method does not return anything.

    """
    for key, item in kwargs.items():
        set_attribute(cls, key, item)
    pass

id_of(element)

Gets the unique identifier of a given element. This function retrieves a unique identifier associated with the 'element' parameter. If the 'element' has an 'id' attribute, that value is returned. Otherwise, this function falls back to Python's built-in id() function to return a unique identifier.

Parameters:

Name Type Description Default
element ElementType

The element for which the unique identifier is to be retrieved.

required

Returns:

Name Type Description
int int

The unique identifier for the 'element'. If 'id' attribute exists it is returned; otherwise, the result of id(element) is returned.

Source code in stateforward/model/element.py
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def id_of(element: ElementType) -> int:
    """
    Gets the unique identifier of a given element.
    This function retrieves a unique identifier associated with the 'element' parameter.
    If the 'element' has an '__id__' attribute, that value is returned. Otherwise, this function
    falls back to Python's built-in `id()` function to return a unique identifier.

    Args:
        element (ElementType):
             The element for which the unique identifier is to be retrieved.

    Returns:
        int:
             The unique identifier for the 'element'. If '__id__' attribute exists it is returned; otherwise, the result of `id(element)` is returned.

    """
    return getattr(element, "__id__", id(element))

type_of(element)

Determines the type of a given element. This function takes an element of any type and returns its type.

Parameters:

Name Type Description Default
element ElementType

The element for which to determine the type.

required

Returns:

Type Description
type[Element]

type[Element]: The type of the given element.

Source code in stateforward/model/element.py
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
def type_of(element: ElementType) -> type["Element"]:
    """
    Determines the type of a given element.
    This function takes an element of any type and returns its type.

    Args:
        element (ElementType):
             The element for which to determine the type.

    Returns:
        type[Element]:
             The type of the given element.

    """
    return element.__type__

owned_elements_of(element)

Generates elements owned by a given element. The function iterates over element IDs stored in the __owned_elements__ attribute of the provided element and yields the corresponding elements from the __all_elements__ mapping.

Parameters:

Name Type Description Default
element ElementType

The element whose owned elements are to be generated.

required

Returns:

Type Description
Generator[ElementType, None, None]

Generator[ElementType, None, None]: A generator that yields elements owned by the input element.

Source code in stateforward/model/element.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
def owned_elements_of(
    element: ElementType,
) -> typing.Generator[ElementType, None, None]:
    """
    Generates elements owned by a given element.
    The function iterates over element IDs stored in the `__owned_elements__` attribute of the provided element and yields the corresponding elements from the `__all_elements__` mapping.

    Args:
        element (ElementType):
             The element whose owned elements are to be generated.

    Returns:
        Generator[ElementType, None, None]:
             A generator that yields elements owned by the input element.

    """
    for owned_element_id in element.__owned_elements__:
        yield element.__all_elements__[owned_element_id]

descendants_of(element)

Generates all descendants of a given element in a hierarchy. This generator function recursively yields all the descendants of the specified element. A descendant is defined as any element that is a direct or indirect child of the given element, at any depth level in the hierarchy. Each descendant element is yielded exactly once.

Parameters:

Name Type Description Default
element ElementType

The element whose descendants are to be generated.

required

Yields:

Name Type Description
ElementType ElementType

The next descendant element in the hierarchy.

Source code in stateforward/model/element.py
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def descendants_of(element: ElementType) -> typing.Generator[ElementType, None, None]:
    """
    Generates all descendants of a given element in a hierarchy.
    This generator function recursively yields all the descendants of the specified element. A descendant is defined as any element that is a direct or indirect child of the given element, at any depth level in the hierarchy. Each descendant element is yielded exactly once.

    Args:
        element (ElementType):
             The element whose descendants are to be generated.

    Yields:
        ElementType:
             The next descendant element in the hierarchy.

    """
    for owned_element in owned_elements_of(element):
        yield owned_element
        yield from descendants_of(owned_element)

is_descendant_of(ancestor, descendant)

Determines whether a specified element is a descendant of a given ancestor element.

Parameters:

Name Type Description Default
ancestor ElementType

The element to be considered as the ancestor.

required
descendant ElementType

The element to check for being a descendant.

required

Returns:

Name Type Description
bool bool

True if the descendant is indeed a descendant of the ancestor, otherwise False.

Source code in stateforward/model/element.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def is_descendant_of(ancestor: ElementType, descendant: ElementType) -> bool:
    """
    Determines whether a specified element is a descendant of a given ancestor element.

    Args:
        ancestor (ElementType):
             The element to be considered as the ancestor.
        descendant (ElementType):
             The element to check for being a descendant.

    Returns:
        bool:
             True if the descendant is indeed a descendant of the ancestor, otherwise False.

    """
    return (
        next(
            (element for element in descendants_of(ancestor) if element == descendant),
            None,
        )
        is not None
    )

ancestors_of(element)

Retrieves a generator of the ancestors of a given element. The function yields the owner of the provided element, followed recursively by the owner of that owner, and so on. It continues to traverse the ownership hierarchy until it reaches an element that does not have an owner.

Parameters:

Name Type Description Default
element ElementType

The element for which to determine the ancestry.

required

Returns:

Type Description
Generator[ElementType, None, None]

typing.Generator[ElementType, None, None]: A generator yielding the ancestors of the given element, in the order from the direct owner to the most distant ancestor found.

Source code in stateforward/model/element.py
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def ancestors_of(element: ElementType) -> typing.Generator[ElementType, None, None]:
    """
    Retrieves a generator of the ancestors of a given element.
    The function yields the owner of the provided element, followed recursively by the owner of that owner, and so on. It continues to traverse the ownership hierarchy until it reaches an element that does not have an owner.

    Args:
        element (ElementType):
             The element for which to determine the ancestry.

    Returns:
        typing.Generator[ElementType, None, None]:
             A generator yielding the ancestors of the given element, in the order from the direct owner to the most distant ancestor found.

    """
    owner = owner_of(element)
    if owner is not None:
        yield owner
        yield from ancestors_of(owner)

is_ancestor_of(descendant, ancestor)

Determines if the provided ancestor element is an ancestor of the specified descendant element.

Parameters:

Name Type Description Default
descendant ElementType

The element that is potentially a descendant.

required
ancestor ElementType

The element that is potentially an ancestor.

required

Returns:

Name Type Description
bool bool

True if the ancestor is an ancestor of the descendant, otherwise False.

Source code in stateforward/model/element.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
def is_ancestor_of(descendant: ElementType, ancestor: ElementType) -> bool:
    """
    Determines if the provided ancestor element is an ancestor of the specified descendant element.

    Args:
        descendant (ElementType):
             The element that is potentially a descendant.
        ancestor (ElementType):
             The element that is potentially an ancestor.

    Returns:
        bool:
             True if the ancestor is an ancestor of the descendant, otherwise False.

    """
    return is_descendant_of(ancestor, descendant)

set_model(element, model)

Sets the model attribute for a given element and propagates this setting to all elements owned by it. Recursively sets the 'model' attribute of the given 'element' to the integer ID of the 'model'. It also applies the same setting to all elements that are considered owned by the 'element'. The 'owned_elements_of' generator is used to iterate over these owned elements.

Parameters:

Name Type Description Default
element ElementType

The element for which the model is being set.

required
model ElementType

The model element whose ID will be used to set the 'model' attribute.

required
Source code in stateforward/model/element.py
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def set_model(element: ElementType, model: ElementType):
    """
    Sets the model attribute for a given element and propagates this setting to all elements owned by it.
    Recursively sets the '__model__' attribute of the given 'element' to the integer ID of the 'model'. It also
    applies the same setting to all elements that are considered owned by the 'element'. The 'owned_elements_of' generator is used to iterate over these owned elements.

    Args:
        element (ElementType):
             The element for which the model is being set.
        model (ElementType):
             The model element whose ID will be used to set the '__model__' attribute.

    """
    element.__model__ = id_of(model)
    for owned_element in owned_elements_of(element):
        set_model(owned_element, model)

set_owner(element, owner)

Sets the owner of an element and all its owned elements to a specified owner element, then updates their model references to the model of the new owner. This function recursively assigns the owner's ID to the element and all of its owned sub-elements. It also updates the model reference for each element to match the model reference of the new owner. This procedure ensures a consistent ownership hierarchy and proper linkage to the corresponding model for each element within a given context.

Parameters:

Name Type Description Default
element ElementType

The element whose owner and model are to be updated.

required
owner ElementType

The element that will be set as the new owner.

required

Returns:

Source code in stateforward/model/element.py
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
def set_owner(element: ElementType, owner: ElementType):
    """
    Sets the owner of an element and all its owned elements to a specified owner element, then updates their model references to the model of the new owner.
    This function recursively assigns the owner's ID to the element and all of its owned
    sub-elements. It also updates the model reference for each element to match the model
    reference of the new owner. This procedure ensures a consistent ownership hierarchy and
    proper linkage to the corresponding model for each element within a given context.

    Args:
        element (ElementType):
             The element whose owner and model are to be updated.
        owner (ElementType):
             The element that will be set as the new owner.

    Returns:

    """
    element.__owner__ = id_of(owner)
    for owned_element in owned_elements_of(element):
        set_owner(owned_element, element)
    set_model(element, element.__all_elements__[owner.__model__])

add_owned_element_to(owner, element, *, change_ownership=False)

Adds an owned element to the specified owner, optionally changing the current ownership. This function is responsible for taking an element and adding it to the ownership structure of the given owner. If the element already has an owner and change_ownership is False, a ValueError is raised. If True, the current owner is disassociated before proceeding. The function sets the element's ownership to the given owner and appends its identifier to the owner's list of owned elements.

Parameters:

Name Type Description Default
owner ElementType

The entity that will own the element after the operation.

required
element ElementType

The element to be added to the ownership structure of the owner.

required
change_ownership bool

A flag to indicate if the ownership should be changed if the element already has an owner. Defaults to False.

False

Raises:

Type Description
ValueError

If the element already has an owner and change_ownership is False.

Returns:

Source code in stateforward/model/element.py
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
def add_owned_element_to(
    owner: ElementType,
    element: ElementType,
    *,
    change_ownership: bool = False,
):
    """
    Adds an owned element to the specified owner, optionally changing the current ownership.
    This function is responsible for taking an element and adding it to the ownership structure of the given owner.
    If the element already has an owner and `change_ownership` is `False`, a `ValueError` is raised. If `True`, the current owner is disassociated before proceeding.
    The function sets the element's ownership to the given owner and appends its identifier to the owner's list of owned elements.

    Args:
        owner (ElementType):
             The entity that will own the element after the operation.
        element (ElementType):
             The element to be added to the ownership structure of the owner.
        change_ownership (bool, optional):
             A flag to indicate if the ownership should be changed if the element already has an owner. Defaults to `False`.

    Raises:
        ValueError:
             If the element already has an owner and `change_ownership` is `False`.

    Returns:

    """
    element_owner = owner_of(element)
    if element_owner is not None:
        if not change_ownership:
            raise ValueError(f"element {element.__name__} already has an owner")
        remove_owned_element_from(element_owner, element)
    set_owner(element, owner)
    owner.__owned_elements__.append(id_of(element))

remove_owned_element_from(owner, element, *, disassociate=False)

Removes an owned element from its owner and optionally disassociates related elements.

Parameters:

Name Type Description Default
owner ElementType

The owner object from which to remove the element.

required
element ElementType

The element to be removed from the owner.

required
disassociate bool

Flag that indicates whether to disassociate the element from related elements. Defaults to False.

False

Returns:

Name Type Description
ElementType ElementType

The element that was removed.

Raises:

Type Description
ValueError

If the element is not owned by the given owner.

Source code in stateforward/model/element.py
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
def remove_owned_element_from(
    owner: ElementType, element: ElementType, *, disassociate: bool = False
) -> ElementType:
    """
    Removes an owned element from its owner and optionally disassociates related elements.

    Args:
        owner (ElementType):
             The owner object from which to remove the element.
        element (ElementType):
             The element to be removed from the owner.
        disassociate (bool, optional):
             Flag that indicates whether to disassociate the
            element from related elements. Defaults to False.

    Returns:
        ElementType:
             The element that was removed.

    Raises:
        ValueError:
             If the element is not owned by the given owner.

    """
    element_id = id_of(element)
    if owner_of(element) != owner:
        raise ValueError(f"element {element.__name__} is not owned by {owner.__name__}")
    if disassociate:
        for name, element in associations_of(element).items():
            remove_association_from(owner, element)
    owner.__owned_elements__.remove(element_id)
    element.__owner__ = None
    return element

add_association_to(owner, element, name=None)

Adds an association to an owner element with a reference to another element by its unique identifier. The association is recorded in the owner's __associations__ dictionary, with the name as the key and the unique identifier of the element as the value.

Parameters:

Name Type Description Default
owner ElementType

The element that will hold the association.

required
element ElementType

The element to which the owner element will be associated.

required
name str

The key under which the association is stored. If not provided, a default or an implicit name should be determined in other parts of the codebase.

None

Raises:

Type Description
AttributeError

If the owner does not have an __associations__ attribute.

Source code in stateforward/model/element.py
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
def add_association_to(owner: ElementType, element: ElementType, name: str = None):
    """
    Adds an association to an owner element with a reference to another element by its unique identifier.
    The association is recorded in the owner's `__associations__` dictionary, with the
    name as the key and the unique identifier of the element as the value.

    Args:
        owner (ElementType):
             The element that will hold the association.
        element (ElementType):
             The element to which the owner element will be associated.
        name (str, optional):
             The key under which the association is stored. If not provided,
            a default or an implicit name should be determined in other parts of the codebase.

    Raises:
        AttributeError:
             If the owner does not have an `__associations__` attribute.

    """
    owner.__associations__[name] = id_of(element)

remove_association_from(owner, element)

Removes the association between two ElementType objects. This function iterates over the associations of the 'owner' ElementType, comparing each associated element to the 'element' argument. If a match is found, the association is removed from the 'owner' by deleting the association entry.

Parameters:

Name Type Description Default
owner ElementType

The ElementType object from which the association is to be removed.

required
element ElementType

The ElementType object which is to be disassociated from the owner.

required

Returns:

Name Type Description
None

The function doesn't return anything.

Source code in stateforward/model/element.py
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
def remove_association_from(owner: ElementType, element: ElementType):
    """
    Removes the association between two ElementType objects.
    This function iterates over the associations of the 'owner' ElementType,
    comparing each associated element to the 'element' argument. If a match is found,
    the association is removed from the 'owner' by deleting the association entry.

    Args:
        owner (ElementType):
             The ElementType object from which the association is to be removed.
        element (ElementType):
             The ElementType object which is to be disassociated from the owner.

    Returns:
        None:
             The function doesn't return anything.

    """
    for name, element in associations_of(owner).items():
        if element == element:
            del owner.__associations__[name]

associations_of(element)

Retrieves the associations of a given ElementType object. This function takes an ElementType object and returns a dictionary where the keys are the names of the associated elements, and the values are the associated ElementType instances. It works by iterating over the element's __associations__ attribute which contains a mapping of names to element IDs, and uses the __all_elements__ mapping attribute of the element to obtain the actual ElementType instances.

Parameters:

Name Type Description Default
element ElementType

The ElementType object whose associations are to be retrieved.

required

Returns:

Type Description
dict[str, ElementType]

dict[str, ElementType]: A dictionary mapping names to ElementType instances representing the associations of the provided element.

Source code in stateforward/model/element.py
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
def associations_of(element: ElementType) -> dict[str, ElementType]:
    """
    Retrieves the associations of a given ElementType object.
    This function takes an ElementType object and returns a dictionary where the keys are the names of the associated elements, and the values are the associated ElementType instances. It works by iterating over the element's `__associations__` attribute which contains a mapping of names to element IDs, and uses the `__all_elements__` mapping attribute of the element to obtain the actual ElementType instances.

    Args:
        element (ElementType):
             The ElementType object whose associations are to be retrieved.

    Returns:
        dict[str, ElementType]:
             A dictionary mapping names to ElementType instances representing the associations of the provided element.

    """
    return dict(
        (name, element.__all_elements__[element_id])
        for name, element_id in element.__associations__.items()
    )

associations_for(element, associated)

Retrieves a dictionary of associations between two elements of specified types. This function searches within the given 'element's associations, identifying and returning associations where the associated element has the same id as the 'associated' element. Each matching association is stored in the dictionary with the association name as the key and the corresponding element as the value.

Parameters:

Name Type Description Default
element ElementType

The element from which associations will be searched.

required
associated ElementType

The element whose id is used to find matching associations.

required

Returns:

Type Description
dict[str, ElementType]

dict[str, ElementType]: A dictionary where each key is the name of the association, and each value is the ElementType instance associated with the 'associated' element's id.

Source code in stateforward/model/element.py
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
def associations_for(
    element: ElementType, associated: ElementType
) -> dict[str, ElementType]:
    """
    Retrieves a dictionary of associations between two elements of specified types.
    This function searches within the given 'element's associations, identifying and
    returning associations where the associated element has the same id as
    the 'associated' element. Each matching association is stored in the dictionary
    with the association name as the key and the corresponding element as the value.

    Args:
        element (ElementType):
             The element from which associations will be searched.
        associated (ElementType):
             The element whose id is used to find matching associations.

    Returns:
        dict[str, ElementType]:
             A dictionary where each key is the name of the
            association, and each value is the `ElementType` instance associated with
            the 'associated' element's id.

    """
    return dict(
        (name, element.__all_elements__[element_id])
        for name, element_id in element.__associations__.items()
        if element_id == id_of(associated)
    )

name_of(element)

Gets the name of a given element.

Parameters:

Name Type Description Default
element ElementType

The element whose name is to be retrieved. This can be an instance or a class.

required

Returns:

Name Type Description
str str

The name of the element. If 'element' is a class, it returns the name of the class. If 'element' is an instance of a class, it returns the name of the instance's class.

Source code in stateforward/model/element.py
408
409
410
411
412
413
414
415
416
417
418
419
420
421
def name_of(element: ElementType) -> str:
    """
    Gets the name of a given element.

    Args:
        element (ElementType):
             The element whose name is to be retrieved. This can be an instance or a class.

    Returns:
        str:
             The name of the element. If 'element' is a class, it returns the name of the class. If 'element' is an instance of a class, it returns the name of the instance's class.

    """
    return element.__name__ if isinstance(element, type) else element.__class__.__name__

attributes_of(element)

Retrieves the annotations of the attributes from a given ElementType object.

Parameters:

Name Type Description Default
element ElementType

The object whose attribute annotations we want to obtain.

required

Returns:

Type Description
dict[str, Any]

dict[str, typing.Any]: A dictionary where the keys are the names of the attributes and the values are the corresponding annotations.

Source code in stateforward/model/element.py
424
425
426
427
428
429
430
431
432
433
434
435
436
437
def attributes_of(element: ElementType) -> dict[str, typing.Any]:
    """
    Retrieves the annotations of the attributes from a given ElementType object.

    Args:
        element (ElementType):
             The object whose attribute annotations we want to obtain.

    Returns:
        dict[str, typing.Any]:
             A dictionary where the keys are the names of the attributes and the values are the corresponding annotations.

    """
    return element.__annotations__

qualified_name_of(element)

Determines the fully qualified name of the provided element by traversing its ownership hierarchy. This function ascertains the complete dotted path name of the element starting from the top-level owner down to the element itself. This is useful for identifying elements within a nested structure with their full context.

Parameters:

Name Type Description Default
element ElementType

The element for which to determine the qualified name. The ElementType is a type that is assumed to have __name__ and __owner__ attributes or a way to identify its owner and its container.

required

Returns:

Name Type Description
str str

A string representing the fully qualified name of the element. The function first identifies the owner of the element, then recursively constructs the qualified name by prepending the name of the owner (if any) followed by a dot and then the name of the element itself. If the element does not have an owner, the function simply returns the name of the element.

Source code in stateforward/model/element.py
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
def qualified_name_of(element: ElementType) -> str:
    """
    Determines the fully qualified name of the provided `element` by traversing its ownership hierarchy.
    This function ascertains the complete dotted path name of the element starting from the top-level owner down to the element itself. This is useful for identifying elements within a nested structure with their full context.

    Args:
        element (ElementType):
             The element for which to determine the qualified name. The ElementType is
            a type that is assumed to have `__name__` and `__owner__` attributes or a way to identify its
            owner and its container.

    Returns:
        str:
             A string representing the fully qualified name of the element.
            The function first identifies the owner of the element, then recursively constructs the qualified name
            by prepending the name of the owner (if any) followed by a dot and then the name of the element itself.
            If the element does not have an owner, the function simply returns the name of the element.

    """
    owner = owner_of(element)
    if owner is None:
        return name_of(element)
    return f"{qualified_name_of(owner)}.{name_of(element)}"

is_type(element, types)

Determines if an element is of a given type or types. This function checks if the provided element is either an instance of, or a subclass of, the given type or types. It supports checking against a single type or a collection of types. If multiple types are provided, the function will return True if the element matches any one of the types.

Parameters:

Name Type Description Default
element ElementType

The element to check.

required
types Union[type, Collection[type]]

A single type or a collection of types against which to check the element.

required

Returns:

Name Type Description
bool bool

True if the element is an instance of one of the types or is a subclass of one of the types, otherwise False.

Source code in stateforward/model/element.py
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
def is_type(
    element: ElementType, types: typing.Union[type, typing.Collection[type]]
) -> bool:
    """
    Determines if an element is of a given type or types.
    This function checks if the provided element is either an instance of, or a subclass of,
    the given type or types. It supports checking against a single type or a collection
    of types. If multiple types are provided, the function will return True if the element
    matches any one of the types.

    Args:
        element (ElementType):
             The element to check.
        types (typing.Union[type, typing.Collection[type]]):
             A single type or a collection of types
            against which to check the element.

    Returns:
        bool:
             True if the element is an instance of one of the types or is a subclass of one
            of the types, otherwise False.

    """
    return (
        issubclass(element, types)
        if isinstance(element, type)
        else isinstance(element, types)
    )

is_subtype(element, types)

Determines if a given element type is a subtype of specified types. This function checks if the provided element is not exactly one of the types and subsequently verifies if it is a subclass or an instance of the given types.

Parameters:

Name Type Description Default
element ElementType

The element or type to check.

required
types Union[type, Collection[type]]

A single type or a collection of types to compare with the element.

required

Returns:

Name Type Description
bool bool

True if element is a subtype of any of the given types, otherwise False.

Note:

Source code in stateforward/model/element.py
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
def is_subtype(
    element: ElementType, types: typing.Union[type, typing.Collection[type]]
) -> bool:
    """
    Determines if a given element type is a subtype of specified types.
    This function checks if the provided `element` is not exactly one of the `types` and subsequently verifies if it is a subclass or an instance of the given `types`.

    Args:
        element (ElementType):
             The element or type to check.
        types (Union[type, Collection[type]]):
             A single type or a collection of types to compare with the `element`.

    Returns:
        bool:
             True if `element` is a subtype of any of the given `types`, otherwise False.

    Note:

    """
    if is_element(types):
        types = (types,)
    return element not in types and is_type(element, types)

is_element(value)

Determines whether a given value is an instance of the Element type or a subtype thereof. This function checks if the provided value is an instance of Element or any class derived from Element.

Parameters:

Name Type Description Default
value Any

The value to be checked.

required

Returns:

Name Type Description
bool bool

True if 'value' is an instance of Element or a derived class, otherwise False.

Source code in stateforward/model/element.py
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
def is_element(value: typing.Any) -> bool:
    """
    Determines whether a given value is an instance of the Element type or a subtype thereof.
    This function checks if the provided value is an instance of Element or any class derived from Element.

    Args:
        value (typing.Any):
             The value to be checked.

    Returns:
        bool:
             True if 'value' is an instance of Element or a derived class, otherwise False.

    """
    return is_type(value, Element)

owner_of(element)

Determines the owner of a given element. The function checks if the provided 'element' is an instance of the Element type and retrieves its owner attribute. If the element is not an instance of Element, it attempts to look up the owner in the element's 'all_elements' dictionary using the element's 'owner' attribute as the key. The function then returns the owner of the element.

Parameters:

Name Type Description Default
element ElementType

The element for which the owner is to be determined.

required

Returns:

Name Type Description
ElementType ElementType

The owner of the provided element. If the element is an instance of the Element type, returns the value of its owner attribute. If not, returns the corresponding value from the element's 'all_elements' dictionary for the key 'owner'.

Raises:

Type Description
AttributeError

If 'owner' or 'all_elements' attributes do not exist on the provided element.

Source code in stateforward/model/element.py
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
def owner_of(element: ElementType) -> ElementType:
    """
    Determines the owner of a given element.
    The function checks if the provided 'element' is an instance of the Element type and retrieves its owner attribute. If the element is not an instance of Element, it attempts to look up the owner in the element's '__all_elements__' dictionary using the element's '__owner__' attribute as the key. The function then returns the owner of the element.

    Args:
        element (ElementType):
             The element for which the owner is to be determined.

    Returns:
        ElementType:
             The owner of the provided element. If the element is an instance of the Element type, returns the value of its __owner__ attribute. If not, returns the corresponding value from the element's '__all_elements__' dictionary for the key '__owner__'.

    Raises:
        AttributeError:
             If '__owner__' or '__all_elements__' attributes do not exist on the provided element.

    """
    return (
        element.__owner__
        if isinstance(element, Element)
        else element.__all_elements__.get(element.__owner__, None)
    )

redefined_element_of(element)

Retrieves the redefined element from the given element object. This function fetches the 'redefined_element' attribute from the element passed to it. It expects a predefined attribute 'redefined_element' to be present on the 'element' which is the redefined version of the element.

Parameters:

Name Type Description Default
element ElementType

The element from which the redefined version will be retrieved.

required

Returns:

Name Type Description
ElementType ElementType

The redefined version of the element.

Raises:

Type Description
AttributeError

If the element does not have 'redefined_element' attribute.

Source code in stateforward/model/element.py
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
def redefined_element_of(element: ElementType) -> ElementType:
    """
    Retrieves the redefined element from the given element object.
    This function fetches the '__redefined_element__' attribute from the element passed to it. It expects a
    predefined attribute '__redefined_element__' to be present on the 'element' which is the redefined version of the element.

    Args:
        element (ElementType):
             The element from which the redefined version will be retrieved.

    Returns:
        ElementType:
             The redefined version of the element.

    Raises:
        AttributeError:
             If the element does not have '__redefined_element__' attribute.

    """
    return element.__redefined_element__

is_owner_of(owner, element)

Determines if the provided 'owner' is the owner of the 'element'.

Parameters:

Name Type Description Default
owner ElementType

The potential owner whose ownership is being checked.

required
element ElementType

The element for which ownership is being verified.

required

Returns:

Name Type Description
bool bool

True if 'owner' is the owner of 'element', otherwise False.

Source code in stateforward/model/element.py
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
def is_owner_of(owner: ElementType, element: ElementType) -> bool:
    """
    Determines if the provided 'owner' is the owner of the 'element'.

    Args:
        owner (ElementType):
             The potential owner whose ownership is being checked.
        element (ElementType):
             The element for which ownership is being verified.

    Returns:
        bool:
             True if 'owner' is the owner of 'element', otherwise False.

    """
    return owner_of(element) == owner

specialize(base, derived, **kwargs)

Specializes the given base ElementType by deriving a new ElementType with properties and associations of the base type adjusted for the derived type. This function works by iterating through the owned elements of the base ElementType and creating a new owned element for each of them within the derived ElementType with redefinitions as needed. Associations within the base ElementType are also remapped to corresponding elements within the derived ElementType. If the base ElementType has no owner, a mapping is established between the base elements and the new elements, and associations are adapted accordingly.

Parameters:

Name Type Description Default
base ElementType

The base element type from which the new derived type will be created.

required
derived ElementType

The new element type that will inherit and specialize from the base type.

required
**kwargs

Additional keyword arguments (unused).

{}

Returns:

Name Type Description
None

The function performs in-place specialization and does not return any value.

Source code in stateforward/model/element.py
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
def specialize(base: ElementType, derived: ElementType, **kwargs):
    """
    Specializes the given base ElementType by deriving a new ElementType with properties and associations of the base type adjusted for the derived type.
    This function works by iterating through the owned elements of the base ElementType and creating a new owned element for each of them within the derived ElementType with redefinitions as needed. Associations within the base ElementType are also remapped to corresponding elements within the derived ElementType. If the base ElementType has no owner, a mapping is established between the base elements and the new elements, and associations are adapted accordingly.

    Args:
        base (ElementType):
             The base element type from which the new derived type will be created.
        derived (ElementType):
             The new element type that will inherit and specialize from the base type.
        **kwargs:
             Additional keyword arguments (unused).

    Returns:
        None:
             The function performs in-place specialization and does not return any value.

    """
    # we have to create copies of the base core during inheritance
    # loop through base owned element mapping
    for owned_element_id in base.__owned_elements__:
        # get the owned element
        owned_element = base.__all_elements__[owned_element_id]
        # create a new owned element
        new_owned_element = typing.cast(
            ElementType,
            types.new_class(
                owned_element.__name__,
                (owned_element,),
                {
                    "redefined_element": base,
                },
            ),
        )
        add_owned_element_to(derived, new_owned_element)

    if owner_of(base) is None:
        base_elements = (base, *descendants_of(base))
        new_elements = (derived, *descendants_of(derived))
        element_map = dict(
            (id_of(base), id_of(derived))
            for base, derived in zip(base_elements, new_elements)
        )

        for index, element in enumerate(base_elements):
            new_element = new_elements[index]
            for name, element_id in element.__associations__.items():
                associated_id = new_element.__associations__[name] = element_map[
                    element_id
                ]
                setattr(new_element, name, new_element.__all_elements__[associated_id])
    return None

is_redefined(element)

Determines if the provided element has been redefined. This function checks whether the element passed to it has a redefined counterpart by calling the 'redefined_element_of' function and inspecting if the returned value is not None.

Parameters:

Name Type Description Default
element ElementType

The element to check for a redefinition.

required

Returns:

Name Type Description
bool bool

True if the element has been redefined, False otherwise.

Source code in stateforward/model/element.py
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
def is_redefined(element: ElementType) -> bool:
    """
    Determines if the provided element has been redefined.
    This function checks whether the element passed to it has a redefined counterpart by calling the 'redefined_element_of' function and
    inspecting if the returned value is not None.

    Args:
        element (ElementType):
             The element to check for a redefinition.

    Returns:
        bool:
             True if the element has been redefined, False otherwise.

    """
    return redefined_element_of(element) is not None

redefine(element, **kwargs)

Redefines an existing element by creating a new subclass with additional properties. The redefine function takes an existing class or type (referred to as element) and returns a new class that is a subclass of the given element. This subclass can incorporate additional properties that are passed to the function as keyword arguments (**kwargs). The original class/type is also stored as an attribute redefined_element in the newly created subclass.

Parameters:

Name Type Description Default
element ElementType

The original class or type that is to be redefined into a new subclass.

required
**kwargs

Arbitrary keyword arguments that represent additional properties to be included in the new subclass.

{}

Returns:

Name Type Description
ElementType

A new subclass of the provided element, with added keyword arguments as attributes.

Source code in stateforward/model/element.py
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
def redefine(element: ElementType, **kwargs):
    """
    Redefines an existing element by creating a new subclass with additional properties.
    The `redefine` function takes an existing class or type (referred to as `element`) and returns a new class that is a subclass of the given `element`. This subclass can incorporate additional properties that are passed to the function as keyword arguments (`**kwargs`). The original class/type is also stored as an attribute `redefined_element` in the newly created subclass.

    Args:
        element (ElementType):
             The original class or type that is to be redefined into a new subclass.
        **kwargs:
             Arbitrary keyword arguments that represent additional properties to be included in the new subclass.

    Returns:
        ElementType:
             A new subclass of the provided `element`, with added keyword arguments as attributes.

    """
    return typing.cast(
        ElementType,
        types.new_class(
            name_of(element),
            kwargs.pop("bases", (element,)),
            {
                "redefined_element": element,
                **kwargs,
            },
        ),
    )

find_owned_elements_of(element, condition)

Generates elements owned by a given element that meet a specified condition. This generator function iterates through elements owned by the provided element and yields each owned element that satisfies the condition function. The condition function should take an ElementType as its argument and return a boolean indicating whether the element meets the desired criteria.

Parameters:

Name Type Description Default
element ElementType

The element whose owned elements are to be examined.

required
condition Callable[[ElementType], bool]

A function that takes an ElementType as an argument and returns True if the element satisfies the condition; otherwise, False.

required

Returns:

Type Description
Generator[ElementType, None, None]

Generator[ElementType, None, None]: A generator yielding owned elements of the provided element that satisfy the condition.

Source code in stateforward/model/element.py
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
def find_owned_elements_of(
    element: "ElementType", condition: typing.Callable[["ElementType"], bool]
) -> typing.Generator["ElementType", None, None]:
    """
    Generates elements owned by a given element that meet a specified condition.
    This generator function iterates through elements owned by the provided `element` and yields each owned element that satisfies the `condition` function. The `condition` function should take an `ElementType` as its argument and return a boolean indicating whether the element meets the desired criteria.

    Args:
        element (ElementType):
             The element whose owned elements are to be examined.
        condition (Callable[[ElementType], bool]):
             A function that takes an `ElementType` as an argument and returns True if the element satisfies the condition; otherwise, False.

    Returns:
        Generator[ElementType, None, None]:
             A generator yielding owned elements of the provided `element` that satisfy the `condition`.

    """
    for owned_element in owned_elements_of(element):
        if condition(owned_element):
            yield owned_element

find_owned_element_of(element, condition)

Finds the first element within a given element's ownership hierarchy that satisfies a specified condition. This function traverses the ownership structure of the provided element to locate the first child or descendant that meets the criteria defined by the condition callable. If such an element is found, it is returned; otherwise, the function returns None.

Parameters:

Name Type Description Default
element ElementType

The element from which the search for owned elements should begin.

required
condition Callable[[ElementType], bool]

A function that takes an element of type ElementType as a single argument and returns a boolean value. The function should return True for an element that fulfills the search criteria and False otherwise.

required

Returns:

Type Description
Optional[ElementType]

Optional[ElementType]: The first element that satisfies the condition, or None if no matching element is found.

Source code in stateforward/model/element.py
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
def find_owned_element_of(
    element: "ElementType", condition: typing.Callable[["ElementType"], bool]
) -> typing.Optional["ElementType"]:
    """
    Finds the first element within a given element's ownership hierarchy that satisfies a specified condition.
    This function traverses the ownership structure of the provided element to locate the first child or descendant
    that meets the criteria defined by the `condition` callable. If such an element is found, it is returned;
    otherwise, the function returns `None`.

    Args:
        element (ElementType):
             The element from which the search for owned elements should begin.
        condition (Callable[[ElementType], bool]):
             A function that takes an element of type `ElementType` as a single argument
            and returns a boolean value. The function should return `True` for an element that fulfills the
            search criteria and `False` otherwise.

    Returns:
        Optional[ElementType]:
             The first element that satisfies the condition, or `None` if no matching element is found.

    """
    return next(find_owned_elements_of(element, condition), None)

find_ancestors_of(element, condition)

Generates a sequence of ancestor elements of a given element that satisfy a specified condition. This generator function traverses the ancestor hierarchy of the provided element, testing each ancestor against a condition function. It yields each ancestor element that meets the criteria defined by the condition function. The traversal continues until the root of the hierarchy is reached or the generator is exhausted.

Parameters:

Name Type Description Default
element ElementType

The element whose ancestors are to be found.

required
condition Callable[[ElementType], bool]

A callable that takes an element as its single argument and returns a boolean indicating whether the element meets the desired condition.

required

Yields:

Name Type Description
ElementType ElementType

Ancestors of the initial element that satisfy the condition.

Source code in stateforward/model/element.py
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
def find_ancestors_of(
    element: "ElementType", condition: typing.Callable[["ElementType"], bool]
) -> typing.Generator["ElementType", None, None]:
    """
    Generates a sequence of ancestor elements of a given element that satisfy a specified condition.
    This generator function traverses the ancestor hierarchy of the provided element, testing each ancestor against a condition function.
    It yields each ancestor element that meets the criteria defined by the condition function. The traversal continues until the root of the hierarchy is reached or the generator is exhausted.

    Args:
        element (ElementType):
             The element whose ancestors are to be found.
        condition (typing.Callable[[ElementType], bool]):
             A callable that takes an element as its single argument
            and returns a boolean indicating whether the element meets the desired condition.

    Yields:
        ElementType:
             Ancestors of the initial element that satisfy the condition.

    """
    for element in ancestors_of(element):
        if condition(element):
            yield element

find_ancestor_of(element, expr)

Finds the first ancestor of a specified element that matches a given condition.

Parameters:

Name Type Description Default
element ElementType

The element from which to begin the search for an ancestor.

required
expr Callable[[ElementType], bool]

A function that takes an element as an argument and returns True if the element matches the condition, False otherwise.

required

Returns:

Type Description
Optional[ElementType]

typing.Optional['ElementType']: The first ancestor element that matches the condition specified by expr. If no matching ancestor is found, returns None.

Source code in stateforward/model/element.py
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
def find_ancestor_of(
    element: "ElementType", expr: typing.Callable[["ElementType"], bool]
) -> typing.Optional["ElementType"]:
    """
    Finds the first ancestor of a specified element that matches a given condition.

    Args:
        element (ElementType):
             The element from which to begin the search for an ancestor.
        expr (typing.Callable[['ElementType'], bool]):
             A function that takes an element as an argument and returns True if the element matches the condition, False otherwise.

    Returns:
        typing.Optional['ElementType']:
             The first ancestor element that matches the condition specified by expr. If no matching ancestor is found, returns None.

    """
    return next(find_ancestors_of(element, expr), None)

find_descendants_of(element, condition)

Finds and yields descendants of a given element that satisfy a specified condition. This generator function traverses through the descendants of the provided element, checking each one against the given condition function. If a descendant meets the condition, it is yielded.

Parameters:

Name Type Description Default
element ElementType

The element whose descendants will be checked.

required
condition Callable[[ElementType], bool]

A function that takes an element as its argument and returns True if the element satisfies the condition, otherwise False.

required

Yields:

Name Type Description
ElementType ElementType

The next descendant of 'element' that satisfies the 'condition'.

Source code in stateforward/model/element.py
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
def find_descendants_of(
    element: "ElementType",
    condition: typing.Callable[["ElementType"], bool],
) -> typing.Generator["ElementType", None, None]:
    """
    Finds and yields descendants of a given element that satisfy a specified condition.
    This generator function traverses through the descendants of the provided element, checking each one
    against the given condition function. If a descendant meets the condition, it is yielded.

    Args:
        element (ElementType):
             The element whose descendants will be checked.
        condition (Callable[[ElementType], bool]):
             A function that takes an element as its argument
            and returns True if the element satisfies the condition, otherwise False.

    Yields:
        ElementType:
             The next descendant of 'element' that satisfies the 'condition'.

    """
    for element in descendants_of(element):
        if condition(element):
            yield element

set_attribute(element, name, value)

Sets an attribute for an ElementType object with special handling for Element objects. This method sets an attribute on an ElementType object with the given name and value. If the value is an Element, additional steps are taken to manage ownership and associations. If the Element is not owned by any ElementType, or if it's a descendant of 'element' and it doesn't belong to a different model, it will be added to 'element's owned elements. Furthermore, an association between 'element' and the value is established using the name as the key. If the provided value is not an Element, the attribute is simply set on 'element' with the provided name and value.

Parameters:

Name Type Description Default
element ElementType

The ElementType object to which the attribute should be set.

required
name str

The name of the attribute to be set.

required
value Any

The value to be assigned to the attribute. If an Element, ownership and association logic applies.

required

Raises:

Type Description
ValueError

If the Element value is owned by a different model and is not a descendant of 'element', or if any ownership related issues are encountered.

Source code in stateforward/model/element.py
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
def set_attribute(
    element: ElementType,
    name: str,
    value: typing.Any,
):
    """
    Sets an attribute for an ElementType object with special handling for Element objects.
    This method sets an attribute on an ElementType object with the given name and value. If the value is an Element,
    additional steps are taken to manage ownership and associations. If the Element is not owned by any ElementType, or if
    it's a descendant of 'element' and it doesn't belong to a different model, it will be added to 'element's owned
    elements. Furthermore, an association between 'element' and the value is established using the name as the key.
    If the provided value is not an Element, the attribute is simply set on 'element' with the provided name and value.

    Args:
        element (ElementType):
             The ElementType object to which the attribute should be set.
        name (str):
             The name of the attribute to be set.
        value (typing.Any):
             The value to be assigned to the attribute. If an Element, ownership and
            association logic applies.

    Raises:
        ValueError:
             If the Element value is owned by a different model and is not a descendant
            of 'element', or if any ownership related issues are encountered.

    """
    if is_element(value):
        value_id = id_of(value)
        if value_id not in element.__owned_elements__:
            owner = owner_of(value)
            change_ownership = (
                owner is None or is_descendant_of(element, owner)
            ) and element.__model__ != id_of(value)
            if change_ownership:
                add_owned_element_to(element, value, change_ownership=change_ownership)
        add_association_to(element, value, name)
    setattr(element, name, value)

new(name, bases=None, **kwargs)

Creates a new class with the given name, optional base classes, and any additional keyword arguments.

Parameters:

Name Type Description Default
name str

The name of the new class.

required
bases Collection[type]

An optional collection of base classes for the new class. Defaults to a tuple only containing Element.

None
**kwargs

Arbitrary keyword arguments that will be included as class attributes.

{}

Returns:

Type Description
type[T]

type[T]: A new class of type T that is derived from the specified base classes and includes the provided keyword arguments as class attributes.

Source code in stateforward/model/element.py
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
def new(name: str, bases: typing.Collection[type] = None, **kwargs) -> type[T]:
    """
    Creates a new class with the given name, optional base classes, and any additional keyword arguments.

    Args:
        name (str):
             The name of the new class.
        bases (typing.Collection[type], optional):
             An optional collection of base classes for the new class. Defaults to a tuple only containing Element.
        **kwargs:
             Arbitrary keyword arguments that will be included as class attributes.

    Returns:
        type[T]:
             A new class of type T that is derived from the specified base classes and includes the provided keyword arguments as class attributes.

    """
    return typing.cast(
        type[T],
        types.new_class(
            name,
            bases or (Element,),
            {
                **kwargs,
            },
        ),
    )