From a78b75644237114b4be196c02c6588309fb6942a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Mond=C3=A9jar=20Rubio?= Date: Fri, 15 Nov 2024 09:27:24 +0100 Subject: [PATCH] Add `--no-empty-msgstr` flag --- src/mdpo/cli.py | 38 ++++++++++------- src/mdpo/md2po/__main__.py | 22 ++++++++-- src/mdpo/md2po2md/__init__.py | 21 ++++++++- src/mdpo/md2po2md/__main__.py | 21 +++++++-- src/mdpo/mdpo2html/__main__.py | 29 ++++++++++++- src/mdpo/po2md/__main__.py | 19 ++++++++- tests/test_unit/test_md2po/test_md2po_cli.py | 45 +++++++++++++++++++- 7 files changed, 166 insertions(+), 29 deletions(-) diff --git a/src/mdpo/cli.py b/src/mdpo/cli.py index 2ec3ea3f..0b27f289 100644 --- a/src/mdpo/cli.py +++ b/src/mdpo/cli.py @@ -113,13 +113,8 @@ def parse_metadata_cli_arguments(metadata): ) -def add_common_cli_first_arguments(parser, quiet=True): - """Add common mdpo arguments to an argument parser at the beginning. - - Args: - parser (:py:class:`argparse.ArgumentParser`): Parser to extend. - quiet (bool): Include the argument ``-q/--quiet``. - """ +def add_common_cli_first_arguments(parser): + """Add common mdpo arguments to an argument parser at the beginning.""" parser.add_argument( '-h', '--help', action='help', help='Show this help message and exit.', @@ -131,11 +126,10 @@ def add_common_cli_first_arguments(parser, quiet=True): version='%(prog)s %(version)s', help='Show program version number and exit.', ) - if quiet: - parser.add_argument( - '-q', '--quiet', action='store_true', - help='Do not print output to STDOUT.', - ) + parser.add_argument( + '-q', '--quiet', action='store_true', + help='Do not print output to STDOUT.', + ) def add_command_alias_argument(parser): @@ -303,7 +297,7 @@ def add_check_option(parser): """ parser.add_argument( '--check', dest='check_saved_files_changed', action='store_true', - help='Run in check mode, which returns code 1 at exit when a file' + help='Run in check mode, which returns code 2 at exit when a file' ' has been changed or previously did not exist.', ) @@ -349,8 +343,22 @@ def add_no_obsolete_option(parser): parser.add_argument( '--no-obsolete', dest='no_obsolete', action='store_true', help=( - 'Do not include obsolete messages in PO files. If found,' - ' it will exit with non zero code.' + 'If obsolete entries found in PO files exit with non' + ' zero code.' + ), + ) + + +def add_no_empty_msgstr_option(parser): + """Add the ``--no-empty-msgstr`` option to an argument parser. + + Args: + parser (:py:class:`argparse.ArgumentParser`): Parser to extend. + """ + parser.add_argument( + '--no-empty-msgstr', dest='no_empty_msgstr', action='store_true', + help=( + 'If empty msgstrs found in PO files exit with non zero code.' ), ) diff --git a/src/mdpo/md2po/__main__.py b/src/mdpo/md2po/__main__.py index 1eba3d53..d6bf3c14 100755 --- a/src/mdpo/md2po/__main__.py +++ b/src/mdpo/md2po/__main__.py @@ -19,6 +19,7 @@ add_event_argument, add_extensions_argument, add_include_codeblocks_option, + add_no_empty_msgstr_option, add_no_obsolete_option, add_nolocation_option, add_wrapwidth_argument, @@ -146,6 +147,7 @@ def build_parser(): add_debug_option(parser) add_check_option(parser) add_no_obsolete_option(parser) + add_no_empty_msgstr_option(parser) return parser @@ -221,13 +223,14 @@ def run(args=frozenset()): md2po = Md2Po(opts.files_or_content, **init_kwargs) pofile = md2po.extract(**extract_kwargs) + exitcode = 0 if not opts.quiet: sys.stdout.write(f'{pofile.__unicode__()}\n') # pre-commit mode if opts.check_saved_files_changed and md2po._saved_files_changed: - return (pofile, 1) + exitcode = 2 if opts.no_obsolete and md2po.obsoletes: if not opts.quiet: @@ -237,9 +240,22 @@ def run(args=frozenset()): " and passed '--no-obsolete'\n" ), ) - return (pofile, 1) + exitcode = 3 - return (pofile, 0) + if opts.no_empty_msgstr: + for entry in pofile: + if not entry.msgstr: + if not opts.quiet: + sys.stderr.write( + ( + f"Empty msgstr found at {opts.po_filepath}" + " and passed '--no-empty-msgstr'\n" + ), + ) + exitcode = 4 + break + + return (pofile, exitcode) def main(): diff --git a/src/mdpo/md2po2md/__init__.py b/src/mdpo/md2po2md/__init__.py index 94423b30..8f543d75 100644 --- a/src/mdpo/md2po2md/__init__.py +++ b/src/mdpo/md2po2md/__init__.py @@ -97,6 +97,8 @@ def markdown_to_pofile_to_markdown( ) _saved_files_changed = None if not _check_saved_files_changed else False + obsoletes = False + empty = False for filepath in input_paths_glob_: for lang in langs: @@ -154,7 +156,13 @@ def markdown_to_pofile_to_markdown( if _check_saved_files_changed and _saved_files_changed is False: _saved_files_changed = md2po._saved_files_changed - obsoletes = md2po.obsoletes + if not obsoletes: + obsoletes = md2po.obsoletes + if not empty: + for entry in md2po.pofile: + if not entry.msgstr: + empty = True + break # po2md po2md = Po2Md( @@ -183,4 +191,13 @@ def markdown_to_pofile_to_markdown( if obsoletes: break - return (_saved_files_changed, obsoletes) + if not empty: + for pofile in po2md.pofiles: + for entry in pofile: + if not entry.msgstr: + empty = True + break + if empty: + break + + return (_saved_files_changed, obsoletes, empty) diff --git a/src/mdpo/md2po2md/__main__.py b/src/mdpo/md2po2md/__main__.py index 33c06b9b..ea7ea49b 100755 --- a/src/mdpo/md2po2md/__main__.py +++ b/src/mdpo/md2po2md/__main__.py @@ -18,6 +18,7 @@ add_encoding_arguments, add_extensions_argument, add_include_codeblocks_option, + add_no_empty_msgstr_option, add_no_obsolete_option, add_nolocation_option, add_wrapwidth_argument, @@ -89,6 +90,7 @@ def build_parser(): add_debug_option(parser) add_check_option(parser) add_no_obsolete_option(parser) + add_no_empty_msgstr_option(parser) return parser @@ -140,24 +142,35 @@ def run(args=frozenset()): '_check_saved_files_changed': opts.check_saved_files_changed, } - (_saved_files_changed, obsoletes) = markdown_to_pofile_to_markdown( + ( + _saved_files_changed, + obsoletes, + empty, + ) = markdown_to_pofile_to_markdown( opts.langs, opts.input_paths_glob, opts.output_paths_schema, **kwargs, ) if opts.check_saved_files_changed and _saved_files_changed: - exitcode = 1 + exitcode = 2 if opts.no_obsolete and obsoletes: - exitcode = 1 + exitcode = 3 if not opts.quiet: sys.stderr.write( - "Obsolete messages found at PO files and" " passed '--no-obsolete'\n", + ) + + if opts.no_empty_msgstr and empty: + exitcode = 4 + if not opts.quiet: + sys.stderr.write( + "Empty msgstr found at PO files and" + " passed '--no-empty-msgstr'\n", ) return exitcode diff --git a/src/mdpo/mdpo2html/__main__.py b/src/mdpo/mdpo2html/__main__.py index 9169f363..127316eb 100755 --- a/src/mdpo/mdpo2html/__main__.py +++ b/src/mdpo/mdpo2html/__main__.py @@ -14,6 +14,8 @@ add_command_alias_argument, add_common_cli_first_arguments, add_encoding_arguments, + add_no_empty_msgstr_option, + add_no_obsolete_option, cli_codespan, parse_command_aliases_cli_arguments, ) @@ -54,6 +56,8 @@ def build_parser(): add_encoding_arguments(parser, markup_encoding='html') add_command_alias_argument(parser) add_check_option(parser) + add_no_obsolete_option(parser) + add_no_empty_msgstr_option(parser) return parser @@ -107,7 +111,30 @@ def run(args=frozenset()): sys.stdout.write(f'{output}\n') if opts.check_saved_files_changed and mdpo2html._saved_files_changed: - return (output, 1) + return (output, 2) + + if opts.no_obsolete: + for pofile in mdpo2html.pofiles: + for entry in pofile: + if entry.obsolete: + if not opts.quiet: + sys.stderr.write( + "Obsolete messages found at PO files and" + " passed '--no-obsolete'\n", + ) + return (output, 3) + + if opts.no_empty_msgstr: + for pofile in mdpo2html.pofiles: + for entry in pofile: + if not entry.msgstr: + if not opts.quiet: + sys.stderr.write( + f"Empty msgstr for msgid '{entry.msgid}'" + " found at PO files and" + " passed '--no-empty-msgstr'\n", + ) + return (output, 4) return (output, 0) diff --git a/src/mdpo/po2md/__main__.py b/src/mdpo/po2md/__main__.py index ef72d690..c4dee351 100755 --- a/src/mdpo/po2md/__main__.py +++ b/src/mdpo/po2md/__main__.py @@ -16,6 +16,7 @@ add_debug_option, add_encoding_arguments, add_event_argument, + add_no_empty_msgstr_option, add_no_obsolete_option, add_wrapwidth_argument, cli_codespan, @@ -73,6 +74,7 @@ def build_parser(): add_debug_option(parser) add_check_option(parser) add_no_obsolete_option(parser) + add_no_empty_msgstr_option(parser) return parser @@ -132,7 +134,7 @@ def run(args=frozenset()): # pre-commit mode if opts.check_saved_files_changed and po2md._saved_files_changed: - return (output, 1) + return (output, 2) if opts.no_obsolete and get_obsoletes(po2md.pofiles): if not opts.quiet: @@ -142,7 +144,20 @@ def run(args=frozenset()): " '--no-obsolete'\n", ) - return (output, 1) + return (output, 3) + + if opts.no_empty_msgstr: + for pofile in po2md.pofiles: + for entry in pofile: + if not entry.msgstr: + if not opts.quiet: + sys.stderr.write( + ( + f"Empty msgstr found at {opts.po_filepath}" + " and passed '--no-empty-msgstr'\n" + ), + ) + return (output, 4) return (output, 0) diff --git a/tests/test_unit/test_md2po/test_md2po_cli.py b/tests/test_unit/test_md2po/test_md2po_cli.py index 68d27f36..5558214d 100644 --- a/tests/test_unit/test_md2po/test_md2po_cli.py +++ b/tests/test_unit/test_md2po/test_md2po_cli.py @@ -746,7 +746,7 @@ def test_no_obsolete(capsys, arg, tmp_file): pofile, exitcode = run([arg, '-p', filename, '--no-location', 'Bye']) stdout, stderr = capsys.readouterr() - assert exitcode == 1 + assert exitcode == 3 assert f'{pofile}\n' == expected_output assert stdout == expected_output assert stderr == ( @@ -771,9 +771,50 @@ def test_no_obsolete(capsys, arg, tmp_file): pofile, exitcode = run([arg, '-p', filename, '--no-location', 'Bye']) stdout, stderr = capsys.readouterr() - assert exitcode == 1 + assert exitcode == 3 assert f'{pofile}\n' == expected_output assert stdout == expected_output assert stderr == ( f"Obsolete messages found at {filename} and passed '--no-obsolete'\n" ) + + +@pytest.mark.parametrize('arg', ('--no-empty-msgstr',)) +def test_no_empty_mgstr(capsys, arg, tmp_file): + po_input = '''# +msgid "" +msgstr "" + +msgid "Hello" +msgstr "" + +''' + + with tmp_file(po_input, '.po') as filename: + pofile, exitcode = run([arg, '-p', filename, '--no-location', 'Hello']) + stdout, stderr = capsys.readouterr() + + assert exitcode == 4 + assert f'{pofile}\n' == po_input + assert stdout == po_input + assert stderr == ( + f"Empty msgstr found at {filename} and passed '--no-empty-msgstr'\n" + ) + + po_input = '''# +msgid "" +msgstr "" + +msgid "Hello" +msgstr "Hola" + +''' + + with tmp_file(po_input, '.po') as filename: + pofile, exitcode = run([arg, '-p', filename, '--no-location', 'Hello']) + stdout, stderr = capsys.readouterr() + + assert exitcode == 0 + assert f'{pofile}\n' == po_input + assert stdout == po_input + assert stderr == ''