26 lines
1.2 KiB
Python
26 lines
1.2 KiB
Python
"""Shared interpreter-shutdown predicate for background threads that can outlive
|
|
process teardown (cron delivery, concurrent tool submission, retry paths).
|
|
|
|
Once finalization starts, ``concurrent.futures`` refuses new work and asyncio's
|
|
default executor is gone, so any further scheduling only produces noise (stray
|
|
prints after the TUI exited, tracebacks in ``errors.log``, futile retries).
|
|
CPython raises ``cannot schedule new futures after interpreter shutdown``
|
|
(module-global flag) or ``... after shutdown`` (a pool whose ``shutdown()`` ran);
|
|
the short prefix catches both — safe here because every pool involved is a
|
|
module-global daemon or a ``with``-scoped local only finalization can shut down.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from typing import Optional
|
|
|
|
|
|
def interpreter_shutting_down(exc: Optional[BaseException] = None) -> bool:
|
|
"""True when the interpreter is finalizing. ``exc`` lets a caller treat an
|
|
already-raised scheduling error as a shutdown signal: the ``concurrent.futures``
|
|
flag can be set a hair before ``sys.is_finalizing()`` flips."""
|
|
if sys.is_finalizing():
|
|
return True
|
|
return exc is not None and "cannot schedule new futures" in str(exc).lower()
|