on python3, print() does not automatically flush() stdout/stderr

Issue #177 resolved
Cosimo Lupo
created an issue

Hi,

I noticed that doing print() from a PyObjC application behaves differently when run from python 2 or python 3.

I tried to make a standalone .app with py2app from the example "HelloWorld.py" script:

https://bitbucket.org/ronaldoussoren/pyobjc/src/9bdbc79f0a19b0c19a9aa17a7a0ea74fbd18667d/pyobjc-core/Examples/Scripts/HelloWorld.py

The setup.py looks like this:

from setuptools import setup

setup(
    app=["HelloWorld.py"],
    setup_requires=["py2app"],
)

Now, if I build it with Python 3.5.2 (downloaded from python.org), using pyobjc 3.2.1 (released today) and the latest py2app, the output of print() is only shown in the Console.app only when the application is closed.

Similarly, If I run it from the Terminal.app by doing dist/HelloWorld.app/Contents/MacOS/HelloWorld, the output is only printed after quitting.

However, if I manually do sys.stdout.flush() after each print, then I see the output immediately after clicking the buttons, while the app is still running.

The issue does not occur when compiling the same code with the system python 2.7.10 and same version of pyobjc 3.2.1 (in a virtualenv).

Thank you for your support.

Cosimo

Comments (10)

  1. Cosimo Lupo reporter

    according to the docs, the standard streams are line-buffered only when running from an interactive console, and block-buffered when redirected to a file.

    https://docs.python.org/3/library/sys.html#sys.stdout

    I still don't understand why this would work in Python 2 and not in Python 3, though..

    Also, I wonder if I could pass the PYTHONUNBUFFERED variable or the -u command line switch to a py2app-generated app so that it flushes stdout immediately?

  2. Ronald Oussoren repo owner

    PyObjC doesn't perform the redirection.

    On OSX 10.8 or earlier the system automatically redirected stdout and stderr to the Console.app logs, on newer OSX releases this doesn't happen but py2app contains code to perform the redirection using the ASL library, the relevant code is in the main.c for the app template.

    That code likely causes the problem, it replaces the file descriptors for stdout and stderr by new ones provided by ASL. In python2 sys.stdout (used by print) uses the C "FILE*" stream for stdout, which is initialised before the file descriptor trickery by py2app and hence doesn't notice that stdout isn't a tty anymore; in python3 sys.stdout is fully implemented in Python (with a C accelerator) and is initialised after py2app changes the file descriptors and probably notices that those file descriptors aren't ttys.

    I guess I can teach py2app to set "PYTHONUNBUFFERED" in the environment before initialising the Python interpreter, that would fix your problem.

  3. Log in to comment