aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_pathlib/support/local_path.py23
-rw-r--r--Lib/test/test_pathlib/support/zip_path.py48
-rw-r--r--Lib/test/test_pathlib/test_pathlib_abc.py41
-rw-r--r--Lib/test/test_pathlib/test_write.py109
4 files changed, 178 insertions, 43 deletions
diff --git a/Lib/test/test_pathlib/support/local_path.py b/Lib/test/test_pathlib/support/local_path.py
index 1d2b03df225..1cf64316b40 100644
--- a/Lib/test/test_pathlib/support/local_path.py
+++ b/Lib/test/test_pathlib/support/local_path.py
@@ -1,5 +1,6 @@
"""
-Implementation of ReadablePath for local paths, for use in pathlib tests.
+Implementations of ReadablePath and WritablePath for local paths, for use in
+pathlib tests.
LocalPathGround is also defined here. It helps establish the "ground truth"
about local paths in tests.
@@ -143,3 +144,23 @@ class ReadableLocalPath(pathlib.types._ReadablePath, LexicalPath):
def readlink(self):
return self.with_segments(os.readlink(self))
+
+
+class WritableLocalPath(pathlib.types._WritablePath, LexicalPath):
+ """
+ Simple implementation of a WritablePath class for local filesystem paths.
+ """
+
+ __slots__ = ()
+
+ def __fspath__(self):
+ return str(self)
+
+ def __open_wb__(self, buffering=-1):
+ return open(self, 'wb')
+
+ def mkdir(self, mode=0o777):
+ os.mkdir(self, mode)
+
+ def symlink_to(self, target, target_is_directory=False):
+ os.symlink(target, self, target_is_directory)
diff --git a/Lib/test/test_pathlib/support/zip_path.py b/Lib/test/test_pathlib/support/zip_path.py
index ab6a929fc4a..4e24e35a03a 100644
--- a/Lib/test/test_pathlib/support/zip_path.py
+++ b/Lib/test/test_pathlib/support/zip_path.py
@@ -1,5 +1,6 @@
"""
-Implementation of ReadablePath for zip file members, for use in pathlib tests.
+Implementations of ReadablePath and WritablePath for zip file members, for use
+in pathlib tests.
ZipPathGround is also defined here. It helps establish the "ground truth"
about zip file members in tests.
@@ -276,3 +277,48 @@ class ReadableZipPath(pathlib.types._ReadablePath):
elif not info.is_symlink():
raise OSError(errno.EINVAL, "Not a symlink", self)
return self.with_segments(self.zip_file.read(info.zip_info).decode())
+
+
+class WritableZipPath(pathlib.types._WritablePath):
+ """
+ Simple implementation of a WritablePath class for .zip files.
+ """
+
+ __slots__ = ('_segments', 'zip_file')
+ parser = posixpath
+
+ def __init__(self, *pathsegments, zip_file):
+ self._segments = pathsegments
+ self.zip_file = zip_file
+
+ def __hash__(self):
+ return hash((str(self), self.zip_file))
+
+ def __eq__(self, other):
+ if not isinstance(other, WritableZipPath):
+ return NotImplemented
+ return str(self) == str(other) and self.zip_file is other.zip_file
+
+ def __str__(self):
+ if not self._segments:
+ return ''
+ return self.parser.join(*self._segments)
+
+ def __repr__(self):
+ return f'{type(self).__name__}({str(self)!r}, zip_file={self.zip_file!r})'
+
+ def with_segments(self, *pathsegments):
+ return type(self)(*pathsegments, zip_file=self.zip_file)
+
+ def __open_wb__(self, buffering=-1):
+ return self.zip_file.open(str(self), 'w')
+
+ def mkdir(self, mode=0o777):
+ self.zip_file.mkdir(str(self), mode)
+
+ def symlink_to(self, target, target_is_directory=False):
+ zinfo = zipfile.ZipInfo(str(self))._for_archive(self.zip_file)
+ zinfo.external_attr = stat.S_IFLNK << 16
+ if target_is_directory:
+ zinfo.external_attr |= 0x10
+ self.zip_file.writestr(zinfo, str(target))
diff --git a/Lib/test/test_pathlib/test_pathlib_abc.py b/Lib/test/test_pathlib/test_pathlib_abc.py
index 02e2a1da7ee..cff4e3372b7 100644
--- a/Lib/test/test_pathlib/test_pathlib_abc.py
+++ b/Lib/test/test_pathlib/test_pathlib_abc.py
@@ -336,10 +336,6 @@ class ReadablePathTest(JoinablePathTest):
class WritablePathTest(JoinablePathTest):
cls = DummyWritablePath
- def test_is_writable(self):
- p = self.cls(self.base)
- self.assertIsInstance(p, _WritablePath)
-
class DummyRWPath(DummyWritablePath, DummyReadablePath):
__slots__ = ()
@@ -349,43 +345,6 @@ class RWPathTest(WritablePathTest, ReadablePathTest):
cls = DummyRWPath
can_symlink = False
- def test_read_write_bytes(self):
- p = self.cls(self.base)
- (p / 'fileA').write_bytes(b'abcdefg')
- self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg')
- # Check that trying to write str does not truncate the file.
- self.assertRaises(TypeError, (p / 'fileA').write_bytes, 'somestr')
- self.assertEqual((p / 'fileA').read_bytes(), b'abcdefg')
-
- def test_read_write_text(self):
- p = self.cls(self.base)
- (p / 'fileA').write_text('äbcdefg', encoding='latin-1')
- self.assertEqual((p / 'fileA').read_text(
- encoding='utf-8', errors='ignore'), 'bcdefg')
- # Check that trying to write bytes does not truncate the file.
- self.assertRaises(TypeError, (p / 'fileA').write_text, b'somebytes')
- self.assertEqual((p / 'fileA').read_text(encoding='latin-1'), 'äbcdefg')
-
- def test_write_text_with_newlines(self):
- p = self.cls(self.base)
- # Check that `\n` character change nothing
- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\n')
- self.assertEqual((p / 'fileA').read_bytes(),
- b'abcde\r\nfghlk\n\rmnopq')
- # Check that `\r` character replaces `\n`
- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r')
- self.assertEqual((p / 'fileA').read_bytes(),
- b'abcde\r\rfghlk\r\rmnopq')
- # Check that `\r\n` character replaces `\n`
- (p / 'fileA').write_text('abcde\r\nfghlk\n\rmnopq', newline='\r\n')
- self.assertEqual((p / 'fileA').read_bytes(),
- b'abcde\r\r\nfghlk\r\n\rmnopq')
- # Check that no argument passed will change `\n` to `os.linesep`
- os_linesep_byte = bytes(os.linesep, encoding='ascii')
- (p / 'fileA').write_text('abcde\nfghlk\n\rmnopq')
- self.assertEqual((p / 'fileA').read_bytes(),
- b'abcde' + os_linesep_byte + b'fghlk' + os_linesep_byte + b'\rmnopq')
-
def test_copy_file(self):
base = self.cls(self.base)
source = base / 'fileA'
diff --git a/Lib/test/test_pathlib/test_write.py b/Lib/test/test_pathlib/test_write.py
new file mode 100644
index 00000000000..3d6057fb9dd
--- /dev/null
+++ b/Lib/test/test_pathlib/test_write.py
@@ -0,0 +1,109 @@
+"""
+Tests for pathlib.types._WritablePath
+"""
+
+import io
+import os
+import unittest
+
+from pathlib import Path
+from pathlib.types import _WritablePath
+from pathlib._os import magic_open
+
+from test.test_pathlib.support.local_path import WritableLocalPath, LocalPathGround
+from test.test_pathlib.support.zip_path import WritableZipPath, ZipPathGround
+
+
+class WriteTestBase:
+ def setUp(self):
+ self.root = self.ground.setup()
+
+ def tearDown(self):
+ self.ground.teardown(self.root)
+
+ def test_is_writable(self):
+ self.assertIsInstance(self.root, _WritablePath)
+
+ def test_open_w(self):
+ p = self.root / 'fileA'
+ with magic_open(p, 'w') as f:
+ self.assertIsInstance(f, io.TextIOBase)
+ f.write('this is file A\n')
+ self.assertEqual(self.ground.readtext(p), 'this is file A\n')
+
+ def test_open_wb(self):
+ p = self.root / 'fileA'
+ with magic_open(p, 'wb') as f:
+ #self.assertIsInstance(f, io.BufferedWriter)
+ f.write(b'this is file A\n')
+ self.assertEqual(self.ground.readbytes(p), b'this is file A\n')
+
+ def test_write_bytes(self):
+ p = self.root / 'fileA'
+ p.write_bytes(b'abcdefg')
+ self.assertEqual(self.ground.readbytes(p), b'abcdefg')
+ # Check that trying to write str does not truncate the file.
+ self.assertRaises(TypeError, p.write_bytes, 'somestr')
+ self.assertEqual(self.ground.readbytes(p), b'abcdefg')
+
+ def test_write_text(self):
+ p = self.root / 'fileA'
+ p.write_text('äbcdefg', encoding='latin-1')
+ self.assertEqual(self.ground.readbytes(p), b'\xe4bcdefg')
+ # Check that trying to write bytes does not truncate the file.
+ self.assertRaises(TypeError, p.write_text, b'somebytes')
+ self.assertEqual(self.ground.readbytes(p), b'\xe4bcdefg')
+
+ def test_write_text_with_newlines(self):
+ # Check that `\n` character change nothing
+ p = self.root / 'fileA'
+ p.write_text('abcde\r\nfghlk\n\rmnopq', newline='\n')
+ self.assertEqual(self.ground.readbytes(p), b'abcde\r\nfghlk\n\rmnopq')
+
+ # Check that `\r` character replaces `\n`
+ p = self.root / 'fileB'
+ p.write_text('abcde\r\nfghlk\n\rmnopq', newline='\r')
+ self.assertEqual(self.ground.readbytes(p), b'abcde\r\rfghlk\r\rmnopq')
+
+ # Check that `\r\n` character replaces `\n`
+ p = self.root / 'fileC'
+ p.write_text('abcde\r\nfghlk\n\rmnopq', newline='\r\n')
+ self.assertEqual(self.ground.readbytes(p), b'abcde\r\r\nfghlk\r\n\rmnopq')
+
+ # Check that no argument passed will change `\n` to `os.linesep`
+ os_linesep_byte = bytes(os.linesep, encoding='ascii')
+ p = self.root / 'fileD'
+ p.write_text('abcde\nfghlk\n\rmnopq')
+ self.assertEqual(self.ground.readbytes(p),
+ b'abcde' + os_linesep_byte +
+ b'fghlk' + os_linesep_byte + b'\rmnopq')
+
+ def test_mkdir(self):
+ p = self.root / 'newdirA'
+ self.assertFalse(self.ground.isdir(p))
+ p.mkdir()
+ self.assertTrue(self.ground.isdir(p))
+
+ def test_symlink_to(self):
+ if not self.ground.can_symlink:
+ self.skipTest('needs symlinks')
+ link = self.root.joinpath('linkA')
+ link.symlink_to('fileA')
+ self.assertTrue(self.ground.islink(link))
+ self.assertEqual(self.ground.readlink(link), 'fileA')
+
+
+class ZipPathWriteTest(WriteTestBase, unittest.TestCase):
+ ground = ZipPathGround(WritableZipPath)
+
+
+class LocalPathWriteTest(WriteTestBase, unittest.TestCase):
+ ground = LocalPathGround(WritableLocalPath)
+
+
+class PathWriteTest(WriteTestBase, unittest.TestCase):
+ ground = LocalPathGround(Path)
+
+
+if __name__ == "__main__":
+ unittest.main()