From ca0f5ea18fc7a582afa6bb247ea9032ae2f5074c Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 10 Sep 2023 14:07:21 -0700 Subject: [PATCH 1/2] [mypyc] Fix direct __dict__ access on inner functions in new Python Fixes #16077 --- mypyc/codegen/emitclass.py | 5 ++++- mypyc/test-data/run-functions.test | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/mypyc/codegen/emitclass.py b/mypyc/codegen/emitclass.py index 62e1b4b2dea1..8dcf7212b694 100644 --- a/mypyc/codegen/emitclass.py +++ b/mypyc/codegen/emitclass.py @@ -217,7 +217,7 @@ def generate_class(cl: ClassIR, module: str, emitter: Emitter) -> None: fields["tp_name"] = f'"{name}"' generate_full = not cl.is_trait and not cl.builtin_base - needs_getseters = cl.needs_getseters or not cl.is_generated + needs_getseters = cl.needs_getseters or not cl.is_generated or cl.has_dict if not cl.builtin_base: fields["tp_new"] = new_name @@ -886,6 +886,9 @@ def generate_getseters_table(cl: ClassIR, name: str, emitter: Emitter) -> None: else: emitter.emit_line("NULL, NULL, NULL},") + if cl.has_dict: + emitter.emit_line('{"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict},') + emitter.emit_line("{NULL} /* Sentinel */") emitter.emit_line("};") diff --git a/mypyc/test-data/run-functions.test b/mypyc/test-data/run-functions.test index 21993891c4e3..ad3e0e66f87d 100644 --- a/mypyc/test-data/run-functions.test +++ b/mypyc/test-data/run-functions.test @@ -1256,3 +1256,17 @@ def foo(**kwargs: Unpack[Person]) -> None: foo(name='Jennifer', age=38) [out] Jennifer + +[case testNestedFunctionDunderDict] +def foo() -> None: + def inner() -> str: return "bar" + print(inner.__dict__) # type: ignore[attr-defined] + inner.__dict__.update({"x": 1}) # type: ignore[attr-defined] + print(inner.__dict__) # type: ignore[attr-defined] + print(inner.x) # type: ignore[attr-defined] + +foo() +[out] +{} +{'x': 1} +1 From 0fb92e5481a33e5d24d7b6756033e0f67a3ae5ab Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 10 Sep 2023 15:44:52 -0700 Subject: [PATCH 2/2] fix tests --- mypyc/test-data/run-functions.test | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/mypyc/test-data/run-functions.test b/mypyc/test-data/run-functions.test index ad3e0e66f87d..bd8f1a9197dd 100644 --- a/mypyc/test-data/run-functions.test +++ b/mypyc/test-data/run-functions.test @@ -1257,7 +1257,9 @@ foo(name='Jennifer', age=38) [out] Jennifer -[case testNestedFunctionDunderDict] +[case testNestedFunctionDunderDict312] +import sys + def foo() -> None: def inner() -> str: return "bar" print(inner.__dict__) # type: ignore[attr-defined] @@ -1265,8 +1267,22 @@ def foo() -> None: print(inner.__dict__) # type: ignore[attr-defined] print(inner.x) # type: ignore[attr-defined] -foo() +if sys.version_info >= (3, 12): # type: ignore + foo() [out] +[out version>=3.12] {} {'x': 1} 1 + +[case testFunctoolsUpdateWrapper] +import functools + +def bar() -> None: + def inner() -> str: return "bar" + functools.update_wrapper(inner, bar) # type: ignore + print(inner.__dict__) # type: ignore + +bar() +[out] +{'__module__': 'native', '__name__': 'bar', '__qualname__': 'bar', '__doc__': None, '__wrapped__': }