Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional check to tell if it's safe to redirect stdout/err #270

Merged
merged 3 commits into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ Changes
- Migrate doctests to Python 3.8 [#261]
- Migrate Python tests to pytest [#265]

Fixes
-----
- Add additional check to tell if it's safe to redirect stdout/err [#270]


2.4.0 (2021-09-30)
==================
Expand Down
29 changes: 19 additions & 10 deletions Corrfunc/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1029,24 +1029,33 @@ def prep(w,x):
@contextmanager
def sys_pipes():
'''
We can use the Wurlitzer package to redirect stdout and stderr
from the command line into a Jupyter notebook. But if we're not
in a notebook, this isn't safe because we can't redirect stdout
to itself. This function is a thin wrapper that checks if the
stdout/err streams are TTYs and enables output redirection
based on that.
In a Jupyter notebook, Python's ``sys.stdout`` and ``sys.stderr`` are redirected
so output ends up in cells. But C extensions don't know about that! Wurlitzer
uses os.dup2 to redirect fds 1 & 2 to the new location and restore them on return,
but will cause the output to hang if they were not already redirected. It seems
we can compare Python's ``sys.stdout`` to the saved ``sys.__stdout__`` to tell
if redirection occurred. We will also check if the output is a TTY as a safety
net, even though it is probably a subset of the preceeding check.

Basic usage is:

>>> with sys_pipes(): # doctest: +SKIP
... call_some_c_function()

See the Wurlitzer package for usage of `wurlitzer.pipes()`;
see also https://github.com/manodeep/Corrfunc/issues/157.
see also https://github.com/manodeep/Corrfunc/issues/157,
https://github.com/manodeep/Corrfunc/issues/269.
'''

kwargs = {'stdout':None if sys.stdout.isatty() else sys.stdout,
'stderr':None if sys.stderr.isatty() else sys.stderr }

kwargs = {}
if sys.stdout.isatty() or (sys.stdout is sys.__stdout__):
kwargs['stdout'] = None
else:
kwargs['stdout'] = sys.stdout
if sys.stderr.isatty() or (sys.stderr is sys.__stderr__):
kwargs['stderr'] = None
else:
kwargs['stderr'] = sys.stderr

# Redirection might break for any number of reasons, like
# stdout/err already being closed/redirected. We probably
Expand Down