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')