Skip to content

sdk: Fix walk_submodel() skipping Entity and Operation children#465

Open
zrgt wants to merge 1 commit intoeclipse-basyx:developfrom
rwth-iat:fix/issue-423-walk-submodel-entity-operation
Open

sdk: Fix walk_submodel() skipping Entity and Operation children#465
zrgt wants to merge 1 commit intoeclipse-basyx:developfrom
rwth-iat:fix/issue-423-walk-submodel-entity-operation

Conversation

@zrgt
Copy link
Contributor

@zrgt zrgt commented Feb 25, 2026

Summary

Fixes #423.

traversal.walk_submodel() was only recursing into SubmodelElementCollection.value and
SubmodelElementList.value, missing two other container types defined by the AAS specification:

  • Entity.statement
  • Operation.input_variable, Operation.output_variable, Operation.in_output_variable

This caused a concrete data-loss bug: File SubmodelElements nested inside an Entity or
Operation were silently dropped from the file_store when reading AASX files
(AASXReader._collect_supplementary_files uses walk_submodel to find all File elements).

Changes

  • sdk/basyx/aas/util/traversal.py: Extracted element-level recursion into a private helper
    _walk_submodel_helper() that handles all four container types. The post-order traversal
    (children before parent) is preserved and works correctly for arbitrary nesting
    (e.g. Entity inside Operation.input_variable, SubmodelElementCollection inside
    Entity.statement).

  • sdk/test/util/test_traversal.py (new): 13 unit tests covering basic traversal, Entity
    statements, Operation variables, nested combinations, empty containers, and two explicit
    regression tests for issue traversal.walksubmodel(): Child Submodel Elements of Entity and Operation are skipped #423.

Fixes eclipse-basyx#423. The traversal now recurses into Entity.statement and
Operation.input_variable/output_variable/in_output_variable, so
File SubmodelElements nested inside these containers are no longer
silently dropped when reading AASX files.

Adds test_traversal.py with 13 unit tests covering the fix and
regression cases.
Comment on lines +16 to +25
def _walk_submodel_helper(elements: Iterable[model.SubmodelElement]) -> Iterator[model.SubmodelElement]:
for element in elements:
if isinstance(element, (model.SubmodelElementCollection, model.SubmodelElementList)):
yield from _walk_submodel_helper(element.value)
elif isinstance(element, model.Operation):
for var_list in (element.input_variable, element.output_variable, element.in_output_variable):
yield from _walk_submodel_helper(var_list)
elif isinstance(element, model.Entity):
yield from _walk_submodel_helper(element.statement)
yield element
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would keep this code in the walk_submodel() method.
I don't really see a use case for reusal, which would outweigh the annoyance to jump from one method to the other just to understand what's happening.
I'm free to be convinced otherwise though ;)

Comment on lines +25 to +32
def test_collection_post_order(self):
child1 = model.Property("child1", model.datatypes.String)
child2 = model.Property("child2", model.datatypes.String)
coll = model.SubmodelElementCollection("coll", value=[child1, child2])
sm = self._submodel(coll)
result = list(walk_submodel(sm))
# post-order: children before parent
self.assertEqual([child1, child2, coll], result)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was implicitly the ordering before. I'm not sure we should guarantee that ordering, though.
I think the method should only guarantee that all elements are returned, without making any promises about their order, especially since this is a yield-based method.
Therefore, I'd remove the tests regarding order.
Also, I'd reformulate the asserts as asserting just that all the elements are returned, not their exact order.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants