From 4a22494e4f3a389c3be764f15181e01bf36189dc Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Sat, 19 Aug 2023 18:26:14 -0700 Subject: [PATCH] Python: Fix ODR Violation In pybind11 (and nanobind), auxiliary headers and `PYBIND11_MAKE_OPAQUE` definitions for distributed modules need to be included in every translation unit. Otherwise, a one-definition-rule violation occurs, which is undefined behavior. --- include/openPMD/binding/python/Common.hpp | 55 +++++++++++++++++++++ include/openPMD/binding/python/Numpy.hpp | 4 +- include/openPMD/binding/python/Pickle.hpp | 5 +- src/binding/python/Access.cpp | 6 +-- src/binding/python/Attributable.cpp | 10 +--- src/binding/python/BaseRecord.cpp | 8 +-- src/binding/python/BaseRecordComponent.cpp | 11 ++--- src/binding/python/ChunkInfo.cpp | 8 +-- src/binding/python/Container.cpp | 42 +--------------- src/binding/python/Dataset.cpp | 8 +-- src/binding/python/Datatype.cpp | 8 +-- src/binding/python/Error.cpp | 13 +++-- src/binding/python/Helper.cpp | 8 +-- src/binding/python/Iteration.cpp | 8 +-- src/binding/python/IterationEncoding.cpp | 6 +-- src/binding/python/Mesh.cpp | 8 +-- src/binding/python/MeshRecordComponent.cpp | 9 ++-- src/binding/python/ParticlePatches.cpp | 8 +-- src/binding/python/ParticleSpecies.cpp | 8 +-- src/binding/python/PatchRecord.cpp | 9 ++-- src/binding/python/PatchRecordComponent.cpp | 9 ++-- src/binding/python/Record.cpp | 8 +-- src/binding/python/RecordComponent.cpp | 11 ++--- src/binding/python/Series.cpp | 12 ++--- src/binding/python/UnitDimension.cpp | 6 +-- src/binding/python/openPMD.cpp | 7 +-- 26 files changed, 113 insertions(+), 182 deletions(-) create mode 100644 include/openPMD/binding/python/Common.hpp diff --git a/include/openPMD/binding/python/Common.hpp b/include/openPMD/binding/python/Common.hpp new file mode 100644 index 0000000000..39fed57238 --- /dev/null +++ b/include/openPMD/binding/python/Common.hpp @@ -0,0 +1,55 @@ +/* Copyright 2023 The openPMD Community + * + * This header is used to centrally define classes that shall not violate the + * C++ one-definition-rule (ODR) for various Python translation units. + * + * Authors: Axel Huebl + * License: LGPL-3.0-or-later + */ +#pragma once + +#include "openPMD/Iteration.hpp" +#include "openPMD/Mesh.hpp" +#include "openPMD/ParticlePatches.hpp" +#include "openPMD/ParticleSpecies.hpp" +#include "openPMD/Record.hpp" +#include "openPMD/Series.hpp" +#include "openPMD/backend/BaseRecord.hpp" +#include "openPMD/backend/BaseRecordComponent.hpp" +#include "openPMD/backend/MeshRecordComponent.hpp" +#include "openPMD/backend/PatchRecord.hpp" +#include "openPMD/backend/PatchRecordComponent.hpp" + +#include +#include +#include +#include +#include +// not yet used: +// pybind11/functional.h // for std::function + +// used exclusively in all our Python .cpp files +namespace py = pybind11; +using namespace openPMD; + +// opaque types +using PyIterationContainer = Series::IterationsContainer_t; +using PyMeshContainer = Container; +using PyPartContainer = Container; +using PyPatchContainer = Container; +using PyRecordContainer = Container; +using PyPatchRecordContainer = Container; +using PyRecordComponentContainer = Container; +using PyMeshRecordComponentContainer = Container; +using PyPatchRecordComponentContainer = Container; +using PyBaseRecordComponentContainer = Container; +PYBIND11_MAKE_OPAQUE(PyIterationContainer) +PYBIND11_MAKE_OPAQUE(PyMeshContainer) +PYBIND11_MAKE_OPAQUE(PyPartContainer) +PYBIND11_MAKE_OPAQUE(PyPatchContainer) +PYBIND11_MAKE_OPAQUE(PyRecordContainer) +PYBIND11_MAKE_OPAQUE(PyPatchRecordContainer) +PYBIND11_MAKE_OPAQUE(PyRecordComponentContainer) +PYBIND11_MAKE_OPAQUE(PyMeshRecordComponentContainer) +PYBIND11_MAKE_OPAQUE(PyPatchRecordComponentContainer) +PYBIND11_MAKE_OPAQUE(PyBaseRecordComponentContainer) diff --git a/include/openPMD/binding/python/Numpy.hpp b/include/openPMD/binding/python/Numpy.hpp index 3601ba7081..971aa8613f 100644 --- a/include/openPMD/binding/python/Numpy.hpp +++ b/include/openPMD/binding/python/Numpy.hpp @@ -22,9 +22,7 @@ #include "openPMD/Datatype.hpp" -#include -#include -#include +#include "Common.hpp" #include #include diff --git a/include/openPMD/binding/python/Pickle.hpp b/include/openPMD/binding/python/Pickle.hpp index a57a63d447..eabe307af9 100644 --- a/include/openPMD/binding/python/Pickle.hpp +++ b/include/openPMD/binding/python/Pickle.hpp @@ -24,8 +24,7 @@ #include "openPMD/Series.hpp" #include "openPMD/backend/Attributable.hpp" -#include -#include +#include "Common.hpp" #include #include @@ -46,8 +45,6 @@ template inline void add_pickle(pybind11::class_ &cl, T_SeriesAccessor &&seriesAccessor) { - namespace py = pybind11; - // helper: get first class in py::class_ - that's the type we pickle using PickledClass = typename std::tuple_element<0, std::tuple >::type; diff --git a/src/binding/python/Access.cpp b/src/binding/python/Access.cpp index 8fcdcb73c7..3b1d2a4297 100644 --- a/src/binding/python/Access.cpp +++ b/src/binding/python/Access.cpp @@ -18,13 +18,9 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/IO/Access.hpp" -namespace py = pybind11; -using namespace openPMD; +#include "openPMD/binding/python/Common.hpp" void init_Access(py::module &m) { diff --git a/src/binding/python/Attributable.cpp b/src/binding/python/Attributable.cpp index a18ae2c471..88dbb95cbc 100644 --- a/src/binding/python/Attributable.cpp +++ b/src/binding/python/Attributable.cpp @@ -22,11 +22,9 @@ #include "openPMD/DatatypeHelpers.hpp" #include "openPMD/auxiliary/Variant.hpp" #include "openPMD/backend/Attribute.hpp" -#include "openPMD/binding/python/Numpy.hpp" -#include -#include -#include +#include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Numpy.hpp" #include #include @@ -35,11 +33,7 @@ #include #include -namespace py = pybind11; -using namespace openPMD; - using PyAttributeKeys = std::vector; -// PYBIND11_MAKE_OPAQUE(PyAttributeKeys) bool setAttributeFromBufferInfo( Attributable &attr, std::string const &key, py::buffer &a) diff --git a/src/binding/python/BaseRecord.cpp b/src/binding/python/BaseRecord.cpp index e893b54174..7aeee2d38a 100644 --- a/src/binding/python/BaseRecord.cpp +++ b/src/binding/python/BaseRecord.cpp @@ -18,18 +18,14 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/backend/BaseRecord.hpp" #include "openPMD/backend/BaseRecordComponent.hpp" #include "openPMD/backend/Container.hpp" #include "openPMD/backend/MeshRecordComponent.hpp" #include "openPMD/backend/PatchRecordComponent.hpp" -#include "openPMD/binding/python/UnitDimension.hpp" -namespace py = pybind11; -using namespace openPMD; +#include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/UnitDimension.hpp" void init_BaseRecord(py::module &m) { diff --git a/src/binding/python/BaseRecordComponent.cpp b/src/binding/python/BaseRecordComponent.cpp index 0a3a306e76..95be596560 100644 --- a/src/binding/python/BaseRecordComponent.cpp +++ b/src/binding/python/BaseRecordComponent.cpp @@ -18,19 +18,14 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include -#include - -#include "openPMD/Datatype.hpp" #include "openPMD/backend/BaseRecordComponent.hpp" +#include "openPMD/Datatype.hpp" + +#include "openPMD/binding/python/Common.hpp" #include "openPMD/binding/python/Numpy.hpp" #include -namespace py = pybind11; -using namespace openPMD; - void init_BaseRecordComponent(py::module &m) { py::class_(m, "Base_Record_Component") diff --git a/src/binding/python/ChunkInfo.cpp b/src/binding/python/ChunkInfo.cpp index 5edc29353b..d86a579905 100644 --- a/src/binding/python/ChunkInfo.cpp +++ b/src/binding/python/ChunkInfo.cpp @@ -18,17 +18,13 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/ChunkInfo.hpp" +#include "openPMD/binding/python/Common.hpp" + #include #include -namespace py = pybind11; -using namespace openPMD; - void init_Chunk(py::module &m) { py::class_(m, "ChunkInfo") diff --git a/src/binding/python/Container.cpp b/src/binding/python/Container.cpp index 8adebc570d..ef0a194637 100644 --- a/src/binding/python/Container.cpp +++ b/src/binding/python/Container.cpp @@ -23,23 +23,9 @@ * * BSD-style license, see pybind11 LICENSE file. */ - -#include -#include -#include - -#include "openPMD/Iteration.hpp" -#include "openPMD/Mesh.hpp" -#include "openPMD/ParticlePatches.hpp" -#include "openPMD/ParticleSpecies.hpp" -#include "openPMD/Record.hpp" -#include "openPMD/Series.hpp" -#include "openPMD/backend/BaseRecord.hpp" -#include "openPMD/backend/BaseRecordComponent.hpp" #include "openPMD/backend/Container.hpp" -#include "openPMD/backend/MeshRecordComponent.hpp" -#include "openPMD/backend/PatchRecord.hpp" -#include "openPMD/backend/PatchRecordComponent.hpp" + +#include "openPMD/binding/python/Common.hpp" #include #include @@ -47,9 +33,6 @@ #include #include -namespace py = pybind11; -using namespace openPMD; - namespace detail { /* based on std_bind.h in pybind11 @@ -156,27 +139,6 @@ bind_container(py::handle scope, std::string const &name, Args &&...args) } } // namespace detail -using PyIterationContainer = Series::IterationsContainer_t; -using PyMeshContainer = Container; -using PyPartContainer = Container; -using PyPatchContainer = Container; -using PyRecordContainer = Container; -using PyPatchRecordContainer = Container; -using PyRecordComponentContainer = Container; -using PyMeshRecordComponentContainer = Container; -using PyPatchRecordComponentContainer = Container; -using PyBaseRecordComponentContainer = Container; -PYBIND11_MAKE_OPAQUE(PyIterationContainer) -PYBIND11_MAKE_OPAQUE(PyMeshContainer) -PYBIND11_MAKE_OPAQUE(PyPartContainer) -PYBIND11_MAKE_OPAQUE(PyPatchContainer) -PYBIND11_MAKE_OPAQUE(PyRecordContainer) -PYBIND11_MAKE_OPAQUE(PyPatchRecordContainer) -PYBIND11_MAKE_OPAQUE(PyRecordComponentContainer) -PYBIND11_MAKE_OPAQUE(PyMeshRecordComponentContainer) -PYBIND11_MAKE_OPAQUE(PyPatchRecordComponentContainer) -PYBIND11_MAKE_OPAQUE(PyBaseRecordComponentContainer) - void init_Container(py::module &m) { ::detail::bind_container(m, "Iteration_Container"); diff --git a/src/binding/python/Dataset.cpp b/src/binding/python/Dataset.cpp index bdd35db956..a67d7f1221 100644 --- a/src/binding/python/Dataset.cpp +++ b/src/binding/python/Dataset.cpp @@ -18,17 +18,13 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/Dataset.hpp" + +#include "openPMD/binding/python/Common.hpp" #include "openPMD/binding/python/Numpy.hpp" #include -namespace py = pybind11; -using namespace openPMD; - void init_Dataset(py::module &m) { py::class_(m, "Dataset") diff --git a/src/binding/python/Datatype.cpp b/src/binding/python/Datatype.cpp index 6c5587725d..9d53fba5ca 100644 --- a/src/binding/python/Datatype.cpp +++ b/src/binding/python/Datatype.cpp @@ -18,14 +18,10 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/Datatype.hpp" -#include "openPMD/binding/python/Numpy.hpp" -namespace py = pybind11; -using namespace openPMD; +#include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Numpy.hpp" void init_Datatype(py::module &m) { diff --git a/src/binding/python/Error.cpp b/src/binding/python/Error.cpp index df1b39a5b2..681398c579 100644 --- a/src/binding/python/Error.cpp +++ b/src/binding/python/Error.cpp @@ -1,9 +1,14 @@ +/* Copyright 2019-2023 The openPMD Community + * + * This header is used to centrally define classes that shall not violate the + * C++ one-definition-rule (ODR) for various Python translation units. + * + * Authors: Franz Poeschel, Axel Huebl + * License: LGPL-3.0-or-later + */ #include "openPMD/Error.hpp" -#include - -namespace py = pybind11; -using namespace openPMD; +#include "openPMD/binding/python/Common.hpp" void init_Error(py::module &m) { diff --git a/src/binding/python/Helper.cpp b/src/binding/python/Helper.cpp index 9b07a37f70..e0aef84e0d 100644 --- a/src/binding/python/Helper.cpp +++ b/src/binding/python/Helper.cpp @@ -18,20 +18,16 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/Series.hpp" #include "openPMD/cli/ls.hpp" #include "openPMD/helper/list_series.hpp" +#include "openPMD/binding/python/Common.hpp" + #include #include #include -namespace py = pybind11; -using namespace openPMD; - void init_Helper(py::module &m) { m.def( diff --git a/src/binding/python/Iteration.cpp b/src/binding/python/Iteration.cpp index b54c81c626..22e51aa974 100644 --- a/src/binding/python/Iteration.cpp +++ b/src/binding/python/Iteration.cpp @@ -18,18 +18,14 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/Iteration.hpp" +#include "openPMD/binding/python/Common.hpp" + #include #include #include -namespace py = pybind11; -using namespace openPMD; - void init_Iteration(py::module &m) { py::class_(m, "Iteration") diff --git a/src/binding/python/IterationEncoding.cpp b/src/binding/python/IterationEncoding.cpp index 479ef65555..ef412e2639 100644 --- a/src/binding/python/IterationEncoding.cpp +++ b/src/binding/python/IterationEncoding.cpp @@ -18,13 +18,9 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/IterationEncoding.hpp" -namespace py = pybind11; -using namespace openPMD; +#include "openPMD/binding/python/Common.hpp" void init_IterationEncoding(py::module &m) { diff --git a/src/binding/python/Mesh.cpp b/src/binding/python/Mesh.cpp index 8b6da30e64..e883e5e496 100644 --- a/src/binding/python/Mesh.cpp +++ b/src/binding/python/Mesh.cpp @@ -18,21 +18,17 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/Mesh.hpp" #include "openPMD/backend/BaseRecord.hpp" #include "openPMD/backend/MeshRecordComponent.hpp" + +#include "openPMD/binding/python/Common.hpp" #include "openPMD/binding/python/Pickle.hpp" #include "openPMD/binding/python/UnitDimension.hpp" #include #include -namespace py = pybind11; -using namespace openPMD; - void init_Mesh(py::module &m) { py::class_ > cl(m, "Mesh"); diff --git a/src/binding/python/MeshRecordComponent.cpp b/src/binding/python/MeshRecordComponent.cpp index 98e602bbcb..120fe00da2 100644 --- a/src/binding/python/MeshRecordComponent.cpp +++ b/src/binding/python/MeshRecordComponent.cpp @@ -18,20 +18,17 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include +#include "openPMD/backend/MeshRecordComponent.hpp" #include "openPMD/RecordComponent.hpp" #include "openPMD/Series.hpp" -#include "openPMD/backend/MeshRecordComponent.hpp" + +#include "openPMD/binding/python/Common.hpp" #include "openPMD/binding/python/Pickle.hpp" #include #include -namespace py = pybind11; -using namespace openPMD; - void init_MeshRecordComponent(py::module &m) { py::class_ cl( diff --git a/src/binding/python/ParticlePatches.cpp b/src/binding/python/ParticlePatches.cpp index 28deeab1b5..326162191d 100644 --- a/src/binding/python/ParticlePatches.cpp +++ b/src/binding/python/ParticlePatches.cpp @@ -18,17 +18,13 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/ParticlePatches.hpp" #include "openPMD/backend/Container.hpp" #include "openPMD/backend/PatchRecord.hpp" -#include +#include "openPMD/binding/python/Common.hpp" -namespace py = pybind11; -using namespace openPMD; +#include void init_ParticlePatches(py::module &m) { diff --git a/src/binding/python/ParticleSpecies.cpp b/src/binding/python/ParticleSpecies.cpp index 349081ea8e..349ea8c689 100644 --- a/src/binding/python/ParticleSpecies.cpp +++ b/src/binding/python/ParticleSpecies.cpp @@ -18,22 +18,18 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/ParticleSpecies.hpp" #include "openPMD/Record.hpp" #include "openPMD/Series.hpp" #include "openPMD/backend/Container.hpp" + +#include "openPMD/binding/python/Common.hpp" #include "openPMD/binding/python/Pickle.hpp" #include #include #include -namespace py = pybind11; -using namespace openPMD; - void init_ParticleSpecies(py::module &m) { py::class_ > cl(m, "ParticleSpecies"); diff --git a/src/binding/python/PatchRecord.cpp b/src/binding/python/PatchRecord.cpp index 7d01add8ea..aaef39546c 100644 --- a/src/binding/python/PatchRecord.cpp +++ b/src/binding/python/PatchRecord.cpp @@ -18,16 +18,13 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include +#include "openPMD/backend/PatchRecord.hpp" #include "openPMD/backend/BaseRecord.hpp" -#include "openPMD/backend/PatchRecord.hpp" #include "openPMD/backend/PatchRecordComponent.hpp" -#include "openPMD/binding/python/UnitDimension.hpp" -namespace py = pybind11; -using namespace openPMD; +#include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/UnitDimension.hpp" void init_PatchRecord(py::module &m) { diff --git a/src/binding/python/PatchRecordComponent.cpp b/src/binding/python/PatchRecordComponent.cpp index bf6a687b04..e668f7a1d9 100644 --- a/src/binding/python/PatchRecordComponent.cpp +++ b/src/binding/python/PatchRecordComponent.cpp @@ -18,16 +18,13 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include +#include "openPMD/backend/PatchRecordComponent.hpp" #include "openPMD/DatatypeHelpers.hpp" #include "openPMD/backend/BaseRecordComponent.hpp" -#include "openPMD/backend/PatchRecordComponent.hpp" -#include "openPMD/binding/python/Numpy.hpp" -namespace py = pybind11; -using namespace openPMD; +#include "openPMD/binding/python/Common.hpp" +#include "openPMD/binding/python/Numpy.hpp" namespace { diff --git a/src/binding/python/Record.cpp b/src/binding/python/Record.cpp index ee96e304e6..d97641bbce 100644 --- a/src/binding/python/Record.cpp +++ b/src/binding/python/Record.cpp @@ -18,21 +18,17 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/Record.hpp" #include "openPMD/RecordComponent.hpp" #include "openPMD/backend/BaseRecord.hpp" + +#include "openPMD/binding/python/Common.hpp" #include "openPMD/binding/python/Pickle.hpp" #include "openPMD/binding/python/UnitDimension.hpp" #include #include -namespace py = pybind11; -using namespace openPMD; - void init_Record(py::module &m) { py::class_ > cl(m, "Record"); diff --git a/src/binding/python/RecordComponent.cpp b/src/binding/python/RecordComponent.cpp index 32e1e0fb0d..ee8bb7d3bd 100644 --- a/src/binding/python/RecordComponent.cpp +++ b/src/binding/python/RecordComponent.cpp @@ -18,15 +18,13 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include -#include - +#include "openPMD/RecordComponent.hpp" #include "openPMD/DatatypeHelpers.hpp" #include "openPMD/Error.hpp" -#include "openPMD/RecordComponent.hpp" #include "openPMD/Series.hpp" #include "openPMD/backend/BaseRecordComponent.hpp" + +#include "openPMD/binding/python/Common.hpp" #include "openPMD/binding/python/Numpy.hpp" #include "openPMD/binding/python/Pickle.hpp" @@ -42,9 +40,6 @@ #include #include -namespace py = pybind11; -using namespace openPMD; - /** Convert a py::tuple of py::slices to Offset & Extent * * https://docs.scipy.org/doc/numpy-1.15.0/reference/arrays.indexing.html diff --git a/src/binding/python/Series.cpp b/src/binding/python/Series.cpp index 282b678c9e..241e14d69f 100644 --- a/src/binding/python/Series.cpp +++ b/src/binding/python/Series.cpp @@ -18,17 +18,14 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ - -#include -#include -#include - +#include "openPMD/Series.hpp" #include "openPMD/IO/Access.hpp" #include "openPMD/IterationEncoding.hpp" -#include "openPMD/Series.hpp" #include "openPMD/auxiliary/JSON.hpp" #include "openPMD/config.hpp" +#include "openPMD/binding/python/Common.hpp" + #if openPMD_HAVE_MPI // re-implemented signatures: // include @@ -38,9 +35,6 @@ #include #include -namespace py = pybind11; -using namespace openPMD; - #if openPMD_HAVE_MPI /** mpi4py communicator wrapper * diff --git a/src/binding/python/UnitDimension.cpp b/src/binding/python/UnitDimension.cpp index 72074cde78..6e46a6cfcf 100644 --- a/src/binding/python/UnitDimension.cpp +++ b/src/binding/python/UnitDimension.cpp @@ -18,13 +18,9 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/UnitDimension.hpp" -namespace py = pybind11; -using namespace openPMD; +#include "openPMD/binding/python/Common.hpp" void init_UnitDimension(py::module &m) { diff --git a/src/binding/python/openPMD.cpp b/src/binding/python/openPMD.cpp index 5133c66d21..28b56b7d9c 100644 --- a/src/binding/python/openPMD.cpp +++ b/src/binding/python/openPMD.cpp @@ -18,18 +18,15 @@ * and the GNU Lesser General Public License along with openPMD-api. * If not, see . */ -#include -#include - #include "openPMD/config.hpp" #include "openPMD/version.hpp" +#include "openPMD/binding/python/Common.hpp" + #include #include #include -namespace py = pybind11; - // forward declarations of exposed classes void init_Access(py::module &); void init_Attributable(py::module &);