Collects all four artifacts under <repo>/dist/ (PyInstaller and Flatpak
renamed to testium-<version>(.suff); wheel and AppImage keep PEP 427 /
appimage-builder original names). Re-uses scripts/build_env.sh and
set_env.sh, same venv as run.sh. AppImage build.sh now picks the actual
output file dynamically instead of a hardcoded lowercase name.
Native file dialog routes through the XDG document portal, which exposes
only the selected file at /run/user/UID/doc/... — siblings (param.yaml,
.py) are unreachable. Force Qt's non-native dialog in Flatpak so it walks
the real filesystem via --filesystem=home and returns a usable path.
build.sh runs appimage-builder in a Debian Bookworm container (Podman or
Docker) so it works on Arch / non-Debian hosts. Uses single src/requirements.txt;
TESTIUM_VERSION exported in runtime.env.
org.testium.Testium.yaml uses host Python/Lua only (no bundled interpreter).
build.sh exports a .flatpak bundle. README documents the install procedure.
_testium_launch_cmd() returns the right entry point per mode (AppImage,
Flatpak, PyInstaller, source/wheel). Fixes PermissionError on read-only
__main__.py inside the AppImage squashfs mount.
_which() probes host dirs only in Flatpak (/run/host/usr/bin) and AppImage
(/usr/bin); apply_host_libs prepares env for host subprocesses (prepend host
libs in Flatpak, strip $APPDIR pollution + PYTHONHOME in AppImage); user
override resolved via _which() for bare names.
stdout/stderr of the subprocesses were going to DEVNULL — early-startup
errors (lua require failures, exceptions before stdio_redir kicks in)
were lost.
New helper proc_drain.drain_to_log spawns a daemon thread per pipe that
print()s each line through stdio_redir, so it reaches the log + live
output. Used by py_process and lua_process with [py_func]/[lua_func]
prefixes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
get_testium_version() used pkg_resources (deprecated, slow to import)
and a narrow catch on git.InvalidGitRepositoryError; any other git
exception fell through to the outer except and returned "unknown".
- Use importlib.metadata.version("testium") to read the wheel
version that setuptools bakes from src/VERSION at build time. Works
out of any source checkout — pip-installed copies report
"<x.y> (wheel release)" instead of "unknown".
- Source-checkout path: tried first when prefs.git_supported, broadly
catches Exception so a missing repo / detached worktree / etc. no
longer hides the wheel-metadata fallback.
- PyInstaller path: graceful "unknown (binary release)" if the bundled
VERSION file is unreadable, instead of an unhandled exception.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- README.md: pruned developer-oriented sections (Sphinx setup, Qt
Creator workflow, VSCode debugging, release procedure, AppImage
Wayland note) and replaced them with a user-facing layout: pre-built
releases pointer, quick start, manual install, troubleshooting,
licence.
- CONTRIBUTING.md: absorbed the developer content (debugging in VSCode,
Qt GUI regen, Sphinx build, validation suite — batch + GUI variants,
cross-distrib check, release procedure).
- doc/quick_start.md: 5-minute path from install to a passing test,
in batch mode and in the GUI.
- doc/tutorial.md: guided walk-through against a small calc.py
module — check, py_func, expected_result, $(...) expansion, group,
let, condition, report (with the mkdir reminder), context_id.
- CLAUDE.md: subprocess API contract, bins.py, report-exporter
plugin section, packaging matrix (wheel / PyInstaller / Flatpak /
.deb work-in-progress), refreshed recent-fixes list. README/CLAUDE
validation command no longer carries the spurious "-l" flag (which
is GUI-only and a no-op in batch).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Added some api accessible from python and lua sub_processes. Now the tests only access to py_func.tm instead of direct api.testium module access.
Corrected some f"xxx" to allow working with old python (bookworm).
Changed param.yaml of the test to allow lua to work in all situations.
Various other small fixes for frozen app, wheel.
Tested in all situations, and OK. Ready for tag !
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Drop the now-obsolete src/lib and src/py_func data entries (those
paths no longer exist)
- Add src/testium/py_func and src/testium/runtime as bundle-root data
dirs: the py_func subprocess is launched with the *host* Python
(not the frozen interpreter), so it needs the source files on disk
at cwd=subproc_path() to find py_func/__main__.py and import from
runtime.*
- Hidden imports updated: libs.* → api.*, plus py_func.* explicitly
declared so PyInstaller pulls them into the bundle even though
they are loaded as data
Smoke-tested: built binary runs `testium -b`, py_func subprocess works.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move src/lib/ → src/testium/runtime/ (internal plumbing)
Move src/testium/libs/ → src/testium/api/ (public SDK for test scripts)
Move src/py_func/ → src/testium/py_func/ (Python subprocess)
Move src/lua_func/ → src/testium/lua_func/ (Lua subprocess data)
The package now ships as a single coherent unit instead of four sibling
top-level packages (testium, lib, py_func, lua_func) — pip install
gives a clean site-packages/testium/ with no namespace pollution; .lua
files travel with the wheel via package_data; the wheel installs
cleanly and `testium -b` runs end-to-end including py_func subprocesses
and entry-point exporter plugins.
Naming:
- runtime/ (internal, no API guarantees) clearer than lib/
- api/ (public SDK consumed as `import api.testium as tm`) clearer than libs/
Imports updated en masse: from lib. → from runtime. and from libs. →
from api., plus the importlib.import_module("libs.*") strings in
test_item_console.py and test_item_runtime_plot.py. Test/example
scripts (helper_lib.py, parallel.py, post_execution.py) and the
fake_exporter test suite migrated too.
paths.py: subproc_path() now returns testium_path() — both point at
the testium package directory since the subprocesses live inside.
pyproject.toml: removed exclude=["lua_func", "py_func"] (no longer
needed), added package-data for testium.lua_func/*.lua, removed the
license classifier (PEP 639 conflict with license expression).
Subprocess isolation contract: py_func/ and lua_func/ may only import
runtime/ and their own modules — never interpreter/, main_win/, api/,
or testium/. Enforced by test/validation/items/isolation/ which runs a
py_func that statically scans subprocess source files for forbidden
imports. The contract holds today; the test prevents future drift.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the hardcoded if/elif in Export.exec() with a dict registry.
Built-in formats (text, json, junit, html) are registered as lazy
loaders; missing optional deps (junit_xml, lxml) print a clear message
with a pip install hint instead of raising. Entry-points
(group "testium.exporters") are discovered at import time — installed
plugins are auto-detected with no extra config.
An unknown or unavailable format prints an info line and skips the
export; the test run is not interrupted.
Validation:
- New testium-fake-exporter package under test/validation/fake_exporter/
installed automatically by scripts/build_env.sh on venv creation.
It registers fake_format via entry-points and exports the tests
table to CSV — a real, useful exporter that exercises the plugin
contract end-to-end (entry-point discovery, dispatch, SQLite query).
- New dedicated items/report_plugin/ test exercises both the
unknown-format skip path and the fake_format plugin path, with a
py_func check (file_check.py) on the produced CSV. Runs once per
validation suite.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Merge the two "Recent fixes" sections into one (branches are gone),
add parallel_branch icon, F1 panel, test-tree state, unittest rename,
run item rename, licence. Fix SUCCESS/FAILURE → PASS/FAIL in run item.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add LICENSE (full EUPL-1.2 text + project copyright), CONTRIBUTING.md
with the inbound = outbound rule, and declare the licence in
pyproject.toml and README.md.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reload (re-loading the same .tum file) was rebuilding the GUI tree
from scratch, resetting every checkbox and unfolding everything.
Snapshot the user's selection and fold state via the existing
getCheckList/restoreCheckList and getFoldList/restoreFoldList methods
(already used for session persistence through prefs), so a same-file
reload keeps both as well. A change in the total item count (file
edited between loads) skips the restore.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A parallel branch now displays a single-arrow icon (parallel_branch.png)
distinct from the parallel container's three-arrow icon, making the
tree hierarchy easier to read at a glance.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The 'branches' list shown in the F1 panel previously contained each
branch's full 'steps', duplicating what is already visible in the test
tree. Strip 'steps' inside each branch dict while keeping 'branches'
itself so per-branch attributes (name, wait_for, condition, ...) stay
visible.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The parallel item runs branches concurrently with sync:all or sync:any
policy and optional per-branch wait_for synchronization. Each branch
runs in its own daemon thread and produces a clean per-item entry in
the SQLite report; the live output is prefixed [<branch_name>] so
concurrent branches stay readable.
Supporting changes:
- StdoutProxy (lib/stdout_redirect.py): thread-aware sys.stdout/stderr
with per-thread capture buffers and per-branch live-output prefix.
Adds writeln() for Python 3.14 unittest compatibility.
- TestItemContainer: shared base extracted from Group/Cycle for the
sequential children execution pattern.
- TestItemSleep: interruptible loop polling _is_stopped so sync:any
can cancel slow branches quickly.
- TestReport: thread-safe SQLite (check_same_thread=False + lock).
Also drops the unused -m/--terminal mode and its module.
Validation: 11 scenarios in test/validation/items/parallel covering
sync:all/any, no_fail, wait_for + timeout, conditions, multi-branch,
nested parallel, parallel inside loop, real branch failure.
Documentation: new parallel_test_item.rst added to the manual.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Clarify result semantics (SUCCESS on launch, not on sub-test result),
batch vs GUI mode behaviour, and clean up attribute descriptions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- run item: rename tum_fime→tum, remove stdout=PIPE (deadlock with
spawn), support batch mode (-b), SUCCESS on any completed subprocess
regardless of sub-test result
- batch.py: fix control("loaded") deadlock via daemon thread + Event +
is_alive() polling; fix premature finish on gd_update messages;
propagate success flag from finished message; guard control("close")
- process.py: include success flag in send_finished message
- py_process/lua_process: add stdout/stderr=DEVNULL to Popen
- test_run.py: fix finished detection ("id" in m and m["id"] is None)
- testium_win.py: track run_exit_code, SIGABRT handler, clean exit
- __init__.py: sys.exit with batch success flag
- Add run item validation tests and CLAUDE.md documentation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each dialog test item now accepts an optional auto_result parameter
(ok/cancel/yes/no) and auto_value for text dialogs. When set, the dialog
window opens, stays visible 2 seconds, then closes automatically with the
specified result — allowing the validation suite to run without manual
interaction.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>