1616 List ,
1717 Literal ,
1818 Optional ,
19+ Set ,
1920 Tuple ,
2021 Union ,
2122 get_type_hints ,
@@ -2264,6 +2265,9 @@ class RobotExtendBaseProfile(RobotBaseProfile):
22642265class RobotProfile (RobotExtendBaseProfile ):
22652266 """Robot Framework configuration profile."""
22662267
2268+ def __hash__ (self ) -> int :
2269+ return id (self )
2270+
22672271 description : Optional [str ] = field (description = "Description of the profile." )
22682272
22692273 detached : Optional [bool ] = field (
@@ -2291,6 +2295,9 @@ class RobotProfile(RobotExtendBaseProfile):
22912295 """
22922296 )
22932297
2298+ def is_enabled (self ) -> bool :
2299+ return self .enabled is None or bool (self .enabled )
2300+
22942301 hidden : Union [bool , Condition , None ] = field (
22952302 description = """\
22962303 The profile should be hidden.
@@ -2349,13 +2356,13 @@ class RobotConfig(RobotExtendBaseProfile):
23492356
23502357 tool : Any = field (description = "Tool configurations." )
23512358
2352- def select_profiles (
2359+ def _select_profiles (
23532360 self ,
23542361 * names : str ,
23552362 verbose_callback : Optional [Callable [[Union [str , Callable [[], Any ]]], None ]] = None ,
23562363 error_callback : Optional [Callable [[Union [str , Callable [[], Any ]]], None ]] = None ,
2357- ) -> Dict [str , RobotProfile ]:
2358- result : Dict [str , RobotProfile ] = {}
2364+ ) -> Dict [str , Tuple [ RobotProfile , Optional [ Set [ Tuple [ str , RobotProfile ]]]] ]:
2365+ result : Dict [str , Tuple [ RobotProfile , Optional [ Set [ Tuple [ str , RobotProfile ]]]] ] = {}
23592366
23602367 profiles = self .profiles or {}
23612368
@@ -2372,14 +2379,20 @@ def select_profiles(
23722379
23732380 names = (* (default_profile or ()),)
23742381
2375- def select (name : str ) -> None :
2382+ def select (name : str , parent_profiles : Optional [ Set [ Tuple [ str , RobotProfile ]]] = None ) -> None :
23762383 if not name :
23772384 return
23782385
23792386 nonlocal result
23802387
23812388 if verbose_callback :
2382- verbose_callback (f"Selecting profiles matching '{ name } '." )
2389+ if parent_profiles is not None :
2390+ verbose_callback (
2391+ f"Selecting profiles matching '{ name } '"
2392+ f" for parent profile '{ next (f for f in parent_profiles )[0 ]} '."
2393+ )
2394+ else :
2395+ verbose_callback (f"Selecting profiles matching '{ name } '." )
23832396
23842397 profile_names = [p for p in profiles .keys () if fnmatch .fnmatchcase (p , name )]
23852398
@@ -2393,13 +2406,24 @@ def select(name: str) -> None:
23932406
23942407 for v in profile_names :
23952408 p = profiles [v ]
2396- result . update ({ v : p })
2409+
23972410 if p .inherits :
23982411 if isinstance (p .inherits , list ):
23992412 for i in p .inherits :
2400- select (str (i ))
2413+ select (str (i ), {(v , p )})
2414+ else :
2415+ select (str (p .inherits ), {(v , p )})
2416+
2417+ if v in result :
2418+ if parent_profiles is None :
2419+ result [v ] = (p , None )
24012420 else :
2402- select (str (p .inherits ))
2421+ parents = result [v ][1 ]
2422+ if parents is not None :
2423+ parents .update (parent_profiles )
2424+
2425+ else :
2426+ result .update ({v : (p , parent_profiles )})
24032427
24042428 for name in names :
24052429 select (name )
@@ -2438,7 +2462,7 @@ def combine_profiles_ex(
24382462 }
24392463 )
24402464
2441- selected_profiles = self .select_profiles (
2465+ selected_profiles = self ._select_profiles (
24422466 * names , verbose_callback = verbose_callback , error_callback = error_callback
24432467 )
24442468 if verbose_callback :
@@ -2447,21 +2471,48 @@ def combine_profiles_ex(
24472471 else :
24482472 verbose_callback ("No profiles selected." )
24492473
2450- for profile_name , profile in sorted (selected_profiles .items (), key = lambda x : x [1 ].precedence or 0 ):
2474+ for profile_name , (profile , parent_profiles ) in sorted (
2475+ selected_profiles .items (), key = lambda x : x [1 ][0 ].precedence or 0
2476+ ):
24512477 try :
2452- if profile . enabled is not None and not bool ( profile .enabled ):
2478+ if not profile .is_enabled ( ):
24532479 if verbose_callback :
24542480 verbose_callback (f'Skipping profile "{ profile_name } " because it\' s disabled.' )
24552481 continue
24562482 except EvaluationError as e :
2457- message = f' Error evaluating " enabled" condition for profile " { profile_name } " : { e } '
2483+ message = f" Error evaluating ' enabled' condition for profile ' { profile_name } ' : { e } "
24582484
24592485 if error_callback is None :
24602486 raise ValueError (message ) from e
24612487
24622488 error_callback (message )
24632489 continue
24642490
2491+ if parent_profiles is not None :
2492+ disabled_profiles = []
2493+ skip = False
2494+ for parent_profile in parent_profiles :
2495+ try :
2496+ if not parent_profile [1 ].is_enabled ():
2497+ disabled_profiles .append (parent_profile [0 ])
2498+ except EvaluationError as e :
2499+ message = f"Error evaluating 'enabled' condition for profile '{ parent_profile [0 ]} ': { e } "
2500+
2501+ if error_callback is None :
2502+ raise ValueError (message ) from e
2503+
2504+ error_callback (message )
2505+ skip = True
2506+ break
2507+
2508+ if skip or len (disabled_profiles ) == len (parent_profiles ):
2509+ if verbose_callback :
2510+ verbose_callback (
2511+ f"Skipping profile inherited '{ profile_name } ' because no parent is enabled."
2512+ f" Disabled profiles: { ', ' .join (disabled_profiles )} ."
2513+ )
2514+ continue
2515+
24652516 if verbose_callback :
24662517 verbose_callback (f'Using profile "{ profile_name } ".' )
24672518
@@ -2471,7 +2522,7 @@ def combine_profiles_ex(
24712522 for k , v in profile .env .items ():
24722523 os .environ [k ] = str (v )
24732524 if verbose_callback :
2474- verbose_callback (lambda : f"Set environment variable ` { k } ` to ` { v } ` " )
2525+ verbose_callback (lambda : f"Set environment variable ' { k } ' to ' { v } ' " )
24752526
24762527 if profile .detached :
24772528 result = RobotBaseProfile ()
@@ -2520,4 +2571,4 @@ def combine_profiles_ex(
25202571 if new is not None :
25212572 setattr (result , f .name , new )
25222573
2523- return result , selected_profiles , enabled_profiles
2574+ return result , { k : v [ 0 ] for k , v in selected_profiles . items ()} , enabled_profiles
0 commit comments