robotcode-robot 2.8.0.dev677__py3-none-any.whl → 2.9.0.dev51__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.
@@ -1 +1 @@
1
- __version__ = "2.8.0-dev.677"
1
+ __version__ = "2.9.0-dev.51"
@@ -3222,6 +3222,42 @@ class RobotProfile(RobotExtendBaseProfile):
3222
3222
  )
3223
3223
 
3224
3224
 
3225
+ @dataclass(frozen=True)
3226
+ class UnknownProfile:
3227
+ """A profile name or pattern that selects no profile, and where it comes from."""
3228
+
3229
+ name: str
3230
+ # the profile whose `inherits` names it; None for a name of the selection or of `default-profiles`
3231
+ inherited_by: Optional[str] = None
3232
+ # whether it comes from `default-profiles`
3233
+ default: bool = False
3234
+
3235
+ @property
3236
+ def selected(self) -> bool:
3237
+ """Whether the name comes from the selection: `-p`, `ROBOTCODE_PROFILES` or an editor."""
3238
+ return self.inherited_by is None and not self.default
3239
+
3240
+ @property
3241
+ def message(self) -> str:
3242
+ return f"No profile matches '{self.name}'."
3243
+
3244
+
3245
+ class ProfileNotFoundError(ValueError):
3246
+ """A profile name or pattern that selects no profile."""
3247
+
3248
+ def __init__(self, unknown: UnknownProfile) -> None:
3249
+ super().__init__(unknown.message)
3250
+ self.unknown = unknown
3251
+
3252
+
3253
+ class ProfileInheritanceError(ValueError):
3254
+ """A profile that inherits itself, directly or through other profiles."""
3255
+
3256
+ def __init__(self, path: Tuple[str, ...]) -> None:
3257
+ super().__init__(f"The profile '{path[0]}' inherits itself: {' -> '.join(path)}.")
3258
+ self.path = path
3259
+
3260
+
3225
3261
  @dataclass
3226
3262
  class RobotConfig(RobotExtendBaseProfile):
3227
3263
  """Robot Framework configuration."""
@@ -3288,11 +3324,13 @@ class RobotConfig(RobotExtendBaseProfile):
3288
3324
  *names: str,
3289
3325
  verbose_callback: Optional[Callable[[Union[str, Callable[[], Any]]], None]] = None,
3290
3326
  error_callback: Optional[Callable[[Union[str, Callable[[], Any]]], None]] = None,
3327
+ unknown_profile_callback: Optional[Callable[[UnknownProfile], None]] = None,
3291
3328
  ) -> Dict[str, Tuple[RobotProfile, Optional[Set[Tuple[str, RobotProfile]]]]]:
3292
3329
  result: Dict[str, Tuple[RobotProfile, Optional[Set[Tuple[str, RobotProfile]]]]] = {}
3293
3330
 
3294
3331
  profiles = self.profiles or {}
3295
3332
 
3333
+ from_default_profiles = not names
3296
3334
  if not names:
3297
3335
  if verbose_callback:
3298
3336
  verbose_callback("No profiles given, try to check if there are default profiles specified.")
@@ -3306,40 +3344,65 @@ class RobotConfig(RobotExtendBaseProfile):
3306
3344
 
3307
3345
  names = (*(default_profile or ()),)
3308
3346
 
3309
- def select(name: str, parent_profiles: Optional[Set[Tuple[str, RobotProfile]]] = None) -> None:
3347
+ # each name that selects no profile is reported once for each place it comes from
3348
+ reported: Set[UnknownProfile] = set()
3349
+
3350
+ def report(unknown: UnknownProfile) -> None:
3351
+ if unknown in reported:
3352
+ return
3353
+ reported.add(unknown)
3354
+
3355
+ # a name that selects no profile is an error of the configuration; only callers that must go on, such as
3356
+ # the language server, take it and go on without it
3357
+ if unknown_profile_callback is not None:
3358
+ unknown_profile_callback(unknown)
3359
+ # a name of `default-profiles` is only reported: the `default-profiles` of the user configuration can name
3360
+ # a profile of that file, which the `[profiles]` of a project replace
3361
+ elif unknown.default and error_callback is not None:
3362
+ error_callback(unknown.message)
3363
+ else:
3364
+ raise ProfileNotFoundError(unknown)
3365
+
3366
+ # `path` holds the profiles whose `inherits` lead to the name; the last one names it
3367
+ def select(name: str, path: Tuple[str, ...] = ()) -> None:
3310
3368
  if not name:
3311
3369
  return
3312
3370
 
3313
3371
  nonlocal result
3314
3372
 
3373
+ parent = path[-1] if path else None
3374
+
3315
3375
  if verbose_callback:
3316
- if parent_profiles is not None:
3317
- verbose_callback(
3318
- f"Selecting profiles matching '{name}'"
3319
- f" for parent profile '{next(f for f in parent_profiles)[0]}'."
3320
- )
3376
+ if parent is not None:
3377
+ verbose_callback(f"Selecting profiles matching '{name}' for parent profile '{parent}'.")
3321
3378
  else:
3322
3379
  verbose_callback(f"Selecting profiles matching '{name}'.")
3323
3380
 
3324
- profile_names = [p for p in profiles.keys() if fnmatch.fnmatchcase(p, name)]
3381
+ if name in profiles:
3382
+ # an exact name selects its profile, also when it contains `*`, `?` or `[`
3383
+ profile_names = [name]
3384
+ else:
3385
+ # a pattern in `inherits` does not match the profile that has it
3386
+ profile_names = [p for p in profiles.keys() if p != parent and fnmatch.fnmatchcase(p, name)]
3325
3387
 
3326
3388
  if not profile_names:
3327
- message = f"Can't find any configuration profiles matching the pattern '{name}'."
3328
- if error_callback is None:
3329
- raise ValueError(message)
3330
-
3331
- error_callback(message)
3389
+ report(UnknownProfile(name, inherited_by=parent, default=from_default_profiles and parent is None))
3332
3390
  return
3333
3391
 
3392
+ parent_profiles = {(parent, profiles[parent])} if parent is not None else None
3393
+
3334
3394
  for v in profile_names:
3395
+ if v in path:
3396
+ raise ProfileInheritanceError((*path[path.index(v) :], v))
3397
+
3335
3398
  p = profiles[v]
3336
3399
 
3337
3400
  if p.inherits:
3338
3401
  if isinstance(p.inherits, list):
3339
3402
  for i in p.inherits:
3340
- select(str(i), {(v, p)})
3403
+ select(str(i), (*path, v))
3341
3404
  else:
3342
- select(str(p.inherits), {(v, p)})
3405
+ select(str(p.inherits), (*path, v))
3343
3406
 
3344
3407
  if v in result:
3345
3408
  if parent_profiles is None:
@@ -3362,14 +3425,21 @@ class RobotConfig(RobotExtendBaseProfile):
3362
3425
  *names: str,
3363
3426
  verbose_callback: Optional[Callable[[Union[str, Callable[[], Any]]], None]] = None,
3364
3427
  error_callback: Optional[Callable[[Union[str, Callable[[], Any]]], None]] = None,
3428
+ unknown_profile_callback: Optional[Callable[[UnknownProfile], None]] = None,
3365
3429
  ) -> RobotBaseProfile:
3366
- return self.combine_profiles_ex(*names, verbose_callback=verbose_callback, error_callback=error_callback)[0]
3430
+ return self.combine_profiles_ex(
3431
+ *names,
3432
+ verbose_callback=verbose_callback,
3433
+ error_callback=error_callback,
3434
+ unknown_profile_callback=unknown_profile_callback,
3435
+ )[0]
3367
3436
 
3368
3437
  def combine_profiles_ex(
3369
3438
  self,
3370
3439
  *names: str,
3371
3440
  verbose_callback: Optional[Callable[[Union[str, Callable[[], Any]]], None]] = None,
3372
3441
  error_callback: Optional[Callable[[Union[str, Callable[[], Any]]], None]] = None,
3442
+ unknown_profile_callback: Optional[Callable[[UnknownProfile], None]] = None,
3373
3443
  ) -> Tuple[RobotBaseProfile, Dict[str, RobotProfile], List[str]]:
3374
3444
  enabled_profiles = []
3375
3445
  type_hints = get_type_hints(RobotBaseProfile)
@@ -3390,7 +3460,10 @@ class RobotConfig(RobotExtendBaseProfile):
3390
3460
  )
3391
3461
 
3392
3462
  selected_profiles = self._select_profiles(
3393
- *names, verbose_callback=verbose_callback, error_callback=error_callback
3463
+ *names,
3464
+ verbose_callback=verbose_callback,
3465
+ error_callback=error_callback,
3466
+ unknown_profile_callback=unknown_profile_callback,
3394
3467
  )
3395
3468
  if verbose_callback:
3396
3469
  if selected_profiles:
@@ -2728,7 +2728,7 @@ class _Logger(AbstractLogger):
2728
2728
 
2729
2729
  def _import_test_library(name: str) -> Union[Any, Tuple[Any, str]]:
2730
2730
  with OutputCapturer(library_import=True):
2731
- importer = Importer("test library", LOGGER)
2731
+ importer = Importer("library", LOGGER)
2732
2732
  return importer.import_class_or_module(name, return_source=True)
2733
2733
 
2734
2734
 
@@ -144,14 +144,18 @@ class LinkFormatter:
144
144
  return pre + self._get_link(url)
145
145
 
146
146
  def _get_image(self, src: str, title: Optional[str] = None) -> str:
147
- return f"![{title or src}]({self._unquote_hash(src)})"
147
+ return f"![{title or src}]({self._target(src)})"
148
148
 
149
149
  def _get_link(self, href: str, content: Optional[str] = None) -> str:
150
- return f"[{content or href}]({self._unquote_hash(href)})"
150
+ return f"[{content or href}]({self._target(href)})"
151
151
 
152
- def _unquote_hash(self, target: str) -> str:
152
+ def _target(self, target: str) -> str:
153
153
  # `#` is escaped in the whole line before links are formatted, a link target needs it as it is
154
- return target.replace("\\#", "#")
154
+ target = target.replace("\\#", "#")
155
+ # Markdown takes a target with spaces only in angle brackets; `<` is already escaped in the whole line
156
+ if " " in target:
157
+ return "<" + target.replace(">", "\\>") + ">"
158
+ return target
155
159
 
156
160
  def _quot(self, attr: str) -> str:
157
161
  return attr if '"' not in attr else attr.replace('"', "&quot;")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: robotcode-robot
3
- Version: 2.8.0-dev.677
3
+ Version: 2.9.0-dev.51
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://opencollective.com/robotcode
@@ -27,7 +27,7 @@ Classifier: Topic :: Utilities
27
27
  Classifier: Typing :: Typed
28
28
  Requires-Python: >=3.10
29
29
  Requires-Dist: platformdirs>=4.3
30
- Requires-Dist: robotcode-core==2.8.0-dev.677
30
+ Requires-Dist: robotcode-core==2.9.0-dev.51
31
31
  Requires-Dist: robotframework>=5.0.0
32
32
  Requires-Dist: tomli>=1.1.0; python_version < '3.11'
33
33
  Description-Content-Type: text/markdown
@@ -1,9 +1,9 @@
1
1
  robotcode/robot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- robotcode/robot/__version__.py,sha256=0xyLlet74gxp40f05fA-fjXhAr2XdtEik3UuIJs6yAM,30
2
+ robotcode/robot/__version__.py,sha256=68lI1Ud2IVxiSKwJTXlHsfwV7s6ASsCia4CPMEdJ8Ls,29
3
3
  robotcode/robot/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
4
4
  robotcode/robot/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  robotcode/robot/config/loader.py,sha256=HLbkZem8JiBuy9Q5naghZddAuMPOn8Tk6UBgN2T3Uyc,9073
6
- robotcode/robot/config/model.py,sha256=i8EH_n_20U7eCNY81nWa7oTFAxKj9iSH5Sxm1vr8bOQ,112151
6
+ robotcode/robot/config/model.py,sha256=2dRKRDQV50_k1PmX-7uhqrPTX7Z6oJq4PcAG4pBDRi8,115165
7
7
  robotcode/robot/config/utils.py,sha256=A8gD5IItxuC7AY5Olcc8tmsSbqCCi_vZPVoK3BqWt_8,4070
8
8
  robotcode/robot/diagnostics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  robotcode/robot/diagnostics/analyzer_result.py,sha256=5pHW5Yf3C3rmaDvmM7tP0y_qwqLW3YHhkeVV-qDhxtg,1459
@@ -16,7 +16,7 @@ robotcode/robot/diagnostics/errors.py,sha256=lqHDWrMNy3ZhuEIVxeEhaU0ns8PB6pVTQBf
16
16
  robotcode/robot/diagnostics/import_resolver.py,sha256=DZjUOD3uNxFAwsVUqrCTRhColjz9DRPetAvIb_Ccufs,32588
17
17
  robotcode/robot/diagnostics/imports_manager.py,sha256=opemApuCLgPNsnqVuYc9MefqHt42g_7Ozqhrmu_osH0,90401
18
18
  robotcode/robot/diagnostics/keyword_finder.py,sha256=nwTmjvhyu5H7HHzyk8gt-pny2K2xdH2qCNyKXwwXRnk,18998
19
- robotcode/robot/diagnostics/library_doc.py,sha256=MYztjgnOmXAPjXn7td651oWats2qDlPrLgCkmwpdSmU,153576
19
+ robotcode/robot/diagnostics/library_doc.py,sha256=xJCFm1uMM2OFZqn6sJNfdjGZJ2WsQjGlRmlqDHv64uA,153571
20
20
  robotcode/robot/diagnostics/model_helper.py,sha256=_ySXwerkK5xvjWa82T0DFy8jpxRzcaavTJiAHnk2lXQ,29740
21
21
  robotcode/robot/diagnostics/namespace.py,sha256=Rcmjk3V0vcY-DUkgjkRyuOdYXurKaTEqXJLc6efYrwY,35489
22
22
  robotcode/robot/diagnostics/namespace_analyzer.py,sha256=dGAEbbznPJlFBKN4dLkMDU7w9xc0mYdmRARvRS3Zlwg,104331
@@ -36,13 +36,13 @@ robotcode/robot/diagnostics/semantic_analyzer/variable_tokenizer.py,sha256=vBor3
36
36
  robotcode/robot/utils/__init__.py,sha256=-A0YeHv7e7WK1SId7Er7Vu6frrDYWopUrcyFlyxLmPY,396
37
37
  robotcode/robot/utils/ast.py,sha256=S9xyiJZee4Y5VcroNrGIIWp8f9sutb_1o4blAlCqzdg,11218
38
38
  robotcode/robot/utils/markdown_docs.py,sha256=jY3jT919TicVRMhcYo03dR0NzhGq0kEnDolBSPc-lNI,29548
39
- robotcode/robot/utils/markdownformatter.py,sha256=hThVK-L7_0-xcAtNNXvFeAaSzbNix0hP73t_BO_JCsc,14122
39
+ robotcode/robot/utils/markdownformatter.py,sha256=hHilBaj1DzBV1tlNHyNfMvM3h92Six-15guhQy6edgU,14323
40
40
  robotcode/robot/utils/match.py,sha256=KgA6o6TbnQpOT1eAzEjhl_-FZ2XO07xiV0L7IYRzyzE,1125
41
41
  robotcode/robot/utils/robot_patching.py,sha256=jXHhnPvZx8hCQq4B_2uwX9j51Be_toWpUoTYYe8HjPo,1463
42
42
  robotcode/robot/utils/robot_path.py,sha256=ObLP8PqamTZAz5oi0eDXE_dnyZwAPXp4TJYm6ugeENs,2185
43
43
  robotcode/robot/utils/stubs.py,sha256=umugZYAyneFNgqRJBRMJPzm0u0B_TH8Sx_y-ykXnxpw,351
44
44
  robotcode/robot/utils/variables.py,sha256=9WnP3QqcHdq-zioJ_gJXJobw_2Gcto_rGPCUGmOH9YQ,9829
45
45
  robotcode/robot/utils/visitor.py,sha256=nP3O0qh3YYuxR6S8wYJRBFfNwIVgsgohURBlrnFkRYQ,2299
46
- robotcode_robot-2.8.0.dev677.dist-info/METADATA,sha256=-WMG4AXbck6ZGANXnHl578n_RxVj5Y5o7iron1Hu8OU,2960
47
- robotcode_robot-2.8.0.dev677.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
48
- robotcode_robot-2.8.0.dev677.dist-info/RECORD,,
46
+ robotcode_robot-2.9.0.dev51.dist-info/METADATA,sha256=RziLuNl8hmcFuiRfMnuUYgOZm7OFM-E06dYl1ZNS6yE,2958
47
+ robotcode_robot-2.9.0.dev51.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
48
+ robotcode_robot-2.9.0.dev51.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.32.4
2
+ Generator: hatchling 1.33.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any