robotcode-repl 0.99.0__tar.gz → 0.100.0__tar.gz
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_repl-0.99.0 → robotcode_repl-0.100.0}/PKG-INFO +4 -4
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/README.md +2 -1
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/pyproject.toml +1 -2
- robotcode_repl-0.100.0/src/robotcode/repl/__version__.py +1 -0
- robotcode_repl-0.99.0/src/robotcode/repl/interpreter.py → robotcode_repl-0.100.0/src/robotcode/repl/base_interpreter.py +68 -146
- robotcode_repl-0.100.0/src/robotcode/repl/cli.py +141 -0
- robotcode_repl-0.100.0/src/robotcode/repl/console_interpreter.py +140 -0
- robotcode_repl-0.100.0/src/robotcode/repl/run.py +133 -0
- robotcode_repl-0.99.0/src/robotcode/repl/__version__.py +0 -1
- robotcode_repl-0.99.0/src/robotcode/repl/cli/__init__.py +0 -3
- robotcode_repl-0.99.0/src/robotcode/repl/cli/repl.py +0 -232
- robotcode_repl-0.99.0/src/robotcode/repl/repl_listener.py +0 -25
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/.gitignore +0 -0
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/LICENSE.txt +0 -0
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/src/robotcode/repl/Repl/__init__.py +0 -0
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/src/robotcode/repl/Repl/repl.py +0 -0
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/src/robotcode/repl/__init__.py +0 -0
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/src/robotcode/repl/hooks.py +0 -0
- {robotcode_repl-0.99.0 → robotcode_repl-0.100.0}/src/robotcode/repl/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: robotcode-repl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.100.0
|
|
4
4
|
Summary: RobotCode REPL for Robot Framework
|
|
5
5
|
Project-URL: Homepage, https://robotcode.io
|
|
6
6
|
Project-URL: Donate, https://opencollective.com/robotcode
|
|
@@ -24,8 +24,7 @@ Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
|
24
24
|
Classifier: Topic :: Utilities
|
|
25
25
|
Classifier: Typing :: Typed
|
|
26
26
|
Requires-Python: >=3.8
|
|
27
|
-
Requires-Dist: robotcode-
|
|
28
|
-
Requires-Dist: robotcode-runner==0.99.0
|
|
27
|
+
Requires-Dist: robotcode-runner==0.100.0
|
|
29
28
|
Description-Content-Type: text/markdown
|
|
30
29
|
|
|
31
30
|
# robotcode-repl
|
|
@@ -38,7 +37,8 @@ Description-Content-Type: text/markdown
|
|
|
38
37
|
|
|
39
38
|
## Introduction
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
Provides a REPL for [RobotCode](https://robotcode.io).
|
|
41
|
+
|
|
42
42
|
|
|
43
43
|
## Installation
|
|
44
44
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.100.0"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import abc
|
|
2
|
+
from datetime import datetime
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from typing import TYPE_CHECKING, Any, Iterator, List, Optional, Tuple, Union, cast
|
|
4
5
|
|
|
5
|
-
import click
|
|
6
6
|
from robot.api import get_model
|
|
7
7
|
from robot.errors import ExecutionStatus
|
|
8
8
|
from robot.output import LOGGER
|
|
@@ -11,7 +11,7 @@ from robot.running import Keyword, TestCase, TestSuite
|
|
|
11
11
|
from robot.running.context import EXECUTION_CONTEXTS
|
|
12
12
|
from robot.running.signalhandler import _StopSignalMonitor
|
|
13
13
|
|
|
14
|
-
from robotcode.
|
|
14
|
+
from robotcode.core.utils.path import normalized_path
|
|
15
15
|
from robotcode.robot.utils import get_robot_version
|
|
16
16
|
from robotcode.robot.utils.ast import iter_nodes
|
|
17
17
|
|
|
@@ -46,26 +46,21 @@ else:
|
|
|
46
46
|
return kw.run(context)
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
TRUE_STRINGS = {"TRUE", "YES", "ON", "1"}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def is_true(value: Union[str, bool]) -> bool:
|
|
53
|
-
if isinstance(value, str):
|
|
54
|
-
return value.upper() in TRUE_STRINGS
|
|
55
|
-
return bool(value)
|
|
56
|
-
|
|
57
|
-
|
|
58
49
|
if get_robot_version() < (7, 0):
|
|
59
50
|
|
|
60
51
|
class InterpreterLogger:
|
|
61
|
-
def __init__(self, interpreter: "
|
|
52
|
+
def __init__(self, interpreter: "BaseInterpreter") -> None:
|
|
62
53
|
self.interpreter = interpreter
|
|
63
54
|
self.enabled = False
|
|
64
55
|
|
|
65
56
|
def log_message(self, message: OutputMessage) -> None:
|
|
57
|
+
if not self.enabled:
|
|
58
|
+
return
|
|
66
59
|
self.interpreter.log_message(message.message, message.level, message.html, message.timestamp)
|
|
67
60
|
|
|
68
61
|
def message(self, message: OutputMessage) -> None:
|
|
62
|
+
if not self.enabled:
|
|
63
|
+
return
|
|
69
64
|
self.interpreter.message(message.message, message.level, message.html, message.timestamp)
|
|
70
65
|
|
|
71
66
|
def start_keyword(self, args: Any) -> None:
|
|
@@ -82,14 +77,18 @@ else:
|
|
|
82
77
|
import robot.output.loggerapi # pyright: ignore[reportMissingImports]
|
|
83
78
|
|
|
84
79
|
class InterpreterLogger(robot.output.loggerapi.LoggerApi): # type: ignore[no-redef]
|
|
85
|
-
def __init__(self, interpreter: "
|
|
80
|
+
def __init__(self, interpreter: "BaseInterpreter") -> None:
|
|
86
81
|
self.interpreter = interpreter
|
|
87
82
|
self.enabled = False
|
|
88
83
|
|
|
89
84
|
def log_message(self, message: OutputMessage) -> None:
|
|
85
|
+
if not self.enabled:
|
|
86
|
+
return
|
|
90
87
|
self.interpreter.log_message(message.message, message.level, message.html, message.timestamp)
|
|
91
88
|
|
|
92
89
|
def message(self, message: OutputMessage) -> None:
|
|
90
|
+
if not self.enabled:
|
|
91
|
+
return
|
|
93
92
|
self.interpreter.message(message.message, message.level, message.html, message.timestamp)
|
|
94
93
|
|
|
95
94
|
def start_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None:
|
|
@@ -102,28 +101,26 @@ else:
|
|
|
102
101
|
return
|
|
103
102
|
self.interpreter.end_keyword(data, result)
|
|
104
103
|
|
|
104
|
+
def start_body_item(self, data: "running.Keyword", result: "result.Keyword") -> None:
|
|
105
|
+
if not self.enabled:
|
|
106
|
+
return
|
|
107
|
+
self.interpreter.start_keyword(data, result)
|
|
105
108
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
files: Optional[List[Path]] = None,
|
|
111
|
-
show_keywords: bool = False,
|
|
112
|
-
inspect: Optional[bool] = False,
|
|
113
|
-
) -> None:
|
|
114
|
-
_patch()
|
|
109
|
+
def end_body_item(self, data: "running.Keyword", result: "result.Keyword") -> None:
|
|
110
|
+
if not self.enabled:
|
|
111
|
+
return
|
|
112
|
+
self.interpreter.end_keyword(data, result)
|
|
115
113
|
|
|
116
|
-
self.app = app
|
|
117
|
-
self.files = files
|
|
118
|
-
self.show_keywords = show_keywords
|
|
119
|
-
self.inspect = inspect
|
|
120
114
|
|
|
121
|
-
|
|
115
|
+
class BaseInterpreter(abc.ABC):
|
|
116
|
+
def __init__(self) -> None:
|
|
117
|
+
_patch()
|
|
122
118
|
|
|
123
119
|
self._logger = InterpreterLogger(self)
|
|
124
120
|
LOGGER.register_logger(self._logger)
|
|
125
|
-
|
|
121
|
+
self.last_result: Any = None
|
|
126
122
|
self.indent = 0
|
|
123
|
+
self.source: Optional[Path] = None
|
|
127
124
|
|
|
128
125
|
def check_for_errors(self, node: Any) -> List[str]:
|
|
129
126
|
if hasattr(node, "tokens"):
|
|
@@ -145,7 +142,9 @@ class Interpreter:
|
|
|
145
142
|
+ ("\n ".join(command.split("\n")) if "\n" in command else command)
|
|
146
143
|
) + "\n"
|
|
147
144
|
|
|
148
|
-
|
|
145
|
+
curdir = normalized_path(self.source).parent if self.source is not None else Path.cwd()
|
|
146
|
+
|
|
147
|
+
model = get_model(suite_str, curdir=str(curdir).replace("\\", "\\\\"))
|
|
149
148
|
suite: TestSuite = TestSuite.from_model(model)
|
|
150
149
|
|
|
151
150
|
errors: List[str] = []
|
|
@@ -155,80 +154,39 @@ class Interpreter:
|
|
|
155
154
|
|
|
156
155
|
return cast(TestCase, suite.tests[0]), errors
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
raise EOFError
|
|
161
|
-
|
|
162
|
-
if self.files:
|
|
163
|
-
file = self.files.pop(0)
|
|
164
|
-
|
|
165
|
-
self.executed_files.append(file)
|
|
166
|
-
|
|
167
|
-
text = file.read_text(encoding="utf-8")
|
|
168
|
-
|
|
169
|
-
test, errors = self.get_test_body_from_string(text)
|
|
170
|
-
if errors:
|
|
171
|
-
return
|
|
172
|
-
|
|
173
|
-
for kw in test.body:
|
|
174
|
-
yield kw
|
|
175
|
-
else:
|
|
176
|
-
|
|
177
|
-
lines: List[str] = []
|
|
178
|
-
last_one = False
|
|
179
|
-
while True:
|
|
180
|
-
|
|
181
|
-
prompt = ""
|
|
182
|
-
if sys.stdin.isatty():
|
|
183
|
-
prompt = ">>> " if not lines else "... "
|
|
184
|
-
|
|
185
|
-
try:
|
|
186
|
-
text = input(prompt)
|
|
187
|
-
if len(lines) == 0 and text == "":
|
|
188
|
-
break
|
|
189
|
-
except KeyboardInterrupt:
|
|
190
|
-
if len(lines) > 0:
|
|
191
|
-
lines = []
|
|
192
|
-
last_one = False
|
|
193
|
-
continue
|
|
194
|
-
raise
|
|
195
|
-
|
|
196
|
-
lines.append(text)
|
|
197
|
-
|
|
198
|
-
test, errors = self.get_test_body_from_string("\n".join(lines))
|
|
199
|
-
|
|
200
|
-
if len(lines) > 1 and lines[-1] == "" and text == "":
|
|
201
|
-
last_one = True
|
|
202
|
-
|
|
203
|
-
if errors:
|
|
204
|
-
if not last_one:
|
|
205
|
-
continue
|
|
206
|
-
|
|
207
|
-
for kw in test.body:
|
|
208
|
-
yield kw
|
|
209
|
-
|
|
210
|
-
break
|
|
157
|
+
@abc.abstractmethod
|
|
158
|
+
def get_input(self) -> Iterator[Optional[Keyword]]: ...
|
|
211
159
|
|
|
212
160
|
def run_keyword(self, kw: Keyword) -> Any:
|
|
213
161
|
self.indent = 0
|
|
214
162
|
context = EXECUTION_CONTEXTS.current
|
|
215
|
-
|
|
163
|
+
try:
|
|
164
|
+
return _run_keyword(kw, context)
|
|
165
|
+
except (SystemExit, KeyboardInterrupt):
|
|
166
|
+
raise
|
|
167
|
+
except ExecutionStatus:
|
|
168
|
+
raise
|
|
169
|
+
except BaseException as e:
|
|
170
|
+
self.log_message(str(e), "ERROR", timestamp=datetime.now()) # noqa: DTZ005
|
|
216
171
|
|
|
217
172
|
def run(self) -> Any:
|
|
218
173
|
self._logger.enabled = True
|
|
219
174
|
|
|
220
175
|
has_input = True
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
176
|
+
try:
|
|
177
|
+
while has_input:
|
|
178
|
+
try:
|
|
179
|
+
self.run_input()
|
|
180
|
+
except EOFError:
|
|
181
|
+
break
|
|
182
|
+
except (SystemExit, KeyboardInterrupt):
|
|
183
|
+
break
|
|
184
|
+
except ExecutionStatus:
|
|
185
|
+
pass
|
|
186
|
+
except BaseException as e:
|
|
187
|
+
self.log_message(str(e), "ERROR", timestamp=datetime.now()) # noqa: DTZ005
|
|
188
|
+
finally:
|
|
189
|
+
self._logger.enabled = False
|
|
232
190
|
|
|
233
191
|
def run_input(self) -> None:
|
|
234
192
|
for kw in self.get_input():
|
|
@@ -237,65 +195,29 @@ class Interpreter:
|
|
|
237
195
|
self.set_last_result(self.run_keyword(kw))
|
|
238
196
|
|
|
239
197
|
def set_last_result(self, result: Any) -> None:
|
|
240
|
-
|
|
241
|
-
return
|
|
242
|
-
if self.app is not None:
|
|
243
|
-
self.app.echo(f"{result}")
|
|
198
|
+
self.last_result = result
|
|
244
199
|
|
|
200
|
+
@abc.abstractmethod
|
|
245
201
|
def log_message(
|
|
246
|
-
self, message: str, level: str, html: Union[str, bool] = False, timestamp:
|
|
247
|
-
) -> None:
|
|
248
|
-
if self.app is None:
|
|
249
|
-
return
|
|
250
|
-
|
|
251
|
-
if not self.app.config.verbose and level in ["DEBUG", "TRACE"]:
|
|
252
|
-
return
|
|
253
|
-
|
|
254
|
-
std_err = level in ["ERROR", "FAIL"]
|
|
255
|
-
|
|
256
|
-
if level == "INFO":
|
|
257
|
-
level = click.style("INFO", fg="green")
|
|
258
|
-
elif level == "WARN":
|
|
259
|
-
level = click.style("WARN", fg="yellow")
|
|
260
|
-
elif level == "ERROR":
|
|
261
|
-
level = click.style("ERROR", fg="red")
|
|
262
|
-
elif level == "FAIL":
|
|
263
|
-
level = click.style("FAIL", fg="red", bold=True)
|
|
264
|
-
elif level == "SKIP":
|
|
265
|
-
level = click.style("SKIP", dim=True)
|
|
266
|
-
elif level == "DEBUG":
|
|
267
|
-
level = click.style("DEBUG", fg="bright_black")
|
|
268
|
-
elif level == "TRACE":
|
|
269
|
-
level = click.style("TRACE", fg="bright_black", dim=True)
|
|
270
|
-
|
|
271
|
-
if is_true(html):
|
|
272
|
-
message = f"*HTML*{message}"
|
|
273
|
-
|
|
274
|
-
self.app.echo(f"{' '*self.indent}[ {level} ] {message}", file=sys.__stdout__ if std_err else sys.__stderr__)
|
|
202
|
+
self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None
|
|
203
|
+
) -> None: ...
|
|
275
204
|
|
|
205
|
+
@abc.abstractmethod
|
|
276
206
|
def message(
|
|
277
|
-
self, message: str, level: str, html: Union[str, bool] = False, timestamp:
|
|
278
|
-
) -> None:
|
|
279
|
-
if self.app is not None and self.app.config.verbose:
|
|
280
|
-
self.log_message(message, level, html, timestamp)
|
|
207
|
+
self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None
|
|
208
|
+
) -> None: ...
|
|
281
209
|
|
|
282
210
|
def start_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None:
|
|
283
|
-
|
|
284
|
-
return
|
|
211
|
+
pass
|
|
285
212
|
|
|
286
|
-
|
|
287
|
-
|
|
213
|
+
def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None:
|
|
214
|
+
pass
|
|
288
215
|
|
|
289
|
-
self.app.echo(
|
|
290
|
-
f"{' '*self.indent}KEYWORD {result.libname}.{result.kwname} {' '.join(result.args)}", file=sys.__stdout__
|
|
291
|
-
)
|
|
292
|
-
self.indent += 1
|
|
293
216
|
|
|
294
|
-
|
|
295
|
-
if not self.show_keywords:
|
|
296
|
-
return
|
|
217
|
+
TRUE_STRINGS = {"TRUE", "YES", "ON", "1"}
|
|
297
218
|
|
|
298
|
-
if self.app is None:
|
|
299
|
-
return
|
|
300
219
|
|
|
301
|
-
|
|
220
|
+
def is_true(value: Union[str, bool]) -> bool:
|
|
221
|
+
if isinstance(value, str):
|
|
222
|
+
return value.upper() in TRUE_STRINGS
|
|
223
|
+
return bool(value)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Optional, Tuple
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from robotcode.plugin import Application, pass_application
|
|
7
|
+
|
|
8
|
+
from .__version__ import __version__
|
|
9
|
+
from .console_interpreter import ConsoleInterpreter
|
|
10
|
+
from .run import run_repl
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.command(add_help_option=True)
|
|
14
|
+
@click.option(
|
|
15
|
+
"-v",
|
|
16
|
+
"--variable",
|
|
17
|
+
metavar="name:value",
|
|
18
|
+
type=str,
|
|
19
|
+
multiple=True,
|
|
20
|
+
help="Set variables in the test data. see `robot --variable` option.",
|
|
21
|
+
)
|
|
22
|
+
@click.option(
|
|
23
|
+
"-V",
|
|
24
|
+
"--variablefile",
|
|
25
|
+
metavar="PATH",
|
|
26
|
+
type=str,
|
|
27
|
+
multiple=True,
|
|
28
|
+
help="Python or YAML file file to read variables from. see `robot --variablefile` option.",
|
|
29
|
+
)
|
|
30
|
+
@click.option(
|
|
31
|
+
"-P",
|
|
32
|
+
"--pythonpath",
|
|
33
|
+
metavar="PATH",
|
|
34
|
+
type=str,
|
|
35
|
+
multiple=True,
|
|
36
|
+
help="Additional locations where to search test libraries"
|
|
37
|
+
" and other extensions when they are imported. see `robot --pythonpath` option.",
|
|
38
|
+
)
|
|
39
|
+
@click.option(
|
|
40
|
+
"-k",
|
|
41
|
+
"--show-keywords",
|
|
42
|
+
is_flag=True,
|
|
43
|
+
default=False,
|
|
44
|
+
help="Executed keywords will be shown in the output.",
|
|
45
|
+
)
|
|
46
|
+
@click.option(
|
|
47
|
+
"-i",
|
|
48
|
+
"--inspect",
|
|
49
|
+
is_flag=True,
|
|
50
|
+
default=False,
|
|
51
|
+
help="Activate inspection mode. This forces a prompt to appear after the REPL script is executed.",
|
|
52
|
+
)
|
|
53
|
+
@click.option(
|
|
54
|
+
"-d",
|
|
55
|
+
"--outputdir",
|
|
56
|
+
metavar="DIR",
|
|
57
|
+
type=str,
|
|
58
|
+
help="Where to create output files. see `robot --outputdir` option.",
|
|
59
|
+
)
|
|
60
|
+
@click.option(
|
|
61
|
+
"-o",
|
|
62
|
+
"--output",
|
|
63
|
+
metavar="FILE",
|
|
64
|
+
type=str,
|
|
65
|
+
help="XML output file. see `robot --output` option.",
|
|
66
|
+
)
|
|
67
|
+
@click.option(
|
|
68
|
+
"-r",
|
|
69
|
+
"--report",
|
|
70
|
+
metavar="FILE",
|
|
71
|
+
type=str,
|
|
72
|
+
help="HTML output file. see `robot --report` option.",
|
|
73
|
+
)
|
|
74
|
+
@click.option(
|
|
75
|
+
"-l",
|
|
76
|
+
"--log",
|
|
77
|
+
metavar="FILE",
|
|
78
|
+
type=str,
|
|
79
|
+
help="HTML log file. see `robot --log` option.",
|
|
80
|
+
)
|
|
81
|
+
@click.option(
|
|
82
|
+
"-x",
|
|
83
|
+
"--xunit",
|
|
84
|
+
metavar="FILE",
|
|
85
|
+
type=str,
|
|
86
|
+
help="xUnit output file. see `robot --xunit` option.",
|
|
87
|
+
)
|
|
88
|
+
@click.option(
|
|
89
|
+
"-s",
|
|
90
|
+
"--source",
|
|
91
|
+
type=click.Path(path_type=Path),
|
|
92
|
+
metavar="FILE",
|
|
93
|
+
help="Specifies the path to a source file. This file must not exist and will neither be read nor written. "
|
|
94
|
+
"It is used solely to set the current working directory for the REPL script "
|
|
95
|
+
"and to assign a name to the internal suite.",
|
|
96
|
+
)
|
|
97
|
+
@click.version_option(version=__version__, prog_name="RobotCode REPL")
|
|
98
|
+
@click.argument(
|
|
99
|
+
"files",
|
|
100
|
+
type=click.Path(exists=True, dir_okay=False, path_type=Path),
|
|
101
|
+
nargs=-1,
|
|
102
|
+
required=False,
|
|
103
|
+
)
|
|
104
|
+
@pass_application
|
|
105
|
+
def repl(
|
|
106
|
+
app: Application,
|
|
107
|
+
variable: Tuple[str, ...],
|
|
108
|
+
variablefile: Tuple[str, ...],
|
|
109
|
+
pythonpath: Tuple[str, ...],
|
|
110
|
+
show_keywords: bool,
|
|
111
|
+
inspect: bool,
|
|
112
|
+
outputdir: Optional[str],
|
|
113
|
+
output: Optional[str],
|
|
114
|
+
report: Optional[str],
|
|
115
|
+
log: Optional[str],
|
|
116
|
+
xunit: Optional[str],
|
|
117
|
+
source: Optional[Path],
|
|
118
|
+
files: Tuple[Path, ...],
|
|
119
|
+
) -> None:
|
|
120
|
+
"""\
|
|
121
|
+
Run Robot Framework interactively.
|
|
122
|
+
"""
|
|
123
|
+
if files:
|
|
124
|
+
files = tuple(f.absolute() for f in files)
|
|
125
|
+
|
|
126
|
+
interpreter = ConsoleInterpreter(app, files=list(files), show_keywords=show_keywords, inspect=inspect)
|
|
127
|
+
|
|
128
|
+
run_repl(
|
|
129
|
+
interpreter=interpreter,
|
|
130
|
+
app=app,
|
|
131
|
+
variablefile=variable,
|
|
132
|
+
variable=variablefile,
|
|
133
|
+
pythonpath=pythonpath,
|
|
134
|
+
outputdir=outputdir,
|
|
135
|
+
output=output,
|
|
136
|
+
report=report,
|
|
137
|
+
log=log,
|
|
138
|
+
xunit=xunit,
|
|
139
|
+
source=source,
|
|
140
|
+
files=files,
|
|
141
|
+
)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Iterator, List, Optional, Union
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
from robot import result, running
|
|
8
|
+
from robot.running import Keyword
|
|
9
|
+
|
|
10
|
+
from robotcode.plugin import Application
|
|
11
|
+
|
|
12
|
+
from .base_interpreter import BaseInterpreter, is_true
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ConsoleInterpreter(BaseInterpreter):
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
app: Optional[Application],
|
|
19
|
+
files: Optional[List[Path]] = None,
|
|
20
|
+
show_keywords: bool = False,
|
|
21
|
+
inspect: Optional[bool] = False,
|
|
22
|
+
) -> None:
|
|
23
|
+
super().__init__()
|
|
24
|
+
|
|
25
|
+
self.app = app
|
|
26
|
+
self.files = files
|
|
27
|
+
self.show_keywords = show_keywords
|
|
28
|
+
self.inspect = inspect
|
|
29
|
+
|
|
30
|
+
self.executed_files: List[Path] = []
|
|
31
|
+
|
|
32
|
+
def get_input(self) -> Iterator[Optional[Keyword]]:
|
|
33
|
+
if self.executed_files and not self.files and not self.inspect:
|
|
34
|
+
raise EOFError
|
|
35
|
+
|
|
36
|
+
if self.files:
|
|
37
|
+
file = self.files.pop(0)
|
|
38
|
+
|
|
39
|
+
self.executed_files.append(file)
|
|
40
|
+
|
|
41
|
+
text = file.read_text(encoding="utf-8")
|
|
42
|
+
|
|
43
|
+
test, errors = self.get_test_body_from_string(text)
|
|
44
|
+
if errors:
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
for kw in test.body:
|
|
48
|
+
yield kw
|
|
49
|
+
else:
|
|
50
|
+
lines: List[str] = []
|
|
51
|
+
last_one = False
|
|
52
|
+
while True:
|
|
53
|
+
prompt = ""
|
|
54
|
+
if sys.stdin.isatty():
|
|
55
|
+
prompt = ">>> " if not lines else "... "
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
text = input(prompt)
|
|
59
|
+
if len(lines) == 0 and text == "":
|
|
60
|
+
break
|
|
61
|
+
except KeyboardInterrupt:
|
|
62
|
+
if len(lines) > 0:
|
|
63
|
+
lines = []
|
|
64
|
+
last_one = False
|
|
65
|
+
continue
|
|
66
|
+
raise
|
|
67
|
+
|
|
68
|
+
lines.append(text)
|
|
69
|
+
|
|
70
|
+
test, errors = self.get_test_body_from_string("\n".join(lines))
|
|
71
|
+
|
|
72
|
+
if len(lines) > 1 and lines[-1] == "" and text == "":
|
|
73
|
+
last_one = True
|
|
74
|
+
|
|
75
|
+
if errors:
|
|
76
|
+
if not last_one:
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
for kw in test.body:
|
|
80
|
+
yield kw
|
|
81
|
+
|
|
82
|
+
break
|
|
83
|
+
|
|
84
|
+
def log_message(
|
|
85
|
+
self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None
|
|
86
|
+
) -> None:
|
|
87
|
+
if self.app is None:
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
if not self.app.config.verbose and level in ["DEBUG", "TRACE"]:
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
std_err = level in ["ERROR", "FAIL"]
|
|
94
|
+
|
|
95
|
+
if level == "INFO":
|
|
96
|
+
level = click.style("INFO", fg="green")
|
|
97
|
+
elif level == "WARN":
|
|
98
|
+
level = click.style("WARN", fg="yellow")
|
|
99
|
+
elif level == "ERROR":
|
|
100
|
+
level = click.style("ERROR", fg="red")
|
|
101
|
+
elif level == "FAIL":
|
|
102
|
+
level = click.style("FAIL", fg="red", bold=True)
|
|
103
|
+
elif level == "SKIP":
|
|
104
|
+
level = click.style("SKIP", dim=True)
|
|
105
|
+
elif level == "DEBUG":
|
|
106
|
+
level = click.style("DEBUG", fg="bright_black")
|
|
107
|
+
elif level == "TRACE":
|
|
108
|
+
level = click.style("TRACE", fg="bright_black", dim=True)
|
|
109
|
+
|
|
110
|
+
if is_true(html):
|
|
111
|
+
message = f"*HTML*{message}"
|
|
112
|
+
|
|
113
|
+
self.app.echo(f"{' '*self.indent}[ {level} ] {message}", file=sys.__stdout__ if std_err else sys.__stderr__)
|
|
114
|
+
|
|
115
|
+
def message(
|
|
116
|
+
self, message: str, level: str, html: Union[str, bool] = False, timestamp: Union[datetime, str, None] = None
|
|
117
|
+
) -> None:
|
|
118
|
+
if self.app is not None and self.app.config.verbose:
|
|
119
|
+
self.log_message(message, level, html, timestamp)
|
|
120
|
+
|
|
121
|
+
def start_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None:
|
|
122
|
+
if not self.show_keywords:
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
if self.app is None:
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
self.app.echo(
|
|
129
|
+
f"{' '*self.indent}KEYWORD {result.libname}.{result.kwname} {' '.join(result.args)}", file=sys.__stdout__
|
|
130
|
+
)
|
|
131
|
+
self.indent += 1
|
|
132
|
+
|
|
133
|
+
def end_keyword(self, data: "running.Keyword", result: "result.Keyword") -> None:
|
|
134
|
+
if not self.show_keywords:
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
if self.app is None:
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
self.indent -= 1
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any, ClassVar, Dict, Optional, Tuple
|
|
5
|
+
|
|
6
|
+
from robot.api import TestSuite, get_model
|
|
7
|
+
from robot.conf import RobotSettings
|
|
8
|
+
from robot.errors import DATA_ERROR, INFO_PRINTED, DataError, Information
|
|
9
|
+
from robot.output import LOGGER
|
|
10
|
+
from robot.reporting import ResultWriter
|
|
11
|
+
|
|
12
|
+
from robotcode.core.utils.path import normalized_path
|
|
13
|
+
from robotcode.plugin import (
|
|
14
|
+
Application,
|
|
15
|
+
)
|
|
16
|
+
from robotcode.robot.utils import get_robot_version
|
|
17
|
+
from robotcode.runner.cli.robot import RobotFrameworkEx, handle_robot_options
|
|
18
|
+
|
|
19
|
+
from .base_interpreter import BaseInterpreter
|
|
20
|
+
|
|
21
|
+
REPL_SUITE = """\
|
|
22
|
+
*** Settings ***
|
|
23
|
+
Library robotcode.repl.Repl
|
|
24
|
+
*** Test Cases ***
|
|
25
|
+
RobotCode REPL
|
|
26
|
+
repl
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ReplListener:
|
|
31
|
+
ROBOT_LISTENER_API_VERSION = 2
|
|
32
|
+
instance: ClassVar["ReplListener"]
|
|
33
|
+
|
|
34
|
+
def __init__(self, app: Application, interpreter: BaseInterpreter) -> None:
|
|
35
|
+
ReplListener.instance = self
|
|
36
|
+
self.app = app
|
|
37
|
+
self.interpreter = interpreter
|
|
38
|
+
|
|
39
|
+
def start_keyword(
|
|
40
|
+
self,
|
|
41
|
+
name: str,
|
|
42
|
+
attributes: Dict[str, Any],
|
|
43
|
+
) -> None:
|
|
44
|
+
if name != "robotcode.repl.Repl.Repl":
|
|
45
|
+
return
|
|
46
|
+
|
|
47
|
+
self.interpreter.run()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def run_repl(
|
|
51
|
+
interpreter: BaseInterpreter,
|
|
52
|
+
app: Application,
|
|
53
|
+
variable: Tuple[str, ...] = (),
|
|
54
|
+
variablefile: Tuple[str, ...] = (),
|
|
55
|
+
pythonpath: Tuple[str, ...] = (),
|
|
56
|
+
outputdir: Optional[str] = None,
|
|
57
|
+
output: Optional[str] = None,
|
|
58
|
+
report: Optional[str] = None,
|
|
59
|
+
log: Optional[str] = None,
|
|
60
|
+
xunit: Optional[str] = None,
|
|
61
|
+
source: Optional[Path] = None,
|
|
62
|
+
files: Tuple[Path, ...] = (),
|
|
63
|
+
) -> None:
|
|
64
|
+
robot_options_and_args: Tuple[str, ...] = ()
|
|
65
|
+
|
|
66
|
+
if files:
|
|
67
|
+
files = tuple(f.absolute() for f in files)
|
|
68
|
+
|
|
69
|
+
for var in variable:
|
|
70
|
+
robot_options_and_args += ("--variable", var)
|
|
71
|
+
for varfile in variablefile:
|
|
72
|
+
robot_options_and_args += ("--variablefile", varfile)
|
|
73
|
+
for pypath in pythonpath:
|
|
74
|
+
robot_options_and_args += ("--pythonpath", pypath)
|
|
75
|
+
if outputdir:
|
|
76
|
+
robot_options_and_args += ("--outputdir", outputdir)
|
|
77
|
+
|
|
78
|
+
root_folder, _profile, cmd_options = handle_robot_options(app, (*robot_options_and_args, *(str(f) for f in files)))
|
|
79
|
+
|
|
80
|
+
with app.chdir(root_folder) as orig_folder:
|
|
81
|
+
try:
|
|
82
|
+
curdir = normalized_path(source).parent if source is not None else Path.cwd()
|
|
83
|
+
|
|
84
|
+
options, _ = RobotFrameworkEx(
|
|
85
|
+
app,
|
|
86
|
+
["."],
|
|
87
|
+
app.config.dry,
|
|
88
|
+
root_folder=root_folder,
|
|
89
|
+
orig_folder=orig_folder,
|
|
90
|
+
).parse_arguments((*cmd_options, *robot_options_and_args))
|
|
91
|
+
|
|
92
|
+
interpreter.source = source
|
|
93
|
+
|
|
94
|
+
settings = RobotSettings(
|
|
95
|
+
options,
|
|
96
|
+
outputdir=str(curdir),
|
|
97
|
+
console="NONE",
|
|
98
|
+
output=output,
|
|
99
|
+
log=log,
|
|
100
|
+
report=report,
|
|
101
|
+
xunit=xunit,
|
|
102
|
+
quiet=True,
|
|
103
|
+
listener=[
|
|
104
|
+
ReplListener(app, interpreter),
|
|
105
|
+
],
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
if app is not None and app.show_diagnostics:
|
|
109
|
+
LOGGER.register_console_logger(**settings.console_output_config)
|
|
110
|
+
else:
|
|
111
|
+
LOGGER.unregister_console_logger()
|
|
112
|
+
|
|
113
|
+
if get_robot_version() >= (5, 0):
|
|
114
|
+
if settings.pythonpath:
|
|
115
|
+
sys.path = settings.pythonpath + sys.path
|
|
116
|
+
|
|
117
|
+
with io.StringIO(REPL_SUITE) as suite_io:
|
|
118
|
+
model = get_model(suite_io, curdir=str(curdir).replace("\\", "\\\\"))
|
|
119
|
+
|
|
120
|
+
suite = TestSuite.from_model(model)
|
|
121
|
+
suite.configure(**settings.suite_config)
|
|
122
|
+
result = suite.run(settings)
|
|
123
|
+
|
|
124
|
+
if settings.log or settings.report or settings.xunit:
|
|
125
|
+
writer = ResultWriter(settings.output if settings.log else result)
|
|
126
|
+
writer.write_results(settings.get_rebot_settings())
|
|
127
|
+
|
|
128
|
+
except Information as err:
|
|
129
|
+
app.echo(str(err))
|
|
130
|
+
app.exit(INFO_PRINTED)
|
|
131
|
+
except DataError as err:
|
|
132
|
+
app.error(str(err))
|
|
133
|
+
app.exit(DATA_ERROR)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.99.0"
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import io
|
|
2
|
-
import sys
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import Optional, Tuple
|
|
5
|
-
|
|
6
|
-
import click
|
|
7
|
-
from robot.api import TestSuite, get_model
|
|
8
|
-
from robot.conf import RobotSettings
|
|
9
|
-
from robot.errors import DATA_ERROR, INFO_PRINTED, DataError, Information
|
|
10
|
-
from robot.output import LOGGER
|
|
11
|
-
from robot.reporting import ResultWriter
|
|
12
|
-
|
|
13
|
-
from robotcode.plugin import (
|
|
14
|
-
Application,
|
|
15
|
-
pass_application,
|
|
16
|
-
)
|
|
17
|
-
from robotcode.robot.utils import get_robot_version
|
|
18
|
-
from robotcode.runner.cli.robot import RobotFrameworkEx, handle_robot_options
|
|
19
|
-
|
|
20
|
-
from ..interpreter import Interpreter
|
|
21
|
-
from ..repl_listener import ReplListener
|
|
22
|
-
|
|
23
|
-
REPL_SUITE = """\
|
|
24
|
-
*** Settings ***
|
|
25
|
-
Library robotcode.repl.Repl
|
|
26
|
-
*** Test Cases ***
|
|
27
|
-
RobotCode REPL
|
|
28
|
-
repl
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def run_repl(
|
|
33
|
-
app: Application,
|
|
34
|
-
inspect: bool = False,
|
|
35
|
-
variable: Tuple[str, ...] = (),
|
|
36
|
-
variablefile: Tuple[str, ...] = (),
|
|
37
|
-
pythonpath: Tuple[str, ...] = (),
|
|
38
|
-
outputdir: Optional[str] = None,
|
|
39
|
-
output: Optional[str] = None,
|
|
40
|
-
report: Optional[str] = None,
|
|
41
|
-
log: Optional[str] = None,
|
|
42
|
-
xunit: Optional[str] = None,
|
|
43
|
-
files: Tuple[Path, ...] = (),
|
|
44
|
-
show_keywords: bool = False,
|
|
45
|
-
interpreter: Optional[Interpreter] = None,
|
|
46
|
-
) -> None:
|
|
47
|
-
robot_options_and_args: Tuple[str, ...] = ()
|
|
48
|
-
|
|
49
|
-
if files:
|
|
50
|
-
files = tuple(f.absolute() for f in files)
|
|
51
|
-
|
|
52
|
-
for var in variable:
|
|
53
|
-
robot_options_and_args += ("--variable", var)
|
|
54
|
-
for varfile in variablefile:
|
|
55
|
-
robot_options_and_args += ("--variablefile", varfile)
|
|
56
|
-
for pypath in pythonpath:
|
|
57
|
-
robot_options_and_args += ("--pythonpath", pypath)
|
|
58
|
-
if outputdir:
|
|
59
|
-
robot_options_and_args += ("--outputdir", outputdir)
|
|
60
|
-
|
|
61
|
-
root_folder, _profile, cmd_options = handle_robot_options(app, (*robot_options_and_args, *(str(f) for f in files)))
|
|
62
|
-
|
|
63
|
-
try:
|
|
64
|
-
|
|
65
|
-
options, _ = RobotFrameworkEx(
|
|
66
|
-
app,
|
|
67
|
-
["."],
|
|
68
|
-
app.config.dry,
|
|
69
|
-
root_folder,
|
|
70
|
-
).parse_arguments((*cmd_options, *robot_options_and_args))
|
|
71
|
-
|
|
72
|
-
if interpreter is None:
|
|
73
|
-
interpreter = Interpreter(app, files=list(files), show_keywords=show_keywords, inspect=inspect)
|
|
74
|
-
|
|
75
|
-
settings = RobotSettings(
|
|
76
|
-
options,
|
|
77
|
-
console="NONE",
|
|
78
|
-
output=output,
|
|
79
|
-
log=log,
|
|
80
|
-
report=report,
|
|
81
|
-
xunit=xunit,
|
|
82
|
-
quiet=True,
|
|
83
|
-
listener=[
|
|
84
|
-
ReplListener(app, interpreter),
|
|
85
|
-
],
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
if app is not None and app.show_diagnostics:
|
|
89
|
-
LOGGER.register_console_logger(**settings.console_output_config)
|
|
90
|
-
else:
|
|
91
|
-
LOGGER.unregister_console_logger()
|
|
92
|
-
|
|
93
|
-
if get_robot_version() >= (5, 0):
|
|
94
|
-
if settings.pythonpath:
|
|
95
|
-
sys.path = settings.pythonpath + sys.path
|
|
96
|
-
|
|
97
|
-
with io.StringIO(REPL_SUITE) as suite_io:
|
|
98
|
-
model = get_model(suite_io)
|
|
99
|
-
|
|
100
|
-
suite = TestSuite.from_model(model)
|
|
101
|
-
suite.configure(**settings.suite_config)
|
|
102
|
-
result = suite.run(settings)
|
|
103
|
-
|
|
104
|
-
if settings.log or settings.report or settings.xunit:
|
|
105
|
-
writer = ResultWriter(settings.output if settings.log else result)
|
|
106
|
-
writer.write_results(settings.get_rebot_settings())
|
|
107
|
-
|
|
108
|
-
except Information as err:
|
|
109
|
-
app.echo(str(err))
|
|
110
|
-
app.exit(INFO_PRINTED)
|
|
111
|
-
except DataError as err:
|
|
112
|
-
app.error(str(err))
|
|
113
|
-
app.exit(DATA_ERROR)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
@click.command(
|
|
117
|
-
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
118
|
-
add_help_option=True,
|
|
119
|
-
)
|
|
120
|
-
@click.option(
|
|
121
|
-
"-v",
|
|
122
|
-
"--variable",
|
|
123
|
-
metavar="name:value",
|
|
124
|
-
type=str,
|
|
125
|
-
multiple=True,
|
|
126
|
-
help="Set variables in the test data. see `robot --variable` option.",
|
|
127
|
-
)
|
|
128
|
-
@click.option(
|
|
129
|
-
"-V",
|
|
130
|
-
"--variablefile",
|
|
131
|
-
metavar="PATH",
|
|
132
|
-
type=str,
|
|
133
|
-
multiple=True,
|
|
134
|
-
help="Python or YAML file file to read variables from. see `robot --variablefile` option.",
|
|
135
|
-
)
|
|
136
|
-
@click.option(
|
|
137
|
-
"-P",
|
|
138
|
-
"--pythonpath",
|
|
139
|
-
metavar="PATH",
|
|
140
|
-
type=str,
|
|
141
|
-
multiple=True,
|
|
142
|
-
help="Additional locations where to search test libraries"
|
|
143
|
-
" and other extensions when they are imported. see `robot --pythonpath` option.",
|
|
144
|
-
)
|
|
145
|
-
@click.option(
|
|
146
|
-
"-k",
|
|
147
|
-
"--show-keywords",
|
|
148
|
-
is_flag=True,
|
|
149
|
-
default=False,
|
|
150
|
-
help="Executed keywords will be shown in the output.",
|
|
151
|
-
)
|
|
152
|
-
@click.option(
|
|
153
|
-
"-i",
|
|
154
|
-
"--inspect",
|
|
155
|
-
is_flag=True,
|
|
156
|
-
default=False,
|
|
157
|
-
help="Activate inspection mode. This forces a prompt to appear after the REPL script is executed.",
|
|
158
|
-
)
|
|
159
|
-
@click.option(
|
|
160
|
-
"-d",
|
|
161
|
-
"--outputdir",
|
|
162
|
-
metavar="DIR",
|
|
163
|
-
type=str,
|
|
164
|
-
help="Where to create output files. see `robot --outputdir` option.",
|
|
165
|
-
)
|
|
166
|
-
@click.option(
|
|
167
|
-
"-o",
|
|
168
|
-
"--output",
|
|
169
|
-
metavar="FILE",
|
|
170
|
-
type=str,
|
|
171
|
-
help="XML output file. see `robot --output` option.",
|
|
172
|
-
)
|
|
173
|
-
@click.option(
|
|
174
|
-
"-r",
|
|
175
|
-
"--report",
|
|
176
|
-
metavar="FILE",
|
|
177
|
-
type=str,
|
|
178
|
-
help="HTML output file. see `robot --report` option.",
|
|
179
|
-
)
|
|
180
|
-
@click.option(
|
|
181
|
-
"-l",
|
|
182
|
-
"--log",
|
|
183
|
-
metavar="FILE",
|
|
184
|
-
type=str,
|
|
185
|
-
help="HTML log file. see `robot --log` option.",
|
|
186
|
-
)
|
|
187
|
-
@click.option(
|
|
188
|
-
"-x",
|
|
189
|
-
"--xunit",
|
|
190
|
-
metavar="FILE",
|
|
191
|
-
type=str,
|
|
192
|
-
help="xUnit output file. see `robot --xunit` option.",
|
|
193
|
-
)
|
|
194
|
-
@click.argument(
|
|
195
|
-
"files",
|
|
196
|
-
type=click.Path(exists=True, dir_okay=False, path_type=Path),
|
|
197
|
-
nargs=-1,
|
|
198
|
-
required=False,
|
|
199
|
-
)
|
|
200
|
-
@pass_application
|
|
201
|
-
def repl(
|
|
202
|
-
app: Application,
|
|
203
|
-
variable: Tuple[str, ...],
|
|
204
|
-
variablefile: Tuple[str, ...],
|
|
205
|
-
pythonpath: Tuple[str, ...],
|
|
206
|
-
show_keywords: bool,
|
|
207
|
-
inspect: bool,
|
|
208
|
-
outputdir: Optional[str],
|
|
209
|
-
output: Optional[str],
|
|
210
|
-
report: Optional[str],
|
|
211
|
-
log: Optional[str],
|
|
212
|
-
xunit: Optional[str],
|
|
213
|
-
files: Tuple[Path, ...],
|
|
214
|
-
) -> None:
|
|
215
|
-
"""\
|
|
216
|
-
Run Robot Framework interactively.
|
|
217
|
-
"""
|
|
218
|
-
|
|
219
|
-
run_repl(
|
|
220
|
-
app=app,
|
|
221
|
-
inspect=inspect,
|
|
222
|
-
variablefile=variable,
|
|
223
|
-
variable=variablefile,
|
|
224
|
-
pythonpath=pythonpath,
|
|
225
|
-
outputdir=outputdir,
|
|
226
|
-
output=output,
|
|
227
|
-
report=report,
|
|
228
|
-
log=log,
|
|
229
|
-
xunit=xunit,
|
|
230
|
-
files=files,
|
|
231
|
-
show_keywords=show_keywords,
|
|
232
|
-
)
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
from typing import Any, ClassVar, Dict, Optional
|
|
2
|
-
|
|
3
|
-
from robotcode.plugin import Application
|
|
4
|
-
|
|
5
|
-
from .interpreter import Interpreter
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class ReplListener:
|
|
9
|
-
ROBOT_LISTENER_API_VERSION = 2
|
|
10
|
-
instance: ClassVar["ReplListener"]
|
|
11
|
-
|
|
12
|
-
def __init__(self, app: Application, interpreter: Optional[Interpreter] = None) -> None:
|
|
13
|
-
ReplListener.instance = self
|
|
14
|
-
self.app = app
|
|
15
|
-
self.interpreter = interpreter or Interpreter(app)
|
|
16
|
-
|
|
17
|
-
def start_keyword(
|
|
18
|
-
self,
|
|
19
|
-
name: str,
|
|
20
|
-
attributes: Dict[str, Any],
|
|
21
|
-
) -> None:
|
|
22
|
-
if name != "robotcode.repl.Repl.Repl":
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
self.interpreter.run()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|