Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Print entry file name and lineno with --no-obsolete #319

Merged
merged 6 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/mdpo/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,8 @@ def save_file_checking_file_changed(filepath, content, encoding='utf-8'):
with open(filepath, 'w', encoding=encoding) as f:
f.write(content)
return changed


def flatten(xss):
"""Flatten a iterable of iterables."""
return (x for xs in xss for x in xs)
19 changes: 3 additions & 16 deletions src/mdpo/md2po/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from mdpo.event import add_debug_events, parse_events_kwarg, raise_skip_event
from mdpo.io import (
filter_paths,
flatten,
save_file_checking_file_changed,
to_files_or_content,
)
Expand Down Expand Up @@ -74,7 +75,6 @@ def transform_foo(self, block, text):
'include_codeblocks',
'metadata',
'events',
'obsoletes',

'location',
'_current_top_level_block_number',
Expand Down Expand Up @@ -142,11 +142,8 @@ def transform_foo(self, block, text):
def __init__(self, files_or_content, **kwargs):
is_glob, files_or_content = to_files_or_content(files_or_content)
if is_glob:
filepaths = []
for globpath in files_or_content:
filepaths.extend(glob.glob(globpath))
self.filepaths = filter_paths(
filepaths,
flatten(glob.glob(globpath) for globpath in files_or_content),
ignore_paths=kwargs.get('ignore', []),
)
else:
Expand Down Expand Up @@ -183,10 +180,6 @@ def __init__(self, files_or_content, **kwargs):
if kwargs.get('debug'):
add_debug_events('md2po', self.events)

#: bool: If there are entries in the PO file that
#: are obsolete and not found in the current extraction.
self.obsoletes = False

#: str: The msgid being currently built for the next
#: message entry. Keep in mind that, if you are executing
#: an event that will be followed by an span one
Expand Down Expand Up @@ -992,10 +985,6 @@ def extract(
wrapwidth=parse_wrapwidth_argument(wrapwidth),
**pofile_kwargs,
)
for entry in self.pofile:
if entry.obsolete:
self.obsoletes = True
break

parser = md4c.GenericParser(
0,
Expand Down Expand Up @@ -1044,12 +1033,10 @@ def _parse(content):
self.found_entries,
)
elif self.mark_not_found_as_obsolete:
obsoletes = mark_not_found_entries_as_obsoletes(
mark_not_found_entries_as_obsoletes(
self.pofile,
self.found_entries,
)
if not self.obsoletes:
self.obsoletes = obsoletes

if self.metadata:
self.pofile.metadata.update(self.metadata)
Expand Down
29 changes: 18 additions & 11 deletions src/mdpo/md2po/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from mdpo.io import environ
from mdpo.md2po import Md2Po
from mdpo.md4c import DEFAULT_MD4C_GENERIC_PARSER_EXTENSIONS
from mdpo.po import check_obsolete_entries_in_filepaths


DESCRIPTION = (
Expand Down Expand Up @@ -232,17 +233,23 @@ def run(args=frozenset()):
if opts.check_saved_files_changed and md2po._saved_files_changed:
exitcode = 2

if opts.no_obsolete and md2po.obsoletes:
if not opts.quiet:
sys.stderr.write(
(
f"Obsolete messages found at {opts.po_filepath}"
" and passed '--no-obsolete'\n"
),
)
exitcode = 3

if opts.no_empty_msgstr:
if opts.no_obsolete:
locations = list(check_obsolete_entries_in_filepaths(
(opts.po_filepath,),
))
if locations:
if len(locations) > 2: # noqa PLR2004
sys.stderr.write(
f'Found {len(locations)} obsolete entries:\n',
)
for location in locations:
sys.stderr.write(f'{location}\n')
else:
for location in locations:
sys.stderr.write(
f'Found obsolete entry at {location}\n')
exitcode = 3
elif opts.no_empty_msgstr:
for entry in pofile:
if not entry.msgstr:
if not opts.quiet:
Expand Down
20 changes: 8 additions & 12 deletions src/mdpo/md2po2md/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from mdpo.md2po import Md2Po
from mdpo.md4c import DEFAULT_MD4C_GENERIC_PARSER_EXTENSIONS
from mdpo.po import check_obsolete_entries_in_filepaths
from mdpo.po2md import Po2Md


Expand All @@ -24,6 +25,7 @@
md2po_kwargs=None,
po2md_kwargs=None,
_check_saved_files_changed=False,
no_obsolete=False,
):
"""Translate a set of Markdown files using PO files.

Expand Down Expand Up @@ -70,6 +72,7 @@
``markdown_to_pofile`` function.
po2md_kwargs (dict): Additional optional arguments passed to
``pofile_to_markdown`` function.
no_obsolete (bool): If ``True``, check for obsolete entries in PO files.
"""
if '{lang}' not in output_paths_schema:
raise ValueError(
Expand Down Expand Up @@ -97,7 +100,7 @@
)

_saved_files_changed = None if not _check_saved_files_changed else False
obsoletes = False
obsoletes = []
empty = False

for filepath in input_paths_glob_:
Expand Down Expand Up @@ -156,8 +159,6 @@
if _check_saved_files_changed and _saved_files_changed is False:
_saved_files_changed = md2po._saved_files_changed

if not obsoletes:
obsoletes = md2po.obsoletes
if not empty:
for entry in md2po.pofile:
if not entry.msgstr:
Expand All @@ -182,15 +183,10 @@
if _check_saved_files_changed and _saved_files_changed is False:
_saved_files_changed = po2md._saved_files_changed

if not obsoletes:
for pofile in po2md.pofiles:
for entry in pofile:
if entry.obsolete:
obsoletes = True
break
if obsoletes:
break

if no_obsolete:
obsoletes.extend(check_obsolete_entries_in_filepaths(

Check warning on line 187 in src/mdpo/md2po2md/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/mdpo/md2po2md/__init__.py#L187

Added line #L187 was not covered by tests
[po_filepath],
))
if not empty:
for pofile in po2md.pofiles:
for entry in pofile:
Expand Down
21 changes: 13 additions & 8 deletions src/mdpo/md2po2md/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ def run(args=frozenset()):
'md_encoding': opts.md_encoding,
'include_codeblocks': opts.include_codeblocks,
'_check_saved_files_changed': opts.check_saved_files_changed,
'no_obsolete': opts.no_obsolete,
}

(
Expand All @@ -155,16 +156,20 @@ def run(args=frozenset()):
if opts.check_saved_files_changed and _saved_files_changed:
exitcode = 2

if opts.no_obsolete and obsoletes:
exitcode = 3

if not opts.quiet:
if obsoletes:
if len(obsoletes) > 2: # noqa PLR2004
sys.stderr.write(
"Obsolete messages found at PO files and"
" passed '--no-obsolete'\n",
f'Found {len(obsoletes)} obsolete entries:\n',
)

if opts.no_empty_msgstr and empty:
for location in obsoletes:
sys.stderr.write(f'{location}\n')
else:
for location in obsoletes:
sys.stderr.write(
f'Found obsolete entry at {location}\n',
)
exitcode = 3
elif opts.no_empty_msgstr and empty:
exitcode = 4

if not opts.quiet:
Expand Down
42 changes: 42 additions & 0 deletions src/mdpo/po.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,45 @@ def paths_or_globs_to_unique_pofiles(pofiles_globs, ignore, po_encoding=None):
_po_filepaths.append(po_filepath)

return pofiles


def check_obsolete_entries_in_filepaths(filenames):
"""Warns about all obsolete entries found in a set of PO files.

Args:
filenames (list): Set of file names to check.

Returns:
list(str): error messages produced.
"""
for filename in filenames:
with open(filename, 'rb') as f:
content_lines = f.readlines()

yield from parse_obsoletes_from_content_lines(
content_lines,
location_prefix=f'{filename}:',
)


def parse_obsoletes_from_content_lines(
content_lines,
location_prefix='line ',
):
"""Warns about all obsolete entries found in a set of PO files.

Args:
content_lines (list): Set of content lines to check.
location_prefix (str): Prefix to use in the location message.

Returns:
list(str): error locations found.
"""
inside_obsolete_message = False
for i, line in enumerate(content_lines):
if not inside_obsolete_message and line[0:3] == b'#~ ':
inside_obsolete_message = True

yield f'{location_prefix}{i + 1}'
elif inside_obsolete_message and line[0:3] != b'#~ ':
inside_obsolete_message = False
35 changes: 26 additions & 9 deletions src/mdpo/po2md/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
parse_event_argument,
)
from mdpo.io import environ
from mdpo.po import (
check_obsolete_entries_in_filepaths,
paths_or_globs_to_unique_pofiles,
)
from mdpo.po2md import Po2Md


Expand Down Expand Up @@ -136,15 +140,28 @@ def run(args=frozenset()):
if opts.check_saved_files_changed and po2md._saved_files_changed:
return (output, 2)

if opts.no_obsolete and get_obsoletes(po2md.pofiles):
if not opts.quiet:
sys.stderr.write(

"Obsolete messages found at PO files and passed"
" '--no-obsolete'\n",

)
return (output, 3)
if opts.no_obsolete:
pofiles = paths_or_globs_to_unique_pofiles(
opts.pofiles,
opts.ignore or [],
po_encoding=opts.po_encoding,
)
locations = list(check_obsolete_entries_in_filepaths(
pofiles,
))
if locations:
if len(locations) > 2: # noqa PLR2004
sys.stderr.write(
f'Found {len(locations)} obsolete entries:\n',
)
for location in locations:
sys.stderr.write(f'{location}\n')
else:
for location in locations:
sys.stderr.write(
f'Found obsolete entry at {location}\n',
)
return (output, 3)

if opts.no_empty_msgstr:
for pofile in po2md.pofiles:
Expand Down
63 changes: 56 additions & 7 deletions tests/test_unit/test_md2po/test_md2po_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,14 +744,14 @@ def test_no_obsolete(capsys, arg, tmp_file):

with tmp_file(po_input, '.po') as filename:
pofile, exitcode = run([arg, '-p', filename, '--no-location', 'Bye'])
stdout, stderr = capsys.readouterr()
stdout, stderr = capsys.readouterr()

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"
)
assert exitcode == 3
assert f'{pofile}\n' == expected_output
assert stdout == expected_output
assert stderr == (
f'Found obsolete entry at {filename}:5\n'
)

po_input = '''#
msgid ""
Expand All @@ -776,6 +776,55 @@ def test_no_obsolete(capsys, arg, tmp_file):
assert stdout == expected_output


@pytest.mark.parametrize('arg', ('--no-obsolete',))
def test_no_obsolete_multiple(capsys, arg, tmp_file):
po_input = '''#
msgid ""
msgstr ""

#~ msgid "Foo"
#~ msgstr "Foo lang"

#~ msgid "Bar"
#~ msgstr "Bar lang"

#~ msgid "Baz"
#~ msgstr "Baz lang"
'''

expected_output = '''#
msgid ""
msgstr ""

msgid "Bye"
msgstr ""

#~ msgid "Foo"
#~ msgstr "Foo lang"

#~ msgid "Bar"
#~ msgstr "Bar lang"

#~ msgid "Baz"
#~ msgstr "Baz lang"

'''

with tmp_file(po_input, '.po') as filename:
pofile, exitcode = run([arg, '-p', filename, '--no-location', 'Bye'])
stdout, stderr = capsys.readouterr()

assert exitcode == 3
assert f'{pofile}\n' == expected_output
assert stdout == expected_output
assert stderr == (
'Found 3 obsolete entries:\n'
f'{filename}:5\n'
f'{filename}:8\n'
f'{filename}:11\n'
)


@pytest.mark.parametrize('arg', ('--no-empty-msgstr',))
def test_no_empty_mgstr(capsys, arg, tmp_file):
po_input = '''#
Expand Down
Loading