From 27519dd41adc9e9a9704018a5e8c05d2f8926f02 Mon Sep 17 00:00:00 2001 From: Eric Cousineau Date: Thu, 24 Dec 2020 13:53:36 -0600 Subject: [PATCH 1/2] test_eval: Show example of working closure --- tests/test_eval.cpp | 12 ++++++++++++ tests/test_eval.py | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/tests/test_eval.cpp b/tests/test_eval.cpp index 5416c2ec4d..6cbcdeda71 100644 --- a/tests/test_eval.cpp +++ b/tests/test_eval.cpp @@ -15,6 +15,7 @@ TEST_SUBMODULE(eval_, m) { // test_evals auto global = py::dict(py::module_::import("__main__").attr("__dict__")); + py::handle copy = py::module::import("copy").attr("copy"); m.def("test_eval_statements", [global]() { auto local = py::dict(); @@ -96,4 +97,15 @@ TEST_SUBMODULE(eval_, m) { auto int_class = py::eval("isinstance(42, int)", global); return global; }); + + m.def("test_eval_closure", [global, copy]() { + py::dict local = copy(global); + py::exec(R"( + closure_value = 10 + + def func(): + return closure_value + )", local, local); + return local; + }); } diff --git a/tests/test_eval.py b/tests/test_eval.py index 1bb05af05e..1c25eb094c 100644 --- a/tests/test_eval.py +++ b/tests/test_eval.py @@ -33,3 +33,8 @@ def test_eval_empty_globals(): g = {} assert "__builtins__" in m.eval_empty_globals(g) assert "__builtins__" in g + + +def test_eval_closure(): + local = m.test_eval_closure() + assert local["func"]() == 10 From 649a1e7da9faefe681d6834063ae223e3ba64e01 Mon Sep 17 00:00:00 2001 From: Yannick Jadoul Date: Mon, 25 Jan 2021 01:32:22 +0100 Subject: [PATCH 2/2] Extend test_eval_closure with weirder examples of closures for py::eval --- tests/test_eval.cpp | 20 +++++++++++++------- tests/test_eval.py | 16 ++++++++++++++-- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/test_eval.cpp b/tests/test_eval.cpp index 6cbcdeda71..160a2f941a 100644 --- a/tests/test_eval.cpp +++ b/tests/test_eval.cpp @@ -15,7 +15,6 @@ TEST_SUBMODULE(eval_, m) { // test_evals auto global = py::dict(py::module_::import("__main__").attr("__dict__")); - py::handle copy = py::module::import("copy").attr("copy"); m.def("test_eval_statements", [global]() { auto local = py::dict(); @@ -98,14 +97,21 @@ TEST_SUBMODULE(eval_, m) { return global; }); - m.def("test_eval_closure", [global, copy]() { - py::dict local = copy(global); + // test_eval_closure + m.def("test_eval_closure", []() { + py::dict global; + global["closure_value"] = 42; + py::dict local; + local["closure_value"] = 0; py::exec(R"( - closure_value = 10 + local_value = closure_value - def func(): + def func_global(): return closure_value - )", local, local); - return local; + + def func_local(): + return local_value + )", global, local); + return std::make_pair(global, local); }); } diff --git a/tests/test_eval.py b/tests/test_eval.py index 1c25eb094c..601e526f43 100644 --- a/tests/test_eval.py +++ b/tests/test_eval.py @@ -36,5 +36,17 @@ def test_eval_empty_globals(): def test_eval_closure(): - local = m.test_eval_closure() - assert local["func"]() == 10 + global_, local = m.test_eval_closure() + + assert global_["closure_value"] == 42 + assert local["closure_value"] == 0 + + assert "local_value" not in global_ + assert local["local_value"] == 0 + + assert "func_global" not in global_ + assert local["func_global"]() == 42 + + assert "func_local" not in global_ + with pytest.raises(NameError): + local["func_local"]()