bugfix: don't use sys.stdout as a default arg value (#16541)
After migrating to `travis-ci.com`, we saw I/O issues in our tests -- tests that relied on `capfd` and `capsys` were failing. We've also seen this in GitHub actions, and it's kept us from switching to them so far. Turns out that the issue is that using streams like `sys.stdout` as default arguments doesn't play well with `pytest` and output redirection, as `pytest` changes the values of `sys.stdout` and `sys.stderr`. if these values are evaluated before output redirection (as they are when used as default arg values), output won't be captured properly later. - [x] replace all stream default arg values with `None`, and only assign stream values inside functions. - [x] fix tests we didn't notice were relying on this erroneous behavior
This commit is contained in:
@@ -45,18 +45,18 @@ def __init__(self, prog, description, usage,
|
||||
class ArgparseWriter(argparse.HelpFormatter):
|
||||
"""Analyzes an argparse ArgumentParser for easy generation of help."""
|
||||
|
||||
def __init__(self, prog, out=sys.stdout, aliases=False):
|
||||
def __init__(self, prog, out=None, aliases=False):
|
||||
"""Initializes a new ArgparseWriter instance.
|
||||
|
||||
Parameters:
|
||||
prog (str): the program name
|
||||
out (file object): the file to write to
|
||||
out (file object): the file to write to (default sys.stdout)
|
||||
aliases (bool): whether or not to include subparsers for aliases
|
||||
"""
|
||||
super(ArgparseWriter, self).__init__(prog)
|
||||
self.level = 0
|
||||
self.prog = prog
|
||||
self.out = out
|
||||
self.out = sys.stdout if out is None else out
|
||||
self.aliases = aliases
|
||||
|
||||
def parse(self, parser, prog):
|
||||
@@ -167,7 +167,7 @@ def write(self, parser):
|
||||
class ArgparseRstWriter(ArgparseWriter):
|
||||
"""Write argparse output as rst sections."""
|
||||
|
||||
def __init__(self, prog, out=sys.stdout, aliases=False,
|
||||
def __init__(self, prog, out=None, aliases=False,
|
||||
rst_levels=_rst_levels):
|
||||
"""Create a new ArgparseRstWriter.
|
||||
|
||||
@@ -178,6 +178,7 @@ def __init__(self, prog, out=sys.stdout, aliases=False,
|
||||
rst_levels (list of str): list of characters
|
||||
for rst section headings
|
||||
"""
|
||||
out = sys.stdout if out is None else out
|
||||
super(ArgparseRstWriter, self).__init__(prog, out, aliases)
|
||||
self.rst_levels = rst_levels
|
||||
|
||||
|
@@ -215,20 +215,22 @@ def cextra(string):
|
||||
return len(''.join(re.findall(r'\033[^m]*m', string)))
|
||||
|
||||
|
||||
def cwrite(string, stream=sys.stdout, color=None):
|
||||
def cwrite(string, stream=None, color=None):
|
||||
"""Replace all color expressions in string with ANSI control
|
||||
codes and write the result to the stream. If color is
|
||||
False, this will write plain text with no color. If True,
|
||||
then it will always write colored output. If not supplied,
|
||||
then it will be set based on stream.isatty().
|
||||
"""
|
||||
stream = sys.stdout if stream is None else stream
|
||||
if color is None:
|
||||
color = get_color_when()
|
||||
stream.write(colorize(string, color=color))
|
||||
|
||||
|
||||
def cprint(string, stream=sys.stdout, color=None):
|
||||
def cprint(string, stream=None, color=None):
|
||||
"""Same as cwrite, but writes a trailing newline to the stream."""
|
||||
stream = sys.stdout if stream is None else stream
|
||||
cwrite(string + "\n", stream, color)
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user