Skip to content

Commit

Permalink
fix: Give __name__ to executed Python "modules", and populate `sys.…
Browse files Browse the repository at this point in the history
…modules` too

Issue-47: #47
  • Loading branch information
pawamoy committed May 20, 2024
1 parent 20b7570 commit db25ee7
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/markdown_exec/formatters/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

from __future__ import annotations

import re
import sys
import traceback
from collections import defaultdict
from functools import partial
from io import StringIO
from types import ModuleType
from typing import Any

from markdown_exec.formatters.base import ExecutionError, base_format
Expand Down Expand Up @@ -51,6 +54,15 @@ def _run_python(
_code_blocks[code_block_id] = code.split("\n")
exec_globals = _sessions_globals[session] if session else {}

# Other libraries expect functions to have a valid `__module__` attribute.
# To achieve this, we need to add a `__name__` attribute to the globals.
# We compute the name from the code block ID, replacing invalid characters with `_`.
# We also create a module object with the same name and add it to `sys.modules`,
# because that's what yet other libraries expect (`dataclasses` for example).
module_name = re.sub(r"[^a-zA-Z\d]+", "_", code_block_id)
exec_globals["__name__"] = module_name
sys.modules[module_name] = ModuleType(module_name)

buffer = StringIO()
exec_globals["print"] = partial(_buffer_print, buffer)

Expand Down
21 changes: 21 additions & 0 deletions tests/test_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,24 @@ def test_removing_output_from_pycon_code(md: Markdown) -> None:
)
assert "ok" in html
assert "ko" not in html


def test_functions_have_a_module_attribute(md: Markdown) -> None:
"""Assert functions have a `__module__` attribute.
Parameters:
md: A Markdown instance (fixture).
"""
html = md.convert(
dedent(
"""
```python exec="1"
def func():
pass
print(f"`{func.__module__}`")
```
""",
),
)
assert "_code_block_n" in html

0 comments on commit db25ee7

Please sign in to comment.