baldertest 0.1.0b11__py3-none-any.whl → 0.1.0b12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
_balder/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.1.0b11'
15
+ __version__ = version = '0.1.0b12'
16
16
  __version_tuple__ = version_tuple = (0, 1, 0)
@@ -1,4 +1,6 @@
1
1
  from __future__ import annotations
2
+
3
+ import copy
2
4
  from typing import Dict, List, Type, Union, TYPE_CHECKING
3
5
 
4
6
  import sys
@@ -443,10 +445,15 @@ class DeviceController(BaseDeviceController, ABC):
443
445
  if all_instanced_features is None:
444
446
  # has no features -> skip
445
447
  return
446
- for _, cur_feature in all_instanced_features.items():
447
- if cur_feature.active_vdevices != {}:
448
+ for cur_attr_name, cur_feature in all_instanced_features.items():
449
+ # clone feature and its active_device dict to make sure that shared instances in parent classes are handled
450
+ # correctly
451
+ new_feature = copy.copy(cur_feature)
452
+ new_feature.active_vdevices = {**cur_feature.active_vdevices}
453
+ setattr(self.related_cls, cur_attr_name, new_feature)
454
+ if new_feature.active_vdevices != {}:
448
455
  # do something only if there exists an internal mapping
449
- for cur_mapped_vdevice, cur_mapped_device in cur_feature.active_vdevices.items():
456
+ for cur_mapped_vdevice, cur_mapped_device in new_feature.active_vdevices.items():
450
457
  if isinstance(cur_mapped_device, str):
451
458
  resolved_device = \
452
459
  scenario_or_setup_controller.get_inner_device_class_by_string(cur_mapped_device)
@@ -454,5 +461,5 @@ class DeviceController(BaseDeviceController, ABC):
454
461
  raise RuntimeError(
455
462
  f"found no possible matching name while trying to resolve "
456
463
  f"the given vDevice string `{cur_mapped_vdevice}` in feature "
457
- f"`{cur_feature.__class__.__name__}`")
458
- cur_feature.active_vdevices[cur_mapped_vdevice] = resolved_device
464
+ f"`{new_feature.__class__.__name__}`")
465
+ new_feature.active_vdevices[cur_mapped_vdevice] = resolved_device
@@ -1,13 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
- import itertools
4
- from typing import Type, Union, List, Dict, Tuple, TYPE_CHECKING
3
+ from typing import Type, Union, List, Dict, TYPE_CHECKING
5
4
 
6
5
  import inspect
7
6
  import logging
8
7
  from _balder.cnnrelations import OrConnectionRelation
9
8
  from _balder.device import Device
10
9
  from _balder.connection import Connection
10
+ from _balder.feature_replacement_mapping import FeatureReplacementMapping
11
11
  from _balder.fixture_execution_level import FixtureExecutionLevel
12
12
  from _balder.testresult import ResultState, BranchBodyResult, ResultSummary
13
13
  from _balder.executor.basic_executable_executor import BasicExecutableExecutor
@@ -16,6 +16,7 @@ from _balder.executor.unresolved_parametrized_testcase_executor import Unresolve
16
16
  from _balder.previous_executor_mark import PreviousExecutorMark
17
17
  from _balder.routing_path import RoutingPath
18
18
  from _balder.unmapped_vdevice import UnmappedVDevice
19
+ from _balder.feature_vdevice_mapping import FeatureVDeviceMapping
19
20
  from _balder.controllers import DeviceController, VDeviceController, FeatureController, NormalScenarioSetupController
20
21
  from _balder.exceptions import NotApplicableVariationException, UnclearAssignableFeatureConnectionError
21
22
 
@@ -23,7 +24,6 @@ if TYPE_CHECKING:
23
24
  from _balder.setup import Setup
24
25
  from _balder.feature import Feature
25
26
  from _balder.scenario import Scenario
26
- from _balder.vdevice import VDevice
27
27
  from _balder.controllers.scenario_controller import ScenarioController
28
28
  from _balder.controllers.setup_controller import SetupController
29
29
  from _balder.executor.scenario_executor import ScenarioExecutor
@@ -50,12 +50,10 @@ class VariationExecutor(BasicExecutableExecutor):
50
50
  self._routings: Dict[Connection, List[RoutingPath]] = {}
51
51
  # buffer variable to save the feature replacement after it was determined with
52
52
  # `determine_feature_replacement_and_vdevice_mappings()`
53
- self._feature_replacement: \
54
- Union[None, Dict[Type[Device], Dict[str, Tuple[Union[Feature, None], Feature]]]] = None
53
+ self._feature_replacement: Union[None, Dict[Type[Device], FeatureReplacementMapping]] = None
55
54
  # buffer variable to save the feature replacement after it was determined with
56
55
  # `determine_feature_replacement_and_vdevice_mappings()`
57
- self._abs_setup_feature_vdevice_mappings: \
58
- Union[None, Dict[Type[Device], Dict[Feature, Dict[Type[VDevice], Type[Device]]]]] = None
56
+ self._abs_setup_feature_vdevice_mappings: Union[None, Dict[Type[Device], FeatureVDeviceMapping]] = None
59
57
 
60
58
  # contains the absolute scenario device connections for the current variation
61
59
  self._abs_variation_scenario_device_connections: Union[List[Connection], None] = None
@@ -67,8 +65,7 @@ class VariationExecutor(BasicExecutableExecutor):
67
65
  # contains the original active vdevice mappings for all scenario and setup devices (will be managed by
68
66
  # `update_active_vdevice_device_mappings_in_scenario_and_setup_devices()` and
69
67
  # `revert_active_vdevice_device_mappings_in_scenario_and_setup_devices()`)
70
- self._original_active_vdevice_mappings: \
71
- Dict[Type[Device], Dict[Feature, Dict[Type[VDevice], Type[Device]]]] = {}
68
+ self._original_active_vdevice_mappings: Dict[Type[Device], FeatureVDeviceMapping] = {}
72
69
 
73
70
  # is True if the applicability check was done
74
71
  self._applicability_check_done = False
@@ -138,18 +135,17 @@ class VariationExecutor(BasicExecutableExecutor):
138
135
  return self._fixture_manager
139
136
 
140
137
  @property
141
- def feature_replacement(self) -> Dict[Type[Device], Dict[str, Tuple[Union[Feature, None], Feature]]]:
138
+ def feature_replacement(self) -> Dict[Type[Device], FeatureReplacementMapping]:
142
139
  """
143
- this property is a dictionary with every scenario device as key and a dictionary as value - the value dictionary
144
- contains a tuple (inner dict value) for every attribute name(inner dict key) - the tuples always consist of two
145
- elements, the old feature as first item of the tuple (the instantiated feature from the scenario if it exists,
146
- otherwise this is None) and the new feature as second item (the feature of the related Setup-Device)
140
+ this property is a dictionary with every scenario device as key and feature-replacement-mapping as value - the
141
+ mappings hold at least information about the attribute name of the feature in scenario device, the old
142
+ scenario-feature the instantiated feature from the scenario if it exists, otherwise this is None) and the
143
+ new feature as second item (the feature of the related Setup-Device)
147
144
  """
148
145
  return self._feature_replacement
149
146
 
150
147
  @property
151
- def abs_setup_feature_vdevice_mappings(self) \
152
- -> Dict[Type[Device], Dict[Feature, Dict[Type[VDevice], Type[Device]]]]:
148
+ def abs_setup_feature_vdevice_mappings(self) -> Dict[Type[Device], FeatureVDeviceMapping]:
153
149
  """returns the feature replacement that was determined with
154
150
  `determine_feature_replacement_and_vdevice_mappings()`"""
155
151
  return self._abs_setup_feature_vdevice_mappings
@@ -230,26 +226,22 @@ class VariationExecutor(BasicExecutableExecutor):
230
226
  vDevices-Mappings (so the mapped setup-devices) implements all features that are defined in the vDevices
231
227
  """
232
228
 
233
- for cur_scenario_device, cur_replacement_dict in self.feature_replacement.items():
229
+ for cur_scenario_device, cur_replacement_mapping in self.feature_replacement.items():
234
230
  cur_setup_device = self.get_setup_device_for(scenario_device=cur_scenario_device)
235
231
  all_inner_setup_features = \
236
232
  DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
237
233
 
238
- # describes the mapping from the new setup feature (key) to the instantiated scenario feature (value)
239
- # note that this dictionary only contains the required one
240
- setup_to_scenario_feature_mapping: Dict[Type[Feature], Feature] = {
241
- cur_replacement_tuple[1]: cur_replacement_tuple[0]
242
- for cur_attr_name, cur_replacement_tuple in cur_replacement_dict.items()
243
- if cur_replacement_tuple[0] is not None}
244
-
245
234
  # now secure that all features are available in the corresponding setup device, that are defined in the
246
235
  # mapped vDevice
247
236
  for _, cur_setup_feature_obj in all_inner_setup_features.items():
248
- # only check if there is a requirement of this feature (the feature is required by the Scenario)
249
- if cur_setup_feature_obj.__class__ not in setup_to_scenario_feature_mapping.keys():
250
- # ignore this, because no requirement for this feature
237
+ related_scenario_feature_obj = \
238
+ cur_replacement_mapping.get_replaced_scenario_feature_for(cur_setup_feature_obj)
239
+
240
+ # only check if this feature is required by the scenario
241
+ if related_scenario_feature_obj is None:
242
+ # ignore this, because this feature is not used in the scenario
251
243
  continue
252
- related_scenario_feature_obj = setup_to_scenario_feature_mapping[cur_setup_feature_obj.__class__]
244
+
253
245
  # get vDevice and device mapping
254
246
  partner_scenario_vdevice, partner_scenario_device = \
255
247
  related_scenario_feature_obj.active_vdevice_device_mapping
@@ -258,7 +250,7 @@ class VariationExecutor(BasicExecutableExecutor):
258
250
  # ignore because no mapping exist here
259
251
  continue
260
252
 
261
- partner_setup_device = self.get_setup_device_for(scenario_device=partner_scenario_vdevice)
253
+ partner_setup_device = self.get_setup_device_for(scenario_device=partner_scenario_device)
262
254
  # get the related vDevice on setup view that is currently active
263
255
  mapped_setup_vdevices = [
264
256
  cur_vdevice for cur_vdevice
@@ -388,15 +380,20 @@ class VariationExecutor(BasicExecutableExecutor):
388
380
  :raises NotApplicableVariationError: will be thrown if this variation cannot be applied, because the setup-/
389
381
  scenario-device-features can not be resolved
390
382
  """
391
- feature_replacement = {scenario_dev: {} for scenario_dev in self.base_device_mapping.keys()}
392
- abs_setup_vdevice_mappings = {setup_dev: {} for setup_dev in self.base_device_mapping.values()}
383
+ feature_replacement = {
384
+ scenario_dev: FeatureReplacementMapping() for scenario_dev in self.base_device_mapping.keys()
385
+ }
386
+
387
+ abs_setup_vdevice_mappings = {
388
+ setup_dev: FeatureVDeviceMapping() for setup_dev in self.base_device_mapping.values()
389
+ }
393
390
  for cur_scenario_device, cur_setup_device in self.base_device_mapping.items():
394
391
  cur_setup_features = DeviceController.get_for(cur_setup_device).get_all_instantiated_feature_objects()
395
392
 
396
393
  all_assigned_setup_features = []
397
- cur_scenario_device_orig_features = \
398
- DeviceController.get_for(cur_scenario_device).get_original_instanced_feature_objects()
399
- for cur_attr_name, cur_scenario_feature_obj in cur_scenario_device_orig_features.items():
394
+ cur_scenario_device_features = \
395
+ DeviceController.get_for(cur_scenario_device).get_all_instantiated_feature_objects()
396
+ for cur_attr_name, cur_scenario_feature_obj in cur_scenario_device_features.items():
400
397
  active_scenario_vdevice, mapped_scenario_device = cur_scenario_feature_obj.active_vdevice_device_mapping
401
398
 
402
399
  cur_setup_feature_objs = self._get_matching_setup_features_for(
@@ -431,7 +428,7 @@ class VariationExecutor(BasicExecutableExecutor):
431
428
  f'`{cur_scenario_device.__name__}`) in setup device `{cur_setup_device.__name__}`')
432
429
 
433
430
  all_assigned_setup_features.append(cur_setup_feature_obj)
434
- if cur_attr_name not in feature_replacement[cur_scenario_device].keys():
431
+ if cur_attr_name not in feature_replacement[cur_scenario_device].attr_names:
435
432
  cleanup_feature_controller = FeatureController.get_for(cur_setup_feature_obj.__class__)
436
433
 
437
434
  used_setup_vdevice, mapped_setup_device = cur_setup_feature_obj.active_vdevice_device_mapping
@@ -446,26 +443,41 @@ class VariationExecutor(BasicExecutableExecutor):
446
443
  if cur_vdevice.__name__ == active_scenario_vdevice.__name__]
447
444
  used_setup_vdevice = setup_vdevices[0]
448
445
  # set the mapping
449
- abs_setup_vdevice_mappings[cur_setup_device][cur_setup_feature_obj] = {
450
- used_setup_vdevice: self.get_setup_device_for(mapped_scenario_device)}
446
+ abs_setup_vdevice_mappings[cur_setup_device].add(
447
+ feature=cur_setup_feature_obj,
448
+ mappings={
449
+ used_setup_vdevice: self.get_setup_device_for(mapped_scenario_device)
450
+ }
451
+ )
451
452
  # if there is a vDevice mapping on setup level, but not on scenario level, so directly update the
452
453
  # VDevice-Device-Mapping there
453
454
  elif mapped_scenario_device is None and mapped_setup_device is not None:
454
- abs_setup_vdevice_mappings[cur_setup_device][cur_setup_feature_obj] = {
455
- used_setup_vdevice: mapped_setup_device}
455
+ abs_setup_vdevice_mappings[cur_setup_device].add(
456
+ feature=cur_setup_feature_obj,
457
+ mappings={
458
+ used_setup_vdevice: mapped_setup_device
459
+ }
460
+ )
461
+
462
+ feature_replacement[cur_scenario_device].add(attr_name=cur_attr_name,
463
+ scenario_feature=cur_scenario_feature_obj,
464
+ setup_feature=cur_setup_feature_obj)
456
465
 
457
- feature_replacement[cur_scenario_device][cur_attr_name] = \
458
- (cur_scenario_feature_obj, cur_setup_feature_obj)
459
466
  # also add all setup features that are not assigned as autonomous features
460
467
  for cur_setup_feature in cur_setup_features.values():
461
468
  if cur_setup_feature not in all_assigned_setup_features:
462
469
  # determine free name
463
470
  idx = 0
464
471
  autonomous_name = None
465
- while autonomous_name is None or autonomous_name in feature_replacement[cur_scenario_device].keys():
472
+ while (autonomous_name is None
473
+ or autonomous_name in feature_replacement[cur_scenario_device].attr_names):
466
474
  autonomous_name = f"_autonomous_feat_{idx}"
467
475
  idx += 1
468
- feature_replacement[cur_scenario_device][autonomous_name] = (None, cur_setup_feature)
476
+ feature_replacement[cur_scenario_device].add(
477
+ attr_name=autonomous_name,
478
+ scenario_feature=None,
479
+ setup_feature=cur_setup_feature
480
+ )
469
481
 
470
482
  # set the result to internal properties
471
483
  self._feature_replacement = feature_replacement
@@ -531,20 +543,18 @@ class VariationExecutor(BasicExecutableExecutor):
531
543
  This method ensures that the (mostly abstract) feature instances of a scenario are exchanged with the
532
544
  feature instances of the assigned setup devices
533
545
  """
534
- for cur_scenario_device, cur_replacement_dict in self.feature_replacement.items():
535
- for cur_attr_name, cur_replacement_tuple in cur_replacement_dict.items():
536
- _, new_feature_obj = cur_replacement_tuple
537
- setattr(cur_scenario_device, cur_attr_name, new_feature_obj)
546
+ for cur_scenario_device, cur_replacement_mapping in self.feature_replacement.items():
547
+ for cur_feature_mapping in cur_replacement_mapping.mappings:
548
+ setattr(cur_scenario_device, cur_feature_mapping.attr_name, cur_feature_mapping.setup_feature)
538
549
 
539
550
  def revert_scenario_device_feature_instances(self):
540
551
  """
541
552
  This method ensures that all initialized feature instances of a scenario are set back to the initial given
542
553
  features.
543
554
  """
544
- for cur_scenario_device, cur_replacement_dict in self.feature_replacement.items():
545
- for cur_attr_name, cur_replacement_tuple in cur_replacement_dict.items():
546
- old_instantiated_feature_obj, _ = cur_replacement_tuple
547
- setattr(cur_scenario_device, cur_attr_name, old_instantiated_feature_obj)
555
+ for cur_scenario_device, cur_replacement_mapping in self.feature_replacement.items():
556
+ for cur_feature_mapping in cur_replacement_mapping.mappings:
557
+ setattr(cur_scenario_device, cur_feature_mapping.attr_name, cur_feature_mapping.scenario_feature)
548
558
 
549
559
  def update_active_vdevice_device_mappings_in_all_features(self):
550
560
  """
@@ -552,28 +562,28 @@ class VariationExecutor(BasicExecutableExecutor):
552
562
  scenario-device classes are set correctly.
553
563
  """
554
564
 
555
- for cur_setup_device, feature_dict in self.abs_setup_feature_vdevice_mappings.items():
565
+ for cur_setup_device, feature_vdevice_mapping in self.abs_setup_feature_vdevice_mappings.items():
556
566
  if cur_setup_device not in self._original_active_vdevice_mappings.keys():
557
- self._original_active_vdevice_mappings[cur_setup_device] = {}
558
- for cur_setup_feature, mapping_dict in feature_dict.items():
567
+ self._original_active_vdevice_mappings[cur_setup_device] = FeatureVDeviceMapping()
568
+ for cur_setup_feature in feature_vdevice_mapping.features:
569
+ vdev_dev_mappings_of_setup_feat = feature_vdevice_mapping.get_mappings_for_feature(cur_setup_feature)
559
570
 
560
- cur_setup_feature_vdevice = list(mapping_dict.keys())[0]
561
- cur_mapped_setup_device = list(mapping_dict.values())[0]
571
+ cur_setup_feature_vdevice = vdev_dev_mappings_of_setup_feat[0].vdevice
572
+ cur_mapped_setup_device = vdev_dev_mappings_of_setup_feat[0].device
562
573
 
563
574
  # first save old value to revert it later
564
- self._original_active_vdevice_mappings[cur_setup_device][cur_setup_feature] = \
565
- cur_setup_feature.active_vdevices
575
+ self._original_active_vdevice_mappings[cur_setup_device].add(
576
+ feature=cur_setup_feature,
577
+ mappings=cur_setup_feature.active_vdevices
578
+ )
566
579
  # now set new value
567
580
  cur_setup_feature.active_vdevices = {cur_setup_feature_vdevice: cur_mapped_setup_device}
568
581
 
569
582
  # now also determine the mapping for the scenario-feature (if there exists one)
570
583
  cur_scenario_device = self.get_scenario_device_for(cur_setup_device)
571
- cur_scenario_feature = None
572
- for cur_replacement_scenario_feature, cur_replacement_setup_feature in \
573
- self.feature_replacement[cur_scenario_device].values():
574
- if cur_replacement_setup_feature == cur_setup_feature:
575
- cur_scenario_feature = cur_replacement_scenario_feature
576
- break
584
+ cur_scenario_feature = self.feature_replacement[cur_scenario_device].get_replaced_scenario_feature_for(
585
+ cur_setup_feature
586
+ )
577
587
  if cur_scenario_feature is None:
578
588
  # there exists no scenario feature -> we can ignore this
579
589
  pass
@@ -587,10 +597,12 @@ class VariationExecutor(BasicExecutableExecutor):
587
597
  # only if there exists exactly one scenario vdevice with the same name
588
598
 
589
599
  if cur_scenario_device not in self._original_active_vdevice_mappings.keys():
590
- self._original_active_vdevice_mappings[cur_scenario_device] = {}
600
+ self._original_active_vdevice_mappings[cur_scenario_device] = FeatureVDeviceMapping()
591
601
  # first save old value to revert it later
592
- self._original_active_vdevice_mappings[cur_scenario_device][cur_scenario_feature] = \
593
- cur_scenario_feature.active_vdevices
602
+ self._original_active_vdevice_mappings[cur_scenario_device].add(
603
+ feature=cur_scenario_feature,
604
+ mappings=cur_scenario_feature.active_vdevices
605
+ )
594
606
  # now set new value
595
607
  cur_scenario_feature.active_vdevices = \
596
608
  {cur_scenario_feature_vdevice[0]: self.get_scenario_device_for(cur_mapped_setup_device)}
@@ -598,10 +610,14 @@ class VariationExecutor(BasicExecutableExecutor):
598
610
  def revert_active_vdevice_device_mappings_in_all_features(self):
599
611
  """
600
612
  This method ensures that the `active_vdevices` property that was changed with
601
- `update_active_vdevice_device_mappings()` will be reverted correctly.
613
+ `update_active_vdevice_device_mappings_in_all_features()` will be reverted correctly.
602
614
  """
603
- for _, cur_feature_mapping_dict in self._original_active_vdevice_mappings.items():
604
- for cur_feature, cur_original_mapping in cur_feature_mapping_dict.items():
615
+ for cur_feature_vdevice_mapping in self._original_active_vdevice_mappings.values():
616
+ for cur_feature in cur_feature_vdevice_mapping.features:
617
+ cur_original_mapping = {
618
+ mapping.vdevice:mapping.device
619
+ for mapping in cur_feature_vdevice_mapping.get_mappings_for_feature(cur_feature)
620
+ }
605
621
  cur_feature.active_vdevices = cur_original_mapping
606
622
 
607
623
  def exchange_unmapped_vdevice_references(self):
@@ -661,7 +677,7 @@ class VariationExecutor(BasicExecutableExecutor):
661
677
  cur_vdevice, cur_device = cur_feature.active_vdevice_device_mapping
662
678
  if cur_vdevice is not None and cur_device is not None:
663
679
  cur_vdevice_controller = VDeviceController.get_for(cur_vdevice)
664
- cur_vdevice_all_features = cur_vdevice_controller.get_original_instanced_feature_objects()
680
+ cur_vdevice_all_features = cur_vdevice_controller.get_all_instantiated_feature_objects()
665
681
 
666
682
  cur_device_controller = DeviceController.get_for(cur_device)
667
683
  cur_device_all_features = cur_device_controller.get_all_instantiated_feature_objects()
@@ -722,64 +738,54 @@ class VariationExecutor(BasicExecutableExecutor):
722
738
 
723
739
  # now iterate over every feature, that is used by the scenario and determine the class-based feature connections
724
740
  # of the mapped scenario feature (and its vDevice)
725
- for cur_setup_device, feature_dict in self.abs_setup_feature_vdevice_mappings.items():
741
+ for cur_setup_device, feature_vdev_mapping in self.abs_setup_feature_vdevice_mappings.items():
726
742
  cur_scenario_device = self.get_scenario_device_for(cur_setup_device)
727
- for cur_setup_feature, mapping_dict in feature_dict.items():
728
- feature_replacement = {
729
- cur_tuple[1]: cur_tuple[0] for _, cur_tuple in self.feature_replacement[cur_scenario_device].items()
730
- }
731
- cur_scenario_feature: Feature = feature_replacement[cur_setup_feature]
732
- cur_setup_feature_vdevice = list(mapping_dict.keys())[0]
733
- cur_mapped_setup_device = list(mapping_dict.values())[0]
743
+ for cur_setup_feature, vdev_mappings_of_setup_feature in feature_vdev_mapping.items():
744
+ cur_scenario_feature: Feature = (
745
+ self.feature_replacement[cur_scenario_device].get_replaced_scenario_feature_for(
746
+ setup_feature=cur_setup_feature)
747
+ )
734
748
 
735
- if cur_mapped_setup_device not in self.base_device_mapping.values():
749
+ if vdev_mappings_of_setup_feature[0].device not in self.base_device_mapping.values():
736
750
  raise NotApplicableVariationException(
737
- f'the mapped setup device `{cur_mapped_setup_device.__qualname__}` which is mapped to the '
738
- f'VDevice `{cur_setup_feature_vdevice.__qualname__}` is no part of this variation')
751
+ f'the mapped setup device `{vdev_mappings_of_setup_feature[0].device.__qualname__}` which is '
752
+ f'mapped to the VDevice `{vdev_mappings_of_setup_feature[0].vdevice.__qualname__}` is no part '
753
+ f'of this variation')
739
754
 
740
- cur_mapped_scenario_device = self.get_scenario_device_for(cur_mapped_setup_device)
755
+ cur_mapped_scenario_device = self.get_scenario_device_for(vdev_mappings_of_setup_feature[0].device)
741
756
 
742
757
  # get relevant class based connections for the current feature on setup level (this is really be used
743
758
  # here)
744
- feature_cnn = \
745
- FeatureController.get_for(
746
- cur_setup_feature.__class__).get_abs_class_based_for_vdevice()[cur_setup_feature_vdevice]
759
+ feat_cnn = FeatureController.get_for(cur_setup_feature.__class__)\
760
+ .get_abs_class_based_for_vdevice()[vdev_mappings_of_setup_feature[0].vdevice]
747
761
  # connection that are relevant for this feature
748
762
  relevant_cnns = [
749
763
  cnn for cnn in abs_var_scenario_device_cnns
750
- if cnn.has_connection_from_to(cur_scenario_device, end_device=cur_mapped_scenario_device)
764
+ if (cnn.has_connection_from_to(cur_scenario_device, end_device=cur_mapped_scenario_device)
765
+ and max(single_feat_cnn.contained_in(cnn, ignore_metadata=True)
766
+ for single_feat_cnn in feat_cnn.get_singles())
767
+ )
751
768
  ]
752
769
 
753
- relevant_device_cnn = None
754
-
755
770
  if len(relevant_cnns) > 1:
756
- # we have parallel possibilities -> determine the selected one (only one is allowed to fit)
757
- for cur_relevant_cnn in relevant_cnns:
758
- for cur_relevant_single_cnn, cur_feature_single_cnn in (
759
- itertools.product(cur_relevant_cnn.get_singles(), feature_cnn.get_singles())):
760
- if not cur_feature_single_cnn.contained_in(cur_relevant_single_cnn, ignore_metadata=True):
761
- continue
762
- if relevant_device_cnn is not None:
763
- raise UnclearAssignableFeatureConnectionError(
764
- f"the devices {cur_scenario_device.__name__} and "
765
- f"{cur_mapped_scenario_device.__name__} have multiple parallel connections - the "
766
- f"device `{cur_scenario_device.__name__}` uses a feature "
767
- f"`{cur_scenario_feature.__class__.__name__}` that matches with the device "
768
- f"`{cur_mapped_scenario_device.__name__}`, but it is not clear which of the "
769
- f"parallel connection could be used"
770
- )
771
- relevant_device_cnn = cur_relevant_cnn
772
- elif len(relevant_cnns) == 1:
773
- relevant_device_cnn = relevant_cnns[0]
774
- if relevant_device_cnn is None:
771
+ raise UnclearAssignableFeatureConnectionError(
772
+ f"the devices {cur_scenario_device.__name__} and {cur_mapped_scenario_device.__name__} have "
773
+ f"multiple parallel connections - the device `{cur_scenario_device.__name__}` uses a feature "
774
+ f"`{cur_scenario_feature.__class__.__name__}` that matches with the device "
775
+ f"`{cur_mapped_scenario_device.__name__}`, but it is not clear which of the parallel "
776
+ f"connection could be used")
777
+
778
+ if len(relevant_cnns) == 0:
775
779
  # todo this does not map here
776
780
  raise ValueError("can not find matching connection on scenario level")
777
781
 
782
+ relevant_device_cnn = relevant_cnns[0]
783
+
778
784
  # now cleanup the scenario-device connection `relevant_device_cnn` according to the class-based feature
779
785
  # connection
780
786
  new_cnn_to_replace = Connection.based_on(OrConnectionRelation(*[
781
787
  cur_old_cnn_single for cur_old_cnn_single in relevant_device_cnn.get_singles()
782
- if feature_cnn.contained_in(cur_old_cnn_single, ignore_metadata=True)
788
+ if feat_cnn.contained_in(cur_old_cnn_single, ignore_metadata=True)
783
789
  ]))
784
790
  new_cnn_to_replace.set_metadata_for_all_subitems(relevant_device_cnn.metadata)
785
791
 
@@ -0,0 +1,69 @@
1
+ from typing import Union
2
+ import dataclasses
3
+ from .feature import Feature
4
+
5
+
6
+ class FeatureReplacementMapping:
7
+ """
8
+ helper object that stores mappings between scenario and setup features - is used in :class:`VariationExecutor`
9
+ """
10
+
11
+ @dataclasses.dataclass
12
+ class FeatureMapping:
13
+ """
14
+ stores a single mapping
15
+ """
16
+ #: the feature attribute name in scenario device
17
+ attr_name: str
18
+ #: the scenario feature instance or None if the current variation does not use this setup feature in scenario
19
+ scenario_feature: Union[Feature, None]
20
+ #: the setup feature that is used for the scenario feature
21
+ setup_feature: Feature
22
+
23
+ def __init__(self):
24
+ self._mappings: list[FeatureReplacementMapping.FeatureMapping] = []
25
+
26
+ @property
27
+ def mappings(self) -> list[FeatureMapping]:
28
+ """
29
+ returns all existing mappings
30
+ """
31
+ return list(self._mappings)
32
+
33
+ @property
34
+ def attr_names(self) -> list[str]:
35
+ """
36
+ returns all used attribute names
37
+ """
38
+ return [mapping.attr_name for mapping in self._mappings]
39
+
40
+ def add(self, attr_name: str, scenario_feature: Union[Feature, None], setup_feature: Feature):
41
+ """
42
+ adds a new mapping
43
+
44
+ :param attr_name: the feature attribute name in scenario device
45
+ :param scenario_feature: the scenario feature instance or None if the current variation does not use this setup
46
+ feature in scenario
47
+ :param setup_feature: the setup feature that is used for the scenario feature
48
+ """
49
+ if attr_name in self.attr_names:
50
+ raise KeyError(f'entry for property name `{attr_name}` already exist - can not define it multiple times')
51
+ self._mappings.append(FeatureReplacementMapping.FeatureMapping(attr_name, scenario_feature, setup_feature))
52
+
53
+ def get_features_for_attr_name(self, attr_name: str) -> tuple[Feature, Feature]:
54
+ """
55
+ returns the scenario and its mapped setup feature for a specific attribute name used in the scenario device
56
+ """
57
+ for mapping in self._mappings:
58
+ if mapping.attr_name == attr_name:
59
+ return mapping.scenario_feature, mapping.setup_feature
60
+ raise KeyError(f'entry for property name `{attr_name}` does not exist')
61
+
62
+ def get_replaced_scenario_feature_for(self, setup_feature: Feature) -> Union[Feature, None]:
63
+ """
64
+ returns the mapped scenario feature for a given setup feature
65
+ """
66
+ for mapping in self._mappings:
67
+ if mapping.setup_feature == setup_feature:
68
+ return mapping.scenario_feature
69
+ raise KeyError(f'cannot find setup feature for {setup_feature}')
@@ -0,0 +1,88 @@
1
+ from __future__ import annotations
2
+ from typing import Type
3
+ import dataclasses
4
+
5
+ from .controllers.feature_controller import FeatureController
6
+ from .device import Device
7
+ from .feature import Feature
8
+ from .vdevice import VDevice
9
+
10
+
11
+ class FeatureVDeviceMapping:
12
+ """
13
+ helper object that stores mappings between :class:`VDevice` and :class:`Device`
14
+ """
15
+
16
+ @dataclasses.dataclass
17
+ class VDeviceDeviceMapping:
18
+ """describes the mapping of one VDevice to one Device"""
19
+ #: the vdevice class
20
+ vdevice: Type[VDevice]
21
+ #: the mapped device to this VDevice
22
+ device: Type[Device]
23
+
24
+ @dataclasses.dataclass
25
+ class VDevicesMapping:
26
+ """
27
+ stores a single mapping
28
+ """
29
+ #: the feature object, this mapping belongs to
30
+ feature: Feature
31
+ #: the available mapping for this feature (at the moment, we only support one)
32
+ mappings: list[FeatureVDeviceMapping.VDeviceDeviceMapping]
33
+
34
+ def __init__(self):
35
+ self._mappings: list[FeatureVDeviceMapping.VDevicesMapping] = []
36
+
37
+ @property
38
+ def mappings(self) -> list[VDevicesMapping]:
39
+ """
40
+ returns all existing mappings
41
+ """
42
+ return list(self._mappings)
43
+
44
+ @property
45
+ def features(self) -> list[Feature]:
46
+ """
47
+ returns all used attribute names
48
+ """
49
+ return [mapping.feature for mapping in self._mappings]
50
+
51
+ def items(self) -> list[tuple[Feature, list[VDeviceDeviceMapping]]]:
52
+ """
53
+ :return: a list of Feature/vdevice mapping tuples
54
+ """
55
+ return [(mapping.feature, mapping.mappings) for mapping in self._mappings]
56
+
57
+ def add(self, feature: Feature, mappings: dict[Type[VDevice], Type[Device]]):
58
+ """
59
+ adds a new mapping
60
+
61
+ :param feature: the :class:`Feature` class this mapping belongs to
62
+ :param mappings: a dictionary that describes the mapping between the :class:`VDevice` and :class:`Device`. The
63
+ :class:`VDevice` needs to be part of the :class:`Feature`
64
+ """
65
+ if feature in self.features:
66
+ raise KeyError(f'entry for feature `{feature}` already exist - can not define it multiple times')
67
+ feature_controller = FeatureController.get_for(feature.__class__)
68
+ vdevice_device_mappings = []
69
+ for cur_vdev, cur_dev in mappings.items():
70
+ if not (isinstance(cur_vdev, type) and issubclass(cur_vdev, VDevice)):
71
+ raise TypeError(f'the provided key objects in mappings needs to be a subclass of `{VDevice.__name__}`')
72
+ if not (isinstance(cur_dev, type) and issubclass(cur_dev, Device)):
73
+ raise TypeError(f'the provided value objects in mappings needs to be a subclass of `{Device.__name__}`')
74
+ if cur_vdev not in feature_controller.get_abs_inner_vdevice_classes():
75
+ raise ValueError(f'the provided VDevice `{cur_vdev}` is not part of the provided feature `{feature}`')
76
+ vdevice_device_mappings.append(self.VDeviceDeviceMapping(cur_vdev, cur_dev))
77
+ new_mapping = self.VDevicesMapping(feature=feature, mappings=vdevice_device_mappings)
78
+
79
+ self._mappings.append(new_mapping)
80
+
81
+ def get_mappings_for_feature(self, feature: Feature) -> list[VDeviceDeviceMapping]:
82
+ """
83
+ returns the list with all mappings for the provided feature
84
+ """
85
+ for cur_item in self._mappings:
86
+ if cur_item.feature == feature:
87
+ return cur_item.mappings
88
+ raise KeyError(f'entry for feature `{feature}` does not exist')
_balder/routing_path.py CHANGED
@@ -96,12 +96,15 @@ class RoutingPath:
96
96
  for cur_from_setup_node_conn in setup_devices_cnns:
97
97
  # only if there is a connection outgoing from `from_setup_device`
98
98
  if cur_from_setup_node_conn.has_connection_from_to(start_device=from_setup_device):
99
- cur_from_setup_node = cur_from_setup_node_conn.from_node_name \
100
- if cur_from_setup_node_conn.from_device == from_setup_device \
101
- else cur_from_setup_node_conn.to_node_name
102
- new_route = RoutingPath(cur_from_setup_node_conn, start_device=from_setup_device,
103
- start_node_name=cur_from_setup_node)
104
- all_possible_routes.append(new_route)
99
+ all_possible_routes.append(
100
+ RoutingPath(
101
+ cur_from_setup_node_conn,
102
+ start_device=from_setup_device,
103
+ start_node_name=(cur_from_setup_node_conn.from_node_name
104
+ if cur_from_setup_node_conn.from_device == from_setup_device
105
+ else cur_from_setup_node_conn.to_node_name)
106
+ )
107
+ )
105
108
  # now go through every possibility and add them - filter all Routes that ``has_loop() == True`` or
106
109
  # are completed
107
110
  while len(all_possible_routes) > 0:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: baldertest
3
- Version: 0.1.0b11
3
+ Version: 0.1.0b12
4
4
  Summary: balder: reusable scenario based test framework
5
5
  Home-page: https://docs.balder.dev
6
6
  Author: Max Stahlschmidt and others
@@ -1,5 +1,5 @@
1
1
  _balder/__init__.py,sha256=Qk4wkVInPlXLFV36Yco5K7PDawJoeeWQVakzj6g5pmA,195
2
- _balder/_version.py,sha256=fgSwP5K0NJOmhZpDfiqSUfFysLGqMES9LZQlLZ92X9Q,414
2
+ _balder/_version.py,sha256=S15DTS8dk0LprNo0fc6N8N7MUlyHFciSG3FMI5y2iZE,414
3
3
  _balder/balder_plugin.py,sha256=EQzJP1dwwVDydhMLJtAmTCXOczlDuXBJur05lalmK_k,3136
4
4
  _balder/balder_session.py,sha256=ezT86gC_VzPQZOQ4r5qQ75IEm6rXZHiIpEqZDczkRsE,16149
5
5
  _balder/balder_settings.py,sha256=U96PVep7dGSaTXrMfeZMYf6oCIcEDPEqrBlFcoX476s,582
@@ -18,6 +18,8 @@ _balder/device.py,sha256=5O3tqj_iLKfHb5Zi_viJ76VH82cMOzX58OzRrMRRv0k,833
18
18
  _balder/exceptions.py,sha256=_zQFUK4kYKaVGUtH9IcH0q-GOyBb9qzqSU6BOsUnG7Y,4375
19
19
  _balder/exit_code.py,sha256=P0oFWKfjMo36Frv13ADRcm8eSPN3kE-WmZBE9qZJHdA,513
20
20
  _balder/feature.py,sha256=Da6BP4H1X0eKm0DyQKRdSnrQeqV8QeCFE4JybI_wYSc,3888
21
+ _balder/feature_replacement_mapping.py,sha256=fCUnWY3pSJqPrdN_kA4jzkfzx7UYSkBDm6NbC2A522c,2766
22
+ _balder/feature_vdevice_mapping.py,sha256=aAQ8R48orYiOr_9_L8nZCz3jq5-qlq9gfY7DeTzmUyM,3576
21
23
  _balder/fixture_definition_scope.py,sha256=0MP0U2fcM9iS28Ytkfuu3TzZ4cUNG5u81GBWGBm9ucw,709
22
24
  _balder/fixture_execution_level.py,sha256=-y7-4bihTSMzhYvM2O1Qc40ovyvW7SP25rHvWHZpD6g,655
23
25
  _balder/fixture_manager.py,sha256=RjAQjpvBBGy-loCVCHlkArvyr35rr4shNWUpeY-0QP4,29227
@@ -26,7 +28,7 @@ _balder/node_gateway.py,sha256=64mv7Nx82JVknnQ09UXC-AcdDl6i_OB6NOsq_uBxeYo,4710
26
28
  _balder/parametrization.py,sha256=SnaGeGpf7-5H-y107CBDx5V-onX-oiLS1KU1IquZwcU,2678
27
29
  _balder/plugin_manager.py,sha256=Ev2jnx4NtFHDsZ3C6h0HrJtQisqLO-V34JRM3wzTnFM,6921
28
30
  _balder/previous_executor_mark.py,sha256=gwpGu7d-kwPzQT8CmaPfuEG6fess2Upf5Q-zX6Oi6NY,835
29
- _balder/routing_path.py,sha256=cHDjIIZbCeFHe_JX3kp3XADg3CApxGaKwTYQAPpCYZA,16767
31
+ _balder/routing_path.py,sha256=pyPaLD_-SyX3PZDWI6BUHHrIIPg3k5swfxFI6ncf2iA,16803
30
32
  _balder/scenario.py,sha256=ATowBUl2HYQBmJHZ-eBpliqjPsWPnZAme9kwIeX3Tak,840
31
33
  _balder/setup.py,sha256=zSgtzNIWTVBjiZ5mn-qfpqIAnP3Im73t3Lqoaw0gWEI,763
32
34
  _balder/solver.py,sha256=NbpAdvrGWdJTY6eZmNZFr7YDubyggY0yW64rDB3JkT0,13121
@@ -43,7 +45,7 @@ _balder/console/balder.py,sha256=rF1qgW6h35hKqGijGbZgGD2_y0Sd9Mbs_EXF2v_EUCk,258
43
45
  _balder/controllers/__init__.py,sha256=UNb6QzMj4TqPI15OSvXyUJlA-NSai0CKkQhV5JIsba0,570
44
46
  _balder/controllers/base_device_controller.py,sha256=g-vY2SqKFUC9yGOvHLfbdmILT3sK2YyaWKSfvTRcC0o,3174
45
47
  _balder/controllers/controller.py,sha256=XGRE5LKWxxftEf-bZODvKxXwULu09iG131wMwRoz4Fk,803
46
- _balder/controllers/device_controller.py,sha256=MXX_Jr7MFhsEq-2GzneA0c09X-wdcPGEPfiYLlrtiSc,23985
48
+ _balder/controllers/device_controller.py,sha256=_Leg_qYnuAQGVmqO77oJOm77EXSYRi7I1e38ZevgcEw,24343
47
49
  _balder/controllers/feature_controller.py,sha256=ve7t9zwhkPP-L_LZbKghdD6An2LO2TYWErAfN9dfRdQ,41405
48
50
  _balder/controllers/normal_scenario_setup_controller.py,sha256=w7VBxnrFu7_NBeTRD-XZBRflBjA8MPD_aL0DTh7w_pU,21924
49
51
  _balder/controllers/scenario_controller.py,sha256=sfCpR4NfWgEIksVV3dP8gko95vu_6FBMseU5Pb_CBZk,22354
@@ -58,7 +60,7 @@ _balder/executor/scenario_executor.py,sha256=3-CkamjyIatDxS3INcYGTXDOtGR-bokcMLa
58
60
  _balder/executor/setup_executor.py,sha256=Icn-b3MHLMCGGOIGAPB01KWC6LkkZ-ikD_0XqcQjK0Y,8570
59
61
  _balder/executor/testcase_executor.py,sha256=xSOjDexvcUET6vfwn1ogOs1Xi-9yeCt2AsnivXZkTao,7702
60
62
  _balder/executor/unresolved_parametrized_testcase_executor.py,sha256=nwScqqiJD7Clkk3YcrPqXJnGEWjvunAlUYAwYvpUI2s,9075
61
- _balder/executor/variation_executor.py,sha256=lfBVnGC5O8DeS8e9rJQjDlRauAMa7Vrhtcd7Smrwagg,53649
63
+ _balder/executor/variation_executor.py,sha256=PBkhNvucf7oPIrDiFSbcy8f7g-KfLOKMLSfTWAuCDVk,53093
62
64
  _balder/objects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
65
  _balder/objects/connections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
66
  _balder/objects/connections/osi_1_physical.py,sha256=74lKWJd6ETEtvNXH0_dmTbkZlStJ_af218pQkUht0aA,2189
@@ -75,9 +77,9 @@ balder/connections.py,sha256=H6rf7UsiVY_FeZLngZXCT9WDw9cQqpiDiPbz_0J4yjM,2331
75
77
  balder/devices.py,sha256=zupHtz8yaiEjzR8CrvgZU-RzsDQcZFeN5mObfhtjwSw,173
76
78
  balder/exceptions.py,sha256=iaR4P2L7K3LggYSDnjCGLheZEaGgnMilxDQdoYD5KHQ,1954
77
79
  balder/parametrization.py,sha256=R8U67f6DEnXdDc9cGOgS8yFTEAfhglv1v9mnAUAExUg,150
78
- baldertest-0.1.0b11.dist-info/LICENSE,sha256=Daz9qTpqbiq-klWb2Q9lYOmn3rJ5oIQnbs62sGcqOZ4,1084
79
- baldertest-0.1.0b11.dist-info/METADATA,sha256=zFBAEOFb5RiSNIk31ATneqnYvTrqD6d-oLZjG_vOklU,15784
80
- baldertest-0.1.0b11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
81
- baldertest-0.1.0b11.dist-info/entry_points.txt,sha256=hzqu_nrMKTCi5IJqzS1fhIXWEiL7mTGZ-kgj2lUYlRU,65
82
- baldertest-0.1.0b11.dist-info/top_level.txt,sha256=RUkIBkNLqHMemx2C9aEpoS65dpqb6_jU-oagIPxGQEA,15
83
- baldertest-0.1.0b11.dist-info/RECORD,,
80
+ baldertest-0.1.0b12.dist-info/LICENSE,sha256=Daz9qTpqbiq-klWb2Q9lYOmn3rJ5oIQnbs62sGcqOZ4,1084
81
+ baldertest-0.1.0b12.dist-info/METADATA,sha256=UmZEcpV1c0RcuZGHol2Q08Z5OPKkcYop47aM2iPjBoU,15784
82
+ baldertest-0.1.0b12.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
83
+ baldertest-0.1.0b12.dist-info/entry_points.txt,sha256=hzqu_nrMKTCi5IJqzS1fhIXWEiL7mTGZ-kgj2lUYlRU,65
84
+ baldertest-0.1.0b12.dist-info/top_level.txt,sha256=RUkIBkNLqHMemx2C9aEpoS65dpqb6_jU-oagIPxGQEA,15
85
+ baldertest-0.1.0b12.dist-info/RECORD,,