The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Install a handler | previous = signal.signal(signal.SIGTERM, handle_shutdown) | View examples |
| Check the main thread | is_main = threading.current_thread() is threading.main_thread() | View examples |
| List supported signals | supported = signal.valid_signals() | View examples |
| Request graceful stop | def handler(signum, frame): shutdown.set() | View examples |
| Wait interruptibly | requested = shutdown.wait(timeout=1.0) | View examples |
| Restore a disposition | signal.signal(signal.SIGTERM, previous) | View examples |
| Schedule SIGALRM | remaining = signal.alarm(seconds) | View examples |
| Schedule a real-time timer | previous = signal.setitimer(signal.ITIMER_REAL, delay, interval) | View examples |
| Block signals in one thread | previous = signal.pthread_sigmask(signal.SIG_BLOCK, signals) | View examples |
| Read with a default | mode = os.getenv('APP_MODE', 'production') | View examples |
| Require a variable | database_url = os.environ['DATABASE_URL'] | View examples |
| Copy the environment | environment = os.environ.copy() | View examples |
| Set a process variable | os.environ['APP_MODE'] = 'test' | View examples |
| Remove a process variable | os.environ.pop('APP_MODE', None) | View examples |
| Reload external changes | os.reload_environ() | View examples |
| Pass a child environment | subprocess.run(argv, env=child_env, check=True) | View examples |
| Override selected child values | child_env = os.environ | {'APP_MODE': 'batch'} | View examples |
| Expand environment syntax | expanded = os.path.expandvars(template) | View examples |
| Read a bytes environment | raw = os.environb.get(b'KEY') | View examples |
| Check bytes environment support | available = os.supports_bytes_environ | View examples |
Signals are asynchronous operating-system notifications, while environment variables are inherited process configuration. Python runs signal handlers in the main thread at a later bytecode checkpoint, not inside the low-level handler. Robust services translate signals into simple shutdown state, keep cleanup in ordinary control flow, snapshot validated configuration early, and pass deliberate environments to child processes.
Step by step
Detailed examples
Understand Python's deferred signal model
Python's low-level handler sets a flag and the interpreter later calls the Python handler in the main thread. A long-running C operation may delay that call. Only the main thread of the main interpreter can install handlers, and signals cannot provide inter-thread delivery guarantees; use threading.Event, queues, or cancellation primitives for thread coordination.
import signal
received: list[int] = []
def handle(signum, frame) -> None:
received.append(signum)
handle(signal.SIGTERM, None)
print(received == [signal.SIGTERM])
print(signal.Signals(received[0]).name) True
SIGTERMTranslate termination into ordinary control flow
A handler should perform minimal work such as setting an Event or boolean. The main loop then stops accepting work, drains or cancels within a deadline, flushes durable state, and exits. Logging, locks, arbitrary callbacks, and exceptions inside handlers can interact with code interrupted at an inconvenient point; repeated signals may need a documented force-exit policy.
class StopFlag:
requested = False
flag = StopFlag()
def handler(signum, frame) -> None:
flag.requested = True
handler(15, None)
if flag.requested:
print("stop intake")
print("cleanup complete") stop intake
cleanup completeTreat timers and signal masks as Unix-specific tools
alarm and setitimer schedule process signals and can overwrite a timer owned by another library. pthread_sigmask changes the calling thread's signal mask on supporting Unix platforms; new threads inherit that mask. Use feature detection and restore prior state in finally. Windows exposes a smaller, different signal model and console control events have special process-group rules.
import signal
features = {
"alarm": hasattr(signal, "alarm"),
"pthread_sigmask": hasattr(signal, "pthread_sigmask"),
"setitimer": hasattr(signal, "setitimer"),
}
print(all(isinstance(value, bool) for value in features.values()))
print(sorted(features)) True
['alarm', 'pthread_sigmask', 'setitimer']Read environment configuration with a schema
os.environ is a mutable string-to-string mapping captured during interpreter startup. getenv distinguishes a missing key only when the default is chosen appropriately; an empty value is not the same as absence. Parse and validate booleans, numbers, lists, encodings, and URLs once near startup, and avoid scattering implicit defaults through business logic.
def parse_bool(value: str) -> bool:
normalized = value.strip().casefold()
if normalized not in {"true", "false"}:
raise ValueError("expected true or false")
return normalized == "true"
print(parse_bool(" TRUE "))
try:
parse_bool("yes")
except ValueError as error:
print(error) True
expected true or falseModify os.environ instead of calling putenv directly
Assigning or deleting os.environ entries updates the process environment through the platform API. putenv does not update the mapping, so direct mapping edits are preferred. On Windows keys are normalized to uppercase; on Unix environb may expose bytes when supported. Environment mutation is process-global and unsafe as request-local state.
import os
name = "CMDMEMO_EXAMPLE_MODE"
previous = os.environ.get(name)
try:
os.environ[name] = "test"
print(os.environ[name])
finally:
if previous is None:
os.environ.pop(name, None)
else:
os.environ[name] = previous
print(os.environ.get(name) == previous) test
TruePass an allowlisted environment to child processes
Children inherit the parent's environment by default, which can leak credentials and alter executable, locale, proxy, or library resolution. Construct a minimal environment from reviewed keys and pass it with subprocess env. On Windows include variables required by the target runtime; on POSIX use absolute executables or a controlled PATH. Never log the full environment.
parent = {"PATH": "/usr/bin", "APP_TOKEN": "secret", "LANG": "C.UTF-8"}
allowed = {key: parent[key] for key in ("PATH", "LANG") if key in parent}
allowed["APP_MODE"] = "batch"
for key in sorted(allowed):
print(key, allowed[key]) APP_MODE batch
LANG C.UTF-8
PATH /usr/binKeep secrets out of ambient process state when possible
Environment variables are convenient but may be exposed to child processes, crash reports, diagnostics, orchestration metadata, or same-user inspection depending on the platform. Prefer a secret manager or inherited descriptor when the threat model requires it, scope access narrowly, and rotate independently. Deleting a variable does not erase copies already made by libraries or the operating system.
environment = {"APP_MODE": "prod", "API_TOKEN": "abc", "PORT": "8080"}
safe = {
key: ("<redacted>" if key.endswith(("TOKEN", "PASSWORD", "SECRET")) else value)
for key, value in environment.items()
}
for key in sorted(safe):
print(f"{key}={safe[key]}") API_TOKEN=<redacted>
APP_MODE=prod
PORT=8080Local code tester
Validate process configuration
Parse a small environment-style mapping into typed configuration without reading or modifying the host environment.
Press Run to load Python locally.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- Python Software Foundationsignal — Set handlers for asynchronous eventsdocs.python.org
- Python Software Foundationos — Miscellaneous operating system interfacesdocs.python.org
- Python Software Foundationsubprocess — Subprocess managementdocs.python.org
- Python Software Foundationthreading — Thread-based parallelismdocs.python.org
- Python Software FoundationPython Initialization Configurationdocs.python.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



