【发布时间】:2017-01-22 19:00:18
【问题描述】:
我有一个名为mypack 的包,里面有一个模块mymod.py,并且
__init__.py。
出于某种没有争议的原因,我需要打包这个模块编译
(也不允许 .py 或 .pyc 文件)。也就是说,__init__.py 是唯一的
分布式压缩文件中允许的源文件。
文件夹结构为:
.
│
├── mypack
│ ├── __init__.py
│ └── mymod.py
├── setup.py
我发现 Cython 能够通过转换 .so 库中的每个 .py 文件来做到这一点 可以直接用python导入。
问题是:setup.py 文件必须如何才能轻松打包和安装?
目标系统有一个 virtualenv 必须安装包 任何允许轻松安装和卸载的方法(easy_install、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
您可能会注意到,目标是带有 python 2.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 文件放入轮子中。
【问题讨论】:
标签: python cython setuptools distutils setup.py