feat: Sprachlabels für Codeblöcke aus Inhalt und Buchkontext (R1)
- Gedruckte Zeilennummern ("00 #include …") werden für die Erkennung
ignoriert, bleiben aber im Block stehen.
- Python zusätzlich per ast.parse (Kontrollstrukturen, def/class, Import
mit Code) und an >>>-Sitzungen erkannt; YAML zählt nicht.
- Vordurchlauf bestimmt die Sprache des Buches aus den sicher erkannten
Blöcken; passt sie, reichen für kurze Schnipsel schwächere Signale
(detected_by: "book-context"). Programmausgaben bleiben ohne Label.
Ohne Label: C-Buch 518 -> 132 von 574, Python-Buch 492 -> 326 von 747.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
29c6294584
commit
2526ee6789
2 changed files with 207 additions and 7 deletions
|
|
@ -118,3 +118,57 @@ def test_print_wrap_markers_can_be_kept(convert):
|
|||
run = convert(Book(docs=[Doc("c.xhtml", body)]), "--keep-wrap-markers")
|
||||
(_, _, code), = fenced_blocks(run.chapter("001"))
|
||||
assert code == "a = (1,\n↪ 2)"
|
||||
|
||||
|
||||
def test_printed_line_numbers_do_not_hide_the_language(convert):
|
||||
listing = ("00 // Kapitel1/hallo.c\n01 #include <stdio.h>\n \n02 int main(void) {\n"
|
||||
"03 printf(\"Hallo\\n\");\n04 return 0;\n05 }")
|
||||
run = convert(Book(docs=[Doc("c.xhtml", f"<h1>N</h1><pre>{listing}</pre>")]))
|
||||
(_, lang, code), = fenced_blocks(run.chapter("001"))
|
||||
assert lang == "c"
|
||||
assert code.startswith("00 // Kapitel1/hallo.c\n01 #include <stdio.h>") # numbers stay in the block
|
||||
|
||||
|
||||
def test_python_is_recognized_by_parsing(convert):
|
||||
blocks = ["from collections import ChainMap\n\nchain = ChainMap({}, {})\nprint(chain)",
|
||||
"zahl = -1\nif zahl < 0:\n print(\"negativ\")",
|
||||
">>> 2 + 3\n5",
|
||||
"name: epub2md\nversion: 1", # YAML is valid Python syntax, but no Python code
|
||||
"[1, 4, 9]", # program output
|
||||
"x = compute()"] # Python, but too weak without book context
|
||||
body = "<h1>P</h1>" + "".join(f"<pre>{b}</pre>" for b in blocks)
|
||||
run = convert(Book(docs=[Doc("c.xhtml", body)]))
|
||||
langs = [lang for _, lang, _ in fenced_blocks(run.chapter("001"))]
|
||||
assert langs == ["python", "python", "python", "", "", ""]
|
||||
|
||||
|
||||
def test_weak_signals_follow_the_book_language(convert):
|
||||
c_listing = "#include <stdio.h>\nint main(void) { return 0; }"
|
||||
snippets = ["char ch = 65; // 'A'", "if (a || b) {\n x();\n}", "int remove(const char *pathname);",
|
||||
"struct node {\n int value;\n};", "Ergebnis: 12345", "|00003.14|", "gcc -Wall -o prog prog.c",
|
||||
"Dezimal: 65; Zeichen: A"]
|
||||
body = "<h1>C</h1>" + "".join(f"<pre>{c_listing}</pre>" for _ in range(5))
|
||||
body += "".join(f"<pre>{s}</pre>" for s in snippets)
|
||||
run = convert(Book(docs=[Doc("c.xhtml", body)]))
|
||||
langs = [lang for _, lang, _ in fenced_blocks(run.chapter("001"))][5:]
|
||||
assert langs == ["c", "c", "c", "c", "", "", "", ""]
|
||||
by = [item["detected_by"] for item in run.report["code_blocks"]["items"]][5:9]
|
||||
assert by == ["book-context"] * 4
|
||||
|
||||
|
||||
def test_python_book_labels_assignments_but_not_output(convert):
|
||||
py = "def f(x):\n return x"
|
||||
snippets = ["foo = decorate(foo)", "random.sample(population, k)", "[x * x for x in range(5)]",
|
||||
"True", "('A', 'B', 'C')", "Hallo Welt", "4\n3\nnohtyP", "Jane\n42\nPerson(name='Jane')"]
|
||||
body = "<h1>P</h1>" + "".join(f"<pre>{py}</pre>" for _ in range(5))
|
||||
body += "".join(f"<pre>{s}</pre>" for s in snippets)
|
||||
run = convert(Book(docs=[Doc("c.xhtml", body)]))
|
||||
langs = [lang for _, lang, _ in fenced_blocks(run.chapter("001"))][5:]
|
||||
assert langs == ["python", "python", "python", "", "", "", "", ""]
|
||||
|
||||
|
||||
def test_mixed_book_gets_no_context_labels(convert):
|
||||
body = "<h1>M</h1>" + "<pre>def f(x):\n return x</pre>" * 3
|
||||
body += "<pre>#include <stdio.h>\nint main(void) { return 0; }</pre>" * 3 + "<pre>x = compute();</pre>"
|
||||
run = convert(Book(docs=[Doc("c.xhtml", body)]))
|
||||
assert fenced_blocks(run.chapter("001"))[-1][1] == ""
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ def test_qa2_10_book_readme_recommends_pdf_via_html(convert):
|
|||
|
||||
def test_qa2_11_code_language_hint(convert):
|
||||
py = "def f(x):\n return x\n\nclass A:\n pass"
|
||||
body = "<h1>C</h1>" + "".join(f"<pre>{py}\n# {i}</pre><pre>print({i})</pre>" for i in range(10))
|
||||
body = "<h1>C</h1>" + "".join(f"<pre>{py}\n# {i}</pre><pre>Ergebnis: {i}</pre>" for i in range(10))
|
||||
run = convert(Book(docs=[Doc("c.xhtml", body)]))
|
||||
hints = [i for i in run.report["infos"] if i["code"] == "code-language-hint"]
|
||||
assert hints and "--code-language python" in hints[0]["message"]
|
||||
|
|
|
|||
Loading…
Reference in a new issue