From b9a81d9675a1ff4f4c11d4239ddcd7d82aaa6f08 Mon Sep 17 00:00:00 2001 From: Howard Butler Date: Fri, 3 Dec 2021 13:29:41 -0600 Subject: [PATCH 1/2] alternative fetches of drivers and options --- pdal/drivers.py | 21 +++++++++++++ pdal/libpdalpython.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/pdal/drivers.py b/pdal/drivers.py index 54ea8820..4ca8b2ed 100644 --- a/pdal/drivers.py +++ b/pdal/drivers.py @@ -4,6 +4,9 @@ from typing import Callable, ClassVar, FrozenSet, Mapping, Optional, Sequence, Type from .pipeline import Filter, Reader, Stage, Writer +from . import libpdalpython + +import shlex StreamableTypes: FrozenSet @@ -59,6 +62,11 @@ def factory(self) -> Callable[..., Stage]: def inject_pdal_drivers() -> None: + +# drivers = libpdalpython.getDrivers() +# +# options = libpdalpython.getOptions() + drivers = json.loads( subprocess.run(["pdal", "--drivers", "--showjson"], capture_output=True).stdout ) @@ -69,6 +77,19 @@ def inject_pdal_drivers() -> None: ).stdout ) ) + + command = 'pdal --options all --showjson' + + p = subprocess.run(shlex.split(command), + encoding='utf-8', + capture_output=True) + output, error = p.stdout, p.stderr + if p.returncode: + print (f'return code {p.returncode} error: "{error}"') + if error: + raise RuntimeError(f"Unable to run pdal --options with error '{error}'") + + options = dict( json.loads( output )) streamable = [] for d in drivers: name = d["name"] diff --git a/pdal/libpdalpython.cpp b/pdal/libpdalpython.cpp index b3dfca90..f1c2b818 100644 --- a/pdal/libpdalpython.cpp +++ b/pdal/libpdalpython.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,72 @@ namespace pdal { ); }; + std::vector getDrivers() { + py::gil_scoped_acquire acquire; + std::vector drivers; + + pdal::StageFactory f(false); + pdal::PluginManager::loadAll(); + pdal::StringList stages = pdal::PluginManager::names(); + + pdal::StageExtensions& extensions = pdal::PluginManager::extensions(); + for (auto name : stages) + { + pdal::Stage *s = f.createStage(name); + std::string description = pdal::PluginManager::description(name); + std::string link = pdal::PluginManager::link(name); + std::vector extension_names = extensions.extensions(name); + + py::dict d( + "name"_a=name, + "description"_a=description, + "streamable"_a=s->pipelineStreamable(), + "extensions"_a=extension_names + ); + f.destroyStage(s); + drivers.push_back(std::move(d)); + } + return drivers; + + }; + + std::vector getOptions() { + py::gil_scoped_acquire acquire; + py::object json = py::module_::import("json"); + std::vector stageOptions; + + pdal::StageFactory f; + pdal::PluginManager::loadAll(); + pdal::StringList stages = pdal::PluginManager::names(); + + for (auto name : stages) + { + if ( name == "filters.info" ) continue; + pdal::Stage *s = f.createStage(name); + pdal::ProgramArgs args; + s->addAllArgs(args); + std::ostringstream ostr; + args.dump3(ostr); + py::str pystring(ostr.str()); + pystring.attr("strip"); + + py::object j; + + try { + j = json.attr("loads")(pystring); + } catch (py::error_already_set &e) { + std::cout << "failed:" << name << "'" << ostr.str() << "'" < getDimensions() { py::object np = py::module_::import("numpy"); py::object dtype = np.attr("dtype"); @@ -169,6 +236,8 @@ namespace pdal { .def("_get_json", &Pipeline::getJson) .def("_del_executor", &Pipeline::delExecutor); m.def("getInfo", &getInfo); + m.def("getDrivers", &getDrivers); + m.def("getOptions", &getOptions); m.def("getDimensions", &getDimensions); m.def("infer_reader_driver", &StageFactory::inferReaderDriver); m.def("infer_writer_driver", &StageFactory::inferWriterDriver); diff --git a/setup.py b/setup.py index 8c508c85..d3738f3d 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ changes = fp.read() setup( - name="PDAL", + name="python-pdal", version=version, description="Point cloud data processing", license="BSD", From 1b8573d9f6b8cb79f14a451b8f9ec04219b93ebd Mon Sep 17 00:00:00 2001 From: Andrew Bell Date: Fri, 3 Dec 2021 16:13:48 -0500 Subject: [PATCH 2/2] Make return type of options a dictionary, as expected. --- pdal/drivers.py | 30 ++---------------------------- pdal/libpdalpython.cpp | 12 +++++------- 2 files changed, 7 insertions(+), 35 deletions(-) diff --git a/pdal/drivers.py b/pdal/drivers.py index 4ca8b2ed..5737b27a 100644 --- a/pdal/drivers.py +++ b/pdal/drivers.py @@ -62,34 +62,8 @@ def factory(self) -> Callable[..., Stage]: def inject_pdal_drivers() -> None: - -# drivers = libpdalpython.getDrivers() -# -# options = libpdalpython.getOptions() - - drivers = json.loads( - subprocess.run(["pdal", "--drivers", "--showjson"], capture_output=True).stdout - ) - options = dict( - json.loads( - subprocess.run( - ["pdal", "--options", "all", "--showjson"], capture_output=True - ).stdout - ) - ) - - command = 'pdal --options all --showjson' - - p = subprocess.run(shlex.split(command), - encoding='utf-8', - capture_output=True) - output, error = p.stdout, p.stderr - if p.returncode: - print (f'return code {p.returncode} error: "{error}"') - if error: - raise RuntimeError(f"Unable to run pdal --options with error '{error}'") - - options = dict( json.loads( output )) + drivers = libpdalpython.getDrivers() + options = libpdalpython.getOptions() streamable = [] for d in drivers: name = d["name"] diff --git a/pdal/libpdalpython.cpp b/pdal/libpdalpython.cpp index f1c2b818..9dc920c1 100644 --- a/pdal/libpdalpython.cpp +++ b/pdal/libpdalpython.cpp @@ -57,10 +57,10 @@ namespace pdal { }; - std::vector getOptions() { + std::map getOptions() { py::gil_scoped_acquire acquire; py::object json = py::module_::import("json"); - std::vector stageOptions; + std::map stageOptions; pdal::StageFactory f; pdal::PluginManager::loadAll(); @@ -87,12 +87,10 @@ namespace pdal { } f.destroyStage(s); - py::list l = py::make_tuple( name, pystring); - stageOptions.push_back(std::move(l)); + stageOptions[name] = j; } - return stageOptions; - - }; + return stageOptions; + } std::vector getDimensions() { py::object np = py::module_::import("numpy");