附录 B 打包与分发
本节介绍如何使用标准的distutils模块打包。
distutils模块允许编写简单的Python脚本,该脚本知道如何将Python模块安装到任何Python的安装目录中,包括托管在一个虚拟环境中。按照惯例,这个脚本叫做setup.py,它位于项目结构的顶层。可以执行这个脚本进行实际的安装。
B.1 使用distutils配置一个包
下面是一个distutils的简单例子。将为在第11章缩写的palindrome模块创建一个基本的setup.py安装脚本。
首先,创建一个目录来保存项目。该目录名为palindrome,在这个目录中放一份palindrome.py的副本:
""" palindrome.py - 检测回文数字 """
import unittest
def digits(x):
"""将整数转换为数字列表。
Args:
x:我们想要的数字
Returns:数字列表,按照“x”的顺序排列。
>>> digits(4586378)
[4, 5, 8, 6, 3, 7, 8]
"""
digs = []
while x != 0:
div, mod = divmod(x, 10)
digs.append(mod)
x = div
return digs[::-1]
def is_palindrome(x):
"""确定一个整数是否是回文。
Args:
x:需要进行回文检查的数字。
Returns:如果数字“x”是回文数字就返回True,否则返回False。
>>> is_palindrom(1234)
False
>>> is_palindrom(2468642)
True
"""
digs = digits(x)
for f, r in zip(digs, reversed(digs)):
if f != r:
return False
return True
class Tests(unittest.TestCase):
"""''is_Palindrom()''函数的测试"""
def test_negative(self):
"""检查结果为错误返回False。"""
self.assertFalse(is_palindrome(1234))
def test_positive(self):
"""检查结果为正确返回True。"""
self.assertTrue(is_palindrome(1234321))
def test_single_digit(self):
"""对于一位数字,检查能正常运行。"""
for i in range(10):
self.assertTrue(is_palindrome(i))
if __name__ == '__main__':
unittest.main()
最后创建一个setup.py脚本:
from distutils.core import setup
setup(
name='palindrome',
version='1.0',
py_modules=['palindrome'],
# metadata
author='Austin Bingham',
# author_email =
description='A module for finding palindromic integers.',
license='Public domain',
keywords='palindrome',)
文件第一行从distutils.core模块导入setup()函数。这个函数完成所有的安装代码的工作,我们通过向函数传递参数来告诉它。
我们告诉setup()的第一件事就是这个项目的名字。一般来说,最简单的办法就是保持名称与项目的名称相同。
下一个参数是版本。它可以是任何你想要的字符串,Python不依赖于版本来遵循任何规则。
参数py_modules可能是最令人关注的。用它来指定想要安装的Python模块。此列表中的每个条目都是不带.py扩展名的模块名称。setup()将查找匹配的.py文件并进行安装。
其它的参数是不言自明的,主要是为了帮助你正确地使用模块,并知道如果有问题要联系谁。
在开始使用setup.py之前,首先要创建一个虚拟环境,并将模块安装到该环境中。在palindrome目录中,创建一个qkylpalindrome_env的虚拟环境:
D:\python\写给程序员的Python教程\pyfund\palindrome>python -m venv palindrome
_env
创建完成后,就可以激活这个新的的环境了。在Linux系统或MacOS系统上,寻找这个激活脚本的源:
$ source palindrome_env/Scripts/activate
在Windows系统上直接调用这个脚本:
D:\python\写给程序员的Python教程\pyfund\palindrome>palindrome_env\Scripts\activate
B.2 使用distutils安装
下面将这个模块安装到虚拟环境中。通过将install参数传递给setup.py来完成此操作:
(palindrome_env) D:\python\写给程序员的Python教程\pyfund\palindrome>python setup.py install
running install
D:\python\写给程序员的Python教程\pyfund\palindrome\palindrome_env\Lib\site-packages\setuptools\command\install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
warnings.warn(
D:\python\写给程序员的Python教程\pyfund\palindrome\palindrome_env\Lib\site-packages\setuptools\command\easy_install.py:144: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.
warnings.warn(
running bdist_egg
running egg_info
creating palindrome.egg-info
writing palindrome.egg-info\PKG-INFO
writing dependency_links to palindrome.egg-info\dependency_links.txt
writing top-level names to palindrome.egg-info\top_level.txt
writing manifest file 'palindrome.egg-info\SOURCES.txt'
reading manifest file 'palindrome.egg-info\SOURCES.txt'
writing manifest file 'palindrome.egg-info\SOURCES.txt'
installing library code to build\bdist.win-amd64\egg
running install_lib
running build_py
creating build
creating build\lib
copying palindrome.py -> build\lib
creating build\bdist.win-amd64
creating build\bdist.win-amd64\egg
copying build\lib\palindrome.py -> build\bdist.win-amd64\egg
byte-compiling build\bdist.win-amd64\egg\palindrome.py to palindrome.cpython-311.pyc
creating build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\PKG-INFO -> build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\SOURCES.txt -> build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\dependency_links.txt -> build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\top_level.txt -> build\bdist.win-amd64\egg\EGG-INFO
zip_safe flag not set; analyzing archive contents...
creating dist
creating 'dist\palindrome-1.0-py3.11.egg' and adding 'build\bdist.win-amd64\egg' to it
removing 'build\bdist.win-amd64\egg' (and everything under it)
Processing palindrome-1.0-py3.11.egg
Copying palindrome-1.0-py3.11.egg to d:\python\写给程序员的python教程\pyfund\palindrome\palindrome_env\lib\site-packages
Adding palindrome 1.0 to easy-install.pth file
Installed d:\python\写给程序员的python教程\pyfund\palindrome\palindrome_env\lib\site-packages\palindrome-1.0-py3.11.egg
Processing dependencies for palindrome==1.0
Finished processing dependencies for palindrome==1.0
当调用setup()时,它会输出几行信息来报告进度。对于我们来说最重要的是将palindrome.py复制到安装文件夹中:
creating build
creating build\lib
copying palindrome.py -> build\lib
creating build\bdist.win-amd64
creating build\bdist.win-amd64\egg
copying build\lib\palindrome.py -> build\bdist.win-amd64\egg
byte-compiling build\bdist.win-amd64\egg\palindrome.py to palindrome.cpython-311.pyc
creating build\bdist.win-amd64
creating build\bdist.win-amd64\egg
creating dist
creating 'dist\palindrome-1.0-py3.11.egg' and adding 'build\bdist.win-amd64\egg' to it
Copying palindrome-1.0-py3.11.egg to d:\python\写给程序员的python教程\pyfund\palindrome\palindrome_env\lib\site-packages
第三方软件包,例如模块,通常安装在Python安装目录的site-packages目录中。所以安装工作看起来是正常的。
下面运行Python来验证这一点,并看一下模块如何被导入。请注意,我们希望在执行此操作之前可以更改目录,否则当导入palindrome时,Python将简单地将源文件加载到当前目录中:
(palindrome_env) D:\python\写给程序员的Python教程\pyfund\palindrome>cd d:\
(palindrome_env) d:\>python
Python 3.11.2 (tags/v3.11.2:878ead1, Feb 7 2023, 16:38:35) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import palindrome
>>> palindrome.__file__
'D:\\python\\写给程序员的Python教程\\pyfund\\palindrome\\palindrome_env\\Lib\\site-packages\\palindrome-1.0-py3.11.egg\\palindrome.py'
在这里,使用模块的__file__属性来查看模块从哪里导入,可以看到正在从虚拟环境的sete-packages导入模块。
退出Python REPL之后,不要忘记切换回源代码目录:
(palindrome_env) d:\>cd \python\写给程序员的Python教程\pyfund\palindrome
(palindrome_env) d:\python\写给程序员的Python教程\pyfund\palindrome>
B.3 使用distutils打包
setup()的另一个有用的功能是它可以创建各种类型的“分发”格式。将指定的所有模块,捆绑到易于分发的软件包中。可以使用sdist命令(这是source distribution的缩写)执行此操作:
(palindrome_env) d:\python\写给程序员的Python教程\pyfund\palindrome>python setup.py sdist --format zip
running sdist
running egg_info
writing palindrome.egg-info\PKG-INFO
writing dependency_links to palindrome.egg-info\dependency_links.txt
writing top-level names to palindrome.egg-info\top_level.txt
reading manifest file 'palindrome.egg-info\SOURCES.txt'
writing manifest file 'palindrome.egg-info\SOURCES.txt'
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md
running check
creating palindrome-1.0
creating palindrome-1.0\palindrome.egg-info
copying files to palindrome-1.0...
copying palindrome.py -> palindrome-1.0
copying setup.py -> palindrome-1.0
copying palindrome.egg-info\PKG-INFO -> palindrome-1.0\palindrome.egg-info
copying palindrome.egg-info\SOURCES.txt -> palindrome-1.0\palindrome.egg-info
copying palindrome.egg-info\dependency_links.txt -> palindrome-1.0\palindrome.egg-info
copying palindrome.egg-info\top_level.txt -> palindrome-1.0\palindrome.egg-info
Writing palindrome-1.0\setup.cfg
creating 'dist\palindrome-1.0.zip' and adding 'palindrome-1.0' to it
adding 'palindrome-1.0'
adding 'palindrome-1.0\palindrome.egg-info'
adding 'palindrome-1.0\palindrome.py'
adding 'palindrome-1.0\PKG-INFO'
adding 'palindrome-1.0\setup.cfg'
adding 'palindrome-1.0\setup.py'
adding 'palindrome-1.0\palindrome.egg-info\dependency_links.txt'
adding 'palindrome-1.0\palindrome.egg-info\PKG-INFO'
adding 'palindrome-1.0\palindrome.egg-info\SOURCES.txt'
adding 'palindrome-1.0\palindrome.egg-info\top_level.txt'
removing 'palindrome-1.0' (and everything under it)
在目录dist创建了新生成的分发文件:
(palindrome_env) d:\python\写给程序员的Python教程\pyfund\palindrome>dir dist
驱动器 D 中的卷没有标签。
d:\python\写给程序员的Python教程\pyfund\palindrome\dist 的目录
2023/07/07 10:26 <DIR> .
2023/07/07 10:26 <DIR> ..
2023/07/07 09:17 3,370 palindrome-1.0-py3.11.egg
2023/07/07 10:26 2,779 palindrome-1.0.zip
2 个文件 6,149 字节
这个palindrome-1.0.zip文件中打包了项目的源码以及setup.py脚本。可以把这个zip文件发送给使用人,他们可以使用setup.py将代码安装到他们自己的系统中。
sdist命令可以生成各种类型的分发。使用--help-formats选项可以查看。
(palindrome_env) d:\python\写给程序员的Python教程\pyfund\palindrome>python setup.py sdist --help-formats
List of available source distribution formats:
--formats=bztar bzip2'ed tar-file
--formats=gztar gzip'ed tar-file
--formats=tar uncompressed tar file
--formats=xztar xz'ed tar-file
--formats=zip ZIP file
--formats=ztar compressed tar file
这一节只是涉及distutils的基础知识,可以通过传递--help到setup.py来找到更多有关如何使用distutils的信息:
(palindrome_env) d:\python\写给程序员的Python教程\pyfund\palindrome>python setup.py --help
Common commands: (see '--help-commands' for more)
setup.py build will build the package underneath 'build/'
setup.py install will install the package
Global options:
--verbose (-v) run verbosely (default)
--quiet (-q) run quietly (turns verbosity off)
--dry-run (-n) don't actually do anything
--help (-h) show detailed help message
--no-user-cfg ignore pydistutils.cfg in your home directory
--command-packages list of packages that provide distutils commands
Information display options (just display information, ignore any commands)
--help-commands list all available commands
--name print package name
--version (-V) print package version
--fullname print <package name>-<version>
--author print the author's name
--author-email print the author's email address
--maintainer print the maintainer's name
--maintainer-email print the maintainer's email address
--contact print the maintainer's name if known, else the author's
--contact-email print the maintainer's email address if known, else the
author's
--url print the URL for this package
--license print the license of the package
--licence alias for --license
--description print the package description
--long-description print the long package description
--platforms print the list of platforms
--classifiers print the list of classifiers
--keywords print the list of keywords
--provides print the list of packages/modules provided
--requires print the list of packages/modules required
--obsoletes print the list of packages/modules made obsolete
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
or: setup.py --help [cmd1 cmd2 ...]
or: setup.py --help-commands
or: setup.py cmd --help
对于很多简单的项目,你会发现本节知识已经涵盖了几乎所有你需要知道的。