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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ log
# The default `--cache`, which a run and the tests write into the directory
# they are run from.
.in2lambda-agent/
# The default `--out`: a run writes the replies, the flags and the zip of a
# private document there. A run's output is evidence for a pull request, not
# part of the repository.
out/
4 changes: 3 additions & 1 deletion docs/plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ a word Mathpix misread passes every tier. The comparison with an exported set, o
reader, detects it. An OCR check is separate work. The one misread the route detects is a
separator line read as a minus sign: `stray_minus` flags a field whose display maths
begins or ends with a minus sign, and a field holding a minus sign on a line of its own
beside a display maths.
beside a display maths. The check applies to a document Mathpix converted and not to one
pandoc converted, because pandoc reads no separator line and such a minus sign is the
author's own.

## Response areas

Expand Down
24 changes: 16 additions & 8 deletions in2lambda_agent/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
passage of the source, never its own words (`adjudicate`); what neither settles is a flag
for a person (`reconcile`). A field only one route filled is not a disagreement: the text
of the route that filled it is taken, and no call is made. A minus sign inside or beside a
display maths, which Mathpix reads from a separator line, is flagged too (`stray_minus`).
`to_set` and `build` write the result with in2lambda.
display maths, which Mathpix reads from a separator line, is flagged too (`stray_minus`),
in a document Mathpix converted and not in one pandoc converted. `to_set` and `build`
write the result with in2lambda.

`convert` converts one document. `convert_folder` converts a folder of them: it pairs each
sheet with its solutions document, writes one filter from the first pair, and reports for
Expand Down Expand Up @@ -143,7 +144,9 @@ def stray_minus(reply: Reply_) -> list[str]:
"""The fields holding a minus sign Mathpix read from a separator line.

A display maths begins or ends with the minus sign, or the minus sign stands on a
line of its own beside the block.
line of its own beside the block. `convert` asks this of OCR markdown only, because
the same minus sign in a tex or docx document is the author's own; the function reads
a reply and asks nothing about the document the reply came from.
"""
found = []
for key, text in fields(reply).items():
Expand Down Expand Up @@ -547,10 +550,10 @@ def said(stage: str, message: str) -> None:
# The build writes the zip here at the end of the run; the replies are written
# into the same directory as each route answers, before the build makes it.
out_dir.mkdir(parents=True, exist_ok=True)
read = [f"{Path(d).name}: {_read_as(d, cache_dir)}" for d in (document, solutions) if d is not None]
read = [(Path(d).name, _read_as(d, cache_dir)) for d in (document, solutions) if d is not None]
markdown, images = markdown_of(document, cache_dir, settings)
solutions_md = markdown_of(solutions, cache_dir, settings)[0] if solutions else None
said("ocr", "; ".join(read))
said("ocr", "; ".join(f"{name}: {how}" for name, how in read))
source = markdown + ("\n" + solutions_md if solutions_md else "")
if route_a is None:
route_a, usage = direct(markdown, solutions_md, backend)
Expand Down Expand Up @@ -588,9 +591,14 @@ def said(stage: str, message: str) -> None:
reconciled.agreed, reconciled.defaulted, reconciled.adjudicated,
)
said("route B", "ran")
for k in stray_minus(reply):
if not any(f.field == k for f in flags):
flags.append(Flag(k, fields(reply)[k], "", STRAY_MINUS))
# The stray minus sign is Mathpix reading a printed separator line. Pandoc reads no
# such line, so a minus sign at the edge of a display maths of a tex or docx document
# is the author's own, and the check runs only where a document was not converted by
# pandoc.
if any(how != "pandoc" for _, how in read):
for k in stray_minus(reply):
if not any(f.field == k for f in flags):
flags.append(Flag(k, fields(reply)[k], "", STRAY_MINUS))
result = Converted(
set=to_set(reply, name=name, directory=images), zip_path=None, flags=flags,
reply=reply, route_a=route_a, route_b=route_b, tokens=tokens,
Expand Down
8 changes: 8 additions & 0 deletions tests/fixtures/tex-sheet.tex
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ \section*{Problem Sheet 1: Kinematics}
\item Two ships sail from the same point. Are they on a crash course? If not,
find their distance of closest approach.

% The display maths begins with the author's own minus sign, which the
% stray-minus check must not flag in a document pandoc converted.
\item The potential of a dipole on its axis is
\[
-\frac{p}{4 \pi \varepsilon_0 z^2}.
\]
Find the field at a distance $z$.

\end{enumerate}

\end{document}
30 changes: 30 additions & 0 deletions tests/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,36 @@ def test_convert_reports_the_stray_minus_as_a_flag(tmp_path):
assert result.route_a == REPLY


@pytest.mark.skipif(shutil.which("pandoc") is None, reason="pandoc")
def test_a_minus_at_the_edge_of_a_maths_in_a_tex_document_is_the_authors(tmp_path):
# The tex fixture's third question opens a display maths with a minus sign the
# author wrote. Pandoc reads no separator line, so convert makes no flag of it,
# although the pattern names the field.
reply = [
{
"title": "",
"main_text": "The potential of a dipole on its axis is",
"parts": [
{
"content": "Find the field at a distance $z$.",
"options": [],
"answer": "",
"worked_solution": "$$-\\frac{p}{4 \\pi \\varepsilon_0 z^2}.$$",
}
],
}
]
assert routes.stray_minus(reply) == ["q1.p1.worked_solution"]

result = routes.convert(
Path(__file__).parent / "fixtures" / "tex-sheet.tex",
out_dir=tmp_path / "out",
backend=FakeBackend(json.dumps(reply)),
settings=Settings(),
)
assert result.flags == []


def test_a_reply_given_to_convert_is_route_as_and_no_call_is_made(tmp_path):
# What a targets run hands back from the reply it saved: the same reading of
# the document, so that two runs compare the same set with the export.
Expand Down
Loading