With Python 3, Cython is pickier about circular dependencies.  This is
all well and good, but sometimes lower level objects
(e.g. ``Subdevice`` instances) need pointers from higher level objects
(e.g. ``Device`` instances).  How does that work?

All of the C types used in the library are defined in library-specific
``_*_h.pxd`` files at the bottom of the dependency tree.  The
low-level objects don't really need the higher level objects (which
would create a circular import), they need the *pointers* held by the
higher level object.  The solution is create minimal wrappers
(e.g. ``DeviceHolder``), holding only the typed attributes
(``DeviceHolder.device``) and basic methods.  These minimal classes
can be subclassed by the full-fledged class (``Device``), but they can
*also* be imported by the lower level modules and used to define
attributes (``Subdevice.device``) that can then hold either the
minimal (``DeviceHolder``) or the full-fledged (``Device``) version of
the higher level object.

For clarity in the above, I discussed the ``Device`` / ``Subdevice``
relationship, but the same logic holds for similar high- / low-level
relationships (e.g. ``Subdevice`` / ``Channel``, etc.).
