skip to main content

@tonyfast s notebooks

site navigation
notebook summary
title
formatting markdown it tokens as python doctests
description
midgy is a tool i've been crafting that translates markdown to valid python. this concept might sound perculiar from a programming perspective, but it was designed as a [literate programming] tool.
cells
18 total
9 code
state
executed in order
kernel
Python [conda env:root] *
language
python
name
conda-root-py
lines of code
54
outputs
3
table of contents
{"kernelspec": {"display_name": "Python [conda env:root] *", "language": "python", "name": "conda-root-py"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13"}, "title": "formatting markdown it tokens as python doctests", "description": "midgy is a tool i've been crafting that translates markdown to valid python.\nthis concept might sound perculiar from a programming perspective,\nbut it was designed as a [literate programming] tool."}
notebook toolbar
Activate
cell ordering
1

formatting markdown it tokens as python

2

midgy is a tool i've been crafting that translates markdown to valid python. this concept might sound perculiar from a programming perspective, but it was designed as a [literate programming] tool.

to avoid feature creep, midgy tries to stick fairly close to the commonspec when tokenizing markdown. midgy adds a doctest token to the parser. we make this addition because doctest is a [literate programming] considered in the core python language.

in this document, we convert the markdown_it tokens into valid doctest.DocTest runners.

3
    import midgy, doctest, unittest, typing
    from textwrap import dedent
4

write some sample doctests to parse

5
    def a_testable_function():
        """
        >>> range(1)
        range(0, 1)
        
        >>> assert False
        Traceback (most recent call last):
        ...
        AssertionError
        """
6

verify that these tests pass. doctest.testmod runs doctest on the __main__ module.

7
    doctest.testmod(optionflags=doctest.ELLIPSIS)
1 outputs.
TestResults(failed=0, attempted=2)
8

make some markdown_it tokens from the doctests.

9
    (tokens := (parser := midgy.Python()).parse(a_testable_function.__doc__))
1 outputs.
[Token(type='code_block', tag='code', nesting=0, attrs={}, map=[1, 3], level=0, children=None, content='    >>> range(1)\n    range(0, 1)\n', markup='', info='', meta={'first_indent': 4, 'last_indent': 4, 'min_indent': 4, 'is_magic': False, 'is_doctest': True, 'input': [1, 2], 'output': [2, 3]}, block=True, hidden=False),
 Token(type='code_block', tag='code', nesting=0, attrs={}, map=[4, 8], level=0, children=None, content='    >>> assert False\n    Traceback (most recent call last):\n    ...\n    AssertionError\n', markup='', info='', meta={'first_indent': 4, 'last_indent': 4, 'min_indent': 4, 'is_magic': False, 'is_doctest': True, 'input': [4, 5], 'output': [5, 8]}, block=True, hidden=False)]
10

get_example_from_token translates a markdown token to a doctest

11
    def get_example_from_token(token) -> typing.Iterable[doctest.Example]:
        m = doctest.DocTestParser._EXAMPLE_RE.match(token.content)
        want = dedent(m.group("want"))
        exc = doctest.DocTestParser._EXCEPTION_RE.match(want)
        source = "".join(x.lstrip()[4:] for x in m.group("source").splitlines(1))
        yield doctest.Example(
            source=source, want=want, lineno=token.map[0],
            exc_msg=exc.group("msg") if exc else None, indent=len(m.group("indent"))
        )
12

get_examples_from_tokens aggregates the doctest.Example s

13
    def get_examples_from_tokens(tokens) -> typing.Iterable[doctest.Example]:
        for token in tokens:
            if token.meta.get("is_doctest"):
                yield from get_example_from_token(token)
            
14

finally we generate a unittest.TestSuite

15
    def get_suite_from_tokens(tokens) -> unittest.TestSuite:
        suite = unittest.TestSuite()            
        for example in get_examples_from_tokens(tokens):
            suite.addTest(doctest.DocTestCase(
                doctest.DocTest([example], globals(), __name__, None, example.lineno, None),
                optionflags=doctest.ELLIPSIS
            ))
        return suite
16
    def run_suite(suite=(suite:=get_suite_from_tokens(tokens))) -> unittest.TestResult:
        suite.run(result:= unittest.TestResult())
        return result
17

run our generated doctest suite to verify that it doesn't fail.

18
    run_suite(suite)
1 outputs.
<unittest.result.TestResult run=2 errors=0 failures=0>