Skip to content

Commit

Permalink
[parsing] Add support for remote packages
Browse files Browse the repository at this point in the history
  • Loading branch information
jwnimmer-tri committed Mar 21, 2023
1 parent 8ea4342 commit 77a1885
Show file tree
Hide file tree
Showing 12 changed files with 659 additions and 33 deletions.
16 changes: 14 additions & 2 deletions bindings/pydrake/multibody/parsing_py.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,26 @@ PYBIND11_MODULE(parsing, m) {
using Class = PackageMap;
constexpr auto& cls_doc = doc.PackageMap;
py::class_<Class> cls(m, "PackageMap", cls_doc.doc);
{
using Nested = PackageMap::RemoteParams;
constexpr auto& nested_doc = cls_doc.RemoteParams;
py::class_<Nested> nested(cls, "RemoteParams", nested_doc.doc);
nested.def(ParamInit<Nested>());
nested.def("ToJson", &Nested::ToJson, nested_doc.ToJson.doc);
DefAttributesUsingSerialize(&nested, nested_doc);
DefReprUsingSerialize(&nested);
DefCopyAndDeepCopy(&nested);
}
cls // BR
.def(py::init<>(), cls_doc.ctor.doc)
.def(py::init<const Class&>(), py::arg("other"), "Copy constructor")
.def("Add", &Class::Add, py::arg("package_name"),
py::arg("package_path"), cls_doc.Add.doc)
.def("AddMap", &Class::AddMap, py::arg("other_map"), cls_doc.AddMap.doc)
.def("AddPackageXml", &Class::AddPackageXml, py::arg("filename"),
cls_doc.AddPackageXml.doc)
.def("AddRemote", &Class::AddRemote, py::arg("package_name"),
py::arg("params"))
.def("Contains", &Class::Contains, py::arg("package_name"),
cls_doc.Contains.doc)
.def("Remove", &Class::Remove, py::arg("package_name"),
Expand All @@ -53,8 +67,6 @@ PYBIND11_MODULE(parsing, m) {
return self.GetPath(package_name);
},
py::arg("package_name"), cls_doc.GetPath.doc)
.def("AddPackageXml", &Class::AddPackageXml, py::arg("filename"),
cls_doc.AddPackageXml.doc)
.def("PopulateFromFolder", &Class::PopulateFromFolder, py::arg("path"),
cls_doc.PopulateFromFolder.doc)
.def("PopulateFromEnvironment", &Class::PopulateFromEnvironment,
Expand Down
28 changes: 28 additions & 0 deletions bindings/pydrake/multibody/test/parsing_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,34 @@ def test_package_map(self):
dut.PopulateFromEnvironment(environment_variable='TEST_TMPDIR')
dut.PopulateFromFolder(path=tmpdir)

def test_package_map_remote_params(self):
dut = PackageMap.RemoteParams(
urls=["file:///tmp/missing.zip"],
sha256="0" * 64,
archive_type="zip",
strip_prefix="prefix",)
self.assertIn("missing.zip", dut.ToJson())
copy.copy(dut)
copy.deepcopy(dut)

def test_package_map_add_remote(self):
"""Runs a full lifecycle of AddRemote + GetPath to check that Python
bindings calling C++ code that shells out to Python all plays nice.
"""
dut = PackageMap.MakeEmpty()
zipfile = FindResourceOrThrow(
"drake/multibody/parsing/test/package_map_test_packages/"
"compressed.zip")
dut.AddRemote(package_name="compressed",
params=PackageMap.RemoteParams(
urls=[f"file://{zipfile}"],
sha256=("b4bdbad313293ca61fe8f4ed1b5579da"
"dadb3a5c08f0a6d06a8e39e5f97f1bd1"),
strip_prefix="compressed_prefix"))
path = dut.GetPath("compressed")
with open(f"{path}/README", encoding="utf-8") as f:
self.assertEqual(f.read(), "This package is empty.\n")

def test_parser_file(self):
"""Calls every combination of arguments for the Parser methods which
use a file_name (not contents) and inspects their return type.
Expand Down
23 changes: 21 additions & 2 deletions multibody/parsing/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ filegroup(
testonly = 1,
srcs = glob([
"test/**/*.config",
"test/**/*.dmd.yaml",
"test/**/*.obj",
"test/**/*.png",
"test/**/*.sdf",
"test/**/*.urdf",
"test/**/*.xml",
"test/**/*.dmd.yaml",
"test/**/*.png",
"test/**/*.zip",
"test/**/COLCON_IGNORE",
]),
visibility = ["//visibility:public"],
Expand Down Expand Up @@ -66,10 +67,14 @@ drake_cc_library(
visibility = ["//visibility:public"],
interface_deps = [
"//common:essential",
"//common:name_value",
],
deps = [
"//common:find_cache",
"//common:find_resource",
"//common:find_runfiles",
"//common:scope_exit",
"//common/yaml",
"@tinyxml2_internal//:tinyxml2",
],
)
Expand Down Expand Up @@ -622,6 +627,20 @@ drake_cc_googletest(
],
)

drake_cc_googletest(
name = "package_map_remote_test",
data = [
":test_models",
],
deps = [
":package_map",
"//common:find_cache",
"//common:find_resource",
"//common:scope_exit",
"//common/test_utilities:expect_throws_message",
],
)

drake_cc_googletest(
name = "drake_manifest_resolution_test",
data = [
Expand Down
7 changes: 6 additions & 1 deletion multibody/parsing/package_downloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,13 @@ def _run(*, temp_dir: Path, package_name: str, urls: List[str], sha256: str,


def _main(argv):
# We expect exactly two command-line arguments to this program:
# - The filename containing JSON data with our *actual* arguments.
# - A dummy argument that we'll ignore. (It's sometimes used by our caller
# to suppress valgrind when we're called from C++ code).
config_json, _ = argv

# Read our config file.
config_json, = argv
with open(config_json, "r") as f:
kwargs = json.load(f)

Expand Down
Loading

0 comments on commit 77a1885

Please sign in to comment.