LSSTApplications  18.1.0
LSSTDataManagementBasePackage
schema.cc
Go to the documentation of this file.
1 /*
2  * LSST Data Management System
3  * Copyright 2008-2016 AURA/LSST.
4  *
5  * This product includes software developed by the
6  * LSST Project (http://www.lsst.org/).
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the LSST License Statement and
19  * the GNU General Public License along with this program. If not,
20  * see <https://www.lsstcorp.org/LegalNotices/>.
21  */
22 
23 #include "pybind11/pybind11.h"
24 #include "pybind11/stl.h"
25 
26 #include <sstream>
27 
28 #include "ndarray/pybind11.h"
29 
30 #include "lsst/utils/python.h"
31 
32 #include "lsst/afw/fits.h"
34 #include "lsst/afw/table/Schema.h"
37 
38 namespace py = pybind11;
39 using namespace pybind11::literals;
40 
41 namespace lsst {
42 namespace afw {
43 namespace table {
44 
45 namespace {
46 
47 using PySchema = py::class_<Schema>;
48 
49 using PySubSchema = py::class_<SubSchema>;
50 
51 template <typename T>
52 using PyFieldBase = py::class_<FieldBase<T>>;
53 
54 template <typename T>
55 using PyKeyBase = py::class_<KeyBase<T>>;
56 
57 template <typename T>
58 using PyField = py::class_<Field<T>, FieldBase<T>>;
59 
60 template <typename T>
61 using PyKey = py::class_<Key<T>, KeyBase<T>, FieldBase<T>>;
62 
63 template <typename T>
64 using PySchemaItem = py::class_<SchemaItem<T>>;
65 
66 // Specializations for FieldBase
67 
68 template <typename T>
69 void declareFieldBaseSpecializations(PyFieldBase<T> &cls) {
70  cls.def(py::init<>());
71 }
72 
73 template <typename T>
74 void declareFieldBaseSpecializations(PyFieldBase<Array<T>> &cls) {
75  cls.def(py::init<int>(), "size"_a = 0);
76  cls.def("getSize", &FieldBase<Array<T>>::getSize);
77  cls.def("isVariableLength", &FieldBase<Array<T>>::isVariableLength);
78 }
79 
80 void declareFieldBaseSpecializations(PyFieldBase<std::string> &cls) {
81  cls.def(py::init<int>(), "size"_a = -1);
82  cls.def("getSize", &FieldBase<std::string>::getSize);
83 }
84 
85 // Specializations for Field
86 
87 template <typename T>
88 void declareFieldSpecializations(PyField<T> &cls) {
89  cls.def(py::pickle(
90  [](Field<T> const &self) {
91  /* Return a tuple that fully encodes the state of the object */
92  return py::make_tuple(self.getName(), self.getDoc(), self.getUnits());
93  },
94  [](py::tuple t) {
95  int const NPARAMS = 3;
96  if (t.size() != NPARAMS) {
98  os << "Invalid number of parameters (" << t.size() << ") when unpickling; expected "
99  << NPARAMS;
100  throw std::runtime_error(os.str());
101  }
102  return Field<T>(t[0].cast<std::string>(), t[1].cast<std::string>(), t[2].cast<std::string>());
103  }));
104 }
105 
106 // Field<Array<T>> and Field<std::string> have the same pickle implementation
107 template <typename T>
108 void _sequenceFieldSpecializations(PyField<T> &cls) {
109  cls.def(py::pickle(
110  [](Field<T> const &self) {
111  /* Return a tuple that fully encodes the state of the object */
112  return py::make_tuple(self.getName(), self.getDoc(), self.getUnits(), self.getSize());
113  },
114  [](py::tuple t) {
115  int const NPARAMS = 4;
116  if (t.size() != NPARAMS) {
118  os << "Invalid number of parameters (" << t.size() << ") when unpickling; expected "
119  << NPARAMS;
120  throw std::runtime_error(os.str());
121  }
122  return Field<T>(t[0].cast<std::string>(), t[1].cast<std::string>(), t[2].cast<std::string>(),
123  t[3].cast<int>());
124  }));
125 }
126 
127 template <typename T>
128 void declareFieldSpecializations(PyField<Array<T>> &cls) {
129  _sequenceFieldSpecializations(cls);
130 }
131 
132 void declareFieldSpecializations(PyField<std::string> &cls) { _sequenceFieldSpecializations(cls); }
133 
134 // Specializations for KeyBase
135 
136 template <typename T>
137 void declareKeyBaseSpecializations(PyKeyBase<T> &) {}
138 
139 template <typename T>
140 void declareKeyBaseSpecializations(PyKeyBase<Array<T>> &cls) {
141  cls.def("__getitem__", [](Key<Array<T>> const &self, py::object const &index) -> py::object {
142  if (py::isinstance<py::slice>(index)) {
143  py::slice slice(index);
144  py::size_t start = 0, stop = 0, step = 0, length = 0;
145  bool valid = slice.compute(self.getSize(), &start, &stop, &step, &length);
146  if (!valid) throw py::error_already_set();
147  if (step != 1) {
148  throw LSST_EXCEPT(pex::exceptions::InvalidParameterError,
149  "Step for array Key indexing must be 1.");
150  }
151  return py::cast(self.slice(start, stop));
152  } else {
153  return py::cast(self[py::cast<int>(index)]);
154  }
155  });
156  cls.def("slice", &KeyBase<Array<T>>::slice);
157 }
158 
159 // Specializations for Key
160 
161 template <typename T>
162 void declareKeyAccessors(PyKey<T> &cls) {
163  cls.def("get", [](Key<T> const &self, BaseRecord &record) { return record.get(self); });
164  cls.def("set", [](Key<T> const &self, BaseRecord &record, typename Key<T>::Value const &value) {
165  record.set(self, value);
166  });
167 }
168 
169 template <typename U>
170 void declareKeyAccessors(PyKey<Array<U>> &cls) {
171  auto getter = [](Key<Array<U>> const &self, BaseRecord &record) -> ndarray::Array<U, 1, 1> {
172  return record[self];
173  };
174  auto setter = [](Key<Array<U>> const &self, BaseRecord &record, py::object const &value) {
175  if (self.getSize() == 0) {
176  // Variable-length array field: do a shallow copy, which requires a non-const
177  // contiguous array.
178  record.set(self, py::cast<ndarray::Array<U, 1, 1>>(value));
179  } else {
180  // Fixed-length array field: do a deep copy, which can work with a const
181  // noncontiguous array. But we need to check the size first, since the
182  // penalty for getting that wrong is assert->abort.
183  auto v = py::cast<ndarray::Array<U const, 1, 0>>(value);
184  ndarray::ArrayRef<U, 1, 1> ref = record[self];
185  if (v.size() != ref.size()) {
186  throw LSST_EXCEPT(
187  pex::exceptions::LengthError,
188  (boost::format("Array sizes do not agree: %s != %s") % v.size() % ref.size()).str());
189  }
190  ref = v;
191  }
192  return;
193  };
194  cls.def("get", getter);
195  cls.def("set", setter);
196 }
197 
198 template <typename T>
199 void declareKeySpecializations(PyKey<T> &cls) {
200  declareKeyAccessors(cls);
201  cls.def_property_readonly("subfields", [](py::object const &) { return py::none(); });
202  cls.def_property_readonly("subkeys", [](py::object const &) { return py::none(); });
203  cls.def(py::pickle(
204  [](Key<T> const &self) {
205  /* Return a tuple that fully encodes the state of the object */
206  return py::make_tuple(self.getOffset());
207  },
208  [](py::tuple t) {
209  int const NPARAMS = 1;
210  if (t.size() != NPARAMS) {
212  os << "Invalid number of parameters (" << t.size() << ") when unpickling; expected "
213  << NPARAMS;
214  throw std::runtime_error(os.str());
215  }
216  return detail::Access::makeKey<T>(t[0].cast<int>());
217  }));
218 }
219 
220 void declareKeySpecializations(PyKey<Flag> &cls) {
221  declareKeyAccessors(cls);
222  cls.def_property_readonly("subfields", [](py::object const &) { return py::none(); });
223  cls.def_property_readonly("subkeys", [](py::object const &) { return py::none(); });
224  cls.def("getBit", &Key<Flag>::getBit);
225  cls.def(py::pickle(
226  [](Key<Flag> const &self) {
227  /* Return a tuple that fully encodes the state of the object */
228  return py::make_tuple(self.getOffset(), self.getBit());
229  },
230  [](py::tuple t) {
231  int const NPARAMS = 2;
232  if (t.size() != NPARAMS) {
234  os << "Invalid number of parameters (" << t.size() << ") when unpickling; expected "
235  << NPARAMS;
236  throw std::runtime_error(os.str());
237  }
238  return detail::Access::makeKey(t[0].cast<int>(), t[1].cast<int>());
239  }));
240 }
241 
242 template <typename T>
243 void declareKeySpecializations(PyKey<Array<T>> &cls) {
244  declareKeyAccessors(cls);
245  cls.def_property_readonly("subfields", [](Key<Array<T>> const &self) -> py::object {
247  for (int i = 0; i < self.getSize(); ++i) {
248  result.append(py::cast(i));
249  }
250  return py::tuple(result);
251  });
252  cls.def_property_readonly("subkeys", [](Key<Array<T>> const &self) -> py::object {
254  for (int i = 0; i < self.getSize(); ++i) {
255  result.append(py::cast(self[i]));
256  }
257  return py::tuple(result);
258  });
259  cls.def(py::pickle(
260  [](Key<Array<T>> const &self) {
261  /* Return a tuple that fully encodes the state of the object */
262  return py::make_tuple(self.getOffset(), self.getElementCount());
263  },
264  [](py::tuple t) {
265  int const NPARAMS = 2;
266  if (t.size() != NPARAMS) {
268  os << "Invalid number of parameters (" << t.size() << ") when unpickling; expected "
269  << NPARAMS;
270  throw std::runtime_error(os.str());
271  }
272  return detail::Access::makeKeyArray<T>(t[0].cast<int>(), t[1].cast<int>());
273  }));
274 }
275 
276 void declareKeySpecializations(PyKey<std::string> &cls) {
277  declareKeyAccessors(cls);
278  cls.def_property_readonly("subfields", [](py::object const &) { return py::none(); });
279  cls.def_property_readonly("subkeys", [](py::object const &) { return py::none(); });
280  cls.def(py::pickle(
281  [](Key<std::string> const &self) {
282  /* Return a tuple that fully encodes the state of the object */
283  return py::make_tuple(self.getOffset(), self.getElementCount());
284  },
285  [](py::tuple t) {
286  int const NPARAMS = 2;
287  if (t.size() != NPARAMS) {
289  os << "Invalid number of parameters (" << t.size() << ") when unpickling; expected "
290  << NPARAMS;
291  throw std::runtime_error(os.str());
292  }
293  return detail::Access::makeKeyString(t[0].cast<int>(), t[1].cast<int>());
294  }));
295 }
296 
297 // Wrap all helper classes (FieldBase, KeyBase, Key, Field, SchemaItem) declarefor a Schema field type.
298 template <typename T>
299 void declareSchemaType(py::module &mod) {
300  std::string suffix = FieldBase<T>::getTypeString();
301  py::str pySuffix(suffix);
302 
303  py::object astropyUnit = py::module::import("astropy.units").attr("Unit");
304 
305  // FieldBase
306  PyFieldBase<T> clsFieldBase(mod, ("FieldBase" + suffix).c_str());
307  clsFieldBase.def_static("getTypeString", &FieldBase<T>::getTypeString);
308  declareFieldBaseSpecializations(clsFieldBase);
309 
310  // KeyBase
311  PyKeyBase<T> clsKeyBase(mod, ("KeyBase" + suffix).c_str());
312  clsKeyBase.def_readonly_static("HAS_NAMED_SUBFIELDS", &KeyBase<T>::HAS_NAMED_SUBFIELDS);
313  declareKeyBaseSpecializations(clsKeyBase);
314 
315  // Field
316  PyField<T> clsField(mod, ("Field" + suffix).c_str());
317  declareFieldSpecializations(clsField);
318 
319  mod.attr("_Field")[pySuffix] = clsField;
320  clsField.def(py::init([astropyUnit]( // capture by value to refcount in Python instead of dangle in C++
321  std::string const &name, std::string const &doc, py::str const &units,
322  py::object const &size, py::str const &parse_strict) {
323  astropyUnit(units, "parse_strict"_a = parse_strict);
324  std::string u = py::cast<std::string>(units);
325  if (size.is(py::none())) {
326  return new Field<T>(name, doc, u);
327  } else {
328  int s = py::cast<int>(size);
329  return new Field<T>(name, doc, u, s);
330  }
331  }),
332  "name"_a, "doc"_a = "", "units"_a = "", "size"_a = py::none(), "parse_strict"_a = "raise");
333  clsField.def("_addTo", [](Field<T> const &self, Schema &schema, bool doReplace) -> Key<T> {
334  return schema.addField(self, doReplace);
335  });
336  clsField.def("getName", &Field<T>::getName);
337  clsField.def("getDoc", &Field<T>::getDoc);
338  clsField.def("getUnits", &Field<T>::getUnits);
339  clsField.def("copyRenamed", &Field<T>::copyRenamed);
340  utils::python::addOutputOp(clsField, "__str__");
341  utils::python::addOutputOp(clsField, "__repr__");
342 
343  // Key
344  PyKey<T> clsKey(mod, ("Key" + suffix).c_str());
345  mod.attr("_Key")[pySuffix] = clsKey;
346  clsKey.def(py::init<>());
347  clsKey.def(
348  "__eq__", [](Key<T> const &self, Key<T> const &other) -> bool { return self == other; },
349  py::is_operator());
350  clsKey.def(
351  "__ne__", [](Key<T> const &self, Key<T> const &other) -> bool { return self != other; },
352  py::is_operator());
353  clsKey.def("isValid", &Key<T>::isValid);
354  clsKey.def("getOffset", &Key<T>::getOffset);
355  utils::python::addOutputOp(clsKey, "__str__");
356  utils::python::addOutputOp(clsKey, "__repr__");
357  // The Key methods below actually wrap templated methods on Schema and
358  // SchemaMapper. Rather than doing many-type overload resolution by
359  // wrapping those methods directly, we use the visitor pattern by having
360  // the wrappers for those methods delegate back to these non-templated
361  // methods on the templated Key classes.
362  clsKey.def("_findIn", [](Key<T> const &self, Schema const &schema) { return schema.find(self); });
363  clsKey.def("_addMappingTo", [](Key<T> const &self, SchemaMapper &mapper, Field<T> const &field,
364  bool doReplace) { return mapper.addMapping(self, field, doReplace); });
365  clsKey.def("_addMappingTo", [](Key<T> const &self, SchemaMapper &mapper, std::string const &name,
366  bool doReplace) { return mapper.addMapping(self, name, doReplace); });
367  clsKey.def("_addMappingTo", [](Key<T> const &self, SchemaMapper &mapper, py::object const &,
368  bool doReplace) { return mapper.addMapping(self, doReplace); });
369  declareKeySpecializations(clsKey);
370 
371  // SchemaItem
372  PySchemaItem<T> clsSchemaItem(mod, ("SchemaItem" + suffix).c_str());
373  mod.attr("_SchemaItem")[pySuffix] = clsSchemaItem;
374  clsSchemaItem.def_readonly("key", &SchemaItem<T>::key);
375  clsSchemaItem.def_readonly("field", &SchemaItem<T>::field);
376  clsSchemaItem.def("getKey", [](SchemaItem<T> const &self) { return self.key; });
377  clsSchemaItem.def("getField", [](SchemaItem<T> const &self) { return self.field; });
378  clsSchemaItem.def("__getitem__", [](py::object const &self, int index) -> py::object {
379  if (index == 0) {
380  return self.attr("key");
381  } else if (index == 1) {
382  return self.attr("field");
383  }
384  // Have to raise IndexError not some LSST exception to get the
385  // right behavior when unpacking.
386  throw py::index_error("Index to SchemaItem must be 0 or 1.");
387  });
388  clsSchemaItem.def("__len__", [](py::object const &self) -> int { return 2; });
389  clsSchemaItem.def("__str__", [](py::object const &self) -> py::str { return py::str(py::tuple(self)); });
390  clsSchemaItem.def("__repr__", [](py::object const &self) -> py::str {
391  return py::str("SchemaItem(key={0.key}, field={0.field})").format(self);
392  });
393  clsSchemaItem.def(py::pickle(
394  [](SchemaItem<T> const &self) {
395  /* Return a tuple that fully encodes the state of the object */
396  return py::make_tuple(self.key, self.field);
397  },
398  [](py::tuple t) {
399  int const NPARAMS = 2;
400  if (t.size() != NPARAMS) {
402  os << "Invalid number of parameters (" << t.size() << ") when unpickling; expected "
403  << NPARAMS;
404  throw std::runtime_error(os.str());
405  }
406  return SchemaItem<T>(t[0].cast<Key<T>>(), t[1].cast<Field<T>>());
407  }));
408 } // namespace
409 
410 // Helper class for Schema::find(name, func) that converts the result to Python.
411 // In C++14, this should be converted to a universal lambda.
412 struct MakePythonSchemaItem {
413  template <typename T>
414  void operator()(SchemaItem<T> const &item) {
415  result = py::cast(item);
416  }
417 
418  py::object result;
419 };
420 
421 void declareSchema(py::module &mod) {
422  py::module::import("lsst.afw.table.aliasMap");
423 
424  PySchema cls(mod, "Schema");
425  // wrap ComparisonFlags values as ints since we use them as bitflags,
426  // not true enums
427  cls.attr("EQUAL_KEYS") = py::cast(int(Schema::EQUAL_KEYS));
428  cls.attr("EQUAL_NAMES") = py::cast(int(Schema::EQUAL_NAMES));
429  cls.attr("EQUAL_DOCS") = py::cast(int(Schema::EQUAL_DOCS));
430  cls.attr("EQUAL_UNITS") = py::cast(int(Schema::EQUAL_UNITS));
431  cls.attr("EQUAL_FIELDS") = py::cast(int(Schema::EQUAL_FIELDS));
432  cls.attr("EQUAL_ALIASES") = py::cast(int(Schema::EQUAL_ALIASES));
433  cls.attr("IDENTICAL") = py::cast(int(Schema::IDENTICAL));
434 
435  cls.attr("VERSION") = py::cast(int(Schema::VERSION));
436 
437  cls.def(py::init<>());
438  cls.def(py::init<Schema const &>());
439  cls.def("__getitem__", [](Schema &self, std::string const &name) { return self[name]; });
440  cls.def(
441  "__eq__", [](Schema const &self, Schema const &other) { return self == other; },
442  py::is_operator());
443  cls.def(
444  "__ne__", [](Schema const &self, Schema const &other) { return self != other; },
445  py::is_operator());
446  cls.def("getCitizen", &Schema::getCitizen, py::return_value_policy::reference_internal);
447  cls.def("getRecordSize", &Schema::getRecordSize);
448  cls.def("getFieldCount", &Schema::getFieldCount);
449  cls.def("getFlagFieldCount", &Schema::getFlagFieldCount);
450  cls.def("getNonFlagFieldCount", &Schema::getNonFlagFieldCount);
451  cls.def("find", [](py::object const &self, py::object const &key) -> py::object {
452  try {
453  if (py::isinstance<py::str>(key) || py::isinstance<py::bytes>(key)) {
454  Schema const &s = py::cast<Schema const &>(self);
455  std::string name = py::cast<std::string>(key);
456  MakePythonSchemaItem func;
457  s.findAndApply(name, func);
458  return func.result;
459  }
460  return key.attr("_findIn")(self);
461  } catch (pex::exceptions::NotFoundError &err) {
462  // Avoid API change by re-throwing as KeyError.
463  PyErr_SetString(PyExc_KeyError, err.what());
464  throw py::error_already_set();
465  }
466  });
467  cls.def("getNames", &Schema::getNames, "topOnly"_a = false);
468  cls.def("getAliasMap", &Schema::getAliasMap);
469  cls.def("setAliasMap", &Schema::setAliasMap, "aliases"_a);
470  cls.def("disconnectAliases", &Schema::disconnectAliases);
471  cls.def("forEach", [](Schema &self, py::object &obj) { self.forEach(obj); });
472  cls.def("compare", &Schema::compare, "other"_a, "flags"_a = int(Schema::EQUAL_KEYS));
473  cls.def("contains", (int (Schema::*)(Schema const &, int) const) & Schema::contains, "other"_a,
474  "flags"_a = int(Schema::EQUAL_KEYS));
475  cls.def("__contains__", [](py::object const &self, py::object const &key) {
476  try {
477  self.attr("find")(key);
478  } catch (py::error_already_set &err) {
479  err.restore();
480  PyErr_Clear();
481  return false;
482  }
483  return true;
484  });
485  cls.def_static("readFits", (Schema(*)(std::string const &, int)) & Schema::readFits, "filename"_a,
486  "hdu"_a = fits::DEFAULT_HDU);
487  cls.def_static("readFits", (Schema(*)(fits::MemFileManager &, int)) & Schema::readFits, "manager"_a,
488  "hdu"_a = fits::DEFAULT_HDU);
489 
490  cls.def("join", (std::string(Schema::*)(std::string const &, std::string const &) const) & Schema::join,
491  "a"_a, "b"_a);
492  cls.def("join",
493  (std::string(Schema::*)(std::string const &, std::string const &, std::string const &) const) &
494  Schema::join,
495  "a"_a, "b"_a, "c"_a);
496  cls.def("join",
497  (std::string(Schema::*)(std::string const &, std::string const &, std::string const &,
498  std::string const &) const) &
499  Schema::join,
500  "a"_a, "b"_a, "c"_a, "d"_a);
501  utils::python::addOutputOp(cls, "__str__");
502  utils::python::addOutputOp(cls, "__repr__");
503 }
504 
505 void declareSubSchema(py::module &mod) {
506  PySubSchema cls(mod, "SubSchema");
507  cls.def("getNames", &SubSchema::getNames, "topOnly"_a = false);
508  cls.def("getPrefix", &SubSchema::getPrefix);
509  cls.def("asKey", [](SubSchema const &self) -> py::object {
510  MakePythonSchemaItem func;
511  self.apply(func);
512  return func.result.attr("key");
513  });
514  cls.def("asField", [](SubSchema const &self) -> py::object {
515  MakePythonSchemaItem func;
516  self.apply(func);
517  return func.result.attr("field");
518  });
519  cls.def("find", [](SubSchema const &self, std::string const &name) -> py::object {
520  MakePythonSchemaItem func;
521  self.findAndApply(name, func);
522  return func.result;
523  });
524  cls.def("__getitem__", [](SubSchema &self, std::string const &name) { return self[name]; });
525 }
526 
527 PYBIND11_MODULE(schema, mod) {
528  // We'll add instantiations of Field, Key, and SchemaItem to these private
529  // dicts, and then in schemaContinued.py we'll add them to a TemplateMeta
530  // ABC.
531  mod.attr("_Field") = py::dict();
532  mod.attr("_Key") = py::dict();
533  mod.attr("_SchemaItem") = py::dict();
534 
535  declareSchemaType<std::uint8_t>(mod);
536  declareSchemaType<std::uint16_t>(mod);
537  declareSchemaType<std::int32_t>(mod);
538  declareSchemaType<std::int64_t>(mod);
539  declareSchemaType<float>(mod);
540  declareSchemaType<double>(mod);
541  declareSchemaType<std::string>(mod);
542  declareSchemaType<lsst::geom::Angle>(mod);
543  declareSchemaType<Array<std::uint8_t>>(mod);
544  declareSchemaType<Array<std::uint16_t>>(mod);
545  declareSchemaType<Array<int>>(mod);
546  declareSchemaType<Array<float>>(mod);
547  declareSchemaType<Array<double>>(mod);
548  declareSchemaType<Flag>(mod);
549 
550  declareSchema(mod);
551  declareSubSchema(mod);
552 }
553 } // namespace
554 } // namespace table
555 } // namespace afw
556 } // namespace lsst
void addOutputOp(PyClass &cls, std::string const &method)
Add __str__ or __repr__ method implemented by operator<<.
Definition: python.h:87
bool contains(VertexIterator const begin, VertexIterator const end, UnitVector3d const &v)
table::Key< int > field
Definition: ApCorrMap.cc:77
def init()
Definition: tests.py:75
PYBIND11_MODULE(camera, mod)
Definition: camera.cc:34
py::object result
Definition: schema.cc:418
constexpr Key< K, V > makeKey(K const &id)
Factory function for Key, to enable type parameter inference.
Definition: GenericMap.h:162
STL class.
A base class for image defects.
int const step
bool isValid
Definition: fits.cc:380
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:168
T str(T... args)
table::Schema schema
Definition: Camera.cc:161
solver_t * s
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
T ref(T... args)
Key< U > key
Definition: Schema.cc:281
ItemVariant const * other
Definition: Schema.cc:56
daf::base::PropertyList * list
Definition: fits.cc:885
std::ostream * os
Definition: Schema.cc:746
SchemaMapper * mapper
Definition: SchemaMapper.cc:78
const int DEFAULT_HDU
Specify that the default HDU should be read.
Definition: fitsDefaults.h:18