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