diff --git a/arbor/include/arbor/mechcat.hpp b/arbor/include/arbor/mechcat.hpp index 0fc0a23fabeb678375f9c357937231c5ae80795d..436edbc2d21d794c2b26e4065c920a271825c914 100644 --- a/arbor/include/arbor/mechcat.hpp +++ b/arbor/include/arbor/mechcat.hpp @@ -110,6 +110,9 @@ public: ~mechanism_catalogue(); + // Grab a collection of all mechanism names in the catalogue. + std::vector<std::string> mechanism_names() const; + private: std::unique_ptr<catalogue_state> state_; diff --git a/arbor/mechcat.cpp b/arbor/mechcat.cpp index 3fac9e805dc2aeabe7d479d6682c5ce57ab56ccc..001ab95eb75dca4b06f9465239328997ac01a1b9 100644 --- a/arbor/mechcat.cpp +++ b/arbor/mechcat.cpp @@ -8,6 +8,7 @@ #include <arbor/mechcat.hpp> #include <arbor/util/expected.hpp> +#include "util/rangeutil.hpp" #include "util/maputil.hpp" /* Notes on implementation: @@ -479,6 +480,14 @@ struct catalogue_state { return over; } + // Collect all mechanism names present in this catalogue + std::vector<std::string> mechanism_names() const { + std::vector<std::string> result; + util::assign(result, util::keys(info_map_)); + util::append(result, util::keys(derived_map_)); + return result; + } + // Schemata for (un-derived) mechanisms. string_map<mechanism_info_ptr> info_map_; @@ -495,6 +504,10 @@ mechanism_catalogue::mechanism_catalogue(): state_(new catalogue_state) {} +std::vector<std::string> mechanism_catalogue::mechanism_names() const { + return state_->mechanism_names(); +} + mechanism_catalogue::mechanism_catalogue(mechanism_catalogue&& other) = default; mechanism_catalogue& mechanism_catalogue::operator=(mechanism_catalogue&& other) = default; diff --git a/doc/python/mechanisms.rst b/doc/python/mechanisms.rst index e31f137a2979f171ee10f3a83938406282e5d78b..b55aa460a8604f180eb5e60bded2a30eeda5c184 100644 --- a/doc/python/mechanisms.rst +++ b/doc/python/mechanisms.rst @@ -280,6 +280,12 @@ Mechanism catalogues :return: mechanism metadata :rtype: :class:`mechanism_info` + .. py:method:: names() + + Return a list names of all the mechanisms in the catalogue. + + :return: list + .. py:method:: derive(name, parent, globals={}, ions={}) Derive a new mechanism with *name* from the mechanism *parent*. diff --git a/python/mechanism.cpp b/python/mechanism.cpp index 9c65cc2d8858cf3b3e2bfd991109296e87e67c75..e0fc984636d7c53e140cd4ed6cb8f8e77a1bd683 100644 --- a/python/mechanism.cpp +++ b/python/mechanism.cpp @@ -107,7 +107,9 @@ void register_mechanisms(pybind11::module& m) { cat .def(pybind11::init<const arb::mechanism_catalogue&>()) .def("has", &arb::mechanism_catalogue::has, - "name"_a, "Is 'name' in the catalogue?") + "name"_a, "Is 'name' in the catalogue?") + .def("keys", &arb::mechanism_catalogue::mechanism_names, + "Return a list of all mechanisms in this catalogues.") .def("is_derived", &arb::mechanism_catalogue::is_derived, "name"_a, "Is 'name' a derived mechanism or can it be implicitly derived?") .def("__getitem__", diff --git a/test/unit/test_mechcat.cpp b/test/unit/test_mechcat.cpp index 31526aa2c8e840861ace53879666658d94129ee5..ffd6b26510c9d79564609062db3bb7ae7c66cd60 100644 --- a/test/unit/test_mechcat.cpp +++ b/test/unit/test_mechcat.cpp @@ -244,6 +244,48 @@ TEST(mechcat, fingerprint) { arb::fingerprint_mismatch); } +TEST(mechcat, names) { + // All names are caught; covers `add' and `derive' + { + auto cat = build_fake_catalogue(); + auto names = cat.mechanism_names(); + auto expect = std::vector<std::string>{"bleeble", "burble", "fleeb", "fleeb1", "fleeb2", "fleeb3", "special_fleeb"}; + std::sort(names.begin(), names.end()); + EXPECT_EQ(names, expect); + } + + // Deriving names does not add to catalogue + { + auto cat = build_fake_catalogue(); + auto info = cat["burble/quux=3,xyzzy=4"]; + auto names = cat.mechanism_names(); + auto expect = std::vector<std::string>{"bleeble", "burble", "fleeb", "fleeb1", "fleeb2", "fleeb3", "special_fleeb"}; + std::sort(names.begin(), names.end()); + EXPECT_EQ(names, expect); + } + + // Deleting a mechanism removes it and all derived from it. + { + auto cat = build_fake_catalogue(); + cat.remove("fleeb"); + auto names = cat.mechanism_names(); + auto expect = std::vector<std::string>{"bleeble", "burble"}; + std::sort(names.begin(), names.end()); + EXPECT_EQ(names, expect); + } + + // Empty means empty. + { + auto cat = build_fake_catalogue(); + cat.remove("fleeb"); + cat.remove("burble"); + auto names = cat.mechanism_names(); + auto expect = std::vector<std::string>{}; + std::sort(names.begin(), names.end()); + EXPECT_EQ(names, expect); + } +} + TEST(mechcat, derived_info) { auto cat = build_fake_catalogue();