LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
python.h
Go to the documentation of this file.
1// -*- lsst-c++ -*-
2/*
3 * LSST Data Management System
4 * See COPYRIGHT file at the top of the source tree.
5 *
6 * This product includes software developed by the
7 * LSST Project (http://www.lsst.org/).
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the LSST License Statement and
20 * the GNU General Public License along with this program. If not,
21 * see <http://www.lsstcorp.org/LegalNotices/>.
22 */
23
24#ifndef LSST_CPPUTILS_PYTHON_H
25#define LSST_CPPUTILS_PYTHON_H
26
27#include "pybind11/pybind11.h"
28
29#include <cstddef>
30#include <memory>
31#include <string>
32#include <sstream>
33#include <utility>
34#include <list>
35#include <functional>
36
37#include <iostream>
38
39#include "lsst/pex/exceptions.h"
41
42namespace lsst {
43namespace cpputils {
44namespace python {
45
62template<typename T, typename PyClass>
63inline void addSharedPtrEquality(PyClass & cls) {
64 cls.def("__eq__",
65 [](std::shared_ptr<T> self, std::shared_ptr<T> other) { return self.get() == other.get(); },
66 pybind11::is_operator());
67 cls.def("__ne__",
68 [](std::shared_ptr<T> self, std::shared_ptr<T> other) { return self.get() != other.get(); },
69 pybind11::is_operator());
70}
71
86template <class PyClass>
87void addOutputOp(PyClass &cls, std::string const &method) {
88 cls.def(method.c_str(), [](typename PyClass::type const &self) {
89 std::ostringstream os;
90 os << self;
91 return os.str();
92 });
93}
94
103template <class PyClass>
104void addHash(PyClass &cls) {
105 using Class = typename PyClass::type;
106 cls.def("__hash__", [](Class const &self) {
107 static auto const hash = std::hash<Class>();
108 return hash(self);
109 });
110}
111
125 auto const i_orig = i;
126 if (i < 0) {
127 // index backwards from the end
128 i += size;
129 }
130 if (i < 0 || i >= size) {
132 os << "Index " << i_orig << " not in range [" << -size << ", " << size - 1 << "]";
133 throw pybind11::index_error(os.str());
134 }
135 return static_cast<std::size_t>(i);
136}
137
152 try {
153 return {cppIndex(size_i, i), cppIndex(size_j, j)};
156 os << "Index (" << i << ", " << j << ") not in range ["
157 << -size_i << ", " << size_i - 1 << "], ["
158 << -size_j << ", " << size_j - 1 << "]";
159 throw pybind11::index_error(os.str());
160 }
161}
162
243 // LSST_PRIVATE above: don't export symbols used only in pybind11 wrappers
244public:
245
247 using WrapperCallback = std::function<void(pybind11::module &)>;
248
264 explicit WrapperCollection(pybind11::module module_, std::string const & package) :
265 module(module_),
266 _package(package)
267 {}
268
269 // WrapperCollection is move-contructable.
271 module(std::move(other.module)),
272 _package(std::move(other._package)),
273 _dependencies(std::move(other._dependencies)),
274 _definitions(std::move(other._definitions))
275 {}
276
277 // WrapperCollection is not copyable or assignable.
281
283 if (std::uncaught_exceptions()==0 && !_definitions.empty()) {
284 PyErr_SetString(PyExc_ImportError,
285 "WrapperCollection::finish() not called; module definition incomplete.");
286 PyErr_WriteUnraisable(module.ptr());
287 }
288 }
289
319 return WrapperCollection(module.def_submodule(("_" + name).c_str()), _package + "." + name);
320 }
321
330 _dependencies.splice(_dependencies.end(), submodule._dependencies);
331 _definitions.splice(_definitions.end(), submodule._definitions);
332 }
333
344 pybind11::module::import(name.c_str());
345 }
346
358 _dependencies.push_back(name);
359 }
360
369 void wrap(WrapperCallback function) {
370 _definitions.emplace_back(std::make_pair(module, function));
371 }
372
390 template <typename PyType, typename ClassWrapperCallback>
391 PyType wrapType(PyType cls, ClassWrapperCallback function, bool setModuleName=true) {
392 if (setModuleName) {
393 cls.attr("__module__") = _package;
394 }
395 // lambda below is mutable so it can modify the captured `cls` variable
396 wrap(
397 [cls=cls, function=std::move(function)] (pybind11::module & mod) mutable -> void {
398 function(mod, cls);
399 }
400 );
401 return cls;
402 }
403
420 template <typename CxxException, typename CxxBase>
421 auto wrapException(std::string const & pyName, std::string const & pyBase, bool setModuleName=true) {
422 auto cls = pex::exceptions::python::declareException<CxxException, CxxBase>(module, pyName, pyBase);
423 if (setModuleName) {
424 cls.attr("__module__") = _package;
425 }
426 return cls;
427 }
428
435 void finish() {
436 for (auto dep = _dependencies.begin(); dep != _dependencies.end(); dep = _dependencies.erase(dep)) {
437 pybind11::module::import(dep->c_str());
438 }
439 for (auto def = _definitions.begin(); def != _definitions.end(); def = _definitions.erase(def)) {
440 (def->second)(def->first); // WrapperCallback(module)
441 }
442 }
443
448 pybind11::module module;
449
450private:
451 std::string _package;
452 std::list<std::string> _dependencies;
454};
455
456
457}}
458namespace utils = cpputils;
459} // namespace lsst::cpputils::python
460
461#endif
std::ostream * os
Definition Schema.cc:557
#define LSST_PRIVATE
Make a symbol hidden even if default visiblity is public.
Definition base.h:49
T c_str(T... args)
A helper class for subdividing pybind11 module across multiple translation units (i....
Definition python.h:242
void addSignatureDependency(std::string const &name)
Indicate an external module that provides a type used in function/method signatures.
Definition python.h:357
void wrap(WrapperCallback function)
Add a set of wrappers without defining a class.
Definition python.h:369
WrapperCollection & operator=(WrapperCollection const &)=delete
WrapperCollection & operator=(WrapperCollection &&)=delete
void addInheritanceDependency(std::string const &name)
Indicate an external module that provides a base class for a subsequent addType call.
Definition python.h:343
WrapperCollection makeSubmodule(std::string const &name)
Create a WrapperCollection for a submodule defined in the same binary.
Definition python.h:318
PyType wrapType(PyType cls, ClassWrapperCallback function, bool setModuleName=true)
Add a type (class or enum) wrapper, deferring method and other attribute definitions until finish() i...
Definition python.h:391
void finish()
Invoke all deferred wrapper-declaring callables.
Definition python.h:435
WrapperCollection(WrapperCollection const &)=delete
WrapperCollection(WrapperCollection &&other) noexcept
Definition python.h:270
WrapperCollection(pybind11::module module_, std::string const &package)
Construct a new WrapperCollection.
Definition python.h:264
auto wrapException(std::string const &pyName, std::string const &pyBase, bool setModuleName=true)
Wrap a C++ exception as a Python exception.
Definition python.h:421
void collectSubmodule(WrapperCollection &&submodule)
Merge deferred definitions in the given submodule into the parent WrapperCollection.
Definition python.h:329
Reports attempts to access elements outside a valid range of indices.
Definition Runtime.h:89
T get(T... args)
T make_pair(T... args)
T move(T... args)
void addHash(PyClass &cls)
Add __hash__ method implemented by std::hash.
Definition python.h:104
void addOutputOp(PyClass &cls, std::string const &method)
Add __str__ or __repr__ method implemented by operator<<.
Definition python.h:87
void addSharedPtrEquality(PyClass &cls)
Add __eq__ and __ne__ methods based on two std::shared_ptr<T> pointing to the same address.
Definition python.h:63
std::size_t cppIndex(std::ptrdiff_t size, std::ptrdiff_t i)
Compute a C++ index from a Python index (negative values count from the end) and range-check.
Definition python.h:124