Skip to content

Commit 5cbc4f0

Browse files
committed
Regenerate golden parity fixture after example edits
scripts/check_example_migration_parity.py compares the live examples against tests/fixtures/golden_examples.py — the frozen snapshot from the Markdown migration. After the recent example edits (strings/café, testing/logging/datetime long-line breaks, networking figure swap + prose rewrite, three unsupported-cell prose rewrites), the golden was out of sync with the sources. Regenerated the fixture from the current examples. Parity check now reports "100% golden parity"; 58 tests, lint, format-check all clean.
1 parent 7ff89b7 commit 5cbc4f0

1 file changed

Lines changed: 80 additions & 35 deletions

File tree

tests/fixtures/golden_examples.py

Lines changed: 80 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,19 +1252,22 @@
12521252
'prose': 'Use `is` and `id()` to observe identity while two names refer to the '
12531253
'same object.'}]},
12541254
{'cells': [{'code': 'english = "hello"\n'
1255+
'french = "café"\n'
12551256
'thai = "สวัสดี"\n'
12561257
'\n'
1257-
'for label, word in [("English", english), ("Thai", thai)]:\n'
1258+
'for label, word in [("English", english), ("French", french), ("Thai", '
1259+
'thai)]:\n'
12581260
' print(label, word, len(word), len(word.encode("utf-8")))',
12591261
'kind': 'cell',
12601262
'line': 17,
1261-
'output': 'English hello 5 5\nThai สวัสดี 6 18',
1262-
'prose': ['Compare an English greeting with a Thai greeting. Both are Python `str` '
1263-
'values, but UTF-8 uses one byte for each ASCII code point and multiple '
1264-
'bytes for many non-ASCII code points.']},
1263+
'output': 'English hello 5 5\nFrench café 4 5\nThai สวัสดี 6 18',
1264+
'prose': ['Compare three words by code-point count and UTF-8 byte count. ASCII '
1265+
'characters take one byte each (`hello` → 5 bytes); the `é` in `café` is '
1266+
'one code point but two UTF-8 bytes; each Thai character takes three. The '
1267+
'`str` type abstracts over all three.']},
12651268
{'code': 'print(thai[0])\nprint([hex(ord(char)) for char in thai[:2]])',
12661269
'kind': 'cell',
1267-
'line': 34,
1270+
'line': 36,
12681271
'output': "ส\n['0xe2a', '0xe27']",
12691272
'prose': ['Indexing and iteration work with Unicode code points, not encoded bytes. '
12701273
'`ord()` returns the integer code point, which is often displayed in '
@@ -1275,14 +1278,15 @@
12751278
'print(clean.upper())\n'
12761279
'print(clean.encode("utf-8"))',
12771280
'kind': 'cell',
1278-
'line': 48,
1281+
'line': 50,
12791282
'output': "café\nCAFÉ\nb'caf\\xc3\\xa9'",
12801283
'prose': ['String methods return new strings because strings are immutable. Encoding '
12811284
'turns text into bytes when another system needs a byte representation.']}],
12821285
'code': 'english = "hello"\n'
1286+
'french = "café"\n'
12831287
'thai = "สวัสดี"\n'
12841288
'\n'
1285-
'for label, word in [("English", english), ("Thai", thai)]:\n'
1289+
'for label, word in [("English", english), ("French", french), ("Thai", thai)]:\n'
12861290
' print(label, word, len(word), len(word.encode("utf-8")))\n'
12871291
'\n'
12881292
'print(thai[0])\n'
@@ -1296,6 +1300,7 @@
12961300
'doc_path': '/library/stdtypes.html#text-sequence-type-str',
12971301
'doc_url': 'https://docs.python.org/3.13/library/stdtypes.html#text-sequence-type-str',
12981302
'expected_output': 'English hello 5 5\n'
1303+
'French café 4 5\n'
12991304
'Thai สวัสดี 6 18\n'
13001305
'ส\n'
13011306
"['0xe2a', '0xe27']\n"
@@ -1328,13 +1333,16 @@
13281333
'version_notes': None,
13291334
'version_sensitive': False,
13301335
'walkthrough': [{'code': 'english = "hello"\n'
1336+
'french = "café"\n'
13311337
'thai = "สวัสดี"\n'
13321338
'\n'
1333-
'for label, word in [("English", english), ("Thai", thai)]:\n'
1339+
'for label, word in [("English", english), ("French", french), ("Thai", '
1340+
'thai)]:\n'
13341341
' print(label, word, len(word), len(word.encode("utf-8")))',
1335-
'prose': 'Compare an English greeting with a Thai greeting. Both are Python '
1336-
'`str` values, but UTF-8 uses one byte for each ASCII code point and '
1337-
'multiple bytes for many non-ASCII code points.'},
1342+
'prose': 'Compare three words by code-point count and UTF-8 byte count. ASCII '
1343+
'characters take one byte each (`hello` → 5 bytes); the `é` in `café` '
1344+
'is one code point but two UTF-8 bytes; each Thai character takes '
1345+
'three. The `str` type abstracts over all three.'},
13381346
{'code': 'print(thai[0])\nprint([hex(ord(char)) for char in thai[:2]])',
13391347
'prose': 'Indexing and iteration work with Unicode code points, not encoded '
13401348
'bytes. `ord()` returns the integer code point, which is often '
@@ -7679,8 +7687,13 @@
76797687
'kind': 'unsupported',
76807688
'line': 18,
76817689
'output': '',
7682-
'prose': ['Dynamic Workers do not provide the `venv` module or a project environment '
7683-
'workflow.']},
7690+
'prose': ['`venv.EnvBuilder` configures the description of a new environment, then '
7691+
'`create(".venv")` materialises it on disk as a directory containing its '
7692+
'own interpreter and `site-packages`. `with_pip=False` skips bootstrapping '
7693+
"pip — useful when the venv is for an isolated tool that doesn't need to "
7694+
'install third-party packages. (This fragment runs in standard Python only '
7695+
"— Dynamic Workers don't provide the `venv` module or a project environment "
7696+
'workflow.)']},
76847697
{'code': 'import pathlib\n'
76857698
'import tempfile\n'
76867699
'import venv\n'
@@ -9812,7 +9825,8 @@
98129825
'logger = logging.getLogger("example")\n'
98139826
'logger.setLevel(logging.INFO)\n'
98149827
'handler = logging.StreamHandler(sys.stdout)\n'
9815-
'handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s"))\n'
9828+
'formatter = logging.Formatter("%(levelname)s:%(message)s")\n'
9829+
'handler.setFormatter(formatter)\n'
98169830
'logger.handlers[:] = [handler]\n'
98179831
'\n'
98189832
'logger.debug("hidden")\n'
@@ -9828,7 +9842,8 @@
98289842
'logger = logging.getLogger("example")\n'
98299843
'logger.setLevel(logging.INFO)\n'
98309844
'handler = logging.StreamHandler(sys.stdout)\n'
9831-
'handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s"))\n'
9845+
'formatter = logging.Formatter("%(levelname)s:%(message)s")\n'
9846+
'handler.setFormatter(formatter)\n'
98329847
'logger.handlers[:] = [handler]\n'
98339848
'\n'
98349849
'logger.debug("hidden")\n'
@@ -9864,7 +9879,8 @@
98649879
'logger = logging.getLogger("example")\n'
98659880
'logger.setLevel(logging.INFO)\n'
98669881
'handler = logging.StreamHandler(sys.stdout)\n'
9867-
'handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s"))\n'
9882+
'formatter = logging.Formatter("%(levelname)s:%(message)s")\n'
9883+
'handler.setFormatter(formatter)\n'
98689884
'logger.handlers[:] = [handler]\n'
98699885
'\n'
98709886
'logger.debug("hidden")\n'
@@ -9911,9 +9927,11 @@
99119927
'`assertRaises` asserts that a block raises the expected exception type.']},
99129928
{'code': 'import io\n'
99139929
'\n'
9914-
'suite = unittest.defaultTestLoader.loadTestsFromTestCase(AddTests)\n'
9930+
'loader = unittest.defaultTestLoader\n'
9931+
'suite = loader.loadTestsFromTestCase(AddTests)\n'
99159932
'stream = io.StringIO()\n'
9916-
'result = unittest.TextTestRunner(stream=stream, verbosity=0).run(suite)\n'
9933+
'runner = unittest.TextTestRunner(stream=stream, verbosity=0)\n'
9934+
'result = runner.run(suite)\n'
99179935
'print(result.testsRun)\n'
99189936
'print(result.wasSuccessful())',
99199937
'kind': 'cell',
@@ -9949,9 +9967,11 @@
99499967
' with self.assertRaises(ZeroDivisionError):\n'
99509968
' divide(1, 0)\n'
99519969
'\n'
9952-
'suite = unittest.defaultTestLoader.loadTestsFromTestCase(AddTests)\n'
9970+
'loader = unittest.defaultTestLoader\n'
9971+
'suite = loader.loadTestsFromTestCase(AddTests)\n'
99539972
'stream = io.StringIO()\n'
9954-
'result = unittest.TextTestRunner(stream=stream, verbosity=0).run(suite)\n'
9973+
'runner = unittest.TextTestRunner(stream=stream, verbosity=0)\n'
9974+
'result = runner.run(suite)\n'
99559975
'print(result.testsRun)\n'
99569976
'print(result.wasSuccessful())\n',
99579977
'doc_path': '/library/unittest.html',
@@ -10011,10 +10031,11 @@
1001110031
'type.'},
1001210032
{'code': 'import io\n'
1001310033
'\n'
10014-
'suite = unittest.defaultTestLoader.loadTestsFromTestCase(AddTests)\n'
10034+
'loader = unittest.defaultTestLoader\n'
10035+
'suite = loader.loadTestsFromTestCase(AddTests)\n'
1001510036
'stream = io.StringIO()\n'
10016-
'result = unittest.TextTestRunner(stream=stream, '
10017-
'verbosity=0).run(suite)\n'
10037+
'runner = unittest.TextTestRunner(stream=stream, verbosity=0)\n'
10038+
'result = runner.run(suite)\n'
1001810039
'print(result.testsRun)\n'
1001910040
'print(result.wasSuccessful())',
1002010041
'prose': 'A runner executes the suite and records whether every assertion '
@@ -10029,7 +10050,12 @@
1002910050
'kind': 'unsupported',
1003010051
'line': 18,
1003110052
'output': '',
10032-
'prose': ['Dynamic Workers do not provide child processes.']},
10053+
'prose': ['`subprocess.run` spawns a child Python interpreter, captures its stdout '
10054+
'and stderr (`capture_output=True`), decodes them as text (`text=True`), '
10055+
'and raises `CalledProcessError` if the child exits non-zero '
10056+
'(`check=True`). The returned `result` holds the captured streams and exit '
10057+
'code as portable evidence the child ran. (This fragment runs in standard '
10058+
"Python only — Dynamic Workers don't provide child processes.)"]},
1003310059
{'code': 'import subprocess\n'
1003410060
'import sys\n'
1003510061
'\n'
@@ -10108,7 +10134,13 @@
1010810134
'kind': 'unsupported',
1010910135
'line': 18,
1011010136
'output': '',
10111-
'prose': ['Dynamic Workers do not provide native threads or child processes.']},
10137+
'prose': ['`ThreadPoolExecutor` runs `square` across two worker threads sharing the '
10138+
'same interpreter (and the GIL); `ProcessPoolExecutor` runs `pow` across '
10139+
'two child processes with isolated memory. Each `pool.map` returns an '
10140+
'iterator over results in input order, and the surrounding `with` block '
10141+
'joins the workers when the body exits. (This fragment runs in standard '
10142+
"Python only — Dynamic Workers don't provide native threads or child "
10143+
'processes.)']},
1011210144
{'code': 'from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor\n'
1011310145
'\n'
1011410146
'\n'
@@ -10184,8 +10216,12 @@
1018410216
'kind': 'unsupported',
1018510217
'line': 18,
1018610218
'output': '',
10187-
'prose': ['Dynamic Workers do not provide arbitrary low-level sockets, and this app '
10188-
'disables Dynamic Worker outbound access.']},
10219+
'prose': ['`socketpair()` returns two connected endpoints. `sendall` writes encoded '
10220+
'bytes into one end, and `recv` reads up to 16 bytes off the other. The '
10221+
'byte boundary is the whole point: `"ping".encode("utf-8")` produces '
10222+
"`b'ping'`, which is what the socket actually moves. (This fragment runs in "
10223+
"standard Python only — Dynamic Workers don't expose arbitrary sockets and "
10224+
'this app disables Worker outbound access.)']},
1018910225
{'code': 'import socket\n'
1019010226
'\n'
1019110227
'left, right = socket.socketpair()\n'
@@ -10201,8 +10237,11 @@
1020110237
'kind': 'cell',
1020210238
'line': 28,
1020310239
'output': "b'ping'\nping",
10204-
'prose': ['Sockets exchange bytes. Encoding and decoding make the boundary between '
10205-
'Python text and network data visible.']}],
10240+
'prose': ['The complete version adds two things: a `try`/`finally` so both endpoints '
10241+
'close even if `recv` or the surrounding work raises, and a second `print` '
10242+
'that `decode`s the received bytes back into a Python `str` for display. '
10243+
"The first `print` shows the raw bytes `b'ping'`; the second shows the "
10244+
'decoded text `ping`.']}],
1020610245
'code': 'import socket\n'
1020710246
'\n'
1020810247
'left, right = socket.socketpair()\n'
@@ -10251,8 +10290,11 @@
1025110290
'finally:\n'
1025210291
' left.close()\n'
1025310292
' right.close()',
10254-
'prose': 'Sockets exchange bytes. Encoding and decoding make the boundary '
10255-
'between Python text and network data visible.'}]},
10293+
'prose': 'The complete version adds two things: a `try`/`finally` so both '
10294+
'endpoints close even if `recv` or the surrounding work raises, and a '
10295+
'second `print` that `decode`s the received bytes back into a Python '
10296+
"`str` for display. The first `print` shows the raw bytes `b'ping'`; "
10297+
'the second shows the decoded text `ping`.'}]},
1025610298
{'cells': [{'code': 'from datetime import date, datetime, time, timedelta, timezone\n'
1025710299
'\n'
1025810300
'release_day = date(2026, 5, 4)\n'
@@ -10280,7 +10322,8 @@
1028010322
'prose': ['Use `timedelta` for durations. Adding one to a `datetime` produces another '
1028110323
'`datetime` without manually changing calendar fields.']},
1028210324
{'code': 'print(created_at.strftime("%Y-%m-%d %H:%M %Z"))\n'
10283-
'parsed = datetime.fromisoformat("2026-05-04T12:30:00+00:00")\n'
10325+
'iso_text = "2026-05-04T12:30:00+00:00"\n'
10326+
'parsed = datetime.fromisoformat(iso_text)\n'
1028410327
'print(parsed == created_at)',
1028510328
'kind': 'cell',
1028610329
'line': 56,
@@ -10301,7 +10344,8 @@
1030110344
'print(expires_at.isoformat())\n'
1030210345
'\n'
1030310346
'print(created_at.strftime("%Y-%m-%d %H:%M %Z"))\n'
10304-
'parsed = datetime.fromisoformat("2026-05-04T12:30:00+00:00")\n'
10347+
'iso_text = "2026-05-04T12:30:00+00:00"\n'
10348+
'parsed = datetime.fromisoformat(iso_text)\n'
1030510349
'print(parsed == created_at)\n',
1030610350
'doc_path': '/library/datetime.html',
1030710351
'doc_url': 'https://docs.python.org/3.13/library/datetime.html',
@@ -10371,7 +10415,8 @@
1037110415
'prose': 'Use `timedelta` for durations. Adding one to a `datetime` produces '
1037210416
'another `datetime` without manually changing calendar fields.'},
1037310417
{'code': 'print(created_at.strftime("%Y-%m-%d %H:%M %Z"))\n'
10374-
'parsed = datetime.fromisoformat("2026-05-04T12:30:00+00:00")\n'
10418+
'iso_text = "2026-05-04T12:30:00+00:00"\n'
10419+
'parsed = datetime.fromisoformat(iso_text)\n'
1037510420
'print(parsed == created_at)',
1037610421
'prose': 'Use `strftime()` for human-facing formatting and `fromisoformat()` '
1037710422
'when reading ISO 8601 text back into a `datetime`.'}]},

0 commit comments

Comments
 (0)