From 5347ec98acaf265f682845f83ec09c2795a2b64c Mon Sep 17 00:00:00 2001 From: Louis Sautier Date: Sun, 16 Jun 2024 23:09:01 +0200 Subject: [PATCH] Fix ResourceWarning in tests (and more) (#225) * Fix ResourceWarnings caused by open().read() For instance: ``` aeidon/test/test_encodings.py:166: ResourceWarning: unclosed file <_io.BufferedReader name='/tmp/gaupol-my14g87e.srt'> blob = open(path, "rb").read() ``` * Fix ResourceWarnings caused by open().write() For example: ``` aeidon/test/test_encodings.py:167: ResourceWarning: unclosed file <_io.BufferedWriter name='/tmp/gaupol-my14g87e.srt'> open(path, "wb").write(codecs.BOM_UTF16_BE + blob) ``` * Fix mode ResourceWarnings by replacing f = open() Some of these changes are not strictly necessary as the file descriptor was properly closed in some cases but I decided to change them for increased consistency. --- aeidon/agents/test/test_open.py | 12 ++++--- aeidon/files/test/test_ass.py | 3 +- aeidon/files/test/test_lrc.py | 3 +- aeidon/files/test/test_microdvd.py | 3 +- aeidon/files/test/test_mpl2.py | 3 +- aeidon/files/test/test_ssa.py | 3 +- aeidon/files/test/test_subrip.py | 3 +- aeidon/files/test/test_subviewer2.py | 3 +- aeidon/files/test/test_tmplayer.py | 3 +- aeidon/files/test/test_webvtt.py | 3 +- aeidon/test/test_encodings.py | 30 ++++++++++------ aeidon/test/test_temp.py | 6 ++-- aeidon/test/test_util.py | 43 +++++++++++++--------- gaupol/config.py | 43 +++++++++++----------- setup-aeidon.py | 5 ++- setup.py | 54 ++++++++++++++-------------- 16 files changed, 129 insertions(+), 91 deletions(-) diff --git a/aeidon/agents/test/test_open.py b/aeidon/agents/test/test_open.py index 569232c3..1945c8fd 100644 --- a/aeidon/agents/test/test_open.py +++ b/aeidon/agents/test/test_open.py @@ -32,8 +32,10 @@ def test_open_main(self): def test_open_main__bom(self): path = self.new_subrip_file() - blob = open(path, "rb").read() - open(path, "wb").write(codecs.BOM_UTF8 + blob) + with open(path, "rb") as f: + blob = f.read() + with open(path, "wb") as f: + f.write(codecs.BOM_UTF8 + blob) self.project.open_main(path, "ascii") assert self.project.subtitles assert self.project.main_file.encoding == "utf_8_sig" @@ -61,8 +63,10 @@ def test_open_translation__align_position(self): def test_open_translation__bom(self): path = self.new_subrip_file() - blob = open(path, "rb").read() - open(path, "wb").write(codecs.BOM_UTF8 + blob) + with open(path, "rb") as f: + blob = f.read() + with open(path, "wb") as f: + f.write(codecs.BOM_UTF8 + blob) self.project.open_translation(path, "ascii") assert self.project.subtitles assert self.project.tran_file.encoding == "utf_8_sig" diff --git a/aeidon/files/test/test_ass.py b/aeidon/files/test/test_ass.py index 0a0f3ff0..cee763fe 100644 --- a/aeidon/files/test/test_ass.py +++ b/aeidon/files/test/test_ass.py @@ -33,5 +33,6 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format) diff --git a/aeidon/files/test/test_lrc.py b/aeidon/files/test/test_lrc.py index b3fb01b9..e1c80e7d 100644 --- a/aeidon/files/test/test_lrc.py +++ b/aeidon/files/test/test_lrc.py @@ -32,5 +32,6 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format, self.name) diff --git a/aeidon/files/test/test_microdvd.py b/aeidon/files/test/test_microdvd.py index 649f3f01..e82a7681 100644 --- a/aeidon/files/test/test_microdvd.py +++ b/aeidon/files/test/test_microdvd.py @@ -32,5 +32,6 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format) diff --git a/aeidon/files/test/test_mpl2.py b/aeidon/files/test/test_mpl2.py index 27a6f133..e4182a60 100644 --- a/aeidon/files/test/test_mpl2.py +++ b/aeidon/files/test/test_mpl2.py @@ -32,5 +32,6 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format) diff --git a/aeidon/files/test/test_ssa.py b/aeidon/files/test/test_ssa.py index 3169e4b7..45e24377 100644 --- a/aeidon/files/test/test_ssa.py +++ b/aeidon/files/test/test_ssa.py @@ -33,5 +33,6 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format) diff --git a/aeidon/files/test/test_subrip.py b/aeidon/files/test/test_subrip.py index 8486314f..6ddf16f1 100644 --- a/aeidon/files/test/test_subrip.py +++ b/aeidon/files/test/test_subrip.py @@ -32,7 +32,8 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format, self.name) diff --git a/aeidon/files/test/test_subviewer2.py b/aeidon/files/test/test_subviewer2.py index 675f559e..b1efb8a8 100644 --- a/aeidon/files/test/test_subviewer2.py +++ b/aeidon/files/test/test_subviewer2.py @@ -33,5 +33,6 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format) diff --git a/aeidon/files/test/test_tmplayer.py b/aeidon/files/test/test_tmplayer.py index ebc7c5c9..4173d1f6 100644 --- a/aeidon/files/test/test_tmplayer.py +++ b/aeidon/files/test/test_tmplayer.py @@ -32,7 +32,8 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format, self.name) diff --git a/aeidon/files/test/test_webvtt.py b/aeidon/files/test/test_webvtt.py index 8991379e..9811de98 100644 --- a/aeidon/files/test/test_webvtt.py +++ b/aeidon/files/test/test_webvtt.py @@ -32,5 +32,6 @@ def test_read(self): def test_write(self): self.file.write(self.file.read(), aeidon.documents.MAIN) - text = open(self.file.path, "r").read().strip() + with open(self.file.path, "r") as f: + text = f.read().strip() assert text == self.get_sample_text(self.format, self.name) diff --git a/aeidon/test/test_encodings.py b/aeidon/test/test_encodings.py index 7e597507..0ac3f662 100644 --- a/aeidon/test/test_encodings.py +++ b/aeidon/test/test_encodings.py @@ -163,40 +163,50 @@ def test_detect_bom__none(self): @patch("aeidon.encodings.is_valid_code", lambda x: True) def test_detect_bom__utf_16_be(self): path = self.new_subrip_file() - blob = open(path, "rb").read() - open(path, "wb").write(codecs.BOM_UTF16_BE + blob) + with open(path, "rb") as f: + blob = f.read() + with open(path, "wb") as f: + f.write(codecs.BOM_UTF16_BE + blob) encoding = aeidon.encodings.detect_bom(path) assert encoding == "utf_16_be" @patch("aeidon.encodings.is_valid_code", lambda x: True) def test_detect_bom__utf_16_le(self): path = self.new_subrip_file() - blob = open(path, "rb").read() - open(path, "wb").write(codecs.BOM_UTF16_LE + blob) + with open(path, "rb") as f: + blob = f.read() + with open(path, "wb") as f: + f.write(codecs.BOM_UTF16_LE + blob) encoding = aeidon.encodings.detect_bom(path) assert encoding == "utf_16_le" @patch("aeidon.encodings.is_valid_code", lambda x: True) def test_detect_bom__utf_32_be(self): path = self.new_subrip_file() - blob = open(path, "rb").read() - open(path, "wb").write(codecs.BOM_UTF32_BE + blob) + with open(path, "rb") as f: + blob = f.read() + with open(path, "wb") as f: + f.write(codecs.BOM_UTF32_BE + blob) encoding = aeidon.encodings.detect_bom(path) assert encoding == "utf_32_be" @patch("aeidon.encodings.is_valid_code", lambda x: True) def test_detect_bom__utf_32_le(self): path = self.new_subrip_file() - blob = open(path, "rb").read() - open(path, "wb").write(codecs.BOM_UTF32_LE + blob) + with open(path, "rb") as f: + blob = f.read() + with open(path, "wb") as f: + f.write(codecs.BOM_UTF32_LE + blob) encoding = aeidon.encodings.detect_bom(path) assert encoding == "utf_32_le" @patch("aeidon.encodings.is_valid_code", lambda x: True) def test_detect_bom__utf_8_sig(self): path = self.new_subrip_file() - blob = open(path, "rb").read() - open(path, "wb").write(codecs.BOM_UTF8 + blob) + with open(path, "rb") as f: + blob = f.read() + with open(path, "wb") as f: + f.write(codecs.BOM_UTF8 + blob) encoding = aeidon.encodings.detect_bom(path) assert encoding == "utf_8_sig" diff --git a/aeidon/test/test_temp.py b/aeidon/test/test_temp.py index dd43b96b..e4cfa814 100644 --- a/aeidon/test/test_temp.py +++ b/aeidon/test/test_temp.py @@ -31,8 +31,10 @@ def test_create_directory(self): def test_remove__directory(self): path = aeidon.temp.create_directory() - open(os.path.join(path, "a"), "w").write("a") - open(os.path.join(path, "b"), "w").write("b") + with open(os.path.join(path, "a"), "w") as f: + f.write("a") + with open(os.path.join(path, "b"), "w") as f: + f.write("b") os.makedirs(os.path.join(path, "c")) aeidon.temp.remove(path) assert not os.path.isdir(path) diff --git a/aeidon/test/test_util.py b/aeidon/test/test_util.py index 68461139..f1077e16 100644 --- a/aeidon/test/test_util.py +++ b/aeidon/test/test_util.py @@ -24,14 +24,16 @@ def test_atomic_open__existing_file(self): path = self.new_subrip_file() with aeidon.util.atomic_open(path, "w") as f: f.write("test\n") - text = open(path, "r").read() + with open(path, "r") as f: + text = f.read() assert text == "test\n" def test_atomic_open__no_existing_file(self): path = aeidon.temp.create() with aeidon.util.atomic_open(path, "w") as f: f.write("test\n") - text = open(path, "r").read() + with open(path, "r") as f: + text = f.read() assert text == "test\n" def test_compare_versions(self): @@ -48,19 +50,22 @@ def test_detect_format(self): def test_detect_newlines__mac(self): path = aeidon.temp.create() - open(path, "w", newline="").write("a\rb\rc\r") + with open(path, "w", newline="") as f: + f.write("a\rb\rc\r") newlines = aeidon.util.detect_newlines(path) assert newlines == aeidon.newlines.MAC def test_detect_newlines__unix(self): path = aeidon.temp.create() - open(path, "w", newline="").write("a\nb\nc\n") + with open(path, "w", newline="") as f: + f.write("a\nb\nc\n") newlines = aeidon.util.detect_newlines(path) assert newlines == aeidon.newlines.UNIX def test_detect_newlines__windows(self): path = aeidon.temp.create() - open(path, "w", newline="").write("a\r\nb\r\nc\r\n") + with open(path, "w", newline="") as f: + f.write("a\r\nb\r\nc\r\n") newlines = aeidon.util.detect_newlines(path) assert newlines == aeidon.newlines.WINDOWS @@ -96,48 +101,52 @@ def test_get_unique__last(self): def test_read__basic(self): path = self.new_subrip_file() - text = open(path, "r", encoding="ascii").read().strip() + with open(path, "r", encoding="ascii") as f: + text = f.read().strip() assert aeidon.util.read(path) == text def test_read__fallback(self): path = self.new_subrip_file() - open(path, "w", encoding="utf_8").write("\xc3\xb6\n") + with open(path, "w", encoding="utf_8") as f: + f.write("\xc3\xb6\n") assert aeidon.util.read(path, "ascii") == "\xc3\xb6" def test_readlines__basic(self): path = self.new_subrip_file() - lines = [x.rstrip() for x in open(path, "r").readlines()] + with open(path, "r") as f: + lines = [x.rstrip() for x in f.readlines()] assert aeidon.util.readlines(path) == lines def test_readlines__fallback(self): path = self.new_subrip_file() - open(path, "w", encoding="utf_8").write("\xc3\xb6\n") + with open(path, "w", encoding="utf_8") as f: + f.write("\xc3\xb6\n") assert aeidon.util.readlines(path, "ascii") == ["\xc3\xb6"] def test_write__basic(self): text = "test\ntest\n" path = self.new_subrip_file() aeidon.util.write(path, text) - f = open(path, "r", encoding="ascii") - assert f.read() == text + with open(path, "r", encoding="ascii") as f: + assert f.read() == text def test_write__fallback(self): text = "\xc3\xb6\n" path = self.new_subrip_file() aeidon.util.write(path, text, "ascii") - f = open(path, "r", encoding="utf_8") - assert f.read() == text + with open(path, "r", encoding="utf_8") as f: + assert f.read() == text def test_writelines__basic(self): lines = ("test", "test") path = self.new_subrip_file() aeidon.util.writelines(path, lines) - f = open(path, "r", encoding="ascii") - assert f.read() == "test\ntest\n" + with open(path, "r", encoding="ascii") as f: + assert f.read() == "test\ntest\n" def test_writelines__fallback(self): text = "\xc3\xb6" path = self.new_subrip_file() aeidon.util.writelines(path, (text,), "ascii") - f = open(path, "r", encoding="utf_8") - assert f.read() == text + "\n" + with open(path, "r", encoding="utf_8") as f: + assert f.read() == text + "\n" diff --git a/gaupol/config.py b/gaupol/config.py index fa23bea5..ad4a4244 100644 --- a/gaupol/config.py +++ b/gaupol/config.py @@ -474,28 +474,27 @@ def _write_to_file(self): encoding = aeidon.util.get_default_encoding() # Ignore possible encoding errors, which are only related to # saved file and directory names and not in any way critical. - f = open(self.path, "w", encoding=encoding, errors="replace") - root = self._flatten(self._root) - defaults = self._flatten(self._defaults) - for section in sorted(root): - f.write("\n[{}]\n".format(section)) - for option in sorted(root[section]): - value = root[section][option] - json_value = json.dumps( - value, cls=EnumEncoder, ensure_ascii=False) - # Discard removed options, but always keep - # all options of all extensions. - if (not section.startswith("extensions::") - and (not section in defaults or - not option in defaults[section])): continue - # Write options that remain at their default value - # (perhaps, but not necessarily unset) as commented out. - if (section in defaults - and option in defaults[section] - and value == defaults[section][option]): - f.write("# ") - f.write("{} = {}\n".format(option, json_value)) - f.close() + with open(self.path, "w", encoding=encoding, errors="replace") as f: + root = self._flatten(self._root) + defaults = self._flatten(self._defaults) + for section in sorted(root): + f.write("\n[{}]\n".format(section)) + for option in sorted(root[section]): + value = root[section][option] + json_value = json.dumps( + value, cls=EnumEncoder, ensure_ascii=False) + # Discard removed options, but always keep + # all options of all extensions. + if (not section.startswith("extensions::") + and (not section in defaults or + not option in defaults[section])): continue + # Write options that remain at their default value + # (perhaps, but not necessarily unset) as commented out. + if (section in defaults + and option in defaults[section] + and value == defaults[section][option]): + f.write("# ") + f.write("{} = {}\n".format(option, json_value)) def write_to_file(self): """Write values of configuration options to file.""" diff --git a/setup-aeidon.py b/setup-aeidon.py index a6879350..5c077efb 100755 --- a/setup-aeidon.py +++ b/setup-aeidon.py @@ -12,13 +12,16 @@ shutil.copytree("data/headers", "aeidon/data/headers") shutil.copytree("data/patterns", "aeidon/data/patterns") +with open("README.aeidon.md", "r") as f: + long_description = f.read() + setup( name="aeidon", version=get_aeidon_version(), author="Osmo Salomaa", author_email="otsaloma@iki.fi", description="Reading, writing and manipulating text-based subtitle files", - long_description=open("README.aeidon.md", "r").read(), + long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/otsaloma/gaupol", license="GPL", diff --git a/setup.py b/setup.py index 38bf1e0a..72193fd4 100755 --- a/setup.py +++ b/setup.py @@ -74,12 +74,14 @@ def get_aeidon_version(): path = os.path.join("aeidon", "__init__.py") - text = open(path, "r", encoding="utf_8").read() + with open(path, "r", encoding="utf_8") as f: + text = f.read() return re.search(r"__version__ *= *['\"](.*?)['\"]", text).group(1) def get_gaupol_version(): path = os.path.join("gaupol", "__init__.py") - text = open(path, "r", encoding="utf_8").read() + with open(path, "r", encoding="utf_8") as f: + text = f.read() return re.search(r"__version__ *= *['\"](.*?)['\"]", text).group(1) def run_or_exit(cmd): @@ -96,17 +98,16 @@ class Clean(clean): def run(self): clean.run(self) - f = open(os.path.join("manifests", "clean.manifest"), "r") - for targets in [glob.glob(x.strip()) for x in f]: - for target in filter(os.path.isdir, targets): - log.info("removing {}".format(target)) - if not self.dry_run: - shutil.rmtree(target) - for target in filter(os.path.isfile, targets): - log.info("removing {}".format(target)) - if not self.dry_run: - os.remove(target) - f.close() + with open(os.path.join("manifests", "clean.manifest"), "r") as f: + for targets in [glob.glob(x.strip()) for x in f]: + for target in filter(os.path.isdir, targets): + log.info("removing {}".format(target)) + if not self.dry_run: + shutil.rmtree(target) + for target in filter(os.path.isfile, targets): + log.info("removing {}".format(target)) + if not self.dry_run: + os.remove(target) class Distribution(distribution): @@ -126,17 +127,16 @@ def __init__(self, attrs=None): def __find_data_files(self, name): fok = lambda x: not x.endswith((".in", ".pyc")) basename = "{}.manifest".format(name) - f = open(os.path.join("manifests", basename), "r") - for line in [x.strip() for x in f]: - if not line: continue - if line.startswith("["): - dest = line[1:-1] - continue - files = list(filter(fok, glob.glob(line))) - files = list(filter(os.path.isfile, files)) - assert files - self.data_files.append((dest, files)) - f.close() + with open(os.path.join("manifests", basename), "r") as f: + for line in [x.strip() for x in f]: + if not line: continue + if line.startswith("["): + dest = line[1:-1] + continue + files = list(filter(fok, glob.glob(line))) + files = list(filter(os.path.isfile, files)) + assert files + self.data_files.append((dest, files)) def __find_man_pages(self): mandir = self.mandir @@ -343,7 +343,8 @@ def install(self): locale_dir = os.path.join(prefix, "share", "locale") # Write changes to the aeidon.paths module. path = os.path.join(self.build_dir, "aeidon", "paths.py") - text = open(path, "r", encoding="utf_8").read() + with open(path, "r", encoding="utf_8") as f: + text = f.read() patt = r"^DATA_DIR = .*$" repl = "DATA_DIR = {!r}".format(data_dir) text = re.sub(patt, repl, text, flags=re.MULTILINE) @@ -352,7 +353,8 @@ def install(self): repl = "LOCALE_DIR = {!r}".format(locale_dir) text = re.sub(patt, repl, text, flags=re.MULTILINE) assert text.count(repl) == 1 - open(path, "w", encoding="utf_8").write(text) + with open(path, "w", encoding="utf_8") as f: + f.write(text) return install_lib.install(self)