Metadata-Version: 2.5
Name: beebium
Version: 0.1.10
Summary: Python client for the Beebium BBC Micro emulator
Project-URL: Homepage, https://github.com/rob-smallshire/beebium
Project-URL: Repository, https://github.com/rob-smallshire/beebium
Author-email: Robert Smallshire <robert@smallshire.org.uk>
License-Expression: GPL-3.0-or-later
License-File: COPYING.txt
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Emulators
Requires-Python: >=3.12
Requires-Dist: grpcio>=1.60.0
Requires-Dist: protobuf>=4.25.0
Requires-Dist: stevedore>=5.0.0
Provides-Extra: discovery
Requires-Dist: zeroconf>=0.131.0; extra == 'discovery'
Provides-Extra: imaging
Requires-Dist: pillow>=10.0.0; extra == 'imaging'
Description-Content-Type: text/markdown

<!-- Generated by scripts/generate_readme.py from readme/README.md.j2 and
     the tested snippets in readme/snippets/. Do not edit this file directly:
     edit the template or a snippet and run scripts/generate_readme.py.
     See CONTRIBUTING.md. -->
# Beebium Python Client

## What is Beebium?

Beebium is a headless, cycle-accurate BBC Micro emulator with a client-server
architecture. The emulator runs as a server process -- one per machine variant
(Model B, B+, B+ 128K, B with ROM/RAM board) -- and is driven entirely over
gRPC, so front-ends and automation talk to it across a well-defined protocol
rather than being wired into the emulation core.

## What is the Python client?

`beebium` is the Python client for that protocol: a typed API over the gRPC
services for controlling and automating emulator instances from Python -- type
on the keyboard, read the screen in any display mode, peek and poke memory,
drive the debugger, mount discs, and more. It is built for pytest-based testing
of BBC Micro software: a `bbc` fixture gives each test a fresh machine.

### Relationship to `beebium-server`

`beebium-server` is a separate, **optional** package: platform wheels that carry
the emulator itself -- the server binaries, the ROMs, the presets and the
bundled extensions. Install both and you have a complete, self-contained
headless system:

```bash
pip install beebium beebium-server
```

With `beebium-server` present, `Beebium.launch()` needs no arguments -- it finds
the server and its ROMs in that wheel. Without it, the client works just as well
with a server installed any other way (Homebrew, the `.deb`/`.rpm` packages,
Scoop, or a checkout build) or one already running, reached with
`Beebium.connect()`.

## Installation

With [uv](https://docs.astral.sh/uv/):

```bash
uv add beebium beebium-server        # add to your project
# or, into a plain virtualenv:
uv pip install beebium beebium-server
```

With pip:

```bash
pip install beebium beebium-server
```

`beebium-server` is optional (see above). On an externally-managed system
install into a virtualenv (or use `uv`/`pipx`).

### Extras

```bash
pip install beebium[imaging]     # + Pillow, for saving captured frames as images
pip install beebium[discovery]   # + zeroconf, for discovering servers over mDNS
```

## Usage

Every example below is a real test that runs against the `beebium-server` wheel
(see `readme/snippets/`), so the code here is the code that runs.

### Launch a server

The flagship path: with `beebium-server` installed, `launch()` takes no
arguments and stops the server again when the block exits.

```python
from beebium.client import Beebium

# With the beebium-server package installed, launch() needs no arguments:
# the emulator binary and its ROMs come from that wheel, and the server is
# stopped again when the block exits.
with Beebium.launch() as bbc:
    bbc.expect("BASIC")            # wait for the boot banner / BASIC prompt
    bbc.keyboard.type("PRINT 2+2")
    bbc.keyboard.press_return()
    print(bbc.expect("4"))         # -> 4
```

### Connect to a running server

```python
from beebium.client import Beebium

# Connect to a server that is already running. The target defaults to
# localhost on port 48875 (0xBEEB); pass "host:port" to reach another.
with Beebium.connect() as bbc:
    bbc.debugger.stop()
    print(f"PC = 0x{bbc.cpu.pc:04X}")
```

### Choose a variant or a specific server

```python
from beebium.client import Beebium

# Pick a machine variant: "model-b" (default), "model-b-plus",
# "model-b-plus-128k" or "model-b-romram". To run a specific install
# instead of the default search, pass server="/path/to/beebium" (a binary
# or an install root), or set the BEEBIUM_SERVER environment variable.
with Beebium.launch(variant="model-b-plus") as bbc:
    bbc.expect("BASIC")
```

### Type on the keyboard

Given a launched or connected `bbc`:

```python
bbc.keyboard.type("PRINT 2+2")     # type text, shifting as needed
bbc.keyboard.press_return()

bbc.keyboard.key_down("A")         # or drive individual keys
bbc.keyboard.key_up("A")
```

### Read the screen

`bbc.video.screen_text()` reads the displayed text in any mode. For MODE 7
(teletext) work, `beebium.client.screen` adds helpers -- `read_mode7_screen`,
`screen_contains`, `find`, `dump_screen` -- that correct for hardware scrolling.

```python
# Read the text the machine is displaying, whatever the screen mode.
text = bbc.video.screen_text().text

# Wait (up to a timeout) for text to appear -- pexpect-style automation.
bbc.expect("BASIC")
```

### Read and write memory

```python
# Side-effect-free peek -- safe even for I/O registers.
via_flags = bbc.memory.address.peek[0xFE4D]        # System VIA IFR
zero_page = bbc.memory.address.peek[0x0000:0x0100]

# Follow a 6502 vector (16-bit little-endian).
wrchv = bbc.memory.address.peek.word(0x020E)       # the OSWRCH vector

# Bus access reads and writes through the memory bus, like real hardware.
bbc.memory.address.bus[0x1900] = 0x42
value = bbc.memory.address.bus[0x1900]
```

### Drive the debugger

```python
state = bbc.debugger.stop()            # pause; returns the execution state
print(state.is_running)                # -> False
print(bbc.cpu.registers)               # A=.. X=.. Y=.. SP=.. PC=.. P=.. [flags]

# Break the next time the OS writes a character, then let it run. The
# breakpoint is removed automatically when the block exits.
with bbc.debugger.breakpoint(0xFFEE):  # OSWRCH entry point
    bbc.keyboard.type("X")             # the echoed key drives OSWRCH
    bbc.debugger.run_and_wait_for_stop()
    print(f"stopped at PC=0x{bbc.cpu.pc:04X}")
```

### Testing with pytest

Installing `beebium` registers the pytest plugin, so the `bbc` fixture is
available with no extra configuration:

```python
# The beebium pytest plugin registers a `bbc` fixture: a fresh BBC Micro,
# launched and torn down per test. Install beebium and it is available with no
# conftest wiring.
def test_print(bbc):
    bbc.expect("BASIC")
    bbc.keyboard.type("PRINT 2+2")
    bbc.keyboard.press_return()
    assert bbc.expect("4") == "4"
```

Companion fixtures: `bbc_shared` (one machine per module), `stopped_bbc` (starts
paused), and the session-scoped `mos_filepath` / `basic_filepath`. Point the
plugin at a server or ROMs with `--beebium-server` / `--beebium-rom-dir` (or the
`BEEBIUM_SERVER` / `BEEBIUM_ROM_DIR` environment variables).

### Further reading

Fuller documentation and runnable programs live in the repository: see
[`docs/`](https://github.com/rob-smallshire/beebium/tree/master/docs) for the
gRPC service reference and subsystem guides, and
[`examples/`](https://github.com/rob-smallshire/beebium/tree/master/clients/beebium-python-client/examples)
for end-to-end scripts. (Later: links to the published API reference.)

## Contributing

Development happens in the
[Beebium repository](https://github.com/rob-smallshire/beebium). This README is
**generated** -- do not edit `README.md` directly. See
[CONTRIBUTING.md](CONTRIBUTING.md) for the checkout, uv and wheel-test workflow
and for how to edit the README (its template and snippets).

## License

GPL-3.0-or-later. See [COPYING.txt](COPYING.txt).
