robotcode-robot 0.78.0__tar.gz → 0.78.1__tar.gz

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.
Files changed (31) hide show
  1. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/PKG-INFO +2 -2
  2. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/pyproject.toml +1 -1
  3. robotcode_robot-0.78.1/src/robotcode/robot/__version__.py +1 -0
  4. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/config/model.py +65 -14
  5. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/entities.py +3 -0
  6. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/namespace.py +24 -0
  7. robotcode_robot-0.78.0/src/robotcode/robot/__version__.py +0 -1
  8. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/.gitignore +0 -0
  9. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/LICENSE.txt +0 -0
  10. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/README.md +0 -0
  11. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/__init__.py +0 -0
  12. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/config/__init__.py +0 -0
  13. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/config/loader.py +0 -0
  14. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/config/utils.py +0 -0
  15. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/__init__.py +0 -0
  16. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/document_cache_helper.py +0 -0
  17. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/errors.py +0 -0
  18. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/imports_manager.py +0 -0
  19. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/library_doc.py +0 -0
  20. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/model_helper.py +0 -0
  21. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/namespace_analyzer.py +0 -0
  22. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/diagnostics/workspace_config.py +0 -0
  23. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/py.typed +0 -0
  24. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/utils/__init__.py +0 -0
  25. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/utils/ast.py +0 -0
  26. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/utils/markdownformatter.py +0 -0
  27. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/utils/match.py +0 -0
  28. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/utils/robot_path.py +0 -0
  29. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/utils/stubs.py +0 -0
  30. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/utils/variables.py +0 -0
  31. {robotcode_robot-0.78.0 → robotcode_robot-0.78.1}/src/robotcode/robot/utils/visitor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: robotcode-robot
3
- Version: 0.78.0
3
+ Version: 0.78.1
4
4
  Summary: Support classes for RobotCode for handling Robot Framework projects.
5
5
  Project-URL: Homepage, https://robotcode.io
6
6
  Project-URL: Donate, https://github.com/sponsors/d-biehl
@@ -26,7 +26,7 @@ Classifier: Topic :: Utilities
26
26
  Classifier: Typing :: Typed
27
27
  Requires-Python: >=3.8
28
28
  Requires-Dist: platformdirs<4.2.0,>=3.2.0
29
- Requires-Dist: robotcode-core==0.78.0
29
+ Requires-Dist: robotcode-core==0.78.1
30
30
  Requires-Dist: robotframework>=4.1.0
31
31
  Requires-Dist: tomli>=1.1.0; python_version < '3.11'
32
32
  Description-Content-Type: text/markdown
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "robotframework>=4.1.0",
30
30
  "tomli>=1.1.0; python_version < '3.11'",
31
31
  "platformdirs>=3.2.0,<4.2.0",
32
- "robotcode-core==0.78.0",
32
+ "robotcode-core==0.78.1",
33
33
  ]
34
34
  dynamic = ["version"]
35
35
 
@@ -0,0 +1 @@
1
+ __version__ = "0.78.1"
@@ -16,6 +16,7 @@ from typing import (
16
16
  List,
17
17
  Literal,
18
18
  Optional,
19
+ Set,
19
20
  Tuple,
20
21
  Union,
21
22
  get_type_hints,
@@ -2264,6 +2265,9 @@ class RobotExtendBaseProfile(RobotBaseProfile):
2264
2265
  class RobotProfile(RobotExtendBaseProfile):
2265
2266
  """Robot Framework configuration profile."""
2266
2267
 
2268
+ def __hash__(self) -> int:
2269
+ return id(self)
2270
+
2267
2271
  description: Optional[str] = field(description="Description of the profile.")
2268
2272
 
2269
2273
  detached: Optional[bool] = field(
@@ -2291,6 +2295,9 @@ class RobotProfile(RobotExtendBaseProfile):
2291
2295
  """
2292
2296
  )
2293
2297
 
2298
+ def is_enabled(self) -> bool:
2299
+ return self.enabled is None or bool(self.enabled)
2300
+
2294
2301
  hidden: Union[bool, Condition, None] = field(
2295
2302
  description="""\
2296
2303
  The profile should be hidden.
@@ -2349,13 +2356,13 @@ class RobotConfig(RobotExtendBaseProfile):
2349
2356
 
2350
2357
  tool: Any = field(description="Tool configurations.")
2351
2358
 
2352
- def select_profiles(
2359
+ def _select_profiles(
2353
2360
  self,
2354
2361
  *names: str,
2355
2362
  verbose_callback: Optional[Callable[[Union[str, Callable[[], Any]]], None]] = None,
2356
2363
  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]]]]] = {}
2359
2366
 
2360
2367
  profiles = self.profiles or {}
2361
2368
 
@@ -2372,14 +2379,20 @@ class RobotConfig(RobotExtendBaseProfile):
2372
2379
 
2373
2380
  names = (*(default_profile or ()),)
2374
2381
 
2375
- def select(name: str) -> None:
2382
+ def select(name: str, parent_profiles: Optional[Set[Tuple[str, RobotProfile]]] = None) -> None:
2376
2383
  if not name:
2377
2384
  return
2378
2385
 
2379
2386
  nonlocal result
2380
2387
 
2381
2388
  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}'.")
2383
2396
 
2384
2397
  profile_names = [p for p in profiles.keys() if fnmatch.fnmatchcase(p, name)]
2385
2398
 
@@ -2393,13 +2406,24 @@ class RobotConfig(RobotExtendBaseProfile):
2393
2406
 
2394
2407
  for v in profile_names:
2395
2408
  p = profiles[v]
2396
- result.update({v: p})
2409
+
2397
2410
  if p.inherits:
2398
2411
  if isinstance(p.inherits, list):
2399
2412
  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)
2401
2420
  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)})
2403
2427
 
2404
2428
  for name in names:
2405
2429
  select(name)
@@ -2438,7 +2462,7 @@ class RobotConfig(RobotExtendBaseProfile):
2438
2462
  }
2439
2463
  )
2440
2464
 
2441
- selected_profiles = self.select_profiles(
2465
+ selected_profiles = self._select_profiles(
2442
2466
  *names, verbose_callback=verbose_callback, error_callback=error_callback
2443
2467
  )
2444
2468
  if verbose_callback:
@@ -2447,14 +2471,16 @@ class RobotConfig(RobotExtendBaseProfile):
2447
2471
  else:
2448
2472
  verbose_callback("No profiles selected.")
2449
2473
 
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
+ ):
2451
2477
  try:
2452
- if profile.enabled is not None and not bool(profile.enabled):
2478
+ if not profile.is_enabled():
2453
2479
  if verbose_callback:
2454
2480
  verbose_callback(f'Skipping profile "{profile_name}" because it\'s disabled.')
2455
2481
  continue
2456
2482
  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}"
2458
2484
 
2459
2485
  if error_callback is None:
2460
2486
  raise ValueError(message) from e
@@ -2462,6 +2488,31 @@ class RobotConfig(RobotExtendBaseProfile):
2462
2488
  error_callback(message)
2463
2489
  continue
2464
2490
 
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
+
2465
2516
  if verbose_callback:
2466
2517
  verbose_callback(f'Using profile "{profile_name}".')
2467
2518
 
@@ -2471,7 +2522,7 @@ class RobotConfig(RobotExtendBaseProfile):
2471
2522
  for k, v in profile.env.items():
2472
2523
  os.environ[k] = str(v)
2473
2524
  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}'")
2475
2526
 
2476
2527
  if profile.detached:
2477
2528
  result = RobotBaseProfile()
@@ -2520,4 +2571,4 @@ class RobotConfig(RobotExtendBaseProfile):
2520
2571
  if new is not None:
2521
2572
  setattr(result, f.name, new)
2522
2573
 
2523
- return result, selected_profiles, enabled_profiles
2574
+ return result, {k: v[0] for k, v in selected_profiles.items()}, enabled_profiles
@@ -155,6 +155,9 @@ class VariableMatcher:
155
155
  if isinstance(o, str):
156
156
  match = search_variable(o, "$@&%", ignore_errors=True)
157
157
  base = match.base
158
+ if base is None:
159
+ return False
160
+
158
161
  normalized = str(normalize(base))
159
162
  return self.normalized_name == normalized
160
163
 
@@ -1123,6 +1123,7 @@ class Namespace:
1123
1123
  top_level: bool = False,
1124
1124
  source: Optional[str] = None,
1125
1125
  parent_import: Optional[Import] = None,
1126
+ parent_source: Optional[str] = None,
1126
1127
  ) -> Optional[LibraryEntry]:
1127
1128
  result: Optional[LibraryEntry] = None
1128
1129
  try:
@@ -1304,6 +1305,26 @@ class Namespace:
1304
1305
  source=DIAGNOSTICS_SOURCE_NAME,
1305
1306
  code=type(e).__qualname__,
1306
1307
  )
1308
+ elif parent_import is not None:
1309
+ self.append_diagnostics(
1310
+ range=parent_import.range,
1311
+ message="Import definition contains errors.",
1312
+ severity=DiagnosticSeverity.ERROR,
1313
+ source=DIAGNOSTICS_SOURCE_NAME,
1314
+ code=Error.IMPORT_CONTAINS_ERRORS,
1315
+ related_information=(
1316
+ (
1317
+ [
1318
+ DiagnosticRelatedInformation(
1319
+ location=Location(str(Uri.from_path(parent_source)), value.range),
1320
+ message=str(e),
1321
+ ),
1322
+ ]
1323
+ )
1324
+ if parent_source
1325
+ else None
1326
+ ),
1327
+ )
1307
1328
  finally:
1308
1329
  self._reset_global_variables()
1309
1330
 
@@ -1318,6 +1339,7 @@ class Namespace:
1318
1339
  variables: Optional[Dict[str, Any]] = None,
1319
1340
  source: Optional[str] = None,
1320
1341
  parent_import: Optional[Import] = None,
1342
+ parent_source: Optional[str] = None,
1321
1343
  depth: int = 0,
1322
1344
  ) -> Optional[Dict[str, Any]]:
1323
1345
 
@@ -1335,6 +1357,7 @@ class Namespace:
1335
1357
  top_level=top_level,
1336
1358
  source=source,
1337
1359
  parent_import=parent_import,
1360
+ parent_source=parent_source if parent_source else source,
1338
1361
  )
1339
1362
 
1340
1363
  if entry is not None:
@@ -1358,6 +1381,7 @@ class Namespace:
1358
1381
  variables=variables,
1359
1382
  source=entry.library_doc.source,
1360
1383
  parent_import=imp if top_level else parent_import,
1384
+ parent_source=parent_source if top_level else source,
1361
1385
  depth=depth + 1,
1362
1386
  )
1363
1387
  except (SystemExit, KeyboardInterrupt):
@@ -1 +0,0 @@
1
- __version__ = "0.78.0"