robotcode-repl-server 2.6.2__py3-none-any.whl → 2.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- __version__ = "2.6.2"
1
+ __version__ = "2.8.0"
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import threading
3
3
  import time
4
+ from concurrent.futures import wait
4
5
  from pathlib import Path
5
6
  from typing import Any, Optional, Sequence, Tuple
6
7
 
@@ -14,7 +15,9 @@ from robotcode.plugin.click_helper.options import (
14
15
  server_options,
15
16
  )
16
17
  from robotcode.plugin.click_helper.types import AddressesPort, add_options
18
+ from robotcode.plugin.click_helper.wrappable import wrappable
17
19
  from robotcode.repl.run import run_repl
20
+ from robotcode.runner.cli.robot import load_robot_profile
18
21
 
19
22
  from .__version__ import __version__
20
23
  from .interpreter import Interpreter
@@ -80,9 +83,14 @@ def run_jsonrpc_server(
80
83
  ) -> None:
81
84
  loop = asyncio.new_event_loop()
82
85
  asyncio.set_event_loop(loop)
83
- run_jsonrpc_server_async(mode, port, bind, pipe_name, interpreter)
86
+ try:
87
+ run_jsonrpc_server_async(mode, port, bind, pipe_name, interpreter)
88
+ finally:
89
+ # closed here, not by the garbage collector at exit, which can fail with a traceback on Python 3.11
90
+ loop.close()
84
91
 
85
92
 
93
+ @wrappable
86
94
  @click.command(
87
95
  context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
88
96
  add_help_option=True,
@@ -154,11 +162,11 @@ def run_jsonrpc_server(
154
162
  "--source",
155
163
  type=click.Path(path_type=Path),
156
164
  metavar="FILE",
157
- help="Use the parent directory of FILE as the REPL's working directory. "
158
- "Relative paths inside `Import Resource`, `Import Library`, "
159
- "file-based variables, etc. resolve against that directory. "
160
- "The file itself is never read or written, so the path doesn't "
161
- "need to exist.",
165
+ help="Run the session as if its keywords were written in FILE: `${CURDIR}` is the "
166
+ "directory of FILE, `${SUITE SOURCE}` is FILE and, on Robot Framework 7.4 and newer, "
167
+ "relative paths in `Import Resource`, `Import Library`, and `Import Variables` resolve "
168
+ "against that directory. A relative FILE is resolved against the directory the command "
169
+ "is started from. The file itself is never read or written, so the path doesn't need to exist.",
162
170
  )
163
171
  @click.argument(
164
172
  "files",
@@ -195,6 +203,10 @@ def repl_server(
195
203
  Start a REPL server, client can connect to the server and run the REPL scripts.
196
204
  """
197
205
 
206
+ # Before the server starts, so that it runs under the `wrapper` too; an error of the
207
+ # configuration shows when `run_repl` uses it, after the server has started.
208
+ load_robot_profile(app, tuple(str(f.absolute()) for f in files))
209
+
198
210
  mode, port, bind, pipe_name = resolve_server_options(
199
211
  ctx,
200
212
  app,
@@ -211,12 +223,17 @@ def repl_server(
211
223
 
212
224
  interpreter = Interpreter(list(files))
213
225
 
214
- server_task = run_as_debugpy_hidden_task(run_jsonrpc_server, mode, port, bind, pipe_name, interpreter)
226
+ # A dry run starts no server; `run_repl` only prints what it would execute.
227
+ server_task = (
228
+ None
229
+ if app.config.dry
230
+ else run_as_debugpy_hidden_task(run_jsonrpc_server, mode, port, bind, pipe_name, interpreter)
231
+ )
215
232
 
216
- server = wait_for_server(server_task)
233
+ server = wait_for_server(server_task) if server_task is not None else None
217
234
 
218
235
  try:
219
- run_repl(
236
+ result = run_repl(
220
237
  interpreter=interpreter,
221
238
  app=app,
222
239
  variable=variable,
@@ -231,7 +248,15 @@ def repl_server(
231
248
  files=files,
232
249
  )
233
250
  finally:
251
+ # Closing stops the server's stdio reader too. It runs on the server's loop, because
252
+ # called from here it waits until all clients of a TCP server have disconnected (from
253
+ # Python 3.12 on). The wait must not raise: an error of the session, such as an
254
+ # invalid robot.toml, has to reach Click unchanged.
234
255
  if server is not None:
235
- server.loop.stop()
256
+ server.loop.call_soon_threadsafe(server.close)
257
+
258
+ if server_task is not None:
259
+ wait([server_task], timeout=1)
236
260
 
237
- server_task.result(5)
261
+ if result.exit_code is not None:
262
+ app.exit(result.exit_code)
@@ -118,6 +118,8 @@ class Interpreter(BaseInterpreter):
118
118
  self._interrupted = False
119
119
  self._has_shutdown = False
120
120
  self._cell_errors: List[str] = []
121
+ # Set while the session waits for a cell: SIGTERM then ends the wait (`_end_waiting`).
122
+ self._waiting = False
121
123
 
122
124
  def shutdown(self) -> None:
123
125
  self._code = []
@@ -270,7 +272,14 @@ class Interpreter(BaseInterpreter):
270
272
  self._success = True
271
273
 
272
274
  def run_input(self) -> None:
273
- self.has_input.wait()
275
+ self._waiting = True
276
+ try:
277
+ # Checked after marking the wait: a SIGTERM in between can't be missed.
278
+ if self._termination_requested:
279
+ raise EOFError
280
+ self.has_input.wait()
281
+ finally:
282
+ self._waiting = False
274
283
  if self._has_shutdown:
275
284
  self.executed.set()
276
285
  raise EOFError
@@ -280,3 +289,9 @@ class Interpreter(BaseInterpreter):
280
289
  finally:
281
290
  self.has_input.clear()
282
291
  self.executed.set()
292
+
293
+ def _end_waiting(self) -> None:
294
+ # Raised rather than `shutdown()`: setting the event takes a lock that the main
295
+ # thread, interrupted by the signal, may hold.
296
+ if self._waiting:
297
+ raise EOFError
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: robotcode-repl-server
3
- Version: 2.6.2
3
+ Version: 2.8.0
4
4
  Summary: RobotCode REPL Server 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
- Requires-Dist: robotcode-jsonrpc2==2.6.2
29
- Requires-Dist: robotcode-runner==2.6.2
29
+ Requires-Dist: robotcode-jsonrpc2==2.8.0
30
+ Requires-Dist: robotcode-runner==2.8.0
30
31
  Description-Content-Type: text/markdown
31
32
 
32
33
  # robotcode-repl-server
@@ -0,0 +1,12 @@
1
+ robotcode/repl_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ robotcode/repl_server/__version__.py,sha256=z6im3C9Qb6qiQIpaJdE4f9WQiCnFGSUQnQXDPw_dvDg,22
3
+ robotcode/repl_server/cli.py,sha256=DF9VvWl8b1lV17kz6OY9IcqFVAGOQfFp88ce-Rb8iHM,7424
4
+ robotcode/repl_server/hooks.py,sha256=4O9H8cefHc6T7erjPxzU941w3KWytTBB5gmvYb4bs_I,196
5
+ robotcode/repl_server/interpreter.py,sha256=KZFAbkXuTfJlMlLlKCo0orRJeDGtd1SlPSM4l75nbpU,9896
6
+ robotcode/repl_server/protocol.py,sha256=SGCRyYdkcQPcD9zUBOQNvHVg6f5_AhNtmi85FR92rTc,1118
7
+ robotcode/repl_server/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
8
+ robotcode/repl_server/server.py,sha256=zzFsD6ds56d4GQJKXoysVZP-oiS08AtMKeyLKXH9Fss,746
9
+ robotcode_repl_server-2.8.0.dist-info/METADATA,sha256=O2hfujYpxrQk9relIFWBZKw2T_ZZ3vCDXVArFccbePI,2871
10
+ robotcode_repl_server-2.8.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
11
+ robotcode_repl_server-2.8.0.dist-info/entry_points.txt,sha256=U_1iYu71VNyPq_epO0fXHki3B4BE4gR2mbZFAOWN1cg,54
12
+ robotcode_repl_server-2.8.0.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,12 +0,0 @@
1
- robotcode/repl_server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- robotcode/repl_server/__version__.py,sha256=53Sii4w6BIWn-1RhaTyqUO46gDe4nDCRQDAcpsWFH24,22
3
- robotcode/repl_server/cli.py,sha256=S6_bWYQZZV3rsZQBFSkKri33y-R9eAXa8-coede6x_4,6026
4
- robotcode/repl_server/hooks.py,sha256=4O9H8cefHc6T7erjPxzU941w3KWytTBB5gmvYb4bs_I,196
5
- robotcode/repl_server/interpreter.py,sha256=_cQ5RgGxFl4zWRHWgXgxqL-urr1SNL0Yy3OGE4U8oNQ,9282
6
- robotcode/repl_server/protocol.py,sha256=SGCRyYdkcQPcD9zUBOQNvHVg6f5_AhNtmi85FR92rTc,1118
7
- robotcode/repl_server/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
8
- robotcode/repl_server/server.py,sha256=zzFsD6ds56d4GQJKXoysVZP-oiS08AtMKeyLKXH9Fss,746
9
- robotcode_repl_server-2.6.2.dist-info/METADATA,sha256=eKVZZmICo9sZgzHMGAk0wXeLYNKf9XiyxpIlejZbwdY,2820
10
- robotcode_repl_server-2.6.2.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
11
- robotcode_repl_server-2.6.2.dist-info/entry_points.txt,sha256=U_1iYu71VNyPq_epO0fXHki3B4BE4gR2mbZFAOWN1cg,54
12
- robotcode_repl_server-2.6.2.dist-info/RECORD,,