python 是一门很棒的编程语言,但打包是它的弱点之一。这是社会上众所周知的事实。多年来,安装、导入、使用和创建包已经有了很大的改进,但它仍然无法与 Go 和 Rust 等从 Python 和其他成熟语言的斗争中学到很多东西的新语言相提并论。
在本教程中,您将了解有关编写、打包和分发自己的包的所有知识。
如何编写 Python 库?
Python 库是 Python 模块的连贯集合,组织为 Python 包。一般来说,这意味着所有模块都位于同一目录下,并且该目录位于 Python 搜索路径中。 让我们快速编写一个小的 Python 3 包并说明所有这些概念。
The Pathology Package
Python 3 有一个出色的 Path 对象,它比 Python 2 笨拙的 os.path 模块有了巨大的改进。但它缺少一项关键功能——查找当前脚本的路径。当您想要定位相对于当前脚本的访问文件时,这一点非常重要。 很多情况下,脚本可以安装在任意位置,所以不能使用绝对路径,工作目录可以设置为任意值,所以不能使用相对路径。如果要访问子目录或父目录中的文件,则必须能够找出当前脚本目录。 以下是您在 Python 中的操作方式:
import pathlib
script_dir = pathlib.Path(__file__).parent.resolve()
要访问当前脚本目录的 'data' 子目录中名为 'file.txt' 的文件,可以使用以下代码:
print(open(str(script_dir/'data/file.txt').read( ))
使用 pathology 包,你有一个内置的 script_dir 方法,你可以像这样使用它:
from pathology.Path import script_dir
print(open(str(script_dir()/'data/file.txt').read())
对,就是一口。Pathology Package非常简单。 它从 pathlib 的 Path 派生出自己的 Path 类,并添加一个静态 script_dir() ,它始终返回调用脚本的路径。 这是实现:
import pathlib
import inspect
class Path(type(pathlib.Path())):
@staticmethod
def script_dir():
print(inspect.stack()[1].filename)
p = pathlib.Path(inspect.stack()[1].filename)
return p.parent.resolve()
由于 pathlib.Path 的跨平台实现,您可以直接从它派生,并且必须从特定的子类(PosixPath 或 WindowsPath)派生。 script_dir 解析使用检查模块查找调用者,然后查找其文件名属性。
测试 Pathology Package
每当您编写的东西不仅仅是一次性脚本时,您都应该对其进行测试。 Pathology模块也不例外。 以下是使用标准单元测试框架的测试:
import os
import shutil
from unittest import TestCase
from pathology.path import Path
class PathTest(TestCase):
def test_script_dir(self):
expected = os.path.abspath(os.path.dirname(__file__))
actual = str(Path.script_dir())
self.assertEqual(expected, actual)
def test_file_access(self):
script_dir = os.path.abspath(os.path.dirname(__file__))
subdir = os.path.join(script_dir, 'test_data')
if Path(subdir).is_dir():
shutil.rmtree(subdir)
os.makedirs(subdir)
file_path = str(Path(subdir)/'file.txt')
content = '123'
open(file_path, 'w').write(content)
test_path = Path.script_dir()/subdir/'file.txt'
actual = open(str(test_path)).read()
self.assertEqual(content, actual)
Python 路径
Python 包必须安装在 Python 搜索路径上的某个位置,才能由 Python 模块导入。 Python 搜索路径是目录列表,并且始终在 sys.path 中可用。 这是我当前的 sys.path:
>>> print('\n'.join(sys.path))
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python36.zip
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/lib-dynload
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages
/Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages/setuptools-27.2.0-py3.6.egg
请注意,输出的第一个空行代表当前目录,因此您可以从当前工作目录导入模块,无论它是什么。 您可以直接在 sys.path 中添加或删除目录。
您还可以定义 PYTHONPATH 环境变量,还有其他一些方法可以控制它。 默认情况下包含标准站点包,这是您通过 pip go 安装包的位置。
如何打包 Python 库
现在我们有了代码和测试,让我们将它们全部打包到一个适当的库中。 Python 通过 setup 模块提供了一种简单的方法。 在包的根目录中创建一个名为 setup.py 的文件。 setup.py 文件包含许多元数据信息,例如作者、许可证、维护者以及有关包的其他信息。 这是对使用从 setuptools 导入的 find_packages() 函数来查找子包的 packages 项的补充。
这是Pathology Package的 setup.py 文件:
from setuptools import setup, find_packages
setup(name='pathology',
version='0.1',
url='https://github.com/the-gigi/pathology',
license='MIT',
author='Gigi Sayfan',
author_email='the.gigi@gmail.com',
description='Add static script_dir() method to Path',
packages=find_packages(exclude=['tests']),
long_description=open('README.md').read(),
zip_safe=False)
源分发包
源分发包是指包含 python 包、模块以及用于包发布的其他文件的存档文件(例如,版本 1、2 等)。 文件分发后,最终用户可以下载并将其安装在他们的操作系统上。 要创建源分发包 (sdist),请运行:
python setup.py sdist
让我们构建一个源代码分发:
$ python setup.py sdist
running sdist
running egg_info
creating pathology.egg-info
writing pathology.egg-info/PKG-INFO
writing dependency_links to pathology.egg-info/dependency_links.txt
writing top-level names to pathology.egg-info/top_level.txt
writing manifest file 'pathology.egg-info/SOURCES.txt'
reading manifest file 'pathology.egg-info/SOURCES.txt'
writing manifest file 'pathology.egg-info/SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt
running check
creating pathology-0.1
creating pathology-0.1/pathology
creating pathology-0.1/pathology.egg-info
copying files to pathology-0.1...
copying setup.py -> pathology-0.1
copying pathology/__init__.py -> pathology-0.1/pathology
copying pathology/path.py -> pathology-0.1/pathology
copying pathology.egg-info/PKG-INFO -> pathology-0.1/pathology.egg-info
copying pathology.egg-info/SOURCES.txt -> pathology-0.1/pathology.egg-info
copying pathology.egg-info/dependency_links.txt -> pathology-0.1/pathology.egg-info
copying pathology.egg-info/not-zip-safe -> pathology-0.1/pathology.egg-info
copying pathology.egg-info/top_level.txt -> pathology-0.1/pathology.egg-info
Writing pathology-0.1/setup.cfg
creating dist
Creating tar archive
removing 'pathology-0.1' (and everything under it)
警告是因为我使用了非标准的 README.md 文件。 忽略它是安全的。 上面的命令将使用当前操作系统的默认格式创建一个存档文件。 对于 Unix 系统,将在 dist 目录下生成一个 gzip 压缩的 tar 文件:
$ ls -la dist
total 8
drwxr-xr-x 3 gigi.sayfan gigi.sayfan 102 Apr 18 21:20 .
drwxr-xr-x 12 gigi.sayfan gigi.sayfan 408 Apr 18 21:20 ..
-rw-r--r-- 1 gigi.sayfan gigi.sayfan 1223 Apr 18 21:20 pathology-0.1.tar.gz
如果您使用的是 Windows,则会生成一个 zip 文件。 您还可以使用格式选项指定其他附加文件格式,如下所示。 |
python setup.py sdist --formats=gztar,zip
例如,上面的命令将生成一个 gzipped tarball 和一个 zip 文件。 可用的不同格式有: |
zip: .zip
gztar: .tar.gz
bztar: .tar.bz2
xztar: .tar.xz
ztar: .tar.Z
tar: .tar
二进制分布
要创建称为轮子的二进制分发,请运行:
python setup.py bdist_wheel
这是一个二进制分布:
$ python setup.py bdist_wheel
running bdist_wheel
running build
running build_py
creating build
creating build/lib
creating build/lib/pathology
copying pathology/__init__.py -> build/lib/pathology
copying pathology/path.py -> build/lib/pathology
installing to build/bdist.macosx-10.7-x86_64/wheel
running install
running install_lib
creating build/bdist.Macosx-10.7-x86_64
creating build/bdist.macosx-10.7-x86_64/wheel
creating build/bdist.macosx-10.7-x86_64/wheel/pathology
copying build/lib/pathology/__init__.py -> build/bdist.macosx-10.7-x86_64/wheel/pathology
copying build/lib/pathology/path.py -> build/bdist.macosx-10.7-x86_64/wheel/pathology
running install_egg_info
running egg_info
writing pathology.egg-info/PKG-INFO
writing dependency_links to pathology.egg-info/dependency_links.txt
writing top-level names to pathology.egg-info/top_level.txt
reading manifest file 'pathology.egg-info/SOURCES.txt'
writing manifest file 'pathology.egg-info/SOURCES.txt'
Copying pathology.egg-info to build/bdist.macosx-10.7-x86_64/wheel/pathology-0.1-py3.6.egg-info
running install_scripts
creating build/bdist.macosx-10.7-x86_64/wheel/pathology-0.1.dist-info/WHEEL
pathology 包仅包含纯 Python 模块,因此可以构建通用包。 如果你的包包含 C 扩展,你必须为每个平台构建一个单独的轮子:
$ ls -la dist
total 16
drwxr-xr-x 4 gigi.sayfan gigi.sayfan 136 Apr 18 21:24 .
drwxr-xr-x 13 gigi.sayfan gigi.sayfan 442 Apr 18 21:24 ..
-rw-r--r-- 1 gigi.sayfan gigi.sayfan 2695 Apr 18 21:24 pathology-0.1-py3-none-any.whl
-rw-r--r-- 1 gigi.sayfan gigi.sayfan 1223 Apr 18 21:20 pathology-0.1.tar.gz
要深入了解打包 Python 库的主题,请查看如何编写自己的 Python 包。
如何分发 Python 包
Python 有一个名为 PyPI(Python 包索引)的中央包存储库。 PyPI 可以轻松管理不同版本的包。例如,如果用户需要安装特定的包版本,pip 知道在哪里寻找它。 当您使用 pip 安装 Python 包时,它将从 PyPI 下载包(除非您指定不同的存储库)。要分发我们的Pathology Package,我们需要将其上传到 PyPI 并提供一些 PyPI 所需的额外元数据。步骤是: 升级您的点子版本。 在 PyPI 上创建一个帐户(只需一次)。 注册您的包裹。 上传您的包裹。
升级你的 pip 版本
确保您的操作系统中安装了最新版本的 pip。要升级 pip,请发出以下命令
python3 -m pip install --upgrade pip
创建一个帐户 您可以在 PyPI 网站上创建一个帐户。然后在你的主目录中创建一个 .pypirc 文件:
[distutils]
index-servers=pypi
[pypi]
repository = https://pypi.python.org/pypi
username = the_gigi
出于测试目的,您可以将 pypitest 索引服务器添加到 .pypirc 文件中:
[distutils]
index-servers=
pypi
pypitest
[pypitest]
repository = https://testpypi.python.org/pypi
username = the_gigi
[pypi]
repository = https://pypi.python.org/pypi
username = the_gigi
注册您的包
如果这是你的包的第一个版本,你需要用 PyPI 注册它。 使用 setup.py 的 register 命令。 它会询问您的密码。 请注意,我将其指向此处的测试存储库:
$ python setup.py register -r pypitest
running register
running egg_info
writing pathology.egg-info/PKG-INFO
writing dependency_links to pathology.egg-info/dependency_links.txt
writing top-level names to pathology.egg-info/top_level.txt
reading manifest file 'pathology.egg-info/SOURCES.txt'
writing manifest file 'pathology.egg-info/SOURCES.txt'
running check
Password:
Registering pathology to https://testpypi.python.org/pypi
Server response (200): OK
上传您的包
现在包已经注册好了,我们可以上传它了。 我建议使用 twine,它更安全。 使用 pip install twine 像往常一样安装它。 然后使用 twine 上传您的包裹并提供您的密码(如下所示):
$ twine upload -r pypitest -p <redacted> dist/*
Uploading distributions to https://testpypi.python.org/pypi
Uploading pathology-0.1-py3-none-any.whl
[================================] 5679/5679 - 00:00:02
Uploading pathology-0.1.tar.gz
[================================] 4185/4185 - 00:00:01
该软件包现已在 Pypi 官方网站上提供,如下所示。
要使用 pip 安装它,只需发出以下命令:
pip install pathology
要更深入地了解分发包的主题,请查看如何共享 Python 包。
结论
在本教程中,我们完成了编写 Python 库、打包并通过 PyPI 分发它的完整过程。 此时,您应该拥有编写库并与世界共享库的所有工具。
- The Pathology Package
- 测试 Pathology Package
- Python 路径
- 源分发包
- 二进制分布
- 升级你的 pip 版本
发表评论