Honor `TRACTOR_LOGLEVEL`+`TRACTOR_SPAWN_METHOD` env-vars
Add env-var overrides inside `._root.open_root_actor()` so devs/test-runs can swap the actor-spawn backend or crank console verbosity *without* touching application code. In `._root.open_root_actor()`, - read `TRACTOR_LOGLEVEL` early, overriding any caller-passed `loglevel` and stashing an `env_ll_report` to emit once the console log is set up. - pull the `loglevel` fallback (`or _default_loglevel`) and `log.get_console_log()` init *up* so the env-var report routes through tractor's own logger. - read `TRACTOR_SPAWN_METHOD`, overriding any caller-passed `start_method` and warn-logging when the env-var clobbers an explicit caller value. Wire the same vars through `tests/devx/conftest.py::spawn`, - request the `loglevel` fixture, set both `TRACTOR_LOGLEVEL` and `TRACTOR_SPAWN_METHOD` in `os.environ` before each `pexpect.spawn()` (inherited by the example subproc). - expand `supported_spawners` to include `main_thread_forkserver` and `subint_forkserver` bc example scripts no longer need per-script CLI plumbing. - pop both vars in fixture teardown so a leaked value can't re-route a later in-process tractor test's spawn-backend or loglevel. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-codesubint_forkserver_backend
parent
22cdf15b73
commit
208e7c0926
|
|
@ -56,6 +56,7 @@ type PexpectSpawner = Callable[
|
|||
@pytest.fixture
|
||||
def spawn(
|
||||
start_method: str,
|
||||
loglevel: str,
|
||||
testdir: pytest.Pytester,
|
||||
reg_addr: tuple[str, int],
|
||||
|
||||
|
|
@ -67,11 +68,12 @@ def spawn(
|
|||
'''
|
||||
supported_spawners: set[str] = {
|
||||
'trio',
|
||||
# ?TODO, other spawners that will work?
|
||||
# - [ ] need to pass `start_method={spawner}` to underlying
|
||||
# `examples/debugging/<script>.py` somehow?
|
||||
# 'main_thread_forkserver',
|
||||
# 'subint_forkserver',
|
||||
# `examples/debugging/<script>.py` picks up the spawn
|
||||
# backend via the `TRACTOR_SPAWN_METHOD` env-var which
|
||||
# is honored inside `tractor._root.open_root_actor()`,
|
||||
# so no per-script edits are required.
|
||||
'main_thread_forkserver',
|
||||
'subint_forkserver',
|
||||
}
|
||||
if start_method not in supported_spawners:
|
||||
pytest.skip(
|
||||
|
|
@ -94,6 +96,32 @@ def spawn(
|
|||
# disable all ANSI color output
|
||||
# os.environ['NO_COLOR'] = '1'
|
||||
|
||||
def set_spawn_method():
|
||||
'''
|
||||
Drive the actor-spawn backend inside the spawned
|
||||
`examples/debugging/<script>.py` subproc via env-var
|
||||
(consumed by `tractor._root.open_root_actor()`),
|
||||
without requiring per-script CLI plumbing.
|
||||
|
||||
'''
|
||||
import os
|
||||
os.environ['TRACTOR_SPAWN_METHOD'] = start_method
|
||||
|
||||
def set_loglevel():
|
||||
'''
|
||||
Forward the test-suite parametrized `loglevel` into the
|
||||
spawned `examples/debugging/<script>.py` subproc via
|
||||
env-var (consumed by `tractor._root.open_root_actor()`),
|
||||
so console verbosity can be cranked or silenced from
|
||||
the test harness without per-script edits.
|
||||
|
||||
'''
|
||||
import os
|
||||
if loglevel:
|
||||
os.environ['TRACTOR_LOGLEVEL'] = loglevel
|
||||
else:
|
||||
os.environ.pop('TRACTOR_LOGLEVEL', None)
|
||||
|
||||
spawned: PexpectSpawner|None = None
|
||||
|
||||
def _spawn(
|
||||
|
|
@ -103,6 +131,8 @@ def spawn(
|
|||
) -> pty_spawn.spawn:
|
||||
nonlocal spawned
|
||||
unset_colors()
|
||||
set_spawn_method()
|
||||
set_loglevel()
|
||||
spawned = testdir.spawn(
|
||||
cmd=mk_cmd(
|
||||
cmd,
|
||||
|
|
@ -146,6 +176,16 @@ def spawn(
|
|||
if ptyproc.isalive():
|
||||
ptyproc.kill(signal.SIGKILL)
|
||||
|
||||
# Scope our env-var mutations to this single fixture
|
||||
# invocation — both `TRACTOR_SPAWN_METHOD` and
|
||||
# `TRACTOR_LOGLEVEL` are honored by
|
||||
# `tractor._root.open_root_actor()` so leaking them past
|
||||
# this test could inadvertently re-route a later
|
||||
# in-process tractor test's spawn-backend / loglevel.
|
||||
import os
|
||||
os.environ.pop('TRACTOR_SPAWN_METHOD', None)
|
||||
os.environ.pop('TRACTOR_LOGLEVEL', None)
|
||||
|
||||
# TODO? ensure we've cleaned up any UDS-paths?
|
||||
# breakpoint()
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,7 @@ async def open_root_actor(
|
|||
f'_registry_addrs: {registry_addrs!r}\n'
|
||||
)
|
||||
|
||||
# debug.mk_pdb().set_trace()
|
||||
async with maybe_block_bp(
|
||||
debug_mode=debug_mode,
|
||||
maybe_enable_greenback=maybe_enable_greenback,
|
||||
|
|
@ -284,6 +285,75 @@ async def open_root_actor(
|
|||
)
|
||||
enable_modules.extend(rpc_module_paths)
|
||||
|
||||
# `TRACTOR_LOGLEVEL` env-var wins over any caller-passed
|
||||
# `loglevel` so devs/test-runs can crank (or silence)
|
||||
# console verbosity without touching application code.
|
||||
env_ll_report: str = ''
|
||||
if env_ll := os.environ.get('TRACTOR_LOGLEVEL'):
|
||||
loglevel = env_ll
|
||||
env_ll_report: str = (
|
||||
f'Detected env-var setting,\n'
|
||||
f'TRACTOR_LOGLEVEL={env_ll!r}\n'
|
||||
f'\n'
|
||||
f'Setting console loglevel per,\n'
|
||||
f'loglevel={loglevel!r}\n'
|
||||
)
|
||||
if (
|
||||
loglevel
|
||||
and
|
||||
loglevel.upper() != env_ll.upper()
|
||||
):
|
||||
env_ll_report += (
|
||||
f'\n'
|
||||
f'NOTE env-var OVERRIDES caller-passed,\n'
|
||||
f'loglevel={loglevel!r}\n'
|
||||
)
|
||||
|
||||
loglevel: str = (
|
||||
loglevel
|
||||
or
|
||||
log._default_loglevel
|
||||
)
|
||||
loglevel: str = loglevel.upper()
|
||||
|
||||
assert loglevel
|
||||
_log = log.get_console_log(
|
||||
level=loglevel,
|
||||
name='tractor',
|
||||
logger=logger,
|
||||
)
|
||||
assert _log
|
||||
if env_ll_report:
|
||||
_log.info(env_ll_report)
|
||||
|
||||
# `TRACTOR_SPAWN_METHOD` env-var wins over any caller-passed
|
||||
# `start_method` so devs/test-runs can swap the actor spawn
|
||||
# backend without touching application code (e.g. driving
|
||||
# the `examples/debugging/<script>.py` suite under each
|
||||
# backend from `tests/devx/conftest.py::spawn`).
|
||||
if env_sm := os.environ.get('TRACTOR_SPAWN_METHOD'):
|
||||
start_method: str = env_sm
|
||||
env_sm_report: str = (
|
||||
f'Detected env-var setting,\n'
|
||||
f'TRACTOR_SPAWN_METHOD={env_sm!r}\n'
|
||||
f'\n'
|
||||
f'Setting spawn backend as,\n'
|
||||
f'start_method={env_sm!r}\n'
|
||||
)
|
||||
if (
|
||||
start_method
|
||||
and
|
||||
start_method != env_sm
|
||||
):
|
||||
_log.warning(
|
||||
env_sm_report
|
||||
+
|
||||
f'NOTE env-var OVERRIDES caller-passed,\n'
|
||||
f'`start_method={start_method!r}`\n'
|
||||
)
|
||||
else:
|
||||
_log.info(env_sm_report)
|
||||
|
||||
if start_method is not None:
|
||||
_spawn.try_set_start_method(start_method)
|
||||
|
||||
|
|
@ -300,12 +370,6 @@ async def open_root_actor(
|
|||
wrap_address(uw_addr)
|
||||
for uw_addr in uw_reg_addrs
|
||||
]
|
||||
loglevel: str = (
|
||||
loglevel
|
||||
or
|
||||
log._default_loglevel
|
||||
)
|
||||
loglevel: str = loglevel.upper()
|
||||
|
||||
# Debug-mode is currently only supported for backends whose
|
||||
# subactor root runtime is trio-native (so `tractor.devx.
|
||||
|
|
@ -341,13 +405,6 @@ async def open_root_actor(
|
|||
f'{_spawn._spawn_method!r}.'
|
||||
)
|
||||
|
||||
assert loglevel
|
||||
_log = log.get_console_log(
|
||||
level=loglevel,
|
||||
name='tractor',
|
||||
)
|
||||
assert _log
|
||||
|
||||
# TODO: factor this into `.devx._stackscope`!!
|
||||
if (
|
||||
debug_mode
|
||||
|
|
|
|||
Loading…
Reference in New Issue