Skip to content

Commit 55f559d

Browse files
committed
feat: user default robot.toml config file
Instead of defining default settings like output-dir or python-path in VSCode a default config file is created in user directory. The default settings in VSCode are removed, but you can define them here again, but the prefered way is to use the `robot.toml` file in user directory.
1 parent 3195451 commit 55f559d

File tree

9 files changed

+87
-50
lines changed

9 files changed

+87
-50
lines changed

.vscode/launch.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,9 @@
4242
// "toml",
4343
"--no-color",
4444
"--no-pager",
45-
"--default-path",
46-
".",
4745
//"config", "info", "desc",
48-
"discover",
49-
"info"
46+
"config",
47+
"files"
5048
]
5149
},
5250
{

bundled_requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ click>=8.1.0
33
pluggy>=1.0.0
44
tomli > 2.0.0
55
tomli_w >= 1.0.0
6+
platformdirs<3.9.0,>=3.2.0

package.json

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -449,14 +449,11 @@
449449
},
450450
"robotcode.robot.pythonPath": {
451451
"type": "array",
452-
"default": [
453-
"./lib",
454-
"./resources"
455-
],
452+
"default": [],
456453
"items": {
457454
"type": "string"
458455
},
459-
"markdownDescription": "Specifies additional python paths for robotframework. Corresponds to the `--pythonpath` option of __robot__.\n\n> **WARNING:**\n>\n> The default value for this will changed in one of the next releases to `[]`, because there is the new `robot.toml` configuration file. Please use this file to configure the python path.",
456+
"markdownDescription": "Specifies additional python paths for robotframework. Corresponds to the `--pythonpath` option of __robot__.",
460457
"scope": "resource"
461458
},
462459
"robotcode.robot.env": {
@@ -497,8 +494,8 @@
497494
},
498495
"robotcode.robot.outputDir": {
499496
"type": "string",
500-
"default": "results",
501-
"markdownDescription": "Specifies the output directory where robotframework saves output files. Corresponds to the `--outputdir` option of __robot__.\n\n> **WARNING:**\n>\n> The default value for this will changed in one of the next releases to `\"\"`, because there is the new `robot.toml` configuration file. Please use this file to configure the output directory.",
497+
"default": "",
498+
"markdownDescription": "Specifies the output directory where robotframework saves output files. Corresponds to the `--outputdir` option of __robot__.",
502499
"scope": "resource"
503500
},
504501
"robotcode.robot.mode": {

packages/robot/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ classifiers = [
2828
dependencies = [
2929
"robotframework>=4.1.0",
3030
"tomli>=1.1.0; python_version < '3.11'",
31+
"platformdirs<3.9.0,>=3.2.0",
3132
"robotcode-core==0.48.0",
3233
]
3334
dynamic = ["version"]

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,25 @@
1616
PYPROJECT_TOML = "pyproject.toml"
1717
ROBOT_TOML = "robot.toml"
1818
LOCAL_ROBOT_TOML = ".robot.toml"
19+
USER_DEFAULT_CONFIG_TOML = "default config"
1920

2021

2122
class DiscoverdBy(str, Enum):
2223
GIT = ".git directory"
2324
HG = "hg"
24-
PYPROJECT_TOML = PYPROJECT_TOML
25-
ROBOT_TOML = ROBOT_TOML
26-
LOCAL_ROBOT_TOML = LOCAL_ROBOT_TOML
25+
PYPROJECT_TOML = "pyproject.toml (project file))"
26+
ROBOT_TOML = "robot.toml (project file)"
27+
LOCAL_ROBOT_TOML = ".robot.toml (local file)"
28+
USER_DEFAULT_CONFIG_TOML = "robot.toml (user default config)"
2729
NOT_FOUND = "not found"
2830

2931

3032
class ConfigType(str, Enum):
31-
PYPROJECT_TOML = PYPROJECT_TOML
32-
ROBOT_TOML = ROBOT_TOML
33-
LOCAL_ROBOT_TOML = LOCAL_ROBOT_TOML
34-
CUSTOM_TOML = ".toml"
33+
PYPROJECT_TOML = "pyproject.toml (project file))"
34+
ROBOT_TOML = "robot.toml (project file)"
35+
LOCAL_ROBOT_TOML = ".robot.toml (local file)"
36+
USER_DEFAULT_CONFIG_TOML = "robot.toml (user default config)"
37+
CUSTOM_TOML = ".toml (custom file)"
3538

3639

3740
class ConfigValueError(ValueError):
@@ -72,6 +75,13 @@ def _load_config_data_from_path(__path: Path) -> RobotConfig:
7275
raise ConfigTypeError(__path, f'Parsing "{__path}" failed: {e}') from e
7376

7477

78+
def get_default_config() -> RobotConfig:
79+
result = RobotConfig()
80+
result.output_dir = "results"
81+
result.python_path = ["./lib", "./resources"]
82+
return result
83+
84+
7585
def load_config_from_path(*__paths: Union[Path, Tuple[Path, ConfigType]]) -> RobotConfig:
7686
result = RobotConfig()
7787

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import re
99
from dataclasses import dataclass
1010
from enum import Enum
11+
from pathlib import Path
1112
from typing import (
1213
Any,
1314
Callable,
@@ -20,7 +21,8 @@
2021
get_type_hints,
2122
)
2223

23-
from robotcode.core.dataclasses import TypeValidationError, ValidateMixin, validate_types
24+
import tomli_w
25+
from robotcode.core.dataclasses import TypeValidationError, ValidateMixin, as_dict, validate_types
2426
from robotcode.core.utils.safe_eval import safe_eval
2527
from typing_extensions import Self
2628

@@ -2101,6 +2103,11 @@ class RobotBaseProfile(CommonOptions, CommonExtraOptions, RobotOptions, RobotExt
21012103
"""
21022104
)
21032105

2106+
def save(self, path: os.PathLike[str]) -> None:
2107+
Path(path).parent.mkdir(parents=True, exist_ok=True)
2108+
with Path(path).open("w", encoding="utf-8") as f:
2109+
f.write(tomli_w.dumps(as_dict(self, remove_defaults=True)))
2110+
21042111

21052112
@dataclass
21062113
class RobotExtraBaseProfile(RobotBaseProfile):
Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,31 @@
11
from pathlib import Path
22
from typing import Callable, Optional, Sequence, Tuple, Union
33

4-
from .loader import (
5-
ConfigType,
6-
DiscoverdBy,
7-
find_project_root,
8-
get_config_files_from_folder,
9-
)
4+
import platformdirs
5+
6+
from .loader import ConfigType, DiscoverdBy, find_project_root, get_config_files_from_folder, get_default_config
7+
8+
9+
def get_user_config_file(
10+
create: bool = True, verbose_callback: Optional[Callable[[str], None]] = None
11+
) -> Optional[Path]:
12+
result = Path(platformdirs.user_config_dir("robotcode", appauthor=False), "robot.toml")
13+
if result.is_file():
14+
if verbose_callback:
15+
verbose_callback(f"Found user configuration file:\n {result}")
16+
return result
17+
18+
if not create:
19+
if verbose_callback:
20+
verbose_callback("User configuration file not found, but create is set to False.")
21+
return None
22+
23+
if verbose_callback:
24+
verbose_callback(f"User configuration file not found, try to create it at:\n {result}")
25+
26+
get_default_config().save(result)
27+
28+
return result
1029

1130

1231
def get_config_files(
@@ -30,21 +49,27 @@ def get_config_files(
3049

3150
if config_files:
3251
if verbose_callback:
33-
verbose_callback("Using config file:" + "\n ".join(str(config_files)))
52+
verbose_callback("Using config file:" + "\n ".join([str(f) for f in config_files]))
3453

35-
return [(f, ConfigType.CUSTOM_TOML) for f in config_files], root_folder, discovered_by
54+
result: Sequence[Tuple[Path, ConfigType]] = [(f, ConfigType.CUSTOM_TOML) for f in config_files]
55+
else:
56+
result = get_config_files_from_folder(root_folder)
3657

37-
result = get_config_files_from_folder(root_folder)
58+
if not result and raise_on_error:
59+
raise FileNotFoundError("Cannot find any configuration file. 😥")
3860

39-
if not result and raise_on_error:
40-
raise FileNotFoundError("Cannot find any configuration file. 😥")
61+
if verbose_callback:
62+
if result:
63+
verbose_callback(
64+
"Found configuration files:\n " + "\n ".join(str(f[0]) for f in result),
65+
)
66+
else:
67+
verbose_callback("No configuration files found.")
4168

42-
if verbose_callback:
43-
if result:
44-
verbose_callback(
45-
"Found configuration files:\n " + "\n ".join(str(f[0]) for f in result),
46-
)
47-
else:
48-
verbose_callback("No configuration files found.")
49-
50-
return result, root_folder, discovered_by
69+
user_config = get_user_config_file(verbose_callback=verbose_callback)
70+
71+
return (
72+
[*([(user_config, ConfigType.USER_DEFAULT_CONFIG_TOML)] if user_config else []), *result],
73+
root_folder,
74+
discovered_by,
75+
)

src/robotcode/cli/commands/config.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ def show(
5050
robotcode --format json config show
5151
```
5252
"""
53-
config_files, _, _ = get_config_files(paths, app.config.config_files, verbose_callback=app.verbose)
54-
5553
try:
54+
config_files, _, _ = get_config_files(paths, app.config.config_files, verbose_callback=app.verbose)
55+
5656
if single:
5757
for file, _ in config_files:
5858
config = load_config_from_path(file)
@@ -65,17 +65,15 @@ def show(
6565

6666
app.print_data(config, remove_defaults=True, default_output_format=OutputFormat.TOML)
6767

68-
except (TypeError, ValueError) as e:
68+
except (TypeError, ValueError, OSError) as e:
6969
raise UnknownError(str(e)) from e
7070

7171

7272
@config.command
7373
@click.argument("paths", type=click.Path(exists=True, path_type=Path), nargs=-1, required=False)
74+
@click.argument("user", type=bool, default=False)
7475
@pass_application
75-
def files(
76-
app: Application,
77-
paths: List[Path],
78-
) -> None:
76+
def files(app: Application, paths: List[Path], user: bool = False) -> None:
7977
"""\
8078
Search for _robot_ configuration files and list them.
8179
@@ -112,11 +110,11 @@ def files(
112110

113111
if app.config.output_format is None or app.config.output_format == OutputFormat.TEXT:
114112
for entry in result["files"]:
115-
app.echo(entry["path"])
113+
app.echo(f'{entry["path"]} ({entry["type"].value})')
116114
else:
117115
app.print_data(result)
118116

119-
except FileNotFoundError as e:
117+
except OSError as e:
120118
raise UnknownError(str(e)) from e
121119

122120

src/robotcode/cli/commands/profiles.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def show(
4141

4242
app.print_data(config, remove_defaults=True, default_output_format=OutputFormat.TOML)
4343

44-
except (TypeError, ValueError, FileNotFoundError) as e:
44+
except (TypeError, ValueError, OSError) as e:
4545
raise UnknownError(str(e)) from e
4646

4747

@@ -90,5 +90,5 @@ def list(
9090
else:
9191
app.print_data(result)
9292

93-
except (TypeError, ValueError, FileNotFoundError) as e:
93+
except (TypeError, ValueError, OSError) as e:
9494
raise UnknownError(str(e)) from e

0 commit comments

Comments
 (0)