Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我应该如何构造包含Cython代码的Python包_Python_Packaging_Cython - Fatal编程技术网

我应该如何构造包含Cython代码的Python包

我应该如何构造包含Cython代码的Python包,python,packaging,cython,Python,Packaging,Cython,我想制作一个包含一些代码的Python包。我的Cython代码运行得很好。然而,现在我想知道如何最好地包装它 对于大多数只想安装软件包的人来说,我希望包括Cython创建的.c文件,并安排setup.py编译该文件以生成模块。那么用户不需要安装Cython就可以安装软件包 但是对于那些可能想要修改软件包的人,我也希望提供Cython.pyx文件,并且以某种方式允许setup.py使用Cython构建它们(因此那些用户需要安装Cython) 我应该如何构造包中的文件以满足这两种情况 这个。但是它没

我想制作一个包含一些代码的Python包。我的Cython代码运行得很好。然而,现在我想知道如何最好地包装它

对于大多数只想安装软件包的人来说,我希望包括Cython创建的
.c
文件,并安排
setup.py
编译该文件以生成模块。那么用户不需要安装Cython就可以安装软件包

但是对于那些可能想要修改软件包的人,我也希望提供Cython
.pyx
文件,并且以某种方式允许
setup.py
使用Cython构建它们(因此那些用户需要安装Cython)

我应该如何构造包中的文件以满足这两种情况


这个。但是它没有说明如何制作一个单独的
setup.py
,来处理有/没有Cython的两种情况。

最简单的方法是同时包含这两种情况,而只使用c文件?包含.pyx文件很好,但是一旦有了.c文件就不需要了。想要重新编译.pyx的人可以安装Pyrex并手动执行

否则,您需要为首先生成C文件的distutils使用自定义build_ext命令。Cython已经包括了一个

该文档没有说明如何使其有条件,但是

try:
     from Cython.distutils import build_ext
except ImportError:
     from distutils.command import build_ext

应该可以处理。

我现在已经在Python包(-EDIT:now)中完成了这项工作(我不认为这是一个流行的包,但这是学习Cython的好机会)

此方法依赖于这样一个事实:使用
Cython.Distutils.build\u ext
(至少使用Cython版本0.14)构建
.pyx
文件似乎总是在与源
.pyx
文件相同的目录中创建
.c
文件

下面是
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创建的源代码发行版)


我不会将mycythonmodule.c提交给版本控制“trunk”(或Mercurial的“default”)。在发布时,我需要记住首先执行
python setup.py build\u 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"])]
)

这是我编写的一个安装脚本,它使在构建中包含嵌套目录变得更容易。需要从包中的文件夹运行它

Givig结构如下:

__init__.py
setup.py
test.py
subdir/
      __init__.py
      anothertest.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'],
        ),
    ],
)
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
从设置工具导入设置,扩展
从Cython.Distutils导入生成\u ext
#从操作系统导入路径
外部名称=(
"测试",,
“子目录另一个测试”,
) 
cmdclass={'build\u ext':build\u ext}
#对于主目录中的模块
外部模块=[
延伸(
提取,
[ext+“.py”],
) 
如果ext.find('.')<0,则用于ext_名称中的ext
#对于子目录中的模块,只需向下一级!!
#修改它,如果你需要更多!!!
外部模块+=[
延伸(
提取,
[“/”.join(ext.split('.')+“.py”],
)
如果ext.find('.')>0,则用于ext_名称中的ext
设置(
name='name',
ext_模块=ext_模块,
cmdclass=cmdclass,
packages=[“base”,“base.subdir”],
)
#建造--------------------------
#python setup.py build_ext--inplace
快乐编辑;)

包含(Cython)生成的.c文件非常奇怪。特别是当我们将其包含在git中时。我更喜欢用。当Cython不可用时,它将构建一个具有内置Cython环境的egg,然后使用egg构建代码

一个可能的例子:


更新(2017-01-05):


由于
setuptools 18.0
,因此无需使用
setuptools\u 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即可。您可能不应该共享此代码,但对于我自己的依赖项,它已经足够好了。

我发现,仅使用setuptools而不是功能受限的distutils的最简单方法是

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\u requires
    请求Cython和导入Cython之间产生鸡和蛋的问题
现代解决方案是使用setuptools,请参阅(Cython extensions的自动处理需要setuptools 18.0,也就是说,它已经提供了很多年)。国防部
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'],
        ),
    ],
)