@@ -29,3 +29,235 @@ class Element(metaclass=abc.ABCMeta):
2929 tree, all references held automatically become invalid.
3030 """
3131 __slots__ = []
32+
33+ @abc .abstractmethod
34+ def get_init_stack (self ):
35+ """Gets the stack trace where this element was first initialized."""
36+
37+ @abc .abstractmethod
38+ def get_last_modified_stacks_for_all_attributes (self ):
39+ """Gets a dict of stack traces where each attribute was last modified."""
40+
41+ @abc .abstractmethod
42+ def is_same_as (self , other ):
43+ """Checks whether another element is semantically equivalent to this one.
44+
45+ Two elements are considered equivalent if they have the same
46+ specification (i.e. same tag appearing in the same context), the same
47+ attribute values, and all of their children are equivalent. The ordering
48+ of non-repeated children is not important for this comparison, while
49+ the ordering of repeated children are important only amongst the same
50+ type* of children. In other words, for two bodies to be considered
51+ equivalent, their child sites must appear in the same order, and their
52+ child geoms must appear in the same order, but permutations between sites
53+ and geoms are disregarded. (The only exception is in tendon definition,
54+ where strict ordering of all children is necessary for equivalence.)
55+
56+ *Note that the notion of "same type" in this function is very loose:
57+ for example different actuator element subtypes are treated as separate
58+ types when children ordering is considered. Therefore, two <actuator>
59+ elements might be considered equivalent even though they result in different
60+ orderings of `mjData.ctrl` when compiled. As it stands, this function
61+ is designed primarily as a testing aid and should not be used to guarantee
62+ that models are actually identical.
63+
64+ Args:
65+ other: An `mjcf.Element`
66+
67+ Returns:
68+ `True` if `other` element is semantically equivalent to this one.
69+ """
70+
71+ @property
72+ @abc .abstractmethod
73+ def tag (self ):
74+ pass
75+
76+ @property
77+ @abc .abstractmethod
78+ def spec (self ):
79+ pass
80+
81+ @property
82+ @abc .abstractmethod
83+ def parent (self ):
84+ pass
85+
86+ @property
87+ @abc .abstractmethod
88+ def namescope (self ):
89+ pass
90+
91+ @property
92+ @abc .abstractmethod
93+ def root (self ):
94+ pass
95+
96+ @abc .abstractmethod
97+ def prefixed_identifier (self , prefix_root ):
98+ pass
99+
100+ @property
101+ @abc .abstractmethod
102+ def full_identifier (self ):
103+ """Fully-qualified identifier used for this element in the generated XML."""
104+
105+ @abc .abstractmethod
106+ def find (self , namespace , identifier ):
107+ """Finds an element with a particular identifier.
108+
109+ This function allows the direct access to an arbitrarily deeply nested
110+ child element by name, without the need to manually traverse through the
111+ object tree. The `namespace` argument specifies the kind of element to
112+ find. In most cases, this corresponds to the element's XML tag name.
113+ However, if an element has multiple specialized tags, then the namespace
114+ corresponds to the tag name of the most general element of that kind.
115+ For example, `namespace='joint'` would search for `<joint>` and
116+ `<freejoint>`, while `namespace='actuator'` would search for `<general>`,
117+ `<motor>`, `<position>`, `<velocity>`, and `<cylinder>`.
118+
119+ Args:
120+ namespace: A string specifying the namespace being searched. See the
121+ docstring above for explanation.
122+ identifier: The identifier string of the desired element.
123+
124+ Returns:
125+ An `mjcf.Element` object, or `None` if an element with the specified
126+ identifier is not found.
127+
128+ Raises:
129+ ValueError: if either `namespace` or `identifier` is not a string, or if
130+ `namespace` is not a valid namespace.
131+ """
132+
133+ @abc .abstractmethod
134+ def find_all (self , namespace ,
135+ immediate_children_only = False , exclude_attachments = False ):
136+ """Finds all elements of a particular kind.
137+
138+ The `namespace` argument specifies the kind of element to
139+ find. In most cases, this corresponds to the element's XML tag name.
140+ However, if an element has multiple specialized tags, then the namespace
141+ corresponds to the tag name of the most general element of that kind.
142+ For example, `namespace='joint'` would search for `<joint>` and
143+ `<freejoint>`, while `namespace='actuator'` would search for `<general>`,
144+ `<motor>`, `<position>`, `<velocity>`, and `<cylinder>`.
145+
146+ Args:
147+ namespace: A string specifying the namespace being searched. See the
148+ docstring above for explanation.
149+ immediate_children_only: (optional) A boolean, if `True` then only
150+ the immediate children of this element are returned.
151+ exclude_attachments: (optional) A boolean, if `True` then elements
152+ belonging to attached models are excluded.
153+
154+ Returns:
155+ A list of `mjcf.Element`.
156+
157+ Raises:
158+ ValueError: if `namespace` is not a valid namespace.
159+ """
160+
161+ @abc .abstractmethod
162+ def enter_scope (self , scope_identifier ):
163+ """Finds the root element of the given scope and returns it.
164+
165+ This function allows the access to a nested scope that is a child of this
166+ element. The `scope_identifier` argument specifies the path to the child
167+ scope element.
168+
169+ Args:
170+ scope_identifier: The path of the desired scope element.
171+
172+ Returns:
173+ An `mjcf.Element` object, or `None` if a scope element with the
174+ specified path is not found.
175+ """
176+
177+ @abc .abstractmethod
178+ def get_attribute_xml_string (self , attribute_name , prefix_root = None ):
179+ pass
180+
181+ @abc .abstractmethod
182+ def get_attributes (self ):
183+ pass
184+
185+ @abc .abstractmethod
186+ def set_attributes (self , ** kwargs ):
187+ pass
188+
189+ @abc .abstractmethod
190+ def get_children (self , element_name ):
191+ pass
192+
193+ @abc .abstractmethod
194+ def add (self , element_name , ** kwargs ):
195+ """Add a new child element to this element.
196+
197+ Args:
198+ element_name: The tag of the element to add.
199+ **kwargs: Attributes of the new element being created.
200+
201+ Raises:
202+ ValueError: If the 'element_name' is not a valid child, or if an invalid
203+ attribute is specified in `kwargs`.
204+
205+ Returns:
206+ An `mjcf.Element` corresponding to the newly created child element.
207+ """
208+
209+ @abc .abstractmethod
210+ def remove (self , affect_attachments = False ):
211+ """Removes this element from the model."""
212+
213+ @property
214+ @abc .abstractmethod
215+ def is_removed (self ):
216+ pass
217+
218+ @abc .abstractmethod
219+ def all_children (self ):
220+ pass
221+
222+ @abc .abstractmethod
223+ def to_xml (self , prefix_root = None , debug_context = None ):
224+ """Generates an etree._Element corresponding to this MJCF element.
225+
226+ Args:
227+ prefix_root: (optional) A `NameScope` object to be treated as root
228+ for the purpose of calculating the prefix.
229+ If `None` then no prefix is included.
230+ debug_context: (optional) A `debugging.DebugContext` object to which
231+ the debugging information associated with the generated XML is written.
232+ This is intended for internal use within PyMJCF; users should never need
233+ manually pass this argument.
234+
235+ Returns:
236+ An etree._Element object.
237+ """
238+
239+ @abc .abstractmethod
240+ def to_xml_string (self , prefix_root = None ,
241+ self_only = False , pretty_print = True , debug_context = None ):
242+ """Generates an XML string corresponding to this MJCF element.
243+
244+ Args:
245+ prefix_root: (optional) A `NameScope` object to be treated as root
246+ for the purpose of calculating the prefix.
247+ If `None` then no prefix is included.
248+ self_only: (optional) A boolean, whether to generate an XML corresponding
249+ only to this element without any children.
250+ pretty_print: (optional) A boolean, whether to the XML string should be
251+ properly indented.
252+ debug_context: (optional) A `debugging.DebugContext` object to which
253+ the debugging information associated with the generated XML is written.
254+ This is intended for internal use within PyMJCF; users should never need
255+ manually pass this argument.
256+
257+ Returns:
258+ A string.
259+ """
260+
261+ @abc .abstractmethod
262+ def resolve_references (self ):
263+ pass
0 commit comments