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

Redirect io #69

Merged
merged 11 commits into from
Feb 21, 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
2 changes: 1 addition & 1 deletion baseclasses/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "1.5.4"
__version__ = "1.6.0"

from .problems import (
AeroProblem,
Expand Down
100 changes: 100 additions & 0 deletions baseclasses/utils/redirectIO.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from contextlib import contextmanager
import io
import os
import sys

"""
Functions for redirecting stdout/stderr to different streams

Based on: http://eli.thegreenplace.net/2015/redirecting-all-kinds-of-stdout-in-python/.
"""


def redirectIO(f_out, f_err=None):
"""
This function redirects stdout/stderr to the given file handle.

Parameters
----------
f_out : file
A file stream to redirect stdout to

f_err : file
A file stream to redirect stderr to. If none is specified it is set to `f_out`
"""

if f_err is None:
f_err = f_out

orig_out = sys.stdout.fileno()
orig_err = sys.stderr.fileno()

# flush the standard out
sys.stdout.flush()
sys.stderr.flush()

# close the standard
sys.stdout.close()
sys.stderr.close()

os.dup2(f_out.fileno(), orig_out)
os.dup2(f_err.fileno(), orig_err)

# reopen the stream with new file descriptors
sys.stdout = io.TextIOWrapper(os.fdopen(orig_out, "wb"))
sys.stderr = io.TextIOWrapper(os.fdopen(orig_err, "wb"))


@contextmanager
def redirectingIO(f_out, f_err=None):
"""
A function that redirects stdout in a with block and returns to the stdout after the `with` block completes.
The filestream passed to this function will be closed after exiting the `with` block.

Here is an example of usage where all adflow output is redirected to the file `adflow_out.txt`:
>>> from baseclasses.utils import redirectIO
>>> print("Printing some information to terminal")
>>> with redirectIO.redirectingIO(open("adflow_out.txt", "w")):
... CFDSolver = ADFLOW(options=options)
... CFDSolver(AeroProblem(**apOptions)
>>> print("Printing some more information to terminal")

Parameters
----------
f_out : file
A file stream that stdout should be redirected to

f_err : file
A file stream to redirect stderr to. If none is specified it is set to `f_out`
"""

if f_err is None:
f_err = f_out

# save the file descriptors to restore to
saved_stdout_fd = os.dup(sys.stdout.fileno())
saved_stderr_fd = os.dup(sys.stderr.fileno())

# redirect the stdout/err streams
redirectIO(f_out, f_err)

# yield to the with block
yield

orig_out = sys.stdout.fileno()
orig_err = sys.stderr.fileno()

# flush output
sys.stderr.flush()
sys.stdout.flush()

# close the output
sys.stderr.close()
sys.stdout.close()

os.dup2(saved_stdout_fd, orig_out)
os.dup2(saved_stderr_fd, orig_err)

# reopen the standard streams with original file descriptors
sys.stdout = io.TextIOWrapper(os.fdopen(orig_out, "wb"))
sys.stderr = io.TextIOWrapper(os.fdopen(orig_err, "wb"))