robotcode-repl 2.6.2__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.
@@ -28,6 +28,7 @@ from prompt_toolkit.history import History, InMemoryHistory
28
28
  from robot import result, running
29
29
 
30
30
  from robotcode.plugin import Application
31
+ from robotcode.robot.utils.markdown_docs import REFERENCE_KEYWORD, LinkResolver
31
32
 
32
33
  from ._pt.components import (
33
34
  _DEFAULT_STYLE,
@@ -121,12 +122,32 @@ class PromptToolkitConsoleInterpreter(ConsoleInterpreter):
121
122
  return self._session.prompt(prompt, default=prefill, completer=completer)
122
123
  return self._session.prompt(prompt, default=prefill)
123
124
 
125
+ def _end_read(self) -> None:
126
+ loop = self._session.app.loop
127
+ if loop is None:
128
+ # No event loop runs the prompt (yet, or any more).
129
+ super()._end_read()
130
+ return
131
+ # The signal handler can run inside a callback of the prompt's event loop, which
132
+ # would only report an error raised there; so the prompt ends through the loop.
133
+ loop.call_soon_threadsafe(self._end_prompt)
134
+
135
+ def _end_prompt(self) -> None:
136
+ app = self._session.app
137
+ if app.future is not None and not app.future.done():
138
+ app.exit(exception=EOFError())
139
+
140
+ def _report_interrupt(self, prompt: str) -> None:
141
+ # An aborted prompt has already ended its line.
142
+ del prompt
143
+ self._echo("KeyboardInterrupt")
144
+
124
145
  def make_completer(
125
146
  self, command_names: List[str], context_provider: Callable[[], Tuple[Any, Any]]
126
147
  ) -> Optional[Any]:
127
148
  return _RobotCompleter(command_names=command_names, context_provider=context_provider)
128
149
 
129
- def show_doc(self, title: str, markdown: str, *, scroll_to: Optional[str] = None) -> None:
150
+ def show_doc(self, title: str, markdown: str, *, scroll_to: Optional[str] = None, outline: bool = False) -> None:
130
151
  """Display ``markdown`` in the fullscreen doc viewer.
131
152
 
132
153
  Blocks until the user closes the viewer (Esc / q / Enter). The
@@ -135,8 +156,9 @@ class PromptToolkitConsoleInterpreter(ConsoleInterpreter):
135
156
  untouched. Safe to call from inside a dot-command handler that
136
157
  runs between two `read_line` invocations. ``scroll_to`` opens the
137
158
  viewer scrolled to the first rendered line containing that text.
159
+ ``outline`` gives the page of a library a sidebar with its headings.
138
160
  """
139
- self._doc_viewer.run(title, markdown, scroll_to=scroll_to)
161
+ self._doc_viewer.run(title, markdown, scroll_to=scroll_to, outline=outline)
140
162
 
141
163
  def _keyword_list_entry(self, owner_name: str, kw_name: str) -> str:
142
164
  """Render a `.kw` list entry as a link into the keyword's page.
@@ -148,6 +170,17 @@ class PromptToolkitConsoleInterpreter(ConsoleInterpreter):
148
170
  """
149
171
  return f"- [{kw_name}](kw:{quote(f'{owner_name}.{kw_name}')})"
150
172
 
173
+ def _keyword_link_resolver(self, owner_name: str) -> Optional[LinkResolver]:
174
+ """References to other keywords of the same owner open that
175
+ keyword's page, like the entries of the `.kw` list."""
176
+
177
+ def resolve(kind: str, name: str) -> Optional[str]:
178
+ if kind == REFERENCE_KEYWORD:
179
+ return f"kw:{quote(f'{owner_name}.{name}')}"
180
+ return None
181
+
182
+ return resolve
183
+
151
184
  def _resolve_doc_link(self, target: str) -> Optional[Tuple[str, str]]:
152
185
  """Resolve a `kw:<owner.keyword>` doc-viewer link to a keyword
153
186
  page; returns ``None`` for any other target so the viewer falls
robotcode/repl/run.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import io
2
2
  import sys
3
+ from dataclasses import dataclass
3
4
  from pathlib import Path
4
5
  from typing import Optional, Tuple
5
6
 
@@ -25,6 +26,36 @@ RobotCode REPL
25
26
  repl
26
27
  """
27
28
 
29
+ # Options from robot.toml, `args`, argument files or ROBOT_OPTIONS that are meant for real
30
+ # suites. Applied to REPL_SUITE they deselect or skip its only test, so the REPL never
31
+ # starts, or turn the session into a dry run in which nothing typed is executed. The
32
+ # other skip options are dropped along with them.
33
+ _IGNORED_ROBOT_OPTIONS = (
34
+ "include",
35
+ "exclude",
36
+ "suite",
37
+ "test",
38
+ "task",
39
+ "rerunfailed",
40
+ "rerunfailedsuites",
41
+ "dryrun",
42
+ "settag",
43
+ "skip",
44
+ "skiponfailure",
45
+ "skipteardownonexit",
46
+ )
47
+
48
+
49
+ @dataclass
50
+ class ReplResult:
51
+ """How a REPL session ended."""
52
+
53
+ # Robot Framework's return code for the session test: 1 when it failed, 0 when it
54
+ # passed or when `statusrc` is switched off.
55
+ return_code: int
56
+ # The code given to `.exit`/`.quit`, None without one.
57
+ exit_code: Optional[int]
58
+
28
59
 
29
60
  def run_repl(
30
61
  interpreter: BaseInterpreter,
@@ -39,7 +70,8 @@ def run_repl(
39
70
  xunit: Optional[str] = None,
40
71
  source: Optional[Path] = None,
41
72
  files: Tuple[Path, ...] = (),
42
- ) -> None:
73
+ statusrc: Optional[bool] = None,
74
+ ) -> ReplResult:
43
75
  robot_options_and_args: Tuple[str, ...] = ()
44
76
 
45
77
  if files:
@@ -53,16 +85,18 @@ def run_repl(
53
85
  robot_options_and_args += ("--pythonpath", pypath)
54
86
  if outputdir:
55
87
  robot_options_and_args += ("--outputdir", outputdir)
88
+ # Parsed after the configured options, so Robot's "last one wins" lets it override them.
89
+ if statusrc is not None:
90
+ robot_options_and_args += ("--statusrc" if statusrc else "--nostatusrc",)
56
91
 
57
92
  root_folder, _profile, cmd_options = handle_robot_options(app, (*robot_options_and_args, *(str(f) for f in files)))
58
93
 
59
- if source is None:
60
- source = Path.cwd() / "__repl_internal__.robot"
94
+ # Resolved before `app.chdir`, so a relative `--source` is relative to where the
95
+ # REPL was started (like FILES), not to the project root.
96
+ source = normalized_path(source if source is not None else Path.cwd() / "__repl_internal__.robot")
61
97
 
62
98
  with app.chdir(root_folder) as orig_folder:
63
99
  try:
64
- curdir = normalized_path(source).parent if source is not None else Path.cwd()
65
-
66
100
  options, _ = RobotFrameworkEx(
67
101
  app,
68
102
  ["."],
@@ -71,7 +105,12 @@ def run_repl(
71
105
  orig_folder=orig_folder,
72
106
  ).parse_arguments((*cmd_options, *robot_options_and_args))
73
107
 
74
- interpreter.source = normalized_path(source) if source is not None else None
108
+ # Every key is dropped, but only options that are actually set (not e.g. `--nodryrun`) are reported.
109
+ ignored = [key for key in _IGNORED_ROBOT_OPTIONS if options.pop(key, None)]
110
+ if ignored:
111
+ app.verbose(f"Ignoring robot options in the REPL: {', '.join(ignored)}")
112
+
113
+ interpreter.source = source
75
114
 
76
115
  settings = RobotSettings(
77
116
  options,
@@ -92,8 +131,9 @@ def run_repl(
92
131
  sys.path = settings.pythonpath + sys.path
93
132
 
94
133
  with io.StringIO(REPL_SUITE) as suite_io:
95
- model = get_model(suite_io, curdir=str(curdir).replace("\\", "\\\\"))
96
- model.source = source
134
+ model = get_model(suite_io, curdir=str(source.parent).replace("\\", "\\\\"))
135
+ # RF < 6.1 expects a `str` suite source; RF 6.1+ converts it to a `Path` itself.
136
+ model.source = str(source)
97
137
 
98
138
  suite = TestSuite.from_model(model)
99
139
  suite.configure(**settings.suite_config)
@@ -109,3 +149,6 @@ def run_repl(
109
149
  except DataError as err:
110
150
  app.error(str(err))
111
151
  app.exit(DATA_ERROR)
152
+
153
+ # The prompt loop runs inside `suite.run`, so a code given to `.exit` is known by now.
154
+ return ReplResult(result.return_code, interpreter.exit_code)
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: robotcode-repl
3
- Version: 2.6.2
3
+ Version: 2.8.0-dev.548
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
@@ -20,13 +20,14 @@ 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
29
  Requires-Dist: prompt-toolkit!=3.0.52
29
- Requires-Dist: robotcode-runner==2.6.2
30
+ Requires-Dist: robotcode-runner==2.8.0-dev.548
30
31
  Description-Content-Type: text/markdown
31
32
 
32
33
  # robotcode-repl
@@ -0,0 +1,30 @@
1
+ robotcode/repl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ robotcode/repl/__version__.py,sha256=4qGR5Sg7VszfoERVpnszHJ_tsWJ0G_bUZdheH0_dqx4,30
3
+ robotcode/repl/_backends.py,sha256=s7PV-HBhnAvwjn2le0cbOJ5hwLb4MjahUo6KWtRC3lc,110
4
+ robotcode/repl/_indent.py,sha256=jwFKaHNvTWYpUwIWHu6JHoaCz7ljOxneR5sBrKcAjpI,3303
5
+ robotcode/repl/_keyword_lookup.py,sha256=c8InMUDGKsw4wYmiqJzBr9GGxPC-59sRZHI0C-GWjFA,7748
6
+ robotcode/repl/_progress.py,sha256=BaSbDGOy5UOXvD855Kd-lDrYbqPrYIWRVs507vJznK4,2586
7
+ robotcode/repl/_session_export.py,sha256=sTSkLEMoSxNQOsII3xfDY8h-nV-mrem-4h6Iug7VQv4,2841
8
+ robotcode/repl/base_interpreter.py,sha256=haLDzqVqrgs7uqmAGVjma8W8j110GcLA0KZlv0QHKxI,29856
9
+ robotcode/repl/cli.py,sha256=jt0fvcQqZ40wX7GwfPawGDAd53BFCggsKSnydZYsHvc,22029
10
+ robotcode/repl/console_interpreter.py,sha256=4PwPwsE3D6ZE8qYe0ZRc58gTuf3GWQQa7Hh5hqs7hJw,87781
11
+ robotcode/repl/doc_cli.py,sha256=24ZzA37cOt21wPzggx1fi_K2_GCpBekA6xiAp5_WRE0,23122
12
+ robotcode/repl/hooks.py,sha256=huqeT18sHWxG2dQNCGmgQUkb11CzVQkOoDgrDAy9hqg,238
13
+ robotcode/repl/prompt_toolkit_interpreter.py,sha256=0xbh71AMbuJt8nyIRVv0gEfIhnRrmO7ZVNKVss5yfNw,13344
14
+ robotcode/repl/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
15
+ robotcode/repl/run.py,sha256=IWeiGZm56vkLn-hykP-_mWLrdpDciNyMk33_dT-6EJA,5327
16
+ robotcode/repl/Repl/__init__.py,sha256=-j2WxY3MzdLfsMvpa2wMs6WVF_eeJygdshtMN50r67U,43
17
+ robotcode/repl/Repl/repl.py,sha256=k3vCeg9z_4cb2dgZ4YKHl4TD599gumVkQMImAzGl20Y,1628
18
+ robotcode/repl/_debug/__init__.py,sha256=uQNyC3pdlpJZI3FRKzcp9BYEz1QtfBR--gsgKNomxrQ,908
19
+ robotcode/repl/_debug/controller.py,sha256=D5lxDqrVmjRG4bAF9_5561TIQ9MzlvOphIBVW8DzhOU,33221
20
+ robotcode/repl/_debug/types.py,sha256=3Vbecx44pruY0fXptEowKr_tYhljXSb6Sbr81YS22Mk,4597
21
+ robotcode/repl/_pt/__init__.py,sha256=k1bJgYbKwp5ScYO8fSx0BVy8XW9Aw_8o0jTOWQTQdX8,411
22
+ robotcode/repl/_pt/completion.py,sha256=BJD6sASKu1EfW0QPNKIDRc9O-8ttErXvxvnFb10lAxk,23318
23
+ robotcode/repl/_pt/components.py,sha256=kuYVXJc4bFJq4b3-JtAtBYymvS7ssSwlKDldWYFGMuA,20152
24
+ robotcode/repl/_pt/doc_viewer.py,sha256=iazNOQEvRygPSUyqKH2qOYShzdYqd7vufZcxPziJx8Q,71648
25
+ robotcode/repl/_pt/history.py,sha256=Rvbdu4LtbYk9dPgYJY7D1JpfyT1SETUdNmtevxo21H4,1591
26
+ robotcode/repl/_pt/lexer.py,sha256=YXtDMWQXPIocwceMXFlvULWyGXCDmqeAtTer_Ecuvwk,13925
27
+ robotcode_repl-2.8.0.dev548.dist-info/METADATA,sha256=tIi2Mhdf0HfnLnCvUOt5LQwp_vcblkLrW1fEqG_Fatc,2835
28
+ robotcode_repl-2.8.0.dev548.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
29
+ robotcode_repl-2.8.0.dev548.dist-info/entry_points.txt,sha256=lI4idVOEmSWxmmioejg-_QvHXTLySK6ZxJ13R_v8ykU,40
30
+ robotcode_repl-2.8.0.dev548.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.30.1
2
+ Generator: hatchling 1.32.4
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,29 +0,0 @@
1
- robotcode/repl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- robotcode/repl/__version__.py,sha256=53Sii4w6BIWn-1RhaTyqUO46gDe4nDCRQDAcpsWFH24,22
3
- robotcode/repl/_backends.py,sha256=s7PV-HBhnAvwjn2le0cbOJ5hwLb4MjahUo6KWtRC3lc,110
4
- robotcode/repl/_indent.py,sha256=0v0RYe8nWpfNZpCEQanVOuotA7WZJtfg5KFuybq18I0,3014
5
- robotcode/repl/_keyword_lookup.py,sha256=c8InMUDGKsw4wYmiqJzBr9GGxPC-59sRZHI0C-GWjFA,7748
6
- robotcode/repl/_progress.py,sha256=BaSbDGOy5UOXvD855Kd-lDrYbqPrYIWRVs507vJznK4,2586
7
- robotcode/repl/_session_export.py,sha256=sTSkLEMoSxNQOsII3xfDY8h-nV-mrem-4h6Iug7VQv4,2841
8
- robotcode/repl/base_interpreter.py,sha256=TZGHfoXgUATlFhQdpFS48DFO21oZrUxqosGJhMV8jnI,17786
9
- robotcode/repl/cli.py,sha256=A6QwuTYyOfTkQf1U6dWgd-pEY5_69deURaYa4AA59dU,19418
10
- robotcode/repl/console_interpreter.py,sha256=c88N5U7FNXCTwexj79iiAZ8Rq_o1TI7sEPmi1d92fZg,75687
11
- robotcode/repl/hooks.py,sha256=FyaV18JRJqAls3Sox8J3uRQFV59HDO92EdN6cQEEgPo,208
12
- robotcode/repl/prompt_toolkit_interpreter.py,sha256=iZnsS0hwbxxS_RFh799x1Ide0tvAghEI25R7JF8lC4E,11939
13
- robotcode/repl/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
14
- robotcode/repl/run.py,sha256=ISAU_m5nGwVQqBnjLCy30oBbIvtYQsU-aknkSJODPGw,3581
15
- robotcode/repl/Repl/__init__.py,sha256=-j2WxY3MzdLfsMvpa2wMs6WVF_eeJygdshtMN50r67U,43
16
- robotcode/repl/Repl/repl.py,sha256=-uYIceM5OQ2uvkc4WUBJ1SjQjT3avusoeSBVx9UnUGg,1129
17
- robotcode/repl/_debug/__init__.py,sha256=uQNyC3pdlpJZI3FRKzcp9BYEz1QtfBR--gsgKNomxrQ,908
18
- robotcode/repl/_debug/controller.py,sha256=DOs3MM1AVxui0g5I1WdNA4nwGgeUdOhtfQogRE-4KC0,31263
19
- robotcode/repl/_debug/types.py,sha256=9bj3oi99wI3KsWNm7xs9GrxizaOw8WKDd7CCxrqxhAs,4363
20
- robotcode/repl/_pt/__init__.py,sha256=k1bJgYbKwp5ScYO8fSx0BVy8XW9Aw_8o0jTOWQTQdX8,411
21
- robotcode/repl/_pt/completion.py,sha256=BJD6sASKu1EfW0QPNKIDRc9O-8ttErXvxvnFb10lAxk,23318
22
- robotcode/repl/_pt/components.py,sha256=hMZl9K82gc1ONNUa0kuTCzyHeMyiqs0FG0aBSd3-Q-c,20094
23
- robotcode/repl/_pt/doc_viewer.py,sha256=_WAkJP8U3eslj2aWrNaOknLyYzdpKUsWeWuVC3PB6Y0,55635
24
- robotcode/repl/_pt/history.py,sha256=Rvbdu4LtbYk9dPgYJY7D1JpfyT1SETUdNmtevxo21H4,1591
25
- robotcode/repl/_pt/lexer.py,sha256=EIPGOkUaQie0PGa3lym0-s3CHHvLZiIxvz5sJNo3jdQ,13725
26
- robotcode_repl-2.6.2.dist-info/METADATA,sha256=RSThPSpI0PZIHMFNjl8hYkFtMYIO9vkNVHB4pICOGyg,2768
27
- robotcode_repl-2.6.2.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
28
- robotcode_repl-2.6.2.dist-info/entry_points.txt,sha256=lI4idVOEmSWxmmioejg-_QvHXTLySK6ZxJ13R_v8ykU,40
29
- robotcode_repl-2.6.2.dist-info/RECORD,,