Skip to content

Commit 330367c

Browse files
committed
Refactor event creation API
- Add new BehaviorSettings class to Workspace - Event names are created dynamically from settings
1 parent 682c59c commit 330367c

File tree

4 files changed

+244
-41
lines changed

4 files changed

+244
-41
lines changed

src/autosar/xml/element.py

+147-15
Original file line numberDiff line numberDiff line change
@@ -2930,13 +2930,51 @@ def ref(self) -> PackageRef:
29302930
return None if ref_str is None else PackageRef(ref_str)
29312931

29322932

2933+
class BehaviorSettings:
2934+
"""
2935+
Enables users to customize settings in SwcInternalBehavior such as naming conventions.
2936+
"""
2937+
2938+
def __init__(self) -> None:
2939+
2940+
# Default prefix used for generating event names
2941+
self.background_event_prefix: str | None = None # BackgroundEvent prefix
2942+
self.data_receive_error_event_prefix: str | None = None # DataReceiveErrorEvent prefix
2943+
self.data_receive_event_prefix: str | None = None # DataReceivedEvent prefix
2944+
self.init_event_prefix: str | None = None # InitEvent prefix
2945+
self.operation_invoked_event_prefix: str | None = None # OperationInvokedEvent prefix
2946+
self.swc_mode_manager_error_event_prefix: str | None = None # SwcModeManagerErrorEvent prefix
2947+
self.swc_mode_switch_event_prefix: str | None = None # SwcModeSwitchEvent prefix
2948+
self.timing_event_prefix: str | None = None # TimingEvent prefix
2949+
2950+
def set_value(self, name: str, value: str):
2951+
"""
2952+
Updates a single value with error check
2953+
"""
2954+
if hasattr(self, name):
2955+
if not isinstance(value, str):
2956+
raise TypeError(f"value: Expected string type. Got {str(type(value))}")
2957+
setattr(self, name, value)
2958+
else:
2959+
raise KeyError(f"name: Invalid name '{name}'")
2960+
2961+
def update(self, value_map: dict[str, str]):
2962+
"""
2963+
Updates multiple values using keys in value_map, with error-check
2964+
"""
2965+
for name, value in value_map.items():
2966+
self.set_value(name, value)
2967+
2968+
29332969
class PackageCollection:
29342970
"""
29352971
Base class that maintains a collection of AUTOSAR packages
29362972
"""
29372973

2938-
def __init__(self, packages: list[Package] | None = None) -> None:
2974+
def __init__(self, packages: list[Package] | None = None,
2975+
behavior_settings: BehaviorSettings | None = None) -> None:
29392976
self.parent = None
2977+
self.behavior_settings = behavior_settings
29402978
self.packages: list[Package] = [] # .PACKAGES
29412979
self._package_dict = {} # internal package map
29422980
if packages is not None:
@@ -6304,6 +6342,16 @@ def _get_valid_parent(self) -> SwComponentType:
63046342
raise RuntimeError("Behavior object doesn't have a valid parent")
63056343
return self.parent
63066344

6345+
def _get_valid_behavior_settings(self) -> BehaviorSettings:
6346+
"""
6347+
Verifies that the root collection has a valid behavior_settings object and returns it
6348+
"""
6349+
swc = self._get_valid_parent()
6350+
workspace = swc.root_collection()
6351+
if not isinstance(workspace.behavior_settings, BehaviorSettings):
6352+
raise TypeError("Root collection doesn't seem to be a valid workspace")
6353+
return workspace.behavior_settings
6354+
63076355
def ref(self) -> SwcInternalBehaviorRef | None:
63086356
"""
63096357
Returns a reference to this element or
@@ -6377,8 +6425,8 @@ def _make_unique_event_name(self, event_name: str) -> str:
63776425
return event_name
63786426

63796427
def create_background_event(self,
6380-
event_name: str,
63816428
runnable_name: str,
6429+
event_name: str | None = None,
63826430
**kwargs
63836431
) -> BackgroundEvent:
63846432
"""
@@ -6387,15 +6435,24 @@ def create_background_event(self,
63876435
runnable = self.find_runnable(runnable_name)
63886436
if runnable is None:
63896437
raise KeyError(f"Found no runnable with name '{runnable_name}'")
6438+
if event_name is None:
6439+
behavior_settings = self._get_valid_behavior_settings()
6440+
if behavior_settings.background_event_prefix:
6441+
event_name = behavior_settings.background_event_prefix + runnable_name
6442+
else:
6443+
msg = "event_name: Unable to dynamically create event name,"\
6444+
" background_event_prefix is not set in behavior settings"
6445+
raise RuntimeError(msg)
6446+
assert isinstance(event_name, str)
63906447
unique_event_name = self._make_unique_event_name(event_name)
63916448
event = BackgroundEvent(unique_event_name, runnable.ref(), **kwargs)
63926449
self.append_event(event)
63936450
return event
63946451

63956452
def create_data_receive_error_event(self,
6396-
event_name: str,
63976453
runnable_name: str,
63986454
port_data_element: str,
6455+
event_name: str | None = None,
63996456
**kwargs
64006457
) -> DataReceiveErrorEvent:
64016458
"""
@@ -6408,7 +6465,6 @@ def create_data_receive_error_event(self,
64086465
runnable = self.find_runnable(runnable_name)
64096466
if runnable is None:
64106467
raise KeyError(f"Found no runnable with name '{runnable_name}'")
6411-
unique_event_name = self._make_unique_event_name(event_name)
64126468
name_parts = split_ref_strict(port_data_element)
64136469
if len(name_parts) == 1:
64146470
port_name, data_element_name = name_parts[0], None
@@ -6421,6 +6477,18 @@ def create_data_receive_error_event(self,
64216477
if target_data_element is None:
64226478
msg = f"port_data_element: '{port_data_element}' does not name an existing data element in port interface"
64236479
raise ValueError(msg)
6480+
if event_name is None:
6481+
behavior_settings = self._get_valid_behavior_settings()
6482+
if behavior_settings.data_receive_error_event_prefix:
6483+
event_name = behavior_settings.data_receive_error_event_prefix + "_".join([runnable_name,
6484+
context_port.name,
6485+
target_data_element.name])
6486+
else:
6487+
msg = "event_name: Unable to dynamically create event name,"\
6488+
" data_receive_error_event_prefix is not set in behavior settings"
6489+
raise RuntimeError(msg)
6490+
assert isinstance(event_name, str)
6491+
unique_event_name = self._make_unique_event_name(event_name)
64246492
event = DataReceiveErrorEvent.make(unique_event_name,
64256493
runnable.ref(),
64266494
context_port.ref(),
@@ -6430,9 +6498,9 @@ def create_data_receive_error_event(self,
64306498
return event
64316499

64326500
def create_data_received_event(self,
6433-
event_name: str,
64346501
runnable_name: str,
64356502
data_element_ref: str,
6503+
event_name: str | None = None,
64366504
**kwargs
64376505
) -> DataReceivedEvent:
64386506
"""
@@ -6445,7 +6513,6 @@ def create_data_received_event(self,
64456513
runnable = self.find_runnable(runnable_name)
64466514
if runnable is None:
64476515
raise KeyError(f"Found no runnable with name '{runnable_name}'")
6448-
unique_event_name = self._make_unique_event_name(event_name)
64496516
name_parts = split_ref_strict(data_element_ref)
64506517
if len(name_parts) == 1:
64516518
port_name, data_element_name = name_parts[0], None
@@ -6458,6 +6525,18 @@ def create_data_received_event(self,
64586525
if target_data_element is None:
64596526
msg = f"data_element_ref: '{data_element_ref}' does not name an existing data element in port interface"
64606527
raise ValueError(msg)
6528+
if event_name is None:
6529+
behavior_settings = self._get_valid_behavior_settings()
6530+
if behavior_settings.data_receive_event_prefix:
6531+
event_name = behavior_settings.data_receive_event_prefix + "_".join([runnable_name,
6532+
context_port.name,
6533+
target_data_element.name])
6534+
else:
6535+
msg = "event_name: Unable to dynamically create event name,"\
6536+
" data_receive_event_prefix is not set in behavior settings"
6537+
raise RuntimeError(msg)
6538+
assert isinstance(event_name, str)
6539+
unique_event_name = self._make_unique_event_name(event_name)
64616540
event = DataReceivedEvent.make(unique_event_name,
64626541
runnable.ref(),
64636542
context_port.ref(),
@@ -6467,9 +6546,9 @@ def create_data_received_event(self,
64676546
return event
64686547

64696548
def create_data_send_completed_event(self,
6470-
event_name: str,
64716549
runnable_name: str,
64726550
data_element_ref: str,
6551+
event_name: str | None = None,
64736552
**kwargs
64746553
) -> DataSendCompletedEvent:
64756554
"""
@@ -6483,9 +6562,9 @@ def create_data_send_completed_event(self,
64836562
raise NotImplementedError("References to data send points are not yet supported")
64846563

64856564
def create_data_write_completed_event(self,
6486-
event_name: str,
64876565
runnable_name: str,
64886566
data_element_ref: str,
6567+
event_name: str | None = None,
64896568
**kwargs
64906569
) -> DataWriteCompletedEvent:
64916570
"""
@@ -6499,8 +6578,8 @@ def create_data_write_completed_event(self,
64996578
raise NotImplementedError("References to data write access are not yet supported")
65006579

65016580
def create_init_event(self,
6502-
event_name: str,
65036581
runnable_name: str,
6582+
event_name: str | None = None,
65046583
**kwargs
65056584
) -> InitEvent:
65066585
"""
@@ -6509,15 +6588,24 @@ def create_init_event(self,
65096588
runnable = self.find_runnable(runnable_name)
65106589
if runnable is None:
65116590
raise KeyError(f"Found no runnable with name '{runnable_name}'")
6591+
if event_name is None:
6592+
behavior_settings = self._get_valid_behavior_settings()
6593+
if behavior_settings.init_event_prefix:
6594+
event_name = behavior_settings.init_event_prefix + runnable_name
6595+
else:
6596+
msg = "event_name: Unable to dynamically create event name,"\
6597+
" init_event_prefix is not set in behavior settings"
6598+
raise RuntimeError(msg)
6599+
assert isinstance(event_name, str)
65126600
unique_event_name = self._make_unique_event_name(event_name)
65136601
event = InitEvent(unique_event_name, runnable.ref(), **kwargs)
65146602
self.append_event(event)
65156603
return event
65166604

65176605
def create_operation_invoked_event(self,
6518-
event_name: str,
65196606
runnable_name: str,
65206607
operation_ref: str,
6608+
event_name: str | None = None,
65216609
**kwargs
65226610
) -> OperationInvokedEvent:
65236611
"""
@@ -6528,7 +6616,6 @@ def create_operation_invoked_event(self,
65286616
runnable = self.find_runnable(runnable_name)
65296617
if runnable is None:
65306618
raise KeyError(f"Found no runnable with name '{runnable_name}'")
6531-
unique_event_name = self._make_unique_event_name(event_name)
65326619
name_parts = split_ref_strict(operation_ref)
65336620
if len(name_parts) == 1:
65346621
port_name, operation_name = name_parts[0], None
@@ -6540,6 +6627,19 @@ def create_operation_invoked_event(self,
65406627
target_provided_operation = swc.get_operation_in_port(context_port, operation_name)
65416628
if target_provided_operation is None:
65426629
raise ValueError(f"operation_ref: '{operation_ref}' does not name a valid operation in port interface")
6630+
if event_name is None:
6631+
behavior_settings = self._get_valid_behavior_settings()
6632+
if behavior_settings.operation_invoked_event_prefix:
6633+
prefix = behavior_settings.operation_invoked_event_prefix
6634+
event_name = prefix + "_".join([runnable_name,
6635+
context_port.name,
6636+
target_provided_operation.name])
6637+
else:
6638+
msg = "event_name: Unable to dynamically create event name,"\
6639+
" operation_invoked_event_prefix is not set in behavior settings"
6640+
raise RuntimeError(msg)
6641+
assert isinstance(event_name, str)
6642+
unique_event_name = self._make_unique_event_name(event_name)
65436643
event = OperationInvokedEvent.make(unique_event_name,
65446644
runnable.ref(),
65456645
context_port.ref(),
@@ -6549,9 +6649,9 @@ def create_operation_invoked_event(self,
65496649
return event
65506650

65516651
def create_swc_mode_manager_error_event(self,
6552-
event_name: str,
65536652
runnable_name: str,
65546653
port_name: str,
6654+
event_name: str | None = None,
65556655
**kwargs
65566656
) -> SwcModeManagerErrorEvent:
65576657
"""
@@ -6561,14 +6661,26 @@ def create_swc_mode_manager_error_event(self,
65616661
runnable = self.find_runnable(runnable_name)
65626662
if runnable is None:
65636663
raise KeyError(f"Found no runnable with name '{runnable_name}'")
6564-
unique_event_name = self._make_unique_event_name(event_name)
65656664
context_port = swc.find_p_port(port_name)
65666665
if context_port is None:
65676666
raise ValueError(f"port_name: '{port_name}' does not name an existing P-PORT or PR-PORT")
65686667
context_mode_declaration_group = swc.get_mode_declaration_group_in_port(context_port)
65696668
if context_mode_declaration_group is None:
65706669
msg = f"port_name: '{port_name}' does not name a valid ModeDeclarationGroupPrototype in port interface"
65716670
raise ValueError(msg)
6671+
if event_name is None:
6672+
behavior_settings = self._get_valid_behavior_settings()
6673+
if behavior_settings.swc_mode_manager_error_event_prefix:
6674+
prefix = behavior_settings.swc_mode_manager_error_event_prefix
6675+
event_name = prefix + "_".join([runnable_name,
6676+
context_port.name,
6677+
context_mode_declaration_group.name])
6678+
else:
6679+
msg = "event_name: Unable to dynamically create event name,"\
6680+
" swc_mode_manager_error_event_prefix is not set in behavior settings"
6681+
raise RuntimeError(msg)
6682+
assert isinstance(event_name, str)
6683+
unique_event_name = self._make_unique_event_name(event_name)
65726684
event = SwcModeManagerErrorEvent.make(unique_event_name,
65736685
runnable.ref(),
65746686
context_port.ref(),
@@ -6578,10 +6690,10 @@ def create_swc_mode_manager_error_event(self,
65786690
return event
65796691

65806692
def create_swc_mode_mode_switch_event(self,
6581-
event_name: str,
65826693
runnable_name: str,
65836694
mode_ref: str | list[str] | tuple[str, str],
65846695
activation: ar_enum.ModeActivationKind | None = None,
6696+
event_name: str | None = None,
65856697
**kwargs
65866698
) -> SwcModeSwitchEvent:
65876699
"""
@@ -6596,6 +6708,16 @@ def create_swc_mode_mode_switch_event(self,
65966708
runnable = self.find_runnable(runnable_name)
65976709
if runnable is None:
65986710
raise KeyError(f"Found no runnable with name '{runnable_name}'")
6711+
if event_name is None:
6712+
behavior_settings = self._get_valid_behavior_settings()
6713+
if behavior_settings.swc_mode_switch_event_prefix:
6714+
prefix = behavior_settings.swc_mode_switch_event_prefix
6715+
event_name = prefix + runnable_name
6716+
else:
6717+
msg = "event_name: Unable to dynamically create event name,"\
6718+
" swc_mode_switch_event_prefix is not set in behavior settings"
6719+
raise RuntimeError(msg)
6720+
assert isinstance(event_name, str)
65996721
unique_event_name = self._make_unique_event_name(event_name)
66006722
if isinstance(mode_ref, str):
66016723
context_port, context_mode_declaration_group, target_mode_declaration = (
@@ -6628,17 +6750,27 @@ def create_swc_mode_mode_switch_event(self,
66286750
return event
66296751

66306752
def create_timing_event(self,
6631-
event_name: str,
66326753
runnable_name: str,
66336754
period: int | float | None = None,
66346755
offset: int | float | None = None,
6756+
event_name: str | None = None,
66356757
**kwargs) -> TimingEvent:
66366758
"""
66376759
Adds a new TimingEvent to this object
66386760
"""
66396761
runnable = self.find_runnable(runnable_name)
66406762
if runnable is None:
66416763
raise KeyError(f"Found no runnable with name '{runnable_name}'")
6764+
if event_name is None:
6765+
behavior_settings = self._get_valid_behavior_settings()
6766+
if behavior_settings.timing_event_prefix:
6767+
prefix = behavior_settings.timing_event_prefix
6768+
event_name = prefix + runnable_name
6769+
else:
6770+
msg = "event_name: Unable to dynamically create event name,"\
6771+
" timing_event_prefix is not set in behavior settings"
6772+
raise RuntimeError(msg)
6773+
assert isinstance(event_name, str)
66426774
unique_event_name = self._make_unique_event_name(event_name)
66436775
event = TimingEvent(unique_event_name, runnable.ref(), period, offset, **kwargs)
66446776
self.append_event(event)

src/autosar/xml/workspace.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,12 @@ class Workspace(ar_element.PackageCollection):
7979
"""
8080

8181
def __init__(self, config_file_path: str | None = None, document_root: str | None = None) -> None:
82+
super().__init__(behavior_settings=ar_element.BehaviorSettings())
8283
self.namespaces: dict[str, Namespace] = {}
8384
self.documents: list[DocumentConfig] = []
8485
self.document_mappings: list[PackageToDocumentMapping] = []
8586
self.document_root = document_root
8687
self.package_map: dict[str, ar_element.Package] = {} # Each key is user-defined
87-
super().__init__()
8888
if config_file_path is not None:
8989
self.load_config(config_file_path)
9090

@@ -219,6 +219,9 @@ def load_config(self, file_path: str) -> None:
219219
if document_mapping is not None:
220220
for mapping in document_mapping.values():
221221
self._create_document_mapping_from_config(mapping)
222+
behavior_settings = config.get("behavior", None)
223+
if behavior_settings is not None:
224+
self.behavior_settings.update(behavior_settings)
222225

223226
def _write_document_from_config(self,
224227
writer: Writer,

0 commit comments

Comments
 (0)