Skip to content

Commit 44361b2

Browse files
Technologicatclaude
andcommitted
TODO_DEFERRED: add D10 — tier 2 REPL tests for unpythonic.net
Counterpart to mcpyrate's D5. Tier 1 for `unpythonic.net` will use a server-in-thread + in-process client pattern with scripted input via `builtins.input` monkey-patch and captured stdout/ stderr via `io.StringIO`. Single-process, fast, no subprocess boundary needed — the server speaks TCP to `127.0.0.1` and the client loop runs in the same pytest process. Tier 2 would spawn both client and server as real subprocesses, driven through pseudo-terminals via `pexpect` / `ptyprocess`, to catch things tier 1 cannot reach: real readline bindings, terminal escape sequences, signal handling, and the `ptyproxy` machinery itself end-to-end (tier 1 stubs around it by running `InteractiveConsole` against in-memory streams). POSIX-only naturally; Windows support depends on D9 (port `unpythonic.net` to MS Windows) landing first. Rough shape of the eventual `pexpect`-based invocation included. Entry ends with: "we might never need it." Tier 1 already exercises most of the protocol surface; tier 2 is a safety net for terminal-semantics and signal-path bugs specifically. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bf86a2a commit 44361b2

1 file changed

Lines changed: 32 additions & 1 deletion

File tree

TODO_DEFERRED.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Deferred Issues
22

3-
Next unused item code: D10
3+
Next unused item code: D11
44

55
- **D5**: `dispatch.py` — moved to GitHub issue #99. Dispatch-layer improvements for parametric ABCs (warn/error on indistinguishable multimethods). Typecheck-layer part resolved.
66

@@ -31,3 +31,34 @@ Next unused item code: D10
3131
**Related**: the `parse_and_bind` Darwin-branch fix in `net/client.py` (2026-04-15) was a prerequisite refactor — `net/client.py` is now in the right shape for the Windows port to plug into. Also, the three-tier hybrid readline fallback pattern documented in `raven.librarian.minichat` and `mcpyrate.repl.macropython` (same session) is directly reusable for `net/client.py` once `net/client.py`'s top-level `import readline` is moved inside the client function and guarded.
3232

3333
(Added 2026-04-15, based on audit + discussion during the Windows-CI expansion session.)
34+
35+
36+
- **D10: Tier 2 REPL tests (subprocess + pty) for `unpythonic.net` client/server**: Tier 1 coverage for `unpythonic.net.client` and `unpythonic.net.server` uses a server-in-thread + in-process client pattern (see `unpythonic/net/tests/`) with scripted input via `builtins.input` monkey-patch and captured stdout/stderr via `io.StringIO`. Fast, single-process, no subprocess boundary needed — the server speaks TCP to `127.0.0.1` and the client loop runs in the same pytest process. **We might never need tier 2.**
37+
38+
A second tier would spawn the server and client as real subprocesses, with each end driven through a pseudo-terminal (`pexpect` / `ptyprocess`), to catch things tier 1 cannot reach:
39+
40+
- Real GNU-readline binding behaviour on the client side — tab completion against the remote completer, history recall, multi-line input rendering.
41+
- Terminal escape sequences from the colorizer on both sides.
42+
- Signal handling — Ctrl+C from the client forwarded to the remote REPL, Ctrl+D disconnecting cleanly.
43+
- The ptyproxy machinery itself, end-to-end. Tier 1 stubs around the pty by running the `InteractiveConsole` directly against in-memory streams; tier 2 would actually exercise `unpythonic.net.ptyproxy.PTYSocketProxy` with a real master/slave pair.
44+
45+
Cost:
46+
- ~0.5–1 s startup per test × two processes per test (client + server) = ~1–2 s per test. Matters for suite size.
47+
- POSIX-only naturally. Windows support depends on D9 (port `unpythonic.net` to MS Windows) landing first — no point designing tier 2 for a subsystem that doesn't run on Windows yet. If/when D9 lands, Windows tier 2 can use the same ConPTY backend that D9 introduces.
48+
- `pexpect` would become a new dev dep. Small but non-zero.
49+
50+
**Rough shape if we ever do it:**
51+
```python
52+
import pexpect
53+
server = pexpect.spawn(f"{sys.executable} -m unpythonic.net.server", ...)
54+
server.expect(r"Listening on \S+")
55+
client = pexpect.spawn(f"{sys.executable} -m unpythonic.net.client", ...)
56+
client.expect(r">>> ")
57+
client.sendline("2 + 3")
58+
client.expect(r"5\s*\n>>> ")
59+
client.sendcontrol("d")
60+
client.expect(pexpect.EOF)
61+
server.terminate()
62+
```
63+
64+
**When to actually do it**: only if tier 1 coverage turns out to miss something important (a regression hits prod that tier 1 would not have caught). The in-thread server + scripted client approach already exercises most of the protocol surface; tier 2 is primarily a safety net for terminal-semantics and signal-path bugs. Until one of those bites, tier 1 is the main win. (Added 2026-04-15, alongside the tier 1 bring-up.)

0 commit comments

Comments
 (0)