How to conditionally declare code according to Python version in Cython?

Question:

I have the following pxd header which augments a regular Python module:

#!/usr/bin/env python
# coding: utf-8

cimport cython

@cython.locals(media_type=unicode, format=unicode, charset=unicode, render_style=unicode)
cdef class BaseRenderer(object):
    """
    All renderers should extend this class, setting the `media_type`
    and `format` attributes, and override the `.render()` method.
    """

    @cython.locals(indent=int, separators=tuple)
    cpdef object render(self, dict data, accepted_media_type=?, renderer_context=?)

@cython.locals(compact=bool, ensure_ascii=bool, charset=unicode)
cdef class JSONRenderer(BaseRenderer):
    @cython.locals(base_media_type=unicode, params=dict)
    cpdef int get_indent(self, unicode accepted_media_type, dict renderer_context)

@cython.locals(callback_parameter=unicode, default_callback=unicode)
cdef class JSONPRenderer(JSONRenderer):
    cpdef unicode get_callback(self, dict renderer_context)

In Python 2, the render() method might return either string, byte or unicode but in Python 3 it is guaranteed that the method will return unicode.
I am unable to import the Python version #define called PY_MAJOR_VERSION that can be found in the Python/patchlevel.h header.
I tried to include it using:

cdef extern from "patchlevel.h":
  pass

But the definition is not available. The include path is correctly set to /usr/include/pythonx.x./.

How do I branch this code at compilation according to the Python major version?

Asked By: the_drow

||

Answers:

The Python version constants are in https://github.com/cython/cython/blob/master/Cython/Includes/cpython/version.pxd

You can include them with cimport cpython.version and use them with either compile time IF or a runtime if.

Be careful, if you want to distribute the C code without requiring to install Cython using a compile time IF will make your code not portable because the generated code will match only certain python versions.

Answered By: the_drow

Unfortunately it is not possible to use compile-time IF with PY_MAJOR_VERSION or similar; Cython only allows those compile-time constants described in the documentation.

Answered By: Julian Gilbey