项目目录

project_dir/
.git/
test/
doc/
index.rst
html/
index.html
setup.py
MANIFEST.in


项目结构化

项目目录结构/仓库目录

• 工程的名字
• 工程的描述
• 一系列的文件

README.rst
setup.py
requirements.txt
sample/__init__.py
sample/core.py
sample/helpers.py
docs/conf.py
docs/index.rst
tests/test_basic.py


1. sample 目录

您的模块包是这个仓库的核心，它不应该隐藏起来，放在其他目录:

./sample/



如果您的模块只有一个文件，那么您可以直接将这个文件放在仓库的根目录下:

./sample.py


除了源代码本身以外，这个毫无疑问是您仓库最重要的一部分。在这个文件中要有完整的许可说明和授权。

当然，您也可以在发布您的代码时不做任何许可说明，但是这显然阻碍潜在的用户使用您的代码。

3. setup.py

打包和发布管理，跟模块包在同一目录，应该放在仓库根目录下

4. requirements.txt

记录项目对第三方库依赖关系的文件，它应该指明完整工程的所有依赖包: 测试, 编译和文档生成。

如果您的工程没有任何开发依赖，或者您喜欢通过 setup.py 来设置，那么这个文件不是必须的。

5. docs 目录

包的参考文档

6. tests 目录

包的相关测试代码

最开始，一组测试例子只是放在一个文件当中:

./test_sample.py



当测试例子逐步增加时，您会把它放到一个目录里面，像下面这样:

tests/test_basic.py

7. Makefile / manage.py 等

常规的管理任务（可选的）。

如果您看看我的项目或者其他开源项目，您都会发现有一个Makefile。为什么？这些项目也不是用C写的啊。。。简而言之，make对于定义常规的管理任务是非常有用的工具。

样例 Makefile:

init:
pip install -r requirements.txt

test:
py.test tests

PHONY: init test



一些其他的常规管理脚本（比如 manage.py 或者 fabfile.py），也放在仓库的根目录下。

• 将您的包安装到site-packages中。
• 通过简单直接的路径设置来解决导入的问题。

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

import sample



from .context import sample



$django-admin.py startproject samplesite  这样的操作生成的仓库结构是这样的: README.rst samplesite/manage.py samplesite/samplesite/settings.py samplesite/samplesite/wsgi.py samplesite/samplesite/sampleapp/models.py  可以看到显然仓库目录下的项目代码有了两层嵌套结构 应该这样来做： $ django-admin.py startproject samplesite .



README.rst
manage.py
samplesite/settings.py
samplesite/wsgi.py
samplesite/sampleapp/models.py


软件架构和 Python 模块、包

Python 代码中文件即模块，目录即包

模块

Python模块是最主要的抽象层之一，并且很可能是最自然的一个。抽象层允许将代码分为 不同部分，每个部分包含相关的数据与功能。

# OK
import library.plugin.foo
# not OK
import library.foo_plugin



[...]
from modu import *
[...]
x = sqrt(4)  # sqrt是模块modu的一部分么？或是内建函数么？上文定义了么？



from modu import sqrt
[...]
x = sqrt(4)  # 如果在import语句与这条语句之间，sqrt没有被重复定义，它也许是模块modu的一部分。



import modu
[...]
x = modu.sqrt(4)  # sqrt显然是属于模块modu的。



包

Python提供非常简单的包管理系统，即简单地将模块管理机制扩展到一个目录上(目录扩 展为包)。

pack/ 目录下的 modu.py 文件通过 import pack.modu 语句导入。 该语句会在 pack 目录下寻找 __init__.py 文件，并执行其中所有顶层 语句。以上操作之后，modu.py 内定义的所有变量、方法和类在pack.modu命名空 间中均可看到。

不良的架构设计

• 多重且混乱的循环依赖关系：假如在 furn.py 内的Table与Chair类需要 导入 workers.py 中的Carpenter类以回答类似 table.isdoneby() 的问题，并且Carpenter类需要引入Table和Chair类以回答 carpenter.whatdo() 这类问题，这就是一种循环依赖的情况。在这种情况下,您得借助一些不怎么靠谱的 小技巧，比如在方法或函数内部使用import语句。
• 隐含耦合：Table类实现代码中每一个改变都会打破20个不相关的测试用例，由于它 影响了Carpenter类的代码，这要求谨慎地操作以适应改变。这样的情况意味着 Carpenter类代码中包含了太多关于Table类的假设关联（或相反）。
• 大量使用全局变量或上下文：如果Table和Carpenter类使用不仅能被修改而且能被 不同引用修改的全局变量，而不是明确地传递 (height, width, type, wood) 变量。您就需要彻底检查全局变量的所有入口，来理解到为什么一个长方形桌子变 成了正方形，最后发现远程的模板代码修改了这份上下文，弄错了桌子尺寸规格的 定义。
• 面条式代码 (Spaghetti code) ：多页嵌套的if语句与for循环，包含大量复制-粘贴 的过程代码，且没有合适的分割——这样的代码被称为面条式代码。Python中有意思 的缩进排版(最具争议的特性之一)使面条式代码很难维持。所以好消息是您也许不 会经常看到这种面条式代码。
• Python中更可能出现混沌代码：这类代码包含上百段相似的逻辑碎片，通常是缺乏 合适结构的类或对象，如果您始终弄不清手头上的任务应该使用FurnitureTable， AssetTable还是Table，甚至TableNew，也许您已经陷入了混沌代码中

项目构建流程

项目托管

Your code needs a home on the Internet: a website where people can download your software, learn how to use it, and provide feedback. There are several websites that will host your open-source project for free; some popular choices are listed below. The basic requirements are web page hosting, a version control system, and a user feedback system. Feedback mechanisms include bug trackers, forums, and mailing lists. If you’re not sure which host to use, Sourceforge is one of the oldest and best-known hosts; I’ll be using Sourceforge in the examples below.

You’ll need a project name in order to register. Your project’s name is important, but don’t spend too much time obsessing over it. It’s worth doing a quick search on Google, The Python Package Index and freshmeat to see if someone else already has a software product by that name. If it’s something totally unrelated, it’s probably not a problem (but watch out for trademarks). If your name is taken, consider tacking on “Py” or “Python” or a clever Monty Python reference.

Note

Your project name or “short name” may be taken on your host; this may affect the URL of your project’s homepage and detract from its “findability.” Your project’s actual name doesn’t have to match the project name you use on your host, but it helps. Decide whether that’s important; if so, consider whether you want to change your project’s name, live with a mismatched host project name, or find another hosting service that has your name available.

Note

You can set up a project on your own website and host things yourself, but it’s more work.

Sign up for an account on your chosen host. Register your project, and take a few minutes to fill in your project’s metadata. Including a brief description, category, tags or keywords, programming language, etc. will make your software easier for people to find and grok. (If your host requires you to choose a license for your software up front, have a look at the licensing section.)

项目版本控制

Create a Repository

You will need to set up a version control system (VCS; also called a revision control or source code mangagement system) to hold your code on the Internet. This is practically what it means to be an open source project: anybody can easily download your code at any time. It also has the practical benefit of keeping backup copies of every version of your code you check in.

Subversion is probably the most widely-known VCS, and something of a lowest common denominator. It’s a good default choice, supported by many project hosts, and available on all platforms. I’ll be using Subversion for the examples in this article, but feel free to choose one of the newer, sexier VCSes below. They are all functionally identical for the basics, and most have facilities to import from or export to Subversion if you decide you want to change later.

Note that your choice of project host may limit your choice of VCS, or vice versa.

Create a SVN (or git, or hg, or bzr, or…) repository at your project host’s website.

Backing up is always a good idea; we’ll just make a quick tarball in case something gets hosed.

Note

I’m using Unix command lines and pathnames in this document, but the concepts easily map to other operating systems.

In what follows, I’m going to assume your Python source currently lives at */path/to/googlemaps/googlemaps.py*. You’ll need to replace */path/to/* with the appropriate path on your system, and everywhere you see *googlemaps*, replace it with the appropriate name for your project. Now, about that tarball:

$cd */path/to/* $ tar czvf *googlemaps*.tgz *googlemaps/*

While you’re at it, you should clean out your source directory, remove any compiled/binary files (such as *.pyc), clean out any hidden settings files or directories (you have a backup!), and remove anything sensitive or private; everything in there is about to be shared with the world.

Now we’ll move your code directory aside for the new one we’re about to create:

$svn add * Commit your changes $ svn commit -m "Initial import."

That’s it. The master copy of the code now lives on your project host’s servers.. You’ll do all of your coding in this new working directory on your machine, and periodically commit changes to the server. If you’re new to version control, refer to the appropriate link below, but basically: you’ll need to tell your VCS whenever you’re adding, moving, or deleting a file from your source. Here are the basics for svn:

svn stat - Show what’s added or changed

svn commit - Save a snapshot of your code to the repo

svn add - Put a new file under version control

svn mv - Tell svn when you’re moving a file (use instead of /bin/mv)

svn rm - Tell svn you’re removing a file (use instead of /bin/rm)

svn mkdir - Create a new directory in your working copy (use instead of /bin/mkdir)

高质量的编码

Writing good code is a journey. The Pragmatic Programmer by Andrew Hunt and David Thomas is a good first step. Code Complete by Steve McConnell is another. A good sense of design and implementation can be learned, but you still have to use it. Probably the single biggest driver of open source code quality is knowing that other hackers will be looking at and using your code. Write code for other humans to read: your peers, your clients, your potential employers… your open source projects become a part of your reputation, your resume. Invest the effort to write good code. (Did I mention it will save you time and grief in the long run?)

Writing good code is an art. Aesthetics are subjective, but in Python, there is a generally accepted standard for formatting your code: PEP 8. Read it. There is a tool, pep8, for checking your code against it.

Writing good code is a science. There are (semi-) objective means of measuring code quality. First, your code should work, which we can verify with unit testing. Second, your code should look and smell good, which we can check with Pylint.

Python 2 和 Python 3 兼容

The Python world is starting to make a leisurely transition to Python 3, which is not backwards compatible with Python 2. You can prepare your code for the future by running your unit tests under Python 2.6+ with the -3 switch:

$pylint mymodule.py Pylint warns you about many potential problems with your code. The first you’ll probably notice are naming conventions. The short of it is that pretty much all identifiers should be lowercase_with_underscores, with the exception of ClassNames and ExceptionNames, which are CamelCased (and exception names should generally end with Error). “Constants” are UPPER_CASE_UNDERSCORE._private_identifiers can be prefixed with a leading underscore, but for modules, there’s a better way: list all public classes, functions, and data as strings in a global list called __all__: __all__ = ['GoogleMaps', 'GoogleMapsError']  A quick advice rundown: One- and two-character variable names are generally too short to be meaningful. Indent with 4 spaces. Put whitespace around operators and after commas. Give everything a docstring. Don’t shadow variables. Use is to compare with None, True, and False. Make your own exceptions subclass Exception. Limit try clauses to the bare minimum amount of code; catch the most specific exception possible (i.e., not Exception). Keep it simple. Last but very first: don’t use global variables. Look at and learn about the warnings Pylint produces. Know when to ignore them; it can produce false positives. If Pylint complains and you are really sure that your code is safe, indicate to Pylint (and anyone reading your code) that you know what you’re doing: def fetch_json(query_url, params={}, headers={}): # pylint: disable-msg=W0102 ...  Try for a Pylint score of at least 8. Personally, I try to fix or shush all messages except those about long line length in code (I do keep docstrings trimmed for people using the interactive help). 单元测试 测试驱动开发 A good way to check whether your code works is to try it. A great way is to try it automatically, every time it changes. That’s the premise of unit testing: write code to test your code, so that it’s easy, so that you’ll do it often. In this context, unit means module, class, or function; we test each unit of functionality separately, so we have more confidence everything will work when we put it all together. Python 中几种流行的单元测试工具 doctest Python has two standard unit testing modules, doctest and unittest (it’s that important!). doctest is a fantastic way to kill two birds with one stone: demonstrating how to use your code by example, and making sure it gives the answers you expect. You can literally run your code in an interactive session, check if its working, and then paste the session into a docstring: def local_search(self, query, numresults=_LOCAL_RESULTS_PER_PAGE, **kwargs): """ Searches Google Local for the string query and returns a dictionary of the results. >>> gmaps = GoogleMaps() >>> local = gmaps.local_search('sushi san francisco, ca') >>> result = local['responseData']['results'][0] >>> print result['titleNoFormatting'] Sushi Groove """  Then, by putting this in your main routine: if __name__ == "__main__": import doctest doctest.testmod()  doctest will automatically pull the code out of your docstring, run it, and compare the output to that present in the docstring whenever your module is run as a script. Writing examples is an important part of good documentation anyway, and with doctest it takes almost no extra effort to turn those docs into tests. unittest unittest is Python’s standard “heavyweight” unit testing framework. It’s a bit more flexible and a bit more powerful that doctest, but it takes a bit more doing to use. Here is the same test using unittest: import unittest from googlemaps import GoogleMaps class Test(unittest.TestCase): """Unit tests for googlemaps.""" def test_local_search(self): """Test googlemaps local_search().""" gmaps = GoogleMaps(GMAPS_API_KEY, referrer_url='http://www.google.com/') local = gmaps.local_search('sushi san francisco, ca') result = local['responseData']['results'][0] self.assertEqual(result['titleNoFormatting'], 'Sushi Groove') if __name__ == "__main__": unittest.main()  This would go in a file called test/test_googlemaps.py, and this is a general rule: tests go in a directory called test at the root level of your package, and are named test_*modulename*.py. All of the tests for module modulename go in this file, and this file tests all of the functionality in modulename. Even if you are only using doctests, you should still have a test/test_*modulename*.py that runs your doctests: import unittest import doctest import googlemaps class Test(unittest.TestCase): """Unit tests for googlemaps.""" def test_doctests(self): """Run googlemaps doctests""" doctest.testmod(googlemaps) if __name__ == "__main__": unittest.main()  This is because unittest is the standard for Python unit testing, and many tools, IDEs, and people expect to find and interface with unittest tests in the standard place. Since the test modules are in a separate directory from your code, you may need to add your module’s parent directory to your PYTHONPATH in order to run them: $ cd */path/to/googlemaps*

$export PYTHONPATH=$PYTHONPATH:/path/to/*googlemaps*/*googlemaps*

$python test/test_*googlemaps*.py nose Finally, there is one more popular unit testing framework for Python (it’s that important!), nose. nose helps simplify and extend the builtin unittest framework (it can, for example, automagically find your test code and setup your PYTHONPATH for you), but it is not included with the standard Python distribution. In conclusion: Write unit tests. Run them. Often. It will make you feel MUCH more confident about releasing your code to the world. 单元测试相关资源 项目文档 Good documentation is important for showing others how to use your code as well as for keeping you straight on what it’s supposed to do. With the doctest module, you can even use it to test your code. Python makes it easy to insert documentation right into the code with docstrings; they often even do triple-duty as comments. With just a little extra formatting in your docstrings, you can automatically produce beautiful web or print documentation for your project. I even suggest writing the documentation before writing the code (or at least concurrently). This is a great way to employ user-centered design. You are going to have to explain how to use your code at some point; what design would be the easiest to explain? I’d wager that design would also be in the running for “easy to implement, test and maintain” as well. Writing up the docs first will let you figure out how it all works together before committing to the code. This works just as well if a module is written by you, for you as a component of a higher-level program. Ask yourself: if I were looking for a module to do XYZ, what would I want it to look like? How would I want to use it? What would I want to know first? What examples would I like to see? Have compassion on yourself: write good documentation (and code) for you. Write out the docs for this awesome hypothetical module, see if it “coheres,” then fill in the code. Use reStructuredText in docstrings The Python community is gravitating toward reStructuredText for docstring markup; it’s the equivalent of Javadoc for Python. It’s easy to write and read: def reverse_geocode(self, lat, lng, sensor='false', oe='utf8', ll='', spn='', gl=''): """ Converts a (latitude, longitude) pair to an address. Interesting bits: >>> gmaps = GoogleMaps() >>> reverse = gmaps.reverse_geocode(38.887563, -77.019929) >>> address = reverse['Placemark'][0]['address'] >>> print address 200 6th St SW, Washington, DC 20024, USA >>> accuracy = reverse['Placemark'][0]['AddressDetails']['Accuracy'] >>> print accuracy 8 :param lat: latitude :type lat: float :param lng: longitude :type lng: float :return: Reverse geocoder return value_ dictionary giving closest address(es) to (lat, lng) :rtype: dict :raises GoogleMapsError: If the coordinates could not be reverse geocoded. Keyword arguments and return value are identical to those of :meth:geocode(). .. _Reverse geocoder return value: http://code.google.com/apis/maps/documentation/geocoding/index.html#ReverseGeocoding """  It can automatically generate HTML like this: • GoogleMaps.reverse_geocode(lat, lng, sensor=‘false’, oe=‘utf8’, ll='', spn='', gl='') Converts a (latitude, longitude) pair to an address.Interesting bits:>>> gmaps = GoogleMaps()>>> reverse = gmaps.reverse_geocode(38.887563, -77.019929)>>> address = reverse['Placemark'][0]['address']>>> print address200 6th St SW, Washington, DC 20024, USA>>> accuracy = reverse['Placemark'][0]['AddressDetails']['Accuracy']>>> print accuracy8Parameters:lat (float) – latitudelng (float) – longitudeReturns:Reverse geocoder return value dictionary giving closest address(es) to (lat, lng)Return type:dictRaises GoogleMapsError: If the coordinates could not be reverse geocoded.Keyword arguments and return value are identical to those of geocode(). Take-home points: • Normal docstring formatting conventions apply: see PEP 257. • Identifier references go in backticks. • :param lat: latutide documents parameters • :type lat: float documents parameter types • :return: dictionary giving closest addresses... documents return values • :rtype: dict documents return type • :raises GoogleMapsError: If coordinates could not... documents exceptions raised • >>> starts a doctest and is automatically formatted as code; code can also be indicated by indenting four spaces or preceding with :: and a blank line • Link to other methods, functions, classes, modules with :meth:mymethod, :func:*myfunc*, :class:myclass, and :mod:*mymodule*. • Hyperlink names go in backticks with a trailing underscore: Google_, and targets can be defined anywhere with .. _Google:http://www.google.com/. • See the reStructuredText documentation for much more. Generate docs with Sphinx The documentation above, and the present Howto, were rendered with Sphinx. Sphinx is the official document processor for Python itself and many Python projects. You’ve probably seen its handiwork at http://docs.python.org/. Setting up Sphinx to automatically generate documentation for your module is easy. First tell your VCS to create a doc/ directory under your project root (this is the the standard place for documentation), and then run sphinx-quickstart: $ cd */path/to/googlemaps*

$svn mkdir doc $ cd doc

$sudo easy_install sphinx $ sphinx-quickstart

Answer the questions (the defaults are fine, except be sure to say ‘yes’ to the autodoc extension). Then, edit the generated index.rstfile to add this:

.. automodule:: *googlemaps*

This is the place to put any extra documentation that’s not in your docstrings. Be sure to put index.rst and Sphinx’ conf.py under version control:

$svn add index.rst conf.py You can generate your documentation by running sphinx-build in the doc/ directory: $ sphinx-build . html/

(You will need to have */path/to/googlemaps/googlemaps* in your PYTHONPATH for this to work.)

This will put the HTML documentation in doc/html/. Sphinx generates very nice documentation. Open it up with your web browser and look at it. It will encourage you to write better documentation if you see that you’re making something beautiful as you write.

In addition to the docstrings in your code and the resulting HTML documentation, you should create a README.txt file in the top level of your directory structure. Put it under version control. Your README.txt should contain the following:

• Name, version, and release date of the package
• Brief description of the package
• Any dependencies or required versions of Python
• How to install the package (ideally just easy_install *packagename*)
• How to run the program(s), if your package contains scripts
• Package author and contact information
• Pointer to full documentation

Some people like to break a few of these out into separate files (INSTALL, AUTHORS, ANNOUNCE…), but personally I prefer to keep it simple.

If you already have this information in your docstrings or somewhere else, by all means, don’t repeat yourself: either use Sphinx, which can also produce plain (reStructured) text, or whip up a script to pull out the information and write your README.txt for you. You can extract the docstring from any module, class, or function with, e.g., *mymodule*.__doc__. Here’s how to make Sphinx output plain (reStructured) text to the text/ directory:

$sphinx-build -b text . text/ 文档相关资源 项目许可证 You will need to decide on a license for your code. Popular open-source licenses include the GPL and LGPL, BSD, MIT/X11, Apache, Eclipse, and Mozilla. There are several resources listed below to help guide you in choosing a license. Your choice has implications for who can use your code under what circumstances, including which other open source projects can incorporate it. Your choice of license may also have implications for your choice of project host, since some hosts only permit software under some licenses. Take the time to learn a bit about licensing, and decide how you would like your code to be used. Once you have chosen a license, you can find the complete text at the Open Source Initiative. Read through the text to ensure you agree with its terms. Copy the complete text into a file called LICENSE.txt at the top level of your project (and put it under version control). Then, you will need to put a copyright notice in a comment at the top of each source file, and a brief statment of the licensing terms including where to find the license. You do not have to include the full license directly in your source; see the resources below for suggestions. If you have considerable documentation, consider licensing the documentation itself under one of the available free documentation licenses. 相关资源 为项目添加许可证，是为了别人可以更好的利用你的代码，这里有很多 开源许可 可以选择。 一般来说，这些许可大致分为两类： 1. 许可更关注用户随意使用软件的自由（较宽松的自由软件开源许可，如 MIT、 BSD，以及 Apache）。 2. 许可更关注确保代码 — 包括对其任意的修改和分发 — 的自由（较不宽松的 自由软件许可，如GPL 和 LGPL）。 后者相较而言不太宽松，它们不允许他人在软件中添加代码，也不允许分发软件 包括对其源代码的更改。 为了帮助您选择用于项目的许可，这里有一个 许可选择器可供使用 较宽松： • PSFL (Python Software Foundation License) – 用于贡献给Python • MIT / BSD / ISC • MIT (X11) • New BSD • ISC • Apache 较不宽松: • LGPL • GPL • GPLv2 • GPLv3 关于许可中使用软件时什么能做、不能做、必须做的解释，这里 tl;drLegal 有很好的概述。 项目打包 Packaging takes the files in your carefully crafted directory layout and bundles them up for easy download and use by others. The standard way to do this in Python is with distutils. Creating a simple file, setup.py, will give you your own easy_install-able package. setup.py Here is an example setup.py: from distutils.core import setup import sys sys.path.append('googlemaps') import googlemaps setup(name='googlemaps', version='1.0', author='John Kleint', author_email='py-googlemaps-general@lists.sourceforge.net', url='http://sourceforge.net/projects/py-googlemaps/', download_url='https://sourceforge.net/projects/py-googlemaps/files/', description='Easy geocoding, reverse geocoding, driving directions, and local search in Python via Google.', long_description=googlemaps.GoogleMaps.__doc__, package_dir={'': 'googlemaps'}, py_modules=['googlemaps'], provides=['googlemaps'], keywords='google maps local search ajax api geocode geocoding directions navigation json', license='Lesser Affero General Public License v3', classifiers=['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', 'License :: OSI Approved :: GNU Affero General Public License v3', 'Topic :: Internet', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Scientific/Engineering :: GIS', ], )  Don’t worry if you don’t have a download_url yet. Notice that we import our own module in order to pull in the __doc__ string for the long_description; you are free to use whatever text is appropriate. If you have a package instead of a module, you’d replace py_modules with packages and remove the package_dir. You can find the list of classifiers at PyPI’s list of trove classifiers. If your code depends on other third-party packages/modules, you can specify those with a required keyword argument. This covers our code, but we need one more file to pull in the documentation: MANIFEST.in in the package root: recursive-include doc/html * prune doc/html/.doctrees/ exclude doc/html/.buildinfo include LICENSE.txt  Now, to build your package, you just run setup.py sdist: $ python setup.py sdist

If all goes well, this will create a tarball in dist/*googlemaps*-1.0.tar.gz. Let’s make sure there are no problems installing it and verify the presence of important files with cheesecake_index:

$sudo easy_install cheesecake $ cheesecake_index --path=dist/*googlemaps*-1.0.tar.gz

Ensure at the minimum that your package is able to be installed. Notice that the cheesecake index includes Pylint as one component, so you’re already ahead of the game. Personally I think the score is weighted a bit heavily toward installability and documentation, but a relative cheesecake index of at least 70% seems like a reasonable target.

项目发布

Now that we’ve built the “golden master” in dist/*googlemaps*-1.0.tar.gz, it’s time to upload it. Your project host should have instructions for uploading files for release; most hosts let you do this via the web, SCP/SFTP, or FTP. Once you’ve uploaded the package, upload the documentation in docs/html to your project’s website (don’t forget the subdirectories). Take a moment to update your project’s metadata with things that may have changed, such as the license. If your program has a GUI, take a few screenshots and add them to your project metadata and/or web page.

Copy the URL where your file can be downloaded (the page containing the link is fine), and put it in the download_url argument of your setup.py.

PyPI

You’ll likely want to register your package with the Python Package Index. This enables people to automatically download and install your package with easy_install or pip. You will need to sign up for a PyPI account (it’s free). You can do this either on the PyPI website, or via the command line and have your password mailed to you. Either way:

$python setup.py sdist register upload This will build your packages, prompt you for your username/password, register your package (and its metadata) with PyPI, and then upload your package to PyPI. Uploading your package itself is not strictly necessary, but it may make it easier to find. While you’re at it, you can also create a Windows installer to make it easy for Windows users to get your package: $ python setup.py bdist_wininst upload

This will create a file dist/*googlemaps*-1.0.win32.exe that you can also upload to your project host. (Note that Python 2.6 has a bug that may give the installer the wrong name, but you can simply rename it.)

Visit your project’s PyPI page at http://pypi.python.org/pypi/*projectname*/; you’ll notice that your setup.py long_description text has become the text of the web page. PyPI understands reStructuredText, so go ahead and tweak your long_description to your liking. Remeber that sphinx-build -b text . text/ will “flatten” your documentation to reStructuredText, if you want to put the whole thing on PyPI. You can re-register a revised project without changing the version number. You can also edit your project’s metadata via the PyPI website.

Epilogue

Congratulations on the release of your Python package! Your code may grow from these humble beginnings, but it has a good foundation, and you are now familiar with the mechanics of open source Python projects. In parting, I woluld be remiss not to mention a great resource on all aspects of the open-source project lifecycle, the free book Producing Open Source Software, by Karl Fogel. Best of luck. And…

Always look on the bright side of life…

Always look on the bright side of life…

Previous
Next