Skip to content

Commit 1fe8fc6

Browse files
committed
Engines(refactor[mock]): Rename ConcreteEngine to MockEngine
why: "Concrete" named the in-memory simulator engine, but every real engine (subprocess, control_mode, imsg) is equally a concrete implementation. Across the Python/Rust ecosystem "Concrete*" is a test-only convention for "a minimal instantiable ABC subclass", the opposite of this docs/doctest workhorse, and the word already carries its id/type sense throughout ops/query/objects. "Mock" names the engine by its role: the no-tmux, in-memory stand-in. what: - Rename ConcreteEngine -> MockEngine and AsyncConcreteEngine -> AsyncMockEngine; module concrete.py -> mock.py - EngineKind.CONCRETE ("concrete") -> EngineKind.MOCK ("mock"); EngineSpec.concrete() -> EngineSpec.mock(); registry key becomes "mock" (available_engines() re-sorts accordingly) - Rename the benchmark engine key/label; update RESULTS.md and grid.json to match - Keep docstrings describing the in-memory simulation so the name's test-double flavor does not mislead doctest readers - Leave "concrete" untouched where it means a concrete id/target/pane handle (ops, query, objects, workspace)
1 parent aa6d822 commit 1fe8fc6

63 files changed

Lines changed: 291 additions & 295 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/experimental.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ inspect ``ok``/``status``, or opt into raising with ``raise_for_status()``:
2525
```python
2626
>>> from libtmux.experimental.ops import HasSession, run
2727
>>> from libtmux.experimental.ops._types import SessionId
28-
>>> from libtmux.experimental.engines import ConcreteEngine
29-
>>> result = run(HasSession(target=SessionId("$0")), ConcreteEngine())
28+
>>> from libtmux.experimental.engines import MockEngine
29+
>>> result = run(HasSession(target=SessionId("$0")), MockEngine())
3030
>>> result.ok
3131
True
3232
>>> result.raise_for_status() is result
@@ -46,12 +46,12 @@ only *how* and *where* the command runs.
4646
| Engine | Transport | Use it for |
4747
| --- | --- | --- |
4848
| ``SubprocessEngine`` | one ``tmux`` process per command | the classic path; reproduces today's libtmux behavior |
49-
| ``ConcreteEngine`` | in-memory, no tmux | tests and dry runs (deterministic, fabricated output) |
49+
| ``MockEngine`` | in-memory, no tmux | tests and dry runs (deterministic, fabricated output) |
5050
| ``ControlModeEngine`` | a persistent ``tmux -C`` connection | many commands over one long-lived session |
5151
| ``ImsgEngine`` | tmux's native binary peer protocol | an opt-in easter egg |
5252

5353
Each has an ``Async*`` counterpart (``AsyncSubprocessEngine``,
54-
``AsyncConcreteEngine``, ``AsyncControlModeEngine``) behind ``AsyncTmuxEngine``.
54+
``AsyncMockEngine``, ``AsyncControlModeEngine``) behind ``AsyncTmuxEngine``.
5555
Construct one directly, bind it to a live server with
5656
``SubprocessEngine.for_server(server)``, or select one by name from the engine
5757
registry:
@@ -61,8 +61,8 @@ registry:
6161
>>> from libtmux.experimental.ops import HasSession, run
6262
>>> from libtmux.experimental.ops._types import SessionId
6363
>>> available_engines()
64-
('concrete', 'control_mode', 'imsg', 'subprocess')
65-
>>> engine = create_engine("concrete")
64+
('control_mode', 'imsg', 'mock', 'subprocess')
65+
>>> engine = create_engine("mock")
6666
>>> run(HasSession(target=SessionId("$0")), engine).status
6767
'complete'
6868
```
@@ -77,11 +77,11 @@ later operation can target something that does not exist yet. ``execute``
7777
```python
7878
>>> from libtmux.experimental.ops import LazyPlan, SplitWindow, SendKeys
7979
>>> from libtmux.experimental.ops._types import WindowId
80-
>>> from libtmux.experimental.engines import ConcreteEngine
80+
>>> from libtmux.experimental.engines import MockEngine
8181
>>> plan = LazyPlan()
8282
>>> pane = plan.add(SplitWindow(target=WindowId("@1")))
8383
>>> _ = plan.add(SendKeys(target=pane, keys="echo hi", enter=True))
84-
>>> outcome = plan.execute(ConcreteEngine())
84+
>>> outcome = plan.execute(MockEngine())
8585
>>> outcome.ok
8686
True
8787
>>> [r.status for r in outcome.results]
@@ -107,11 +107,11 @@ many times tmux is invoked:
107107
```python
108108
>>> from libtmux.experimental.ops import LazyPlan, SplitWindow, SendKeys, FoldingPlanner
109109
>>> from libtmux.experimental.ops._types import WindowId
110-
>>> from libtmux.experimental.engines import ConcreteEngine
110+
>>> from libtmux.experimental.engines import MockEngine
111111
>>> plan = LazyPlan()
112112
>>> pane = plan.add(SplitWindow(target=WindowId("@1")))
113113
>>> _ = plan.add(SendKeys(target=pane, keys="echo hi", enter=True))
114-
>>> plan.execute(ConcreteEngine(), planner=FoldingPlanner()).ok
114+
>>> plan.execute(MockEngine(), planner=FoldingPlanner()).ok
115115
True
116116
```
117117

@@ -125,11 +125,11 @@ description into a few dispatches (its async twin is ``arun``):
125125

126126
```python
127127
>>> from libtmux.experimental.fluent import plan
128-
>>> from libtmux.experimental.engines import ConcreteEngine
128+
>>> from libtmux.experimental.engines import MockEngine
129129
>>> p = plan()
130130
>>> pane = p.new_session("dev").window().pane()
131131
>>> _ = pane.do(lambda c: c.send_keys("vim")).split().do(lambda c: c.send_keys("htop"))
132-
>>> p.run(ConcreteEngine()).ok
132+
>>> p.run(MockEngine()).ok
133133
True
134134
```
135135

@@ -147,10 +147,10 @@ duplicating it:
147147

148148
```python
149149
>>> from libtmux.experimental.fluent import plan
150-
>>> from libtmux.experimental.engines import ConcreteEngine
150+
>>> from libtmux.experimental.engines import MockEngine
151151
>>> p = plan()
152152
>>> _ = p.find_or_create_session("dev").window().pane()
153-
>>> p.run(ConcreteEngine()).ok
153+
>>> p.run(MockEngine()).ok
154154
True
155155
```
156156

scripts/bench-results/RESULTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Shape = `windows x panes-per-window`. Structural builds (no shell-readiness wait
2424
| builder / imsg | 20.6 | 31.1 | 62.6 | 153.4 | 262.0 (13x) |
2525
| builder / control_mode | 2.5 | 9.4 | 26.5 | 103.3 | 166.7 (21x) |
2626
| **pipelined (prototype)** | **1.4** | **7.9** | **20.2** | **65.3** | **115.7 (30x)** |
27-
| concrete (offline, in-memory) | 0.1 | 0.1 | 0.3 | 1.3 | 1.5 |
27+
| mock (offline, in-memory) | 0.1 | 0.1 | 0.3 | 1.3 | 1.5 |
2828

2929
Full percentiles at 8x4 (ms):
3030

@@ -35,7 +35,7 @@ Full percentiles at 8x4 (ms):
3535
| imsg | 222 | 283 | 262 | 342 | 421 | 455 | 455 |
3636
| control_mode | 118 | 180 | 167 | 215 | 216 | 398 | 398 |
3737
| pipelined | 97 | 123 | 116 | 156 | 165 | 194 | 194 |
38-
| concrete | 1 | 2 | 2 | 2 | 2 | 2 | 2 |
38+
| mock | 1 | 2 | 2 | 2 | 2 | 2 | 2 |
3939

4040
Reads:
4141

@@ -46,7 +46,7 @@ Reads:
4646
- **pipelined** (prototype: batch independent creates into ~3 `run_batch`
4747
round-trips instead of ~34) is fastest overall, ~1.4x over control_mode. Not
4848
the 11x the round-trip count implies, because the build is **tmux-server-bound**
49-
(one shell fork per pane), not round-trip-bound. `concrete` (offline, 1.5 ms)
49+
(one shell fork per pane), not round-trip-bound. `mock` (offline, 1.5 ms)
5050
is the Python floor: the plan/compile layer is negligible; the time is tmux.
5151

5252
## With vs without shell-readiness wait

scripts/bench-results/grid.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@
144144
"max_ms": 37.03230095561594
145145
},
146146
{
147-
"engine": "concrete",
147+
"engine": "mock",
148148
"shape": "1x1",
149149
"panes": 1,
150150
"wait": false,
@@ -360,7 +360,7 @@
360360
"max_ms": 44.18608907144517
361361
},
362362
{
363-
"engine": "concrete",
363+
"engine": "mock",
364364
"shape": "1x4",
365365
"panes": 4,
366366
"wait": false,
@@ -576,7 +576,7 @@
576576
"max_ms": 78.33038899116218
577577
},
578578
{
579-
"engine": "concrete",
579+
"engine": "mock",
580580
"shape": "3x3",
581581
"panes": 9,
582582
"wait": false,
@@ -792,7 +792,7 @@
792792
"max_ms": 260.35256509203464
793793
},
794794
{
795-
"engine": "concrete",
795+
"engine": "mock",
796796
"shape": "5x4",
797797
"panes": 20,
798798
"wait": false,
@@ -1008,7 +1008,7 @@
10081008
"max_ms": 454.6383459819481
10091009
},
10101010
{
1011-
"engine": "concrete",
1011+
"engine": "mock",
10121012
"shape": "8x4",
10131013
"panes": 32,
10141014
"wait": false,

scripts/bench_engines.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
subprocess builder on SubprocessEngine (one tmux fork per op)
3030
control_mode builder on ControlModeEngine (one persistent ``tmux -C``)
3131
imsg builder on ImsgEngine (AF_UNIX imsg, socket-injected)
32-
concrete builder on ConcreteEngine (offline, in-memory: Python floor)
32+
mock builder on MockEngine (offline, in-memory: Python floor)
3333
pipelined prototype: batch independent creates via run_batch (control_mode)
3434
3535
Timing (``run`` = in-process build-only, the clean signal; ``--hyperfine`` also
@@ -71,9 +71,9 @@
7171
import typer
7272

7373
from libtmux.experimental.engines import (
74-
ConcreteEngine,
7574
ControlModeEngine,
7675
ImsgEngine,
76+
MockEngine,
7777
SubprocessEngine,
7878
)
7979
from libtmux.experimental.engines.base import CommandRequest
@@ -230,9 +230,7 @@ class Impl:
230230
"control_mode", "builder", lambda s: ControlModeEngine.for_server(s)
231231
),
232232
"imsg": Impl("imsg", "builder", lambda s: ImsgForServer(s), needs_preboot=True),
233-
"concrete": Impl(
234-
"concrete", "offline", lambda s: ConcreteEngine(), preflight=False
235-
),
233+
"mock": Impl("mock", "offline", lambda s: MockEngine(), preflight=False),
236234
"pipelined": Impl(
237235
"pipelined", "pipelined", lambda s: ControlModeEngine.for_server(s)
238236
),
@@ -353,7 +351,7 @@ def summarize(samples: list[float]) -> dict[str, float]:
353351
def run(
354352
shapes: str = typer.Option("1x1,1x4,3x3,5x4,8x4", help="comma WxP shapes"),
355353
engines: str = typer.Option(
356-
"classic,subprocess,control_mode,imsg,concrete,pipelined",
354+
"classic,subprocess,control_mode,imsg,mock,pipelined",
357355
help="comma engine names",
358356
),
359357
wait: bool = typer.Option(False, help="ALSO measure with shell-readiness wait"),

src/libtmux/experimental/engines/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
An *engine* executes a rendered tmux command and returns a structured result.
44
Engines are interchangeable behind the :class:`~.base.TmuxEngine` /
55
:class:`~.base.AsyncTmuxEngine` protocols, so the same typed operation can run
6-
through a subprocess (classic), an in-memory simulator (concrete), a persistent
6+
through a subprocess (classic), an in-memory simulator (mock), a persistent
77
``tmux -C`` control connection, an async transport, or (as an easter egg) tmux's
88
native binary peer protocol -- and return the *same* typed result.
99
@@ -26,13 +26,13 @@
2626
SupportsTmuxVersion,
2727
TmuxEngine,
2828
)
29-
from libtmux.experimental.engines.concrete import AsyncConcreteEngine, ConcreteEngine
3029
from libtmux.experimental.engines.control_mode import (
3130
ControlModeEngine,
3231
ControlModeError,
3332
ControlModeParser,
3433
)
3534
from libtmux.experimental.engines.imsg import ImsgEngine
35+
from libtmux.experimental.engines.mock import AsyncMockEngine, MockEngine
3636
from libtmux.experimental.engines.registry import (
3737
available_engines,
3838
create_engine,
@@ -41,20 +41,20 @@
4141
from libtmux.experimental.engines.subprocess import SubprocessEngine
4242

4343
__all__ = (
44-
"AsyncConcreteEngine",
4544
"AsyncControlModeEngine",
45+
"AsyncMockEngine",
4646
"AsyncSubprocessEngine",
4747
"AsyncTmuxEngine",
4848
"CommandRequest",
4949
"CommandResult",
50-
"ConcreteEngine",
5150
"ControlModeEngine",
5251
"ControlModeError",
5352
"ControlModeParser",
5453
"ControlNotification",
5554
"EngineKind",
5655
"EngineSpec",
5756
"ImsgEngine",
57+
"MockEngine",
5858
"SubprocessEngine",
5959
"SupportsTmuxVersion",
6060
"TmuxEngine",

src/libtmux/experimental/engines/base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class EngineKind(str, enum.Enum):
100100
"""Named engine families."""
101101

102102
SUBPROCESS = "subprocess"
103-
CONCRETE = "concrete"
103+
MOCK = "mock"
104104
CONTROL_MODE = "control_mode"
105105
IMSG = "imsg"
106106

@@ -139,9 +139,9 @@ def subprocess(cls, *, protocol_version: int | None = None) -> EngineSpec:
139139
return cls(kind=EngineKind.SUBPROCESS, protocol_version=protocol_version)
140140

141141
@classmethod
142-
def concrete(cls) -> EngineSpec:
143-
"""Build a concrete (in-memory) engine spec."""
144-
return cls(kind=EngineKind.CONCRETE)
142+
def mock(cls) -> EngineSpec:
143+
"""Build a mock (in-memory) engine spec."""
144+
return cls(kind=EngineKind.MOCK)
145145

146146
@classmethod
147147
def control_mode(cls) -> EngineSpec:

src/libtmux/experimental/engines/concrete.py renamed to src/libtmux/experimental/engines/mock.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
"""Deterministic, in-memory engines for tests and docs (no tmux server).
22
3-
The concrete engines simulate just enough tmux behaviour to exercise the
3+
The mock engines simulate just enough tmux behaviour to exercise the
44
operation contract offline: creation commands that ask for an id
55
(``-P -F '#{pane_id}'``) get a fabricated, monotonic id, ``capture-pane`` returns
66
canned lines, and everything else succeeds with empty output. A sync
7-
(:class:`ConcreteEngine`) and async (:class:`AsyncConcreteEngine`) variant share
7+
(:class:`MockEngine`) and async (:class:`AsyncMockEngine`) variant share
88
the same simulation, so the same operation returns the same typed result through
99
either, with no tmux required.
1010
"""
@@ -65,7 +65,7 @@ def _new_counters() -> dict[str, int]:
6565
return {"pane_id": 0, "window_id": 0, "session_id": 0}
6666

6767

68-
class ConcreteEngine:
68+
class MockEngine:
6969
"""Execute operations against an in-memory simulation (synchronous).
7070
7171
Parameters
@@ -84,7 +84,7 @@ class ConcreteEngine:
8484
--------
8585
>>> from libtmux.experimental.ops import SplitWindow, CapturePane, run
8686
>>> from libtmux.experimental.ops._types import WindowId, PaneId
87-
>>> engine = ConcreteEngine(capture_lines=("hello", "world"))
87+
>>> engine = MockEngine(capture_lines=("hello", "world"))
8888
>>> run(SplitWindow(target=WindowId("@1")), engine).new_pane_id
8989
'%1'
9090
>>> run(SplitWindow(target=WindowId("@1")), engine).new_pane_id
@@ -106,16 +106,16 @@ def run_batch(self, requests: Sequence[CommandRequest]) -> list[CommandResult]:
106106
return [self.run(req) for req in requests]
107107

108108

109-
class AsyncConcreteEngine:
110-
"""Async sibling of :class:`ConcreteEngine` for offline async tests/docs.
109+
class AsyncMockEngine:
110+
"""Async sibling of :class:`MockEngine` for offline async tests/docs.
111111
112112
Examples
113113
--------
114114
>>> import asyncio
115115
>>> from libtmux.experimental.ops import SplitWindow, arun
116116
>>> from libtmux.experimental.ops._types import WindowId
117117
>>> async def main():
118-
... return await arun(SplitWindow(target=WindowId("@1")), AsyncConcreteEngine())
118+
... return await arun(SplitWindow(target=WindowId("@1")), AsyncMockEngine())
119119
>>> asyncio.run(main()).new_pane_id
120120
'%1'
121121
"""

src/libtmux/experimental/engines/registry.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
from libtmux import exc
1313
from libtmux.experimental.engines.base import EngineKind
14-
from libtmux.experimental.engines.concrete import ConcreteEngine
1514
from libtmux.experimental.engines.control_mode import ControlModeEngine
15+
from libtmux.experimental.engines.mock import MockEngine
1616
from libtmux.experimental.engines.subprocess import SubprocessEngine
1717

1818
if t.TYPE_CHECKING:
@@ -34,7 +34,7 @@ def available_engines() -> tuple[str, ...]:
3434
Examples
3535
--------
3636
>>> from libtmux.experimental.engines import available_engines
37-
>>> "concrete" in available_engines()
37+
>>> "mock" in available_engines()
3838
True
3939
>>> "subprocess" in available_engines()
4040
True
@@ -48,8 +48,8 @@ def create_engine(name: str | EngineKind, **kwargs: t.Any) -> TmuxEngine:
4848
Examples
4949
--------
5050
>>> from libtmux.experimental.engines import create_engine
51-
>>> create_engine("concrete")
52-
<libtmux.experimental.engines.concrete.ConcreteEngine object at ...>
51+
>>> create_engine("mock")
52+
<libtmux.experimental.engines.mock.MockEngine object at ...>
5353
>>> create_engine("nope")
5454
Traceback (most recent call last):
5555
...
@@ -65,5 +65,5 @@ def create_engine(name: str | EngineKind, **kwargs: t.Any) -> TmuxEngine:
6565

6666

6767
register_engine(EngineKind.SUBPROCESS.value, SubprocessEngine)
68-
register_engine(EngineKind.CONCRETE.value, ConcreteEngine)
68+
register_engine(EngineKind.MOCK.value, MockEngine)
6969
register_engine(EngineKind.CONTROL_MODE.value, ControlModeEngine)

0 commit comments

Comments
 (0)