LSSTApplications  19.0.0-14-gb0260a2+62eef71270,20.0.0+24334de73e,20.0.0+6348ae6e95,20.0.0+bc2efa1fe5,20.0.0+e2e26847c2,20.0.0+f59fc3f720,20.0.0-1-g253301a+6348ae6e95,20.0.0-1-g2b7511a+46a6078777,20.0.0-1-g3dda6ea+2efb611119,20.0.0-1-g5b95a8c+a5c5a8855d,20.0.0-1-gc96f8cb+59c4ba692f,20.0.0-1-gedffbd8+da4718dcfa,20.0.0-10-g0891cd99+4bc1d4fea5,20.0.0-14-g1a12fe12b+614f89f815,20.0.0-17-gcdbda88+a5e48e6195,20.0.0-2-g4dae9ad+59c4ba692f,20.0.0-2-g52fdb94+046030bafd,20.0.0-2-g61b8584+85c46248f3,20.0.0-2-gb780d76+f45b7d88f4,20.0.0-2-gf072044+6348ae6e95,20.0.0-2-gf5acbb6+d921d43168,20.0.0-22-gdf434b7+59c4ba692f,20.0.0-23-g10eeb28+0997c6b94a,20.0.0-25-g3dcad98+558ba85b5f,20.0.0-3-g1653f94+85c46248f3,20.0.0-3-g4cc78c6+63636aeed8,20.0.0-3-g750bffe+aa101c80f9,20.0.0-3-gbd60e8c+ff10c6d78d,20.0.0-34-g9cdc3119+d10e04dcbd,20.0.0-4-g5bce581+e6333997a2,20.0.0-4-g97dc21a+558ba85b5f,20.0.0-4-gfea843c+f45b7d88f4,20.0.0-5-g357b56b+f45b7d88f4,20.0.0-6-g9a5b7a1+ef6ce590e7,20.0.0-63-g7191b3b+c777709640,20.0.0-7-gcda7bf1+d4a432d2df,w.2020.44
LSSTDataManagementBasePackage
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_UTILS_PYTHON_H
25 #define LSST_UTILS_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 
42 namespace lsst {
43 namespace utils {
44 namespace python {
45 
62 template<typename T, typename PyClass>
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 
86 template <class PyClass>
87 void 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 
103 template <class PyClass>
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)};
154  } catch (lsst::pex::exceptions::OutOfRangeError const&) {
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
244 public:
245 
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 
282  ~WrapperCollection() noexcept {
283  if (!std::uncaught_exception() && !_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 
329  void collectSubmodule(WrapperCollection && submodule) {
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 
449 
450 private:
451  std::string _package;
452  std::list<std::string> _dependencies;
454 };
455 
456 
457 }}} // namespace lsst::utils::python
458 
459 #endif
lsst::utils::python::addOutputOp
void addOutputOp(PyClass &cls, std::string const &method)
Add __str__ or __repr__ method implemented by operator<<.
Definition: python.h:87
lsst::utils::python::WrapperCollection::collectSubmodule
void collectSubmodule(WrapperCollection &&submodule)
Merge deferred definitions in the given submodule into the parent WrapperCollection.
Definition: python.h:329
std::string
STL class.
std::shared_ptr
STL class.
std::list< std::string >
std::move
T move(T... args)
lsst::utils::python::WrapperCollection::WrapperCollection
WrapperCollection(pybind11::module module_, std::string const &package)
Construct a new WrapperCollection.
Definition: python.h:264
std::pair
lsst::utils::python::WrapperCollection::~WrapperCollection
~WrapperCollection() noexcept
Definition: python.h:282
Exception.h
lsst::utils::python::WrapperCollection::addInheritanceDependency
void addInheritanceDependency(std::string const &name)
Indicate an external module that provides a base class for a subsequent addType call.
Definition: python.h:343
lsst::utils::python::addHash
void addHash(PyClass &cls)
Add __hash__ method implemented by std::hash.
Definition: python.h:104
lsst::utils::python::WrapperCollection::finish
void finish()
Invoke all deferred wrapper-declaring callables.
Definition: python.h:435
lsst::utils::python::addSharedPtrEquality
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
lsst::utils::python::cppIndex
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
std::function
lsst::afw::geom.transform.transformContinued.name
string name
Definition: transformContinued.py:32
lsst::utils::python::WrapperCollection::addSignatureDependency
void addSignatureDependency(std::string const &name)
Indicate an external module that provides a type used in function/method signatures.
Definition: python.h:357
lsst::afw::geom.transform.transformContinued.cls
cls
Definition: transformContinued.py:33
lsst::utils::python::WrapperCollection::wrapException
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
lsst::utils::python::WrapperCollection::wrap
void wrap(WrapperCallback function)
Add a set of wrappers without defining a class.
Definition: python.h:369
lsst::utils::python::WrapperCollection::wrapType
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
std::string::c_str
T c_str(T... args)
other
ItemVariant const * other
Definition: Schema.cc:56
PyClass
py::class_< ProductBoundedField, std::shared_ptr< ProductBoundedField >, BoundedField > PyClass
Definition: productBoundedField.cc:32
lsst::utils::python::WrapperCollection
A helper class for subdividing pybind11 module across multiple translation units (i....
Definition: python.h:242
lsst
A base class for image defects.
Definition: imageAlgorithm.dox:1
lsst::utils::python::WrapperCollection::operator=
WrapperCollection & operator=(WrapperCollection const &)=delete
std::ostringstream
STL class.
os
std::ostream * os
Definition: Schema.cc:746
std::uncaught_exception
T uncaught_exception(T... args)
exceptions.h
type
table::Key< int > type
Definition: Detector.cc:163
LSST_PRIVATE
#define LSST_PRIVATE
Make a symbol hidden even if default visiblity is public.
Definition: base.h:66
lsst.pex.config.wrap.wrap
def wrap(ctrl)
Definition: wrap.py:302
lsst.pex::exceptions::OutOfRangeError
Reports attempts to access elements outside a valid range of indices.
Definition: Runtime.h:89
std::ptrdiff_t
lsst::utils::python::WrapperCollection::WrapperCollection
WrapperCollection(WrapperCollection &&other) noexcept
Definition: python.h:270
std::size_t
std::make_pair
T make_pair(T... args)
lsst::utils::python::WrapperCollection::module
pybind11::module module
The module object passed to the PYBIND11_MODULE block that contains this WrapperCollection.
Definition: python.h:448
lsst::utils::python::WrapperCollection::makeSubmodule
WrapperCollection makeSubmodule(std::string const &name)
Create a WrapperCollection for a submodule defined in the same binary.
Definition: python.h:318
lsst::utils::python::WrapperCollection::WrapperCollection
WrapperCollection(WrapperCollection const &)=delete
lsst::meas::modelfit.psf.psfContinued.module
module
Definition: psfContinued.py:42
lsst::utils::python::WrapperCollection::operator=
WrapperCollection & operator=(WrapperCollection &&)=delete
std::hash