This repository has been archived by the owner on Dec 10, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathpackaging.html
437 lines (376 loc) · 36.7 KB
/
packaging.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
<!DOCTYPE html>
<meta charset=utf-8>
<title>打包 Python 类库 - Dive Into Python 3</title><!--[if IE]><script src=j/html5.js></script><![endif]-->
<link rel=stylesheet href="dip3.css">
<style>
body{counter-reset:h1 16}
mark{display:inline}
</style>
<link rel=stylesheet media='only screen and (max-device-width: 480px)' href="http://woodpecker.org.cn/diveintopython3/mobile.css">
<link rel=stylesheet media=print href="http://woodpecker.org.cn/diveintopython3/print.css">
<meta name=viewport content='initial-scale=1.0'>
<form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:l5eihuescdw><input type=hidden name=ie value=UTF-8> <input type=search name=q size=25 placeholder="powered by Google™"> <input type=submit name=root value=搜索></div></form>
<p>当前位置: <a href="index.html">首页</a> <span class=u>‣</span> <a href="table-of-contents.html#packaging">深入 Python 3</a> <span class=u>‣</span>
<p id=level>难度级别: <span class=u title=advanced>♦♦♦♦♢</span>
<h1>打包 Python 类库</h1>
<blockquote class=q>
<p><span class=u>❝</span> You’ll find the shame is like the pain; you only feel it once. <span class=u>❞</span><br>— Marquise de Merteuil, <a href=http://www.imdb.com/title/tt0094947/quotes><cite>Dangerous Liaisons</cite></a>
</blockquote>
<p id=toc>
<h2 id=divingin>深入</h2>
<p class=f>读到这里,你可能是想要发布一个 Python 脚本,库,框架,或者应用程序。太棒了!世界需要更多的Python代码。<p>Python 3 自带一个名为 Distutils 的打包框架。Distutils 包含许多功能:构建工具(为你所准备),安装工具(为用户所准备),数据包格式(为搜索引擎所准备)等。它集成了<a href=http://pypi.python.org/> Python 安装包索引</a>(“PyPI”),一个开源 Python 类库的中央资料库。<p>这些 Distutils 的不同功能以<i>setup script</i>为中心,一般被命名为 <code>setup.py</code>。事实上,你已经在本书中见过一些 Distutils 安装脚本。在 <a href="http-web-services.html#introducing-httplib2">《HTTP Web Services》</a> 一章中,我们使用 Distutils 来安装 <code>httplib2</code> ,而在<a href="case-study-porting-chardet-to-python-3.html">《案例研究:将 <code>chardet</code> 移植到 Python 3》</a>一章中,我们用它安装 <code>chardet</code> 。<p>在本章中,你将学习 <code>chardet</code> 和 <code>httplib2</code> 的安装脚本如何工作,并将逐步(学会)发布自己的 Python 软件。<pre class=pp><code># chardet's setup.py
from distutils.core import setup
setup(
name = "chardet",
packages = ["chardet"],
version = "1.0.2",
description = "Universal encoding detector",
author = "Mark Pilgrim",
author_email = "[email protected]",
url = "http://chardet.feedparser.org/",
download_url = "http://chardet.feedparser.org/download/python3-chardet-1.0.1.tgz",
keywords = ["encoding", "i18n", "xml"],
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Development Status :: 4 - Beta",
"Environment :: Other Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)",
"Operating System :: OS Independent",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Text Processing :: Linguistic",
],
long_description = """\
Universal character encoding detector
-------------------------------------
Detects
- ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants)
- Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese)
- EUC-JP, SHIFT_JIS, ISO-2022-JP (Japanese)
- EUC-KR, ISO-2022-KR (Korean)
- KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic)
- ISO-8859-2, windows-1250 (Hungarian)
- ISO-8859-5, windows-1251 (Bulgarian)
- windows-1252 (English)
- ISO-8859-7, windows-1253 (Greek)
- ISO-8859-8, windows-1255 (Visual and Logical Hebrew)
- TIS-620 (Thai)
This version requires Python 3 or later; a Python 2 version is available separately.
"""
)</code></pre>
<blockquote class=note>
<p><span class=u>☞</span><code>chardet</code> 和 <code>httplib2</code> 都是开源的,但这并没有要求你在特定的许可下发布你自己的 Python 库。本章所描述的过程对任何 Python软件都适用,无论它使用什么许可证</blockquote>
<p class=a>⁂
<h2 id=cantdo>Distutils 无法为你完成的工作</h2>
<p>发布第一个 Python 包是一项艰巨的过程。(发布第二个相对容易一些。)Distutils 试图尽可能多的自动完成一些工作,但是仍然有一些事情你必须自己做。<ul>
<li><b>选择一种许可协议 。</b>. 这是一个复杂的话题,充满了派别斗争和危险。如果想将软件发布为开源软件,我冒昧地提出五点忠告:<ol>
<li>不要撰写自己的许可证。</li><li>不要撰写自己的许可证。</li><li>不要撰写自己的许可证。</li><li>许可证并不一定必须是 <abbr>GPL</abbr> ,但它需要与 <abbr>GPL</abbr> 兼容 。</li><li>不要撰写自己的许可证。</li></ol>
</li><li>使用 PyPI 分类系统<b>对软件进行分类</b>。我将在本章后面的部分解释这是什么意思。</li><li><b>写“自述”(read me)文件 。</b>不要在这一点吝惜精力投入。至少,它应该让你的用户了解你的软件可以干什么并知道如何安装它。</li></ul>
<p class=a>⁂
<h2 id=structure>目录结构</h2>
<p>要开始打包 Python 软件,必须先将文件和目录安排好。<code> httplib2</code> 的目录树如下:<pre class=screen>
<a>httplib2/ <span class=u>①</span></a>
|
<a>+--README.txt <span class=u>②</span></a>
|
<a>+--setup.py <span class=u>③</span></a>
|
<a>+--httplib2/ <span class=u>④</span></a>
|
+--__init__.py
|
+--iri2uri.py</pre>
<ol>
<li>创建根目录来保存所有的目录和文件。将其以 Python 模块的名字命名。</li><li>为了适应 Windows 用户,"自述"文件应包含 <code>.txt</code> 扩展名,而且它应该使用 Windows 风格回车符。不能仅仅因为<em>你</em>使用了一个优秀的文本编辑器,它从命令行运行并包括它自己的宏语言,而需要让你的用户为难。(你的用户使用记事本。虽然可悲,但却是事实。)即使你工作在 Linux 或 Mac OS X 环境下,优秀的文本编辑器毫无疑问地会有一个选项,允许将文件以 Windows 风格回车符来保存。</li><li>Distutils 安装脚本应命名为 setup.py,除非你有一个很好的理由不这样做。但你并没有一个很好的理由不这样做。</li><li>如果你的Python软件只包含一个单一的 <code>.py</code> 文件,你应该把它和"自述"文件以及安装脚本放到根目录下。但 <code>httplib2</code> 并不是单一的 <code>.py</code> 文件,它是一个<a href="case-study-porting-chardet-to-python-3.html#multifile-modules">多文件模块</a> 。但是没关系!只需在根目录下放置 <code>httplib2</code> 目录,这样在 <code>httplib2/</code> 根目录下就会有一个包含 <code>__init__.py</code> 文件的 <code>httplib2/</code> 目录。这并不是一个难题,事实上,它可以简化打包过程。</li></ol>
<p><code>chardet</code> 目录看起来有些不同。像 <code>httplib2</code> 一样,它是一个<a href="case-study-porting-chardet-to-python-3.html#multifile-modules">多文件模块</a> ,所以在 <code>chardet/</code> 根目录下有一个 <code>chardet/</code> 目录。除了 <code>README.txt</code> 文件,在 <code>docs/</code> 目录下, <code>chardet</code> 还有 <abbr>HTML</abbr> ——格式化文档。该 <code>docs/</code> 目录包含多个 <code>.html</code> 和<code>.css</code> 文件和 <code>images/</code> 子目录,其中包含几个 <code>.png</code> 和 <code>.gif</code> 文件。(稍后你会发现,这将是很重要的。)此外,对于 <abbr>(L)GPL</abbr> 许可的软件,它包含一个单独的 <code>COPYING.txt</code> 文件,其中包含 <abbr>LGPL</abbr> 许可证的完整内容。<pre class=nd><code>
chardet/
|
+--COPYING.txt
|
+--setup.py
|
+--README.txt
|
+--docs/
| |
| +--index.html
| |
| +--usage.html
| |
| +--images/ ...
|
+--chardet/
|
+--__init__.py
|
+--big5freq.py
|
+--...
</code></pre>
<p class=a>⁂
<h2 id=setuppy>编写安装脚本</h2>
<p>Distutils 安装脚本是一份 Python 脚本。从理论上讲,它可以做任何 Python 可以做的事情。在实践中,安装脚本应该做尽可能少的事情并尽可能按标准的方式做。安装脚本应该简单。安装过程越奇异,错误报告也会更奇特。<p>每个 Distutils 安装脚本的第一行总是相同的:<pre class='nd pp'><code>from distutils.core import setup</code></pre>
<p>该行导入 <code>setup()</code> 函数,这是 Distutils 的主入口点。95% 的 Distutils 安装脚本仅由一个对 <code>setup()</code> 方法的调用组成。(这完全是我臆造的统计,但如果你的 Distutils 安装脚本所做的比仅仅调用 <code>setup()</code> 方法更多,你会有一个好的理由。你有一个好的理由吗?我并不这么认为。)<p><code>setup()</code> 方法<a href=http://docs.python.org/3.1/distutils/apiref.html#distutils.core.setup>可以有几十个参数</a> 。为了使每个参与者都能清楚,你必须对每个参数使用<a href="your-first-python-program.html#optional-arguments">命名变量 </a>。这不只是一项约定,还是一项硬性要求。如果尝试以非命名变量调用 <code>setup()</code> 方法,安装脚本会崩溃。<p>下面的命名变量是必需的:<ul>
<li><b>name</b>,安装包的名称。</li><li><b>version</b>,安装包的版本。</li><li><b>author</b>,您的全名。</li><li><b>author_email</b>,您的邮件地址。</li><li><b>url</b>,项目主页。如果没有一个单独的项目网站,这里可以是安装包的 <a href=http://pypi.python.org/>PyPI</a> 的页面地址。</li></ul>
<p>虽然以下内容不是必须的,但我也建议你把他们包括在你的安装脚本里:<ul>
<li><b>description</b>,在线的项目摘要。</li><li><b>long_description</b>,以 <a href=http://docutils.sourceforge.net/rst.html>reStructuredText format</a> 格式编写的多行字符串。<a href=http://pypi.python.org/>PyPI</a> 将其转换为 <abbr>HTML</abbr> 并在安装包中显示它。</li><li><b>classifiers</b>,下一节中将讲述的特别格式化字符串。</li></ul>
<blockquote class=note>
<p><span class=u>☞</span>安装脚本中用到的元数据具体定义在 <a href=http://www.python.org/dev/peps/pep-0314/><abbr>PEP</abbr> 314</a> 中。</blockquote>
<p>现在让我们看看 <code>chardet</code> 的安装脚本。它包含所有这些要求的和建议的参数,还有一个我没有提到: <code>packages</code> 。<pre class='nd pp'><code>from distutils.core import setup
setup(
name = 'chardet',
<mark>packages = ['chardet']</mark>,
version = '1.0.2',
description = 'Universal encoding detector',
author='Mark Pilgrim',
...
)</code></pre>
<p>在分发过程中,这个 <code>packages</code> 参数凸显出一个不幸的词汇表重叠。我们一直在谈论正在构建的“安装包”(并将潜在地出现在Python包索引中)。但是,这并不是 <code>packages</code> 参数所指代的。它指代的是 <code>chardet</code> 模块是一个<a href="case-study-porting-chardet-to-python-3.html#multifile-modules">多文件模块</a>这一事实 ,有时也被称为...“包”。<code>packages</code> 参数告诉 Distutils 去包含<code>chardet/</code> 目录,它的 <code>__init__.py</code> 文件,以及所有其他构成 <code>chardet</code> 模块的 <code>.py</code> 文件。这还算比较重要;如果你忘记了包含实际的代码,那么所有这些关于文件和元数据的愉快交谈都将是无关紧要的。<p class=a>⁂
<h2 id=trove>将包分类</h2>
<p>Python 包索引(“PyPI”)包含成千上万的 Python 库。正确的分类数据将让人们更容易找到你的包。PyPI 让你<a href='http://pypi.python.org/pypi?:action=browse'>以类别的形式浏览包 </a>。你甚至可以选择多个类别来缩小搜索范围。分类不是你可以忽略的不可见的元数据!<p>你可以通过传递 <code>classifiers</code> 参数给 Distutils 的 <code>setup()</code> 方法来给你的软件分类。<code>classifers</code> 参数是一个字符串列表。这些字符串<em>不是</em>任意形式的。所有的分类字符串应该来自 <a href='http://pypi.python.org/pypi?:action=list_classifiers'>PyPI 上的列表</a> 。<p>分类是可选的。你可以写一个不包含任何分类的 Distutils 安装脚本。<strong>不要这样做。</strong> 你应该<em>总是</em>至少包括以下分类:<ul>
<li><b0编程语言</b>. 特别的,你应该包括<code>"Programming Language :: Python"</code>和"<code>Programming Language :: Python :: 3</code>"。如果你不包括这些,你的包将不会出现在<a href='http://pypi.python.org/pypi?:action=browse&c=533&show=all'>兼容Python 3的库</a>列表中,它链接自每个<code>pypi.python.org</code>单页的侧边拦。</li><li><b>许可证</b>. 当我评价一个第三方库的时候,这<em>绝对是我寻找的第一个</em>东西。不要让我(花太多时间)寻找这个重要的信息。不要包含一个以上的许可证分类,除非你的软件明确地在多许可证下分发。(不要在多许可证下发布你的软件,除非你不得不这样做。不要强迫别人这样做。许可证已经足够让人头痛了,不要使情况变得更糟。)</li><li><b>操作系统0</b>. 如果你的软件只能运行于Windows(或Mac OS X或Linux),我想要尽早知道。如果你的软件不包含任何特定平台的代码并可以在任何平台运行,请使用分类 <code>"Operating System :: OS Independent"</code>。<code>多操作系统</code> 分类仅在你的软件在不同平台需要特别支持时使用。(这并不常见。)</li></ul>
<p>我还建议你包括以下分类:<ul>
<li><b>开发状态</b>. 你的软件品质适合beta发布么?适合Alpha发布么?还是Pre-alpha?在这里面选择一个吧。要诚实点。</li><li><b>目标用户</b>. 谁会下载你的软件?最常见的选项包括: <code>Developers</code>、 <code>End Users/Desktop</code>、 <code>Science/Research</code> 和 <code>System Administrators</code>。</li><li><b>框架</b>. 如果你的软件是像 <a href=http://www.djangoproject.com/>Django</a> 或 <a href=http://www.zope.org/>Zope</a> 这样较大的框架的插件,请包含适当的 <code>Framework</code> 分类。如果不是,请忽略它。</li><li><b>主题</b>. 有 <a href='http://pypi.python.org/pypi?:action=list_classifiers'>大量的主题</a> 可供选择 ,选择所有的适用项。</li></ul>
<h3 id=trove-examples>包分类的优秀范例</h3>
<p>作为例子,下面是 <a href=http://pypi.python.org/pypi/Django/>Django</a> 的分类。它是一个运行在 Web 服务器上的,可用于生产环境的,跨平台的,使用 <abbr>BSD</abbr> 授权的 Web 应用程序框架。(Django还没有与Python 3兼容,因此, 并没有列出 <code>Programming Language :: Python :: 3</code> 分类。)<pre><code>Programming Language :: Python
License :: OSI Approved :: BSD License
Operating System :: OS Independent
Development Status :: 5 - Production/Stable
Environment :: Web Environment
Framework :: Django
Intended Audience :: Developers
Topic :: Internet :: WWW/HTTP
Topic :: Internet :: WWW/HTTP :: Dynamic Content
Topic :: Internet :: WWW/HTTP :: WSGI
Topic :: Software Development :: Libraries :: Python Modules</code></pre>
<p>下面是 <a href=http://pypi.python.org/pypi/chardet><code>chardet</code></a> 的分类。它就是在<a href="case-study-porting-chardet-to-python-3.html">《案例研究:将 <code>chardet</code> 移植到 Python 3</a>》一章提到的字符编码检测库。<code>chardet</code> 是高质量的,跨平台的,与 Python 3 兼容的, <abbr>LGPL</abbr> 许可的库。它旨在让开发者将其集成进自己的产品。<pre><code>Programming Language :: Python
Programming Language :: Python :: 3
License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
Operating System :: OS Independent
Development Status :: 4 - Beta
Environment :: Other Environment
Intended Audience :: Developers
Topic :: Text Processing :: Linguistic
Topic :: Software Development :: Libraries :: Python Modules</code></pre>
<p>以下是在本章开头我提到的 <a href=http://pypi.python.org/pypi/httplib2><code>httplib2</code></a> 模块——<abbr>HTTP</abbr> 的分类。<code>httplib2</code> 是一个测试品质的,跨平台的,<abbr>MIT</abbr> 许可证授权的,为 Python 开发者准备的模块。<pre><code>Programming Language :: Python
Programming Language :: Python :: 3
License :: OSI Approved :: MIT License
Operating System :: OS Independent
Development Status :: 4 - Beta
Environment :: Web Environment
Intended Audience :: Developers
Topic :: Internet :: WWW/HTTP
Topic :: Software Development :: Libraries :: Python Modules</code></pre>
<h2 id=manifest>通过清单指定附加文件</h2>
<p>默认情况下,Distutils 将把下列文件包含在你的发布包中:<ul>
<li><code>README.txt</code>
</li><li><code>setup.py</code>
</li><li>由列在 <code>packages</code> 参数中的多模块文件所需的 <code>.py</code> 文件</li><li>在 <code>py_modules</code> 参数中列出的单独 <code>.py</code> 文件</li></ul>
<p>这将覆盖<a href="packaging.html#structure"><code>httplib2</code> 项目的所有文件</a>。但对于 <code>chardet</code> 项目,我们还希望包含 <code>COPYING.txt</code> 许可文件和含有图像与 <abbr>HTML</abbr> 文件的整个 <code>docs/</code> 目录。要让 Distutils 在构建 <code>chardet</code> 发布包时包含这些额外的文件和目录,你需要创建一个 <i>manifest file</i> 。<p>清单文件是一个名为 <code>MANIFEST.in</code> 的文本文件。将它放置在项目的根目录下,同 <code>README.txt</code> 和 <code>setup.py</code> 一起。清单文件并<em>不是</em> Python 脚本,它是文本文件,其中包含一系列 Distutils 定义格式的命令。清单命令允许你包含或排除特定的文件和目录。<p>以下是 <code>chardet</code> 项目的全部清单文件:<pre class=nd><code><a>include COPYING.txt <span class=u>①</span></a>
<a>recursive-include docs *.html *.css *.png *.gif <span class=u>②</span></a></code></pre>
<ol>
<li>第一行是不言自明的:包含项目根目录的 <code>COPYING.txt</code> 文件。</li><li>第二行有些复杂。<code>recursive-include</code> 命令需要一个目录名和至少一个文件名。文件名并不限于特定的文件,可以包含通配符。这行的意思是“看到在项目根目录下的 <code>docs/</code> 目录了吗?在该目录下(递归地)查找 <code>.html</code>、 <code>.css</code>、 <code>.png</code> 和 <code>.gif</code> 文件。我希望将他们都包含在我的发布包中。”</li></ol>
<p>所有的清单命令都将保持你在项目目录中所设置的目录结构。<code>recursive-include</code> 命令不会将一组 <code>.html</code> 和 <code>.png</code> 文件放置在你的发布包的根目录下。它将保持现有的 <code>docs/</code> 目录结构,但只包含该目录内匹配给定的通配符的文件。(之前我并没有提到, <code>chardet</code> 的文档实际上由 <abbr>XML</abbr> 语言写成,并由一个单独的脚本转换为 <abbr>HTML</abbr> 。我不想在发布包中包含<abbr>XML</abbr> 文件,只包含 <abbr>HTML</abbr> 文件和图像。)<blockquote class=note>
<p><span class=u>☞</span>清单文件有自己独特的格式。详见 <a href=http://docs.python.org/3.1/distutils/sourcedist.html#manifest>分发指定文件 </a>和<a href=http://docs.python.org/3.1/distutils/commandref.html#sdist-cmd>清单文件命令</a>。</blockquote>
<p>重申:仅仅在你需要包含一些 Distutils 不会默认包含的文件时才创建清单文件。I如果你确实需要一个清单文件,它应该只包含那些Distutils不会自动包含的文件和目录。<h2 id=check>检查安装脚本的错误</h2>
<p>有许多事情需要留意。Distutils带有一个内置的验证命令,它检查是否所有必须的元数据都体现在你的安装脚本中。例如,如果你忘记包含 <code>version</code> 参数,Distutils 会提醒你。<pre class=screen>
<samp class=p>c:\Users\pilgrim\chardet> </samp><kbd>c:\python31\python.exe setup.py check</kbd>
<samp>running check
warning: check: missing required meta-data: version</samp></pre>
<p>当你包含了 <code>version</code> 参数(和所有其他所需的元数据)时, <code>check</code> 命令将如下所示:<pre class=screen>
<samp class=p>c:\Users\pilgrim\chardet> </samp><kbd>c:\python31\python.exe setup.py check</kbd>
<samp>running check</samp></pre>
<p class=a>⁂
<h2 id=sdist>创建发布源</h2>
<p>Distutils 支持构建多种类型的发布包。至少,你应该建立一个“源代码分发”,其中包含源代码,你的Distutils 安装脚本,“read me ”文件和<a href="packaging.html#manifest">你想要包含其他文件</a> 。为了建立一个源代码分发,传递 <code>sdist</code> 命令给你的 Distutils 安装脚本。<pre class=screen>
<samp class=p>c:\Users\pilgrim\chardet> </samp><kbd><mark>c:\python31\python.exe setup.py sdist</mark></kbd>
<samp>running sdist
running check
reading manifest template 'MANIFEST.in'
writing manifest file 'MANIFEST'
creating chardet-1.0.2
creating chardet-1.0.2\chardet
creating chardet-1.0.2\docs
creating chardet-1.0.2\docs\images
copying files to chardet-1.0.2...
copying COPYING -> chardet-1.0.2
copying README.txt -> chardet-1.0.2
copying setup.py -> chardet-1.0.2
copying chardet\__init__.py -> chardet-1.0.2\chardet
copying chardet\big5freq.py -> chardet-1.0.2\chardet
...
copying chardet\universaldetector.py -> chardet-1.0.2\chardet
copying chardet\utf8prober.py -> chardet-1.0.2\chardet
copying docs\faq.html -> chardet-1.0.2\docs
copying docs\history.html -> chardet-1.0.2\docs
copying docs\how-it-works.html -> chardet-1.0.2\docs
copying docs\index.html -> chardet-1.0.2\docs
copying docs\license.html -> chardet-1.0.2\docs
copying docs\supported-encodings.html -> chardet-1.0.2\docs
copying docs\usage.html -> chardet-1.0.2\docs
copying docs\images\caution.png -> chardet-1.0.2\docs\images
copying docs\images\important.png -> chardet-1.0.2\docs\images
copying docs\images\note.png -> chardet-1.0.2\docs\images
copying docs\images\permalink.gif -> chardet-1.0.2\docs\images
copying docs\images\tip.png -> chardet-1.0.2\docs\images
copying docs\images\warning.png -> chardet-1.0.2\docs\images
creating dist
creating 'dist\chardet-1.0.2.zip' and adding 'chardet-1.0.2' to it
adding 'chardet-1.0.2\COPYING'
adding 'chardet-1.0.2\PKG-INFO'
adding 'chardet-1.0.2\README.txt'
adding 'chardet-1.0.2\setup.py'
adding 'chardet-1.0.2\chardet\big5freq.py'
adding 'chardet-1.0.2\chardet\big5prober.py'
...
adding 'chardet-1.0.2\chardet\universaldetector.py'
adding 'chardet-1.0.2\chardet\utf8prober.py'
adding 'chardet-1.0.2\chardet\__init__.py'
adding 'chardet-1.0.2\docs\faq.html'
adding 'chardet-1.0.2\docs\history.html'
adding 'chardet-1.0.2\docs\how-it-works.html'
adding 'chardet-1.0.2\docs\index.html'
adding 'chardet-1.0.2\docs\license.html'
adding 'chardet-1.0.2\docs\supported-encodings.html'
adding 'chardet-1.0.2\docs\usage.html'
adding 'chardet-1.0.2\docs\images\caution.png'
adding 'chardet-1.0.2\docs\images\important.png'
adding 'chardet-1.0.2\docs\images\note.png'
adding 'chardet-1.0.2\docs\images\permalink.gif'
adding 'chardet-1.0.2\docs\images\tip.png'
adding 'chardet-1.0.2\docs\images\warning.png'
removing 'chardet-1.0.2' (and everything under it)</samp></pre>
<p>有几件事情需要注意:<ul>
<li>Distutils发现了清单文件( <code>MANIFEST.in</code> )</li><li>Distutils 成功地解析了清单文件,并添加了我们所需要的文件—— <code>COPYING.txt</code> 和在 <code>docs/</code> 目录下的 <abbr>HTML</abbr> 与图像文件。</li><li>如果你进入你的项目目录,你会看到 Distutils 创建了一个 <code>dist/</code> 目录。你可以分发在 <code>dist/</code> 目录中的 <code>.zip</code> 文件。</li></ul>
<pre class=screen>
<samp class=p>c:\Users\pilgrim\chardet> </samp><kbd><mark>dir dist</mark></kbd>
<samp> Volume in drive C has no label.
Volume Serial Number is DED5-B4F8
Directory of c:\Users\pilgrim\chardet\dist
07/30/2009 06:29 PM <DIR> .
07/30/2009 06:29 PM <DIR> ..
07/30/2009 06:29 PM 206,440 <mark>chardet-1.0.2.zip</mark>
1 File(s) 206,440 bytes
2 Dir(s) 61,424,635,904 bytes free</samp></pre>
<p class=a>⁂
<h2 id=bdist>创建图形化安装程序</h2>
<p>在我看来,每一个 Python 库都应该为 Windows 用户提供图形安装程序。这很容易做(即使你并没有运行 Windows ),而且 Windows 用户会对此表示感激。<p>通过传递 <code>bdist_wininst</code> 命令到你的 Distutils 安装脚本,它可以<a href=http://docs.python.org/3.1/distutils/builtdist.html#creating-windows-installers>为你创建一个图形化的 Windows 安装程序</a> 。<pre class=screen>
<samp class=p>c:\Users\pilgrim\chardet> </samp><kbd><mark>c:\python31\python.exe setup.py bdist_wininst</mark></kbd>
<samp>running bdist_wininst
running build
running build_py
creating build
creating build\lib
creating build\lib\chardet
copying chardet\big5freq.py -> build\lib\chardet
copying chardet\big5prober.py -> build\lib\chardet
...
copying chardet\universaldetector.py -> build\lib\chardet
copying chardet\utf8prober.py -> build\lib\chardet
copying chardet\__init__.py -> build\lib\chardet
installing to build\bdist.win32\wininst
running install_lib
creating build\bdist.win32
creating build\bdist.win32\wininst
creating build\bdist.win32\wininst\PURELIB
creating build\bdist.win32\wininst\PURELIB\chardet
copying build\lib\chardet\big5freq.py -> build\bdist.win32\wininst\PURELIB\chardet
copying build\lib\chardet\big5prober.py -> build\bdist.win32\wininst\PURELIB\chardet
...
copying build\lib\chardet\universaldetector.py -> build\bdist.win32\wininst\PURELIB\chardet
copying build\lib\chardet\utf8prober.py -> build\bdist.win32\wininst\PURELIB\chardet
copying build\lib\chardet\__init__.py -> build\bdist.win32\wininst\PURELIB\chardet
running install_egg_info
Writing build\bdist.win32\wininst\PURELIB\chardet-1.0.2-py3.1.egg-info
creating 'c:\users\pilgrim\appdata\local\temp\tmp2f4h7e.zip' and adding '.' to it
adding 'PURELIB\chardet-1.0.2-py3.1.egg-info'
adding 'PURELIB\chardet\big5freq.py'
adding 'PURELIB\chardet\big5prober.py'
...
adding 'PURELIB\chardet\universaldetector.py'
adding 'PURELIB\chardet\utf8prober.py'
adding 'PURELIB\chardet\__init__.py'
removing 'build\bdist.win32\wininst' (and everything under it)</samp>
<samp class=p>c:\Users\pilgrim\chardet> </samp><kbd><mark>dir dist</mark></kbd>
<samp>c:\Users\pilgrim\chardet>dir dist
Volume in drive C has no label.
Volume Serial Number is AADE-E29F
Directory of c:\Users\pilgrim\chardet\dist
07/30/2009 10:14 PM <DIR> .
07/30/2009 10:14 PM <DIR> ..
07/30/2009 10:14 PM 371,236 <mark>chardet-1.0.2.win32.exe</mark>
07/30/2009 06:29 PM 206,440 chardet-1.0.2.zip
2 File(s) 577,676 bytes
2 Dir(s) 61,424,070,656 bytes free</samp></pre>
<h3 id=linux>为其它操作系统编译安装包</h3>
<p>Distutils 可以帮助你<a href=http://docs.python.org/3.1/distutils/builtdist.html#creating-rpm-packages>为 Linux 用户构建可安装包</a> 。我认为,这可能不值得你浪费时间。如果你希望在 Linux 中分发你的软件,你最好将时间花在与那些社区成员进行交流上,他们专门为主流 Linux 发行版打包软件。<p>例如,我的 <code>chardet</code> 库包含在 Debian GNU/Linux 软件仓库中(因而也包含<a href=http://packages.ubuntu.com/python-chardet>在 Ubuntu 的软件仓库</a>中)。我不曾做任何事情,我只在那里将安装包展示了一天。Debian 社区拥有<a href=http://www.debian.org/doc/packaging-manuals/python-policy/>他们自己的关于打包 Python 库的政策</a>,并且Debian 的 <code>python-chardet</code> 包被设计为遵循这些公约。由于这个包存在在 Debian 的软件仓库中,依赖于 Debian 用户所选择的管理自己计算机的系统设置,他们会收到该包的安全更新和(或)新版本。<p>Distutils构建的包不具有Linux包所提供的任何优势。你的时间最好花在其他地方。<p class=a>⁂
<h2 id=pypi>将软件添加到 Python 安装包列表</h2>
<p>上传软件到 Python 包索引需要三个步骤。<ol>
<li>注册你自己</li><li>注册你的软件</li><li>上传你通过 <code>setup.py sdist</code> 和 <code>setup.py bdist_*</code> 创建的包。
</li></ol>
<p>要注册自己,访问 <a href="http://pypi.python.org/pypi?:action=register_form">PyPI用户注册页面</a>。输入你想要的用户名和密码,提供一个有效的电子邮件地址,然后点击 <code>Register</code> 按钮。(如果你有一个 <abbr>PGP</abbr> 或 <abbr>GPG</abbr> 密钥,你也可以提供。如果你没有或者不知道这是什么意思,不用担心。)检查你的电子邮件,在几分钟之内,你应该会收到一封来自 PyPI 的包含验证链接的邮件。点击链接以完成注册过程。<p>现在,你需要在PyPI注册你的软件并上传它。你可以用一步完成。<pre class=screen>
<a><samp class=p>c:\Users\pilgrim\chardet> </samp><kbd>c:\python31\python.exe setup.py register sdist bdist_wininst upload</kbd> <span class=u>①</span></a>
<samp>running register
We need to know who you are, so please choose either:
1. use your existing login,
2. register as a new user,
3. have the server generate a new password for you (and email it to you), or
4. quit</samp>
<a><samp class=p>Your selection [default 1]: </samp><kbd>1</kbd> <span class=u>②</span></a>
<a><samp class=p>Username: </samp><kbd>MarkPilgrim</kbd> <span class=u>③</span></a>
<samp class=p>Password:</samp>
<a><samp>Registering chardet to http://pypi.python.org/pypi</samp> <span class=u>④</span></a>
<samp>Server response (200): OK</samp>
<a><samp>running sdist</samp> <span class=u>⑤</span></a>
<samp>... output trimmed for brevity ...</samp>
<a><samp>running bdist_wininst</samp> <span class=u>⑥</span></a>
<samp>... output trimmed for brevity ...</samp>
<a><samp>running upload</samp> <span class=u>⑦</span></a>
<samp>Submitting dist\chardet-1.0.2.zip to http://pypi.python.org/pypi
Server response (200): OK
Submitting dist\chardet-1.0.2.win32.exe to http://pypi.python.org/pypi
Server response (200): OK
I can store your PyPI login so future submissions will be faster.
(the login will be stored in c:\home\.pypirc)</samp>
<a><samp class=p>Save your login (y/N)?</samp><kbd class=pp>n</kbd> <span class=u>⑧</span></a></pre>
<ol>
<li>当你第一次发布你的项目时,Distutils 会将你的软件加入到Python包索引中并给出它的 <abbr>URL</abbr>。在这之后,它只会用你在 <code>setup.py</code> 参数所做的任何改变来更新项目的元数据。之后,它构建一个源代码发布 (<code>sdist</code>) 和一个 Windows 安装程序 (<code>bdist_wininst</code>) 并把他们上传到PyPI (<code>upload</code>)。</li><li>键入 <kbd>1</kbd> 或 <kbd>ENTER</kbd> 选择“ 使用已有的账户登录【use your existing login.】”。</li><li>输入你在<a href="http://pypi.python.org/pypi?:action=register_form"> PyPI 用户注册页面</a>所选择的用户名和密码。Distuils不会回显你的密码,它甚至不会在相应的位置显示星号。只需输入你的密码,然后按 <kbd>回车键</kbd> 。</li><li>Distutils 在 Python 包索引注册你的包……</li><li>……构建源代码分发……</li><li>……构建Windows安装程序……</li><li>……并把它们上传至 Python 包索引。</li><li>如果你想自动完成发布新版本的过程,你需要将你的PyPI凭据保存在一个本地文件中。这完全是不安全的而且是完全可选的。</li></ol>
<p>恭喜你,现在,在Python包索引中有你自己的页面了!地址是 <code>http://pypi.python.org/pypi/<i>NAME</i></code>,其中 <i>NAME</i> 是你在 <code>setup.py</code> 文件中 <var>name</var> 参数所传递的字符串。<p>如果你想发布一个新版本,只需以新的版本号更新 <code>setup.py</code> 文件,然后再一次运行相同的上传命令:<pre class='nd screen'>
<samp class=p>c:\Users\pilgrim\chardet> </samp><kbd>c:\python31\python.exe setup.py register sdist bdist_wininst upload</kbd>
</pre>
<p class=a>⁂
<h2 id=future>Python 打包工具的一些可能的将来</h2>
<p>Distutils并非是一个代替所有并终结所有的 Python 打包,但在写本书时(2009年8月),它是唯一可以工作在 Python 3 下的打包框架。对于Python 2,还有许多其他的框架,有的重在安装,有的重在测试,还有的重在部署。在未来,它们中的一部分或全体都将移植到Python 3。<p>以下框架重在安装:<ul>
<li><a href=http://pypi.python.org/pypi/setuptools>Setuptools</a>
</li><li><a href=http://pypi.python.org/pypi/pip>Pip</a>
</li><li><a href=http://bitbucket.org/tarek/distribute/>Distribute</a>
</li></ul>
<p>以下框架重在测试和部署:<ul>
<li><a href=http://pypi.python.org/pypi/virtualenv><code>virtualenv</code></a>
</li><li><a href=http://pypi.python.org/pypi/zc.buildout><code>zc.buildout</code></a>
</li><li><a href=http://www.blueskyonmars.com/projects/paver/>Paver</a>
</li><li><a href=http://fabfile.org/>Fabric</a>
</li><li><a href=http://www.py2exe.org/><code>py2exe</code></a>
</li></ul>
<p class=a>⁂
<h2 id=furtherreading>深入阅读</h2>
<p>关于 Distutils:<ul>
<li><a href=http://docs.python.org/3.1/distutils/>通过 Distutils 发布 Python 模块</a>
</li><li><a href=http://docs.python.org/3.1/distutils/apiref.html#module-distutils.core>核心发布功能</a> 列出了 <code>setup()</code> 函数的所有可能参数</li><li><a href=http://wiki.python.org/moin/Distutils/Cookbook>Distutils 食谱</a>
</li><li><a href=http://www.python.org/dev/peps/pep-0370/><abbr>PEP</abbr> 370: 每用户 <code>site-packages</code> 目录</a>
</li><li><a href=http://jessenoller.com/2009/07/19/pep-370-per-user-site-packages-and-environment-stew/><abbr>PEP</abbr> 370 和 “environment stew”</a>
</li></ul>
<p>其它打包框架:<ul>
<li><a href=http://groups.google.com/group/django-developers/msg/5407cdb400157259>Python 打包生态系统</a>
</li><li><a href=http://www.b-list.org/weblog/2008/dec/14/packaging/>关于打包</a>
</li><li><a href=http://blog.ianbicking.org/2008/12/14/a-few-corrections-to-on-packaging/>对 “关于打包” 的几点纠错</a>
</li><li><a href=http://www.b-list.org/weblog/2008/dec/15/pip/>我为什么喜欢 Pip</a>
</li><li><a href=http://cournape.wordpress.com/2009/04/01/python-packaging-a-few-observations-cabal-for-a-solution/>Python 打包:几点看法</a>
</li><li><a href=http://jacobian.org/writing/nobody-expects-python-packaging/>没有人期望 Python 打包!</a>
</li></ul>
<p class=v><a rel=prev href="case-study-porting-chardet-to-python-3.html" title="back to “Case Study: Porting chardet to Python 3”"><span class=u>☜</span></a> <a rel=next href="porting-code-to-python-3-with-2to3.html" title="onward to “Porting Code to Python 3 with 2to3”"><span class=u>☞</span></a>
<p class=c>© 2001–9 <a href="about.html">Mark Pilgrim</a>
<script src="j/jquery.js"></script>
<script src="j/prettify.js"></script>
<script src="j/dip3.js"></script>