fix defer

This commit is contained in:
2026-05-13 05:55:46 -04:00
parent 9266add6a1
commit 1a529ed750
6 changed files with 66 additions and 106 deletions
-9
View File
@@ -1,9 +0,0 @@
import sys
import os
try:
from imgui_bundle import hello_imgui
rp = hello_imgui.RunnerParams()
print(f"Default borderless: {rp.app_window_params.borderless}")
except Exception as e:
print(f"Error: {e}")
-68
View File
@@ -1,68 +0,0 @@
import sys
from ast import (
AsyncFunctionDef,
FunctionDef,
)
from collections import deque
from types import FrameType
from typing import Any, Callable, Optional, cast
from executing.executing import Executing, Source
from defer.errors import FreeVarsError
from defer.sugar.transformer import RewriteDefer
class _ParseDefer:
IDENTITY = lambda *_: None # noqa: E731
def __init__(self, tracefn: Optional[Callable]) -> None:
self.tracefn = tracefn or self.IDENTITY
self.pending: deque[Executing] = deque()
def __call__(self, frame: FrameType, event: str, arg: Any):
self.tracefn(frame, event, arg)
if any(
frame.f_code.co_filename.startswith(path)
for path in {
sys.base_exec_prefix,
sys.base_prefix,
sys.exec_prefix,
sys.prefix,
"<frozen ",
"<string>",
"<pytest ",
}
):
return self
if event != "line":
return self
exc = Source.executing(frame)
if not (stmt := next(iter(exc.statements), None)):
return self
if isinstance(stmt, (AsyncFunctionDef, FunctionDef)):
self.pending.append(exc)
return self
if not self.pending or frame.f_back is not self.pending[-1].frame.f_back:
return self
stmts = self.pending.pop().statements
node = cast(FunctionDef | AsyncFunctionDef, next(iter(stmts)))
fn = frame.f_locals[node.name]
if fn.__module__ in sys.stdlib_module_names:
return self
if fn.__code__.co_freevars:
raise FreeVarsError(fn)
if not (ast := RewriteDefer.transform(node)):
return self
locals = frame.f_locals.copy()
del locals[node.name]
exec(compile(ast, frame.f_code.co_filename, "exec"), frame.f_globals, locals)
frame.f_locals[node.name].__code__ = locals[node.name].__code__
return self
BIN
View File
Binary file not shown.
View File
+1 -2
View File
@@ -9,5 +9,4 @@ def install():
sys.settrace(_ParseDefer(sys.gettrace()))
defer = Defer()
install()
defer = Defer()
+65 -27
View File
@@ -4,15 +4,35 @@ from ast import (
FunctionDef,
)
from collections import deque
from os.path import isabs
from types import FrameType
from typing import Any, Callable, Optional, cast
from executing.executing import Executing, Source
from defer.errors import FreeVarsError
from defer.sugar.transformer import RewriteDefer
def _is_dunder(name: str) -> bool:
return name.startswith("__") and name.endswith("__")
def _is_excluded_path(filename: str) -> bool:
if not filename:
return True
return (
filename.startswith(sys.base_exec_prefix)
or filename.startswith(sys.base_prefix)
or filename.startswith(sys.exec_prefix)
or filename.startswith(sys.prefix)
or ".venv" in filename
or filename.startswith("<frozen ")
or filename.startswith("<string>")
or filename.startswith("<pytest ")
or "thirdparty" in filename
or "__future__" in filename
)
class _ParseDefer:
IDENTITY = lambda *_: None # noqa: E731
@@ -21,47 +41,65 @@ class _ParseDefer:
self.pending: deque[Executing] = deque()
def __call__(self, frame: FrameType, event: str, arg: Any):
try:
self._do_call(frame, event, arg)
except Exception:
pass
return self
def _do_call(self, frame: FrameType, event: str, arg: Any):
self.tracefn(frame, event, arg)
if any(
frame.f_code.co_filename.startswith(path)
for path in {
sys.base_exec_prefix,
sys.base_prefix,
sys.exec_prefix,
sys.prefix,
"<frozen ",
"<string>",
"<pytest ",
}
):
return self
try:
filename = frame.f_code.co_filename
except Exception:
return
if _is_excluded_path(filename):
return
if not isabs(filename):
return
if event != "line":
return self
return
try:
from executing.executing import Executing, Source
except ImportError:
return
try:
exc = Source.executing(frame)
except Exception:
return
if not (stmt := next(iter(exc.statements), None)):
return self
return
if isinstance(stmt, (AsyncFunctionDef, FunctionDef)):
if stmt.name.startswith("__") and stmt.name.endswith("__"):
return self
if _is_dunder(stmt.name):
return
self.pending.append(exc)
return self
return self
return
if not self.pending or frame.f_back is not self.pending[-1].frame.f_back:
return
stmts = self.pending.pop().statements
node = cast(FunctionDef | AsyncFunctionDef, next(iter(stmts)))
fn = frame.f_locals[node.name]
fn_name = node.name
if fn_name not in frame.f_locals:
return
fn = frame.f_locals[fn_name]
if fn.__module__ in sys.stdlib_module_names:
return self
return
if fn.__code__.co_freevars:
raise FreeVarsError(fn)
if not (ast := RewriteDefer.transform(node)):
return self
return
locals = frame.f_locals.copy()
del locals[node.name]
del locals[fn_name]
exec(compile(ast, frame.f_code.co_filename, "exec"), frame.f_globals, locals)
frame.f_locals[node.name].__code__ = locals[node.name].__code__
return self
frame.f_locals[fn_name].__code__ = locals[fn_name].__code__