source

Cython 코드를 포함하는 Python 패키지를 구성하는 방법

factcode 2023. 7. 23. 14:46
반응형

Cython 코드를 포함하는 Python 패키지를 구성하는 방법

싸이톤 코드가 포함된 파이썬 패키지를 만들고 싶습니다.사이톤 코드는 잘 작동합니다.하지만, 지금은 어떻게 포장하는 것이 가장 좋은지 알고 싶습니다.

, 패지를설는대부사의위해을람들다, ▁the,를 포함하고 싶습니다.cCython이 생성하는 파일, 그리고 준비setup.py모듈을 생성하기 위해 컴파일합니다.그러면 사용자는 패키지를 설치하기 위해 Cython을 설치할 필요가 없습니다.

하지만 패키지를 수정하고 싶은 사람들을 위해 싸이톤도 제공하고 싶습니다..pyx든 파일, 그고든어또한허다니도 합니다.setup.pyCython을 사용하여 빌드할 수 있습니다(그러므로 사용자는 Cython을 설치해야 합니다.

이 두 가지 시나리오를 모두 충족하기 위해 패키지의 파일을 어떻게 구성해야 합니까?

사이튼 문서는 약간의 지침을 제공합니다.하지만 그것은 싱글을 만드는 방법을 말하지 않습니다.setup.pyCython이 있는 경우와 없는 경우를 모두 처리합니다.

저는 지금 이것을 파이썬 패키지(BitBucket repo - EDIT: now github)에서 직접 해보았습니다(이것이 인기 있는 패키지가 될 것이라고 기대하지는 않지만, Cython을 배울 수 있는 좋은 기회였습니다).

이 방법은 건물을 짓는 것에 의존합니다..pyx로 철하다Cython.Distutils.build_ext(적어도 Cython 버전 0.14에서는) 항상 생성되는 것 같습니다..c원본과 동일한 디렉토리에 있는 파일.pyxjava.

다음은 의 축소 버전입니다.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 distribution)에됩니다.python setup.py sdist):

...
recursive-include cython *
...

약속하지 않습니다.mycythonmodule.c버제 어또 'trunk' (Mercurial 경 'default')내가 발표할 때, 나는 기억해야 하는 것을 기억해야 합니다.python setup.py build_ext첫째로, 확실하게 하기 위해mycythonmodule.c소스 코드 배포에 대한 최신 상태입니다.저는 또한 릴리즈 브랜치를 만들고 C 파일을 브랜치에 커밋합니다.그런 식으로 저는 그 릴리스와 함께 배포된 C 파일의 과거 기록을 가지고 있습니다.

McQueen의: 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

http://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html#distributing-cython-modules

생성된 .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-file만 사용하면 되나요?.pyx 파일을 포함하는 것은 좋지만 일단 .c 파일이 있으면 필요하지 않습니다..pyx를 다시 컴파일하려는 사용자는 Pyrex를 설치하고 수동으로 작업할 수 있습니다.

그렇지 않으면 C 파일을 먼저 빌드하는 distutils에 대한 사용자 지정 build_ext 명령이 필요합니다.사이톤은 이미 하나를 포함하고 있습니다.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

처리해야 합니다.

(사이톤) 생성된 .c 파일을 포함하는 것은 꽤 이상합니다.특히 우리가 그것을 포함할 때.setuptools_cython을 사용하고 싶습니다.사이톤을 사용할 수 없을 때, 그것은 사이톤 환경을 내장한 알을 만든 다음, 그 알을 사용하여 당신의 코드를 구축할 것입니다.

가능한 예: https://github.com/douban/greenify/blob/master/setup.py


업데이트(2017-01-05):

때부터setuptools 18.0사용할 필요가 없습니다.setuptools_cython다음은 Cython 프로젝트를 처음부터 구축하기 위한 예제입니다.setuptools_cython.

다른 모든 답변은 다음에 의존합니다.

  • 현란한 일
  • 에서 가져오기Cython.Build그것은 사이톤을 필요로 하는 것 사이에 치킨과 치킨 문제를 만듭니다.setup_requires가져오기를 수행할 수 있습니다.

최신 솔루션은 설정 도구를 대신 사용하는 것입니다. 이 답변을 참조하십시오. (Cython 확장을 자동으로 처리하려면 설정 도구 18.0이 필요합니다. 즉, 이미 여러 해 동안 사용할 수 있습니다.)현대의 표준.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'],
        ),
    ],
)

제가 생각해 낸 간단한 해킹은 다음과 같습니다.

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을 가져올 수 없으면 설치만 하면 됩니다.아마 이 코드를 공유하면 안되지만, 나 자신의 의존성에 대해서는 충분합니다.

이것은 빌드 내에 중첩된 디렉토리를 더 쉽게 포함할 수 있도록 작성한 설정 스크립트입니다.패키지 내의 폴더에서 실행해야 합니다.

다음과 같은 큰 구조를 제공합니다.

__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

해피 컴파일 ;)

제한된 기능 대신 설정 도구만 사용하는 가장 쉬운 방법은

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)

할 수 있는 해서 찾은 것 같습니다.build_ext 다음과 같습니다.

  1. 재정의하여 numpy 헤더를 추가합니다.finalize_options() 는것하기import numpy이전에 사용할 수 없는 numpy의 문제를 멋지게 피하는 기능의 본체에서.setup()설치합니다.

  2. 할 수 있는 시템에사사을수있용경연명다결니됩에령어우는서이에 합니다.check_extensions_list() 및 오래된 모듈을 나중에 할 수 C 합니다.build_extension()例방.즉, 할 수 없지만 C 경우에도 하므로 소스 할 수 있습니다.우리는 모듈에서 기능의 후반부를 제공할 뿐입니다. 즉, 사이톤을 사용할 수 없지만 C 확장이 존재하는 경우에도 여전히 작동하므로 소스 배포를 수행할 수 있습니다.

코드는 다음과 같습니다.

import re, sys, os.path
from distutils import dep_util, log
from setuptools.command.build_ext import build_ext

try:
    import Cython.Build
    HAVE_CYTHON = True
except ImportError:
    HAVE_CYTHON = False

class BuildExtWithNumpy(build_ext):
    def check_cython(self, ext):
        c_sources = []
        for fname in ext.sources:
            cname, matches = re.subn(r"(?i)\.pyx$", ".c", fname, 1)
            c_sources.append(cname)
            if matches and dep_util.newer(fname, cname):
                if HAVE_CYTHON:
                    return ext
                raise RuntimeError("Cython and C module unavailable")
        ext.sources = c_sources
        return ext

    def check_extensions_list(self, extensions):
        extensions = [self.check_cython(ext) for ext in extensions]
        return build_ext.check_extensions_list(self, extensions)

    def finalize_options(self):
        import numpy as np
        build_ext.finalize_options(self)
        self.include_dirs.append(np.get_include())

이것은 사람들이 단지 쓸 수 있게 합니다.setup()수입에 대한 걱정이 없는 논쟁과 사이톤을 사용할 수 있는지 여부:

setup(
    # ...
    ext_modules=[Extension("_my_fast_thing", ["src/_my_fast_thing.pyx"])],
    setup_requires=['numpy'],
    cmdclass={'build_ext': BuildExtWithNumpy}
    )

언급URL : https://stackoverflow.com/questions/4505747/how-should-i-structure-a-python-package-that-contains-cython-code

반응형