Skip to content

Commit

Permalink
fix: Don't leak future annotations in user code
Browse files Browse the repository at this point in the history
Issue-47: #47
  • Loading branch information
pawamoy committed May 22, 2024
1 parent 0a485b4 commit ba0c35e
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
8 changes: 8 additions & 0 deletions src/markdown_exec/formatters/_exec_python.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Special module without future annotations for executing Python code."""

from typing import Any, Dict, Optional


def exec_python(code: str, filename: str, exec_globals: Optional[Dict[str, Any]] = None) -> None:
compiled = compile(code, filename=filename, mode="exec")
exec(compiled, exec_globals) # noqa: S102
4 changes: 2 additions & 2 deletions src/markdown_exec/formatters/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from types import ModuleType
from typing import Any

from markdown_exec.formatters._exec_python import exec_python
from markdown_exec.formatters.base import ExecutionError, base_format
from markdown_exec.rendering import code_block

Expand Down Expand Up @@ -67,8 +68,7 @@ def _run_python(
exec_globals["print"] = partial(_buffer_print, buffer)

try:
compiled = compile(code, filename=code_block_id, mode="exec")
exec(compiled, exec_globals) # noqa: S102
exec_python(code, code_block_id, exec_globals)
except Exception as error: # noqa: BLE001
trace = traceback.TracebackException.from_exception(error)
for frame in trace.stack:
Expand Down
26 changes: 26 additions & 0 deletions tests/test_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import re
from textwrap import dedent
from typing import TYPE_CHECKING

Expand Down Expand Up @@ -203,3 +204,28 @@ def func():
),
)
assert "_code_block_n" in html


def test_future_annotations_do_not_leak_into_user_code(md: Markdown) -> None:
"""Assert future annotations do not leak into user code.
Parameters:
md: A Markdown instance (fixture).
"""
html = md.convert(
dedent(
"""
```python exec="1"
class Int:
...
def f(x: Int) -> None:
return x + 1.0
print(f"`{f.__annotations__['x']}`")
```
""",
),
)
assert "<code>Int</code>" not in html
assert re.search(r"class '_code_block_n\d+_\.Int'", html)

0 comments on commit ba0c35e

Please # to comment.