From 81511be341f397f32f245f861f8e10bb744a1429 Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Wed, 7 Sep 2016 00:50:10 +0200 Subject: [PATCH] Replace std::cout with py::print in tests With this change both C++ and Python write to sys.stdout which resolves the capture issues noted in #351. Therefore, the related workarounds are removed. --- .appveyor.yml | 1 - tests/conftest.py | 12 ++---------- tests/constructor_stats.h | 19 +++++++++++-------- tests/pybind11_tests.h | 4 ---- tests/test_issues.cpp | 8 ++++---- tests/test_keep_alive.cpp | 8 ++++---- tests/test_numpy_vectorize.cpp | 2 +- tests/test_python_types.cpp | 23 ++++++++++------------- tests/test_python_types.py | 2 +- tests/test_smart_ptr.cpp | 32 ++++++++++++++++---------------- tests/test_virtual_functions.cpp | 4 ++-- 11 files changed, 51 insertions(+), 64 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4ea654742..688a92efc 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -29,5 +29,4 @@ install: build_script: - cmake -A "%CMAKE_ARCH%" -DPYBIND11_WERROR=ON - set MSBuildLogger="C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" -- set PYTEST_ADDOPTS="-s" # workaround for pytest capture issue, see #351 - cmake --build . --config Release --target pytest -- /v:m /logger:%MSBuildLogger% diff --git a/tests/conftest.py b/tests/conftest.py index eb6fd0260..1d7a24aa1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -70,20 +70,12 @@ class Capture(object): self.out = "" self.err = "" - def _flush(self): - """Workaround for issues on Windows: to be removed after tests get py::print""" - sys.stdout.flush() - os.fsync(sys.stdout.fileno()) - sys.stderr.flush() - os.fsync(sys.stderr.fileno()) - return self.capfd.readouterr() - def __enter__(self): - self._flush() + self.capfd.readouterr() return self def __exit__(self, *_): - self.out, self.err = self._flush() + self.out, self.err = self.capfd.readouterr() def __eq__(self, other): a = Output(self.out) diff --git a/tests/constructor_stats.h b/tests/constructor_stats.h index 757ebf90a..69e385ec6 100644 --- a/tests/constructor_stats.h +++ b/tests/constructor_stats.h @@ -200,14 +200,17 @@ template void track_values(T *, Values &&...values ConstructorStats::get().value(std::forward(values)...); } -inline void print_constr_details_more() { std::cout << std::endl; } -template void print_constr_details_more(const Head &head, Tail &&...tail) { - std::cout << " " << head; - print_constr_details_more(std::forward(tail)...); -} -template void print_constr_details(T *inst, const std::string &action, Output &&...output) { - std::cout << "### " << py::type_id() << " @ " << inst << " " << action; - print_constr_details_more(std::forward(output)...); +/// Don't cast pointers to Python, print them as strings +inline const char *format_ptrs(const char *p) { return p; } +template +py::str format_ptrs(T *p) { return "{:#x}"_s.format(reinterpret_cast(p)); } +template +auto format_ptrs(T &&x) -> decltype(std::forward(x)) { return std::forward(x); } + +template +void print_constr_details(T *inst, const std::string &action, Output &&...output) { + py::print("###", py::type_id(), "@", format_ptrs(inst), action, + format_ptrs(std::forward(output))...); } // Verbose versions of the above: diff --git a/tests/pybind11_tests.h b/tests/pybind11_tests.h index cf3cb36ef..c11b687b2 100644 --- a/tests/pybind11_tests.h +++ b/tests/pybind11_tests.h @@ -1,12 +1,8 @@ #pragma once #include -#include #include #include -using std::cout; -using std::endl; - namespace py = pybind11; using namespace pybind11::literals; diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp index 535ee39a0..34a6edeeb 100644 --- a/tests/test_issues.cpp +++ b/tests/test_issues.cpp @@ -121,14 +121,14 @@ void init_issues(py::module &m) { // classes that were not extended on the Python side struct A { virtual ~A() {} - virtual void f() { std::cout << "A.f()" << std::endl; } + virtual void f() { py::print("A.f()"); } }; struct PyA : A { - PyA() { std::cout << "PyA.PyA()" << std::endl; } + PyA() { py::print("PyA.PyA()"); } void f() override { - std::cout << "PyA.f()" << std::endl; + py::print("PyA.f()"); PYBIND11_OVERLOAD(void, A, f); } }; @@ -177,7 +177,7 @@ void init_issues(py::module &m) { class MoveIssue1 { public: MoveIssue1(int v) : v{v} {} - MoveIssue1(const MoveIssue1 &c) { std::cerr << "copy ctor\n"; v=c.v; } + MoveIssue1(const MoveIssue1 &c) { v = c.v; } MoveIssue1(MoveIssue1 &&) = delete; int v; }; diff --git a/tests/test_keep_alive.cpp b/tests/test_keep_alive.cpp index a07670b6a..cd62a02e8 100644 --- a/tests/test_keep_alive.cpp +++ b/tests/test_keep_alive.cpp @@ -12,14 +12,14 @@ class Child { public: - Child() { std::cout << "Allocating child." << std::endl; } - ~Child() { std::cout << "Releasing child." << std::endl; } + Child() { py::print("Allocating child."); } + ~Child() { py::print("Releasing child."); } }; class Parent { public: - Parent() { std::cout << "Allocating parent." << std::endl; } - ~Parent() { std::cout << "Releasing parent." << std::endl; } + Parent() { py::print("Allocating parent."); } + ~Parent() { py::print("Releasing parent."); } void addChild(Child *) { } Child *returnChild() { return new Child(); } Child *returnNullChild() { return nullptr; } diff --git a/tests/test_numpy_vectorize.cpp b/tests/test_numpy_vectorize.cpp index 7b0c51eae..6d94db2a1 100644 --- a/tests/test_numpy_vectorize.cpp +++ b/tests/test_numpy_vectorize.cpp @@ -12,7 +12,7 @@ #include double my_func(int x, float y, double z) { - std::cout << "my_func(x:int=" << x << ", y:float=" << y << ", z:float=" << z << ")" << std::endl; + py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z)); return (float) x*y*z; } diff --git a/tests/test_python_types.cpp b/tests/test_python_types.cpp index e527c0a0d..9dafe777c 100644 --- a/tests/test_python_types.cpp +++ b/tests/test_python_types.cpp @@ -60,7 +60,7 @@ public: py::list get_list() { py::list list; list.append(py::str("value")); - cout << "Entry at positon 0: " << py::object(list[0]) << endl; + py::print("Entry at position 0:", py::object(list[0])); list[0] = py::str("overwritten"); return list; } @@ -80,42 +80,39 @@ public: /* Easily iterate over a dictionary using a C++11 range-based for loop */ void print_dict(py::dict dict) { for (auto item : dict) - std::cout << "key: " << item.first << ", value=" << item.second << std::endl; + py::print("key: {}, value={}"_s.format(item.first, item.second)); } /* Easily iterate over a set using a C++11 range-based for loop */ void print_set(py::set set) { for (auto item : set) - std::cout << "key: " << item << std::endl; + py::print("key:", item); } /* Easily iterate over a list using a C++11 range-based for loop */ void print_list(py::list list) { int index = 0; for (auto item : list) - std::cout << "list item " << index++ << ": " << item << std::endl; + py::print("list item {}: {}"_s.format(index++, item)); } /* STL data types (such as maps) are automatically casted from Python */ void print_dict_2(const std::map &dict) { for (auto item : dict) - std::cout << "key: " << item.first << ", value=" << item.second << std::endl; + py::print("key: {}, value={}"_s.format(item.first, item.second)); } /* STL data types (such as sets) are automatically casted from Python */ void print_set_2(const std::set &set) { for (auto item : set) - std::cout << "key: " << item << std::endl; + py::print("key:", item); } /* STL data types (such as vectors) are automatically casted from Python */ void print_list_2(std::vector &list) { -#ifdef _WIN32 /* Can't easily mix cout and wcout on Windows */ - _setmode(_fileno(stdout), _O_TEXT); -#endif int index = 0; for (auto item : list) - std::wcout << L"list item " << index++ << L": " << item << std::endl; + py::print("list item {}: {}"_s.format(index++, item)); } /* pybind automatically translates between C++11 and Python tuples */ @@ -132,7 +129,7 @@ public: void print_array(std::array &array) { int index = 0; for (auto item : array) - std::cout << "array item " << index++ << ": " << item << std::endl; + py::print("array item {}: {}"_s.format(index++, item)); } void throw_exception() { @@ -156,8 +153,8 @@ public: } void test_print(const py::object& obj) { - std::cout << obj.str() << std::endl; - std::cout << obj.repr() << std::endl; + py::print(obj.str()); + py::print(obj.repr()); } static int value; diff --git a/tests/test_python_types.py b/tests/test_python_types.py index 087a9a20d..fe58f9321 100644 --- a/tests/test_python_types.py +++ b/tests/test_python_types.py @@ -59,7 +59,7 @@ def test_instance(capture): list_result.append('value2') instance.print_list(list_result) assert capture.unordered == """ - Entry at positon 0: value + Entry at position 0: value list item 0: overwritten list item 1: value2 """ diff --git a/tests/test_smart_ptr.cpp b/tests/test_smart_ptr.cpp index 62c39c5f3..3d3d0ff36 100644 --- a/tests/test_smart_ptr.cpp +++ b/tests/test_smart_ptr.cpp @@ -97,25 +97,25 @@ std::shared_ptr make_myobject2_2() { return std::make_shared make_myobject3_2() { return std::make_shared(9); } -void print_object_1(const Object *obj) { std::cout << obj->toString() << std::endl; } -void print_object_2(ref obj) { std::cout << obj->toString() << std::endl; } -void print_object_3(const ref &obj) { std::cout << obj->toString() << std::endl; } -void print_object_4(const ref *obj) { std::cout << (*obj)->toString() << std::endl; } +void print_object_1(const Object *obj) { py::print(obj->toString()); } +void print_object_2(ref obj) { py::print(obj->toString()); } +void print_object_3(const ref &obj) { py::print(obj->toString()); } +void print_object_4(const ref *obj) { py::print((*obj)->toString()); } -void print_myobject1_1(const MyObject1 *obj) { std::cout << obj->toString() << std::endl; } -void print_myobject1_2(ref obj) { std::cout << obj->toString() << std::endl; } -void print_myobject1_3(const ref &obj) { std::cout << obj->toString() << std::endl; } -void print_myobject1_4(const ref *obj) { std::cout << (*obj)->toString() << std::endl; } +void print_myobject1_1(const MyObject1 *obj) { py::print(obj->toString()); } +void print_myobject1_2(ref obj) { py::print(obj->toString()); } +void print_myobject1_3(const ref &obj) { py::print(obj->toString()); } +void print_myobject1_4(const ref *obj) { py::print((*obj)->toString()); } -void print_myobject2_1(const MyObject2 *obj) { std::cout << obj->toString() << std::endl; } -void print_myobject2_2(std::shared_ptr obj) { std::cout << obj->toString() << std::endl; } -void print_myobject2_3(const std::shared_ptr &obj) { std::cout << obj->toString() << std::endl; } -void print_myobject2_4(const std::shared_ptr *obj) { std::cout << (*obj)->toString() << std::endl; } +void print_myobject2_1(const MyObject2 *obj) { py::print(obj->toString()); } +void print_myobject2_2(std::shared_ptr obj) { py::print(obj->toString()); } +void print_myobject2_3(const std::shared_ptr &obj) { py::print(obj->toString()); } +void print_myobject2_4(const std::shared_ptr *obj) { py::print((*obj)->toString()); } -void print_myobject3_1(const MyObject3 *obj) { std::cout << obj->toString() << std::endl; } -void print_myobject3_2(std::shared_ptr obj) { std::cout << obj->toString() << std::endl; } -void print_myobject3_3(const std::shared_ptr &obj) { std::cout << obj->toString() << std::endl; } -void print_myobject3_4(const std::shared_ptr *obj) { std::cout << (*obj)->toString() << std::endl; } +void print_myobject3_1(const MyObject3 *obj) { py::print(obj->toString()); } +void print_myobject3_2(std::shared_ptr obj) { py::print(obj->toString()); } +void print_myobject3_3(const std::shared_ptr &obj) { py::print(obj->toString()); } +void print_myobject3_4(const std::shared_ptr *obj) { py::print((*obj)->toString()); } test_initializer smart_ptr([](py::module &m) { py::class_> obj(m, "Object"); diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp index e591ba922..50773648c 100644 --- a/tests/test_virtual_functions.cpp +++ b/tests/test_virtual_functions.cpp @@ -20,8 +20,8 @@ public: ~ExampleVirt() { print_destroyed(this); } virtual int run(int value) { - std::cout << "Original implementation of ExampleVirt::run(state=" << state - << ", value=" << value << ")" << std::endl; + py::print("Original implementation of " + "ExampleVirt::run(state={}, value={})"_s.format(state, value)); return state + value; }