Visitor
The visitor
module provides a flexible framework for navigating and processing various elements within a structured model. It uses the Visitor design pattern to separate the algorithm from the elements on which it operates, allowing different kinds of operations to be performed on the elements of a model seamlessly without changing the classes of the elements themselves. Here's a detailed overview of the components within the visitor
module:
Classes
Visitor
The central class in the visitor
module is Visitor
, which serves as a base class for creating specific visitor classes that can walk through a model's structure and perform custom operations.
visit_method_prefix
: A class attribute that stores the prefix for visit methods. It defaults to'visit'
, but subclasses can override it.visited
: A set that keeps track of the ids of visited elements to avoid processing them multiple times.
Methods
__init_subclass__(cls, visit_method_prefix: Optional[str]=None)
: A class method that ensures the subclass adopts a custom prefix for visiting methods. It also dynamically creates visit methods if they are not already defined in the subclass.__init__(self)
: Initializes the visitor instance and the set to track visited elements.visit_element(self, element: Type[model.Element], *args, **kwargs)
: Visits an element and prevents revisiting already processed elements. It also dynamically dispatches to more specific visit methods based on the class of the element.visit_owned_elements(self, element: Type[model.Element], *args, **kwargs)
: Iterates over and visits all elements owned by the given element.visit(self, element: Type[model.Model])
: Starts the visitation process from the top-level model element.
Constants
TITLE_CASE_PATTERN
: A regular expression pattern used to identify title-cased names within a string.-
UNDERSCORE_REPLACE_PATTERN
: A pattern used for replacing characters in a string to facilitate method name generation. -
__all__
: A list containing the names of objects intended for export from the module.
Helper Functions
__get__
: An internal function facilitating the retrieval of the visitor instance in a descriptor context.
Overall, this module provides a generic mechanism for traversing and acting upon different elements within a model by using visitor classes that can be tailored to perform specific operations while maintaining loose coupling between the visitor logic and the model's structure.
Visitor
A base class for implementing visitor pattern logic for traversing and processing elements in a model hierarchy. This class defines the basic mechanics of a visitor pattern, where subclasses can override specific visit methods to implement custom behaviors while traversing model elements. It uses a dynamic method resolution based on element types and their inheritance hierarchy to determine the appropriate visit methods to invoke. Subclasses can define their own visit methods with a customizable prefix by specifying the 'visit_method_prefix' attribute during subclassing. If the subclass does not define a certain prefixed visit method that exists in the base class, it will be automatically populated with a default implementation based on the Visitor's corresponding method. The visitor keeps track of visited elements by their unique IDs to avoid redundant processing, especially when traversing complex model structures with potential redefinitions or cyclic references.
Attributes:
Name | Type | Description |
---|---|---|
visit_method_prefix |
str
|
The prefix used for visitor methods, defaulting to 'visit' for the base class. Subclasses may override. |
visited |
set[int]
|
A set that keeps track of the IDs of elements that have been visited to prevent redundant visits. |
Methods:
Name | Description |
---|---|
__init_subclass__ |
Class method to handle subclass initialization by assigning a method prefix and populating missing prefixed visit methods with default logic from the base class. |
__init__ |
Initializes a new instance of Visitor, primarily responsible for initializing the 'visited' attribute. |
visit_element |
Processes an individual element and its hierarchy, marking it as visited, and calling the specific visit methods based on the element's type. |
visit_owned_elements |
Iterates over and processes all owned elements of a given element using 'visit_element'. |
visit |
The entry point for visiting a model, invoking 'visit_element' on the top-level element. |
Source code in stateforward/model/visitor.py
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
|
__init__()
Source code in stateforward/model/visitor.py
124 125 126 127 128 129 130 |
|
__init_subclass__(visit_method_prefix=None)
Customizes the subclass initialization process by setting a visit method prefix and providing default implementations for visitor methods if they are not already defined in the subclass. This modification allows different subclasses to utilize custom prefixes for their own visitor methods. During the subclass initialization, it checks whether the subclass has defined the necessary visitor methods according to a specified prefix. If such methods are not found, it dynamically creates and assigns default visitor method implementations that delegate the calls to the parent visitor methods. The method specifically targets visitor methods with or without '_element' and '_owned_elements' postfixes. This dynamic method creation aims to maintain consistency across various visitor implementations, ensuring that all necessary visitor interface methods are present in the subclass, regardless of the prefix chosen.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
cls |
type
|
The class being initialized as a subclass. |
required |
visit_method_prefix |
Optional[str]
|
An optional string to specify the prefix for the visit methods in the subclass. If not provided, it defaults to the prefix used in the base Visitor class. |
None
|
Raises:
Type | Description |
---|---|
TypeError
|
If the cls argument is provided, but it is not a type. |
Source code in stateforward/model/visitor.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
|
visit(element)
Visits a model element to perform operations on it. This method delegates the operation to the 'visit_element' method which needs to be implemented to perform actual actions on the model element passed to this 'visit' method.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
element |
Type[Model]
|
The model element that needs to be visited. It should be an instance of a class from the 'model' module. |
required |
Source code in stateforward/model/visitor.py
181 182 183 184 185 186 187 188 189 190 191 |
|
visit_element(element, *args, **kwargs)
Visits a given element and processes it according to the visiting rules defined in the visitor.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
element |
Type[Element]
|
The element to visit. |
required |
*args |
Variable length argument list. |
()
|
|
**kwargs |
Arbitrary keyword arguments. This method processes an element by first checking if it has been redefined and if it hasn't been visited already, provided that the element has a unique identifier. It then iterates over the Method Resolution Order (MRO) of the element. For each class in the MRO, it attempts to find a corresponding method on the visitor with a name that matches the naming convention 'visit_' followed by the class name in lowercase with spaces replaced by underscores. If such a method is found and it is not the base 'visit_element' method, it invokes the method with the element and any additional arguments passed to 'visit_element'. If the method returns a truthy value, the traversal is short-circuited. Lastly, if no truthy value is returned, 'visit_owned_elements' is called to continue processing any owned elements of the current element. |
{}
|
Source code in stateforward/model/visitor.py
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
|
visit_owned_elements(element, *args, **kwargs)
Visits all owned elements of a given model element. This method iterates over all elements owned by the specified element and applies the visit_element method to each. It is intended to be used for traversing a hierarchy of model elements and performing operations on each owned element. The visit_element method called by this function should be defined elsewhere and is responsible for the actual operation performed on each element.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
element |
Type[Element]
|
The root element from which owned elements will be visited. |
required |
*args |
Variable length argument list for arguments to pass to visit_element method. |
()
|
|
**kwargs |
Arbitrary keyword arguments for arguments to pass to visit_element method. |
{}
|
Source code in stateforward/model/visitor.py
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
|