From bee495182e457719a02fb81519bdcb5303db1983 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Fri, 23 Sep 2022 11:27:25 -0700 Subject: [PATCH 1/4] drop python2 compatibility, it's been EOL'd for years now --- tests.py | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/tests.py b/tests.py index 9380e63..1bf66d2 100644 --- a/tests.py +++ b/tests.py @@ -33,8 +33,6 @@ import io from libarchive import Archive, is_archive_name, is_archive from libarchive.zip import is_zipfile, ZipFile, ZipEntry -PY3 = sys.version_info[0] == 3 - TMPDIR = tempfile.mkdtemp(suffix='.python-libarchive') ZIPFILE = 'test.zip' ZIPPATH = os.path.join(TMPDIR, ZIPFILE) @@ -204,10 +202,7 @@ class TestZipWrite(unittest.TestCase): data = i.read(1) if not data: break - if PY3: - o.write(data) - else: - o.write(unicode(data)) + o.write(data) o.close() i.close() z.close() @@ -222,10 +217,7 @@ class TestZipWrite(unittest.TestCase): data = i.read(1) if not data: break - if PY3: - o.write(data) - else: - o.write(unicode(data)) + o.write(data) o.close() i.close() z.close() @@ -237,10 +229,7 @@ class TestZipWrite(unittest.TestCase): z.close() self.assertIsNotNone(z._a) self.assertIsNotNone(z._stream) - if PY3: - o.write('testdata') - else: - o.write(unicode('testdata')) + o.write('testdata') o.close() self.assertIsNone(z._a) self.assertIsNone(z._stream) @@ -269,12 +258,8 @@ ITEM_NAME='test.txt' ZIP1_PWD='pwd' ZIP2_PWD='12345' def create_file_from_content(): - if PY3: - with open(ZIPPATH, mode='wb') as f: - f.write(base64.b64decode(ZIP_CONTENT)) - else: - with open(ZIPPATH, mode='w') as f: - f.write(base64.b64decode(ZIP_CONTENT)) + with open(ZIPPATH, mode='wb') as f: + f.write(base64.b64decode(ZIP_CONTENT)) def create_protected_zip(): @@ -293,10 +278,7 @@ class TestProtectedReading(unittest.TestCase): def test_read_with_password(self): z = ZipFile(ZIPPATH, 'r', password=ZIP1_PWD) - if PY3: - self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) - else: - self.assertEqual(z.read(ITEM_NAME), ITEM_CONTENT) + self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) z.close() def test_read_without_password(self): @@ -318,10 +300,7 @@ class TestProtectedWriting(unittest.TestCase): def test_read_with_password(self): z = ZipFile(ZIPPATH, 'r', password=ZIP2_PWD) - if PY3: - self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) - else: - self.assertEqual(z.read(ITEM_NAME), ITEM_CONTENT) + self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) z.close() def test_read_without_password(self): @@ -336,10 +315,7 @@ class TestProtectedWriting(unittest.TestCase): def test_read_with_password_list(self): z = ZipFile(ZIPPATH, 'r', password=[ZIP1_PWD, ZIP2_PWD]) - if PY3: - self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) - else: - self.assertEqual(z.read(ITEM_NAME), ITEM_CONTENT) + self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) z.close() From 3878bbdfec4ec52b81d8232605bcb72c3b1d60c7 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Fri, 23 Sep 2022 12:02:56 -0700 Subject: [PATCH 2/4] fix up tests so that the temp dir is cleaned up afterward --- tests.py | 140 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 60 deletions(-) diff --git a/tests.py b/tests.py index 1bf66d2..2b15aaa 100644 --- a/tests.py +++ b/tests.py @@ -27,16 +27,13 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import os, unittest, tempfile, random, string, sys -import zipfile import io +import shutil +import zipfile from libarchive import Archive, is_archive_name, is_archive from libarchive.zip import is_zipfile, ZipFile, ZipEntry -TMPDIR = tempfile.mkdtemp(suffix='.python-libarchive') -ZIPFILE = 'test.zip' -ZIPPATH = os.path.join(TMPDIR, ZIPFILE) - FILENAMES = [ 'test1.txt', 'foo', @@ -44,19 +41,31 @@ FILENAMES = [ #'álért.txt', ] +class MakeTempMixIn: + def setUp(self): + self.TMPDIR = tempfile.mkdtemp(suffix='.python-libarchive') + self.ZIPFILE = 'test.zip' + self.ZIPPATH = os.path.join(self.TMPDIR, self.ZIPFILE) -def make_temp_files(): - if not os.path.exists(ZIPPATH): - for name in FILENAMES: - with open(os.path.join(TMPDIR, name), 'w') as f: - f.write(''.join(random.sample(string.ascii_letters, 10))) + def tearDown(self): + shutil.rmtree(self.TMPDIR) + self.TMPDIR = None + self.ZIPFILE = None + self.ZIPPATH = None -def make_temp_archive(): - make_temp_files() - with zipfile.ZipFile(ZIPPATH, mode="w") as z: - for name in FILENAMES: - z.write(os.path.join(TMPDIR, name), arcname=name) + def make_temp_files(self): + if not os.path.exists(self.ZIPPATH): + for name in FILENAMES: + with open(os.path.join(self.TMPDIR, name), 'w') as f: + f.write(''.join(random.sample(string.ascii_letters, 10))) + + + def make_temp_archive(self): + self.make_temp_files() + with zipfile.ZipFile(self.ZIPPATH, mode="w") as z: + for name in FILENAMES: + z.write(os.path.join(self.TMPDIR, name), arcname=name) class TestIsArchiveName(unittest.TestCase): @@ -72,14 +81,18 @@ class TestIsArchiveName(unittest.TestCase): self.assertEqual(is_archive_name('foo.rpm'), 'cpio') -class TestIsArchiveZip(unittest.TestCase): +class TestIsArchiveZip(unittest.TestCase, MakeTempMixIn): def setUp(self): - make_temp_archive() + MakeTempMixIn.setUp(self) + self.make_temp_archive() + + def tearDown(self): + MakeTempMixIn.tearDown(self) def test_zip(self): - self.assertEqual(is_archive(ZIPPATH), True) - self.assertEqual(is_archive(ZIPPATH, formats=('zip',)), True) - self.assertEqual(is_archive(ZIPPATH, formats=('tar',)), False) + self.assertEqual(is_archive(self.ZIPPATH), True) + self.assertEqual(is_archive(self.ZIPPATH, formats=('zip',)), True) + self.assertEqual(is_archive(self.ZIPPATH, formats=('tar',)), False) class TestIsArchiveTar(unittest.TestCase): @@ -89,17 +102,19 @@ class TestIsArchiveTar(unittest.TestCase): # TODO: incorporate tests from: # http://hg.python.org/cpython/file/a6e1d926cd98/Lib/test/test_zipfile.py -class TestZipRead(unittest.TestCase): +class TestZipRead(unittest.TestCase, MakeTempMixIn): def setUp(self): - make_temp_archive() - self.f = open(ZIPPATH, mode='r') + MakeTempMixIn.setUp(self) + self.make_temp_archive() + self.f = open(self.ZIPPATH, mode='r') def tearDown(self): self.f.close() + MakeTempMixIn.tearDown(self) def test_iszipfile(self): self.assertEqual(is_zipfile('/dev/null'), False) - self.assertEqual(is_zipfile(ZIPPATH), True) + self.assertEqual(is_zipfile(self.ZIPPATH), True) def test_iterate(self): z = ZipFile(self.f, 'r') @@ -158,18 +173,20 @@ class TestZipRead(unittest.TestCase): pass -class TestZipWrite(unittest.TestCase): +class TestZipWrite(unittest.TestCase, MakeTempMixIn): def setUp(self): - make_temp_files() - self.f = open(ZIPPATH, mode='w') + MakeTempMixIn.setUp(self) + self.make_temp_files() + self.f = open(self.ZIPPATH, mode='w') def tearDown(self): self.f.close() + MakeTempMixIn.tearDown(self) def test_writepath(self): z = ZipFile(self.f, 'w') for fname in FILENAMES: - with open(os.path.join(TMPDIR, fname), 'r') as f: + with open(os.path.join(self.TMPDIR, fname), 'r') as f: z.writepath(f) z.close() @@ -182,7 +199,7 @@ class TestZipWrite(unittest.TestCase): z.close() self.f.close() - f = open(ZIPPATH, mode='r') + f = open(self.ZIPPATH, mode='r') z = ZipFile(f, 'r') entries = z.infolist() @@ -195,7 +212,7 @@ class TestZipWrite(unittest.TestCase): def test_writestream(self): z = ZipFile(self.f, 'w') for fname in FILENAMES: - full_path = os.path.join(TMPDIR, fname) + full_path = os.path.join(self.TMPDIR, fname) i = open(full_path) o = z.writestream(fname) while True: @@ -210,7 +227,7 @@ class TestZipWrite(unittest.TestCase): def test_writestream_unbuffered(self): z = ZipFile(self.f, 'w') for fname in FILENAMES: - full_path = os.path.join(TMPDIR, fname) + full_path = os.path.join(self.TMPDIR, fname) i = open(full_path) o = z.writestream(fname, os.path.getsize(full_path)) while True: @@ -257,72 +274,75 @@ ITEM_NAME='test.txt' ZIP1_PWD='pwd' ZIP2_PWD='12345' -def create_file_from_content(): - with open(ZIPPATH, mode='wb') as f: - f.write(base64.b64decode(ZIP_CONTENT)) +class TestProtectedReading(unittest.TestCase, MakeTempMixIn): + def create_file_from_content(self): + with open(self.ZIPPATH, mode='wb') as f: + f.write(base64.b64decode(ZIP_CONTENT)) -def create_protected_zip(): - z = ZipFile(ZIPPATH, mode='w', password=ZIP2_PWD) - z.writestr(ITEM_NAME, ITEM_CONTENT) - z.close() - - -class TestProtectedReading(unittest.TestCase): def setUp(self): - create_file_from_content() - + MakeTempMixIn.setUp(self) + self.create_file_from_content() def tearDown(self): - os.remove(ZIPPATH) + MakeTempMixIn.tearDown(self) def test_read_with_password(self): - z = ZipFile(ZIPPATH, 'r', password=ZIP1_PWD) + z = ZipFile(self.ZIPPATH, 'r', password=ZIP1_PWD) self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) z.close() def test_read_without_password(self): - z = ZipFile(ZIPPATH, 'r') + z = ZipFile(self.ZIPPATH, 'r') self.assertRaises(RuntimeError, z.read, ITEM_NAME) z.close() def test_read_with_wrong_password(self): - z = ZipFile(ZIPPATH, 'r', password='wrong') + z = ZipFile(self.ZIPPATH, 'r', password='wrong') self.assertRaises(RuntimeError, z.read, ITEM_NAME) z.close() -class TestProtectedWriting(unittest.TestCase): +class TestProtectedWriting(unittest.TestCase, MakeTempMixIn): + def create_protected_zip(self): + z = ZipFile(self.ZIPPATH, mode='w', password=ZIP2_PWD) + z.writestr(ITEM_NAME, ITEM_CONTENT) + z.close() + def setUp(self): - create_protected_zip() + MakeTempMixIn.setUp(self) + self.create_protected_zip() def tearDown(self): - os.remove(ZIPPATH) + MakeTempMixIn.tearDown(self) def test_read_with_password(self): - z = ZipFile(ZIPPATH, 'r', password=ZIP2_PWD) + z = ZipFile(self.ZIPPATH, 'r', password=ZIP2_PWD) self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) z.close() def test_read_without_password(self): - z = ZipFile(ZIPPATH, 'r') + z = ZipFile(self.ZIPPATH, 'r') self.assertRaises(RuntimeError, z.read, ITEM_NAME) z.close() def test_read_with_wrong_password(self): - z = ZipFile(ZIPPATH, 'r', password='wrong') + z = ZipFile(self.ZIPPATH, 'r', password='wrong') self.assertRaises(RuntimeError, z.read, ITEM_NAME) z.close() def test_read_with_password_list(self): - z = ZipFile(ZIPPATH, 'r', password=[ZIP1_PWD, ZIP2_PWD]) + z = ZipFile(self.ZIPPATH, 'r', password=[ZIP1_PWD, ZIP2_PWD]) self.assertEqual(z.read(ITEM_NAME), bytes(ITEM_CONTENT, 'utf-8')) z.close() - -class TestHighLevelAPI(unittest.TestCase): +class TestHighLevelAPI(unittest.TestCase, MakeTempMixIn): def setUp(self): - make_temp_archive() + MakeTempMixIn.setUp(self) + self.make_temp_archive() + + def tearDown(self): + MakeTempMixIn.tearDown(self) def _test_listing_content(self, f): """Test helper capturing file paths while iterating the archive.""" @@ -335,16 +355,16 @@ class TestHighLevelAPI(unittest.TestCase): def test_open_by_name(self): """Test an archive opened directly by name.""" - self._test_listing_content(ZIPPATH) + self._test_listing_content(self.ZIPPATH) def test_open_by_named_fobj(self): """Test an archive using a file-like object opened by name.""" - with open(ZIPPATH, 'rb') as f: + with open(self.ZIPPATH, 'rb') as f: self._test_listing_content(f) def test_open_by_unnamed_fobj(self): """Test an archive using file-like object opened by fileno().""" - with open(ZIPPATH, 'rb') as zf: + with open(self.ZIPPATH, 'rb') as zf: with io.FileIO(zf.fileno(), mode='r', closefd=False) as f: self._test_listing_content(f) From ba5832c545fff8ed1041b37ff22ee6dd21e754b8 Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Fri, 23 Sep 2022 13:54:30 -0700 Subject: [PATCH 3/4] separate closing from deferred closing for streams.. make context work... don't leak file in SeekableArchive.. --- fixtures/testfile.tar.gz | Bin 0 -> 178 bytes libarchive/__init__.py | 16 +++++++------ tests.py | 47 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 fixtures/testfile.tar.gz diff --git a/fixtures/testfile.tar.gz b/fixtures/testfile.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..2ccd6716f025391fe8b582b7dbe21b108130d995 GIT binary patch literal 178 zcmV;j08RfNiwFQ1p(bMh1MQT-4#FS|Ksoyr{Q_-Sf$!M?bVfZ$jefo$$-J1w!<;ep zg`_3)P*NTev!vk=^X3$ Date: Fri, 23 Sep 2022 14:08:28 -0700 Subject: [PATCH 4/4] make sure that files aren't closed when passed in.. --- tests.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests.py b/tests.py index 9edfb9e..1795efb 100644 --- a/tests.py +++ b/tests.py @@ -415,6 +415,16 @@ class TestArchive(unittest.TestCase): self.assertTrue(arch.f.closed) + def test_noclose(self): + fname = self.fixtures / 'testfile.tar.gz' + + with open(fname) as fp: + with Archive(fp) as arch: + pass + + self.assertFalse(fp.closed) + + self.assertTrue(fp.closed) if __name__ == '__main__': unittest.main()