简体   繁体   English

Python setup.py:如何包含本地包依赖?

[英]Python setup.py: how to include local package dependency?

The question is pretty much self explanatory.这个问题几乎不言自明。 I have got a .zip package dependency that I need to include in my python package installation.我有一个 .zip 包依赖项,我需要将它包含在我的 python 包安装中。 So how do I include this local dependency in my setup.py ?那么如何在我的setup.py包含这个本地依赖? I have got install_requires but this loads my dependency packages from PyPI which is not what I want in this case.我有install_requires但这从 PyPI 加载了我的依赖包,这在这种情况下不是我想要的。

The most relevant files in my project are structured as follows:我的项目中最相关的文件结构如下:

myproject
|- setup.py
|- mypackage
   |- __init__.py
   |- vendor
      |- __init__.py
      |- dependencies
         |- StreamingDataReader.zip

I then tried ...然后我尝试...

include_package_data=True,
package_data={
    'StreamingDataReader': ['mypackage/vendor/dependencies/StreamingDataReader.zip'],
}

... with no success. ......没有成功。 My code can't still locate the package: ImportError: No module named 'StreamingDataReader'我的代码仍然无法找到包: ImportError: No module named 'StreamingDataReader'

This is an old question, but I have something to say about it, so I'm posting.这是一个老问题,但我对此有话要说,所以我发帖了。

You have two separate problems here.你在这里有两个不同的问题。 The first is that the zip file needs to be included in your distribution.首先是 zip 文件需要包含在您的发行版中。 To do this, use package_data as you're intending, but you need to specify, for your package, what data within it you want to include.为此,请按照您的意图使用package_data ,但您需要为您的包指定要包含其中的哪些数据。 You do this as follows:您可以按如下方式执行此操作:

   package_data= {"mypackage": ["vendor/dependencies/StreamingDataReader.zip"]}

Do not use include_package_data at the same time;不要同时使用include_package_data this looks for data in MANIFEST.in and ignores the package_data parameter.这会在MANIFEST.in查找数据并忽略package_data参数。 setuptools is really badly designed for managing this. setuptools设计真的很糟糕,用于管理这个。 The best advice I've found, for both binary and source packaging, is to ensure that all your data is within the package directory, and to use package_data and nothing else.对于二进制和源代码打包,我发现的最佳建议是确保所有数据都在包目录中,并使用package_data而不是其他任何东西。

Your second problem is that you want to be able to import StreamingDataReader .您的第二个问题是您希望能够导入StreamingDataReader Unfortunately, as far as I can tell, there's no way to do this with pip using pip install and nothing else.不幸的是,据我所知,没有办法一起做这个pip使用pip install ,没有别的。 You have two obvious choices:你有两个明显的选择:

(1) You can include a requirements.txt file and list the zip file as a requirement, and have people do pip install -r requirements.txt in advance of pip install ing your project. (1) 您可以包含一个requirements.txt文件并将 zip 文件列为需求,并让人们在pip install您的项目之前执行pip install -r requirements.txt Your requirements.txt file would look like this:您的requirements.txt文件将如下所示:

./mypackage/vendor/dependencies/StreamingDataReader.zip

But requiring the user to do that may be an unacceptable level of pain, and it won't work for anyone who depends on your package.但是要求用户这样做可能会带来不可接受的痛苦,并且对于依赖您的软件包的任何人都不起作用。

(2) Brute force. (2) 蛮力。 Just use zipfile to expand the package.只需使用zipfile来扩展包。

I'm going to assume that StreamingDataReader.zip file is a Python package zip, with a single directory at the toplevel (I'm assuming it's called StreamingDataReader ) which contains a toplevel setup.py and a subdirectory, let's assume it's called StreamingDataReader , which contains the actual software.我将假设StreamingDataReader.zip文件是一个 Python 包 zip,在顶层有一个目录(我假设它称为StreamingDataReader ),其中包含一个顶层setup.py和一个子目录,假设它称为StreamingDataReader ,其中包含实际的软件。 In other words, I assume your zip looks like this:换句话说,我假设你的 zip 看起来像这样:

StreamingDataReader/
StreamingDataReader/setup.py
StreamingDataReader/StreamingDataReader/__init__.py

etc. I'm also going to assume that you're running Python 3.3 or later, in which having an __init__.py file is no longer required to create a package hierarchy.等等。我还将假设您正在运行 Python 3.3 或更高版本,其中不再需要__init__.py文件来创建包层次结构。 (In previous versions, you'd need to manipulate sys.path , which isn't a big deal, but it's now easier.) So vendor/__init__.py isn't doing any work for you. (在以前的版本中,您需要操作sys.path ,这没什么大不了的,但现在更容易了。)因此vendor/__init__.py不会为您做任何工作。

This solution, by the way, assumes that the folks who run your software will have write permission on the directory which contains it.顺便说一下,这个解决方案假设运行你的软件的人对包含它的目录有写权限。

Put the following in your toplevel __init__.py :将以下内容放在您的顶层__init__.py

import zipfile, pathlib

_mpath = pathlib.Path(__file__).resolve().parent
_sdrDir = mpath.joinpath("vendor", "dependencies", "StreamingDataReader")
if not _sdrDir.is_dir():
    _z = zipfile.Zipfile(sdrDir.parent.joinpath("StreamingDataReader.zip"), "r")
    _z.extractall(sdrDir.parent)
    _z.close()
    del _z
# cleanup
del _mpath
del _sdrDir

Once you do this, you can一旦你这样做了,你就可以

import mypackage.vendor.dependencies.StreamingDataReader.StreamingDataReader as StreamingDataReader

wherever you want.随心所欲。

Then, finally, in the setup.py for your package, you'll need to include the dependencies for StreamingDataReader , because you're not recursively installing it with pip .然后,最后,在您的包的setup.py中,您需要包含StreamingDataReader依赖项,因为您没有使用pip递归安装它。

Yes, that's a lot of work.是的,这是很多工作。 But as far as I know, there's no facility in the Python installation mechanism for otherwise installing a package from a zip file you provide yourself.但据我所知,Python 安装机制中没有任何工具可以从您自己提供的 zip 文件中安装包。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM