Skip to content

Commit baac480

Browse files
authored
format code-cell markdown code blocks (#243)
* move the list of cell types to a global var * support languages for `code-cell` * adapt the test to pass around the language * changelog
1 parent 796727c commit baac480

File tree

3 files changed

+195
-3
lines changed

3 files changed

+195
-3
lines changed

blackdoc/formats/markdown.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@
2525
(?P<braces>\{\s*(?P<block_type1>[-a-z0-9]+)\s*\})
2626
|(?P<block_type2>[-a-z0-9]+)
2727
)
28+
(?:
29+
\s+
30+
(?P<language>[a-z]+)
31+
)?
2832
$
2933
"""
3034
)
3135
include_pattern = r"\.md$"
36+
supported_blocks = ("python", "python3", "jupyter-execute", "code-cell")
3237

3338

3439
def preprocess_directive(directive):
@@ -108,7 +113,9 @@ def detection_func(lines):
108113
return None
109114

110115
directive = preprocess_directive(match.groupdict())
111-
if directive["block_type"] not in ("python", "python3", "jupyter-execute"):
116+
if directive["block_type"] not in supported_blocks:
117+
return None
118+
if directive["block_type"] in {"code-cell"} and directive["language"] != "python":
112119
return None
113120

114121
indent = len(directive.pop("indent"))
@@ -167,7 +174,7 @@ def extraction_func(code):
167174
return directive, hide_magic(code_)
168175

169176

170-
def reformatting_func(code, block_type, fences, braces, options):
177+
def reformatting_func(code, block_type, language, fences, braces, options):
171178
if braces:
172179
brace_open = "{"
173180
brace_close = "}"
@@ -176,6 +183,8 @@ def reformatting_func(code, block_type, fences, braces, options):
176183
brace_close = ""
177184

178185
directive = f"{fences}{brace_open}{block_type}{brace_close}"
186+
if language is not None:
187+
directive = f"{directive} {language}"
179188
parts = [directive]
180189
if options:
181190
parts.append(

blackdoc/tests/test_markdown.py

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ def construct_expected(label, string):
221221
"prompt_length": 0,
222222
"fences": "```",
223223
"braces": False,
224+
"language": None,
224225
"options": (),
225226
},
226227
"10 * 5",
@@ -241,6 +242,7 @@ def construct_expected(label, string):
241242
"prompt_length": 0,
242243
"fences": "```",
243244
"braces": False,
245+
"language": None,
244246
"options": (),
245247
},
246248
"10 * 5",
@@ -261,6 +263,7 @@ def construct_expected(label, string):
261263
"prompt_length": 0,
262264
"fences": "```",
263265
"braces": True,
266+
"language": None,
264267
"options": (),
265268
},
266269
"10 * 5",
@@ -281,6 +284,7 @@ def construct_expected(label, string):
281284
"prompt_length": 0,
282285
"fences": "```",
283286
"braces": True,
287+
"language": None,
284288
"options": (),
285289
},
286290
"10 * 5",
@@ -305,6 +309,7 @@ def construct_expected(label, string):
305309
"prompt_length": 0,
306310
"fences": "```",
307311
"braces": True,
312+
"language": None,
308313
"options": ("hide-code: true", "hide-output: true"),
309314
},
310315
"10 * 5",
@@ -325,6 +330,7 @@ def construct_expected(label, string):
325330
"prompt_length": 0,
326331
"fences": ":::",
327332
"braces": False,
333+
"language": None,
328334
"options": (),
329335
},
330336
"10 * 5",
@@ -345,6 +351,7 @@ def construct_expected(label, string):
345351
"prompt_length": 0,
346352
"fences": ":::",
347353
"braces": False,
354+
"language": None,
348355
"options": (),
349356
},
350357
"10 * 5",
@@ -365,6 +372,7 @@ def construct_expected(label, string):
365372
"prompt_length": 0,
366373
"fences": ":::",
367374
"braces": True,
375+
"language": None,
368376
"options": (),
369377
},
370378
"10 * 5",
@@ -385,12 +393,164 @@ def construct_expected(label, string):
385393
"prompt_length": 0,
386394
"fences": ":::",
387395
"braces": True,
396+
"language": None,
388397
"options": (),
389398
},
390399
"10 * 5",
391400
),
392401
id="colons-jupyter-execute",
393402
),
403+
pytest.param(
404+
textwrap.dedent(
405+
"""\
406+
```{python}
407+
10 * 5
408+
```
409+
""".rstrip()
410+
),
411+
(
412+
{
413+
"block_type": "python",
414+
"prompt_length": 0,
415+
"fences": "```",
416+
"braces": True,
417+
"language": None,
418+
"options": (),
419+
},
420+
"10 * 5",
421+
),
422+
id="backticks-with_braces",
423+
),
424+
pytest.param(
425+
textwrap.dedent(
426+
"""\
427+
```{jupyter-execute}
428+
10 * 5
429+
```
430+
""".rstrip()
431+
),
432+
(
433+
{
434+
"block_type": "jupyter-execute",
435+
"prompt_length": 0,
436+
"fences": "```",
437+
"braces": True,
438+
"language": None,
439+
"options": (),
440+
},
441+
"10 * 5",
442+
),
443+
id="backticks-jupyter-execute-with_braces",
444+
),
445+
pytest.param(
446+
textwrap.dedent(
447+
"""\
448+
```{jupyter-execute}
449+
---
450+
hide-code: true
451+
hide-output: true
452+
---
453+
10 * 5
454+
```
455+
""".rstrip()
456+
),
457+
(
458+
{
459+
"block_type": "jupyter-execute",
460+
"prompt_length": 0,
461+
"fences": "```",
462+
"braces": True,
463+
"language": None,
464+
"options": ("hide-code: true", "hide-output: true"),
465+
},
466+
"10 * 5",
467+
),
468+
id="backticks-jupyter-execute-with_options",
469+
),
470+
pytest.param(
471+
textwrap.dedent(
472+
"""\
473+
:::python
474+
10 * 5
475+
:::
476+
""".rstrip()
477+
),
478+
(
479+
{
480+
"block_type": "python",
481+
"prompt_length": 0,
482+
"fences": ":::",
483+
"braces": False,
484+
"language": None,
485+
"options": (),
486+
},
487+
"10 * 5",
488+
),
489+
id="colons",
490+
),
491+
pytest.param(
492+
textwrap.dedent(
493+
"""\
494+
::: python
495+
10 * 5
496+
:::
497+
""".rstrip()
498+
),
499+
(
500+
{
501+
"block_type": "python",
502+
"prompt_length": 0,
503+
"fences": ":::",
504+
"braces": False,
505+
"language": None,
506+
"options": (),
507+
},
508+
"10 * 5",
509+
),
510+
id="colons-with_space",
511+
),
512+
pytest.param(
513+
textwrap.dedent(
514+
"""\
515+
:::{python}
516+
10 * 5
517+
:::
518+
""".rstrip()
519+
),
520+
(
521+
{
522+
"block_type": "python",
523+
"prompt_length": 0,
524+
"fences": ":::",
525+
"braces": True,
526+
"language": None,
527+
"options": (),
528+
},
529+
"10 * 5",
530+
),
531+
id="colons-with_braces",
532+
),
533+
pytest.param(
534+
textwrap.dedent(
535+
"""\
536+
```{code-cell} python
537+
10 * 5
538+
```
539+
""".rstrip()
540+
),
541+
(
542+
{
543+
"block_type": "code-cell",
544+
"prompt_length": 0,
545+
"fences": "```",
546+
"braces": True,
547+
"language": "python",
548+
"options": (),
549+
},
550+
"10 * 5",
551+
),
552+
id="code-cell",
553+
),
394554
pytest.param(
395555
textwrap.dedent(
396556
"""\
@@ -406,6 +566,7 @@ def construct_expected(label, string):
406566
"fences": ":::",
407567
"braces": False,
408568
"options": (),
569+
"language": None,
409570
"prompt_length": 0,
410571
},
411572
textwrap.dedent(
@@ -434,6 +595,7 @@ def test_extraction_func(code, expected):
434595
"block_type": "python",
435596
"fences": "```",
436597
"options": (),
598+
"language": None,
437599
"braces": False,
438600
},
439601
textwrap.dedent(
@@ -451,6 +613,7 @@ def test_extraction_func(code, expected):
451613
"block_type": "jupyter-execute",
452614
"fences": "```",
453615
"braces": True,
616+
"language": None,
454617
"options": ("hide-code: true", "hide-output: true"),
455618
},
456619
textwrap.dedent(
@@ -472,6 +635,7 @@ def test_extraction_func(code, expected):
472635
"block_type": "python",
473636
"fences": ":::",
474637
"braces": False,
638+
"language": None,
475639
"options": (),
476640
},
477641
textwrap.dedent(
@@ -494,6 +658,7 @@ def test_extraction_func(code, expected):
494658
"block_type": "python",
495659
"fences": ":::",
496660
"braces": False,
661+
"language": None,
497662
"options": (),
498663
},
499664
textwrap.dedent(
@@ -506,6 +671,24 @@ def test_extraction_func(code, expected):
506671
),
507672
id="ipython_magic",
508673
),
674+
pytest.param(
675+
"10 * 5",
676+
{
677+
"block_type": "code-cell",
678+
"fences": ":::",
679+
"braces": True,
680+
"language": "python",
681+
"options": (),
682+
},
683+
textwrap.dedent(
684+
"""\
685+
:::{code-cell} python
686+
10 * 5
687+
:::
688+
""".rstrip()
689+
),
690+
id="code-cell-colons",
691+
),
509692
),
510693
)
511694
def test_reformatting_func(code, directive, expected):

doc/changelog.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Changelog
22
=========
33
v0.4.2 (*unreleased*)
44
---------------------
5-
5+
- support ``code-cell`` markdown blocks (:pull:`243`)
66

77
v0.4.1 (26 June 2025)
88
---------------------

0 commit comments

Comments
 (0)