【问题标题】:How to use setuptools packages and ext_modules with the same name?如何使用同名的 setuptools 包和 ext_modules?
【发布时间】:2019-10-08 05:39:08
【问题描述】:

我的 Python C 扩展项目的文件结构如下:

.
├── setup.py
├── source
    ├── cppimplementation
    │   └── fastfile.cpp
    └── fastfilepackage
        ├── __init__.py
        └── version.py

我使用以下setup.py 文件:

from setuptools import setup, Extension

setup(
        name= 'fastfilepackage',
        version= '0.1.1',
        package_dir = {
            '': 'source',
        },

        packages = [
            'fastfilepackage',
        ],

        ext_modules= [
            Extension(
                'fastfilepackage',
                [
                    'source/cppimplementation/fastfile.cpp',
                ]
            )
        ],
    )

我安装它们:

$ pip3 --version
pip 19.1.1 (python 3.6)

$ python3 --version
Python 3.6.7

$ pip3 list
Package                Version      
---------------------- -------------
wheel                  0.33.1        
setuptools             40.8.0        
...

fastfilepackage$ pip3 install .

问题是,当我安装它时,我的 Python C 扩展模块被 fastfilepackage/version.pyfastfilepackage/__init__.py 覆盖,即安装后,我得到以下信息:

import fastfilepackage
print( dir( fastfilepackage ) )
# prints ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', 
#         '__name__', '__package__', '__path__', '__spec__', '__version__',
#         'version']

即,source/cppimplementation/fastfile.cpp 没有导出 FastFile 类,但它具有 fastfilepackage/version.pyfastfilepackage/__init__.py 文件。

这是安装的文件结构:

.
└── dist-packages
    ├── fastfilepackage
    │   ├── __init__.py
    │   ├── __pycache__
    │   │   ├── __init__.cpython-36.pyc
    │   │   └── version.cpython-36.pyc
    │   └── version.py
    ├── fastfilepackage-0.1.1.dist-info
    │   ├── INSTALLER
    │   ├── LICENSE.txt
    │   ├── METADATA
    │   ├── RECORD
    │   ├── top_level.txt
    │   └── WHEEL
    └── fastfilepackage.cpython-36m-x86_64-linux-gnu.so

但是,如果我从我的安装文件中删除package_dir = { '': 'source', },packages = [ 'fastfilepackage', ], 行,那么我的Python C 扩展模块安装正确:

import fastfilepackage
print( dir( fastfilepackage ) )
# prints ['FastFile', '__doc__', '__file__', '__loader__', '__name__', 
#         '__package__', '__spec__']

即,它有source/cppimplementation/fastfile.cpp 导出的FastFile 类,但它没有fastfilepackage/version.pyfastfilepackage/__init__.py 文件。

这是安装的文件结构:

.
└── dist-packages
    ├── fastfilepackage-0.1.1.dist-info
    │   ├── INSTALLER
    │   ├── LICENSE.txt
    │   ├── METADATA
    │   ├── RECORD
    │   ├── top_level.txt
    │   └── WHEEL
    └── fastfilepackage.cpython-36m-x86_64-linux-gnu.so

如何将ext_modulespackages 放在我的setup.py 下使用相同的包名而不覆盖另一个?

【问题讨论】:

    标签: python-3.x pip python-import setuptools python-c-api


    【解决方案1】:

    你不能。第一个导入的获胜。你不能有同名的脚本/模块/包/扩展——一个覆盖所有其他的。

    但是你可以把一个放在另一个里面。将你的扩展命名为fastfilepackage.fastfilepackage,你可以import fastfilepackage导入Python包,import fastfilepackage.fastfilepackage导入扩展;或from fastfilepackage import fastfilepackage

    【讨论】:

    • 你能给我一个setup.py这样做的例子吗?
    • Extension('fastfilepackage.fastfilepackage', ['source/cppimplementation/fastfile.cpp',])
    • 我这样做了,但它没有开箱即用。我还必须编辑fastfilepackage/__init__.py 并手动包含from . import fastfilepackage
    【解决方案2】:

    作为最终解决方案,我完全删除了所有 Python *.py 代码,因为它们导致 C 扩展代码变慢了 30%。现在我的setup.py变成了这样:

    from setuptools import setup, Extension
    
    setup(
            name = 'fastfilepackage',
            version = '0.1.1',
    
            ext_modules = [
                Extension(
                    name = 'fastfilepackage',
                    sources = [
                        'source/fastfile.cpp',
                    ],
                    include_dirs = ['source'],
                )
            ],
        )
    

    文件结构:

    .
    ├── setup.py
    ├── MANIFEST.in
    ├── README.md
    ├── LICENSE.txt
    └── source
        ├── fastfile.cpp
        └── version.h
    

    MANIFEST.in

    include README.md
    include LICENSE.txt
    
    recursive-include source *.h
    

    这是已安装的文件结构:(任何地方都没有 *.py 文件 = 100% 性能)

    .
    └── dist-packages
        ├── fastfilepackage-0.1.1.dist-info
        │   ├── INSTALLER
        │   ├── LICENSE.txt
        │   ├── METADATA
        │   ├── RECORD
        │   ├── top_level.txt
        │   └── WHEEL
        └── fastfilepackage.cpython-36m-x86_64-linux-gnu.so
    

    我只是将version.py 直接替换为 C 扩展模块属性:

    // https://docs.python.org/3/c-api/arg.html#c.Py_BuildValue
    const char* __version__ = "0.1.1";
    PyObject_SetAttrString( thismodule, "__version__", Py_BuildValue( "s", __version__ ) );
    

    参考资料:

    1. Define a global in a Python module from a C API
    2. 原始提交:Deprecated the Python implementation *.py

    【讨论】:

      猜你喜欢
      • 2011-11-23
      • 2012-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-06
      • 2016-05-09
      相关资源
      最近更新 更多