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
38 changes: 34 additions & 4 deletions scripts/notebook_tools/check_split_reading_cells.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,18 +572,46 @@ def role(c):
return role(prev), role(nxt)


_PURE_FENCE_RE = re.compile(r"```[^\n]*\n.*?```\Z", re.DOTALL)


def _is_pure_fence(cell: dict) -> bool:
"""Vrai si la cellule markdown est reduite a UN bloc fence, sans prose.

C'est le gabarit exact d'une conversion code->markdown (pseudo-code fige,
#18602) : ouverture ```` ``` ````, corps, fermeture -- rien avant, rien
apres. Ce n'est ni une lecture ni de la prose : la cellule represente le
code qu'elle etait. La lecture qui la suit commentait SA sortie (disparue
avec la conversion), pas celle du code au-dessus -- la remontee s'arrete
donc sur elle comme sur un exercice. Une cellule faite uniquement de
fences (une ou plusieurs conversions) l'est aussi : chaque fence fige un
code dont la sortie a disparu. Seule la cellule qui MELANGE prose et
fence n'est pas une pure fence : ses lectures restent rattachees au code
au-dessus.
"""
if cell.get("cell_type") != "markdown":
return False
src = cell_source(cell).strip()
if not src.startswith("```"):
return False
return bool(_PURE_FENCE_RE.match(src))


def _output_key_above(cells: list[dict], idx: int) -> str | None:
"""Source de la cellule de code dont ``cells[idx]`` commente la sortie.

La sortie est identifiee par la **source de sa cellule de code** (#17044,
decision ai-01 c.5836401913). La remontee s'arrete a la premiere cellule de
code : c'est elle, et elle seule, que la lecture commente. ``None`` s'il n'y
a rien a lire -- aucun code au-dessus, code d'exercice, ou code jamais
execute.
a rien a lire -- aucun code au-dessus, code d'exercice, code jamais
execute, ou pure fence de conversion (#18602) -- la lecture sous la fence
commentait la sortie du code converti, pas celle du code au-dessus.
"""
for j in range(idx - 1, -1, -1):
c = cells[j]
if c.get("cell_type") != "code":
if _is_pure_fence(c):
return None
continue
if is_exercise_cell(c):
return None
Expand All @@ -599,12 +627,14 @@ def readings_by_output(nb: dict) -> Counter[str]:
C'est ce compte, et lui seul, que le mode diff compare entre la base et la
tete (#17044, decision c.5836401913) : une cellule markdown dont la source
est neuve n'est pas, a elle seule, un ajout -- une fusion, une revision ou
un deplacement laissent ce compte inchange.
un deplacement laissent ce compte inchange. Une pure fence de conversion
code->markdown (#18602) n'est pas une lecture : elle ne gonfle le compte
d'aucune sortie.
"""
cells = nb.get("cells", [])
counts: Counter[str] = Counter()
for i, c in enumerate(cells):
if not is_reading_or_prose(c):
if not is_reading_or_prose(c) or _is_pure_fence(c):
continue
key = _output_key_above(cells, i)
if key is not None:
Expand Down
31 changes: 25 additions & 6 deletions scripts/tests/test_split_reading_code_to_md.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@
Cycle c.1001 : main (commit ``24511147e`` / PR #18604) a fixe le bug
pour ``detect_added_readings`` et la topologie reelle Lean-10 c.63 (les
tests 1 et 3 passent donc en regression). Le test 2
(``readings_by_output``, helper single-notebook) reste en xfail strict :
le helper a un bug separe que le carve-out principal ne touche pas (cf
message commit ``24511147e``). A chaque XPASS sur test 2 = signal que
le helper a ete corrige -> retirer ce xfail.
(``readings_by_output``, helper single-notebook) restait en xfail strict :
le helper avait un bug separe que le carve-out principal ne touchait pas
(cf message commit ``24511147e``).

Cycle suivant (residuel #18602, c.935) : le helper est corrige -- une
pure fence de conversion code->markdown n'est plus comptee comme lecture
et borne la remontee ``_output_key_above`` (la lecture sous la fence
commentait la sortie du code converti, disparue). Le xfail du test 2 est
retire : les trois tests sont des regressions.
"""
import pytest
import sys
from pathlib import Path

Expand Down Expand Up @@ -89,7 +93,6 @@ def test_code_to_md_conversion_not_second_reading():
assert mod.detect_added_readings(head_nb, base_nb) == []


@pytest.mark.xfail(reason="REPRODUCTION c.970 du bug split-reading code->md ; le cliquet rattache a tort -- cf docstring", strict=True)
def test_code_to_md_keeps_legitimate_reading_count():
"""La conversion code->fence ne doit faire monter le compte de lectures
d'AUCUNE sortie : la lecture legitime reste rattachee a la sortie du
Expand Down Expand Up @@ -127,6 +130,22 @@ def test_code_to_md_keeps_legitimate_reading_count():
assert mod.readings_by_output(base_nb) == {"print(100)": 1, "print(42)": 1}


def test_prose_mixed_fence_is_not_a_boundary():
"""Controle negatif de la borne pure-fence : une cellule qui MELANGE prose
et fence n'est pas une conversion figee -- la lecture titree qui la suit
reste rattachee au code execute au-dessus (le melange ne borne pas la
remontee). La prose melangee est comptee comme lecture, comportement
preexistant d'``is_reading_or_prose`` que ce fix ne change pas."""
nb = {
"cells": [
code("print(100)", "c0", output="100\n"),
md("Exemple de reglage :\n```python\nprint(42)\n```\nOn voit la valeur.", "mix"),
md("### Interpretation : resultat", "m2"),
]
}
assert mod.readings_by_output(nb) == {"print(100)": 2}


def test_minimal_repro_pr_18440():
"""Topologie Lean-10-LeanDojo c.60-c.65 mesuree sur la PR #18440
(head = 1ad120705, base = 1ad120705^) : ids reels, memes positions.
Expand Down
Loading