Avoid ResourceWarning: unclosed file (#395)
A number of such warnings showed up when running e.g. PYTHONWARNINGS=always python build_examples.py PYTHONWARNINGS=always wireviz ../../examples/demo0?.yml See https://github.com/wireviz/WireViz/pull/309#issuecomment-2170988381 Fix: All open() calls should be in a "with open() as x" statement to ensure closing the file when exiting the block in any way. Otherwise, use the new file_read_text() or file_write_text() functions to read or write the whole utf-8 text file and closing it.
This commit is contained in:
parent
ee1bd7801e
commit
19cdff1774
@ -44,11 +44,10 @@ from wireviz.wv_gv_html import (
|
|||||||
)
|
)
|
||||||
from wireviz.wv_helper import (
|
from wireviz.wv_helper import (
|
||||||
awg_equiv,
|
awg_equiv,
|
||||||
|
file_write_text,
|
||||||
flatten2d,
|
flatten2d,
|
||||||
is_arrow,
|
is_arrow,
|
||||||
mm2_equiv,
|
mm2_equiv,
|
||||||
open_file_read,
|
|
||||||
open_file_write,
|
|
||||||
tuplelist2tsv,
|
tuplelist2tsv,
|
||||||
)
|
)
|
||||||
from wireviz.wv_html import generate_html_output
|
from wireviz.wv_html import generate_html_output
|
||||||
@ -693,7 +692,7 @@ class Harness:
|
|||||||
# BOM output
|
# BOM output
|
||||||
bomlist = bom_list(self.bom())
|
bomlist = bom_list(self.bom())
|
||||||
if "tsv" in fmt:
|
if "tsv" in fmt:
|
||||||
open_file_write(f"{filename}.bom.tsv").write(tuplelist2tsv(bomlist))
|
file_write_text(f"{filename}.bom.tsv", tuplelist2tsv(bomlist))
|
||||||
if "csv" in fmt:
|
if "csv" in fmt:
|
||||||
# TODO: implement CSV output (preferrably using CSV library)
|
# TODO: implement CSV output (preferrably using CSV library)
|
||||||
print("CSV output is not yet supported")
|
print("CSV output is not yet supported")
|
||||||
|
|||||||
@ -15,9 +15,9 @@ from wireviz.DataClasses import Metadata, Options, Tweak
|
|||||||
from wireviz.Harness import Harness
|
from wireviz.Harness import Harness
|
||||||
from wireviz.wv_helper import (
|
from wireviz.wv_helper import (
|
||||||
expand,
|
expand,
|
||||||
|
file_read_text,
|
||||||
get_single_key_and_value,
|
get_single_key_and_value,
|
||||||
is_arrow,
|
is_arrow,
|
||||||
open_file_read,
|
|
||||||
smart_file_resolve,
|
smart_file_resolve,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -409,7 +409,7 @@ def _get_yaml_data_and_path(inp: Union[str, Path, Dict]) -> (Dict, Path):
|
|||||||
try:
|
try:
|
||||||
yaml_path = Path(inp).expanduser().resolve(strict=True)
|
yaml_path = Path(inp).expanduser().resolve(strict=True)
|
||||||
# if no FileNotFoundError exception happens, get file contents
|
# if no FileNotFoundError exception happens, get file contents
|
||||||
yaml_str = open_file_read(yaml_path).read()
|
yaml_str = file_read_text(yaml_path)
|
||||||
except (FileNotFoundError, OSError, ValueError) as e:
|
except (FileNotFoundError, OSError, ValueError) as e:
|
||||||
# if inp is a long YAML string, Pathlib will normally raise
|
# if inp is a long YAML string, Pathlib will normally raise
|
||||||
# FileNotFoundError or OSError(errno = ENAMETOOLONG) when
|
# FileNotFoundError or OSError(errno = ENAMETOOLONG) when
|
||||||
|
|||||||
@ -11,7 +11,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
import wireviz.wireviz as wv
|
import wireviz.wireviz as wv
|
||||||
from wireviz import APP_NAME, __version__
|
from wireviz import APP_NAME, __version__
|
||||||
from wireviz.wv_helper import open_file_read
|
from wireviz.wv_helper import file_read_text
|
||||||
|
|
||||||
format_codes = {
|
format_codes = {
|
||||||
# "c": "csv",
|
# "c": "csv",
|
||||||
@ -111,7 +111,7 @@ def wireviz(file, format, prepend, output_dir, output_name, version):
|
|||||||
raise Exception(f"File does not exist:\n{prepend_file}")
|
raise Exception(f"File does not exist:\n{prepend_file}")
|
||||||
print("Prepend file:", prepend_file)
|
print("Prepend file:", prepend_file)
|
||||||
|
|
||||||
prepend_input += open_file_read(prepend_file).read() + "\n"
|
prepend_input += file_read_text(prepend_file) + "\n"
|
||||||
else:
|
else:
|
||||||
prepend_input = ""
|
prepend_input = ""
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ def wireviz(file, format, prepend, output_dir, output_name, version):
|
|||||||
"Output file: ", f"{Path(_output_dir / _output_name)}.{output_formats_str}"
|
"Output file: ", f"{Path(_output_dir / _output_name)}.{output_formats_str}"
|
||||||
)
|
)
|
||||||
|
|
||||||
yaml_input = open_file_read(file).read()
|
yaml_input = file_read_text(file)
|
||||||
file_dir = file.parent
|
file_dir = file.parent
|
||||||
|
|
||||||
yaml_input = prepend_input + yaml_input
|
yaml_input = prepend_input + yaml_input
|
||||||
|
|||||||
@ -113,18 +113,31 @@ def clean_whitespace(inp):
|
|||||||
|
|
||||||
|
|
||||||
def open_file_read(filename):
|
def open_file_read(filename):
|
||||||
|
"""Open utf-8 encoded text file for reading - remember closing it when finished"""
|
||||||
# TODO: Intelligently determine encoding
|
# TODO: Intelligently determine encoding
|
||||||
return open(filename, "r", encoding="UTF-8")
|
return open(filename, "r", encoding="UTF-8")
|
||||||
|
|
||||||
|
|
||||||
def open_file_write(filename):
|
def open_file_write(filename):
|
||||||
|
"""Open utf-8 encoded text file for writing - remember closing it when finished"""
|
||||||
return open(filename, "w", encoding="UTF-8")
|
return open(filename, "w", encoding="UTF-8")
|
||||||
|
|
||||||
|
|
||||||
def open_file_append(filename):
|
def open_file_append(filename):
|
||||||
|
"""Open utf-8 encoded text file for appending - remember closing it when finished"""
|
||||||
return open(filename, "a", encoding="UTF-8")
|
return open(filename, "a", encoding="UTF-8")
|
||||||
|
|
||||||
|
|
||||||
|
def file_read_text(filename: str) -> str:
|
||||||
|
"""Read utf-8 encoded text file, close it, and return the text"""
|
||||||
|
return Path(filename).read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def file_write_text(filename: str, text: str) -> int:
|
||||||
|
"""Write utf-8 encoded text file, close it, and return the number of characters written"""
|
||||||
|
return Path(filename).write_text(text, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
def is_arrow(inp):
|
def is_arrow(inp):
|
||||||
"""
|
"""
|
||||||
Matches strings of one or multiple `-` or `=` (but not mixed)
|
Matches strings of one or multiple `-` or `=` (but not mixed)
|
||||||
@ -144,10 +157,10 @@ def aspect_ratio(image_src):
|
|||||||
try:
|
try:
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
image = Image.open(image_src)
|
with Image.open(image_src) as image:
|
||||||
if image.width > 0 and image.height > 0:
|
if image.width > 0 and image.height > 0:
|
||||||
return image.width / image.height
|
return image.width / image.height
|
||||||
print(f"aspect_ratio(): Invalid image size {image.width} x {image.height}")
|
print(f"aspect_ratio(): Invalid image size {image.width} x {image.height}")
|
||||||
# ModuleNotFoundError and FileNotFoundError are the most expected, but all are handled equally.
|
# ModuleNotFoundError and FileNotFoundError are the most expected, but all are handled equally.
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
print(f"aspect_ratio(): {type(error).__name__}: {error}")
|
print(f"aspect_ratio(): {type(error).__name__}: {error}")
|
||||||
|
|||||||
@ -9,9 +9,9 @@ from wireviz.DataClasses import Metadata, Options
|
|||||||
from wireviz.svgembed import data_URI_base64
|
from wireviz.svgembed import data_URI_base64
|
||||||
from wireviz.wv_gv_html import html_line_breaks
|
from wireviz.wv_gv_html import html_line_breaks
|
||||||
from wireviz.wv_helper import (
|
from wireviz.wv_helper import (
|
||||||
|
file_read_text,
|
||||||
|
file_write_text,
|
||||||
flatten2d,
|
flatten2d,
|
||||||
open_file_read,
|
|
||||||
open_file_write,
|
|
||||||
smart_file_resolve,
|
smart_file_resolve,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,14 +35,14 @@ def generate_html_output(
|
|||||||
# fall back to built-in simple template if no template was provided
|
# fall back to built-in simple template if no template was provided
|
||||||
templatefile = Path(__file__).parent / "templates/simple.html"
|
templatefile = Path(__file__).parent / "templates/simple.html"
|
||||||
|
|
||||||
html = open_file_read(templatefile).read()
|
html = file_read_text(templatefile)
|
||||||
|
|
||||||
# embed SVG diagram (only if used)
|
# embed SVG diagram (only if used)
|
||||||
def svgdata() -> str:
|
def svgdata() -> str:
|
||||||
return re.sub(
|
return re.sub(
|
||||||
"^<[?]xml [^?>]*[?]>[^<]*<!DOCTYPE [^>]*>",
|
"^<[?]xml [^?>]*[?]>[^<]*<!DOCTYPE [^>]*>",
|
||||||
"<!-- XML and DOCTYPE declarations from SVG file removed -->",
|
"<!-- XML and DOCTYPE declarations from SVG file removed -->",
|
||||||
open_file_read(f"{filename}.tmp.svg").read(),
|
file_read_text(f"{filename}.tmp.svg"),
|
||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -128,4 +128,4 @@ def generate_html_output(
|
|||||||
pattern = re.compile("|".join(replacements_escaped))
|
pattern = re.compile("|".join(replacements_escaped))
|
||||||
html = pattern.sub(lambda match: replacements[match.group(0)], html)
|
html = pattern.sub(lambda match: replacements[match.group(0)], html)
|
||||||
|
|
||||||
open_file_write(f"{filename}.html").write(html)
|
file_write_text(f"{filename}.html", html)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user