Skip to content

docs: document sys.stdout flush on exit#6081

Closed
SMC17 wants to merge 1 commit into
PyO3:mainfrom
SMC17:docs/sys-stdout-flush-on-exit
Closed

docs: document sys.stdout flush on exit#6081
SMC17 wants to merge 1 commit into
PyO3:mainfrom
SMC17:docs/sys-stdout-flush-on-exit

Conversation

@SMC17
Copy link
Copy Markdown

@SMC17 SMC17 commented May 29, 2026

docs: document sys.stdout flush on exit

Closes #1490.

Summary

Issue #1490 reports that sys.stdout and sys.stderr are not flushed
when a Rust program embedding PyO3 exits, so Python writes without a
trailing newline can be silently dropped.

In 2021 the maintainer redirected the issue from "fix the runtime" to
"document the workaround":

we added the finalizers to flush stdout and then removed them in
#1355 [...] In the end we
decided there's too many issues with finalizers to run them
ourselves. So I think this is a documentation issue.

You may want to consider running with PYTHONUNBUFFERED=1 [...]
Alternatively you could add unsafe { pyo3::ffi::Py_Finalize() } at
the end of your main function if it doesn't cause you problems.

(@davidhewitt, #1490 comment)

The issue carries the documentation and needs-implementer labels
and has had no follow-up PR.

Change

Adds one section to guide/src/python-from-rust/calling-existing-code.md
titled "sys.stdout and sys.stderr are not flushed when the Rust
program exits", placed after "Handling system signals/interrupts
(Ctrl-C)" and before the link-reference block.

The section:

  1. States the behaviour and links to PR gil: tidy ups to finalization #1355 for the rationale on why
    PyO3 does not run Py_Finalize automatically.
  2. Lists three workarounds in increasing order of intrusiveness:
    PYTHONUNBUFFERED=1, explicit sys.stdout.flush() / sys.stderr.flush()
    from Python, and an unsafe { pyo3::ffi::Py_Finalize() } call in
    main, with a SAFETY: note on the lifetime constraint.
  3. Cross-links the upstream CPython documentation at
    Initialization, Finalization, and Threads.

The explicit-flush code block uses the current Python::attach API and
follows the # fn main() -> PyResult<()> { hidden-line pattern already
used elsewhere in the file. The Py_Finalize block is marked
rust,no_run because finalising the interpreter inside a doctest would
interact badly with the rest of the test suite.

Verification

  • cargo doc --no-deps -p pyo3 completes cleanly on the branch
    (pyo3 v0.28.3 docs build, Finished dev profile).
  • No new newsfragment per Contributing.md: "Docs-only PRs do not
    need news items; start your PR title with docs: to skip the check."
  • The diff is a single markdown file, +44 / -0 lines.

Out of scope

This PR does not change the runtime behaviour. PR #1355 already
documented the decision to remove automatic finalisation; the present
PR only fills the doc gap that decision left behind.

Add a section to the "Calling Python from Rust" chapter covering the
behaviour reported in PyO3#1490: when PyO3 embeds a Python interpreter, the
buffered streams are not flushed at process exit because PyO3 does not
call Py_Finalize automatically (see PyO3#1355). The new section enumerates
three workarounds (PYTHONUNBUFFERED, explicit sys.stdout.flush, and
unsafe Py_Finalize) matching the maintainer's guidance in PyO3#1490.

Closes PyO3#1490.

Signed-off-by: Sean Collins <sean@sunlitmoon.online>
Assisted-by: claude-opus-4-7
@SMC17 SMC17 force-pushed the docs/sys-stdout-flush-on-exit branch from fbc9316 to 2fdbf1f Compare May 29, 2026 01:06
@SMC17
Copy link
Copy Markdown
Author

SMC17 commented May 29, 2026

Sorry — been testing some things and this leaked out. Closing.

@SMC17 SMC17 closed this May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sys.stdout not flushed on exit

1 participant