diff --git a/CHANGES.md b/CHANGES.md index 3c52401d..9c08be7a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,12 +8,14 @@ The released versions correspond to PyPi releases. (see [#549](../../issues/549)) #### Fixes + * allow to open existing pipe file descriptor + (see [#493](../../issues/493)) * do not truncate file on failed flush - (see [#548](../../issues/548)) + (see [#548](../../issues/548)) * suppress deprecation warnings while collecting modules - (see [#542](../../issues/542)) + (see [#542](../../issues/542)) * add support for `os.truncate` and `os.ftruncate` - (see [#545](../../issues/545)) + (see [#545](../../issues/545)) #### Infrastructure * fixed another problem with CI test scripts not always propagating errors diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py index 16342c26..bbc20373 100644 --- a/pyfakefs/fake_filesystem.py +++ b/pyfakefs/fake_filesystem.py @@ -4997,6 +4997,14 @@ def __init__(self, filesystem, fd): self.file_object = None self.filedes = None + def __enter__(self): + """To support usage of this fake pipe with the 'with' statement.""" + return self + + def __exit__(self, type, value, traceback): + """To support usage of this fake pipe with the 'with' statement.""" + self.close() + def get_object(self): return self.file_object @@ -5008,6 +5016,10 @@ def read(self, numBytes): """Read from the real pipe.""" return os.read(self.fd, numBytes) + def flush(self): + """Flush the real pipe?""" + pass + def write(self, contents): """Write to the real pipe.""" return os.write(self.fd, contents) @@ -5084,6 +5096,12 @@ def call(self, file_, mode='r', buffering=-1, encoding=None, file_object, file_path, filedes, real_path = self._handle_file_arg( file_) + if file_object is None and file_path is None: + wrapper = FakePipeWrapper(self.filesystem, filedes) + file_des = self.filesystem._add_open_file(wrapper) + wrapper.filedes = file_des + return wrapper + if not filedes: closefd = True @@ -5170,6 +5188,8 @@ def _handle_file_arg(self, file_): # opening a file descriptor filedes = file_ wrapper = self.filesystem.get_open_file(filedes) + if isinstance(wrapper, FakePipeWrapper): + return None, None, filedes, None self._delete_on_close = wrapper.delete_on_close file_object = self.filesystem.get_open_file(filedes).get_object() file_path = file_object.name diff --git a/pyfakefs/tests/fake_os_test.py b/pyfakefs/tests/fake_os_test.py index 7c2e9ea3..f8a31d2f 100644 --- a/pyfakefs/tests/fake_os_test.py +++ b/pyfakefs/tests/fake_os_test.py @@ -2694,6 +2694,22 @@ def test_open_file_with_existing_pipe(self): self.os.close(write_fd) self.os.close(fd) + def test_read_write_pipe(self): + read_fd, write_fd = self.os.pipe() + self.assertEqual(4, self.os.write(write_fd, b'test')) + self.assertEqual(b'test', self.os.read(read_fd, 4)) + self.os.close(read_fd) + self.os.close(write_fd) + + def test_open_existing_pipe(self): + if self.is_pypy: + raise unittest.SkipTest('Does not work correctly with PyPy') + read_fd, write_fd = self.os.pipe() + with self.open(write_fd, 'wb') as f: + self.assertEqual(4, f.write(b'test')) + with self.open(read_fd, 'rb') as f: + self.assertEqual(b'test', f.read(4)) + def test_write_to_pipe(self): read_fd, write_fd = self.os.pipe() self.os.write(write_fd, b'test')