Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

numpy: Require NumPy >= 0.15.0 #8608

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bindings/pydrake/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ drake_py_library(
# We use `common:_init_py` to avoid dependency cycles.
"//bindings:bazel_workaround_4594_libdrake_py",
"//bindings/pydrake/common:_init_py",
"//bindings/pydrake/util:compatibility_py",
"//bindings/pydrake/util:deprecation_py",
# Ensure the correct version of `numpy` is used throughout `pydrake`.
"@numpy_py",
],
)

Expand Down
2 changes: 2 additions & 0 deletions bindings/pydrake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
# We specifically load `common` prior to loading any other pydrake modules,
# in order to get assertion configuration done as early as possible.
from . import common
from .util.compatibility import check_required_numpy_version
from .util.deprecation import ModuleShim

__all__ = ['common', 'getDrakePath']
check_required_numpy_version()
common.set_assertion_failure_to_throw_exception()


Expand Down
2 changes: 1 addition & 1 deletion bindings/pydrake/autodiffutils_py.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace pydrake {
PYBIND11_MODULE(autodiffutils, m) {
m.doc() = "Bindings for Eigen AutoDiff Scalars";

// Install NumPy warning filtres.
// Install NumPy warning filters.
// N.B. This may interfere with other code, but until that is a confirmed
// issue, we should aggressively try to avoid these warnings.
py::module::import("pydrake.util.deprecation")
Expand Down
8 changes: 7 additions & 1 deletion bindings/pydrake/common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ drake_pybind_library(
cc_so_name = "_module_py",
cc_srcs = ["module_py.cc"],
package_info = PACKAGE_INFO,
# Ensure the correct version of `numpy` is used throughout `pydrake`.
py_deps = ["@numpy_py"],
py_srcs = [
"__init__.py",
],
Expand Down Expand Up @@ -87,6 +89,8 @@ drake_py_library(
name = "deprecation_py",
srcs = ["deprecation.py"],
imports = PACKAGE_INFO.py_imports,
# `:module_py` consumes this, so use `_init_py` instead.
deps = [":_init_py"],
)

# N.B. Since `module_py` incorporates `deprecation_py`, C++ Python libraries
Expand Down Expand Up @@ -225,7 +229,9 @@ drake_py_library(
name = "compatibility_py",
srcs = ["compatibility.py"],
deps = [
":module_py",
# `:module_py` consumes this, so use `_init_py` instead.
":_init_py",
":deprecation_py",
],
)

Expand Down
68 changes: 22 additions & 46 deletions bindings/pydrake/common/compatibility.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,34 @@
"""Contains routines to monkey patch or provide alternatives to upstream code
which may need changes for compatibility.
which may need changes for compatibility, or check versions.
"""

import numpy as np
from numpy.lib import NumpyVersion

_numpy_version = np.lib.NumpyVersion(np.version.version)
_patches = {
'numpy_formatters': {
'applied': False,
'required': _numpy_version < np.lib.NumpyVersion('1.13.0'),
},
}
from pydrake.common.deprecation import _warn_deprecated


def _defer_callable_type(cls):
# Makes a type, which is meant to purely callable, and defers its
# construction until it needs to be called.
def check_required_numpy_version(_actual=np.version.version):
"""Fails fast if a minimum version of NumPy is not present.

class Deferred(object):
def __init__(self, *args, **kwargs):
self._args = args
self._kwargs = kwargs
self._obj = None
pydrake requires NumPy >= 0.15.0 namely for the following patches:
https://github.com/numpy/numpy/pull/10898
https://github.com/numpy/numpy/pull/11076

def _get_obj(self):
if self._obj is None:
self._obj = cls(*self._args, **self._kwargs)
return self._obj

def __call__(self, *args, **kwargs):
return self._get_obj().__call__(*args, **kwargs)

return Deferred
If Drake uses user-dtypes in lieu of `dtype=object`, then anything that
refers to `autodiff` or `symbolic` (e.g. all of `systems`,
`multibody`, etc.) could potentially have "random" segfaults.
"""
actual = NumpyVersion(_actual)
minimum = NumpyVersion('1.15.0')
if actual < minimum:
raise RuntimeError(
"pydrake requires numpy >= {}, but only {} is present".format(
minimum.vstring, actual.vstring))


def maybe_patch_numpy_formatters():
"""Required to permit printing of symbolic array types in NumPy < 1.13.0.

See #8729 for more information.
"""
# Provides version-dependent monkey-patch which effectively achieves a
# portion of https://github.com/numpy/numpy/pull/8963
patch = _patches['numpy_formatters']
if not patch['required']:
return
if patch['applied']:
return
module = np.core.arrayprint
defer_callable_types = [
'IntegerFormat',
'FloatFormat',
]
for name in defer_callable_types:
original = getattr(module, name)
deferred = _defer_callable_type(original)
setattr(module, name, deferred)
patch['applied'] = True
"""Deprecated functionality."""
_warn_deprecated(
"`maybe_patch_numpy_formatters` is no longer needed, and will "
"be removed after 2019/01", stacklevel=3)
38 changes: 13 additions & 25 deletions bindings/pydrake/common/test/compatibility_test.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,21 @@
import pydrake.common.compatibility as mut

import numpy as np
import unittest
import warnings

numpy_formatters = mut._patches["numpy_formatters"]

# TODO(eric.cousineau): Try to reproduce NumPy formatter patch with mock types.
# Even with creating a `MockSymbol` type which returns a `MockFormula` which
# raises an error on `__nonzero__`, I could not get the error relevant to #8729
# to trigger via `np.maximum.reduce` (but could trigger the error via
# `np.max`).
import numpy as np


class TestCompatibility(unittest.TestCase):
@unittest.skipIf(not numpy_formatters["required"], "Patch not required")
def test_numpy_formatters(self):
# Ensure that the expected types have been patched with the `Deferred`
# type.
expect_deferred = [
'IntegerFormat',
'FloatFormat',
]
# Before patching.
self.assertFalse(numpy_formatters["applied"])
module = np.core.arrayprint
for name in expect_deferred:
self.assertNotIn("Deferred", str(getattr(module, name)))
# Apply patch.
mut.maybe_patch_numpy_formatters()
self.assertTrue(numpy_formatters["applied"])
for name in expect_deferred:
self.assertIn("Deferred", str(getattr(module, name)))
# Call for backwards compatibility.
with warnings.catch_warnings(record=True) as w:
mut.maybe_patch_numpy_formatters()
self.assertEqual(len(w), 1)

def test_numpy_version(self):
# This should pass nominally.
mut.check_required_numpy_version()
# Mock in an old version.
with self.assertRaises(RuntimeError):
mut.check_required_numpy_version(_actual="1.11.0")
4 changes: 0 additions & 4 deletions bindings/pydrake/symbolic_py.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ PYBIND11_MODULE(symbolic, m) {
py::module::import("pydrake.util.deprecation")
.attr("install_numpy_warning_filters")();

// Install NumPy formatters patch.
py::module::import("pydrake.util.compatibility")
.attr("maybe_patch_numpy_formatters")();

m.doc() =
"Symbolic variable, variables, monomial, expression, polynomial, and "
"formula";
Expand Down
1 change: 0 additions & 1 deletion setup/ubuntu/16.04/binary_distribution/packages.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ libyaml-cpp0.5v5
python
python-lxml
python-matplotlib
python-numpy
python-pydot
python-scipy
python-six
Expand Down
1 change: 0 additions & 1 deletion setup/ubuntu/18.04/binary_distribution/packages.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ libyaml-cpp0.5v5
python
python-lxml
python-matplotlib
python-numpy
python-pydot
python-scipy
python-six
Expand Down
3 changes: 3 additions & 0 deletions tools/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ py_binary(
"//tools/workspace/drake_visualizer:stub_pydrake",
"//tools/workspace/drake_visualizer/plugin",
"@drake_visualizer//:drake_visualizer_python_deps",
# TODO(eric.cousineau): Move `numpy_py` dependency to a `vtk` Python
# library.
"@numpy_py",
"@optitrack_driver//lcmtypes:py_optitrack_lcmtypes",
],
)
Expand Down
4 changes: 4 additions & 0 deletions tools/skylark/pybind.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ def pybind_py_library(
visibility = visibility,
)

# Ensure that we're always using our custom NumPy version.
if "@numpy_py" not in py_deps:
py_deps = py_deps + ["@numpy_py"]

# Add Python library.
py_library_rule(
name = py_name,
Expand Down
1 change: 1 addition & 0 deletions tools/workspace/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ _DRAKE_EXTERNAL_PACKAGE_INSTALLS = ["@%s//:install" % p for p in [
"lcmtypes_robotlocomotion",
"meshcat",
"meshcat_python",
"numpy_py",
"octomap",
"osqp",
"pybind11",
Expand Down
6 changes: 3 additions & 3 deletions tools/workspace/default.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ load("@drake//tools/workspace/meshcat_python:repository.bzl", "meshcat_python_re
load("@drake//tools/workspace/mosek:repository.bzl", "mosek_repository")
load("@drake//tools/workspace/net_sf_jchart2d:repository.bzl", "net_sf_jchart2d_repository") # noqa
load("@drake//tools/workspace/nlopt:repository.bzl", "nlopt_repository")
load("@drake//tools/workspace/numpy:repository.bzl", "numpy_repository")
load("@drake//tools/workspace/numpy_py:repository.bzl", "numpy_py_repository")
load("@drake//tools/workspace/octomap:repository.bzl", "octomap_repository")
load("@drake//tools/workspace/optitrack_driver:repository.bzl", "optitrack_driver_repository") # noqa
load("@drake//tools/workspace/org_apache_xmlgraphics_commons:repository.bzl", "org_apache_xmlgraphics_commons_repository") # noqa
Expand Down Expand Up @@ -168,8 +168,8 @@ def add_default_repositories(excludes = [], mirrors = DEFAULT_MIRRORS):
net_sf_jchart2d_repository(name = "net_sf_jchart2d", mirrors = mirrors)
if "nlopt" not in excludes:
nlopt_repository(name = "nlopt")
if "numpy" not in excludes:
numpy_repository(name = "numpy")
if "numpy_py" not in excludes:
numpy_py_repository(name = "numpy_py", mirrors = mirrors)
if "octomap" not in excludes:
octomap_repository(name = "octomap", mirrors = mirrors)
if "optitrack_driver" not in excludes:
Expand Down
6 changes: 3 additions & 3 deletions tools/workspace/mirrors.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ DEFAULT_MIRRORS = {
"http://maven.ibiblio.org/maven2/{fulljar}",
],
"pypi": [
"https://files.pythonhosted.org/packages/source/{p}/{package}/{package}-{version}.tar.gz", # noqa
"https://drake-mirror.csail.mit.edu/pypi/{package}/{package}-{version}.tar.gz", # noqa
"https://s3.amazonaws.com/drake-mirror/pypi/{package}/{package}-{version}.tar.gz", # noqa
"https://files.pythonhosted.org/packages/{pypi_path}/{filename}", # noqa
"https://drake-mirror.csail.mit.edu/pypi/{pypi_path}/{filename}", # noqa
"https://s3.amazonaws.com/drake-mirror/pypi/{pypi_path}/{filename}", # noqa
],
"vtk": [
"https://drake-packages.csail.mit.edu/vtk/{archive}",
Expand Down
8 changes: 0 additions & 8 deletions tools/workspace/numpy/BUILD.bazel

This file was deleted.

83 changes: 0 additions & 83 deletions tools/workspace/numpy/repository.bzl

This file was deleted.

5 changes: 5 additions & 0 deletions tools/workspace/numpy_py/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# -*- python -*-

load("//tools/lint:lint.bzl", "add_lint_tests")

add_lint_tests()
Loading