From cc2fdf64719d844814dbebed67c33aa5c3c3bc1b Mon Sep 17 00:00:00 2001 From: Qin Muyan <301001071+loganbail@users.noreply.github.com> Date: Mon, 31 Aug 2026 02:25:21 +0800 Subject: [PATCH] fix: use context manager for file read in pdf_renderer.py --- backend/app/services/pdf_renderer.py | 3 +- backend/tests/test_pr_07_pdf_renderer_file.py | 75 +++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 backend/tests/test_pr_07_pdf_renderer_file.py diff --git a/backend/app/services/pdf_renderer.py b/backend/app/services/pdf_renderer.py index 30c1f376..aa768418 100644 --- a/backend/app/services/pdf_renderer.py +++ b/backend/app/services/pdf_renderer.py @@ -52,7 +52,8 @@ def compile_latex_project(project_dir: str, main_tex: str = "main.tex", engine: def _requires_xelatex(main_tex_path: str) -> bool: try: - content = open(main_tex_path, "r", encoding="utf-8", errors="ignore").read(4096) + with open(main_tex_path, "r", encoding="utf-8", errors="ignore") as f: + content = f.read(4096) except OSError: return False return any(marker in content for marker in ("ctexart", "ctexbook", "ctexrep", "xeCJK", "fontspec")) diff --git a/backend/tests/test_pr_07_pdf_renderer_file.py b/backend/tests/test_pr_07_pdf_renderer_file.py new file mode 100644 index 00000000..771cc7eb --- /dev/null +++ b/backend/tests/test_pr_07_pdf_renderer_file.py @@ -0,0 +1,75 @@ +"""Test that pdf_renderer.py uses context managers for file reads. + +Verifies that _requires_xelatex correctly detects XeTeX markers and that +no unclosed file reads remain in the module. +""" +import os +import re +import tempfile + + +def test_requires_xelatex_with_ctexart(): + """_requires_xelatex should return True for files using ctexart.""" + from app.services.pdf_renderer import _requires_xelatex + + with tempfile.NamedTemporaryFile(mode="w", suffix=".tex", delete=False, encoding="utf-8") as f: + f.write("\\documentclass{ctexart}\n\\begin{document}\nHello\n\\end{document}\n") + path = f.name + + try: + assert _requires_xelatex(path) is True + finally: + os.unlink(path) + + +def test_requires_xelatex_with_standard_latex(): + """_requires_xelatex should return False for standard LaTeX without CJK markers.""" + from app.services.pdf_renderer import _requires_xelatex + + with tempfile.NamedTemporaryFile(mode="w", suffix=".tex", delete=False, encoding="utf-8") as f: + f.write("\\documentclass{article}\n\\begin{document}\nHello world\n\\end{document}\n") + path = f.name + + try: + assert _requires_xelatex(path) is False + finally: + os.unlink(path) + + +def test_requires_xelatex_with_fontspec(): + """_requires_xelatex should return True for files using fontspec.""" + from app.services.pdf_renderer import _requires_xelatex + + with tempfile.NamedTemporaryFile(mode="w", suffix=".tex", delete=False, encoding="utf-8") as f: + f.write("\\documentclass{article}\n\\usepackage{fontspec}\n\\begin{document}\nTest\n\\end{document}\n") + path = f.name + + try: + assert _requires_xelatex(path) is True + finally: + os.unlink(path) + + +def test_requires_xelatex_missing_file(): + """_requires_xelatex should return False for nonexistent files.""" + from app.services.pdf_renderer import _requires_xelatex + + assert _requires_xelatex("/nonexistent/path/to/file.tex") is False + + +def test_no_unclosed_file_reads(): + """Verify no open(...).read() patterns remain in pdf_renderer.py.""" + module_path = os.path.join( + os.path.dirname(__file__), + "..", + "app", + "services", + "pdf_renderer.py", + ) + with open(module_path, "r", encoding="utf-8") as f: + source = f.read() + + unclosed = re.findall(r"open\([^)]+\)\.read\([^)]*\)", source) + assert len(unclosed) == 0, ( + f"Found {len(unclosed)} unclosed file read(s) in pdf_renderer.py: {unclosed}" + )