setup.py,pip - 获取Python包的执行原始路径
我有一个Python包,需要通过pip
来安装它,这个包是我项目需求文件的一部分。不过,我还想把一些文件从我的包里复制到安装这个包的项目中。我在考虑用setup()
里的data_files选项来实现,像这样:
setup(
name='my_pacakge',
...
data_files=[
('example/folder1', ['something1/file1.ext', 'something1/file2.ext']),
('folder2', ['something2/file1.ext', 'something2/file2.ext']),
]
)
我希望这些文件能被复制到相对于运行pip install my_package
的目录的路径,理想情况下是我的项目根目录,最终形成这样的结构:
project_root
├── example
│ └── folder1
│ ├── file1.ext
│ └── file2.ext
└── folder2
├── file1.ext
└── file2.ext
但为了做到这一点,我需要知道运行pip install my_package
时的绝对路径。我尝试过用inspect.stack
、inspect.currentframe
、sys.get_frame
、inspect.inspect.getouterframes(some_of_these_frames)
,但这些方法只给我提供了在安装时setup.py当前所在位置的信息,比如:
/private/var/folders/gq/vpylvs0d51162jtyqhtgdc6m0000gn/T/pip-tNcbvb-build
/var/folders/gq/vpylvs0d51162jtyqhtgdc6m0000gn/T/pip-6a8MKS-build/setup.py
这些信息对我来说一点用都没有。
我知道setuptools
/setup.py
不应该这样使用,但我真的需要在可安装的包里打包一些文件,并在安装时把它们复制或移动到项目根目录。
有没有什么建议可以实现这个目标呢?
谢谢!:)
2 个回答
使用 pkg_resources
这个包是和 setuptools 一起安装的。
来自包的文档说明:
Docstring:
Package resource API
--------------------
A resource is a logical file contained within a package, or a logical
subdirectory thereof. The package resource API expects resource names
to have their path parts separated with ``/``, *not* whatever the local
path separator is. Do not use os.path operations to manipulate resource
names being passed into the API.
The package resource API is designed to work with normal filesystem packages,
.egg files, and unpacked .egg files. It can also work in a limited way with
.zip files and with custom PEP 302 loaders that support the ``get_data()``
method.
如果你在安装你的包时设置了 zip_safe = False
,那么你的数据会保存在一个目录里。
如果设置为 zip_safe = True
,那么数据会成为一个蛋(egg)的一部分。不过,如果你需要从那里使用文件,操作起来非常简单,pkg_resources
提供了一系列很方便的函数和方法。
- pkg_resources.resource_exists
- pkg_resources.resource_isdir
- pkg_resources.resource_stream - 提供类似文件的对象
- pkg_resources.resource_filename
- pkg_resources.resource_listdir
- pkg_resources.resource_string
注意,这些方法在 zip_safe 为 True 的安装中也能正常工作。
只需将你的数据放在相对于你的包目录的一个目录中。然后在你的代码中:
import pkg_resources
fname = pkg_resources.resource_filename("your.package.name", "folder/example1.txt")
仅用于静态文件
不要试图在这里放置任何会改变的文件。技术上是可以的(如果 zip_safe = False
,文件就在那里),但这绝对是个糟糕的设计(涉及权限、包的更新等问题)。
不要通过 pip
初始化你的项目,最好提供一个 appinit
命令
使用 pip
将数据安装到应用程序目录中是非常不恰当的。
我建议定义一个由我们的程序安装的命令,比如 appinit
,并在需要填充目录时使用它。像 buildout
(由 zc.buildout
安装)这样的命令通常会使用这种模式。
与其费力地让setuptools来帮你启动项目,不如考虑使用像cookiecutter这样的工具,它们专门用来处理各种项目的启动和设置工作。
对于django项目也有现成的模板可以使用(比如可以查看这里)。