robotcode-repl 2.9.0.dev68__py3-none-any.whl → 2.9.0.dev74__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.
@@ -0,0 +1,530 @@
1
+ import multiprocessing
2
+ import os
3
+ import sys
4
+ import time
5
+ from typing import Any, Callable, Dict, List, Optional, Tuple, TypeVar
6
+
7
+ import click
8
+ from click.core import ParameterSource
9
+ from robot.errors import DATA_ERROR
10
+
11
+ from robotcode.core.utils.path import same_file
12
+ from robotcode.plugin import Application, OutputFormat, pass_application
13
+ from robotcode.plugin.click_helper.exit_codes import robot_exit_codes
14
+ from robotcode.plugin.click_helper.types import add_options
15
+
16
+ from ._session import (
17
+ STARTUP_LIMIT,
18
+ AnswerStatus,
19
+ Request,
20
+ SessionEntry,
21
+ SessionKind,
22
+ connect,
23
+ create_output_pipe,
24
+ create_sessions_dir,
25
+ new_session_id,
26
+ open_sessions,
27
+ project_folder,
28
+ read_entry,
29
+ read_to_end,
30
+ remove_session_files,
31
+ sessions_dir,
32
+ start_session_process,
33
+ )
34
+
35
+ if sys.platform == "win32":
36
+ import msvcrt
37
+
38
+ F = TypeVar("F", bound=Callable[..., Any])
39
+
40
+ # How long `session start` waits for a session to take commands, when `--timeout` isn't longer.
41
+ _STARTUP_LIMIT = STARTUP_LIMIT
42
+
43
+ # 124 for a statement that still runs, as `timeout(1)` exits.
44
+ _EXIT_CODES = {AnswerStatus.PASSED: 0, AnswerStatus.FAILED: 1, AnswerStatus.RUNNING: 124}
45
+
46
+
47
+ def _timeout_option(what: str) -> Callable[[F], F]:
48
+ return click.option(
49
+ "--timeout",
50
+ type=click.FloatRange(min=0),
51
+ default=60,
52
+ show_default=True,
53
+ metavar="SECONDS",
54
+ help=f"Wait at most SECONDS for {what}. After that, print the output so far and exit with code 124, while "
55
+ "the session goes on; `session wait` prints the rest.",
56
+ )
57
+
58
+
59
+ @click.group(invoke_without_command=False)
60
+ def session() -> None:
61
+ """\
62
+ Run a REPL or a debug run in the background and give it one input after the other.
63
+
64
+ `session start` starts the session and prints its ID, which the other commands
65
+ take. The session keeps running when the command has returned, until it is
66
+ stopped or has waited for the idle timeout without a request. When the REPL
67
+ exits or the debug run ends, the session stays open: `session status` tells
68
+ it, `session result` prints the exit code, and `session restart` starts it
69
+ again.
70
+
71
+ \b
72
+ Examples:
73
+ ```
74
+ robotcode session start repl
75
+ robotcode session send repl-3f9a2c1e "Evaluate 1 + 1"
76
+ robotcode session start debug --break tests/orders.robot:19 tests
77
+ robotcode session send debug-7b2d9e04 ".vars --user"
78
+ robotcode session stop repl-3f9a2c1e
79
+ ```
80
+ """
81
+
82
+
83
+ # Errors of robotcode itself exit with 252, as other commands that run Robot Framework do, and not with the 1 of an
84
+ # input that failed.
85
+ robot_exit_codes(session)
86
+
87
+
88
+ @session.group(invoke_without_command=False)
89
+ def start() -> None:
90
+ """\
91
+ Start a session in the background and print its ID and its output up to its first prompt or its end.
92
+
93
+ `start` returns once the session takes commands. A session that isn't
94
+ ready within 60 seconds, or within `--timeout` when that is longer, is
95
+ ended.
96
+ """
97
+
98
+
99
+ _START_OPTIONS = [
100
+ click.option(
101
+ "--idle-timeout",
102
+ type=click.FloatRange(min=0, min_open=True),
103
+ default=15,
104
+ show_default=True,
105
+ metavar="MINUTES",
106
+ help="End the session when it has waited at its prompt for MINUTES without a request. A statement that "
107
+ "runs doesn't count as waiting.",
108
+ ),
109
+ _timeout_option("the first prompt"),
110
+ click.argument("args", nargs=-1, type=click.UNPROCESSED),
111
+ ]
112
+
113
+
114
+ @start.command(
115
+ name="repl",
116
+ context_settings={"ignore_unknown_options": True},
117
+ epilog="Takes the options and arguments of `robotcode repl`.",
118
+ )
119
+ @add_options(*_START_OPTIONS)
120
+ @pass_application
121
+ @click.pass_context
122
+ def start_repl(
123
+ ctx: click.Context, app: Application, idle_timeout: float, timeout: float, args: Tuple[str, ...]
124
+ ) -> None:
125
+ """Start `robotcode repl` in the background; the session is ready at its first prompt."""
126
+ _start(ctx, app, SessionKind.REPL, idle_timeout, timeout, args)
127
+
128
+
129
+ @start.command(
130
+ name="debug",
131
+ context_settings={"ignore_unknown_options": True},
132
+ epilog="Takes the options and arguments of `robotcode robot-debug`.",
133
+ )
134
+ @add_options(*_START_OPTIONS)
135
+ @pass_application
136
+ @click.pass_context
137
+ def start_debug(
138
+ ctx: click.Context, app: Application, idle_timeout: float, timeout: float, args: Tuple[str, ...]
139
+ ) -> None:
140
+ """Start `robotcode robot-debug` in the background; the session is ready at its first stop or at the end of the
141
+ run."""
142
+ _start(ctx, app, SessionKind.DEBUG, idle_timeout, timeout, args)
143
+
144
+
145
+ def _robotcode_options(ctx: click.Context) -> List[str]:
146
+ """The options given to `robotcode` itself on the command line, which the session process gets too; options from
147
+ the environment reach it with the environment."""
148
+ root = ctx.find_root()
149
+ args: List[str] = []
150
+ for param in root.command.params:
151
+ if not isinstance(param, click.Option) or param.name is None or param.name not in root.params:
152
+ continue
153
+ if root.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE:
154
+ continue
155
+ value = root.params[param.name]
156
+ if param.is_flag:
157
+ if value:
158
+ args.append(param.opts[0])
159
+ elif param.secondary_opts:
160
+ args.append(param.secondary_opts[0])
161
+ elif param.multiple:
162
+ for item in value:
163
+ args += [param.opts[0], str(item)]
164
+ elif value is not None:
165
+ args += [param.opts[0], str(value)]
166
+ return args
167
+
168
+
169
+ def _start(
170
+ ctx: click.Context, app: Application, kind: SessionKind, idle_timeout: float, timeout: float, args: Tuple[str, ...]
171
+ ) -> None:
172
+ session_id = new_session_id(kind)
173
+ try:
174
+ create_sessions_dir()
175
+ except OSError as e:
176
+ # A sandbox, for example, can keep a command from writing there.
177
+ raise click.ClickException(
178
+ f"Can't create the files of the session in {sessions_dir()}: {e.strerror or e}."
179
+ ) from e
180
+ # The process writes its standard output and standard error to the pipe and reads it at the other end.
181
+ read_end, write_end = create_output_pipe()
182
+ if sys.platform == "win32":
183
+ output = msvcrt.get_osfhandle(read_end)
184
+ else:
185
+ output = read_end
186
+ command = [
187
+ sys.executable,
188
+ "-m",
189
+ "robotcode.cli",
190
+ *_robotcode_options(ctx),
191
+ "--no-color",
192
+ "--no-pager",
193
+ kind.command,
194
+ "--serve-session",
195
+ session_id,
196
+ "--serve-output",
197
+ str(output),
198
+ "--serve-idle-timeout",
199
+ str(idle_timeout),
200
+ *args,
201
+ ]
202
+ # Unbuffered, so that an answer has all the output written before it, and in UTF-8, which the session decodes.
203
+ env = {**os.environ, "PYTHONUNBUFFERED": "1", "PYTHONIOENCODING": "utf-8"}
204
+ try:
205
+ process = start_session_process(command, output, write_end, env)
206
+ finally:
207
+ os.close(write_end)
208
+
209
+ try:
210
+ # `--timeout` is for the first prompt. Until the session takes commands at all, `start` waits longer, so that
211
+ # the other commands always reach a session whose ID it has printed.
212
+ deadline = time.monotonic() + timeout
213
+ limit = max(timeout, _STARTUP_LIMIT)
214
+ ready_by = time.monotonic() + limit
215
+ entry = read_entry(session_id)
216
+ while entry is None:
217
+ if process.poll() is not None:
218
+ _ended_before_ready(
219
+ app,
220
+ session_id,
221
+ read_to_end(read_end),
222
+ f"The session ended before it was ready, with exit code {process.returncode}.",
223
+ process.returncode,
224
+ )
225
+ if time.monotonic() >= ready_by:
226
+ process.kill()
227
+ process.wait()
228
+ _ended_before_ready(
229
+ app,
230
+ session_id,
231
+ read_to_end(read_end),
232
+ f"The session wasn't ready after {limit:g} seconds and was ended.",
233
+ DATA_ERROR,
234
+ )
235
+ time.sleep(0.05)
236
+ entry = read_entry(session_id)
237
+ finally:
238
+ # Once the session is ready, it reads the pipe itself.
239
+ os.close(read_end)
240
+
241
+ answer = _request(entry, {"request": Request.WAIT}, max(0.0, deadline - time.monotonic()))
242
+ if _structured(app):
243
+ app.print_data({"id": session_id, **_answer_data(answer)})
244
+ else:
245
+ app.echo(f"Started session {session_id}.")
246
+ _echo_answer(app, entry, answer)
247
+ app.exit(_exit_code(answer))
248
+
249
+
250
+ def _ended_before_ready(app: Application, session_id: str, output: str, message: str, exit_code: int) -> None:
251
+ remove_session_files(session_id)
252
+ if output:
253
+ app.echo(output, nl=False)
254
+ app.error(message)
255
+ app.exit(exit_code)
256
+
257
+
258
+ @session.command()
259
+ @_timeout_option("the answer")
260
+ @click.argument("session_id", metavar="ID")
261
+ @click.argument("text", metavar="INPUT")
262
+ @pass_application
263
+ def send(app: Application, timeout: float, session_id: str, text: str) -> None:
264
+ """\
265
+ Give INPUT to the prompt of the session ID and print its output up to the next prompt.
266
+
267
+ INPUT is a whole input: a statement, a text of several lines such as a FOR
268
+ loop with its END, or a dot-command such as `.vars`, which works as at the
269
+ prompt, each in a send of its own. A block that INPUT leaves unfinished
270
+ fails. The exit code is 0 when the statement passed, 1 when it failed, and
271
+ 124 when it still runs after `--timeout`. When the REPL or the run ends,
272
+ `send` says so with its exit code; a `send` after that fails, and
273
+ `session restart` starts it again.
274
+ """
275
+ entry = _entry(session_id)
276
+ answer = _request(entry, {"request": Request.SEND, "input": text}, timeout)
277
+ _echo_answer(app, entry, answer)
278
+ app.exit(_exit_code(answer))
279
+
280
+
281
+ @session.command()
282
+ @_timeout_option("the next prompt")
283
+ @click.argument("session_id", metavar="ID")
284
+ @pass_application
285
+ def wait(app: Application, timeout: float, session_id: str) -> None:
286
+ """\
287
+ Wait until the session ID waits at its prompt or its REPL or run has ended, and print its output since the last
288
+ command.
289
+
290
+ Takes over from a `send` that returned after its `--timeout`, with the exit
291
+ code that `send` would have had.
292
+ """
293
+ entry = _entry(session_id)
294
+ answer = _request(entry, {"request": Request.WAIT}, timeout)
295
+ _echo_answer(app, entry, answer)
296
+ app.exit(_exit_code(answer))
297
+
298
+
299
+ @session.command(name="status")
300
+ @click.argument("session_id", metavar="ID")
301
+ @pass_application
302
+ def session_status(app: Application, session_id: str) -> None:
303
+ """\
304
+ Print whether the session ID runs, waits at its prompt or its REPL or run has ended: `runs`, `waits` or `ended`.
305
+
306
+ It takes none of the output of the session, which `session wait` prints.
307
+ """
308
+ answer = _request(_entry(session_id), {"request": Request.STATE})
309
+ if _structured(app):
310
+ app.print_data({"state": answer["state"]})
311
+ else:
312
+ app.echo(str(answer["state"]))
313
+
314
+
315
+ @session.command(name="result")
316
+ @click.argument("session_id", metavar="ID")
317
+ @pass_application
318
+ def session_result(app: Application, session_id: str) -> None:
319
+ """\
320
+ Print the exit code of the REPL or the run of the session ID once it has ended.
321
+
322
+ `result` itself exits with 0, as Robot Framework gives exit codes a meaning
323
+ of its own; before the end, it says so and exits with 252.
324
+ """
325
+ answer = _request(_entry(session_id), {"request": Request.RESULT})
326
+ if _structured(app):
327
+ app.print_data({"exit_code": answer["exit_code"]})
328
+ else:
329
+ app.echo(str(answer["exit_code"]))
330
+
331
+
332
+ @session.command()
333
+ @_timeout_option("the first prompt")
334
+ @click.argument("session_id", metavar="ID")
335
+ @pass_application
336
+ def restart(app: Application, timeout: float, session_id: str) -> None:
337
+ """\
338
+ Start the REPL or the run of the session ID again in a new process, and print its output up to its first prompt
339
+ or its end.
340
+
341
+ A REPL or a run that hasn't ended is ended as with `session stop`, and its
342
+ output since the last command comes first. The session keeps its ID, and
343
+ the new process starts with the options of `session start` and the
344
+ breakpoints as they are.
345
+ """
346
+ entry = _entry(session_id)
347
+ # The old process ends the REPL or the run as `stop` does, then waits for the new process to take commands.
348
+ answer = _request(entry, {"request": Request.RESTART}, 2 * _STARTUP_LIMIT)
349
+ before = answer.get("output", "")
350
+ if not answer.get("restarted"):
351
+ if before:
352
+ app.echo(before, nl=False)
353
+ if "restart_failed" in answer:
354
+ raise click.ClickException(str(answer["restart_failed"]))
355
+ raise click.ClickException(f"Session '{session_id}' hasn't restarted yet; `session status` tells when it has.")
356
+ # The file names the new process now.
357
+ entry = _entry(session_id)
358
+ answer = _request(entry, {"request": Request.WAIT}, timeout)
359
+ if _structured(app):
360
+ app.print_data({"id": session_id, **_answer_data({**answer, "output": before + answer.get("output", "")})})
361
+ else:
362
+ if before:
363
+ app.echo(before, nl=not before.endswith("\n"))
364
+ app.echo(f"Restarted session {session_id}.")
365
+ _echo_answer(app, entry, answer)
366
+ app.exit(_exit_code(answer))
367
+
368
+
369
+ @session.command()
370
+ @click.argument("session_id", metavar="ID")
371
+ def interrupt(session_id: str) -> None:
372
+ """\
373
+ Interrupt the session ID as Ctrl-C does at its terminal.
374
+
375
+ In a REPL, the statement that runs fails; with the debugger attached, the run
376
+ pauses at the next keyword. `session wait` prints what follows.
377
+ """
378
+ _request(_entry(session_id), {"request": Request.INTERRUPT})
379
+
380
+
381
+ @session.command()
382
+ @click.option("--project", "of_project", is_flag=True, help="End the sessions of the project of the current folder.")
383
+ @click.option("--all", "all_sessions", is_flag=True, help="End all your sessions.")
384
+ @click.argument("session_id", metavar="[ID]", required=False)
385
+ @pass_application
386
+ def stop(app: Application, of_project: bool, all_sessions: bool, session_id: Optional[str]) -> None:
387
+ """\
388
+ End the session ID and print its output since the last command, or end several sessions.
389
+
390
+ `--project` ends the sessions of the project the current folder belongs to,
391
+ the folder RobotCode finds for its `robot.toml`; a session belongs to the
392
+ project of the folder `session start` ran in. `--all` ends all your
393
+ sessions. A debug run that has not ended is aborted as with `.abort`.
394
+ """
395
+ if (session_id is not None) + of_project + all_sessions != 1:
396
+ raise click.UsageError("Give the ID of a session, --project or --all.")
397
+ if session_id is not None:
398
+ answer = _stop(_entry(session_id))
399
+ if answer.get("output"):
400
+ app.echo(answer["output"], nl=False)
401
+ return
402
+
403
+ entries = open_sessions()
404
+ if of_project:
405
+ project = project_folder(app)
406
+ entries = [entry for entry in entries if same_file(entry.project, project)]
407
+ if not entries:
408
+ app.echo("No session is open.")
409
+ for entry in entries:
410
+ # It can have ended since it was listed.
411
+ if read_entry(entry.id) is not None:
412
+ _stop(entry)
413
+ app.echo(f"Stopped session {entry.id}.")
414
+
415
+
416
+ def _stop(entry: SessionEntry) -> Dict[str, Any]:
417
+ answer = _request(entry, {"request": Request.STOP}, 60)
418
+ if not answer.get("stopped"):
419
+ raise click.ClickException(f"Session '{entry.id}' hasn't ended yet; a second `session stop` ends it at once.")
420
+ return answer
421
+
422
+
423
+ @session.command(name="list")
424
+ @pass_application
425
+ def list_sessions(app: Application) -> None:
426
+ """List the open sessions with their project folder, whether they run, wait or their REPL or run has ended, and
427
+ the time left until they end for being idle."""
428
+ entries = open_sessions()
429
+ if _structured(app):
430
+ app.print_data(
431
+ [
432
+ {
433
+ "id": entry.id,
434
+ "project": entry.project,
435
+ "state": entry.state,
436
+ "time_left": None if (left := entry.time_left()) is None else round(left),
437
+ }
438
+ for entry in entries
439
+ ]
440
+ )
441
+ return
442
+ if not entries:
443
+ app.echo("No session is open.")
444
+ return
445
+ rows = [("ID", "PROJECT", "STATE", "IDLE TIME LEFT")] + [
446
+ (entry.id, entry.project, entry.state, _minutes(entry.time_left())) for entry in entries
447
+ ]
448
+ widths = [max(len(row[column]) for row in rows) for column in range(3)]
449
+ for row in rows:
450
+ app.echo(" ".join([*(cell.ljust(width) for cell, width in zip(row, widths)), row[3]]))
451
+
452
+
453
+ def _minutes(seconds: Optional[float]) -> str:
454
+ if seconds is None:
455
+ return "-"
456
+ minutes, seconds = divmod(round(seconds), 60)
457
+ return f"{minutes}:{seconds:02d}"
458
+
459
+
460
+ def _entry(session_id: str) -> SessionEntry:
461
+ entry = read_entry(session_id)
462
+ if entry is None:
463
+ raise click.ClickException(f"No session '{session_id}' is open.")
464
+ return entry
465
+
466
+
467
+ def _request(entry: SessionEntry, message: Dict[str, Any], timeout: Optional[float] = None) -> Dict[str, Any]:
468
+ """The answer of the session `entry` to `message`; after `timeout` seconds, the output so far."""
469
+ answer = _ask(entry, message, timeout)
470
+ if answer.get("moved"):
471
+ # The session has just restarted in a new process, which its file names now.
472
+ moved_to = read_entry(entry.id)
473
+ if moved_to is None or moved_to.address == entry.address:
474
+ raise click.ClickException(f"No session '{entry.id}' is open.")
475
+ answer = _ask(moved_to, message, timeout)
476
+ if "error" in answer:
477
+ raise click.ClickException(str(answer["error"]))
478
+ return answer
479
+
480
+
481
+ def _ask(entry: SessionEntry, message: Dict[str, Any], timeout: Optional[float]) -> Dict[str, Any]:
482
+ """Send `message` to the process that `entry` names and return its answer; after `timeout` seconds, the output so
483
+ far."""
484
+ try:
485
+ with connect(entry) as connection:
486
+ connection.send(message)
487
+ if timeout is not None and not connection.poll(timeout):
488
+ try:
489
+ connection.send({"request": Request.STATUS})
490
+ except OSError:
491
+ # The answer came just now, and the session has closed the connection.
492
+ pass
493
+ answer: Dict[str, Any] = connection.recv()
494
+ except (OSError, EOFError, multiprocessing.AuthenticationError) as e:
495
+ raise click.ClickException(f"Session '{entry.id}' doesn't answer: {e or type(e).__name__}") from e
496
+ return answer
497
+
498
+
499
+ def _structured(app: Application) -> bool:
500
+ return app.config.output_format not in (None, OutputFormat.TEXT)
501
+
502
+
503
+ def _answer_data(answer: Dict[str, Any]) -> Dict[str, Any]:
504
+ data = {"output": answer.get("output", ""), "status": answer.get("status")}
505
+ if "exit_code" in answer:
506
+ data["exit_code"] = answer["exit_code"]
507
+ return data
508
+
509
+
510
+ def _echo_answer(app: Application, entry: SessionEntry, answer: Dict[str, Any]) -> None:
511
+ if _structured(app):
512
+ app.print_data(_answer_data(answer))
513
+ return
514
+ output = answer.get("output", "")
515
+ if output:
516
+ app.echo(output, nl=False)
517
+ if not output.endswith("\n"):
518
+ app.echo("")
519
+ if "exit_code" in answer:
520
+ app.echo(f"{entry.kind.what} has ended with exit code {answer['exit_code']}.", err=True)
521
+ elif answer.get("status") == AnswerStatus.RUNNING:
522
+ app.echo(f"It still runs; `robotcode session wait {entry.id}` prints the rest.", err=True)
523
+
524
+
525
+ def _exit_code(answer: Dict[str, Any]) -> int:
526
+ """How the input went; the exit code of the REPL or the run is in the output."""
527
+ status = answer.get("status")
528
+ if not isinstance(status, AnswerStatus):
529
+ return int(DATA_ERROR)
530
+ return _EXIT_CODES[status]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: robotcode-repl
3
- Version: 2.9.0-dev.68
3
+ Version: 2.9.0-dev.74
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
@@ -27,7 +27,7 @@ Classifier: Topic :: Utilities
27
27
  Classifier: Typing :: Typed
28
28
  Requires-Python: >=3.10
29
29
  Requires-Dist: prompt-toolkit!=3.0.52
30
- Requires-Dist: robotcode-runner==2.9.0-dev.68
30
+ Requires-Dist: robotcode-runner==2.9.0-dev.74
31
31
  Description-Content-Type: text/markdown
32
32
 
33
33
  # robotcode-repl
@@ -1,22 +1,24 @@
1
1
  robotcode/repl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- robotcode/repl/__version__.py,sha256=VKDQl3EnWjlaGGS16iOqZ2LLnLORneHG-g4VFPliDAk,29
2
+ robotcode/repl/__version__.py,sha256=x1AYp8_TYii5MaUcQCE8tgBdUh4FTuZIcutnrqGidP8,29
3
3
  robotcode/repl/_backends.py,sha256=s7PV-HBhnAvwjn2le0cbOJ5hwLb4MjahUo6KWtRC3lc,110
4
4
  robotcode/repl/_indent.py,sha256=jwFKaHNvTWYpUwIWHu6JHoaCz7ljOxneR5sBrKcAjpI,3303
5
5
  robotcode/repl/_keyword_lookup.py,sha256=c8InMUDGKsw4wYmiqJzBr9GGxPC-59sRZHI0C-GWjFA,7748
6
6
  robotcode/repl/_progress.py,sha256=BaSbDGOy5UOXvD855Kd-lDrYbqPrYIWRVs507vJznK4,2586
7
+ robotcode/repl/_session.py,sha256=3L1vzFpdQULMaqKzwmdlXJdpazqg8OkORR7cRX8breY,47702
7
8
  robotcode/repl/_session_export.py,sha256=sTSkLEMoSxNQOsII3xfDY8h-nV-mrem-4h6Iug7VQv4,2841
8
9
  robotcode/repl/base_interpreter.py,sha256=ep1xqH5QCtkn2U2P77IJQCk_Q5TTBsYOcRjGC5hV5cY,30176
9
- robotcode/repl/cli.py,sha256=1o8_p0I8bCPsnhI_QoHXWr9U6t9Mj11PrI1E3XG2e1c,23706
10
- robotcode/repl/console_interpreter.py,sha256=K8GP7nR_L0o7LpV456OZsRFHym7xH5CyK3NkeD9UvHc,88757
10
+ robotcode/repl/cli.py,sha256=RcjFT1yvcDy8HMzVO6r0cuqWCKqFofrs7XdkJPUpp1E,26878
11
+ robotcode/repl/console_interpreter.py,sha256=VNCYLHRrW4LPtj37q27_dq75OHPlayCWPurw4EO9k0o,89411
11
12
  robotcode/repl/doc_cli.py,sha256=lJ1KrS-oxqW32XyRSFiyhSrtKVvzA7TuMclMuZRYIrE,23221
12
- robotcode/repl/hooks.py,sha256=huqeT18sHWxG2dQNCGmgQUkb11CzVQkOoDgrDAy9hqg,238
13
+ robotcode/repl/hooks.py,sha256=JD0A6vqQ0pcJx45l5w0wq-bWqnNkBV_6tPugtMZN4yo,280
13
14
  robotcode/repl/prompt_toolkit_interpreter.py,sha256=fq0uRsWucGhjKwGekUShz4r4Vt0nvbeAa-phLvI6WNw,13416
14
15
  robotcode/repl/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
15
16
  robotcode/repl/run.py,sha256=IWeiGZm56vkLn-hykP-_mWLrdpDciNyMk33_dT-6EJA,5327
17
+ robotcode/repl/session_cli.py,sha256=m5qFjusybPP4c25qc5FSmRNjk1Y3nshXzBWJnAC-Z2E,19825
16
18
  robotcode/repl/Repl/__init__.py,sha256=-j2WxY3MzdLfsMvpa2wMs6WVF_eeJygdshtMN50r67U,43
17
19
  robotcode/repl/Repl/repl.py,sha256=k3vCeg9z_4cb2dgZ4YKHl4TD599gumVkQMImAzGl20Y,1628
18
20
  robotcode/repl/_debug/__init__.py,sha256=uQNyC3pdlpJZI3FRKzcp9BYEz1QtfBR--gsgKNomxrQ,908
19
- robotcode/repl/_debug/controller.py,sha256=D5lxDqrVmjRG4bAF9_5561TIQ9MzlvOphIBVW8DzhOU,33221
21
+ robotcode/repl/_debug/controller.py,sha256=FQY92Jd4gRWcIZ4grZ7WY9cQ9g09SUnQPxmp3bo385Q,34114
20
22
  robotcode/repl/_debug/types.py,sha256=3Vbecx44pruY0fXptEowKr_tYhljXSb6Sbr81YS22Mk,4597
21
23
  robotcode/repl/_pt/__init__.py,sha256=k1bJgYbKwp5ScYO8fSx0BVy8XW9Aw_8o0jTOWQTQdX8,411
22
24
  robotcode/repl/_pt/completion.py,sha256=BJD6sASKu1EfW0QPNKIDRc9O-8ttErXvxvnFb10lAxk,23318
@@ -24,7 +26,7 @@ robotcode/repl/_pt/components.py,sha256=kuYVXJc4bFJq4b3-JtAtBYymvS7ssSwlKDldWYFG
24
26
  robotcode/repl/_pt/doc_viewer.py,sha256=iazNOQEvRygPSUyqKH2qOYShzdYqd7vufZcxPziJx8Q,71648
25
27
  robotcode/repl/_pt/history.py,sha256=Rvbdu4LtbYk9dPgYJY7D1JpfyT1SETUdNmtevxo21H4,1591
26
28
  robotcode/repl/_pt/lexer.py,sha256=YXtDMWQXPIocwceMXFlvULWyGXCDmqeAtTer_Ecuvwk,13925
27
- robotcode_repl-2.9.0.dev68.dist-info/METADATA,sha256=LsjjHtQEfaFbqU5N4pG91dDZiUm2BqaGyEJ1mYFrJ24,2833
28
- robotcode_repl-2.9.0.dev68.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
29
- robotcode_repl-2.9.0.dev68.dist-info/entry_points.txt,sha256=lI4idVOEmSWxmmioejg-_QvHXTLySK6ZxJ13R_v8ykU,40
30
- robotcode_repl-2.9.0.dev68.dist-info/RECORD,,
29
+ robotcode_repl-2.9.0.dev74.dist-info/METADATA,sha256=Fghn58v8ilKZ1gaFB1Xbq9t2EVfapSCk_6fpIiANR0w,2833
30
+ robotcode_repl-2.9.0.dev74.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
31
+ robotcode_repl-2.9.0.dev74.dist-info/entry_points.txt,sha256=lI4idVOEmSWxmmioejg-_QvHXTLySK6ZxJ13R_v8ykU,40
32
+ robotcode_repl-2.9.0.dev74.dist-info/RECORD,,