首页 \ 问答 \ 将输出文件添加到Python扩展(Adding output file to Python extension)

将输出文件添加到Python扩展(Adding output file to Python extension)

我已经定义了一个自定义的build_ext来构建一个时髦的扩展,我正在尝试使用pip-friendly。 以下是我正在做的修剪版本。

foo_ext = Extension(
  name='foo/_foo',
  sources=foo_sources,
)

class MyBuildExt(build_ext):
  def build_extension(self, ext):
    # This standalone script builds the __init__.py file 
    #  and some .h files for the extension
    check_call(['python', 'build_init_file.py'])

    # Now that we've created all the init and .h code
    #  build the C/C++ extension using setuptools/distutils
    build_ext.build_extension(self, ext)

    # Include the generated __init__.py in the build directory 
    #  which is something like `build/lib.linux-x86/foo/`.  
    #  How can I get setuptools/distutils to install the 
    #  generated file automatically?!
    generated_file = 'Source/foo/__init__.py'
    output_path = '/'.join(self.get_outputs()[0].split('/')[:-1])
    self.move_file(generated_file, output_path)

setup(
    ...,
    ext_modules = [foo_ext],
    cmdclass={'build_ext' : MyBuildExt},
)

打包这个模块并用pip安装后,我的virtualenv的site-packages目录中有一个模块foo 。 目录结构如下所示。

foo/
foo/__init__.py
foo/_foo.so

egg-info/SOURCES.txt文件不包含我手动创建/移动的__init__.py文件。 当我执行pip uninstall foo ,命令会在我的virtualenv的site-packages中留下foo/__init__.py 。 我想pip删除整个包。 如何将生成的__init__.py文件添加到安装的输出文件列表中?

我意识到这很令人作呕和骇人听闻,所以我欢迎恶心和苛刻的答案!

尝试:

  1. 添加了packages=['foo'] - 当我这样做时,pip不会构建扩展。 还尝试调整包名称的文件路径/命名空间版本 - 没有区别。

I've defined a custom build_ext to build a funky extension that I'm trying to make pip-friendly. The following is a trimmed version of what I'm doing.

foo_ext = Extension(
  name='foo/_foo',
  sources=foo_sources,
)

class MyBuildExt(build_ext):
  def build_extension(self, ext):
    # This standalone script builds the __init__.py file 
    #  and some .h files for the extension
    check_call(['python', 'build_init_file.py'])

    # Now that we've created all the init and .h code
    #  build the C/C++ extension using setuptools/distutils
    build_ext.build_extension(self, ext)

    # Include the generated __init__.py in the build directory 
    #  which is something like `build/lib.linux-x86/foo/`.  
    #  How can I get setuptools/distutils to install the 
    #  generated file automatically?!
    generated_file = 'Source/foo/__init__.py'
    output_path = '/'.join(self.get_outputs()[0].split('/')[:-1])
    self.move_file(generated_file, output_path)

setup(
    ...,
    ext_modules = [foo_ext],
    cmdclass={'build_ext' : MyBuildExt},
)

After packaging this module up and installing it with pip, I have a module foo in my virtualenv's site-packages directory. The directory structure looks like the following.

foo/
foo/__init__.py
foo/_foo.so

The egg-info/SOURCES.txt file does not include the __init__.py file that I manually created/moved. When I do a pip uninstall foo the command leaves foo/__init__.py in my virtualenv's site-packages. I would like pip to delete the entire package. How can I add the generated __init__.py file that I manually move into the build directory to the list of output files that are installed?

I realize this is disgusting and hacky, so I welcome disgusting and hacky answers!

Attempts:

  1. Added packages=['foo'] -- When I do, pip doesn't build extension. Also tried adjusting file path/namespace versions of the package name -- no difference.

原文:https://stackoverflow.com/questions/10559589
更新时间:2022-05-23 19:05

最满意答案

为了让distutils安装一个Python包,你需要传递packages=['foo'] ,如果你把它放在一个不是项目根级别的地方(我的意思是设置旁边的foo目录)。 py脚本),就像你似乎在这里做的那样,你还必须传递package_dir={'foo': 'Source'}或使用更简单的布局。 如果您的setup.py脚本包含此packages参数,那么build命令将调用build_py命令将Python源文件(和目录)移动到build目录,稍后将通过install命令复制该目录。

这里的问题是你的foo/__init__.py文件是由build_ext命令构建的,该命令在build_py之后运行。 您需要使用自定义生成命令覆盖它:

class MyBuild(build):
  sub_commands = [('build_clib', build.has_c_libraries),
                  ('build_ext', build.has_ext_modules),
                  ('build_py', build.has_pure_modules),
                  ('build_scripts', build.has_scripts),
                 ]

setup(..., cmdclass={'build': MyBuild, 'build_ext': MyBuildExt})

sub_commands属性中的元素是(命令名,调用函数以决定是否运行命令)的元组; 这是在源代码中记录的,但我不记得是否在文档中解释了它。 在标准构建类中,build_py位于build_clib之前。 我可能会在下一版本的Python 2.7中对此进行更改,因为据报道它与2to3转换的交互非常糟糕。


In order to have distutils install a Python package, you need to pass packages=['foo'], and if you’re putting it somewhere that is not the root level of the project (I mean the foo directory next to the setup.py script), like you seem to do here, you also have to pass package_dir={'foo': 'Source'} or to use a simpler layout. If your setup.py script contains this packages parameter then the build command will invoke the build_py command to move the Python source files (and directories) to the build directory, which will be copied later by the install command.

The problem here is that your foo/__init__.py file is built by the build_ext command, which runs after build_py. You need to override that with a custom build command:

class MyBuild(build):
  sub_commands = [('build_clib', build.has_c_libraries),
                  ('build_ext', build.has_ext_modules),
                  ('build_py', build.has_pure_modules),
                  ('build_scripts', build.has_scripts),
                 ]

setup(..., cmdclass={'build': MyBuild, 'build_ext': MyBuildExt})

The elements in the sub_commands attribute are tuples of (command name, function to call to decide whether to run the command or not); this is documented in the source code but I don’t remember if it’s explained in the doc. In the standard build class build_py precedes build_clib. I may change this in the next version of Python 2.7, as it was reported that it interacted badly with 2to3 conversion.

相关问答

更多