Skip to content

Commit 5958402

Browse files
committed
Audit code cells for unwrappable lines; fix three offenders + safety net
User-flagged: /examples/testing showed a horizontal scrollbar inside a walkthrough code cell. Root cause: white-space: pre-wrap wraps at spaces, but the line suite = unittest.defaultTestLoader.loadTestsFromTestCase(AddTests) contains a 58-char run after the first space that pre-wrap can't break. Same pattern in two other examples. TDD: RED — Contract 12 in tests/test_example_content.py (CellCodeWrappingContract) flags any \\S-run > 50 chars in walkthrough cell code. Pre-fix output: logging cell 0 line 6: 68-char run handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s")) testing cell 2 line 2: 58-char run unittest.defaultTestLoader.loadTestsFromTestCase(AddTests) datetime cell 2 line 1: 51-char run datetime.fromisoformat("2026-05-04T12:30:00+00:00") GREEN — introduce intermediate names so each line wraps cleanly: testing.md loader = unittest.defaultTestLoader suite = loader.loadTestsFromTestCase(AddTests) ... runner = unittest.TextTestRunner(stream=stream, verbosity=0) result = runner.run(suite) logging.md formatter = logging.Formatter("%(levelname)s:%(message)s") handler.setFormatter(formatter) datetime.md iso_text = "2026-05-04T12:30:00+00:00" parsed = datetime.fromisoformat(iso_text) Each :::program block and the matching :::cell block updated together so the runnable code and the walkthrough stay in sync. CSS safety net (public/site.css): added `overflow-wrap: anywhere` to `.cell-source pre, .cell-source .shiki-block, .cell-output pre`. A future long URL, long string literal, or long encoded blob will break mid-run instead of pushing a horizontal scrollbar onto the page. Code that's authored to wrap cleanly (the rule above keeps it authored well) will still wrap at spaces because pre-wrap takes precedence over overflow-wrap when both apply. 59 tests pass; SEO/cache lint clears 110 pages.
1 parent dceb834 commit 5958402

7 files changed

Lines changed: 56 additions & 12 deletions

File tree

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/site.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/asset_manifest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Generated by scripts/fingerprint_assets.py. Do not edit by hand.
2-
ASSET_PATHS = {'SITE_CSS': '/site.f9a6740c684b.css', 'SYNTAX_JS': '/syntax-highlight.3b6c7f730d46.js', 'EDITOR_JS': '/editor.dd81f5171b14.js'}
3-
HTML_CACHE_VERSION = 'c48d15294056'
2+
ASSET_PATHS = {'SITE_CSS': '/site.1452cc5609f2.css', 'SYNTAX_JS': '/syntax-highlight.3b6c7f730d46.js', 'EDITOR_JS': '/editor.dd81f5171b14.js'}
3+
HTML_CACHE_VERSION = '54735cba7a40'

src/example_sources/datetime.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ expires_at = created_at + timedelta(days=7, hours=2)
2828
print(expires_at.isoformat())
2929

3030
print(created_at.strftime("%Y-%m-%d %H:%M %Z"))
31-
parsed = datetime.fromisoformat("2026-05-04T12:30:00+00:00")
31+
iso_text = "2026-05-04T12:30:00+00:00"
32+
parsed = datetime.fromisoformat(iso_text)
3233
print(parsed == created_at)
3334
```
3435
:::
@@ -77,7 +78,8 @@ Use `strftime()` for human-facing formatting and `fromisoformat()` when reading
7778

7879
```python
7980
print(created_at.strftime("%Y-%m-%d %H:%M %Z"))
80-
parsed = datetime.fromisoformat("2026-05-04T12:30:00+00:00")
81+
iso_text = "2026-05-04T12:30:00+00:00"
82+
parsed = datetime.fromisoformat(iso_text)
8183
print(parsed == created_at)
8284
```
8385

src/example_sources/logging.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import sys
2020
logger = logging.getLogger("example")
2121
logger.setLevel(logging.INFO)
2222
handler = logging.StreamHandler(sys.stdout)
23-
handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s"))
23+
formatter = logging.Formatter("%(levelname)s:%(message)s")
24+
handler.setFormatter(formatter)
2425
logger.handlers[:] = [handler]
2526

2627
logger.debug("hidden")
@@ -39,7 +40,8 @@ import sys
3940
logger = logging.getLogger("example")
4041
logger.setLevel(logging.INFO)
4142
handler = logging.StreamHandler(sys.stdout)
42-
handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s"))
43+
formatter = logging.Formatter("%(levelname)s:%(message)s")
44+
handler.setFormatter(formatter)
4345
logger.handlers[:] = [handler]
4446

4547
logger.debug("hidden")

src/example_sources/testing.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,11 @@ class AddTests(unittest.TestCase):
4747
with self.assertRaises(ZeroDivisionError):
4848
divide(1, 0)
4949

50-
suite = unittest.defaultTestLoader.loadTestsFromTestCase(AddTests)
50+
loader = unittest.defaultTestLoader
51+
suite = loader.loadTestsFromTestCase(AddTests)
5152
stream = io.StringIO()
52-
result = unittest.TextTestRunner(stream=stream, verbosity=0).run(suite)
53+
runner = unittest.TextTestRunner(stream=stream, verbosity=0)
54+
result = runner.run(suite)
5355
print(result.testsRun)
5456
print(result.wasSuccessful())
5557
```
@@ -111,9 +113,11 @@ A runner executes the suite and records whether every assertion passed. Capturin
111113
```python
112114
import io
113115

114-
suite = unittest.defaultTestLoader.loadTestsFromTestCase(AddTests)
116+
loader = unittest.defaultTestLoader
117+
suite = loader.loadTestsFromTestCase(AddTests)
115118
stream = io.StringIO()
116-
result = unittest.TextTestRunner(stream=stream, verbosity=0).run(suite)
119+
runner = unittest.TextTestRunner(stream=stream, verbosity=0)
120+
result = runner.run(suite)
117121
print(result.testsRun)
118122
print(result.wasSuccessful())
119123
```

tests/test_example_content.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,41 @@ def test_unsupported_prose_mentions_code(self):
7676
self.assertEqual(failures, [], "\n " + "\n ".join(failures))
7777

7878

79+
class CellCodeWrappingContract(unittest.TestCase):
80+
"""Contract 12: walkthrough cell code wraps inside the narrow
81+
prose|code column without horizontal scroll.
82+
83+
The cells render in a column whose mono font fits roughly 55-60
84+
characters at desktop widths and narrower on tablets. CSS sets
85+
`white-space: pre-wrap` so lines wrap at SPACES, but a continuous
86+
run with no space (a long dotted call, an import chain, a string
87+
literal) overflows even after pre-wrap and triggers a horizontal
88+
scrollbar inside the code block.
89+
90+
Heuristic: no \\S-run in any cell may exceed 50 characters. Hits
91+
must be either shortened (introduce a temporary name and split
92+
the call) or accepted with `overflow-wrap: anywhere` in CSS as a
93+
safety net.
94+
"""
95+
96+
MAX_UNBREAKABLE_RUN = 50
97+
98+
def test_no_unwrappable_run_in_cell_code(self):
99+
import re as _re
100+
101+
failures: list[str] = []
102+
for ex in EXAMPLES:
103+
for i, cell in enumerate(ex.get("cells", [])):
104+
for j, line in enumerate(cell.get("code", "").splitlines()):
105+
longest = max(_re.findall(r"\S+", line) or [""], key=len)
106+
if len(longest) > self.MAX_UNBREAKABLE_RUN:
107+
failures.append(
108+
f"{ex['slug']} cell {i} line {j}: "
109+
f"{len(longest)}-char unbreakable run will overflow "
110+
f"the prose|code column → {longest[:60]!r}"
111+
)
112+
self.assertEqual(failures, [], "\n " + "\n ".join(failures))
113+
114+
79115
if __name__ == "__main__":
80116
unittest.main()

0 commit comments

Comments
 (0)