Skip to content
Snippets Groups Projects
Unverified Commit 2176e151 authored by Thorsten Hater's avatar Thorsten Hater Committed by GitHub
Browse files

:snake: Be more lenient when accepting args to file I/O (#1819)

PyArbor I/O routines now try to cast `filename` arguments to a string.
This allows passing `pathlib.Path` objects.

Example
```py
here = Path(__file__).parent
cat = A.load_catalogue(here / 'local-catalogue.so')
```
parent ba781cb5
No related branches found
No related tags found
No related merge requests found
...@@ -9,14 +9,18 @@ ...@@ -9,14 +9,18 @@
#include <arborio/cableio.hpp> #include <arborio/cableio.hpp>
#include "error.hpp" #include "error.hpp"
#include "util.hpp"
#include "strprintf.hpp" #include "strprintf.hpp"
namespace pyarb { namespace pyarb {
arborio::cable_cell_component load_component(const std::string& fname) { namespace py = pybind11;
arborio::cable_cell_component load_component(py::object fn) {
const auto fname = util::to_path(fn);
std::ifstream fid{fname}; std::ifstream fid{fname};
if (!fid.good()) { if (!fid.good()) {
throw pyarb_error("Can't open file '{}'" + fname); throw arb::file_not_found_error(fname);
} }
auto component = arborio::parse_component(fid); auto component = arborio::parse_component(fid);
if (!component) { if (!component) {
...@@ -26,13 +30,13 @@ arborio::cable_cell_component load_component(const std::string& fname) { ...@@ -26,13 +30,13 @@ arborio::cable_cell_component load_component(const std::string& fname) {
}; };
template<typename T> template<typename T>
void write_component(const T& component, const std::string& fname) { void write_component(const T& component, py::object fn) {
std::ofstream fid(fname); std::ofstream fid(util::to_path(fn));
arborio::write_component(fid, component, arborio::meta_data{}); arborio::write_component(fid, component, arborio::meta_data{});
} }
void write_component(const arborio::cable_cell_component& component, const std::string& fname) { void write_component(const arborio::cable_cell_component& component, py::object fn) {
std::ofstream fid(fname); std::ofstream fid(util::to_path(fn));
arborio::write_component(fid, component); arborio::write_component(fid, component);
} }
...@@ -43,40 +47,40 @@ void register_cable_loader(pybind11::module& m) { ...@@ -43,40 +47,40 @@ void register_cable_loader(pybind11::module& m) {
"Load arbor-component (decor, morphology, label_dict, cable_cell) from file."); "Load arbor-component (decor, morphology, label_dict, cable_cell) from file.");
m.def("write_component", m.def("write_component",
[](const arborio::cable_cell_component& d, const std::string& fname) { [](const arborio::cable_cell_component& d, py::object fn) {
return write_component(d, fname); return write_component(d, fn);
}, },
pybind11::arg_v("object", "the cable_component object."), pybind11::arg_v("object", "the cable_component object."),
pybind11::arg_v("filename", "the name of the file."), pybind11::arg_v("filename", "the path of the file."),
"Write cable_component to file."); "Write cable_component to file.");
m.def("write_component", m.def("write_component",
[](const arb::decor& d, const std::string& fname) { [](const arb::decor& d, py::object fn) {
return write_component<arb::decor>(d, fname); return write_component<arb::decor>(d, fn);
}, },
pybind11::arg_v("object", "the decor object."), pybind11::arg_v("object", "the decor object."),
pybind11::arg_v("filename", "the name of the file."), pybind11::arg_v("filename", "the name of the file."),
"Write decor to file."); "Write decor to file.");
m.def("write_component", m.def("write_component",
[](const arb::label_dict& d, const std::string& fname) { [](const arb::label_dict& d, py::object fn) {
return write_component<arb::label_dict>(d, fname); return write_component<arb::label_dict>(d, fn);
}, },
pybind11::arg_v("object", "the label_dict object."), pybind11::arg_v("object", "the label_dict object."),
pybind11::arg_v("filename", "the name of the file."), pybind11::arg_v("filename", "the name of the file."),
"Write label_dict to file."); "Write label_dict to file.");
m.def("write_component", m.def("write_component",
[](const arb::morphology& d, const std::string& fname) { [](const arb::morphology& d, py::object fn) {
return write_component<arb::morphology>(d, fname); return write_component<arb::morphology>(d, fn);
}, },
pybind11::arg_v("object", "the morphology object."), pybind11::arg_v("object", "the morphology object."),
pybind11::arg_v("filename", "the name of the file."), pybind11::arg_v("filename", "the name of the file."),
"Write morphology to file."); "Write morphology to file.");
m.def("write_component", m.def("write_component",
[](const arb::cable_cell& d, const std::string& fname) { [](const arb::cable_cell& d, py::object fn) {
return write_component<arb::cable_cell>(d, fname); return write_component<arb::cable_cell>(d, fn);
}, },
pybind11::arg_v("object", "the cable_cell object."), pybind11::arg_v("object", "the cable_cell object."),
pybind11::arg_v("filename", "the name of the file."), pybind11::arg_v("filename", "the name of the file."),
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "arbor/mechinfo.hpp" #include "arbor/mechinfo.hpp"
#include "util.hpp"
#include "conversion.hpp" #include "conversion.hpp"
#include "strprintf.hpp" #include "strprintf.hpp"
...@@ -197,7 +198,7 @@ void register_mechanisms(pybind11::module& m) { ...@@ -197,7 +198,7 @@ void register_mechanisms(pybind11::module& m) {
m.def("default_catalogue", [](){return arb::global_default_catalogue();}); m.def("default_catalogue", [](){return arb::global_default_catalogue();});
m.def("allen_catalogue", [](){return arb::global_allen_catalogue();}); m.def("allen_catalogue", [](){return arb::global_allen_catalogue();});
m.def("bbp_catalogue", [](){return arb::global_bbp_catalogue();}); m.def("bbp_catalogue", [](){return arb::global_bbp_catalogue();});
m.def("load_catalogue", [](const std::string& fn){return arb::load_catalogue(fn);}); m.def("load_catalogue", [](pybind11::object fn) { return arb::load_catalogue(util::to_string(fn)); });
// arb::mechanism_desc // arb::mechanism_desc
// For specifying a mechanism in the cable_cell interface. // For specifying a mechanism in the cable_cell interface.
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <arborio/neuroml.hpp> #include <arborio/neuroml.hpp>
#endif #endif
#include "util.hpp"
#include "error.hpp" #include "error.hpp"
#include "proxy.hpp" #include "proxy.hpp"
#include "strprintf.hpp" #include "strprintf.hpp"
...@@ -250,10 +251,11 @@ void register_morphology(py::module& m) { ...@@ -250,10 +251,11 @@ void register_morphology(py::module& m) {
// Function that creates a morphology from an swc file. // Function that creates a morphology from an swc file.
// Wraps calls to C++ functions arborio::parse_swc() and arborio::load_swc_arbor(). // Wraps calls to C++ functions arborio::parse_swc() and arborio::load_swc_arbor().
m.def("load_swc_arbor", m.def("load_swc_arbor",
[](std::string fname) { [](py::object fn) {
const auto fname = util::to_path(fn);
std::ifstream fid{fname}; std::ifstream fid{fname};
if (!fid.good()) { if (!fid.good()) {
throw pyarb_error(util::pprintf("can't open file '{}'", fname)); throw arb::file_not_found_error(fname);
} }
try { try {
auto data = arborio::parse_swc(fid); auto data = arborio::parse_swc(fid);
...@@ -275,10 +277,11 @@ void register_morphology(py::module& m) { ...@@ -275,10 +277,11 @@ void register_morphology(py::module& m) {
" are no gaps in the resulting morphology."); " are no gaps in the resulting morphology.");
m.def("load_swc_neuron", m.def("load_swc_neuron",
[](std::string fname) { [](py::object fn) {
const auto fname = util::to_path(fn);
std::ifstream fid{fname}; std::ifstream fid{fname};
if (!fid.good()) { if (!fid.good()) {
throw pyarb_error(util::pprintf("can't open file '{}'", fname)); throw arb::file_not_found_error(fname);
} }
try { try {
auto data = arborio::parse_swc(fid); auto data = arborio::parse_swc(fid);
...@@ -383,10 +386,11 @@ void register_morphology(py::module& m) { ...@@ -383,10 +386,11 @@ void register_morphology(py::module& m) {
neuroml neuroml
// constructors // constructors
.def(py::init( .def(py::init(
[](std::string fname) { [](py::object fn) {
const auto fname = util::to_path(fn);
std::ifstream fid{fname}; std::ifstream fid{fname};
if (!fid.good()) { if (!fid.good()) {
throw pyarb_error(util::pprintf("can't open file '{}'", fname)); throw arb::file_not_found_error(fname);
} }
try { try {
std::string string_data((std::istreambuf_iterator<char>(fid)), std::string string_data((std::istreambuf_iterator<char>(fid)),
......
#pragma once
#include <pybind11/pybind11.h>
#include "strprintf.hpp"
namespace pyarb {
namespace util {
namespace py = pybind11;
inline
std::string to_path(py::object fn) {
if (py::isinstance<py::str>(fn)) {
return std::string{py::str(fn)};
}
else if (py::isinstance(fn,
py::module_::import("pathlib").attr("Path"))) {
return std::string{py::str(fn)};
}
throw std::runtime_error(
util::strprintf("Cannot convert objects of type '{}' to a path-like.",
std::string{py::str(fn.get_type())}));
}
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment