Skip to content

Commit 25027fa

Browse files
committed
feat: new commands robot, rebot, libdoc for robotcode.runner
1 parent 86e8afd commit 25027fa

File tree

31 files changed

+6005
-863
lines changed

31 files changed

+6005
-863
lines changed

.vscode/launch.json

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,27 @@
4444
"module": "robotcode.cli",
4545
"justMyCode": false,
4646
"cwd": "${workspaceFolder}/tests/robotcode/language_server/robotframework/parts/data",
47+
// "env": {
48+
// "ROBOTCODE_COLOR": "1",
49+
// },
4750
"args": [
48-
//"-v",
49-
"-p",
50-
"firefox",
51-
//"--dry",
52-
// "run",
51+
"--verbose",
52+
"--dry",
53+
// "-p",
54+
// "firefox",
55+
// "--dry",
56+
// "robot",
57+
// "--",
58+
// "--help"
5359
// "tests1"
54-
"config",
55-
"show"
60+
// "profiles",
61+
62+
// "show",
63+
// "list",
64+
// "--format",
65+
// "toml"
66+
"rebot",
67+
5668
]
5769
},
5870
{

docs/cli/about.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# About Commandline Interface
2+
3+
TODO

docs/cli/reference.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
::: mkdocs-click
2+
:module: robotcode.cli
3+
:command: robotcode
4+
:prog_name: robotcode
5+
:remove_ascii_art: true
6+
:list_subcommands: true

etc/robot.toml.json

Lines changed: 3099 additions & 236 deletions
Large diffs are not rendered by default.

hatch.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,18 @@ matrix.rf.dependencies = [
7878
]
7979

8080
[envs.lint]
81-
skip-install = true
82-
extra-dependencies = ["tomli>=2.0.0"]
81+
#skip-install = true
82+
#extra-dependencies = ["tomli>=2.0.0"]
8383
features = ["all"]
8484

8585
[envs.lint.scripts]
8686
typing = ["mypy --install-types --non-interactive {args:.}"]
8787
style = ["ruff .", "black --check --diff ."]
88-
fmt = ["ruff --fix .", "black .", "style"]
88+
fmt = ["black .", "ruff --fix .", "style"]
8989
all = ["style", "typing"]
9090

9191
[envs.pages]
92-
detached = true
92+
#detached = true
9393
dependencies = [
9494
"mkdocs>=1.4.2",
9595
"mkdocs-material",

mkdocs.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ markdown_extensions:
6464
emoji_index: !!python/name:materialx.emoji.twemoji
6565
emoji_generator: !!python/name:materialx.emoji.to_svg
6666
- pymdownx.highlight:
67-
auto_title: true
67+
auto_title: false
6868
linenums_style: pymdownx-inline
6969
use_pygments: true
7070
- pymdownx.inlinehilite
@@ -93,6 +93,7 @@ markdown_extensions:
9393
- pymdownx.tasklist:
9494
custom_checkbox: true
9595
- pymdownx.tilde
96+
- mkdocs-click
9697

9798
extra:
9899
consent:
@@ -114,3 +115,6 @@ nav:
114115
- Home: index.md
115116
- Features: features.md
116117
- Installation: installation.md
118+
- CLI:
119+
- About: cli/about.md
120+
- Reference: cli/reference.md

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@
7777
"tomlValidation": [
7878
{
7979
"fileMatch": "robot.toml",
80-
"url": "http://raw.githubusercontent.com/d-biehl/robotcode/main/etc/robot.toml.json"
80+
"url": "http://localhost:8000/etc/robot.toml.json"
8181
},
8282
{
8383
"fileMatch": ".robot.toml",
84-
"url": "http://raw.githubusercontent.com/d-biehl/robotcode/main/etc/robot.toml.json"
84+
"url": "http://localhost:8000/etc/robot.toml.json"
8585
}
8686
],
8787
"configurationDefaults": {
@@ -408,7 +408,7 @@
408408
"items": {
409409
"type": "string"
410410
},
411-
"markdownDescription": "Specifies the paths where robot/robotcode should discover tests. Corresponds to the `paths` option of __robot__.",
411+
"markdownDescription": "Specifies the paths where robot/robotcode should discover tests. Corresponds to the `paths` argument of __robot__.",
412412
"scope": "resource"
413413
},
414414
"robotcode.robot.pythonPath": {

packages/analyze/robotcode/analyze/cli/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
def analyze(
2222
ctx: click.Context,
2323
) -> Union[str, int, None]:
24-
"""Analyzes a Robot Framework project."""
24+
"""Analyzes a Robot Framework project.
25+
26+
TODO: This is not implemented yet.
27+
"""
2528
click.echo("Not implemented yet")
2629
return 0

packages/core/robotcode/core/dataclasses.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ def as_json(obj: Any, indent: Optional[bool] = None, compact: Optional[bool] = N
179179
)
180180

181181

182+
class NamedTypeError(TypeError):
183+
def __init__(self, name: str, message: str) -> None:
184+
super().__init__(f'Invalid value for "{name}": {message}')
185+
self.name = name
186+
self.message = message
187+
188+
182189
def _from_dict_with_name(
183190
name: str,
184191
value: Any,
@@ -189,8 +196,10 @@ def _from_dict_with_name(
189196
) -> _T:
190197
try:
191198
return from_dict(value, types, strict=strict)
199+
except NamedTypeError as e:
200+
raise NamedTypeError(name + "." + e.name, e.message) from e
192201
except TypeError as e:
193-
raise TypeError(f"Invalid value for '{name}': {e}") from e
202+
raise NamedTypeError(name, str(e)) from e
194203

195204

196205
def from_dict(
@@ -315,8 +324,13 @@ def from_dict(
315324
return cast(_T, v)
316325

317326
raise TypeError(
318-
f"Cant convert value <{repr(value)}> of type {type(value)} to type "
319-
f"{repr(types[0]) if len(types)==1 else ' | '.join(repr(e) for e in types)}."
327+
f"Cant convert value {repr(value)} of type {type(value).__name__} to type " + repr(types[0])
328+
if len(types) == 1
329+
else " | ".join(
330+
((getattr(e, "__name__", None) or str(e) if e is not type(None) else "None") if e is not None else "None")
331+
for e in types
332+
)
333+
+ "."
320334
)
321335

322336

@@ -449,6 +463,12 @@ def validate_types(expected_types: Union[type, Tuple[type, ...], None], value: A
449463

450464
return []
451465

466+
if t is Any:
467+
return []
468+
469+
if isinstance(value, origin or t):
470+
return []
471+
452472
if result:
453473
continue
454474

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,118 @@
11
from dataclasses import dataclass
2-
from enum import Enum
2+
from enum import Enum, unique
33
from pathlib import Path
4-
from typing import Any, Callable, List, Optional, TypeVar, cast
4+
from typing import IO, Any, AnyStr, Callable, Dict, List, Optional, TypeVar, Union, cast
55

66
import click
77
import pluggy
88

9-
__all__ = ["hookimpl", "ClickCommonConfig", "pass_common_config"]
9+
from robotcode.core.dataclasses import as_json
10+
11+
__all__ = ["hookimpl", "CommonConfig", "pass_application"]
1012

1113
F = TypeVar("F", bound=Callable[..., Any])
1214
hookimpl = cast(Callable[[F], F], pluggy.HookimplMarker("robotcode"))
1315

1416

17+
@unique
1518
class ColoredOutput(str, Enum):
1619
AUTO = "auto"
1720
YES = "yes"
1821
NO = "no"
1922

2023

24+
@unique
25+
class OutputFormat(str, Enum):
26+
TOML = "toml"
27+
JSON = "json"
28+
FLAT = "flat"
29+
30+
def __str__(self) -> str:
31+
return self.value
32+
33+
2134
@dataclass
22-
class ClickCommonConfig:
35+
class CommonConfig:
2336
config_file: Optional[Path] = None
2437
profiles: Optional[List[str]] = None
2538
dry: bool = False
2639
verbose: bool = False
2740
colored_output: ColoredOutput = ColoredOutput.AUTO
2841

2942

30-
pass_common_config = click.make_pass_decorator(ClickCommonConfig, ensure=True)
43+
class Application:
44+
def __init__(self) -> None:
45+
self.config = CommonConfig()
46+
47+
@property
48+
def colored(self) -> bool:
49+
return self.config.colored_output in [ColoredOutput.AUTO, ColoredOutput.YES]
50+
51+
def verbose(
52+
self,
53+
message: Union[str, Callable[[], Any], None],
54+
file: Optional[IO[AnyStr]] = None,
55+
nl: bool = True,
56+
err: bool = False,
57+
) -> None:
58+
if self.config.verbose:
59+
click.secho(
60+
message() if callable(message) else message,
61+
file=file,
62+
nl=nl,
63+
err=err,
64+
color=self.colored,
65+
fg="bright_black",
66+
)
67+
68+
def warning(
69+
self,
70+
message: Union[str, Callable[[], Any], None],
71+
file: Optional[IO[AnyStr]] = None,
72+
nl: bool = True,
73+
err: bool = False,
74+
) -> None:
75+
click.secho(
76+
f"WARNING: {message() if callable(message) else message}",
77+
file=file,
78+
nl=nl,
79+
err=err,
80+
color=self.colored,
81+
fg="bright_yellow",
82+
)
83+
84+
def print_dict(self, config: Dict[str, Any], format: OutputFormat) -> None:
85+
text = None
86+
if format == "toml":
87+
try:
88+
import tomli_w
89+
90+
text = tomli_w.dumps(config)
91+
except ImportError:
92+
self.warning("Package 'tomli_w' is required to use TOML output. Using JSON format instead.")
93+
format = OutputFormat.JSON
94+
95+
if text is None:
96+
text = as_json(config, indent=True)
97+
98+
if not text:
99+
return
100+
101+
if self.colored:
102+
try:
103+
from rich.console import Console
104+
from rich.syntax import Syntax
105+
106+
Console().print(Syntax(text, format, background_color="default"))
107+
108+
return
109+
except ImportError:
110+
if self.config.colored_output == ColoredOutput.YES:
111+
self.warning('Package "rich" is required to use colored output.')
112+
113+
click.echo(text)
114+
115+
return
116+
117+
118+
pass_application = click.make_pass_decorator(Application, ensure=True)

0 commit comments

Comments
 (0)