robotcode 0.91.0__py3-none-any.whl → 0.93.0__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.
- robotcode/cli/__init__.py +42 -5
- robotcode/cli/__version__.py +1 -1
- robotcode/cli/commands/config.py +75 -51
- robotcode/cli/commands/profiles.py +12 -4
- {robotcode-0.91.0.dist-info → robotcode-0.93.0.dist-info}/METADATA +15 -12
- robotcode-0.93.0.dist-info/RECORD +12 -0
- robotcode-0.91.0.dist-info/RECORD +0 -12
- {robotcode-0.91.0.dist-info → robotcode-0.93.0.dist-info}/WHEEL +0 -0
- {robotcode-0.91.0.dist-info → robotcode-0.93.0.dist-info}/entry_points.txt +0 -0
- {robotcode-0.91.0.dist-info → robotcode-0.93.0.dist-info}/licenses/LICENSE.txt +0 -0
robotcode/cli/__init__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import List, Optional
|
3
|
+
from typing import List, Literal, Optional
|
4
4
|
|
5
5
|
import click
|
6
6
|
|
@@ -49,6 +49,21 @@ from .commands import config, profiles
|
|
49
49
|
If not specified, the default profile is used.
|
50
50
|
""",
|
51
51
|
)
|
52
|
+
@click.option(
|
53
|
+
"-r",
|
54
|
+
"--root",
|
55
|
+
"root",
|
56
|
+
type=click.Path(exists=True, path_type=Path, dir_okay=True, file_okay=False, resolve_path=True),
|
57
|
+
multiple=False,
|
58
|
+
show_envvar=True,
|
59
|
+
help="Specifies the root path to be used for the project. It will be automatically detected if not provided.",
|
60
|
+
)
|
61
|
+
@click.option(
|
62
|
+
"--no-vcs",
|
63
|
+
is_flag=True,
|
64
|
+
show_envvar=True,
|
65
|
+
help="Ignore version control system directories (e.g., .git, .hg) when detecting the project root.",
|
66
|
+
)
|
52
67
|
@click.option(
|
53
68
|
"-f",
|
54
69
|
"--format",
|
@@ -95,6 +110,22 @@ from .commands import config, profiles
|
|
95
110
|
show_default=True,
|
96
111
|
show_envvar=True,
|
97
112
|
)
|
113
|
+
@click.option(
|
114
|
+
"--log-format",
|
115
|
+
type=str,
|
116
|
+
help="Sets the log format. See python logging documentation for more information.",
|
117
|
+
default="%(name)s:%(levelname)s: %(message)s",
|
118
|
+
show_default=True,
|
119
|
+
show_envvar=True,
|
120
|
+
)
|
121
|
+
@click.option(
|
122
|
+
"--log-style",
|
123
|
+
type=click.Choice(["%", "{", "$"]),
|
124
|
+
help="Sets the log style. See python logging documentation for more information.",
|
125
|
+
default="%",
|
126
|
+
show_default=True,
|
127
|
+
show_envvar=True,
|
128
|
+
)
|
98
129
|
@click.option(
|
99
130
|
"--log-filename",
|
100
131
|
type=click.Path(
|
@@ -160,6 +191,8 @@ def robotcode(
|
|
160
191
|
app: Application,
|
161
192
|
config_files: Optional[List[Path]],
|
162
193
|
profiles: Optional[List[str]],
|
194
|
+
root: Optional[Path],
|
195
|
+
no_vcs: bool,
|
163
196
|
format: Optional[OutputFormat],
|
164
197
|
dry: bool,
|
165
198
|
verbose: bool,
|
@@ -167,6 +200,8 @@ def robotcode(
|
|
167
200
|
pager: Optional[bool],
|
168
201
|
log: bool,
|
169
202
|
log_level: str,
|
203
|
+
log_format: str,
|
204
|
+
log_style: Literal["%", "{", "$"],
|
170
205
|
log_filename: Optional[str],
|
171
206
|
log_calls: bool,
|
172
207
|
default_path: Optional[List[str]],
|
@@ -189,6 +224,8 @@ def robotcode(
|
|
189
224
|
app.config.profiles = profiles
|
190
225
|
app.config.dry = dry
|
191
226
|
app.config.verbose = verbose
|
227
|
+
app.config.root = root
|
228
|
+
app.config.no_vcs = no_vcs
|
192
229
|
|
193
230
|
if color is None:
|
194
231
|
app.config.colored_output = ColoredOutput.AUTO
|
@@ -210,7 +247,8 @@ def robotcode(
|
|
210
247
|
|
211
248
|
logging.basicConfig(
|
212
249
|
level=log_level,
|
213
|
-
format=
|
250
|
+
format=log_format,
|
251
|
+
style=log_style,
|
214
252
|
filename=log_filename,
|
215
253
|
)
|
216
254
|
|
@@ -240,9 +278,8 @@ def robotcode(
|
|
240
278
|
robotcode.add_command(config)
|
241
279
|
robotcode.add_command(profiles)
|
242
280
|
|
243
|
-
for
|
244
|
-
|
245
|
-
robotcode.add_command(c)
|
281
|
+
for c in PluginManager.instance().cli_commands:
|
282
|
+
robotcode.add_command(c)
|
246
283
|
|
247
284
|
|
248
285
|
@robotcode.command()
|
robotcode/cli/__version__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.
|
1
|
+
__version__ = "0.93.0"
|
robotcode/cli/commands/config.py
CHANGED
@@ -2,7 +2,7 @@ import dataclasses
|
|
2
2
|
import os
|
3
3
|
from fnmatch import fnmatchcase
|
4
4
|
from pathlib import Path
|
5
|
-
from typing import Any, Dict, List, Optional
|
5
|
+
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple, Type, Union, get_args, get_origin
|
6
6
|
|
7
7
|
import click
|
8
8
|
|
@@ -20,11 +20,9 @@ from robotcode.robot.config.loader import (
|
|
20
20
|
load_robot_config_from_path,
|
21
21
|
)
|
22
22
|
from robotcode.robot.config.model import (
|
23
|
-
|
24
|
-
RebotProfile,
|
23
|
+
BaseOptions,
|
25
24
|
RobotConfig,
|
26
25
|
RobotProfile,
|
27
|
-
TestDocProfile,
|
28
26
|
)
|
29
27
|
from robotcode.robot.config.utils import get_config_files
|
30
28
|
|
@@ -66,11 +64,21 @@ def show(app: Application, single: bool, paths: List[Path]) -> None:
|
|
66
64
|
```
|
67
65
|
"""
|
68
66
|
try:
|
69
|
-
config_files, _, _ = get_config_files(
|
67
|
+
config_files, _, _ = get_config_files(
|
68
|
+
paths,
|
69
|
+
app.config.config_files,
|
70
|
+
root_folder=app.config.root,
|
71
|
+
no_vcs=app.config.no_vcs,
|
72
|
+
verbose_callback=app.verbose,
|
73
|
+
)
|
70
74
|
|
71
75
|
if single:
|
72
76
|
for file, _ in config_files:
|
73
|
-
config = load_robot_config_from_path(
|
77
|
+
config = load_robot_config_from_path(
|
78
|
+
file,
|
79
|
+
extra_tools={k: v for k, v in PluginManager.instance().tool_config_classes},
|
80
|
+
verbose_callback=app.verbose,
|
81
|
+
)
|
74
82
|
click.secho(f"File: {file}")
|
75
83
|
app.print_data(
|
76
84
|
config,
|
@@ -80,7 +88,11 @@ def show(app: Application, single: bool, paths: List[Path]) -> None:
|
|
80
88
|
|
81
89
|
return
|
82
90
|
|
83
|
-
config = load_robot_config_from_path(
|
91
|
+
config = load_robot_config_from_path(
|
92
|
+
*config_files,
|
93
|
+
extra_tools={k: v for k, v in PluginManager.instance().tool_config_classes},
|
94
|
+
verbose_callback=app.verbose,
|
95
|
+
)
|
84
96
|
|
85
97
|
app.print_data(
|
86
98
|
config,
|
@@ -117,7 +129,13 @@ def files(app: Application, paths: List[Path], user: bool = False) -> None:
|
|
117
129
|
"""
|
118
130
|
|
119
131
|
try:
|
120
|
-
config_files, _, discovered_by = get_config_files(
|
132
|
+
config_files, _, discovered_by = get_config_files(
|
133
|
+
paths,
|
134
|
+
app.config.config_files,
|
135
|
+
root_folder=app.config.root,
|
136
|
+
no_vcs=app.config.no_vcs,
|
137
|
+
verbose_callback=app.verbose,
|
138
|
+
)
|
121
139
|
|
122
140
|
result: Dict[str, Any] = {"files": [{"path": str(file), "type": type} for file, type in config_files]}
|
123
141
|
|
@@ -147,7 +165,7 @@ def files(app: Application, paths: List[Path], user: bool = False) -> None:
|
|
147
165
|
required=False,
|
148
166
|
)
|
149
167
|
@pass_application
|
150
|
-
def root(app: Application, paths:
|
168
|
+
def root(app: Application, paths: Tuple[Path, ...]) -> None:
|
151
169
|
"""\
|
152
170
|
Searches for the root folder of the project and prints them.
|
153
171
|
|
@@ -162,7 +180,9 @@ def root(app: Application, paths: List[Path]) -> None:
|
|
162
180
|
```
|
163
181
|
"""
|
164
182
|
|
165
|
-
root_folder, discovered_by = find_project_root(
|
183
|
+
root_folder, discovered_by = find_project_root(
|
184
|
+
*(paths or []), root_folder=app.config.root, no_vcs=app.config.no_vcs
|
185
|
+
)
|
166
186
|
|
167
187
|
if root_folder is None and (app.config.output_format is None or app.config.output_format == OutputFormat.TEXT):
|
168
188
|
raise click.ClickException("Cannot detect root folder. 😥")
|
@@ -193,55 +213,51 @@ def info(app: Application) -> None:
|
|
193
213
|
"""Shows informations about possible configuration settings."""
|
194
214
|
|
195
215
|
|
196
|
-
def
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
216
|
+
def type_to_str(t: Union[Type[Any], str]) -> str:
|
217
|
+
if isinstance(t, str):
|
218
|
+
return f"'{t}'"
|
219
|
+
|
220
|
+
origin = get_origin(t)
|
221
|
+
if origin is None:
|
222
|
+
return t.__name__
|
223
|
+
|
224
|
+
if origin is Union:
|
225
|
+
return " | ".join(type_to_str(a) for a in get_args(t))
|
204
226
|
|
205
|
-
for
|
206
|
-
|
207
|
-
|
227
|
+
return f"{origin.__name__}[{', '.join(type_to_str(a) for a in get_args(t))}]"
|
228
|
+
|
229
|
+
|
230
|
+
def _get_config_fields_for_type(
|
231
|
+
prefix: str, cls: Type[Any], filter: Optional[Callable[[str], bool]] = None
|
232
|
+
) -> Dict[str, Dict[str, str]]:
|
233
|
+
result = {}
|
234
|
+
for field in dataclasses.fields(cls):
|
235
|
+
field_name_encoded = encode_case_for_field_name(cls, field)
|
236
|
+
if filter and not filter(field_name_encoded):
|
208
237
|
continue
|
209
238
|
|
210
|
-
result[
|
211
|
-
"type":
|
239
|
+
result[prefix + field_name_encoded] = {
|
240
|
+
"type": type_to_str(field.type),
|
212
241
|
"description": field.metadata.get("description", "").strip(),
|
213
242
|
}
|
243
|
+
args = get_args(field.type)
|
214
244
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
245
|
+
p = f"{prefix}{'' if prefix[-1]=='.' else '.'}" if prefix else ""
|
246
|
+
for a in args:
|
247
|
+
origin = get_origin(a)
|
248
|
+
if origin is None and issubclass(a, BaseOptions):
|
249
|
+
result.update(_get_config_fields_for_type(f"{p}{field_name_encoded}.", a, filter))
|
250
|
+
return result
|
221
251
|
|
222
|
-
for field in dataclasses.fields(LibDocProfile):
|
223
|
-
field_name_encoded = encode_case_for_field_name(LibDocProfile, field)
|
224
|
-
result["libdoc." + field_name_encoded] = {
|
225
|
-
"type": str(field.type),
|
226
|
-
"description": field.metadata.get("description", "").strip(),
|
227
|
-
}
|
228
252
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
"type": str(field.type),
|
233
|
-
"description": field.metadata.get("description", "").strip(),
|
234
|
-
}
|
253
|
+
def get_config_fields() -> Dict[str, Dict[str, str]]:
|
254
|
+
result = {}
|
255
|
+
result.update(_get_config_fields_for_type("", RobotConfig))
|
235
256
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
field_name_encoded = encode_case_for_field_name(TestDocProfile, field)
|
241
|
-
result[f"{s}." + field_name_encoded] = {
|
242
|
-
"type": str(field.type),
|
243
|
-
"description": field.metadata.get("description", "").strip(),
|
244
|
-
}
|
257
|
+
result.update(_get_config_fields_for_type("[profile].", RobotProfile, lambda x: x not in result))
|
258
|
+
for entry in PluginManager.instance().tool_config_classes:
|
259
|
+
if dataclasses.is_dataclass(entry.config_class):
|
260
|
+
result.update(_get_config_fields_for_type(f"tool.{entry.tool_name}.", entry.config_class))
|
245
261
|
|
246
262
|
return {k: v for k, v in sorted(result.items(), key=lambda item: item[0])}
|
247
263
|
|
@@ -275,7 +291,15 @@ def list(app: Application, name: Optional[List[str]] = None) -> None:
|
|
275
291
|
result.append(field)
|
276
292
|
|
277
293
|
if app.config.output_format is None or app.config.output_format == OutputFormat.TEXT:
|
278
|
-
|
294
|
+
|
295
|
+
def output() -> Iterable[str]:
|
296
|
+
for r in result:
|
297
|
+
yield r + os.linesep
|
298
|
+
|
299
|
+
yield os.linesep
|
300
|
+
yield f"Total: {len(result)}"
|
301
|
+
|
302
|
+
app.echo_via_pager(output())
|
279
303
|
else:
|
280
304
|
app.print_data({"names": result})
|
281
305
|
|
@@ -40,9 +40,11 @@ def profiles() -> None:
|
|
40
40
|
def show(app: Application, no_evaluate: bool, paths: List[Path]) -> None:
|
41
41
|
"""Shows the given profile configuration."""
|
42
42
|
try:
|
43
|
-
config_files, _, _ = get_config_files(
|
43
|
+
config_files, _, _ = get_config_files(
|
44
|
+
paths, app.config.config_files, root_folder=app.config.root, verbose_callback=app.verbose
|
45
|
+
)
|
44
46
|
|
45
|
-
config = load_robot_config_from_path(*config_files).combine_profiles(
|
47
|
+
config = load_robot_config_from_path(*config_files, verbose_callback=app.verbose).combine_profiles(
|
46
48
|
*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error
|
47
49
|
)
|
48
50
|
|
@@ -73,9 +75,15 @@ def list(app: Application, paths: List[Path], show_hidden: bool = False, sort_by
|
|
73
75
|
"""Lists the defined profiles in the current configuration."""
|
74
76
|
|
75
77
|
try:
|
76
|
-
config_files, _, discovered_by = get_config_files(
|
78
|
+
config_files, _, discovered_by = get_config_files(
|
79
|
+
paths,
|
80
|
+
app.config.config_files,
|
81
|
+
root_folder=app.config.root,
|
82
|
+
no_vcs=app.config.no_vcs,
|
83
|
+
verbose_callback=app.verbose,
|
84
|
+
)
|
77
85
|
|
78
|
-
config = load_robot_config_from_path(*config_files)
|
86
|
+
config = load_robot_config_from_path(*config_files, verbose_callback=app.verbose)
|
79
87
|
|
80
88
|
_, selected_profiles, enabled_names = config.combine_profiles_ex(
|
81
89
|
*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: robotcode
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.93.0
|
4
4
|
Summary: Command line interface for RobotCode
|
5
5
|
Project-URL: Homepage, https://robotcode.io
|
6
6
|
Project-URL: Donate, https://opencollective.com/robotcode
|
@@ -33,33 +33,36 @@ Classifier: Topic :: Text Editors :: Integrated Development Environments (IDE)
|
|
33
33
|
Classifier: Topic :: Utilities
|
34
34
|
Classifier: Typing :: Typed
|
35
35
|
Requires-Python: >=3.8
|
36
|
-
Requires-Dist: robotcode-core==0.
|
37
|
-
Requires-Dist: robotcode-plugin==0.
|
38
|
-
Requires-Dist: robotcode-robot==0.
|
36
|
+
Requires-Dist: robotcode-core==0.93.0
|
37
|
+
Requires-Dist: robotcode-plugin==0.93.0
|
38
|
+
Requires-Dist: robotcode-robot==0.93.0
|
39
39
|
Provides-Extra: all
|
40
40
|
Requires-Dist: docutils; extra == 'all'
|
41
41
|
Requires-Dist: pyyaml>=5.4; extra == 'all'
|
42
42
|
Requires-Dist: rich; extra == 'all'
|
43
|
-
Requires-Dist: robotcode-analyze==0.
|
44
|
-
Requires-Dist: robotcode-debugger==0.
|
45
|
-
Requires-Dist: robotcode-language-server==0.
|
46
|
-
Requires-Dist: robotcode-
|
43
|
+
Requires-Dist: robotcode-analyze==0.93.0; extra == 'all'
|
44
|
+
Requires-Dist: robotcode-debugger==0.93.0; extra == 'all'
|
45
|
+
Requires-Dist: robotcode-language-server==0.93.0; extra == 'all'
|
46
|
+
Requires-Dist: robotcode-repl==0.93.0; extra == 'all'
|
47
|
+
Requires-Dist: robotcode-runner==0.93.0; extra == 'all'
|
47
48
|
Requires-Dist: robotframework-robocop>=2.0.0; extra == 'all'
|
48
49
|
Requires-Dist: robotframework-tidy>=2.0.0; extra == 'all'
|
49
50
|
Provides-Extra: analyze
|
50
|
-
Requires-Dist: robotcode-analyze==0.
|
51
|
+
Requires-Dist: robotcode-analyze==0.93.0; extra == 'analyze'
|
51
52
|
Provides-Extra: colored
|
52
53
|
Requires-Dist: rich; extra == 'colored'
|
53
54
|
Provides-Extra: debugger
|
54
|
-
Requires-Dist: robotcode-debugger==0.
|
55
|
+
Requires-Dist: robotcode-debugger==0.93.0; extra == 'debugger'
|
55
56
|
Provides-Extra: languageserver
|
56
|
-
Requires-Dist: robotcode-language-server==0.
|
57
|
+
Requires-Dist: robotcode-language-server==0.93.0; extra == 'languageserver'
|
57
58
|
Provides-Extra: lint
|
58
59
|
Requires-Dist: robotframework-robocop>=2.0.0; extra == 'lint'
|
60
|
+
Provides-Extra: repl
|
61
|
+
Requires-Dist: robotcode-repl==0.93.0; extra == 'repl'
|
59
62
|
Provides-Extra: rest
|
60
63
|
Requires-Dist: docutils; extra == 'rest'
|
61
64
|
Provides-Extra: runner
|
62
|
-
Requires-Dist: robotcode-runner==0.
|
65
|
+
Requires-Dist: robotcode-runner==0.93.0; extra == 'runner'
|
63
66
|
Provides-Extra: tidy
|
64
67
|
Requires-Dist: robotframework-tidy>=2.0.0; extra == 'tidy'
|
65
68
|
Provides-Extra: yaml
|
@@ -0,0 +1,12 @@
|
|
1
|
+
robotcode/cli/__init__.py,sha256=davaLdB53bWWMqm4BMmjktKlL0AyzOuMObZbNbmhiQE,8226
|
2
|
+
robotcode/cli/__main__.py,sha256=hX3nwROMTnsYGT1KS0rXUYrslu9sFzctYdAh66Rcckw,153
|
3
|
+
robotcode/cli/__version__.py,sha256=W-KEJT0wpRrG8XJ2aDG4NSyzaUucgZR9y6mwfCTlku4,23
|
4
|
+
robotcode/cli/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
|
5
|
+
robotcode/cli/commands/__init__.py,sha256=XJHRt_YwMO2Ni2EfL2aj4jkJXMVG6NGFTpzvSVgIRnQ,92
|
6
|
+
robotcode/cli/commands/config.py,sha256=84gG4LrIynfPbEQkQDYA3ZClg50ck32NZyUvAWw9g6w,10479
|
7
|
+
robotcode/cli/commands/profiles.py,sha256=GAyNsnz4vvybkEfktFTjDm-L4zkcntXZtBt385U9oRo,5897
|
8
|
+
robotcode-0.93.0.dist-info/METADATA,sha256=eKwu6UpIwPOazyU3KKtC1bj4TQ23OzHM7CT8Rpdcs-0,6758
|
9
|
+
robotcode-0.93.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
10
|
+
robotcode-0.93.0.dist-info/entry_points.txt,sha256=Pb4DKVVdJb5PboVl48njwk3DkKQHBJOL1A8KkpemqA8,58
|
11
|
+
robotcode-0.93.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
|
12
|
+
robotcode-0.93.0.dist-info/RECORD,,
|
@@ -1,12 +0,0 @@
|
|
1
|
-
robotcode/cli/__init__.py,sha256=6c-evRLgJ0NR08YvynBQzKxAesAbXB0fnrzZ7MvBDM0,7115
|
2
|
-
robotcode/cli/__main__.py,sha256=hX3nwROMTnsYGT1KS0rXUYrslu9sFzctYdAh66Rcckw,153
|
3
|
-
robotcode/cli/__version__.py,sha256=RBon26SFk4Bs08h0XAmTYW8lrYs3N9ihifF9r6VT4Vc,23
|
4
|
-
robotcode/cli/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
|
5
|
-
robotcode/cli/commands/__init__.py,sha256=XJHRt_YwMO2Ni2EfL2aj4jkJXMVG6NGFTpzvSVgIRnQ,92
|
6
|
-
robotcode/cli/commands/config.py,sha256=fCXhxsotQJl3vMSWpCEM-zwV-tST7sZBH7T-5v9j5EU,10061
|
7
|
-
robotcode/cli/commands/profiles.py,sha256=HUCsNMaK75AVSG_A6F1I209xtQH2AICaoLcqpIO7Vjs,5660
|
8
|
-
robotcode-0.91.0.dist-info/METADATA,sha256=IW1fsf7rm_4v9JmF4IWn6BhvmxyTOSqjctFnqROtVuA,6628
|
9
|
-
robotcode-0.91.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
10
|
-
robotcode-0.91.0.dist-info/entry_points.txt,sha256=Pb4DKVVdJb5PboVl48njwk3DkKQHBJOL1A8KkpemqA8,58
|
11
|
-
robotcode-0.91.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
|
12
|
-
robotcode-0.91.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|