-
Notifications
You must be signed in to change notification settings - Fork 18
Open
Description
Description
An AssertionError is raised at fake_popen.py:188when calling with argument stderr=subprocess.STDOUT if stdout is a file (stdout is expected to be None:
> assert self.stdout is not None
E AssertionError
pyvenv\Lib\site-packages\pytest_subprocess\fake_popen.py:188: AssertionError
subprocess.Popen handles this correctly; stderr is simply written to the file at stdout.
Example
Below is an example demonstrating the error. I have GIT_TRACE set so that git rev-parse gives a small amount of stdout and stderr:
$ git rev-parse HEAD
06:05:28.502294 exec-cmd.c:244 trace: resolved executable dir: C:/Program Files/Git/mingw64/bin
06:05:28.537291 git.c:463 trace: built-in: git rev-parse HEAD
47c77698dd8e0e35af00da56806fe98fcb9a1056
I define a function that runs the subprocess (so that I can call the same thing, using either the fake or real Popen:
def run_git_revparse():
import os
os.environ['GIT_TRACE'] = '1'
with NamedTemporaryFile("w+b", delete=False) as f:
path = pathlib.Path(f.name)
# NOTE: I pass f.file because for some reason:
# isinstance(f, io.BufferedWriter) == False
# so pytest_subprocess isinstance checks would fail. I am
# hesitant to change those tests, though you could simply check
# for a few key methods:
# hasattr(f.mode)
# isinstance(f.mode, str)
# hasattr(f.write)
# isinstance(f.write, types.FunctionType)
p = subprocess.Popen(('git', 'rev-parse', 'HEAD'), stdout=f.file, stderr=subprocess.STDOUT)
f.close()
assert p.wait() == 0
assert path.exists()
output = path.read_text()
# print to sys.stdout so I can see with `pytest --capture=no`
print('-'*50)
print(output)
print('-'*50)
output = output.splitlines()
assert len(output) == 3
# account for stderr coming before or after stdout
if 'exec-cmd.c' in output[1]:
output[2], output[0], output[1] = output
# first two lines should be stderr
assert 'exec-cmd.c' in output[0]
assert 'git.c' in output[1]
# last line should be a hex string
assert len(set(output[2]) - set('0123456789abcdef')) == 0Then define my test function, which first runs the real git, then the fake "git":
def test_fp(fp):
print() # for --capture=no
fp.allow_unregistered(True)
run_git_revparse()
fp.register(
["git", 'rev-parse', 'HEAD'],
stdout=["47c77698dd8e0e35af00da56806fe98fcb9a1056"],
stderr=[
'05:17:17.982923 exec-cmd.c:244 trace: resolved executable dir: C:/Program Files/Git/mingw64/bin',
'05:17:18.000760 git.c:463 trace: built-in: git rev-parse HEAD'
])
run_git_revparse()This raises the assertion error. I can correct this:
--- fake_popen.py 2024-02-10 06:09:01.897909800 -0500
+++ fake_popen.py 2024-02-10 06:08:49.610943500 -0500
@@ -181,22 +181,16 @@
stdout = kwargs.get("stdout")
if stdout == subprocess.PIPE:
self.stdout = self._prepare_buffer(self.__stdout)
- elif self.__is_io_writer(stdout):
+ elif isinstance(stdout, (io.BufferedWriter, io.TextIOWrapper)):
self._write_to_buffer(self.__stdout, stdout)
stderr = kwargs.get("stderr")
if stderr == subprocess.STDOUT and self.__stderr:
- if self.__is_io_writer(stdout):
- self._write_to_buffer(self.__stderr, stdout)
- else:
- assert self.stdout is not None
- self.stdout = self._prepare_buffer(self.__stderr, self.stdout)
+ assert self.stdout is not None
+ self.stdout = self._prepare_buffer(self.__stderr, self.stdout)
elif stderr == subprocess.PIPE:
self.stderr = self._prepare_buffer(self.__stderr)
- elif self.__is_io_writer(stderr):
+ elif isinstance(stderr, (io.BufferedWriter, io.TextIOWrapper)):
self._write_to_buffer(self.__stderr, stderr)
-
- def __is_io_writer(self, o):
- return isinstance(o, (io.BufferedWriter, io.TextIOWrapper, io.BufferedRandom))
def _prepare_buffer(
self,Note:
- I pulled out the
isinstancetesting. - I added
io.BufferedRandomto the group, as that is what I had, and I would expect it should be included...my test still won't work without it.
Metadata
Metadata
Assignees
Labels
No labels