lsst.daf.base  13.0-2-g167564e+7
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
propertyList.cc
Go to the documentation of this file.
1 #include "pybind11/pybind11.h"
2 #include "pybind11/stl.h"
3 
7 
8 namespace py = pybind11;
9 using namespace pybind11::literals;
10 
11 namespace lsst {
12 namespace daf {
13 namespace base {
14 namespace {
15 
16 template <typename T, typename C>
17 void declareAccessors(C& cls, std::string const& name) {
18  const std::string getName = "get" + name;
19  cls.def(getName.c_str(), (T (PropertyList::*)(std::string const&) const) & PropertyList::get<T>,
20  "name"_a);
21  cls.def(getName.c_str(), (T (PropertyList::*)(std::string const&, T const&) const) & PropertyList::get<T>,
22  "name"_a, "defaultValue"_a);
23 
24  // Warning: __len__ is ambiguous so do not attempt to define it. It could return
25  // the number of unique names or the number of entries (e.g. as returned by toList,
26  // a pure Python method). C++ begin and end iterate over unique names, but users often
27  // view PropertyList as a representation of a FITS header. When in doubt, refuse to guess.
28 
29  const std::string getArrayName = "getArray" + name;
30  cls.def(getArrayName.c_str(),
31  (std::vector<T> (PropertyList::*)(std::string const&) const) & PropertyList::getArray<T>,
32  "name"_a);
33 
34  const std::string setName = "set" + name;
35  cls.def(setName.c_str(), (void (PropertyList::*)(std::string const&, T const&)) & PropertyList::set<T>);
36  cls.def(setName.c_str(),
37  (void (PropertyList::*)(std::string const&, std::vector<T> const&)) & PropertyList::set<T>);
38  cls.def(setName.c_str(), (void (PropertyList::*)(std::string const&, T const&, std::string const&)) &
39  PropertyList::set<T>);
40  cls.def(setName.c_str(),
41  (void (PropertyList::*)(std::string const&, std::vector<T> const&, std::string const&)) &
42  PropertyList::set<T>);
43 
44  const std::string addName = "add" + name;
45  cls.def(addName.c_str(), (void (PropertyList::*)(std::string const&, T const&)) & PropertyList::add<T>);
46  cls.def(addName.c_str(),
47  (void (PropertyList::*)(std::string const&, std::vector<T> const&)) & PropertyList::add<T>);
48  cls.def(addName.c_str(), (void (PropertyList::*)(std::string const&, T const&, std::string const&)) &
49  PropertyList::add<T>);
50  cls.def(addName.c_str(),
51  (void (PropertyList::*)(std::string const&, std::vector<T> const&, std::string const&)) &
52  PropertyList::add<T>);
53 
54  const std::string typeName = "TYPE_" + name;
55  cls.attr(typeName.c_str()) = py::cast(typeid(T), py::return_value_policy::reference);
56 }
57 
58 } // <anonymous>
59 
60 PYBIND11_PLUGIN(propertyList) {
61  py::module::import("lsst.daf.base.persistable");
62 
63  py::module mod("propertyList");
64 
65  py::class_<PropertyList, std::shared_ptr<PropertyList>, PropertySet, Citizen> cls(mod, "PropertyList");
66 
67  cls.def(py::init<>());
68 
69  cls.def("getComment", &PropertyList::getComment);
70  cls.def("getOrderedNames", &PropertyList::getOrderedNames);
71  cls.def("deepCopy",
72  [](PropertyList const& self) { return std::static_pointer_cast<PropertySet>(self.deepCopy()); });
73 
74  /* __getstate__ and __setstate__ implement support for pickling (protocol version 2)
75  *
76  * They are most easily implemented in Python because the container can hold many different types.
77  * However, implementing __setstate__ in Python leads pickle to create a new instance by calling
78  * object.__new__(PropertyList, *args) which bypasses the pybind11 memory allocation step and hence
79  * leads to segfaults. Thus, __setstate__ first calls the C++ constructor and then calls back to
80  * Python to do the remaining initialization. Note that __getstate__ is mainly implemented in the
81  * same way for clarity, but not strictly needed (I think).
82  */
83  cls.def("__getstate__", [](PropertyList const& self) -> py::object {
84  auto module =
85  py::reinterpret_borrow<py::object>(PyImport_ImportModule("lsst.daf.base.propertyContainer"));
86  if (!module.ptr()) {
87  throw py::error_already_set();
88  } else {
89  auto func = py::reinterpret_borrow<py::object>(PyObject_GetAttrString(module.ptr(), "getstate"));
90  if (!func.ptr()) {
91  throw py::error_already_set();
92  } else {
93  auto pySelf = py::cast(self);
94  auto result = py::reinterpret_steal<py::object>(
95  PyObject_CallFunctionObjArgs(func.ptr(), pySelf.ptr(), NULL));
96  return result;
97  }
98  }
99  return py::none{};
100  });
101  cls.def("__setstate__", [](PropertyList& self, py::object state) {
102  /* Invoke the in-place constructor. Note that this is needed even
103  when the object just has a trivial default constructor */
104  new (&self) PropertyList();
105 
106  auto module =
107  py::reinterpret_borrow<py::object>(PyImport_ImportModule("lsst.daf.base.propertyContainer"));
108  if (!module.ptr()) {
109  throw py::error_already_set();
110  } else {
111  auto func = py::reinterpret_borrow<py::object>(PyObject_GetAttrString(module.ptr(), "setstate"));
112  if (!func.ptr()) {
113  throw py::error_already_set();
114  } else {
115  auto pySelf = py::cast(self);
116  auto result = py::reinterpret_steal<py::object>(
117  PyObject_CallFunctionObjArgs(func.ptr(), pySelf.ptr(), state.ptr(), NULL));
118  }
119  }
120  });
121 
122  declareAccessors<bool>(cls, "Bool");
123  declareAccessors<short>(cls, "Short");
124  declareAccessors<int>(cls, "Int");
125  declareAccessors<long>(cls, "Long");
126  declareAccessors<long long>(cls, "LongLong");
127  declareAccessors<float>(cls, "Float");
128  declareAccessors<double>(cls, "Double");
129  declareAccessors<std::string>(cls, "String");
130  declareAccessors<DateTime>(cls, "DateTime");
131 
132  cls.def("setPropertySet",
133  (void (PropertyList::*)(std::string const&, PropertySet::Ptr const&)) & PropertyList::set);
134 
135  return mod.ptr();
136 }
137 
138 } // base
139 } // daf
140 } // lsst
std::shared_ptr< PropertySet > Ptr
Definition: PropertySet.h:85
Class for storing ordered metadata with comments.
Definition: PropertyList.h:82
Interface for PropertyList class.
Interface for DateTime class.
Class for storing generic metadata.
Definition: PropertySet.h:82
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
Definition: Citizen.h:53
PYBIND11_PLUGIN(citizen)
Definition: citizen.cc:12