diff --git a/python/cells.cpp b/python/cells.cpp index 0d4e6a44de15f19f0e199b134bbe3d9a4a17b19d..b6330912c9c1b2a556d876581079b41221b8e8c9 100644 --- a/python/cells.cpp +++ b/python/cells.cpp @@ -228,33 +228,65 @@ void register_cells(pybind11::module& m) { pybind11::class_<label_dict_proxy> label_dict(m, "label_dict", "A dictionary of labelled region and locset definitions, with a\n" - "unique label is assigned to each definition."); + "unique label assigned to each definition."); label_dict .def(pybind11::init<>(), "Create an empty label dictionary.") .def(pybind11::init<const std::unordered_map<std::string, std::string>&>(), "Initialize a label dictionary from a dictionary with string labels as keys," " and corresponding definitions as strings.") + .def(pybind11::init<const label_dict_proxy&>(), + "Initialize a label dictionary from another one") + .def(pybind11::init([](pybind11::iterator& it) { + label_dict_proxy ld; + for (; it != pybind11::iterator::sentinel(); ++it) { + const auto tuple = it->cast<pybind11::sequence>(); + const auto key = tuple[0].cast<std::string>(); + const auto value = tuple[1].cast<std::string>(); + ld.set(key, value); + } + return ld; + }), + "Initialize a label dictionary from an iterable of key, definition pairs") .def("__setitem__", [](label_dict_proxy& l, const char* name, const char* desc) { l.set(name, desc);}) .def("__getitem__", [](label_dict_proxy& l, const char* name) { - if (!l.cache.count(name)) { - throw pybind11::key_error(name); - } - return l.cache.at(name); + if (auto v = l.getitem(name)) return v.value(); + throw pybind11::key_error(name); }) .def("__len__", &label_dict_proxy::size) .def("__iter__", [](const label_dict_proxy &ld) { return pybind11::make_key_iterator(ld.cache.begin(), ld.cache.end());}, pybind11::keep_alive<0, 1>()) + .def("__contains__", + [](const label_dict_proxy &ld, const char* name) { + return ld.contains(name);}) + .def("keys", + [](const label_dict_proxy &ld) { + return pybind11::make_key_iterator(ld.cache.begin(), ld.cache.end());}, + pybind11::keep_alive<0, 1>()) + .def("items", + [](const label_dict_proxy &ld) { + return pybind11::make_iterator(ld.cache.begin(), ld.cache.end());}, + pybind11::keep_alive<0, 1>()) + .def("values", + [](const label_dict_proxy &ld) { + return pybind11::make_value_iterator(ld.cache.begin(), ld.cache.end()); + }, + pybind11::keep_alive<0, 1>()) .def("append", [](label_dict_proxy& l, const label_dict_proxy& other, const char* prefix) { l.import(other, prefix); }, "other"_a, "The label_dict to be imported" "prefix"_a="", "optional prefix appended to the region and locset labels", "Import the entries of a another label dictionary with an optional prefix.") + .def("update", [](label_dict_proxy& l, const label_dict_proxy& other) { + l.import(other); + }, + "other"_a, "The label_dict to be imported" + "Import the entries of a another label dictionary.") .def_readonly("regions", &label_dict_proxy::regions, "The region definitions.") .def_readonly("locsets", &label_dict_proxy::locsets, diff --git a/python/proxy.hpp b/python/proxy.hpp index 8f3003f13ee7dbc6dcf767495a27bd3e08b3bffd..65c44757b3a8cac13357fc0f9459d8386ea1631c 100644 --- a/python/proxy.hpp +++ b/python/proxy.hpp @@ -20,7 +20,7 @@ struct label_dict_proxy { label_dict_proxy(const str_map& in) { for (auto& i: in) { - set(i.first.c_str(), i.second.c_str()); + set(i.first, i.second); } } @@ -28,18 +28,20 @@ struct label_dict_proxy { update_cache(); } + label_dict_proxy(const label_dict_proxy&) = default; + std::size_t size() const { return locsets.size() + regions.size(); } - void import(const label_dict_proxy& other, std::string prefix) { + void import(const label_dict_proxy& other, std::string prefix = "") { dict.import(other.dict, prefix); clear_cache(); update_cache(); } - void set(const char* name, const char* desc) { + void set(const std::string& name, const std::string& desc) { using namespace std::string_literals; // The following code takes an input name and a region or locset // description, e.g.: @@ -81,7 +83,7 @@ struct label_dict_proxy { throw std::runtime_error(util::pprintf(base, name, desc, msg)); } - // Exceptions are thrown in parse or eval if an unexpected error occured. + // Exceptions are thrown in parse or eval if an unexpected error occured. catch (std::exception& e) { const char* msg = "\n----- internal error -------------------------------------------" @@ -108,6 +110,17 @@ struct label_dict_proxy { s += ")"; return s; } + + bool contains(const std::string& name) const { + return cache.find(name) != cache.end(); + } + + std::optional<std::string> getitem(const std::string& name) const { + if (auto kv = cache.find(name); kv != cache.end()) { + return kv->second; + } + return {}; + } private: diff --git a/python/pybind11 b/python/pybind11 index 8de7772cc72daca8e947b79b83fea46214931604..750e38dcfdac59231a615580d4e6cb3647b31779 160000 --- a/python/pybind11 +++ b/python/pybind11 @@ -1 +1 @@ -Subproject commit 8de7772cc72daca8e947b79b83fea46214931604 +Subproject commit 750e38dcfdac59231a615580d4e6cb3647b31779 diff --git a/spack/package.py b/spack/package.py index 259c0ce8f0a56599d9b1a2a06c31c7da0df7d0c1..df233b88eee9d9bd00745e904dc44e5e5195586a 100644 --- a/spack/package.py +++ b/spack/package.py @@ -49,7 +49,7 @@ class Arbor(CMakePackage, CudaPackage): extends('python', when='+python') depends_on('python@3.6:', when="+python", type=('build', 'run')) depends_on('py-numpy', when='+python', type=('build', 'run')) - depends_on('py-pybind11@2.6:', when='+python', type=('build', 'run')) + depends_on('py-pybind11@2.8:', when='+python', type=('build', 'run')) # sphinx based documentation depends_on('python@3.6:', when="+doc", type='build')