Skip to content

Commit c88c85a

Browse files
committed
Fix newly introduced support for opener argument in open
- the wrong argument had been passed - fixes #689
1 parent b232261 commit c88c85a

File tree

3 files changed

+118
-2
lines changed

3 files changed

+118
-2
lines changed

CHANGES.md

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ The released versions correspond to PyPi releases.
33

44
## Unreleased
55

6+
### Fixes
7+
* fixed support for `opener` introduced in previous patch release
8+
(see [#689](../../issues/689))
9+
610
## [Version 4.6.1](https://pypi.python.org/pypi/pyfakefs/4.6.1) (2022-07-13)
711
Fixes incompatibility with Python 3.11 beta 4.
812

pyfakefs/fake_filesystem.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -5746,7 +5746,7 @@ def call(self, file_: Union[AnyStr, int],
57465746
if opener is not None:
57475747
# opener shall return a file descriptor, which will be handled
57485748
# here as if directly passed
5749-
file_ = opener(file_, open_modes)
5749+
file_ = opener(file_, self._open_flags_from_open_modes(open_modes))
57505750

57515751
file_object, file_path, filedes, real_path = self._handle_file_arg(
57525752
file_)
@@ -5770,7 +5770,7 @@ def call(self, file_: Union[AnyStr, int],
57705770
if not filedes:
57715771
closefd = True
57725772

5773-
if (open_modes.must_not_exist and
5773+
if (not opener and open_modes.must_not_exist and
57745774
(file_object or self.filesystem.islink(file_path) and
57755775
not self.filesystem.is_windows_fs)):
57765776
self.filesystem.raise_os_error(errno.EEXIST, file_path)
@@ -5819,6 +5819,26 @@ def call(self, file_: Union[AnyStr, int],
58195819
fakefile.filedes = self.filesystem._add_open_file(fakefile)
58205820
return fakefile
58215821

5822+
@staticmethod
5823+
def _open_flags_from_open_modes(open_modes: _OpenModes) -> int:
5824+
flags = 0
5825+
if open_modes.can_read and open_modes.can_write:
5826+
flags |= os.O_RDWR
5827+
elif open_modes.can_read:
5828+
flags |= os.O_RDONLY
5829+
elif open_modes.can_write:
5830+
flags |= os.O_WRONLY
5831+
5832+
if open_modes.append:
5833+
flags |= os.O_APPEND
5834+
if open_modes.truncate:
5835+
flags |= os.O_TRUNC
5836+
if not open_modes.must_exist and open_modes.can_write:
5837+
flags |= os.O_CREAT
5838+
if open_modes.must_not_exist and open_modes.can_write:
5839+
flags |= os.O_EXCL
5840+
return flags
5841+
58225842
def _init_file_object(self, file_object: Optional[FakeFile],
58235843
file_path: AnyStr,
58245844
open_modes: _OpenModes,

pyfakefs/tests/fake_open_test.py

+92
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,98 @@ def use_real_fs(self):
949949
return True
950950

951951

952+
class FakeFileOpenWithOpenerTest(FakeFileOpenTestBase):
953+
def opener(self, path, flags):
954+
return self.os.open(path, flags)
955+
956+
def test_use_opener_with_read(self):
957+
file_path = self.make_path('foo')
958+
self.create_file(file_path, contents='test')
959+
with self.open(file_path, opener=self.opener) as f:
960+
assert f.read() == 'test'
961+
with self.assertRaises(OSError):
962+
f.write('foo')
963+
964+
def test_use_opener_with_read_plus(self):
965+
file_path = self.make_path('foo')
966+
self.create_file(file_path, contents='test')
967+
with self.open(file_path, 'r+', opener=self.opener) as f:
968+
assert f.read() == 'test'
969+
assert f.write('bar') == 3
970+
with self.open(file_path) as f:
971+
assert f.read() == 'testbar'
972+
973+
def test_use_opener_with_write(self):
974+
file_path = self.make_path('foo')
975+
self.create_file(file_path, contents='foo')
976+
with self.open(file_path, 'w', opener=self.opener) as f:
977+
with self.assertRaises(OSError):
978+
f.read()
979+
assert f.write('bar') == 3
980+
with self.open(file_path) as f:
981+
assert f.read() == 'bar'
982+
983+
def test_use_opener_with_write_plus(self):
984+
file_path = self.make_path('foo')
985+
self.create_file(file_path, contents='test')
986+
with self.open(file_path, 'w+', opener=self.opener) as f:
987+
assert f.read() == ''
988+
assert f.write('bar') == 3
989+
with self.open(file_path) as f:
990+
assert f.read() == 'bar'
991+
992+
def test_use_opener_with_append(self):
993+
file_path = self.make_path('foo')
994+
self.create_file(file_path, contents='foo')
995+
with self.open(file_path, 'a', opener=self.opener) as f:
996+
assert f.write('bar') == 3
997+
with self.assertRaises(OSError):
998+
f.read()
999+
with self.open(file_path) as f:
1000+
assert f.read() == 'foobar'
1001+
1002+
def test_use_opener_with_append_plus(self):
1003+
file_path = self.make_path('foo')
1004+
self.create_file(file_path, contents='foo')
1005+
with self.open(file_path, 'a+', opener=self.opener) as f:
1006+
assert f.read() == ''
1007+
assert f.write('bar') == 3
1008+
with self.open(file_path) as f:
1009+
assert f.read() == 'foobar'
1010+
1011+
def test_use_opener_with_exclusive_write(self):
1012+
file_path = self.make_path('foo')
1013+
self.create_file(file_path, contents='test')
1014+
with self.assertRaises(OSError):
1015+
self.open(file_path, 'x', opener=self.opener)
1016+
1017+
file_path = self.make_path('bar')
1018+
with self.open(file_path, 'x', opener=self.opener) as f:
1019+
assert f.write('bar') == 3
1020+
with self.assertRaises(OSError):
1021+
f.read()
1022+
with self.open(file_path) as f:
1023+
assert f.read() == 'bar'
1024+
1025+
def test_use_opener_with_exclusive_plus(self):
1026+
file_path = self.make_path('foo')
1027+
self.create_file(file_path, contents='test')
1028+
with self.assertRaises(OSError):
1029+
self.open(file_path, 'x+', opener=self.opener)
1030+
1031+
file_path = self.make_path('bar')
1032+
with self.open(file_path, 'x+', opener=self.opener) as f:
1033+
assert f.write('bar') == 3
1034+
assert f.read() == ''
1035+
with self.open(file_path) as f:
1036+
assert f.read() == 'bar'
1037+
1038+
1039+
class RealFileOpenWithOpenerTest(FakeFileOpenWithOpenerTest):
1040+
def use_real_fs(self):
1041+
return True
1042+
1043+
9521044
@unittest.skipIf(sys.version_info < (3, 8),
9531045
'open_code only present since Python 3.8')
9541046
class FakeFilePatchedOpenCodeTest(FakeFileOpenTestBase):

0 commit comments

Comments
 (0)