diff --git a/bindings/pydrake/BUILD.bazel b/bindings/pydrake/BUILD.bazel index 114be556ec4b..a1a318af9b01 100644 --- a/bindings/pydrake/BUILD.bazel +++ b/bindings/pydrake/BUILD.bazel @@ -90,6 +90,14 @@ drake_cc_library( visibility = ["//visibility:public"], ) +drake_cc_library( + name = "test_util_pybind", + testonly = 1, + hdrs = ["test/test_util_pybind.h"], + declare_installed_headers = 0, + visibility = ["//visibility:public"], +) + drake_cc_library( name = "autodiff_types_pybind", hdrs = ["autodiff_types_pybind.h"], diff --git a/bindings/pydrake/common/BUILD.bazel b/bindings/pydrake/common/BUILD.bazel index 4440b766a506..bffa1f17f780 100644 --- a/bindings/pydrake/common/BUILD.bazel +++ b/bindings/pydrake/common/BUILD.bazel @@ -340,7 +340,10 @@ drake_py_unittest( drake_pybind_cc_googletest( name = "cpp_param_pybind_test", - cc_deps = [":cpp_param_pybind"], + cc_deps = [ + ":cpp_param_pybind", + "//bindings/pydrake:test_util_pybind", + ], py_deps = [":cpp_param_py"], ) @@ -355,6 +358,7 @@ drake_pybind_cc_googletest( name = "cpp_template_pybind_test", cc_deps = [ ":cpp_template_pybind", + "//bindings/pydrake:test_util_pybind", "//common:nice_type_name", "//common/test_utilities:expect_throws_message", ], @@ -365,6 +369,7 @@ drake_pybind_cc_googletest( name = "drake_variant_pybind_test", cc_deps = [ ":drake_variant_pybind", + "//bindings/pydrake:test_util_pybind", ], ) @@ -391,6 +396,7 @@ drake_pybind_cc_googletest( name = "type_safe_index_pybind_test", cc_deps = [ ":type_safe_index_pybind", + "//bindings/pydrake:test_util_pybind", "//common:nice_type_name", ], ) diff --git a/bindings/pydrake/common/test/cpp_param_pybind_test.cc b/bindings/pydrake/common/test/cpp_param_pybind_test.cc index 3651863e3a45..6b4ce9edb889 100644 --- a/bindings/pydrake/common/test/cpp_param_pybind_test.cc +++ b/bindings/pydrake/common/test/cpp_param_pybind_test.cc @@ -11,6 +11,8 @@ #include "pybind11/eval.h" #include "pybind11/pybind11.h" +#include "drake/bindings/pydrake/test/test_util_pybind.h" + using std::string; namespace drake { @@ -86,8 +88,7 @@ int main(int argc, char** argv) { // Define custom class only once here. py::class_(m, "CustomCppType"); - // For Python3 - py::globals().attr("update")(m.attr("__dict__")); + test::SynchronizeGlobalsForPython3(m); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/bindings/pydrake/common/test/cpp_template_pybind_test.cc b/bindings/pydrake/common/test/cpp_template_pybind_test.cc index 99abec482164..a10361c537e6 100644 --- a/bindings/pydrake/common/test/cpp_template_pybind_test.cc +++ b/bindings/pydrake/common/test/cpp_template_pybind_test.cc @@ -12,6 +12,7 @@ #include "pybind11/eval.h" #include "pybind11/pybind11.h" +#include "drake/bindings/pydrake/test/test_util_pybind.h" #include "drake/common/nice_type_name.h" #include "drake/common/test_utilities/expect_throws_message.h" @@ -22,6 +23,8 @@ namespace drake { namespace pydrake { namespace { +using test::SynchronizeGlobalsForPython3; + template struct SimpleTemplate { vector GetNames() { @@ -45,12 +48,6 @@ void CheckValue(const string& expr, const T& expected) { EXPECT_EQ(py::eval(expr).cast(), expected); } -// TODO(eric.cousineau): Figure out why this is necessary. -// Necessary for Python3. -void sync(py::module m) { - py::globals().attr("update")(m.attr("__dict__")); -} - GTEST_TEST(CppTemplateTest, TemplateClass) { py::module m("__main__"); @@ -59,14 +56,14 @@ GTEST_TEST(CppTemplateTest, TemplateClass) { const vector expected_1 = {"int"}; const vector expected_2 = {"int", "double"}; - sync(m); + SynchronizeGlobalsForPython3(m); CheckValue("DefaultInst().GetNames()", expected_1); CheckValue("SimpleTemplate[int]().GetNames()", expected_1); CheckValue("SimpleTemplate[int, float]().GetNames()", expected_2); m.def("simple_func", [](const SimpleTemplate&) {}); - sync(m); + SynchronizeGlobalsForPython3(m); // Check error message if a function is called with the incorrect arguments. // N.B. We use `[^\0]` because C++ regex does not have an equivalent of @@ -93,7 +90,7 @@ GTEST_TEST(CppTemplateTest, TemplateFunction) { const vector expected_1 = {"int"}; const vector expected_2 = {"int", "double"}; - sync(m); + SynchronizeGlobalsForPython3(m); CheckValue("SimpleFunction[int]()", expected_1); CheckValue("SimpleFunction[int, float]()", expected_2); } @@ -120,7 +117,7 @@ GTEST_TEST(CppTemplateTest, TemplateMethod) { const vector expected_1 = {"int"}; const vector expected_2 = {"int", "double"}; - sync(m); + SynchronizeGlobalsForPython3(m); CheckValue("SimpleType().SimpleMethod[int]()", expected_1); CheckValue("SimpleType().SimpleMethod[int, float]()", expected_2); } diff --git a/bindings/pydrake/common/test/drake_variant_pybind_test.cc b/bindings/pydrake/common/test/drake_variant_pybind_test.cc index 65c4910ae49f..3dd468110278 100644 --- a/bindings/pydrake/common/test/drake_variant_pybind_test.cc +++ b/bindings/pydrake/common/test/drake_variant_pybind_test.cc @@ -10,6 +10,7 @@ #include "pybind11/pybind11.h" #include "drake/bindings/pydrake/pydrake_pybind.h" +#include "drake/bindings/pydrake/test/test_util_pybind.h" using std::string; @@ -17,6 +18,8 @@ namespace drake { namespace pydrake { namespace { +using test::SynchronizeGlobalsForPython3; + string VariantToString(const variant& value) { const bool is_int = holds_alternative(value); const bool is_double = holds_alternative(value); @@ -36,6 +39,7 @@ GTEST_TEST(VariantTest, CheckCasting) { py::module m("__main__"); m.def("VariantToString", &VariantToString, py::arg("value")); + SynchronizeGlobalsForPython3(m); ExpectString("VariantToString(1)", "int(1)"); ExpectString("VariantToString(0.5)", "double(0.5)"); ExpectString("VariantToString('foo')", "string(foo)"); diff --git a/bindings/pydrake/common/test/type_safe_index_pybind_test.cc b/bindings/pydrake/common/test/type_safe_index_pybind_test.cc index 99013bc066a0..c50b8ba9b61e 100644 --- a/bindings/pydrake/common/test/type_safe_index_pybind_test.cc +++ b/bindings/pydrake/common/test/type_safe_index_pybind_test.cc @@ -11,6 +11,8 @@ #include "pybind11/eval.h" #include "pybind11/pybind11.h" +#include "drake/bindings/pydrake/test/test_util_pybind.h" + using std::string; using std::vector; @@ -18,6 +20,8 @@ namespace drake { namespace pydrake { namespace { +using test::SynchronizeGlobalsForPython3; + template void CheckValue(const string& expr, const T& expected) { EXPECT_EQ(py::eval(expr).cast(), expected); @@ -34,7 +38,7 @@ GTEST_TEST(TypeSafeIndexTest, CheckCasting) { EXPECT_EQ(x, 10); return x; }); - py::globals().attr("update")(m.attr("__dict__")); // For Python3 + SynchronizeGlobalsForPython3(m); CheckValue("pass_thru_int(10)", 10); CheckValue("pass_thru_int(Index(10))", 10); // TypeSafeIndex<> is not implicitly constructible from an int. @@ -46,7 +50,7 @@ GTEST_TEST(TypeSafeIndexTest, CheckCasting) { return x; }); - py::globals().attr("update")(m.attr("__dict__")); // For Python3 + SynchronizeGlobalsForPython3(m); // TypeSafeIndex<> is not implicitly constructible from an int. // TODO(eric.cousineau): Consider relaxing this to *only* accept `int`s, and diff --git a/bindings/pydrake/manipulation/simple_ui.py b/bindings/pydrake/manipulation/simple_ui.py index 404e3a0af7ee..3502d676f4ea 100644 --- a/bindings/pydrake/manipulation/simple_ui.py +++ b/bindings/pydrake/manipulation/simple_ui.py @@ -3,7 +3,10 @@ and potentially other robotics) applications. """ -import Tkinter as tk +try: + import tkinter as tk +except ImportError: + import Tkinter as tk import numpy as np from pydrake.multibody.multibody_tree.multibody_plant import MultibodyPlant diff --git a/bindings/pydrake/manipulation/test/simple_ui_test.py b/bindings/pydrake/manipulation/test/simple_ui_test.py index 51c21b6d484c..5c8e580eb108 100644 --- a/bindings/pydrake/manipulation/test/simple_ui_test.py +++ b/bindings/pydrake/manipulation/test/simple_ui_test.py @@ -5,7 +5,10 @@ import unittest import numpy as np -import Tkinter as tk +try: + import tkinter as tk +except ImportError: + import Tkinter as tk from pydrake.common import FindResourceOrThrow from pydrake.multibody.multibody_tree.multibody_plant import MultibodyPlant diff --git a/bindings/pydrake/systems/drawing.py b/bindings/pydrake/systems/drawing.py index 0e77573198a8..322a0d4171ea 100644 --- a/bindings/pydrake/systems/drawing.py +++ b/bindings/pydrake/systems/drawing.py @@ -6,7 +6,6 @@ installed. """ -from sys import maxint from tempfile import NamedTemporaryFile import matplotlib.pyplot as plt @@ -38,6 +37,6 @@ def plot_graphviz(dot_text): return plt.imshow(plt.imread(f.name), aspect="equal") -def plot_system_graphviz(system, max_depth=maxint): +def plot_system_graphviz(system, **kwargs): """Renders a System's Graphviz representation in `matplotlib`.""" - return plot_graphviz(system.GetGraphvizString(max_depth)) + return plot_graphviz(system.GetGraphvizString(**kwargs)) diff --git a/bindings/pydrake/systems/meshcat_visualizer.py b/bindings/pydrake/systems/meshcat_visualizer.py index 1a0b7bccae0c..976e966d29ce 100644 --- a/bindings/pydrake/systems/meshcat_visualizer.py +++ b/bindings/pydrake/systems/meshcat_visualizer.py @@ -3,6 +3,7 @@ package, Meshcat: https://github.com/rdeits/meshcat """ +from __future__ import print_function import argparse import math import webbrowser @@ -179,8 +180,8 @@ def load(self): meshcat.geometry.ObjMeshGeometry.from_file( geom.string_data[0:-3] + "obj") else: - print "UNSUPPORTED GEOMETRY TYPE ", \ - geom.type, " IGNORED" + print("UNSUPPORTED GEOMETRY TYPE {} IGNORED".format( + geom.type)) continue # Turn a list of R,G,B elements (any indexable list of >= 3 diff --git a/bindings/pydrake/test/test_util_pybind.h b/bindings/pydrake/test/test_util_pybind.h new file mode 100644 index 000000000000..a6a7d9a2f36e --- /dev/null +++ b/bindings/pydrake/test/test_util_pybind.h @@ -0,0 +1,22 @@ +#pragma once + +#include "pybind11/pybind11.h" + +#include "drake/bindings/pydrake/pydrake_pybind.h" + +namespace drake { +namespace pydrake { +namespace test { + +// TODO(eric.cousineau): Figure out if there is a better solution than this +// hack. +/// pybind11's Python3 implementation seems to disconnect the `globals()` from +/// an embedded interpreter's `__main__` module. To remedy this, we must +/// manually synchronize these variables. +inline void SynchronizeGlobalsForPython3(py::module m) { + py::globals().attr("update")(m.attr("__dict__")); +} + +} // namespace test +} // namespace pydrake +} // namespace drake diff --git a/common/test_utilities/drake_py_unittest_main.py b/common/test_utilities/drake_py_unittest_main.py index 6824e79cca30..fe181d20ec43 100644 --- a/common/test_utilities/drake_py_unittest_main.py +++ b/common/test_utilities/drake_py_unittest_main.py @@ -5,6 +5,7 @@ import argparse import imp +import io import os import re import sys @@ -33,7 +34,7 @@ if not found_filename: raise RuntimeError("No such file found {}!".format( test_filename)) - with open(found_filename, "r") as infile: + with io.open(found_filename, "r", encoding="utf8") as infile: for line in infile.readlines(): if any([line.startswith("if __name__ =="), line.strip().startswith("unittest.main")]): diff --git a/examples/manipulation_station/end_effector_teleop.py b/examples/manipulation_station/end_effector_teleop.py index b85caadbaa94..9fe426ad6712 100644 --- a/examples/manipulation_station/end_effector_teleop.py +++ b/examples/manipulation_station/end_effector_teleop.py @@ -1,7 +1,10 @@ import argparse -import Tkinter as tk +try: + import tkinter as tk +except ImportError: + import Tkinter as tk import numpy as np from pydrake.common import FindResourceOrThrow