Skip to main content

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:

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:

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

With pip:

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

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.

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

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

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:

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.

# 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

# 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

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:

# 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"

bbc is a bare Model B. To configure it, override the beebium_preset fixture (or beebium_extra_args, for extra server arguments) in a conftest.py:

# In conftest.py: every `bbc` in scope boots this preset (an id from
# `list-presets`, or a preset file path) -- here a Model B with a disc system.
import pytest


@pytest.fixture(scope="session")
def beebium_preset():
    return "model-b-disc"


def test_has_a_disc_filing_system(bbc):
    bbc.expect("BASIC")
    bbc.keyboard.type("*HELP")
    bbc.keyboard.press_return()
    bbc.expect("DFS")

A project-wide default can also come from --beebium-preset or a beebium_preset ini key; a fixture override takes precedence over both. When a test needs more than one machine, or a machine configured on the spot, use the launch_bbc factory the other fixtures are built on:

# launch_bbc launches machines on demand -- any variant, any preset, as many
# as a test needs -- and tears every one of them down when the test ends.
def test_same_program_on_two_machines(launch_bbc):
    model_b = launch_bbc(preset="model-b-disc")
    b_plus = launch_bbc(variant="model-b-plus")
    for bbc in (model_b, b_plus):
        bbc.expect("BASIC")
        bbc.keyboard.type("PRINT 6*7")
        bbc.keyboard.press_return()
        assert bbc.expect("42") == "42"

Companion fixtures: bbc_shared (one machine per module, configured like bbc), stopped_bbc (starts paused), bbc_tube (a 65C02 second processor), 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/ for the gRPC service reference and subsystem guides, and examples/ for end-to-end scripts. (Later: links to the published API reference.)

Contributing

Development happens in the Beebium repository. This README is generated -- do not edit README.md directly. See 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.

Metadata

Release files for beebium 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for beebium 0.6.0
File Size Uploaded
beebium-0.6.0.tar.gz 507.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for beebium 0.6.0
File Interpreter ABI Platform
beebium-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 935.7 kB

Release files / beebium-0.6.0.tar.gz

Download URL beebium-0.6.0.tar.gz
Size 507.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e0af29b6178ad657b8a165b9adaa1494a1dcf62301908df5d09cd1a23f0dd4bf
BLAKE2b-256 checksum
How to use checksums
bcd14e709a6040003551f52dc719ebf8904fc3c142f025e12974a20bfc4b6d58
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / beebium-0.6.0-py3-none-any.whl

Download URL beebium-0.6.0-py3-none-any.whl
Size 427.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f313c141c2cf38c2543873597eaca656605839ae4f8a47ec508c8126db454839
BLAKE2b-256 checksum
How to use checksums
43c1b1e227c147e383d8cce7204871a816933963125bd2fd0f9cf7b7cadded76
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.1

2 release files

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.17

2 release files

0.1.16

2 release files

0.1.15

2 release files

0.1.14

2 release files

0.1.13

2 release files

0.1.12

2 release files

0.1.11

2 release files

0.1.10

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page