创建具有关联数据的 pip 可安装的单模块包



我发现这个问题有很多变化,但似乎没有一个能解决我的确切情况

  1. 项目的 Python 代码包含在单个文件中
  2. 安装中必须包含必需的数据目录

我正在尝试创建以下 Python 项目的pip可安装版本,其中该项目由单个 Python 脚本myscript,以及两个不同的数据目录datatest_data组成。data包含运行时由myscript.py获取的必需数据文件:

myscript
|
├── myscript
│   ├── data
│   ├── __init__.py
│   ├── myscript.py
│   └── test_data
├── LICENSE
├── README.md
└── setup.py

我已经看到了在setup.py中使用py_modules来解决类似问题的建议,但这似乎不允许在安装时包含数据目录pip,而且我找不到似乎涵盖此特定情况的文档。

我还看到建议让用户只对存储库进行git clone而不是使用pip,但提供一种pip安装所有依赖项的方法似乎是一种可用性优势,同时以依赖于操作系统的方式正确将脚本添加到 PATH。

这看起来像一个非常标准的Python包。为了重现您的情况,我有以下布局:

$ find * -type f
LICENSE
myscript/myscript.py
myscript/data/data_file_1
myscript/test_data/test_data_file_1
myscript/__init__.py
README.md
setup.cfg
setup.py

要包含数据目录,您可以在setup.cfg文件中使用package_data选项(它正在慢慢取代setup.py作为构建 Python 包的标准方法(。

我们只需要一个存根setup.py

from setuptools import setup
setup()

其他一切都在setup.cfg

[metadata]
name = myscript
version = 1.0
description = An example for glarue
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/larsks/so-example-glarue
author = Lars Kellogg-Stedman
author_email = lars@oddbit.com
[options]
packages = find:
[options.package_data]
myscript = data/*, test_data/*
[options.entry_points]
console_scripts =
myscript = myscript.myscript:main

关键部分是options.package_data"部分,对于每个包,它列出了应作为包一部分包含的 glob 模式。

如果我们从这里构建一个源代码发行版:

$ python setup.py sdist
running sdist
...
Creating tar archive
removing 'myscript-1.0' (and everything under it)

我们可以看到数据文件包含在存档中:

$ tar tf dist/myscript-1.0.tar.gz
myscript-1.0/
myscript-1.0/PKG-INFO
myscript-1.0/README.md
myscript-1.0/myscript/
myscript-1.0/myscript/__init__.py
myscript-1.0/myscript/data/
myscript-1.0/myscript/data/data_file_1
myscript-1.0/myscript/myscript.py
myscript-1.0/myscript/test_data/
myscript-1.0/myscript/test_data/test_data_file_1
myscript-1.0/myscript.egg-info/
myscript-1.0/myscript.egg-info/PKG-INFO
myscript-1.0/myscript.egg-info/SOURCES.txt
myscript-1.0/myscript.egg-info/dependency_links.txt
myscript-1.0/myscript.egg-info/entry_points.txt
myscript-1.0/myscript.egg-info/top_level.txt
myscript-1.0/setup.cfg
myscript-1.0/setup.py

如果您使用bdist构建二进制发行版,情况也是如此。

您可以在 https://github.com/larsks/so-example-glarue 在线找到整个示例。

我认为您缺少MANIFEST.in文件

请看以下小项目:

目录结构

./MANIFEST.in
./mini/data/f1.txt
./mini/__init__.py
./mini/mini.py
./mini/test_data/f1.txt
./README.md
./setup.py

setup.py

from setuptools import setup
setup(name="mini",
version="0.0.1",
description="one file pip installable mod",
long_description="long description",
long_description_content_type="text/x-rst",
classifiers=[
"Development Status :: 3 - Alpha",
],
keywords="sample",
url="https://github.com/demo",
author="me",
author_email="me@my.email.com",
license="MIT",
packages=["mini"],
scripts=[],
entry_points={
"console_scripts": [
"mini = mini.mini:main",
]
},
install_requires=[],
extras_require={},
python_requires=">=3.4",
setup_requires=[],
tests_require=[],
zip_safe=False,
include_package_data=True,
)

MANIFEST.in

include README.md
recursive-include mini/data/ *
recursive-include mini/test_data/ *

迷你/迷你.py

#!/usr/bin/env python
import os
MYPATH = os.path.realpath(os.path.dirname(__file__))
DATA_PATH = os.path.join(MYPATH, "data")
TEST_DATA_PATH = os.path.join(MYPATH, "test_data")
def main():
print("I am the miniscript")
with open(os.path.join(DATA_PATH, "f1.txt")) as fin:
print("DATA FILE", fin.read())
with open(os.path.join(TEST_DATA_PATH, "f1.txt")) as fin:
print("TEST DATA FILE", fin.read())
main()

试用:

python -m setup sdist
tar tvfz dist/mini-0.0.1.tar.gz

最新更新