Как указать источник Python 3 в Cython setup.py?

Я пытаюсь сделать программу "Hello World" на Cython, следуя этому руководству http://docs.cython.org/src/tutorial/cython_tutorial.html#cython-hello-world

Я создал helloworld.pyx

print("Hello World")

и setup.py:

from distutils.core import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("helloworld.pyx")
)

Как я могу изменить setup.py, чтобы указать, что моим источником является Python 3, а не Python 2, как в учебнике? Если я вызываю команду "cython" из командной строки, она принимает опцию -3. Но если я скомпилирую с python setup.py build_ext --inplace, как показано в руководстве, как мне указать исходный код Python 3? Это может не иметь большого значения для программы Hello World, но будет иметь значение, когда я начну использовать Cython для реальных проектов.

Большое спасибо!

Ответ 1

Это правильно, если вы просто вызываете setup.py с Python 3

Использование тестовой программы

print('hello',5,end='**\n') # Python3 syntax, breaks on Python2

Запуск Cython на нем без указания 3 дает

Error compiling Cython file:
------------------------------------------------------------
...
print('hello',5,end='**\n')                  ^
------------------------------------------------------------

print_something.pyx:1:19: Expected ')', found '='

при компиляции с помощью setup.py, вызванного с помощью python3, строит модуль правильно.

Ответ 2

Можно передать language_level в качестве опции в cythonize -function в setup.py -script:

extensions = cythonize(extensions, compiler_directives={'language_level' : "3"})) # or "2" or "3str"

или если скрипт должен интерпретироваться как language_level=2 Python2 и language_level=3 Python3 (поведение %% cython-magic в IPython):

import sys
# passing 3 or 2 as integer is also accepted:
cythonize(extensions, compiler_directives={'language_level' : sys.version_info[0]})

Другой возможный синтаксис:

extensions = cythonize(extensions, language_level = "3")

Выше может быть удобнее, чем добавить

#cython: language_level=3

для каждого pyx файла в проекте, что может оказаться необходимым, поскольку начиная с Cython 0.29 появляется предупреждение, если language_level не установлено явно:

/Main.py:367: FutureWarning: директива Cython 'language_level' отсутствует установить, используя 2 на данный момент (Py2). Это изменится в более позднем выпуске! Файл: XXXXXX.pyx
tree = Parsing.p_module(s, pxd, full_module_name)


Поскольку language_level является глобальной настройкой, декоратор

cimport cython

@cython.language_level("3")
def do_something():
    pass

даже не будет цифонизирован.

Ответ 3

Согласно официальной документации по компиляции, уровень языка Python можно указать с помощью директивы через специальный заголовок комментария в верхней части файла, например:

#!python
#cython: language_level=3

Похоже, нет способа указать это в setup.py. Поэтому, если у вас много файлов Cython, вам необходимо добавить директиву компилятора для каждого файла. Хотя единственная ситуация, с которой я столкнулся до сих пор, которая нуждается в этой директиве, - это print(), как в вашем примере, и я широко использовал Cython.

Ответ 4

Если вы используете файл setup.py с расширением, как в этом примере

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

ext_modules = [
    Extension("mymodule1",  ["mymodule1.py"]),
    Extension("mymodule2",  ["mymodule2.py"]),
]

setup(
    name = 'My Program Name',
    cmdclass = {'build_ext': build_ext},
    ext_modules = ext_modules
)

Затем вы должны добавить следующий фрагмент кода, чтобы применить директиву language_level:

for e in ext_modules:
    e.cython_directives = {'language_level': "3"} #all are Python-3