mypackmymod.py__init__.py__init__.py
. 
│  
├── mypack
│   ├── __init__.py
│   └── mymod.py
├── setup.py

我发现Cython可以通过转换.so库中的每个.py文件来做到这一点
可以直接用python导入。
问题是:为了便于打包和安装,
setup.py
文件必须如何?
目标系统有一个virtualenv,包必须与
任何允许轻松安装和卸载的方法(轻松安装、pip等
欢迎)。
我尽力了我读了
setuptools
distutils
文档,
所有与stackoverflow相关的问题,
并尝试使用各种命令(sdist、bdist、bdist撸egg等),有很多
setup.cfg和MANIFEST.in文件项的组合。
我得到的最接近的是下面的设置文件,它将子类bdist_egg
命令以同时删除.pyc文件,但这会中断安装。
在venv中“手动”安装文件的解决方案是
也很好,前提是所有包含在
包括安装(我需要在venv中运行
pip freeze
,并查看
mymod==0.0.1
)。
运行时使用:
python setup.py bdist_egg --exclude-source-files

安装时
easy_install mymod-0.0.1-py2.7-linux-x86_64.egg

正如您可能注意到的,目标是使用Python2.7的linux 64位。
from Cython.Distutils import build_ext
from setuptools import setup, find_packages
from setuptools.extension import Extension
from setuptools.command import bdist_egg
from setuptools.command.bdist_egg import  walk_egg, log 
import os

class my_bdist_egg(bdist_egg.bdist_egg):

    def zap_pyfiles(self):
        log.info("Removing .py files from temporary directory")
        for base, dirs, files in walk_egg(self.bdist_dir):
            for name in files:
                if not name.endswith('__init__.py'):
                    if name.endswith('.py') or name.endswith('.pyc'):
                        # original 'if' only has name.endswith('.py')
                        path = os.path.join(base, name)
                        log.info("Deleting %s",path)
                        os.unlink(path)

ext_modules=[
    Extension("mypack.mymod", ["mypack/mymod.py"]),
]

setup(
  name = 'mypack',
  cmdclass = {'build_ext': build_ext, 
              'bdist_egg': my_bdist_egg },
  ext_modules = ext_modules,
  version='0.0.1',
  description='This is mypack compiled lib',
  author='Myself',
  packages=['mypack'],
)

更新。
根据@Teyras的答案,可以按照答案中的要求构建一个轮子
setup.py
文件内容是:
import os
import shutil
from setuptools.extension import Extension
from setuptools import setup
from Cython.Build import cythonize
from Cython.Distutils import build_ext

class MyBuildExt(build_ext):
    def run(self):
        build_ext.run(self)
        build_dir = os.path.realpath(self.build_lib)
        root_dir = os.path.dirname(os.path.realpath(__file__))
        target_dir = build_dir if not self.inplace else root_dir
        self.copy_file('mypack/__init__.py', root_dir, target_dir)

    def copy_file(self, path, source_dir, destination_dir):
        if os.path.exists(os.path.join(source_dir, path)):
            shutil.copyfile(os.path.join(source_dir, path), 
                            os.path.join(destination_dir, path))


setup(
  name = 'mypack',
  cmdclass = {'build_ext': MyBuildExt},
  ext_modules = cythonize([Extension("mypack.*", ["mypack/*.py"])]),
  version='0.0.1',
  description='This is mypack compiled lib',
  author='Myself',
  packages=[],
  include_package_data=True )

关键是设置
packages=[],
需要重写
build_ext
run
方法才能在控制盘中获取
__init__.py
文件。

最佳答案:

packages=[]spamspam.eggsspam.baconspam.fizzspam.fizz.buzz
root
├── setup.py
└── spam
    ├── __init__.py
    ├── bacon.py
    ├── eggs.py
    └── fizz
        ├── __init__.py
        └── buzz.py

模块查找是在
build_py
命令中完成的,因此需要用自定义行为对其进行子类化。
简单的例子:编译所有的源代码,没有异常
如果您要编译每个
.py
文件(包括
__init__.py
s),那么重写
build_py.build_packages
方法就足够了,使其成为noop因为
build_packages
什么都不做,所以根本不会收集
.py
文件,而dist只包含cythodized扩展名:
import fnmatch
from setuptools import find_packages, setup, Extension
from setuptools.command.build_py import build_py as build_py_orig
from Cython.Build import cythonize


extensions = [
    # example of extensions with regex
    Extension('spam.*', ['spam/*.py']),
    # example of extension with single source file
    Extension('spam.fizz.buzz', ['spam/fizz/buzz.py']),
]


class build_py(build_py_orig):
    def build_packages(self):
        pass


setup(
    name='...',
    version='...',
    packages=find_packages(),
    ext_modules=cythonize(extensions),
    cmdclass={'build_py': build_py},
)

复杂情况:将cythonized扩展与源模块混合
如果只想编译选定的模块而不修改其余的模块,则需要更复杂的逻辑;在这种情况下,需要重写模块查找在下面的示例中,我仍然将
spam.bacon
spam.eggs
spam.fizz.buzz
编译为共享对象,但不更改
__init__.py
文件,因此它们将作为源模块包含:
import fnmatch
from setuptools import find_packages, setup, Extension
from setuptools.command.build_py import build_py as build_py_orig
from Cython.Build import cythonize


extensions = [
    Extension('spam.*', ['spam/*.py']),
    Extension('spam.fizz.buzz', ['spam/fizz/buzz.py']),
]
cython_excludes = ['**/__init__.py']


def not_cythonized(tup):
    (package, module, filepath) = tup
    return any(
        fnmatch.fnmatchcase(filepath, pat=pattern) for pattern in cython_excludes
    ) or not any(
        fnmatch.fnmatchcase(filepath, pat=pattern)
        for ext in extensions
        for pattern in ext.sources
    )


class build_py(build_py_orig):
    def find_modules(self):
        modules = super().find_modules()
        return list(filter(not_cythonized, modules))

    def find_package_modules(self, package, package_dir):
        modules = super().find_package_modules(package, package_dir)
        return list(filter(not_cythonized, modules))


setup(
    name='...',
    version='...',
    packages=find_packages(),
    ext_modules=cythonize(extensions, exclude=cython_excludes),
    cmdclass={'build_py': build_py},
)