diff --git a/tools/install/bazel/drake.BUILD.bazel b/tools/install/bazel/drake.BUILD.bazel index 01b3ccf83a2d..988474b2be39 100644 --- a/tools/install/bazel/drake.BUILD.bazel +++ b/tools/install/bazel/drake.BUILD.bazel @@ -7,6 +7,8 @@ package(default_visibility = ["//:__subpackages__"]) _DRAKE_RUNFILES = MANIFEST["runfiles"]["drake"] +_PYTHON_SITE_PACKAGES_RELPATH = MANIFEST["python_site_packages_relpath"] + _DRAKE_ROOT_PACKAGE_RUNFILES = [x for x in _DRAKE_RUNFILES if "/" not in x] _EXPECTED_DRAKE_RUNFILES_PACKAGES = [ @@ -55,7 +57,16 @@ filegroup( ]), ) -_IMPORT = ".lib/python3.6/site-packages" +_IMPORT = "." + _PYTHON_SITE_PACKAGES_RELPATH + +# N.B. This is not a standalone Python library. +# TODO(eric.cousineau): Expose this as an alias +# `@drake//lcmtypes:lcmtypes_drake_py` when it can only depend on specific +# parts of the runfiles (not all of pydrake). +py_library( + name = ".lcmtypes_drake_py", + srcs = glob(["*.py"]), +) py_library( name = ".pydrake", @@ -68,6 +79,9 @@ py_library( ":.all_runfiles", ":.drake_shared_library", ], + deps = [ + ":.lcmtypes_drake_py", + ], imports = [ _IMPORT, ], diff --git a/tools/install/bazel/generate_installed_files_manifest.bzl b/tools/install/bazel/generate_installed_files_manifest.bzl index 2f216db40f6a..6c637859073c 100644 --- a/tools/install/bazel/generate_installed_files_manifest.bzl +++ b/tools/install/bazel/generate_installed_files_manifest.bzl @@ -2,6 +2,7 @@ # vi: set ft=python : load("@drake//tools/install:install.bzl", "InstallInfo") +load("@python//:version.bzl", "PYTHON_SITE_PACKAGES_RELPATH") def _impl(ctx): known_non_runfiles = [ @@ -13,18 +14,24 @@ def _impl(ctx): "setup/requirements.txt", ] drake_runfiles = [] + drake_prologue = "share/drake/" + lcmtypes_drake_py_files = [] + lcmtypes_drake_py_prologue = PYTHON_SITE_PACKAGES_RELPATH + "/drake/" for dest in ctx.attr.target[InstallInfo].installed_files: - prologue = "share/drake/" - if not dest.startswith(prologue): - continue - drake_relative_path = dest[len(prologue):] - if drake_relative_path in known_non_runfiles: - continue - drake_runfiles.append(drake_relative_path) + if dest.startswith(drake_prologue): + relative_path = dest[len(drake_prologue):] + if relative_path in known_non_runfiles: + continue + drake_runfiles.append(relative_path) + elif dest.startswith(lcmtypes_drake_py_prologue): + relative_path = dest[len(lcmtypes_drake_py_prologue):] + lcmtypes_drake_py_files.append(relative_path) content = { "runfiles": { "drake": sorted(drake_runfiles), }, + "lcmtypes_drake_py": sorted(lcmtypes_drake_py_files), + "python_site_packages_relpath": PYTHON_SITE_PACKAGES_RELPATH, } ctx.actions.write( output = ctx.outputs.out, diff --git a/tools/install/bazel/repo_template.bzl b/tools/install/bazel/repo_template.bzl index 49be67385cc5..e72e12858b90 100644 --- a/tools/install/bazel/repo_template.bzl +++ b/tools/install/bazel/repo_template.bzl @@ -79,6 +79,16 @@ def _drake_impl(repo_ctx): for relpath in _MANIFEST["runfiles"]["drake"]: repo_ctx.symlink(str(share_drake) + "/" + relpath, relpath) + # Symlink all drake LCM types to this repository's root package, since it + # should be named `drake` (see bazelbuild/bazel#3998). + if repo_ctx.name != "drake": + print("WARNING: Drake LCM types will not be importable via `drake` " + + "if this repository is not named `drake`.") + python_site_packages_relpath = _MANIFEST["python_site_packages_relpath"] + drake_lcmtypes_package = "." + python_site_packages_relpath + "/drake" + for relpath in _MANIFEST["lcmtypes_drake_py"]: + repo_ctx.symlink(drake_lcmtypes_package + "/" + relpath, relpath) + # Emit the manifest for later loading. manifest_bzl = "MANIFEST = " + struct(**_MANIFEST).to_json() repo_ctx.file(".manifest.bzl", content = manifest_bzl, executable = False) diff --git a/tools/install/bazel/test/drake_bazel_installed_test.py b/tools/install/bazel/test/drake_bazel_installed_test.py index 1dff3e0d9670..37ee423240d9 100644 --- a/tools/install/bazel/test/drake_bazel_installed_test.py +++ b/tools/install/bazel/test/drake_bazel_installed_test.py @@ -37,6 +37,13 @@ def main(): deps = ["@drake//bindings/pydrake"], ) +py_test( + name = "import_all_test", + srcs = ["import_all_test.py"], + size = "small", + deps = ["@drake//bindings/pydrake"], +) + # A stub for unit testing; not required for end users. filegroup(name = "dummy_filegroup") """) @@ -46,6 +53,11 @@ def main(): from pydrake.common import FindResourceOrThrow, set_log_level set_log_level("trace") FindResourceOrThrow("drake/examples/pendulum/Pendulum.urdf") +""") + + with open(join(scratch_dir, "import_all_test.py"), "w") as f: + f.write(f""" +import pydrake.all """) # Check that a full `bazel test` passes.