Skip to content

Commit 318d780

Browse files
committed
fix(profiles): profiles inherited by [profile].inherit are now merged before the parent profile, unless the precedence is set and are only enabled if the parent profile is enabled
1 parent bb41952 commit 318d780

File tree

1 file changed

+65
-14
lines changed
  • packages/robot/src/robotcode/robot/config

1 file changed

+65
-14
lines changed

packages/robot/src/robotcode/robot/config/model.py

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
List,
1717
Literal,
1818
Optional,
19+
Set,
1920
Tuple,
2021
Union,
2122
get_type_hints,
@@ -2264,6 +2265,9 @@ class RobotExtendBaseProfile(RobotBaseProfile):
22642265
class 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

Comments
 (0)