いくつかの Cython コードを含むPythonパッケージを作成したい。Cythonコードがうまく機能している。それをパッケージ化します。
パッケージをインストールするだけのほとんどの人のために、.c
Cythonが作成し、setup.py
をコンパイルしてモジュールを生成します。その場合、ユーザーはパッケージをインストールするためにCythonをインストールする必要はありません。
しかし、パッケージを変更したい人のために、Cython .pyx
ファイル、および何らかの理由でsetup.py
Cythonを使用してそれらをビルドします(したがって、それらのユーザーはCythonをインストールする必要があります。
これらの両方のシナリオに対応するために、パッケージ内のファイルをどのように構成する必要がありますか?
Cythonのドキュメントに少しガイダンスがあります 。しかし、単一のsetup.py
Cythonの場合となしの両方のケースを処理します。
Python package simplerandom
( BitBucket repo -EDIT:now- github )(これが人気のあるパッケージになるとは思いませんが、Cythonを学ぶ良い機会でした)。
この方法は、(少なくともCythonバージョン0.14で).pyx
を使用してCython.Distutils.build_ext
ファイルをビルドすると、常にソース.c
ファイルと同じディレクトリに.pyx
ファイルが作成されるように見えるという事実に依存しています。
ここにsetup.py
の短縮版がありますが、これは基本的なものを示しています。
from distutils.core import setup
from distutils.extension import Extension
try:
from Cython.Distutils import build_ext
except ImportError:
use_cython = False
else:
use_cython = True
cmdclass = {}
ext_modules = []
if use_cython:
ext_modules += [
Extension("mypackage.mycythonmodule", ["cython/mycythonmodule.pyx"]),
]
cmdclass.update({'build_ext': build_ext})
else:
ext_modules += [
Extension("mypackage.mycythonmodule", ["cython/mycythonmodule.c"]),
]
setup(
name='mypackage',
...
cmdclass=cmdclass,
ext_modules=ext_modules,
...
)
MANIFEST.in
を編集して、mycythonmodule.c
がソースディストリビューション(python setup.py sdist
で作成されたソースディストリビューション)に含まれるようにしました:
...
recursive-include cython *
...
mycythonmodule.c
をバージョン管理 'trunk'(またはMercurialの 'default')にコミットしません。リリースを行うときは、最初にpython setup.py build_ext
を実行し、mycythonmodule.c
が存在し、ソースコード配布用に最新であることを確認する必要があります。また、リリースブランチを作成し、Cファイルをブランチにコミットします。そうすれば、そのリリースで配布されたCファイルの履歴レコードがあります。
Craig McQueenの答えに追加:sdist
コマンドをオーバーライドして、Cythonがソースディストリビューションを作成する前にソースファイルを自動的にコンパイルする方法については、以下を参照してください。
そうすれば、古いC
ソースを誤って配布するリスクがなくなります。また、配布プロセスの制御が制限されている場合にも役立ちます。継続的インテグレーションなどから自動的に分布を作成する場合.
from distutils.command.sdist import sdist as _sdist
...
class sdist(_sdist):
def run(self):
# Make sure the compiled Cython files in the distribution are up-to-date
from Cython.Build import cythonize
cythonize(['cython/mycythonmodule.pyx'])
_sdist.run(self)
cmdclass['sdist'] = sdist
生成された.cファイルとCythonソースを配布することを強くお勧めします。これにより、ユーザーはCythonを使用可能にする必要なくモジュールをインストールできます。
また、配布するバージョンでCythonコンパイルをデフォルトで有効にしないことをお勧めします。ユーザーがCythonをインストールしていても、おそらくモジュールのインストールだけに使用したくないでしょう。また、彼が持っているバージョンはあなたが使用したものとは異なるかもしれず、ソースを正しくコンパイルできないかもしれません。
これは単に、出荷するsetup.pyファイルが、生成された.cファイルの通常のdistutilsファイルであることを意味します。代わりに、基本的な例があります。
from distutils.core import setup from distutils.extension import Extension setup( ext_modules = [Extension("example", ["example.c"])] )
最も簡単なのは両方を含めることですが、Cファイルを使用するだけですか? .pyxファイルを含めるのはいいことですが、.cファイルを作成した後は、必要ありません。 .pyxを再コンパイルしたい人は、Pyrexをインストールして手動で実行できます。
それ以外の場合は、最初にCファイルをビルドするdistutils用のカスタムbuild_extコマンドが必要です。 Cythonにはすでに含まれています。 http://docs.cython.org/src/userguide/source_files_and_compilation.html
そのドキュメントがしないことは、この条件付きにする方法を言うことですが、
try:
from Cython.distutils import build_ext
except ImportError:
from distutils.command import build_ext
それを処理する必要があります。
(Cython)生成された.cファイルを含めるのはかなり奇妙です。特にgitに含める場合。 setuptools_cython を使用したいと思います。 Cythonが利用できない場合、Cython環境が組み込まれたEggをビルドし、Eggを使用してコードをビルドします。
可能な例: https://github.com/douban/greenify/blob/master/setup.py
アップデート(2017-01-05):
setuptools 18.0
なので、setuptools_cython
を使用する必要はありません。 ここ は、setuptools_cython
なしでCythonプロジェクトをゼロからビルドする例です。
私が思いついた簡単なハック:
from distutils.core import setup
try:
from Cython.Build import cythonize
except ImportError:
from pip import pip
pip.main(['install', 'cython'])
from Cython.Build import cythonize
setup(…)
Cythonをインポートできなかった場合はインストールしてください。おそらくこのコードを共有すべきではありませんが、私自身の依存関係については十分です。
これは、ビルド内にネストされたディレクトリを簡単に含めることができるように作成したセットアップスクリプトです。パッケージ内のフォルダーから実行する必要があります。
このようなGivig構造:
__init__.py
setup.py
test.py
subdir/
__init__.py
anothertest.py
setup.py
from setuptools import setup, Extension
from Cython.Distutils import build_ext
# from os import path
ext_names = (
'test',
'subdir.anothertest',
)
cmdclass = {'build_ext': build_ext}
# for modules in main dir
ext_modules = [
Extension(
ext,
[ext + ".py"],
)
for ext in ext_names if ext.find('.') < 0]
# for modules in subdir ONLY ONE LEVEL DOWN!!
# modify it if you need more !!!
ext_modules += [
Extension(
ext,
["/".join(ext.split('.')) + ".py"],
)
for ext in ext_names if ext.find('.') > 0]
setup(
name='name',
ext_modules=ext_modules,
cmdclass=cmdclass,
packages=["base", "base.subdir"],
)
# Build --------------------------
# python setup.py build_ext --inplace
ハッピーコンパイル;)
機能制限されたdistutilsの代わりにsetuptoolsのみを使用して見つけた最も簡単な方法は
from setuptools import setup
from setuptools.extension import Extension
try:
from Cython.Build import cythonize
except ImportError:
use_cython = False
else:
use_cython = True
ext_modules = []
if use_cython:
ext_modules += cythonize('package/cython_module.pyx')
else:
ext_modules += [Extension('package.cython_module',
['package/cython_modules.c'])]
setup(name='package_name', ext_modules=ext_modules)
他のすべての答えは、
Cython.Build
からインポートすると、setup_requires
を介してcythonを要求してからインポートするまでの間に鶏肉と卵の問題が発生します。最新の解決策は、代わりにsetuptoolsを使用することです。 この回答 を参照してください(Cython拡張機能の自動処理にはsetuptools 18.0が必要です。つまり、すでに長年利用可能です)。要件処理、エントリポイント、cythonモジュールを備えた最新の標準setup.py
は次のようになります。
from setuptools import setup, Extension
with open('requirements.txt') as f:
requirements = f.read().splitlines()
setup(
name='MyPackage',
install_requires=requirements,
setup_requires=[
'setuptools>=18.0', # automatically handles Cython extensions
'cython>=0.28.4',
],
entry_points={
'console_scripts': [
'mymain = mypackage.main:main',
],
},
ext_modules=[
Extension(
'mypackage.my_cython_module',
sources=['mypackage/my_cython_module.pyx'],
),
],
)