robotcode-analyze 2.7.0__py3-none-any.whl → 2.8.0.dev548__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/analyze/__version__.py +1 -1
- robotcode/analyze/cache/cli.py +8 -6
- robotcode/analyze/cli.py +2 -0
- robotcode/analyze/code/cli.py +2 -2
- robotcode/analyze/code/code_analyzer.py +9 -2
- robotcode/analyze/code/diagnostics_context.py +7 -0
- robotcode/analyze/code/robot_framework_language_provider.py +9 -0
- robotcode/analyze/config.py +52 -18
- robotcode/analyze/dump_model.py +155 -0
- {robotcode_analyze-2.7.0.dist-info → robotcode_analyze-2.8.0.dev548.dist-info}/METADATA +6 -5
- robotcode_analyze-2.8.0.dev548.dist-info/RECORD +19 -0
- {robotcode_analyze-2.7.0.dist-info → robotcode_analyze-2.8.0.dev548.dist-info}/WHEEL +1 -1
- robotcode_analyze-2.7.0.dist-info/RECORD +0 -18
- {robotcode_analyze-2.7.0.dist-info → robotcode_analyze-2.8.0.dev548.dist-info}/entry_points.txt +0 -0
robotcode/analyze/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.
|
|
1
|
+
__version__ = "2.8.0-dev.548"
|
robotcode/analyze/cache/cli.py
CHANGED
|
@@ -43,7 +43,7 @@ def _resolve_cache(
|
|
|
43
43
|
cache_base_path = root_folder or Path.cwd()
|
|
44
44
|
if analyzer_config is not None and isinstance(analyzer_config, AnalyzeConfig):
|
|
45
45
|
if analyzer_config.cache is not None and analyzer_config.cache.cache_dir is not None:
|
|
46
|
-
cache_base_path =
|
|
46
|
+
cache_base_path = cache_base_path / analyzer_config.cache.cache_dir
|
|
47
47
|
|
|
48
48
|
cache_base_path = resolve_cache_base_path(cache_base_path)
|
|
49
49
|
|
|
@@ -271,7 +271,9 @@ def cache_list(app: Application, sections: Tuple[str, ...], patterns: Tuple[str,
|
|
|
271
271
|
entries = [e for e in db.list_entries(section) if _entry_matches(e.entry_name, patterns)]
|
|
272
272
|
if not entries:
|
|
273
273
|
continue
|
|
274
|
-
lines.append(
|
|
274
|
+
lines.append(
|
|
275
|
+
f"### {section.name.lower()} ({len(entries)} {'entry' if len(entries) == 1 else 'entries'})"
|
|
276
|
+
)
|
|
275
277
|
lines.append("")
|
|
276
278
|
lines.append("| Name | Size | Created | Modified |")
|
|
277
279
|
lines.append("|---|---:|---|---|")
|
|
@@ -292,7 +294,7 @@ def cache_list(app: Application, sections: Tuple[str, ...], patterns: Tuple[str,
|
|
|
292
294
|
if not entries:
|
|
293
295
|
continue
|
|
294
296
|
found = True
|
|
295
|
-
app.echo(f"[{section.name.lower()}] ({len(entries)} entries)")
|
|
297
|
+
app.echo(f"[{section.name.lower()}] ({len(entries)} {'entry' if len(entries) == 1 else 'entries'})")
|
|
296
298
|
for entry in entries:
|
|
297
299
|
size = _format_bytes(entry.meta_bytes + entry.data_bytes)
|
|
298
300
|
created = entry.created_at or "—"
|
|
@@ -360,11 +362,11 @@ def cache_clear(app: Application, sections: Tuple[str, ...], paths: Tuple[Path,
|
|
|
360
362
|
for section in selected:
|
|
361
363
|
count = db.clear_section(section)
|
|
362
364
|
total += count
|
|
363
|
-
app.echo(f"Cleared {count} entries from {section.name.lower()}.")
|
|
365
|
+
app.echo(f"Cleared {count} {'entry' if count == 1 else 'entries'} from {section.name.lower()}.")
|
|
364
366
|
else:
|
|
365
367
|
total = db.clear_all()
|
|
366
368
|
|
|
367
|
-
app.echo(f"Removed {total} entries total.")
|
|
369
|
+
app.echo(f"Removed {total} {'entry' if total == 1 else 'entries'} total.")
|
|
368
370
|
finally:
|
|
369
371
|
db.close()
|
|
370
372
|
|
|
@@ -390,7 +392,7 @@ def _resolve_cache_root(
|
|
|
390
392
|
cache_base_path = root_folder or Path.cwd()
|
|
391
393
|
if analyzer_config is not None and isinstance(analyzer_config, AnalyzeConfig):
|
|
392
394
|
if analyzer_config.cache is not None and analyzer_config.cache.cache_dir is not None:
|
|
393
|
-
cache_base_path =
|
|
395
|
+
cache_base_path = cache_base_path / analyzer_config.cache.cache_dir
|
|
394
396
|
|
|
395
397
|
cache_base_path = resolve_cache_base_path(cache_base_path)
|
|
396
398
|
|
robotcode/analyze/cli.py
CHANGED
|
@@ -5,6 +5,7 @@ from robotcode.plugin import Application, pass_application
|
|
|
5
5
|
from .__version__ import __version__
|
|
6
6
|
from .cache.cli import cache_group
|
|
7
7
|
from .code.cli import code
|
|
8
|
+
from .dump_model import dump_model
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@click.group(
|
|
@@ -26,3 +27,4 @@ def analyze(app: Application) -> None:
|
|
|
26
27
|
|
|
27
28
|
analyze.add_command(cache_group)
|
|
28
29
|
analyze.add_command(code)
|
|
30
|
+
analyze.add_command(dump_model)
|
robotcode/analyze/code/cli.py
CHANGED
|
@@ -473,8 +473,8 @@ def code(
|
|
|
473
473
|
Performs static code analysis to identify potential issues in the specified *PATHS*. The analysis detects syntax
|
|
474
474
|
errors, missing keywords or variables, missing arguments, and other problems.
|
|
475
475
|
|
|
476
|
-
- **PATHS**: Can be individual files or directories. If no *PATHS* are provided, the
|
|
477
|
-
analyzed
|
|
476
|
+
- **PATHS**: Can be individual files or directories. If no *PATHS* are provided, the whole project is
|
|
477
|
+
analyzed.
|
|
478
478
|
|
|
479
479
|
The return code is a bitwise combination of the following values:
|
|
480
480
|
|
|
@@ -136,6 +136,8 @@ class CodeAnalyzer(DiagnosticsContext):
|
|
|
136
136
|
# Always yield, even when empty: the result collector uses this to count analyzed files.
|
|
137
137
|
yield DocumentDiagnosticReport(document, diagnostics)
|
|
138
138
|
|
|
139
|
+
self.diagnostics.finish_folder(folder)
|
|
140
|
+
|
|
139
141
|
def collect_documents(
|
|
140
142
|
self, folder: WorkspaceFolder, paths: Iterable[Path] = (), filter_patterns: Iterable[str] = ()
|
|
141
143
|
) -> List[TextDocument]:
|
|
@@ -168,7 +170,12 @@ class CodeAnalyzer(DiagnosticsContext):
|
|
|
168
170
|
self.app.error(f"Error reading {file}: {e}")
|
|
169
171
|
continue
|
|
170
172
|
|
|
171
|
-
self.app.verbose(
|
|
172
|
-
|
|
173
|
+
self.app.verbose(
|
|
174
|
+
f"{file_counter} {'file' if file_counter == 1 else 'files'} in workspace folder '{folder.uri.to_path()}'"
|
|
175
|
+
)
|
|
176
|
+
self.app.verbose(
|
|
177
|
+
f"Collected {len(documents)} {'file' if len(documents) == 1 else 'files'} for analyzing "
|
|
178
|
+
f"in workspace folder '{folder.uri.to_path()}'"
|
|
179
|
+
)
|
|
173
180
|
|
|
174
181
|
return documents
|
|
@@ -19,6 +19,9 @@ class DiagnosticHandlers:
|
|
|
19
19
|
@event
|
|
20
20
|
def document_collectors(sender, document: TextDocument) -> Optional[List[Diagnostic]]: ...
|
|
21
21
|
|
|
22
|
+
@event
|
|
23
|
+
def folder_finishers(sender, folder: WorkspaceFolder) -> None: ...
|
|
24
|
+
|
|
22
25
|
def analyze_folder(self, folder: WorkspaceFolder) -> List[Union[List[Diagnostic], BaseException, None]]:
|
|
23
26
|
return self.folder_analyzers(
|
|
24
27
|
self,
|
|
@@ -42,6 +45,10 @@ class DiagnosticHandlers:
|
|
|
42
45
|
return_exceptions=False,
|
|
43
46
|
)
|
|
44
47
|
|
|
48
|
+
def finish_folder(self, folder: WorkspaceFolder) -> None:
|
|
49
|
+
"""After the documents of a folder were analyzed and their diagnostics collected."""
|
|
50
|
+
self.folder_finishers(self, folder, return_exceptions=False)
|
|
51
|
+
|
|
45
52
|
|
|
46
53
|
class DiagnosticsContext(ABC):
|
|
47
54
|
@property
|
|
@@ -58,10 +58,15 @@ class RobotFrameworkLanguageProvider(LanguageProvider):
|
|
|
58
58
|
self.diagnostics_context.diagnostics.folder_analyzers.add(self.analyze_folder)
|
|
59
59
|
self.diagnostics_context.diagnostics.document_analyzers.add(self.analyze_document)
|
|
60
60
|
self.diagnostics_context.diagnostics.document_collectors.add(self.collect_diagnostics)
|
|
61
|
+
self.diagnostics_context.diagnostics.folder_finishers.add(self.finish_folder)
|
|
61
62
|
if self.diagnostics_context.collect_unused:
|
|
62
63
|
self.diagnostics_context.diagnostics.document_collectors.add(self.collect_unused_keywords)
|
|
63
64
|
self.diagnostics_context.diagnostics.document_collectors.add(self.collect_unused_variables)
|
|
64
65
|
|
|
66
|
+
@property
|
|
67
|
+
def document_cache(self) -> DocumentsCacheHelper:
|
|
68
|
+
return self._document_cache
|
|
69
|
+
|
|
65
70
|
def _update_python_path(self) -> None:
|
|
66
71
|
root_path = (
|
|
67
72
|
self.diagnostics_context.workspace.root_uri.to_path()
|
|
@@ -120,6 +125,10 @@ class RobotFrameworkLanguageProvider(LanguageProvider):
|
|
|
120
125
|
|
|
121
126
|
return None
|
|
122
127
|
|
|
128
|
+
def finish_folder(self, sender: Any, folder: WorkspaceFolder) -> None:
|
|
129
|
+
# the cache is shared with the language server and other runs, so only files that do not exist lose entries
|
|
130
|
+
self._document_cache.remove_cached_analyses_of_missing_files(folder)
|
|
131
|
+
|
|
123
132
|
def collect_diagnostics(self, sender: Any, document: TextDocument) -> Optional[List[Diagnostic]]:
|
|
124
133
|
namespace = self._document_cache.get_namespace(document)
|
|
125
134
|
|
robotcode/analyze/config.py
CHANGED
|
@@ -30,12 +30,14 @@ class ModifiersConfig(BaseOptions):
|
|
|
30
30
|
extend_ignore: Optional[List[str]] = field(
|
|
31
31
|
description="""
|
|
32
32
|
Extend the diagnostics codes to ignore.
|
|
33
|
+
It takes effect in `[tool.robotcode-analyze.extend-modifiers]`, where it adds to the codes set so far,
|
|
34
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
33
35
|
|
|
34
36
|
Examples:
|
|
35
37
|
|
|
36
38
|
```toml
|
|
37
|
-
[tool.robotcode-analyze.modifiers]
|
|
38
|
-
|
|
39
|
+
[tool.robotcode-analyze.extend-modifiers]
|
|
40
|
+
extend-ignore = ["VariableNotFound", "multiple-keywords"]
|
|
39
41
|
```
|
|
40
42
|
""",
|
|
41
43
|
alias="extend-ignore",
|
|
@@ -55,12 +57,14 @@ class ModifiersConfig(BaseOptions):
|
|
|
55
57
|
extend_error: Optional[List[str]] = field(
|
|
56
58
|
description="""
|
|
57
59
|
Extend the diagnostics codes to treat as errors.
|
|
60
|
+
It takes effect in `[tool.robotcode-analyze.extend-modifiers]`, where it adds to the codes set so far,
|
|
61
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
58
62
|
|
|
59
63
|
Examples:
|
|
60
64
|
|
|
61
65
|
```toml
|
|
62
|
-
[tool.robotcode-analyze.modifiers]
|
|
63
|
-
|
|
66
|
+
[tool.robotcode-analyze.extend-modifiers]
|
|
67
|
+
extend-error = ["VariableNotFound", "multiple-keywords"]
|
|
64
68
|
```
|
|
65
69
|
""",
|
|
66
70
|
alias="extend-error",
|
|
@@ -80,12 +84,14 @@ class ModifiersConfig(BaseOptions):
|
|
|
80
84
|
extend_warning: Optional[List[str]] = field(
|
|
81
85
|
description="""
|
|
82
86
|
Extend the diagnostics codes to treat as warning.
|
|
87
|
+
It takes effect in `[tool.robotcode-analyze.extend-modifiers]`, where it adds to the codes set so far,
|
|
88
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
83
89
|
|
|
84
90
|
Examples:
|
|
85
91
|
|
|
86
92
|
```toml
|
|
87
|
-
[tool.robotcode-analyze.modifiers]
|
|
88
|
-
|
|
93
|
+
[tool.robotcode-analyze.extend-modifiers]
|
|
94
|
+
extend-warning = ["VariableNotFound", "multiple-keywords"]
|
|
89
95
|
```
|
|
90
96
|
""",
|
|
91
97
|
alias="extend-warning",
|
|
@@ -105,12 +111,14 @@ class ModifiersConfig(BaseOptions):
|
|
|
105
111
|
extend_information: Optional[List[str]] = field(
|
|
106
112
|
description="""
|
|
107
113
|
Extend the diagnostics codes to treat as information.
|
|
114
|
+
It takes effect in `[tool.robotcode-analyze.extend-modifiers]`, where it adds to the codes set so far,
|
|
115
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
108
116
|
|
|
109
117
|
Examples:
|
|
110
118
|
|
|
111
119
|
```toml
|
|
112
|
-
[tool.robotcode-analyze.modifiers]
|
|
113
|
-
|
|
120
|
+
[tool.robotcode-analyze.extend-modifiers]
|
|
121
|
+
extend-information = ["VariableNotFound", "multiple-keywords"]
|
|
114
122
|
```
|
|
115
123
|
""",
|
|
116
124
|
alias="extend-information",
|
|
@@ -130,12 +138,14 @@ class ModifiersConfig(BaseOptions):
|
|
|
130
138
|
extend_hint: Optional[List[str]] = field(
|
|
131
139
|
description="""
|
|
132
140
|
Extend the diagnostics codes to treat as hint.
|
|
141
|
+
It takes effect in `[tool.robotcode-analyze.extend-modifiers]`, where it adds to the codes set so far,
|
|
142
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
133
143
|
|
|
134
144
|
Examples:
|
|
135
145
|
|
|
136
146
|
```toml
|
|
137
|
-
[tool.robotcode-analyze.modifiers]
|
|
138
|
-
|
|
147
|
+
[tool.robotcode-analyze.extend-modifiers]
|
|
148
|
+
extend-hint = ["VariableNotFound", "multiple-keywords"]
|
|
139
149
|
```
|
|
140
150
|
""",
|
|
141
151
|
alias="extend-hint",
|
|
@@ -146,7 +156,15 @@ class ModifiersConfig(BaseOptions):
|
|
|
146
156
|
class CacheConfig(BaseOptions):
|
|
147
157
|
"""Cache configuration."""
|
|
148
158
|
|
|
149
|
-
cache_dir: Optional[str] = field(
|
|
159
|
+
cache_dir: Optional[str] = field(
|
|
160
|
+
description="""\
|
|
161
|
+
Path to the cache directory. A relative path counts from the project root.
|
|
162
|
+
|
|
163
|
+
`robotcode analyze` and the language server keep their cache there, in a `.robotcode_cache`
|
|
164
|
+
folder. For `robotcode analyze`, the `ROBOTCODE_CACHE_DIR` environment variable takes precedence.
|
|
165
|
+
""",
|
|
166
|
+
alias="cache-dir",
|
|
167
|
+
)
|
|
150
168
|
|
|
151
169
|
ignored_libraries: Optional[List[str]] = field(
|
|
152
170
|
description="""\
|
|
@@ -164,7 +182,11 @@ class CacheConfig(BaseOptions):
|
|
|
164
182
|
alias="ignored-libraries",
|
|
165
183
|
)
|
|
166
184
|
extend_ignored_libraries: Optional[List[str]] = field(
|
|
167
|
-
description="
|
|
185
|
+
description="""\
|
|
186
|
+
Extend the ignored libraries setting.
|
|
187
|
+
It takes effect in `[tool.robotcode-analyze.extend-cache]`, where it adds to the list set so far,
|
|
188
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
189
|
+
""",
|
|
168
190
|
alias="extend-ignored-libraries",
|
|
169
191
|
)
|
|
170
192
|
|
|
@@ -183,14 +205,18 @@ class CacheConfig(BaseOptions):
|
|
|
183
205
|
alias="ignored-variables",
|
|
184
206
|
)
|
|
185
207
|
extend_ignored_variables: Optional[List[str]] = field(
|
|
186
|
-
description="
|
|
208
|
+
description="""\
|
|
209
|
+
Extend the ignored variables setting.
|
|
210
|
+
It takes effect in `[tool.robotcode-analyze.extend-cache]`, where it adds to the list set so far,
|
|
211
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
212
|
+
""",
|
|
187
213
|
alias="extend-ignored-variables",
|
|
188
214
|
)
|
|
189
215
|
|
|
190
216
|
ignore_arguments_for_library: Optional[List[str]] = field(
|
|
191
217
|
description="""\
|
|
192
218
|
Specifies a list of libraries for which arguments will be ignored during analysis.
|
|
193
|
-
This is
|
|
219
|
+
This is useful if you have a library that gets variables from a python file as arguments that contains
|
|
194
220
|
complex data like big dictionaries or complex objects that **RobotCode** can't handle.
|
|
195
221
|
You can specify a glob pattern that matches the library name or the source file.
|
|
196
222
|
|
|
@@ -207,7 +233,11 @@ class CacheConfig(BaseOptions):
|
|
|
207
233
|
alias="ignore-arguments-for-library",
|
|
208
234
|
)
|
|
209
235
|
extend_ignore_arguments_for_library: Optional[List[str]] = field(
|
|
210
|
-
description="
|
|
236
|
+
description="""\
|
|
237
|
+
Extend the ignore arguments for library settings.
|
|
238
|
+
It takes effect in `[tool.robotcode-analyze.extend-cache]`, where it adds to the list set so far,
|
|
239
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
240
|
+
""",
|
|
211
241
|
alias="extend-ignore-arguments-for-library",
|
|
212
242
|
)
|
|
213
243
|
|
|
@@ -277,7 +307,11 @@ class CodeConfig(BaseOptions):
|
|
|
277
307
|
alias="exit-code-mask",
|
|
278
308
|
)
|
|
279
309
|
extend_exit_code_mask: Optional[ExitCodeMaskList] = field(
|
|
280
|
-
description="
|
|
310
|
+
description="""\
|
|
311
|
+
Extend the exit code mask setting.
|
|
312
|
+
It takes effect in `[tool.robotcode-analyze.extend-code]`, where it adds to the mask set so far,
|
|
313
|
+
for example in `robot.toml` when used in `.robot.toml`.
|
|
314
|
+
""",
|
|
281
315
|
alias="extend-exit-code-mask",
|
|
282
316
|
)
|
|
283
317
|
|
|
@@ -367,7 +401,7 @@ class AnalyzeConfig(BaseOptions):
|
|
|
367
401
|
description="""\
|
|
368
402
|
Specifies a global [search order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-explicit-priority-between-libraries-and-resources)
|
|
369
403
|
for libraries and resources.
|
|
370
|
-
This is
|
|
404
|
+
This is useful when you have libraries containing keywords with the same name. **RobotCode** is unable to
|
|
371
405
|
analyze the library search order in a file specified with
|
|
372
406
|
[`Set Library Search Order`](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html#Set%20Library%20Search%20Order),
|
|
373
407
|
so you can define a global order here. Just make sure to call the `Set Library Search Order`
|
|
@@ -440,7 +474,6 @@ class AnalyzeConfig(BaseOptions):
|
|
|
440
474
|
semantic_model=self.semantic_model if self.semantic_model is not None else False,
|
|
441
475
|
cache=(
|
|
442
476
|
WorkspaceCacheConfig(
|
|
443
|
-
# TODO savelocation
|
|
444
477
|
ignored_libraries=self.cache.ignored_libraries or [],
|
|
445
478
|
ignored_variables=self.cache.ignored_variables or [],
|
|
446
479
|
ignore_arguments_for_library=self.cache.ignore_arguments_for_library or [],
|
|
@@ -449,6 +482,7 @@ class AnalyzeConfig(BaseOptions):
|
|
|
449
482
|
if self.cache is not None
|
|
450
483
|
else WorkspaceCacheConfig()
|
|
451
484
|
),
|
|
485
|
+
cache_dir=self.cache.cache_dir if self.cache is not None else None,
|
|
452
486
|
robot=AnalysisRobotConfig(
|
|
453
487
|
global_library_search_order=self.global_library_search_order or [],
|
|
454
488
|
load_library_timeout=self.load_library_timeout,
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Hidden `robotcode analyze dump-model` command.
|
|
2
|
+
|
|
3
|
+
Developer/diagnostic tool: builds the real namespace for a single file — same
|
|
4
|
+
configuration path as `robotcode analyze code` (robot.toml, profiles,
|
|
5
|
+
`-v`/`-V`/`-P` overrides) — with the semantic-model build forced on, and
|
|
6
|
+
serializes the resulting `SemanticModel` to deterministic JSON. The JSON
|
|
7
|
+
format carries no stability guarantee.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional, Tuple
|
|
13
|
+
|
|
14
|
+
import click
|
|
15
|
+
|
|
16
|
+
from robotcode.core.utils.cli import show_hidden_arguments
|
|
17
|
+
from robotcode.plugin import Application, pass_application
|
|
18
|
+
from robotcode.robot.config.loader import load_robot_config_from_path
|
|
19
|
+
from robotcode.robot.config.utils import get_config_files
|
|
20
|
+
from robotcode.robot.diagnostics.semantic_analyzer.json_dump import model_to_dict
|
|
21
|
+
|
|
22
|
+
from .code.code_analyzer import CodeAnalyzer
|
|
23
|
+
from .code.robot_framework_language_provider import RobotFrameworkLanguageProvider
|
|
24
|
+
from .config import AnalyzeConfig
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@click.command(name="dump-model", add_help_option=True, hidden=show_hidden_arguments())
|
|
28
|
+
@click.option(
|
|
29
|
+
"-v",
|
|
30
|
+
"--variable",
|
|
31
|
+
metavar="name:value",
|
|
32
|
+
type=str,
|
|
33
|
+
multiple=True,
|
|
34
|
+
help="Set variables in the test data. see `robot --variable` option.",
|
|
35
|
+
)
|
|
36
|
+
@click.option(
|
|
37
|
+
"-V",
|
|
38
|
+
"--variablefile",
|
|
39
|
+
metavar="PATH",
|
|
40
|
+
type=str,
|
|
41
|
+
multiple=True,
|
|
42
|
+
help="Python or YAML file file to read variables from. see `robot --variablefile` option.",
|
|
43
|
+
)
|
|
44
|
+
@click.option(
|
|
45
|
+
"-P",
|
|
46
|
+
"--pythonpath",
|
|
47
|
+
metavar="PATH",
|
|
48
|
+
type=str,
|
|
49
|
+
multiple=True,
|
|
50
|
+
help="Additional locations where to search test libraries"
|
|
51
|
+
" and other extensions when they are imported. see `robot --pythonpath` option.",
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
"-o",
|
|
55
|
+
"--output",
|
|
56
|
+
metavar="FILE",
|
|
57
|
+
type=click.Path(dir_okay=False, writable=True, path_type=Path),
|
|
58
|
+
default=None,
|
|
59
|
+
help="Write the JSON dump to FILE instead of stdout.",
|
|
60
|
+
)
|
|
61
|
+
@click.argument("file", nargs=1, type=click.Path(exists=True, dir_okay=False, readable=True, path_type=Path))
|
|
62
|
+
@pass_application
|
|
63
|
+
def dump_model(
|
|
64
|
+
app: Application,
|
|
65
|
+
variable: Tuple[str, ...],
|
|
66
|
+
variablefile: Tuple[str, ...],
|
|
67
|
+
pythonpath: Tuple[str, ...],
|
|
68
|
+
output: Optional[Path],
|
|
69
|
+
file: Path,
|
|
70
|
+
) -> None:
|
|
71
|
+
"""\
|
|
72
|
+
Dumps the semantic model of a Robot Framework FILE as JSON.
|
|
73
|
+
|
|
74
|
+
Developer/diagnostic tool: the semantic-model build is forced regardless
|
|
75
|
+
of the `robotcode.experimental.semanticModel` setting. The JSON format is
|
|
76
|
+
not a stable interface and may change without notice.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
config_files, root_folder, _ = get_config_files(
|
|
80
|
+
[file],
|
|
81
|
+
app.config.config_files,
|
|
82
|
+
root_folder=app.config.root,
|
|
83
|
+
no_vcs=app.config.no_vcs,
|
|
84
|
+
verbose_callback=app.verbose,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
robot_config = load_robot_config_from_path(
|
|
88
|
+
*config_files, extra_tools={"robotcode-analyze": AnalyzeConfig}, verbose_callback=app.verbose
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
analyzer_config = robot_config.tool.get("robotcode-analyze", None) if robot_config.tool is not None else None
|
|
92
|
+
if analyzer_config is None:
|
|
93
|
+
analyzer_config = AnalyzeConfig()
|
|
94
|
+
|
|
95
|
+
robot_profile = robot_config.combine_profiles(
|
|
96
|
+
*(app.config.profiles or []), verbose_callback=app.verbose, error_callback=app.error
|
|
97
|
+
).evaluated_with_env()
|
|
98
|
+
|
|
99
|
+
if variable:
|
|
100
|
+
if robot_profile.variables is None:
|
|
101
|
+
robot_profile.variables = {}
|
|
102
|
+
for v in variable:
|
|
103
|
+
name, value = v.split(":", 1) if ":" in v else (v, "")
|
|
104
|
+
robot_profile.variables.update({name: value})
|
|
105
|
+
|
|
106
|
+
if pythonpath:
|
|
107
|
+
if robot_profile.python_path is None:
|
|
108
|
+
robot_profile.python_path = []
|
|
109
|
+
robot_profile.python_path.extend(pythonpath)
|
|
110
|
+
|
|
111
|
+
if variablefile:
|
|
112
|
+
if robot_profile.variable_files is None:
|
|
113
|
+
robot_profile.variable_files = []
|
|
114
|
+
for vf in variablefile:
|
|
115
|
+
robot_profile.variable_files.append(vf)
|
|
116
|
+
|
|
117
|
+
analysis_config = analyzer_config.to_workspace_analysis_config()
|
|
118
|
+
analysis_config.semantic_model = True
|
|
119
|
+
|
|
120
|
+
analyzer = CodeAnalyzer(
|
|
121
|
+
app=app,
|
|
122
|
+
analysis_config=analysis_config,
|
|
123
|
+
robot_profile=robot_profile,
|
|
124
|
+
root_folder=root_folder,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
provider = next((h for h in analyzer.language_handlers if isinstance(h, RobotFrameworkLanguageProvider)), None)
|
|
128
|
+
if provider is None:
|
|
129
|
+
raise click.ClickException("no Robot Framework language provider available")
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
document = analyzer.workspace.documents.get_or_open_document(file.absolute())
|
|
133
|
+
namespace = provider.document_cache.get_namespace(document)
|
|
134
|
+
namespace.analyze()
|
|
135
|
+
except (SystemExit, KeyboardInterrupt):
|
|
136
|
+
raise
|
|
137
|
+
except BaseException as e:
|
|
138
|
+
raise click.ClickException(f"cannot analyze '{file}': {e}") from e
|
|
139
|
+
|
|
140
|
+
semantic_model = namespace.semantic_model
|
|
141
|
+
if semantic_model is None:
|
|
142
|
+
raise click.ClickException(f"no semantic model was built for '{file}'")
|
|
143
|
+
|
|
144
|
+
dump = model_to_dict(
|
|
145
|
+
semantic_model,
|
|
146
|
+
workspace_root=analyzer.root_folder,
|
|
147
|
+
source=str(document.uri.to_path()),
|
|
148
|
+
)
|
|
149
|
+
text = json.dumps(dump, indent=2, ensure_ascii=False)
|
|
150
|
+
|
|
151
|
+
if output is not None:
|
|
152
|
+
output.write_text(text + "\n", encoding="utf-8")
|
|
153
|
+
app.verbose(f"Semantic model written to {output}")
|
|
154
|
+
else:
|
|
155
|
+
click.echo(text)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: robotcode-analyze
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.0-dev.548
|
|
4
4
|
Summary: RobotCode analyze plugin for Robot Framework
|
|
5
5
|
Project-URL: Homepage, https://robotcode.io
|
|
6
6
|
Project-URL: Donate, https://opencollective.com/robotcode
|
|
@@ -20,14 +20,15 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.12
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.13
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
23
24
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
24
25
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
25
26
|
Classifier: Topic :: Utilities
|
|
26
27
|
Classifier: Typing :: Typed
|
|
27
28
|
Requires-Python: >=3.10
|
|
28
|
-
Requires-Dist: robotcode-plugin==2.
|
|
29
|
-
Requires-Dist: robotcode-robot==2.
|
|
30
|
-
Requires-Dist: robotcode==2.
|
|
29
|
+
Requires-Dist: robotcode-plugin==2.8.0-dev.548
|
|
30
|
+
Requires-Dist: robotcode-robot==2.8.0-dev.548
|
|
31
|
+
Requires-Dist: robotcode==2.8.0-dev.548
|
|
31
32
|
Requires-Dist: robotframework>=5.0.0
|
|
32
33
|
Description-Content-Type: text/markdown
|
|
33
34
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
robotcode/analyze/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
robotcode/analyze/__version__.py,sha256=4qGR5Sg7VszfoERVpnszHJ_tsWJ0G_bUZdheH0_dqx4,30
|
|
3
|
+
robotcode/analyze/cli.py,sha256=MxGeNvscB-I_h00dag3N2Gmbv-frfuYAUAxfkRo26ys,774
|
|
4
|
+
robotcode/analyze/config.py,sha256=F9_k3-flt2LjJvmENst8F8OHubYCTR65kZQkQE5kdKU,17996
|
|
5
|
+
robotcode/analyze/dump_model.py,sha256=eNTZoZDiQ0tX5VMp4qtiEvtQAHevB6LbOf3XSmmeM20,5264
|
|
6
|
+
robotcode/analyze/hooks.py,sha256=9YHoDSycYreznXuAdwgjSUo48Kxj-qgCchmx2UxtTQQ,396
|
|
7
|
+
robotcode/analyze/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
|
|
8
|
+
robotcode/analyze/cache/cli.py,sha256=TenomugqcXhnFvOgRwV_25q-UPgwLJ0vJLGJnxWchaw,15968
|
|
9
|
+
robotcode/analyze/code/_models.py,sha256=-MO9BGNqrgv2dkEqPGcO6suvANUew0NPXJu5g1CmQS0,1043
|
|
10
|
+
robotcode/analyze/code/_sarif.py,sha256=OjS5X3fvDQxwsE2nZROSrfEgpQNhhbcuV2Um4UP_OCI,2434
|
|
11
|
+
robotcode/analyze/code/cli.py,sha256=-kfa7jmhMLNeIsqmUnYl0K0UWn527q7rDc4qioRshKQ,37945
|
|
12
|
+
robotcode/analyze/code/code_analyzer.py,sha256=NREAZMBPIIbtxeWAjcp6OQediAsenDWUWJFxnxru95o,7349
|
|
13
|
+
robotcode/analyze/code/diagnostics_context.py,sha256=9JZjexOaCBXKZQFn4eUjwiKr1kGhRiZuD2f9czrSSS0,2411
|
|
14
|
+
robotcode/analyze/code/language_provider.py,sha256=Hh3WFtB4p0_brCNgCVZuYZfxyJ0oQ0tXW70b4UXevwM,751
|
|
15
|
+
robotcode/analyze/code/robot_framework_language_provider.py,sha256=z9dR-8QgKUdeFx6vqKq28CvxwWMKRhs1nMii2W76fcU,8541
|
|
16
|
+
robotcode_analyze-2.8.0.dev548.dist-info/METADATA,sha256=9AWwGPnxZAJTe3Cc5XCBA1GspAAgYPXBAbwach9MOwg,2953
|
|
17
|
+
robotcode_analyze-2.8.0.dev548.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
18
|
+
robotcode_analyze-2.8.0.dev548.dist-info/entry_points.txt,sha256=tnZjhZ4BA_m0ZhDzh2TguYSOq4ywFVyFLetV10BAExI,46
|
|
19
|
+
robotcode_analyze-2.8.0.dev548.dist-info/RECORD,,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
robotcode/analyze/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
robotcode/analyze/__version__.py,sha256=EtKWW0Hnl5oWglRNH0HZigvcDT2FEs58ek8buJdwW1E,22
|
|
3
|
-
robotcode/analyze/cli.py,sha256=-8PhF_qsQa40qy-f-qbKs9drus7u1hG0v9zqkPraM4w,707
|
|
4
|
-
robotcode/analyze/config.py,sha256=SsQW2bUCUtmZc6uNS9woGky0BMVf9Q6AlaLEbzbkAh8,15856
|
|
5
|
-
robotcode/analyze/hooks.py,sha256=9YHoDSycYreznXuAdwgjSUo48Kxj-qgCchmx2UxtTQQ,396
|
|
6
|
-
robotcode/analyze/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
|
|
7
|
-
robotcode/analyze/cache/cli.py,sha256=J5-9lgqmWXliBB6zDh0OljUgEJ9qycCVn_NOoRrUybE,15760
|
|
8
|
-
robotcode/analyze/code/_models.py,sha256=-MO9BGNqrgv2dkEqPGcO6suvANUew0NPXJu5g1CmQS0,1043
|
|
9
|
-
robotcode/analyze/code/_sarif.py,sha256=OjS5X3fvDQxwsE2nZROSrfEgpQNhhbcuV2Um4UP_OCI,2434
|
|
10
|
-
robotcode/analyze/code/cli.py,sha256=mEsA_eedYK1qbI8YeIoft2wLSVaHOvyVk0-X5l62-ig,37960
|
|
11
|
-
robotcode/analyze/code/code_analyzer.py,sha256=NaYC9oQqJmJXWxQ0JBeH9GiA2F-JqIPNERRGHMDwsKA,7161
|
|
12
|
-
robotcode/analyze/code/diagnostics_context.py,sha256=1vKIcudZeJDXGSqrgCK30vD3SYep5j_yTm0linZPKTE,2103
|
|
13
|
-
robotcode/analyze/code/language_provider.py,sha256=Hh3WFtB4p0_brCNgCVZuYZfxyJ0oQ0tXW70b4UXevwM,751
|
|
14
|
-
robotcode/analyze/code/robot_framework_language_provider.py,sha256=kziIELOjqUwtMBh0qkNd59QGsOWr-wPWCVIsv2uxsCE,8081
|
|
15
|
-
robotcode_analyze-2.7.0.dist-info/METADATA,sha256=QMVK87TLQo8FJNCinVnmE4RRgpHyxppRc-8AewZKjdg,2870
|
|
16
|
-
robotcode_analyze-2.7.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
17
|
-
robotcode_analyze-2.7.0.dist-info/entry_points.txt,sha256=tnZjhZ4BA_m0ZhDzh2TguYSOq4ywFVyFLetV10BAExI,46
|
|
18
|
-
robotcode_analyze-2.7.0.dist-info/RECORD,,
|
{robotcode_analyze-2.7.0.dist-info → robotcode_analyze-2.8.0.dev548.dist-info}/entry_points.txt
RENAMED
|
File without changes
|