/
create-python-packages.html
446 lines (405 loc) · 30.6 KB
/
create-python-packages.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
438
439
440
441
442
443
444
445
446
<!DOCTYPE html>
<html lang="en">
<!-- head -->
<head>
<meta charset="utf-8" />
<meta name="author" content="Kirill Klenov" />
<meta name="keywords" content="python,setuptools,distutils,distribute," />
<meta name="description" content="Создание python-пакетов (aka setup scripts)" />
<meta name="application-name" content="klen.github.io" />
<meta name="application-url" content="." />
<meta name="og:image" content="http://klen.github.io/theme/images/logo.png" />
<meta name="og:title" content="Создание python-пакетов (aka setup scripts)" />
<title>Создание python-пакетов (aka setup scripts) — klen.github.io</title>
<link href="/theme/build_main.css" rel="stylesheet" type="text/css" media="screen" />
<link rel="alternate" type="application/atom+xml" title="klen.github.io - all posts" href="http://feeds.feedburner.com/klengihubcom">
<link rel="openid.server" href="http://www.myopenid.com/server">
<link rel="openid.delegate" href="http://horneds.myopenid.com/">
<link rel="openid2.local_id" href="http://horneds.myopenid.com/">
<link rel="openid2.provider" href="http://www.myopenid.com/server">
<meta http-equiv="X-XRDS-Location" content="http://www.myopenid.com/xrds?username=horneds.myopenid.com"> </head>
<body class="cloud zeta">
<h1 class="header">
<a class="header_title" href=.><i class="fa fa-beer"></i>klen.github.io</a>
</h1>
<nav class="menu"> <a class="menu_item menu_link" href="./pages/about-en.html">About me</a> <a class="menu_item menu_link" href="./category/blog.html">Blog</a> <a class="menu_item menu_link" href="./category/notes.html">Notes</a> </nav>
<div class="content">
<article class="article">
<header class="article_header">
<time class="article_header_time" datetime="2012-06-13 00:00:00">13.06.2012</time>
<span>in <a href="./category/Blog.html">Blog</a></span>
<h1 class="article_header_title">Создание python-пакетов (aka setup scripts)</h1><span class="article_meta">tags: <span><a href="./tag/python.html">python</a> , </span> <span><a href="./tag/setuptools.html">setuptools</a> , </span> <span><a href="./tag/distutils.html">distutils</a> , </span> <span><a href="./tag/distribute.html">distribute</a> </span> </span></header>
<div class="article_paginator zeta"> <div class="article_paginator_right">
<a href="some-flask-things.html" class="article_paginator_right_link">Неделя с Flask</a> Ctrl→
</div> <div class="article_paginator_left">
←Ctrl <a href="android-push-python.html" class="article_paginator_left_link">Серверная реализация Android C2DM Push уведомлений (python)</a>
</div></div>
<div class="article_content">
<hr class="docutils" />
<div class="contents topic" id="id1">
<p class="topic-title first">Содержание:</p>
<ul class="simple">
<li><a class="reference internal" href="#id2" id="id8">Создаем структуру проекта</a></li>
<li><a class="reference internal" href="#setup-py" id="id9">Редактируем мета-информацию (setup.py)</a></li>
<li><a class="reference internal" href="#id3" id="id10">Виртуальное окружение</a></li>
<li><a class="reference internal" href="#id4" id="id11">Создание команд</a></li>
<li><a class="reference internal" href="#id5" id="id12">Работа с версиями</a></li>
<li><a class="reference internal" href="#id6" id="id13">Управление зависимостями</a></li>
<li><a class="reference internal" href="#manifest-in" id="id14">Управление файлами проекта (MANIFEST.in)</a></li>
<li><a class="reference internal" href="#id7" id="id15">Создание и запуск тестов</a></li>
<li><a class="reference internal" href="#pypi-python-org" id="id16">Публикация пакета на pypi.python.org</a></li>
</ul>
</div>
<hr class="docutils" />
<p>Одна из действительно полезных вещей в python — это система скриптов установки. Любой, серьезно
увлекающийся python-программированием разработчик рано или поздно сталкивается с ней.
Но из-за гибкости инструментария скриптов установки, их документация весьма раздута.
На текущий момент имеется набор утилит (<a class="reference external" href="http://pypi.python.org/pypi/setuptools">setuptools</a>, <a class="reference external" href="http://docs.python.org/distutils/">distutils</a>, <a class="reference external" href="http://pypi.python.org/pypi/distribute">distribute</a>) выполняющих
одинаковые задачи.</p>
<img alt="" src="/static/img/state_of_packaging.jpg" />
<p>В данной статье я на конкретных примерах покажу как создать и настроить простой python-пакет.</p>
<p>Наш проект будет иметь следующую функциональность:</p>
<ul class="simple">
<li>Метод возвращающий строку: "Hello World!";</li>
<li>Команда <cite>helloworld</cite> печатающая эту строку в стандартный вывод.</li>
</ul>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">Исходные коды для данной статьи можно увидеть по адресу: <a class="reference external" href="https://github.com/klen/klen.github.com/tree/master/_code/helloworld-project">https://github.com/klen/klen.github.com/tree/master/_code/helloworld-project</a></p>
</div>
<div class="section" id="id2">
<h2><a class="toc-backref" href="#id8">Создаем структуру проекта</a></h2>
<p>Для начала создадим директорию для пакета. Ее минимальный
набор файлов состоит из: файла дистрибьюции (<cite>setup.py</cite>) описывающего
метаданные и python кода проекта (в нашем случае модуля <tt class="docutils literal">helloworld</tt>).</p>
<p>Также, xорошим тоном считается создание в корне директории файла с описанием проекта: <cite>README.txt</cite>.</p>
<p>Получаем следующую структуру:</p>
<pre class="literal-block">
helloworld-project
├── helloworld
│ ├── __init__.py
│ └── core.py
├── setup.py
└── README.txt
</pre>
<p>Наша корневая директория <cite>helloworld-project</cite> будет содержать мета-данные пакета и вспомогательные файлы
(тесты, лицензию, документацию и т.д.), а поддиректория <cite>helloworld</cite> непосредственно сам модуль <cite>helloworld</cite>.</p>
<p>Теперь отредактируем файл: <cite>helloworld/core.py</cite> и добавим логику нашего приложения (получение и вывод строки "Hello World!"):</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_message</span><span class="p">():</span>
<span class="k">return</span> <span class="s2">"Hello World!"</span>
<span class="k">def</span> <span class="nf">print_message</span><span class="p">():</span>
<span class="k">print</span> <span class="n">get_message</span><span class="p">()</span>
</pre></div>
</div>
<div class="section" id="setup-py">
<h2><a class="toc-backref" href="#id9">Редактируем мета-информацию (setup.py)</a></h2>
<p>Заполним файл описания <cite>README.rst</cite>:</p>
<div class="highlight"><pre><span></span><span class="gh">Description</span>
<span class="gh">===========</span>
An example Hello World project.
</pre></div>
<p>Теперь отредактируем файл <cite>setup.py</cite>:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">setuptools</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">find_packages</span>
<span class="kn">from</span> <span class="nn">os.path</span> <span class="kn">import</span> <span class="n">join</span><span class="p">,</span> <span class="n">dirname</span>
<span class="n">setup</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="s1">'helloworld'</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="s1">'1.0'</span><span class="p">,</span>
<span class="n">packages</span><span class="o">=</span><span class="n">find_packages</span><span class="p">(),</span>
<span class="n">long_description</span><span class="o">=</span><span class="nb">open</span><span class="p">(</span><span class="n">join</span><span class="p">(</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">),</span> <span class="s1">'README.txt'</span><span class="p">))</span><span class="o">.</span><span class="n">read</span><span class="p">(),</span>
<span class="p">)</span>
</pre></div>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">Убедитесь, что в вашей системе доступны <a class="reference external" href="http://pypi.python.org/pypi/setuptools">setuptools</a>, в противном
случае установите python-пакет <a class="reference external" href="http://pypi.python.org/pypi/distribute">distribute</a></p>
</div>
<p>Этих операций достаточно, чтобы собрать пакет дистрибьюции. Выполните команду
сборки:</p>
<div class="highlight"><pre><span></span>$ python setup.py sdist
</pre></div>
<p>В случае успеха вы получите файл: <cite>dist/helloworld-1.0.tar.gz</cite>. Это полноценный,
архивированный python-пакет и вы можете распространять его среди прочих разработчиков.</p>
</div>
<div class="section" id="id3">
<h2><a class="toc-backref" href="#id10">Виртуальное окружение</a></h2>
<p><a class="reference external" href="http://pypi.python.org/pypi/virtualenv/">Virtualenv</a> — пакет применяемый для создания изолированного python-окружения. Используем
его для тестирования нашего проекта.</p>
<p>Создадим окружение <tt class="docutils literal">env</tt>:</p>
<div class="highlight"><pre><span></span>$ virtualenv env
</pre></div>
<p>Команда создаст директорию <tt class="docutils literal">env</tt> внутри нашего проекта и установит туда <tt class="docutils literal">python</tt>, <tt class="docutils literal">pip</tt> и <tt class="docutils literal">distribute</tt>.
Произведем в него установку нашего проекта.</p>
<div class="highlight"><pre><span></span>$ ./env/bin/python setup.py install
running install
running bdist_egg
running egg_info
<span class="o">[</span>...<span class="o">]</span>
Processing dependencies <span class="k">for</span> <span class="nv">helloworld</span><span class="o">==</span>1.0
Finished processing dependencies <span class="k">for</span> <span class="nv">helloworld</span><span class="o">==</span>1.0
</pre></div>
<p>И протестируем его работоспособность:</p>
<div class="highlight"><pre><span></span>$ ./env/bin/python
>>> import helloworld.core as hw
>>> hw.get_message<span class="o">()</span>
<span class="s1">'Hello World!'</span>
>>> hw.print_message<span class="o">()</span>
Hello World!
</pre></div>
<p>Все работает. Осталось добавить поддержку команды <tt class="docutils literal">helloworld</tt> в консоли.</p>
</div>
<div class="section" id="id4">
<h2><a class="toc-backref" href="#id11">Создание команд</a></h2>
<p>Для создания команды <tt class="docutils literal">helloworld</tt> изменим файл <cite>setup.py</cite>:</p>
<div class="highlight"><pre><span></span><span class="n">setup</span><span class="p">(</span>
<span class="o">...</span>
<span class="n">entry_points</span><span class="o">=</span><span class="p">{</span>
<span class="s1">'console_scripts'</span><span class="p">:</span>
<span class="p">[</span><span class="s1">'helloworld = helloworld.core:print_message'</span><span class="p">]</span>
<span class="p">}</span>
<span class="p">)</span>
</pre></div>
<p>В параметре <tt class="docutils literal">entry_points</tt> мы задаем словарь с "точками вызова" нашего приложения. Ключ <tt class="docutils literal">console_scripts</tt>
задает список создаваемых исполняемых скриптов (в Windows это будут exe-файлы). В данном случае
мы указали создание исполняемого скрипта <tt class="docutils literal">helloworld</tt> при вызове которого будет запускаться метод <tt class="docutils literal">print_message</tt>
из модуля <tt class="docutils literal">helloworld.core</tt>.</p>
<p>Переустановим модуль в наше окружение и проверим работу созданного скрипта (для этого прийдется активировать наше окружение):</p>
<div class="highlight"><pre><span></span>$ ./env/bin/python setup.py install
$ <span class="nb">source</span> ./env/bin/activate
<span class="o">(</span>env<span class="o">)</span>
$ helloworld
Hello World!
<span class="o">(</span>env<span class="o">)</span>
</pre></div>
<p>Похоже все работает.</p>
</div>
<div class="section" id="id5">
<h2><a class="toc-backref" href="#id12">Работа с версиями</a></h2>
<p>Номер версии важная часть любого проекта. От него зависит обновление пакетов
и разрешение зависимостей. В примере выше мы указали номер версии <tt class="docutils literal">1.0</tt> в файле <cite>setup.py</cite>.
Более правильное решение перенести его в файл <cite>helloworld/__init__.py</cite> чтобы сделать доступным
в python-коде. По существующим соглашения для хранения номера версии в модуле, используется
переменная <tt class="docutils literal">__version__</tt>.</p>
<p><cite>helloworld/__init__.py`</cite>:</p>
<div class="highlight"><pre><span></span><span class="n">__version__</span> <span class="o">=</span> <span class="s1">'1.0'</span>
</pre></div>
<p>Изменим файл <cite>setup.py</cite>, чтобы нам не приходилось редактировать номер версии в двух местах:</p>
<div class="highlight"><pre><span></span><span class="o">...</span>
<span class="kn">import</span> <span class="nn">helloworld</span>
<span class="n">setup</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="s1">'helloworld'</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="n">helloworld</span><span class="o">.</span><span class="n">__version__</span><span class="p">,</span>
<span class="o">...</span>
</pre></div>
<p>Существует множество систем наименования версий в python обычно рекомендуется использовать <a class="reference external" href="http://www.python.org/dev/peps/pep-0386/">PEP386</a>.
Можно представить, что обозначение версии состоит из номера мажорного, минорного релизов
(номера багфикса при необходимости), разделенных точками. В последней части версии
разрешается использовать буквы латинского алфавита. Примеры из официальной документации:</p>
<pre class="literal-block">
0.4 0.4.0 (these two are equivalent)
0.4.1
0.5a1
0.5b3
0.5
0.9.6
1.0
1.0.4a3
1.0.4b1
1.0.4
</pre>
</div>
<div class="section" id="id6">
<h2><a class="toc-backref" href="#id13">Управление зависимостями</a></h2>
<p>Добавим функциональности нашему проекту. Создадим команду <tt class="docutils literal">serve</tt> которая будет запускать
вебсервер отдающий страницу со строкой "Hello world!" генерируемой нашим модулем. Для этого
воспользуемся пакетом <a class="reference external" href="http://pypi.python.org/pypi/Flask/0.8">Flask</a>.</p>
<p>Добавляем файл <cite>helloworld/web.py</cite>:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">render_template</span>
<span class="kn">from</span> <span class="nn">helloworld.core</span> <span class="kn">import</span> <span class="n">get_message</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
<span class="nd">@app.route</span><span class="p">(</span><span class="s2">"/"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s1">'index.html'</span><span class="p">,</span>
<span class="n">message</span><span class="o">=</span><span class="n">get_message</span><span class="p">())</span>
<span class="k">def</span> <span class="nf">run_server</span><span class="p">():</span>
<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</pre></div>
<p>И файл <cite>helloworld/templates/index.html</cite>:</p>
<div class="highlight"><pre><span></span><span class="cp"><!DOCTYPE HTML></span>
<span class="p"><</span><span class="nt">body</span><span class="p">></span>{{message}}<span class="p"></</span><span class="nt">body</span><span class="p">></span>
</pre></div>
<p>И опишем команду <tt class="docutils literal">serve</tt> в файле <cite>setup.py</cite>:</p>
<div class="highlight"><pre><span></span><span class="o">...</span>
<span class="n">entry_points</span><span class="o">=</span><span class="p">{</span>
<span class="s1">'console_scripts'</span><span class="p">:</span> <span class="p">[</span>
<span class="s1">'helloworld = helloworld.core:print_message'</span><span class="p">,</span>
<span class="s1">'serve = helloworld.web:run_server'</span><span class="p">,</span>
<span class="p">]</span>
<span class="p">},</span>
<span class="o">...</span>
</pre></div>
<p>Теперь в нашем проекте появилась зависимость от пакета <a class="reference external" href="http://pypi.python.org/pypi/Flask/0.8">Flask</a>. Без его установки наше приложение
не будет правильно работать. За описание зависимостей в файле <cite>setup.py</cite> отвечает параметр <tt class="docutils literal">install_requires</tt>:</p>
<div class="highlight"><pre><span></span><span class="o">...</span>
<span class="n">install_requires</span><span class="o">=</span><span class="p">[</span>
<span class="s1">'Flask==0.8'</span>
<span class="p">]</span>
</pre></div>
<p>Проверим установку зависимостей обновив наш пакет и работу команды <tt class="docutils literal">serve</tt>:</p>
<div class="highlight"><pre><span></span>$ ./env/bin/python setup.py develop
...
Processing dependencies <span class="k">for</span> <span class="nv">helloworld</span><span class="o">==</span>0.1
Searching <span class="k">for</span> <span class="nv">Flask</span><span class="o">==</span>0.8
...
$ serve
* Running on http://127.0.0.1:5000/
</pre></div>
<p>Открыв браузер по адресу <tt class="docutils literal"><span class="pre">http://127.0.0.1:5000</span></tt> вы должны увидеть нашу страницу.</p>
</div>
<div class="section" id="manifest-in">
<h2><a class="toc-backref" href="#id14">Управление файлами проекта (MANIFEST.in)</a></h2>
<p>На текущий момент при сборке нашего пакета <tt class="docutils literal">distutils</tt> включает в него только python-файлы.
Необходимо включить в него файл <cite>helloworld/templates/index.html</cite> без которого проект работать не будет.</p>
<p>Чтобы сделать это мы должны сообщить <tt class="docutils literal">distutils</tt> какие еще файлы надо включать в наш проект. Один из способов —
это создание файла <cite>MANIFEST.in</cite>:</p>
<div class="highlight"><pre><span></span>recursive-include helloworld/templates *.html
</pre></div>
<p>Данная команда указывает <tt class="docutils literal">distutils</tt> на включение в проект <em>всех</em> html файлов в директории <cite>helloworld/templates</cite>.</p>
<p>Также придется обновить <cite>setup.py</cite>:</p>
<div class="highlight"><pre><span></span><span class="o">...</span>
<span class="n">setup</span><span class="p">(</span>
<span class="o">...</span>
<span class="n">include_package_data</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="o">...</span>
<span class="p">)</span>
</pre></div>
<p>Теперь шаблоны будут включены в наш проект.</p>
</div>
<div class="section" id="id7">
<h2><a class="toc-backref" href="#id15">Создание и запуск тестов</a></h2>
<p>Хорошей практикой считается создание тестов для вашего проекта.
Добавим простейшую реализацию, файл <cite>tests.py</cite>:</p>
<div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">unittest</span> <span class="kn">import</span> <span class="n">TestCase</span>
<span class="kn">from</span> <span class="nn">helloworld.core</span> <span class="kn">import</span> <span class="n">get_message</span>
<span class="k">class</span> <span class="nc">HelloworldTestCase</span><span class="p">(</span><span class="n">TestCase</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">test_helloworld</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">get_message</span><span class="p">(),</span> <span class="s1">'Hello World!'</span><span class="p">)</span>
</pre></div>
<p>И обновим <cite>setup.py</cite>:</p>
<div class="highlight"><pre><span></span><span class="o">...</span>
<span class="n">setup</span><span class="p">(</span>
<span class="o">...</span>
<span class="n">test_suite</span><span class="o">=</span><span class="s1">'tests'</span><span class="p">,</span>
<span class="o">...</span>
<span class="p">)</span>
</pre></div>
<p>Теперь мы можем произвести предварительное тестирование нашего проекта:</p>
<div class="highlight"><pre><span></span>$ python setup.py <span class="nb">test</span>
running <span class="nb">test</span>
running egg_info
writing requirements to helloworld.egg-info/requires.txt
writing helloworld.egg-info/PKG-INFO
writing top-level names to helloworld.egg-info/top_level.txt
writing dependency_links to helloworld.egg-info/dependency_links.txt
writing entry points to helloworld.egg-info/entry_points.txt
reading manifest file <span class="s1">'helloworld.egg-info/SOURCES.txt'</span>
reading manifest template <span class="s1">'MANIFEST.in'</span>
writing manifest file <span class="s1">'helloworld.egg-info/SOURCES.txt'</span>
running build_ext
test_helloworld <span class="o">(</span>tests.HelloworldTestCase<span class="o">)</span> ... ok
----------------------------------------------------------------------
Ran <span class="m">1</span> <span class="nb">test</span> in 0.000s
OK
</pre></div>
<p>Обратите внимание, что для запуска тестов даже не нужно создание виртуального окружения. Необходимые
зависимости будут скачаны в директорию проекта в виде <tt class="docutils literal">egg</tt> пакетов.</p>
</div>
<div class="section" id="pypi-python-org">
<h2><a class="toc-backref" href="#id16">Публикация пакета на pypi.python.org</a></h2>
<p>Прежде чем вы сможете опубликовать свой проект вам необходимо зарегистрироваться на <a class="reference external" href="http://pypi.python.org">PyPi</a>.
Запишите ваши реквизиты в файле <cite>~/.pypirc</cite>:</p>
<div class="highlight"><pre><span></span><span class="o">[</span>distutils<span class="o">]</span>
index-servers <span class="o">=</span>
pypi
<span class="o">[</span>pypi<span class="o">]</span>
username:<username>
password:<password>
</pre></div>
<p>Все ваш проект готов к публикации. Достаточно ввести соответствующую команду:</p>
<div class="highlight"><pre><span></span>$ python setup.py register sdist upload
</pre></div>
<div class="note">
<p class="first admonition-title">Note</p>
<p class="last">Вы не сможете опубликовать пакет <cite>helloworld</cite>, тк данное имя проекта уже занято.</p>
</div>
</div>
</div>
<g:plusone></g:plusone>
<script>(function(d, t) {
var g = d.createElement(t),
s = d.getElementsByTagName(t)[0];
g.async = true;
g.src = 'https://apis.google.com/js/plusone.js';
g.text = '{lang:"nl"}';
s.parentNode.insertBefore(g, s);
}(document, 'script'));
</script>
<div class="article_paginator zeta"> <div class="article_paginator_right">
<a href="some-flask-things.html" class="article_paginator_right_link">Неделя с Flask</a> Ctrl→
</div> <div class="article_paginator_left">
←Ctrl <a href="android-push-python.html" class="article_paginator_left_link">Серверная реализация Android C2DM Push уведомлений (python)</a>
</div></div>
</article>
<div id="disqus_thread"></div>
<script type="text/javascript">
var disqus_shortname = 'klengithubcom';
var disqus_identifier = 'create-python-packages';
var disqus_url = 'http://klen.github.io/create-python-packages.html';
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<div class="share">
<div class="addthis_toolbox addthis_default_style ">
<a class="addthis_button_preferred_1"></a>
<a class="addthis_button_preferred_2"></a>
<a class="addthis_button_preferred_3"></a>
<a class="addthis_button_preferred_4"></a>
<a class="addthis_button_compact"></a>
<a class="addthis_counter addthis_bubble_style"></a>
</div>
<script type="text/javascript">var addthis_config = {"data_track_clickback":true};</script>
<script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-4e108f9f24976375"></script>
</div> </div>
<a class="github" href="http://github.com/klen"><img src="./static/ForkMe_Wht.png" alt="alt"/></a> <footer class="footer">
© 2011–2015 Kirill Klenov
| <a href="./pages/about-en.html">About me</a>
<div class='pos1'></div>
<div class='pos2'></div>
</footer>
<script language="javascript" type="text/javascript" src="./theme/build_main.js"></script><div style="display:none;"><script type="text/javascript">
(function(w, c) {
(w[c] = w[c] || []).push(function() {
try {
w.yaCounter7784947 = new Ya.Metrika({
id:7784947,
enableAll:true, webvisor:true});
} catch(e) {}
});
})(window, 'yandex_metrika_callbacks');
</script></div>
<script src="//mc.yandex.ru/metrika/watch.js" type="text/javascript" defer="defer"></script>
<noscript><div><img src="//mc.yandex.ru/watch/7784947" style="position:absolute; left:-9999px;" alt="" /></div></noscript><script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-30512655-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>