|
| 1 | +.. highlight:: python |
| 2 | + :linenothreshold: 10 |
| 3 | + |
| 4 | +.. toctree:: |
| 5 | + :maxdepth: 3 |
| 6 | + |
| 7 | +================================= |
| 8 | +Source Code Layout |
| 9 | +================================= |
| 10 | + |
| 11 | +I find it useful to physically separate out the source code into different categories: |
| 12 | + |
| 13 | ++-------------------+------------+--------------------------+-----------+----------+--------------------------------------------------+ |
| 14 | +| Category | Language | ``#include <Python.h>``? | Testable? | Where? | Description | |
| 15 | ++===================+============+==========================+===========+==========+==================================================+ |
| 16 | +| Pure Python | Python | No | Yes | ``py/`` | Regular Python code tested by pytest or similar. | |
| 17 | ++-------------------+------------+--------------------------+-----------+----------+--------------------------------------------------+ |
| 18 | +| CPython interface | Mostly C | Yes | No | ``cpy/`` | C code that defines Python modules and classes. | |
| 19 | +| | | | | | Functions that are exposed directly to Python. | |
| 20 | ++-------------------+------------+--------------------------+-----------+----------+--------------------------------------------------+ |
| 21 | +| CPython utilities | C, C++ | Yes | Yes | ``cpy/`` | Utility C/C++ code that works with Python | |
| 22 | +| | | | | | objects but these functions that are *not* | |
| 23 | +| | | | | | exposed directly to Python. | |
| 24 | +| | | | | | This code can be tested in a C/C++ environment | |
| 25 | +| | | | | | with a specialised test framework. | |
| 26 | +| | | | | | See :ref:`cpp_and_cpython` for some examples. | |
| 27 | ++-------------------+------------+--------------------------+-----------+----------+--------------------------------------------------+ |
| 28 | +| C/C++ core | C, C++ | No | Yes | ``cpp/`` | C/C++ code that knows nothing about Python. | |
| 29 | +| | | | | | This code can be tested in a C/C++ environment | |
| 30 | +| | | | | | with a standard C/C++ test framework. | |
| 31 | ++-------------------+------------+--------------------------+-----------+----------+--------------------------------------------------+ |
| 32 | + |
| 33 | + |
| 34 | +-------------------------------------- |
| 35 | +Testing CPython Utility Code |
| 36 | +-------------------------------------- |
| 37 | + |
| 38 | +When making Python C API calls from a C/C++ environment it is important to initialise the Python interpreter. For example, this small program segfaults: |
| 39 | + |
| 40 | +.. code-block:: sh |
| 41 | +
|
| 42 | + #include <Python.h> |
| 43 | +
|
| 44 | + int main(int /* argc */, const char *[] /* argv[] */) { |
| 45 | + PyErr_Format(PyExc_TypeError, "Stuff",); |
| 46 | + return 0; |
| 47 | + } |
| 48 | +
|
| 49 | +The reason is that ``PyErr_Format`` calls ``PyThreadState *thread_state = PyThreadState_Get();`` theen ``thread_state`` will be NULL unless the Python interpreter is initialised. |
| 50 | + |
| 51 | +So you need to call ``Py_Initialize()`` to set up statically allocated interpreter data. Alternativley put ``if (! Py_IsInitialized()) Py_Initialize();`` in every test. See: `https://docs.python.org/3/c-api/init.html <https://docs.python.org/3/c-api/init.html>`_ |
| 52 | + |
0 commit comments