flnr API Reference¶
flnr (le flâneur).
Small subprocess supervision harness for CI and automation code.
- run_ex(cmd, *, env=None, cwd=None, merge_std_streams=None, timeouts=None, stdout_monitors=None, stderr_monitors=None, environment_monitors=None, stdin=None, check=True, host_termination=None, tracer=None)¶
Run an external program as a child process and supervise it.
This synchronous entry point blocks the caller until the direct child reaches a resolved final state and output monitoring has finished or timed out, or until supervision fails. The subprocess is executed directly, without invoking a shell.
run_ex()must not be called from an existing async context.The return value is a
ProcessFateobject describing the resolved outcome. Whencheck=True(the default), a non-zero subprocess return code is reported asCommandFailedError. This includes subprocesses terminated by flnr after a run timeout or host-requested termination; inspect the exception’sfatefield to distinguish the cause and final outcome. Monitor failures are reported asMonitorFailedErrorafter process teardown completes. Unrecoverable supervision failures are reported asSupervisionFailedError. If process exit cannot be confirmed during teardown,ProcessKillFailedErroris raised.flnrsupervises the direct child process only. It does not manage the full descendant process tree. Descendants may outlive the direct child, keep inherited file descriptors open, and continue producing output untiloutput_drainexpires.With
merge_std_streams=None, stdout handling receives stdout and, unless stderr handling is configured, stderr too. Configure stderr handling to keep stderr separate. Output handling means either output monitors orflnr.BIND_TO_PARENT. Parent-bound output is passed through instead of monitored. Streams with no output handling are connected toDEVNULL. Explicitmerge_std_streams=Truealways merges stderr into stdout and rejectsstderr_monitors. Explicitmerge_std_streams=Falsekeeps stdout and stderr separate.Child stdin is connected to
DEVNULLby default. Passstdin=flnr.INHERIT_STDINto inherit stdin from the parent process.Pass
tracer=flnr.CommandTracer(logger)to log a shell-oriented command recipe before process creation. Custom tracer objects must implementflnr.CommandTracerProtocolto receive the command to execute, caller cwd, child environment, and host process environment before the child process is created.Noneleaves host-driven termination handling disabled.HostTerminationRequest.HOST_SIGNALSinstalls temporary SIGINT and SIGTERM handlers for the duration of the call. While active,flnrowns those handlers and restores the previous ones when the call returns. This mode is Unix/POSIX-only and is supported only when called from the main Python thread.HostTerminationRequest()attaches the run to a caller-managed, sticky trigger source that may be reused across runs. Attaching to an already-triggered request does not prevent process creation ahead of time; the run observes termination as soon as supervision starts.
- Return type:
- Parameters:
cwd (Path | None)
merge_std_streams (bool | None)
timeouts (ExecutionTimeouts | None)
stdout_monitors (Sequence[OutputMonitor] | BindToParent | None)
stderr_monitors (Sequence[OutputMonitor] | BindToParent | None)
environment_monitors (Sequence[EnvironmentMonitor] | None)
stdin (InheritStdin | None)
check (bool)
host_termination (HostTerminationRequest | _HostSignalsSentinel | None)
tracer (CommandTracerProtocol | None)
Process Fate¶
Public objects that describe subprocess outcome.
- class ProcessTerminationDecision¶
Identify the supervisory decision flnr made while resolving outcome.
This enum describes why flnr decided to intervene, or why no intervention was required. It is not a statement about the intrinsic cause of process exit. For the observed process status, inspect
ProcessFate.returncode. For how flnr carried that decision out, inspectProcessTerminationMethod.- NO_INTERVENTION¶
The process finished before flnr had to enforce any lifecycle action.
- TIMEOUT¶
The configured
runtimeout expired. flnr therefore decided that the process must be stopped.
- EXTERNAL_REQUEST¶
A host termination request was active. flnr therefore decided that the process must be stopped.
- INTERNAL_FAILURE¶
flnr observed an unrecoverable internal failure while supervising the process and therefore decided that the process must be stopped immediately.
Note
This value records flnr’s supervisory decision, not a claim about what the operating system process “really died from”. For example, once the
runtimeout is breached, the decision remainsTIMEOUTeven if the process exits on its own before a requested signal takes effect.
- class ProcessTerminationMethod¶
Identify how flnr enforced process termination.
When flnr decides that a process must be stopped, it resolves a termination method and carries execution through that stage.
This value describes the enforcement path chosen by flnr. It is not a claim about what the process itself observed.
- NONE¶
No enforcement was needed.
- TERMINATE¶
flnr resolved termination through the terminate stage.
- KILL¶
flnr resolved termination through the kill stage.
- class ProcessFate(termination_decision, termination_method, returncode)¶
Represents subprocess outcome as resolved by flnr.
A
ProcessFateobject combines three pieces of information:the supervisory decision made by flnr
the termination method selected by flnr
the process return code observed by flnr, if available
returncodemay beNonewhen flnr could not confirm process exit within the allowed observation window.- Parameters:
termination_decision (ProcessTerminationDecision)
termination_method (ProcessTerminationMethod)
returncode (int | None)
Timeouts¶
Command execution timeouts.
- class ExecutionTimeouts(run=None, terminate=5.0, output_drain=1.0, kill=None)¶
Duration of various time-sensitive aspects of command execution.
All timeouts are in seconds (fractional values allowed).
The
killparameter may be left unspecified: ifNone(the default), theterminatevalue is used for the post-kill wait.Teardown Procedure
The library follows a staged escalation when the process must be stopped. The exact sequence depends on the supervisory decision that flnr reaches during execution.
If the ``run`` timeout expires:
Terminate stage: The process is asked to terminate and given
terminateseconds to exit on its own. Monitors continue to run during this phase so final logs and state can be captured.Forced kill: If the process does not exit within the
terminategrace period, it is forcibly killed.
If flnr encounters an unrecoverable internal failure while reading process output:
The process is forcibly terminated immediately, without attempting the terminate stage.
After the forced kill (in either case):
Monitors are paused and the library waits up to the
killtimeout for confirmation that the process has exited.If no such confirmation arrives,
ProcessKillFailedErroris raised.Otherwise, monitors are resumed to allow any remaining output to be drained (subject to the
output_draintimeout).
Monitor Interfaces¶
Interfaces for output and environment monitors.
- class OutputMonitorDisableReason¶
Identify the reason for output monitor disable event.
flnr manages the lifecycle of each output monitor. A monitor starts active and may be disabled under certain circumstances. Once disabled, the transition is final. When disabling a monitor, flnr attempts to notify it by providing one of the reasons below.
- EOF¶
The output stream associated with this monitor has ended. No further data will be available. This is the expected reason under normal operation.
- ERROR¶
The monitor raised an unhandled exception when flnr attempted to interact with it. Monitors should not interrupt execution flow; if they throw, they are disabled.
- DRAIN_TIMEOUT¶
The process finished execution, but flnr could not drain all remaining data from the output stream within the configured
output_draintimeout. This may happen, for instance, when a subprocess spawns children that inherit and hold open its stdout or stderr descriptors.
- class OutputMonitor¶
Interface that subprocess output monitors must implement.
Output monitors are treated as disposable, self-contained objects. Their purpose is to forward subprocess output to some sink (typically a file on disk), optionally applying simple transformations such as transcoding or timestamping.
If an output monitor raises an exception, that exception is saved and the monitor is disabled. The error is reported only after the monitored process finishes execution.
- abstract process(data, ts)¶
Process data from subprocess output stream.
The timestamp identifies when flnr read this chunk from the stream.
- on_disable(reason, ts)¶
Notification callback called when output monitor is disabled.
After this call, process() will never be invoked again. Override to flush any buffered partial data or write a truncation marker. Implement as pass if you don’t need this notification.
- Return type:
- Parameters:
reason (OutputMonitorDisableReason)
ts (float)
- class EnvironmentMonitor(*, period)¶
Interface for execution-environment monitors.
Environment monitors are periodic user-supplied callbacks whose purpose is to observe the execution environment while the subprocess remains the current subject of observation.
These monitors are not process-control hooks. They are observational callbacks. The provided
pidis a convenience handle that helps narrow the observation surface when needed.If an environment monitor raises an exception, that exception is recorded and the monitor is disabled. Execution continues as if that monitor did not exist. The error is reported only after monitored execution finishes.
- Parameters:
period (float)
- on_start(pid, cmd)¶
Notifies when process corresponding to the command is created.
Note
pidis provided for logging/notification purposes only. By the timeon_startis called, the underlying process may already have exited.
- abstract observe(pid)¶
Periodic callback while the subprocess is being monitored.
Callbacks must not assume that the process is still running. The only guarantee is that flnr still treats this process as the current subject of monitoring.
- on_end(process_fate)¶
Notifies when environment observation ends.
The callback receives the final
ProcessFateresolved by flnr.Usually this happens after process exit has been observed, but
process_fate.returncodemay beNoneif flnr could not confirm process exit within the allowed observation window.This callback is not guaranteed to run if the monitor itself fails earlier. It must not be relied upon for cleanup or critical logic.
- Return type:
- Parameters:
process_fate (ProcessFate)
Stream Bindings¶
- class InheritStdin¶
Marker type for inheriting child stdin from the parent stdin.
- class BindToParent¶
Marker type for binding a child output stream to its parent stream.
- flnr.INHERIT_STDIN: InheritStdin¶
Inherit stdin directly from parent.
- flnr.BIND_TO_PARENT: BindToParent¶
Bind child output directly to the corresponding parent stream.
Output routed this way is not observed by output monitors.
Monitor Failures¶
Identification of monitor failure reasons.
- class MonitorHook¶
Identification of the method that caused failure.
- class OutputStream¶
Identification of output stream for error reporting.
- class MonitorFailure(monitor, hook, exception, monitor_index, stream=None)¶
Information about one monitor callback failure.
- Parameters:
monitor (object)
hook (MonitorHook)
exception (Exception)
monitor_index (int)
stream (OutputStream | None)
- monitor¶
Monitor object that raised the exception.
- hook¶
Monitor callback that failed.
- exception¶
Exception raised by the monitor callback.
- monitor_index¶
Zero-based index of the monitor in the configured monitor list.
- stream¶
Output stream associated with an output monitor failure.
Noneidentifies an environment monitor failure.
Exceptions¶
Exceptions defined by the library.
- exception ProcessExecutionError(*, fate, monitor_failures, internal_exceptions=(), message)¶
Base exception for failures raised during supervised process execution.
These exceptions carry the resolved
ProcessFatetogether with any monitor exceptions collected during execution. Users are expected to inspect both pieces of information.- Parameters:
fate (ProcessFate)
monitor_failures (Sequence[MonitorFailure])
internal_exceptions (Sequence[BaseException])
message (str)
- Return type:
None
- exception CommandFailedError(*, fate, monitor_failures, internal_exceptions=(), message)¶
Raised when
check=Trueand the observed return code is non-zero.This also covers subprocesses terminated by flnr after a run timeout or host-requested termination if the resulting return code is non-zero. Inspect the
fatefield to distinguish the cause and final outcome.- Parameters:
fate (ProcessFate)
monitor_failures (Sequence[MonitorFailure])
internal_exceptions (Sequence[BaseException])
message (str)
- Return type:
None
- exception MonitorFailedError(*, fate, monitor_failures, internal_exceptions=(), message)¶
Raised when one or more monitor callbacks fail during execution.
- Parameters:
fate (ProcessFate)
monitor_failures (Sequence[MonitorFailure])
internal_exceptions (Sequence[BaseException])
message (str)
- Return type:
None
- exception SupervisionFailedError(*, fate, monitor_failures, internal_exceptions=(), message)¶
Raised when flnr cannot continue supervising the process correctly.
In this situation flnr attempts to force-stop the process and report any failures it managed to record.
Reported output, process state, and collected diagnostics may be incomplete or unreliable.
This exception may indicate a serious failure in the execution environment itself, as opposed to an ordinary failure of the supervised process.
- Parameters:
fate (ProcessFate)
monitor_failures (Sequence[MonitorFailure])
internal_exceptions (Sequence[BaseException])
message (str)
- Return type:
None
- exception ProcessKillFailedError(*, fate, monitor_failures, internal_exceptions=(), message)¶
Raised when flnr cannot confirm process exit after intervention.
This means flnr completed its supervisory actions but could not observe a final process exit state within the allowed time window.
In such cases
fate.returncodeis expected to beNone.Like tears in the rain, this moment will be lost in time. Your process, however, will not.
- Parameters:
fate (ProcessFate)
monitor_failures (Sequence[MonitorFailure])
internal_exceptions (Sequence[BaseException])
message (str)
- Return type:
None
Host Control¶
Facilities for host to request premature termination.
- class HostTerminationRequest¶
Stable, latched host-termination trigger source.
This object can be passed to
run_ex(host_termination=...)to let the caller control host-side termination requests explicitly, without usingHostTerminationRequest.HOST_SIGNALS.The object is stable and reusable across multiple runs. Once triggered, it remains triggered. A run that attaches to an already-triggered request will observe termination as soon as supervision starts. This does not prevent process creation ahead of time; it only means the run will converge on termination immediately after startup.
Creating a HostTerminationRequest allocates OS resources. Those resources may be released with
close(), butclose()is ordinary lifecycle cleanup and must not race with futuretrigger()calls.trigger()may be called from a Python signal handler in this implementation.close()does not provide that guarantee.-
HOST_SIGNALS:
Final[_HostSignalsSentinel] = _HostSignalsSentinel¶ Sentinel value for
run_ex(..., host_termination=...).Passing
HostTerminationRequest.HOST_SIGNALStellsrun_ex()to temporarily install handlers forSIGINTandSIGTERMfor the duration of the call.Constraints:
Unix/POSIX only
main Python thread only
while active,
flnrowns SIGINT/SIGTERM handling for the duration of the callprevious handlers are restored when
run_ex()returns
This temporarily replaces normal SIGINT/SIGTERM handling for the call.
Use an instance of
HostTerminationRequestif the application manages handling itself and wants to request termination explicitly.
- trigger()¶
Trigger host termination request.
Once triggered, the request remains triggered.
This method may be called from a Python signal handler in this implementation. It is intentionally small and only performs the minimal work needed to wake attached runs.
Repeated calls after the request has already been triggered are harmless.
- Return type:
- close()¶
Release OS resources owned by this request object.
This is ordinary lifecycle cleanup. It is not safe to call from a Python signal handler, and it must not race with future
trigger()calls.In particular, if this object is still reachable from installed signal handlers, callers should not call
close(). In that usage mode, the object is expected to remain alive for the lifetime of the program, or until it has been fully detached from all future signal delivery.Once
close()is called, the object is dead and must not be reused for later runs.- Return type:
-
HOST_SIGNALS:
Command Tracing¶
- class CommandTracerProtocol(*args, **kwargs)¶
Protocol for command tracing implementations.
Implementations receive execution details before the child process is created.
Command arguments and environment variable values may be sensitive. Implementations should record only values appropriate for their output destination.
- trace_command(*, cmd, cwd, env, host_env)¶
Receive execution details before the child process is created.
cmdrepresents the command to execute: the program path followed by its arguments.cwdis the caller-supplied working directory;Nonemeans the child inherits the parent process working directory.envis the environment passed to the child.host_envis a snapshot of the host process environment.
- class CommandTracer(logger, *, env_listing=_DEFAULT_ENV_LISTING, level=logging.INFO)¶
Log diagnostic command recipes.
Command recipes are shell-oriented renderings intended for inspection and logging. They are informational and are not guaranteed to be exact replay scripts.
By default, command tracing records the working directory and command line only. Environment values are not logged unless the caller explicitly enables environment tracing.
Use
with_selected_environment()to trace explicit environment variables,with_changed_environment()to trace values changed from the host process environment, orwith_recreated_environment()to trace the complete child environment from an empty base. These modes write environment variable values to logs, so callers should enable them only for values safe to expose in their logging destination.- Parameters:
- classmethod with_changed_environment(logger, *, level=logging.INFO)¶
Create a tracer logging the command and modified child environment.
The log includes the command line and any child environment variables that differ from the host process. Host variables missing from the child are listed by name only.
Use this mode only if the changed values are safe for the configured log destinations.
- Return type:
- Parameters:
- classmethod with_selected_environment(logger, variables, *, level=logging.INFO)¶
Create a tracer logging the command and selected child variables.
This tracer restricts environment variable listing to explicitly requested keys. Select only variables with values safe for the configured log destinations.
- Return type:
- Parameters:
- classmethod with_recreated_environment(logger, *, level=logging.INFO)¶
Create a tracer logging a recreated child environment.
The log includes the command line and the complete child environment as assignments applied after clearing inherited environment values.
Use this mode only if the full child environment is safe for the configured log destinations.
- Return type:
- Parameters:
- class EnvListing(variables=(), clear_environment=False, removed_variables=(), missing_variables=())¶
Environment rendering instructions for command recipes.
EnvListingis returned by command tracer environment-listing callbacks. It describes what the renderer should include in the command recipe.variablesare environment assignments to render, in order.clear_environmentmeans the recipe should start from an empty environment before applyingvariables.removed_variablesare inherited environment variable names to remove from the rendered recipe. Renderers ignore this field whenclear_environmentis true.missing_variablesare names requested by the listing callback but absent from the child environment. They are reported byCommandTraceras missing, not rendered as assignments.
- list_changed_environment(child_env, host_env)¶
List child environment values changed from the host process environment.
Unchanged host process environment variables are not listed. Host process variables missing from the child environment are listed by name, without their values.
- list_recreated_environment(child_env, host_env)¶
List the complete child environment from an empty environment base.
- list_selected_environment(variables)¶
Create a helper that lists selected environment variables.
Tracer-enabled call sites should not select secret variables for display.
Monitoring Utilities¶
Reference output monitors and output-processing helpers.
- class IncrementalLineSplitter(buffer_limit=_DEFAULT_ILS_BUFFER_LIMIT)¶
Incrementally split byte chunks into newline-terminated records.
- Parameters:
buffer_limit (int)
- feed(chunk)¶
Feed a chunk of bytes, get resulting lines as a byte sequence.
If an empty chunk is fed, this transforms currently accumulated bytes into a line without newline sequence at the end.
Note
If buffered trailing data grows beyond
buffer_limitbefore a newline is seen, the buffered tail is emitted early as a fragment to keep carry-over memory bounded.
- class TextOutputMonitor(*, sink, ils_buffer_limit=_DEFAULT_ILS_BUFFER_LIMIT, encoding='latin-1', auto_flush=True, timestamp_precision=None, timestamp_base=None, append_disable_marker=False)¶
Reference monitor for line-oriented text output.
This monitor buffers incoming bytes, emits complete records terminated by
\n, normalizes a trailing\r\nto\n, decodes the result with the configured encoding usingerrors="replace", and writes the resulting text to a text sink.Buffered partial data is flushed when the monitor is disabled.
Optional timestamping prefixes each emitted line with a monotonic timestamp. If
timestamp_baseis provided, timestamps are emitted relative to that monotonic timestamp value. Disable markers, when enabled, are appended as a diagnostic footer and keep their embedded raw monotonic timestamp values regardless of the configured timestamp style.- Parameters:
- process(data, ts)¶
Process a chunk of subprocess output.
Complete lines are decoded and written to the sink immediately. Partial lines are buffered across calls. An empty chunk (
b"") flushes any buffered tail without adding a newline.If timestamping is enabled, each emitted line is prefixed with the timestamp associated with this call.
- on_disable(reason, ts)¶
Flush buffered data and optionally append a diagnostic footer.
- Return type:
- Parameters:
reason (OutputMonitorDisableReason)
ts (float)
- class BinaryOutputMonitor(*, sink)¶
Built-in monitor that forwards raw output bytes to a binary sink.
- Parameters:
sink (IOBase)
- process(data, ts)¶
Write a chunk of raw output bytes to the sink.
- on_disable(reason, ts)¶
Flush the sink when monitoring ends.
- Return type:
- Parameters:
reason (OutputMonitorDisableReason)
ts (float)
Epigraph
- – If a producer can outpace a consumer, something must grow, block, or die.
(independently rediscovered, like most unpleasant truths)