diff --git a/powrap/powrap.py b/powrap/powrap.py index 66f4bc3..17be2f1 100644 --- a/powrap/powrap.py +++ b/powrap/powrap.py @@ -7,7 +7,7 @@ import argparse import sys from typing import Iterable from pathlib import Path -from subprocess import check_output, run +from subprocess import check_output, run, CalledProcessError from tempfile import NamedTemporaryFile from tqdm import tqdm @@ -16,17 +16,27 @@ from powrap import __version__ def check_style(po_files: Iterable[str], no_wrap=False, quiet=False): - """Check style of given po_files - """ + """Check style of given po_files""" to_fix = [] for po_path in tqdm(po_files, desc="Checking wrapping of po files", disable=quiet): - with open(po_path, encoding="UTF-8") as po_file: - po_content = po_file.read() + try: + with open(po_path, encoding="UTF-8") as po_file: + po_content = po_file.read() + except OSError as open_error: + tqdm.write(f"Error opening '{po_path}': {open_error}") + continue with NamedTemporaryFile("w+") as tmpfile: args = ["msgcat", "-", "-o", tmpfile.name] if no_wrap: args[1:1] = ["--no-wrap"] - run(args, encoding="utf-8", check=True, input=po_content) + try: + run(args, encoding="utf-8", check=True, input=po_content) + except CalledProcessError as run_error: + tqdm.write(f"Error processing '{po_path}': {run_error}") + continue + except FileNotFoundError as run_error: + tqdm.write("Error running " + " ".join(args) + f": {run_error}") + sys.exit(127) new_po_content = tmpfile.read() if po_content != new_po_content: to_fix.append(po_path) @@ -34,20 +44,24 @@ def check_style(po_files: Iterable[str], no_wrap=False, quiet=False): def fix_style(po_files, no_wrap=False, quiet=False): - """Fix style of given po_files. - """ + """Fix style of given po_files.""" for po_path in tqdm(po_files, desc="Fixing wrapping of po files", disable=quiet): with open(po_path, encoding="UTF-8") as po_file: po_content = po_file.read() args = ["msgcat", "-", "-o", po_path] if no_wrap: args[1:1] = ["--no-wrap"] - run(args, encoding="utf-8", check=True, input=po_content) + try: + run(args, encoding="utf-8", check=True, input=po_content) + except CalledProcessError as run_error: + tqdm.write(f"Error processing '{po_path}': {run_error}") + except FileNotFoundError as run_error: + tqdm.write("Error running " + " ".join(args) + f": {run_error}") + sys.exit(127) def parse_args(): - """Parse powrap command line arguments. - """ + """Parse powrap command line arguments.""" def path(path_str): path_obj = Path(path_str) @@ -59,15 +73,19 @@ def parse_args(): raise argparse.ArgumentTypeError("{!r} is not a file.".format(path_str)) try: path_obj.read_text() - except PermissionError: + except PermissionError as read_error: raise argparse.ArgumentTypeError( "{!r}: Permission denied.".format(path_str) - ) + ) from read_error return path_obj parser = argparse.ArgumentParser( prog="powrap", description="Ensure po files are using the standard gettext format", + epilog="""exit code: + 0:nothing to do + 1:would rewrap + 127:error running msgcat""", ) parser.add_argument( "--modified", "-m", action="store_true", help="Use git to find modified files." @@ -100,8 +118,7 @@ def parse_args(): def main(): - """Powrap main entrypoint (parsing command line and all). - """ + """Powrap main entrypoint (parsing command line and all).""" args = parse_args() if args.modified: git_status = check_output(["git", "status", "--porcelain"], encoding="utf-8") diff --git a/tests/bad/invalid_po_file.po b/tests/bad/invalid_po_file.po new file mode 100644 index 0000000..be8598f --- /dev/null +++ b/tests/bad/invalid_po_file.po @@ -0,0 +1,24 @@ +# Copyright (C) 2001-2018, Python Software Foundation +# For licence information, see README file. +# +msgid "" +msgstr "" +"Project-Id-Version: Python 3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-10-09 17:54+0200\n" +"PO-Revision-Date: 2019-12-10 09:26+0100\n" +"Last-Translator: Grenoya \n" +"Language-Team: FRENCH \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.2.1\n" + +#: ../Doc/glossary.rst:5 +msgid "Glossary" +msgstr "Glossaire" ? + +#: ../Doc/glossary.rst:10 +msgid "``>>>``" +msgstr "``>>>``" diff --git a/tests/test_powrap.py b/tests/test_powrap.py index a91339c..5155f8c 100644 --- a/tests/test_powrap.py +++ b/tests/test_powrap.py @@ -1,13 +1,14 @@ from pathlib import Path import pytest +import os from powrap import powrap FIXTURE_DIR = Path(__file__).resolve().parent -@pytest.mark.parametrize("po_file", (FIXTURE_DIR / "bad").glob("*.po")) +@pytest.mark.parametrize("po_file", (FIXTURE_DIR / "bad" / "glossary.po",)) def test_fail_on_bad_wrapping(po_file): assert powrap.check_style([po_file]) == [po_file] @@ -15,3 +16,25 @@ def test_fail_on_bad_wrapping(po_file): @pytest.mark.parametrize("po_file", (FIXTURE_DIR / "good").glob("*.po")) def test_succees_on_good_wrapping(po_file): assert powrap.check_style([po_file]) == [] + + +@pytest.mark.parametrize("po_file", (FIXTURE_DIR / "bad" / "invalid_po_file.po",)) +def test_msgcat_error(po_file): + assert powrap.check_style([po_file]) == [] + + +@pytest.mark.parametrize("po_file", ("non_existent_file.po",)) +def test_fileread_error(po_file): + assert powrap.check_style([po_file]) == [] + + +@pytest.mark.parametrize("po_file", (FIXTURE_DIR / "good").glob("*.po")) +def test_wrong_msgcat(po_file): + """ test if msgcat is not available""" + environ_saved = os.environ["PATH"] + os.environ["PATH"] = "" + with pytest.raises(SystemExit) as sysexit: + powrap.check_style([po_file]) + os.environ["PATH"] = environ_saved + assert sysexit.type == SystemExit + assert sysexit.value.code == 127