robotcode-repl-server 2.7.0__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.7.0"
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
 
@@ -16,6 +17,7 @@ from robotcode.plugin.click_helper.options import (
16
17
  from robotcode.plugin.click_helper.types import AddressesPort, add_options
17
18
  from robotcode.plugin.click_helper.wrappable import wrappable
18
19
  from robotcode.repl.run import run_repl
20
+ from robotcode.runner.cli.robot import load_robot_profile
19
21
 
20
22
  from .__version__ import __version__
21
23
  from .interpreter import Interpreter
@@ -81,7 +83,11 @@ def run_jsonrpc_server(
81
83
  ) -> None:
82
84
  loop = asyncio.new_event_loop()
83
85
  asyncio.set_event_loop(loop)
84
- 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()
85
91
 
86
92
 
87
93
  @wrappable
@@ -156,11 +162,11 @@ def run_jsonrpc_server(
156
162
  "--source",
157
163
  type=click.Path(path_type=Path),
158
164
  metavar="FILE",
159
- help="Use the parent directory of FILE as the REPL's working directory. "
160
- "Relative paths inside `Import Resource`, `Import Library`, "
161
- "file-based variables, etc. resolve against that directory. "
162
- "The file itself is never read or written, so the path doesn't "
163
- "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.",
164
170
  )
165
171
  @click.argument(
166
172
  "files",
@@ -197,6 +203,10 @@ def repl_server(
197
203
  Start a REPL server, client can connect to the server and run the REPL scripts.
198
204
  """
199
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
+
200
210
  mode, port, bind, pipe_name = resolve_server_options(
201
211
  ctx,
202
212
  app,
@@ -213,12 +223,17 @@ def repl_server(
213
223
 
214
224
  interpreter = Interpreter(list(files))
215
225
 
216
- 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
+ )
217
232
 
218
- server = wait_for_server(server_task)
233
+ server = wait_for_server(server_task) if server_task is not None else None
219
234
 
220
235
  try:
221
- run_repl(
236
+ result = run_repl(
222
237
  interpreter=interpreter,
223
238
  app=app,
224
239
  variable=variable,
@@ -233,7 +248,15 @@ def repl_server(
233
248
  files=files,
234
249
  )
235
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.
236
255
  if server is not None:
237
- 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)
238
260
 
239
- 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.7.0
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.7.0
29
- Requires-Dist: robotcode-runner==2.7.0
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.31.0
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=EtKWW0Hnl5oWglRNH0HZigvcDT2FEs58ek8buJdwW1E,22
3
- robotcode/repl_server/cli.py,sha256=bt5gd_MvZvoHW8RhuE52xEOnsW6hAPe9oX9aj-ZVrgw,6099
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.7.0.dist-info/METADATA,sha256=etvHONVHj0YARfk1YDCJJhUYGjIeJOY8C_m-D6Ngu4Q,2820
10
- robotcode_repl_server-2.7.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
11
- robotcode_repl_server-2.7.0.dist-info/entry_points.txt,sha256=U_1iYu71VNyPq_epO0fXHki3B4BE4gR2mbZFAOWN1cg,54
12
- robotcode_repl_server-2.7.0.dist-info/RECORD,,