Local pytest collects. The host runs tests over DevTools_{Host}_{Version}_{PID} (BridgeMessage). Not DevToolsMcp_*.
Client plugin: sibling RevitDevTool.PyTest. How to write tests: .agents/skills/revit-pytest/SKILL.md.
| Path | Role |
|---|---|
External/Handlers/PytestRequestHandler.cs |
tests/run |
External/Handlers/IpyTestRequestHandler.cs |
ipytests/run |
External/Testing/PytestExecutionService.cs |
in-host PytestRunner.py |
External/Testing/IpyTestExecutionService.cs |
in-host IpyTestDriver.py (pyRevit, else embedded 3.4) |
External/Testing/PytestDependencyService.cs |
PEP 723 via active provider — CPython tests/run only |
External/Testing/PytestContracts.cs |
wire models |
Resources/scripts/PytestRunner.py |
pytest.main(--capture=sys) |
Resources/scripts/IpyTestDriver.py |
unittest, dialect 2.7 ∩ 3.4 |
Resources/scripts/SetupRevit.py / SetupAcad.py |
host builtins |
flowchart LR
Plugin[plugin collect] --> Pipe["DevTools_* pipe"]
Pipe --> CPython["tests/run\nPEP 723 then pytest.main"]
Pipe --> IPy["ipytests/run\nunittest, no pixi"]
CPython --> Plugin
IPy --> Plugin
test_*_ipy.py is pytest routing only. Host unittest does not care about that name. Policy: 0026.
PytestRunner.pymust start withfrom __future__ import annotations.import pytestis inside_run()so a missing package becomes a JSON error; annotations must not evaluatepytestat exec (Python 3.13NameError: name 'pytest' is not defined).- Guard
Suppressfor the whole run. - PEP 723 on CPython
conftest.py/test_*.pyonly — never ontest_*_ipy.py. - Capture: CPython
--capture=sys+ restoreprintontosys.stdout; IPy per-test tee. No session StringIO. - IPy: no f-strings; never assign to the name
print.sys.pathincludes the test dir up to workspace. - Lease + mutex:
host + version + workspace. One pytest process. Mixedtest_*.py+test_*_ipy.pyunder one conftest is fine. --maxfail=Nforwarded verbatim. Local stop is pytest Session. IPy: drivershouldStopin-file, C# loop across files.- Pipe wait: CPython
per_test × N + launch_timeout; IPyper_test × N. - CPython
tests/runuses the samePythonInitializeras scripts (host-attach + uv sidecar; PEP 723 viaPytestDependencyServiceon the active provider). ExecuteAsyncdoes not take the pipe-disconnect token (breakpoint can park later runs).
Same request for both methods: workspace_root, test_root, nodeids, pytest_args. IPy response may set engine to pyrevit or embedded.