Internals ========= .. _genwrapper: Autogenerated wrappers ---------------------- The Cython struct wrappers are generated by ``scripts/gen_wrappers.py``. To illustrate how the wrappers work, let's consider a toy C structure and the corresponding generated Cython cdef class. Here's a stripped down version of ``mjData`` with a scalar member and a pointer (array) member:: typedef struct _mjData { int ne; mjtNum* qpos; // (nq x 1) } mjData; Here's the corresponding generated Cython wrapper code:: cdef class PyMjData(object): cdef mjData* ptr cdef mjModel* _model cdef np.ndarray _qpos cdef void _set(self, mjData* p, mjModel* model): self.ptr = p self._model = model self._qpos = _wrap_mjtNum_1d(p.qpos, model.nq) @property def ne(self): return self.ptr.ne @ne.setter def ne(self, int x): self.ptr.ne = x @property def qpos(self): return self._qpos cdef PyMjData WrapMjData(mjData* p, mjModel* model): cdef PyMjData o = PyMjData() o._set(p, model) return o ``PyMjData`` is the wrapper class for exposing the underlying Mujoco structure to Python; it doesn't perform any memory mangement. A user writing Cython code can create this wrapper using ``WrapMjData``. A ``mjModel`` pointer must be passed because the shape of a ``mjData`` member, namely ``qpos``, depends on ``model->nq``. Each field of ``mjData`` corresponds to some generated piece of code in ``PyMjData`` that depends on the type of that field. For example, ``ne`` is a scalar integer, so it gets exposed as a pair of getter and setter methods in ``PyMjData``. ``qpos`` is an array represented as a pointer to its first element, so it's wrapped with a NumPy array by ``_wrap_mjtNum_1d`` and is exposed with a getter for that NumPy array. The function ``_wrap_mjtNum_1d`` creates a Cython memoryview from the data pointer and converts it to a NumPy array pointing to the same memory:: cdef inline np.ndarray _wrap_mjtNum_1d(mjtNum* a, int shape0): if shape0 == 0: return None cdef mjtNum[:] b = a return np.asarray(b) Similar functions for other types are also generated as required. Keep in mind that the only reason to use these autogenerated wrappers is to allow Python users of the Cython code to easily access Mujoco data (for instance the ``MjSim`` Cython class, found in ``cymj/cymj.pyx`). If you're writing Cython code and you don't need the user to access Mujoco data from Python, then there is no reason to use these wrappers.