handle parent lifetime flag

This commit is contained in:
Jakub Trllo 2025-07-23 11:47:57 +02:00
parent 737f3acde1
commit ff7a63099b
2 changed files with 86 additions and 46 deletions

View file

@ -21,6 +21,7 @@ from .exceptions import (
TemplateFillError, TemplateFillError,
) )
from .structures import ( from .structures import (
ParentFlags,
CreatedInstance, CreatedInstance,
ConvertorItem, ConvertorItem,
AttributeValues, AttributeValues,
@ -86,6 +87,7 @@ __all__ = (
"TaskNotSetError", "TaskNotSetError",
"TemplateFillError", "TemplateFillError",
"ParentFlags",
"CreatedInstance", "CreatedInstance",
"ConvertorItem", "ConvertorItem",
"AttributeValues", "AttributeValues",

View file

@ -41,7 +41,12 @@ from .exceptions import (
HostMissRequiredMethod, HostMissRequiredMethod,
) )
from .changes import TrackChangesItem from .changes import TrackChangesItem
from .structures import PublishAttributes, ConvertorItem, InstanceContextInfo from .structures import (
PublishAttributes,
ConvertorItem,
InstanceContextInfo,
ParentFlags,
)
from .creator_plugins import ( from .creator_plugins import (
Creator, Creator,
AutoCreator, AutoCreator,
@ -2069,63 +2074,96 @@ class CreateContext:
sender (Optional[str]): Sender of the event. sender (Optional[str]): Sender of the event.
""" """
instance_ids_by_parent_id = collections.defaultdict(set)
for instance in self.instances:
instance_ids_by_parent_id[instance.parent_instance_id].add(
instance.id
)
instances_to_remove = list(instances)
ids_to_remove = {
instance.id
for instance in instances_to_remove
}
_queue = collections.deque()
_queue.extend(instances_to_remove)
while _queue:
instance = _queue.popleft()
ids_to_remove.add(instance.id)
children_ids = instance_ids_by_parent_id[instance.id]
for children_id in children_ids:
if children_id in ids_to_remove:
continue
instance = self._instances_by_id[children_id]
if instance.parent_flags & ParentFlags.parent_lifetime:
instances_to_remove.append(instance)
ids_to_remove.add(instance.id)
_queue.append(instance)
instances_by_identifier = collections.defaultdict(list) instances_by_identifier = collections.defaultdict(list)
for instance in instances: for instance in instances_to_remove:
identifier = instance.creator_identifier identifier = instance.creator_identifier
instances_by_identifier[identifier].append(instance) instances_by_identifier[identifier].append(instance)
# Just remove instances from context if creator is not available # Just remove instances from context if creator is not available
missing_creators = set(instances_by_identifier) - set(self.creators) missing_creators = set(instances_by_identifier) - set(self.creators)
instances = [] miss_creator_instances = []
for identifier in missing_creators: for identifier in missing_creators:
instances.extend( miss_creator_instances.extend(instances_by_identifier[identifier])
instance
for instance in instances_by_identifier[identifier]
)
self._remove_instances(instances, sender) with self.bulk_remove_instances(sender):
self._remove_instances(miss_creator_instances, sender)
error_message = "Instances removement of creator \"{}\" failed. {}" error_message = "Instances removement of creator \"{}\" failed. {}"
failed_info = [] failed_info = []
# Remove instances by creator plugin order # Remove instances by creator plugin order
for creator in self.get_sorted_creators( for creator in self.get_sorted_creators(
instances_by_identifier.keys() instances_by_identifier.keys()
): ):
identifier = creator.identifier identifier = creator.identifier
creator_instances = instances_by_identifier[identifier] # Filter instances by current state of 'CreateContext'
# - in case instances were already removed as subroutine of
# previous create plugin.
creator_instances = [
instance
for instance in instances_by_identifier[identifier]
if instance.id in self._instances_by_id
]
if not creator_instances:
continue
label = creator.label label = creator.label
failed = False failed = False
add_traceback = False add_traceback = False
exc_info = None exc_info = None
try: try:
creator.remove_instances(creator_instances) creator.remove_instances(creator_instances)
except CreatorError: except CreatorError:
failed = True failed = True
exc_info = sys.exc_info() exc_info = sys.exc_info()
self.log.warning( self.log.warning(
error_message.format(identifier, exc_info[1]) error_message.format(identifier, exc_info[1])
) )
except (KeyboardInterrupt, SystemExit): except (KeyboardInterrupt, SystemExit):
raise raise
except: # noqa: E722 except: # noqa: E722
failed = True failed = True
add_traceback = True add_traceback = True
exc_info = sys.exc_info() exc_info = sys.exc_info()
self.log.warning( self.log.warning(
error_message.format(identifier, ""), error_message.format(identifier, ""),
exc_info=True exc_info=True
) )
if failed: if failed:
failed_info.append( failed_info.append(
prepare_failed_creator_operation_info( prepare_failed_creator_operation_info(
identifier, label, exc_info, add_traceback identifier, label, exc_info, add_traceback
)
) )
)
if failed_info: if failed_info:
raise CreatorsRemoveFailed(failed_info) raise CreatorsRemoveFailed(failed_info)