Skip to content

Commit

Permalink
pydrake symbolic: Capture deprecation warnings with dtype=object comp…
Browse files Browse the repository at this point in the history
…arisons
  • Loading branch information
EricCousineau-TRI committed Apr 11, 2018
1 parent a626f74 commit 16d0f88
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 10 deletions.
6 changes: 6 additions & 0 deletions bindings/pydrake/symbolic_py.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ PYBIND11_MODULE(_symbolic_py, m) {
// NOLINTNEXTLINE(build/namespaces): Emulate placement in namespace.
using namespace drake::symbolic;

// Install NumPy warning filtres.
// N.B. This may interfere with other code, but until that is a confirmed
// issue, we should agressively try to avoid these warnings.
py::module::import("pydrake.util.deprecation")
.attr("install_numpy_warning_filters")();

m.doc() =
"Symbolic variable, variables, monomial, expression, polynomial, and "
"formula";
Expand Down
24 changes: 14 additions & 10 deletions bindings/pydrake/test/symbolic_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,16 +496,20 @@ def test_relational_operators_nonzero(self):
e_yv = np.array([e_y, e_y])
# N.B. In some versions of NumPy, `!=` for dtype=object implies ID
# comparison (e.g. `is`).
# N.B. If `__nonzero__` throws, then NumPy returns a scalar boolean if
# everything's false, vs. an array of `True` otherwise. No errors
# shown?
value = (e_xv == e_yv)
self.assertIsInstance(value, bool)
self.assertFalse(value)
value = (e_xv == e_xv)
self.assertEqual(value.dtype, bool)
self.assertFalse(isinstance(value[0], sym.Formula))
self.assertTrue(value.all())
# N.B. If `__nonzero__` throws, then NumPy swallows the error and
# produces a DeprecationWarning, in addition to effectively garbage
# values. For this reason, `pydrake.symbolic` will automatically
# promote these warnings to errors.
# - All false.
with self.assertRaises(DeprecationWarning):
value = (e_xv == e_yv)
# - True + False.
with self.assertRaises(DeprecationWarning):
e_xyv = np.array([e_x, e_y])
value = (e_xv == e_xyv)
# - All true.
with self.assertRaises(DeprecationWarning):
value = (e_xv == e_xv)

def test_functions_with_float(self):
# TODO(eric.cousineau): Use concrete values once vectorized methods are
Expand Down
22 changes: 22 additions & 0 deletions bindings/pydrake/util/deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,26 @@ def wrapped(original):
return wrapped


def install_numpy_warning_filters(force=False):
"""Install warnings filters specific to NumPy."""
global installed_numpy_warning_filters
if installed_numpy_warning_filters and not force:
return
installed_numpy_warning_filters = True
# Warnings specific to comparison with `dtype=object` should be raised to
# errors (#8315, #8491). Without them, NumPy will return effectively
# garbage values (e.g. comparison based on object ID): either a scalar bool
# or an array of bools (based on what objects are present and the NumPy
# version).
# N.B. Using a `module=` regex filter does not work, as the warning is
# raised from C code, and thus inherits the calling module, which may not
# be "numpy\..*" (numpy/numpy#10861).
warnings.filterwarnings(
"error", category=DeprecationWarning, message="numpy equal will not")
warnings.filterwarnings(
"error", category=DeprecationWarning,
message="elementwise == comparison failed")


warnings.simplefilter('once', DrakeDeprecationWarning)
installed_numpy_warning_filters = False

0 comments on commit 16d0f88

Please sign in to comment.