Skip to content

9.5: runtime tests for tap.python, in Max - #50

Merged
tap merged 2 commits into
mainfrom
v2/runtime-tests
Oct 10, 2026
Merged

tap merged 2 commits into
mainfrom
v2/runtime-tests

Conversation

@tap

@tap tap commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Plan item 9.5 (docs/TAP-PYTHON-PLAN.md): tap.python tested in a real Max, through the max-test harness. The patchers are generated by make_patchers.py, with the classes they load in runtime-tests/python/.

The tests

  • tap.python.load: the first patcher a fresh Max opens, so Max has to find the object through init/. Checks:

    • with no argument, default.py's bang outputs the gain;
    • euclid's bang outputs its list;
    • an @steps 5 argument applies;
    • scale's numpy array comes out as a list;
    • note_name's two values come out right to left, the name as a symbol.
  • tap.python.outputs: every row of the output table, one method of maxtest_outputs each. The values an outlet can't carry (past 64 bits, a dict, a nested list) are reported and nothing is output.

  • tap.python.messages:

    • an attribute set and read back, and get<attr> from the dumpout;
    • a method called by its message;
    • the anything forwarder, including int and symbol;
    • a class without anything saying it doesn't understand.
  • tap.python.reload:

    • a save that widens a tuple return hint adds an outlet before the dumpout; a patch cord made to it carries its value, and the other outlets keep their cords;
    • narrowing removes that outlet and its cord;
    • a broken save is reported once and outputs nothing until fixed.
  • tap.python.shared: one file used by a tap.python~ and a tap.python, then saved. Both objects follow the save, and each kind reports its own reserved name once: mode for tap.python~, dumpout for tap.python.

  • tap.python.threads: a metro every 5 ms, with every output checked against its input, on three threads:

    • the main thread;
    • the scheduler thread (Overdrive on);
    • the audio thread (Scheduler in Audio Interrupt on, audio running).

    The test puts both settings back as they were.

  • tap.python.faults: sys.exit() and an exception are reported, and the object still answers.

  • The soak gains a tap.python answering a metro every 10 ms while its file is saved and reloaded every second. Every output is checked against its input, and every message must be answered.

The runner

  • Restore Windows: for the run, Max's Restore Windows on Launch is off and its crash-recovery workspaces are moved aside. A reopened window would load the binary before the first test. Max's preference files are put back afterwards.
  • Order: tap.python.load always opens first.
  • init/ check: the package's init/ mapping lines are required before a run starts.
  • Reference page: a warning if anything touches tap.python's hand-written page.

How outputs are checked

  • Test.output_is() turns the output into one symbol with [tosymbol] and holds it in a [zl.reg]. At check time a quoted [sel "…"] compares it.
  • An output that never comes fails the check, because the harness records an assertion that never answers as a failure.
  • The formats are what a probe in Max showed. The README records them: symbol C keeps the word symbol, and floats have four decimals (0.5000).

Verified (macOS, Max 9.1.5)

  • All 21 runtime tests pass, with the load test first.
  • The hour-long soak passes all 18 of its checks (61 minutes). The tap.python answered every message of a 10 ms metro correctly for the whole hour, while its file was saved and reloaded every second.
    • Max's memory: 658 MB a minute in, 663 MB at the end, peaking at 675 MB.
    • The file ran 3,601 times.
    • Python's object count stayed between 18,700 and 22,000 throughout.

🤖 Generated with Claude Code

https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz

tap and others added 2 commits October 10, 2026 09:25
Seven test patchers, generated by make_patchers.py with fixtures in runtime-tests/python/:
- tap.python.load, the first patcher a fresh Max opens: Max finds the object through init/; with no
  argument default.py's bang outputs the gain; euclid's list, an @Attribute argument applied, scale's
  array as a list, note_name's two values right to left, the name as a symbol;
- tap.python.outputs: every row of the output table, one method of maxtest_outputs each — what
  cannot be output (past 64 bits, a dict, a nested list) reported and nothing output;
- tap.python.messages: an attribute set and read back, get<attr> from the dumpout, a method, the
  anything forwarder (int and symbol included), a class without anything not understanding;
- tap.python.reload: a save that widens a tuple return hint adds an outlet before the dumpout, which
  takes a cord and carries its value while the others keep theirs; narrowing removes it with its
  cord; a broken save is reported once and outputs nothing until fixed;
- tap.python.shared: one file for a tap.python~ and a tap.python, saved: both follow, and each kind
  says once what it owes (mode reserved by one, dumpout by the other);
- tap.python.threads: a metro every 5 ms, every output checked against its input, on the main
  thread, the scheduler thread (Overdrive) and the audio thread (Scheduler in Audio Interrupt);
  Overdrive and Audio Interrupt put back as they were;
- tap.python.faults: sys.exit() and an exception reported, the object still answering.

The soak gains a tap.python answering a metro every 10 ms while its file is saved and reloaded
every second: every output against its input, every message answered.

run.py: Restore Windows on Launch off for the run and Max's crash-recovery workspaces aside, its
preference files put back afterwards; tap.python.load opened first, so that init/ must find it;
the package's init/ lines required before a run; a warning if anything touches tap.python's
hand-written reference page. Checks are as [tosymbol] writes an output (Test.output_is()), held in a
[zl.reg]: a missing output fails, as the harness records an assertion that never answers.

All 21 runtime tests pass in Max 9.1.5 on macOS, the load test first; a one-minute soak passes with
the new checks.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019rVV9SkjkWmiBXFMT4whkz
@tap
tap merged commit 43da626 into main Oct 10, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant