@@ -241,6 +241,62 @@ def based_on_elements(self) -> OrConnectionRelation:
241
241
242
242
# ---------------------------------- PROTECTED METHODS -------------------------------------------------------------
243
243
244
+ def _is_directly_contained_in (self , other_conn : Connection , ignore_metadata : bool ) -> bool :
245
+ """
246
+ Helper method that returns true if this connection is directly contained in the `other_conn`.
247
+
248
+ .. note::
249
+ 'Directly contained-in' means that the resolved versions of both connections are of the same connection
250
+ type, and the elements of that connection are directly embedded within one another from that point onward.
251
+ It does not check deeper into the other_conn.
252
+
253
+ :param other_conn: the other connection
254
+ :param ignore_metadata: True, if the metadata should be ignored
255
+ """
256
+
257
+ resolved_self = self .get_resolved ()
258
+ resolved_other = other_conn .get_resolved ()
259
+
260
+ if resolved_self .__class__ == Connection and len (resolved_self .based_on_elements ) == 0 or \
261
+ resolved_other .__class__ == Connection and len (resolved_other .based_on_elements ) == 0 :
262
+ # one of the resolved object is a raw `Connection` object without based-on-elements -> always true
263
+ return True
264
+
265
+ if resolved_self .__class__ == Connection :
266
+ return resolved_self .based_on_elements .contained_in (resolved_other , ignore_metadata = ignore_metadata )
267
+
268
+ if resolved_self .__class__ == resolved_other .__class__ :
269
+ # The element itself has already matched, now we still have to check whether at least one inner element
270
+ # of this type is contained in minimum one element of the other
271
+ singles_self = resolved_self .get_singles ()
272
+ singles_other = other_conn .get_singles ()
273
+
274
+ # check that for one single_self element all hierarchical based_on elements are in one of the single
275
+ # other element
276
+ for cur_single_self , cur_single_other in itertools .product (singles_self , singles_other ):
277
+ # check if both consists of only one element
278
+ if len (cur_single_self .based_on_elements ) == 0 :
279
+ # the cur self single is only one element -> this is contained in the other
280
+ return True
281
+
282
+ if len (cur_single_other .based_on_elements ) == 0 :
283
+ # the other element is only one element, but the self element not -> contained_in
284
+ # for this single definitely false
285
+ continue
286
+
287
+ # note: for both only one `based_on_elements` is possible, because they are singles
288
+ self_first_basedon = cur_single_self .based_on_elements [0 ]
289
+ other_first_basedon = cur_single_other .based_on_elements [0 ]
290
+
291
+ if isinstance (self_first_basedon , Connection ) and \
292
+ isinstance (other_first_basedon , AndConnectionRelation ):
293
+ continue
294
+
295
+ # find a complete valid match
296
+ if self_first_basedon .contained_in (other_first_basedon , ignore_metadata = ignore_metadata ):
297
+ return True
298
+ return False
299
+
244
300
# ---------------------------------- METHODS -----------------------------------------------------------------------
245
301
246
302
def get_intersection_with_other_single (
@@ -656,9 +712,10 @@ def contained_in(
656
712
ignore_metadata = False
657
713
) -> bool :
658
714
"""
659
- This method helps to find out whether this connection-tree fits within another connection tree. A connection
660
- object is a certain part of the large connection tree that Balder has at its disposal. This method checks
661
- whether a possibility of this connection tree fits in one possibility of the given connection tree.
715
+ This method determines if one connection tree can be embedded within another connection tree. A connection
716
+ object represents a specific segment of the extensive connection tree managed by Balder. The method evaluates
717
+ whether at least one SINGLE connection object of this connection tree fits within a possible SINGLE connection
718
+ of the provided connection `other_conn`.
662
719
663
720
.. note::
664
721
The method returns true if one single connection of this object fits in another single connection that is
@@ -681,63 +738,26 @@ def contained_in(
681
738
resolved_self = self .get_resolved ()
682
739
resolved_other = other_conn .get_resolved ()
683
740
684
- if resolved_self .__class__ == Connection and len (resolved_self .based_on_elements ) == 0 or \
685
- resolved_other .__class__ == Connection and len (resolved_other .based_on_elements ) == 0 :
686
- # one of the resolved object is a raw `Connection` object without based-on-elements -> always true
741
+ if self ._is_directly_contained_in (resolved_other , ignore_metadata = ignore_metadata ):
687
742
return True
688
743
689
- if resolved_self .__class__ == Connection :
690
- return resolved_self .based_on_elements .contained_in (resolved_other , ignore_metadata = ignore_metadata )
691
-
692
- if resolved_self .__class__ == resolved_other .__class__ :
693
- # The element itself has already matched, now we still have to check whether at least one inner element
694
- # of this type is contained in the minimum one element of the other
695
- singles_self = resolved_self .get_singles ()
696
- singles_other = resolved_other .get_singles ()
744
+ # the elements itself do not match -> go deeper within the other connection
697
745
698
- # check that for one single_self element all hierarchical based_on elements are in one of the single
699
- # other element
700
- for cur_single_self , cur_single_other in itertools .product (singles_self , singles_other ):
701
- # check if both consists of only one element
702
- if len (cur_single_self .based_on_elements ) == 0 :
703
- # the cur self single is only one element -> this is contained in the other
704
- return True
746
+ resolved_other_relation = resolved_other .based_on_elements \
747
+ if isinstance (resolved_other , Connection ) else resolved_other
705
748
706
- if len (cur_single_other .based_on_elements ) == 0 :
707
- # the other element is only one element, but the self element not -> contained_in
708
- # for this single definitely false
709
- continue
710
-
711
- # note: for both only one `based_on_elements` is possible, because they are singles
712
- self_first_basedon = cur_single_self .based_on_elements [0 ]
713
- other_first_basedon = cur_single_other .based_on_elements [0 ]
714
-
715
- if isinstance (self_first_basedon , Connection ) and \
716
- isinstance (other_first_basedon , AndConnectionRelation ):
717
- continue
718
-
719
- # find a complete valid match
720
- if self_first_basedon .contained_in (other_first_basedon , ignore_metadata = ignore_metadata ):
721
- return True
722
-
723
- else :
724
- # the elements itself do not match -> go deeper within the other connection
725
-
726
- resolved_other_relation = resolved_other .based_on_elements \
727
- if isinstance (resolved_other , Connection ) else resolved_other
728
-
729
- for cur_other_based_on in resolved_other_relation .connections :
730
- # `cur_other_based_on` can only be a Connection or an AND (resolved can not ba a inner OR)
731
- if isinstance (cur_other_based_on , AndConnectionRelation ):
732
- # check if the current connection fits in one of the AND relation items -> allowed too (f.e. a
733
- # smaller AND contained in a bigger AND)
734
- for cur_other_and_element in cur_other_based_on .connections :
735
- if resolved_self .contained_in (cur_other_and_element , ignore_metadata = ignore_metadata ):
736
- return True
737
- else :
738
- if resolved_self .contained_in (cur_other_based_on , ignore_metadata = ignore_metadata ):
739
- # element was found in this branch
749
+ for cur_other_based_on in resolved_other_relation .connections :
750
+ # `cur_other_based_on` can only be a Connection or an AND (resolved can not ba a inner OR)
751
+ if isinstance (cur_other_based_on , AndConnectionRelation ):
752
+ # check if the current connection fits in one of the AND relation items -> allowed too (f.e. a
753
+ # smaller AND contained in a bigger AND)
754
+ for cur_other_and_element in cur_other_based_on .connections :
755
+ if resolved_self .contained_in (cur_other_and_element , ignore_metadata = ignore_metadata ):
740
756
return True
757
+ else :
758
+ if resolved_self .contained_in (cur_other_based_on , ignore_metadata = ignore_metadata ):
759
+ # element was found in this branch
760
+ return True
741
761
return False
742
762
743
763
def intersection_with (
0 commit comments