Skip to content
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
12 changes: 10 additions & 2 deletions src/pydocvi/audit/placeholders.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,21 @@ def p07_code_is_byte_identical(corpus: Corpus) -> Iterator[Finding]:

@check("P08", Group.PLACEHOLDERS, hard=True, title="no fence or horizontal rule")
def p08_no_fence(corpus: Corpus) -> Iterator[Finding]:
"""No ``msgstr`` opens a fence or a ``---``.
"""No ``msgstr`` opens a fence or a ``---`` that its ``msgid`` did not.

Both are a model formatting its answer rather than answering, and both are
valid reST that renders as something the English does not.

Unless the English opened the same way, which is the clause this check was
missing. Every other rule in this module reads the pair, and this one read
the translation alone, so a ``msgid`` of ``---`` copied through as ``---``
was reported as a model drawing a rule under its answer. Two entries in the
corpus are that: a literal ``---`` in ``c-api/call.po`` and the inheritance
diagram in ``howto/mro.po``, which opens with a line of dashes because it is
a picture of a class hierarchy.
"""
for one, entry in corpus.translated():
if _FENCE.match(entry.msgstr):
if _FENCE.match(entry.msgstr) and not _FENCE.match(entry.msgid):
yield Finding(
check="P08",
path=corpus.relative(one.path),
Expand Down
17 changes: 13 additions & 4 deletions src/pydocvi/textguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,18 @@ class _Guard:
)

#: A fence or a rule opening the answer. The model presenting its work rather
#: than doing it, which is the same failure wearing different clothes. No
#: licence: the corpus has literal blocks, but a protected one reaches this
#: module as a placeholder and never as three backticks.
#: than doing it, which is the same failure wearing different clothes.
#:
#: Licensed by the source opening the same way, which it did not used to be. The
#: reasoning for having no licence was that the corpus has literal blocks but a
#: protected one reaches this module as a placeholder and never as three
#: backticks, and that is true of the translate path and not of the audit.
#: ``L03`` hands over the raw ``msgstr`` and the raw ``msgid``, with nothing
#: protected, so an entry whose ``msgid`` is ``---`` arrived here as ``---`` and
#: was read as a model drawing a rule. Two entries in the corpus are exactly
#: that: a literal ``---`` in ``c-api/call.po`` and the inheritance diagram in
#: ``howto/mro.po``, both copied through correctly and both reported as
#: narration by the check that exists to catch a model talking.
_FENCE = re.compile(r"^\s*(?:```|~~~|---)")

#: A parenthetical aside about the translation itself, in either language.
Expand Down Expand Up @@ -116,7 +125,7 @@ def find(text: str, source: str = "") -> Narration | None:
without making the decision any different.
"""
fence = _FENCE.match(text)
if fence:
if fence and not _FENCE.match(source):
return Narration(phrase=fence.group(0).strip(), where=0)

hits = [
Expand Down
10 changes: 10 additions & 0 deletions tests/test_audit_placeholders.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ def test_an_ordinary_translation_is_clean(self) -> None:
corpus = over("Return a list.", "Trả về một danh sách.")
assert findings(placeholders.p08_no_fence, corpus) == []

def test_a_rule_the_english_opened_is_not_the_model_drawing_one(self) -> None:
"""Every other rule in this module reads the pair and this one read the
translation alone, so a ``msgid`` of ``---`` copied through as ``---``
was reported. Two entries in the corpus are that."""
assert findings(placeholders.p08_no_fence, over("---", "---")) == []

def test_a_diagram_that_opens_with_dashes_survives_being_copied(self) -> None:
art = " -----------\n| O |\n| / \\ |"
assert findings(placeholders.p08_no_fence, over(art, art)) == []


class TestEveryCheckReportsWhereItLooked:
def test_a_finding_carries_the_file_the_line_and_the_segment(self) -> None:
Expand Down
21 changes: 17 additions & 4 deletions tests/test_textguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,23 @@ def test_a_phrase_with_no_licence_fires_however_the_source_reads(self) -> None:
documentation does not say "as an AI", so nothing can excuse it."""
assert not textguard.clean("As an AI, I note this.", "As an AI system would note that.")

def test_a_fence_is_never_licensed(self) -> None:
"""A literal block reaches this module as a placeholder, never as three
backticks, so a fence in an answer is always the model presenting."""
assert not textguard.clean("```\nTrả về danh sách.\n```", "```\nsorted(x)\n```")
def test_a_fence_the_source_did_not_open_is_the_model_presenting(self) -> None:
assert not textguard.clean("```\nTrả về danh sách.\n```", "Return a list.")

def test_a_fence_the_source_opened_is_licensed_like_any_other_phrase(self) -> None:
"""This asserted the opposite until August 2026, on the grounds that a
literal block reaches this module as a placeholder and never as three
backticks. True of the translate path and not of the audit, which hands
over the raw pair: ``L03`` reported the ``---`` in ``c-api/call.po`` and
the class diagram in ``howto/mro.po`` as a model drawing a rule, when
both are the English copied through exactly."""
assert textguard.clean("---", "---")
assert textguard.clean(" ----\n| O |", " ----\n| O |")

def test_a_fence_with_no_source_is_still_narration(self) -> None:
"""Passing no source licenses nothing, which is the right answer for a
caller holding a string and no idea what it was made from."""
assert not textguard.clean("---\nTrả về danh sách.")

def test_the_leftmost_phrase_is_the_one_reported_not_the_first_listed(self) -> None:
found = textguard.find("Trả về danh sách. Xin lỗi. Here is the translation.")
Expand Down
Loading