A crash course to writing Django modules¶
Django has a vast ecosystem of 3rd party modules. This crash course is an attempt at writing a guide for writing, testing, documenting and deploying such modules to Pypi - the Python Package Index.
The concepts in this guide does not strictly apply just to Django, but can with minor adjustments be used as a guideline for writing all sorts of portable Python modules.
It is not however; a tutorial for Python nor Django. If you are new to Django, I suggest you complete the Django tutorial first, then come back and read the crash course.
Contents:
Working environment¶
When working on a new project it will probably have different requirements than your previous projects.
- Some reasons might include:
- Required libraries probably differs
- Same libraries, but different or incompatible versions
- You shouldn’t pollute your system with libraries only required for a single project.
- It’s easy to fix in case you screw up something
- There are many solutions to this, the most popular includes:
- virtualenv
- pyenv
- Vagrant
Each of these have their own strength and weaknesses, but I usually goes for virtualenv
with a wrapper
library called virtualenvwrapper
. I think it works quite good, so I’m going to use it in this
guide as well.
Installing virtualenv and virtualenvwrapper¶
Virtualenv creates a new python “distribution” in its own directory. All required python libraries will be installed in this directory as well, instead of in the operating systems python environment.
Installing is easy. First you need pip
installed. The pip
command is available in most
recent python installs by default. We’ll install the virtualenv
and virtualenvwrapper
libraries in
our system environment, because it need to have access to the system installed python distribution in order
to make copies of it.
~$ sudo pip install virtualenvwrapper
The above command will install both virtualenv
and the virtualenvwrapper
which gives us an easy
cli for managing our virtual environments.
The virtualenvwrapper
uses an environment variable called WORKON_HOME
, which defaults to
~/.virtualenvs
. All the virtual environments created are placed in this directory. You can of course
override the WORKON_HOME
variable if you choose to, but I think it’s a good place to store my
virtual environments.
Creating a virtual environment for the project¶
We are now ready to create a new and shiny environment for our project. The following statement is probably quite opinionated, but it’s my guide, so here it comes ;)
All new python projects should be written using the most recent Python version (3.4 at the time of writing)!
Of course, there are exceptions to this rule, but I believe that it is better to write in the most recent
version, and use the six
compatibility layer to add backward support.
That being said, go a head and install Python 3 (the most recent version) if you don’t have it installed.
(Skip this step if you already have Python3 installed) ~$ sudo apt-get install python3
Let’s create a new virtual environment called django-foobar
for our project.
~$ mkvirtualenv -p `which python3` django-foobar Running virtualenv with interpreter /usr/local/bin/python3 <snip> Installing setuptools, pip...done. (django-foobar)~$
You’ll see the currently active environment in your prompt. In order to deactivate the environment,
simply enter the command deactivate
, and to activate it again you would type in
workon django-foobar
.
While the virtual environment is active, all packages you install will be installed in the
$WORKON_HOME/django-foobar/lib/python3.4/site-packages/
, the python interpreter will be
$WORKON_HOME/django-foobar/bin/python
and so on. So when you execute the python
command,
it will be the one in your active environment, not your system python.
Good stuff!
Project structure¶
Everybody tends to have a personal preference for the structure of their project, and I’m no different. After some trial and tweaking I’ve come up with a structure I’m quite happy with.
Setting up the project¶
First, activate the django-foobar
environment if it’s not already active. Next we need to install
Django itself into the new environment.
~$ workon django-foobar
(django-foobar):~$ pip install Django
Creating the working directory¶
(django-foobar):~$ mkdir django-foobar (django-foobar):~$ cd django-foobarNote
Whenever referring to the “working directory” in this guide, I’m referring to this. In other words, the top level directory for the entire project.
Set up the testing environment¶
TDD is a good practice to follow when writing 3rd party Django modules. If you want your library to succeed and people to use and contribute to it, you’ll need a good test suite! We are going to use the
django-admin
command to create a testing environment for our module. Inside the project directory enter the following command (make sure you include the.
on the end!)(django-foobar):~/django-foobar$ django-admin startproject tests .Now, you might be wondering why we are using the
django-admin startproject
command to create the testing environment, and not the module we are going to develop. That’s because we don’t want to distribute an entire Django project. We only want to distribute thedjango-foobar
library we’re going to write, but we want to make sure it can run in an existing Django project. That’s what we’re going to use thetests
project for!
Module source code¶
Next, we need to create a directory containing the source code for our
django-foobar
module. Python modules uses underscores instead of dashes in their package names, so the python module will be calleddjango_foobar
. Either create a directory calleddjango_foobar
with an__init__.py
file inside it, or just use thedjango-admin
command to create a new app.(django-foobar):~/django-foobar$ django-admin startapp django_foobar
Documentation¶
Obviously, we need to document our library. This can be done with various tools, but I like to use Sphinx. That’s the very same tool I’ve used to write this guide, so you know how the documentation will look like =)
(django-foobar):~/django-foobar$ pip install Sphinx ... Lots of stuff going on ... (django-foobar):~/django-foobar$ sphinx-quickstart docs Welcome to the Sphinx 1.3.1 quickstart utility. Please enter values for the following settings (just press Enter to accept a default value, if one is given in brackets). Selected root path: docs You have two options for placing the build directory for Sphinx output. Either, you use a directory "_build" within the root path, or you separate "source" and "build" directories within the root path. > Separate source and build directories (y/n) [n]:Just hit
<enter>
for default values and write some sensible values for those which requires input (like project name, author, and so on).
Requirements¶
The
requirements.txt
file contains all the libraries required for developing the module. Requirements for installing the module will be in another file calledsetup.py
. Don’t pay any attention to that for now, we’ll create it later in this guide.Create the
requirements.txt
file in your project root.(django-foobar):~/django-foobar$ touch requirements.txtOpen the file in a text editor and add a few dependencies. It’s quite common to lock dependency versions when developing a library, but it’s not strictly required. If no version lock is found,
pip
will install the most recent version.Django==1.8.4 Sphinx==1.3.1 sphinx-rtd-theme==0.1.8We’ll be adding more to this file as we go along.
README.txt and LICENSE.txt¶
Create a README.txt and LICENSE.txt file. The README.txt file should contain a brief description of the module, as well as other useful information. In case you decide to upload your project to a source hosting service such as Github or Bitbucket, the content of this file will be displayed on the front page of your repository.
The LICENSE.txt file is not so important right now, but if you are going to distribute the source code, it is good practice to slap a license on it. There are many licenses to choose from, but I tend to choose a fairly liberal license such as the MIT License or the Apache v2.0 License. There is no single license which match every project, so choosing the right one depends a lot on the project type and use case. Also, if you work for a company, they might have their own rules and restrictions for licensing source code, so make sure to pay attention to that as well ;)
You don’t have to decide now, just leave the LICENSE.txt file there as a reminder. Check out this link for a list of popular open source licenses.
(django-foobar):~/django-foobar$ touch README.txt LICENSE.txt
Source control¶
This step is optional, but you probably want to add source control to your project. There is different source control tools, but I like Git, so let’s initialize a git repository in the project root.
(django-foobar):~/django-foobar$ git init Initialized empty Git repository in /path/to/your/project/.git/Not all files in your project should go into source control. Add a
.gitignore
file in order to tell Git which files or directories to ignore.(django-foobar):~/django-foobar$ touch .gitignoreOpen the .gitignore file in your favorite text editor and paste the following lines:
__pycache__/ *.py[cod] build/ dist/ sdist/ .eggs/ *.egg-info/ # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache nosetests.xml coverage.xml # Translations *.mo *.pot # Django stuff: *.log *.db # Sphinx documentation docs/_build/You can add stuff to this file as you go along in case there’s something we have missed.
Now is a good time to commit your work!
(django-foobar):~/django-foobar$ git add * (django-foobar):~/django-foobar$ git commit -m "initial commit"
Github¶
If you don’t have a Github account, go ahead and create one now!
Create an empty repository for your code
Fill in some details about your project, but make it public.
Push your code to the new Github repository.
(django-foobar):~/django-foobar$ git remote add origin https://github.com/<your-user>/django-foobar.git (django-foobar):~/django-foobar$ git push -u origin master
Enter your credentials when asked.
There. We now have a pretty good project structure for developing the amazing django-foobar
module.
It should look something like this:
├── LICENSE.txt ├── README.rst ├── django_foobar │ ├── __init__.py │ ├── admin.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py ├── docs │ ├── Makefile │ ├── _build │ ├── _static │ ├── _templates │ ├── conf.py │ ├── index.rst │ └── make.bat ├── manage.py ├── requirements.txt ├── .gitignore └── tests ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
Write some code¶
Now, this is not a guide for writing Django code, so we’ll just write a small testable unit in our
django_foobar
module.
Open the django_foobar/views.py
file in the and write in the following code.
# -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals from django.http import HttpResponse from django.views.generic import View class DeepThoughtView(View): def get(self, request): return HttpResponse(42)
Next, open the tests/settings.py
file and add your module to INSTALLED_APPS
INSTALLED_APPS = ( <snip> 'django_foobar', )
Finally, hook up the view in the tests/urls.py
file.
from django_foobar.views import DeepThoughtView urlpatterns = [ <snip> url(r'^deepthought/$', view=DeepThoughtView.as_view(), name='django_foobar_deepthought'), ]
Testing¶
Django includes a test runner witch can be run by issuing the python manage.py test
command.
However, when writing 3rd party modules I like to use a slightly different approach. It includes creating
a proper setup.py
file, the nose
and tox
testing frameworks.
The setup script¶
Let’s start by creating a setup.py
file. This file will be used to run test suite and later build,
package and upload the module to pypi
.
Make sure you create this file in the projects working directory (next to all the other files we created earlier).
(django-foobar):~/django-foobar$ touch setup.py
We’ll base our setup script on Setuptools.
In order to make this as painless as possible, some nice people has created a bootstrap script for setuptools
which we’ll take advantage of. Download the ez_setup.py
script and place it in the projects working directory.
(django-foobar):~/django-foobar$ curl -O https://bootstrap.pypa.io/ez_setup.py
Once downloaded, open the setup.py
file in a text editor and enter the following code.
import re import os try: from setuptools import setup except ImportError: from ez_setup import use_setuptools use_setuptools() from setuptools import setup setup( name="django-foobar", version="1.0", description="Super awesome portable module for Django", long_description="Here you can elaborate a bit to explain the use case and purpose of the module.", author="John Doe", author_email="john.doe@example.com", url="https://github.com/github-user/django-foobar", download_url="https://github.com/github-user/django-foobar.git", license="MIT License", packages=[ "django_foobar", ], include_package_data=True, install_requires=[ "Django>=1.7.0", ], tests_require=[ "nose", "coverage", ], zip_safe=False, test_suite="tests.runtests.start", classifiers=[ "Operating System :: OS Independent", "Development Status :: 3 - Alpha", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules", ] )
As you can see, this file contains all sorts of useful information about the author of the module,
licensing stuff, development status, etc. More importantly for us now, it contains information about which
libraries are required for installing the library, and which are required for testing the library.
This means, that if you want to run the test suite, all the libraries listed in the tests_require
list will be installed, but if somebody runs pip install django-foobar
, only the libraries which
we actually depends on, listed in install_requires
will be installed (if not already installed).
The important thing here is to know what library versions are the absolute minimum for us to have installed for the library to work. In other words, you should never (or at least rarely) lock library versions in this file, but rather specify that we require version >= (larger than or equal to) some version number. So in the example above, we promise that our code will work with any Django version above v1.7.0.
Note
Keep in mind that you should consider the requirements you specify in this file to be a kind of contract between you as the maintainer and the people which are going to use your code.
You need to write tests in order to fulfill the contract!
Read more about setup.py.
Setting up the test runner¶
Running nose tests¶
In the setup.py
file above, we have specified a test_suite
attribute which points to
tests.runtests.start
. Create a new file called runtests.py
in the tests
project directory,
and enter the following code:
#!/usr/bin/env python from __future__ import absolute_import, print_function, unicode_literals import os import sys import nose def start(argv=None): sys.exitfunc = lambda: sys.stderr.write("Shutting down...\n") if argv is None: argv = [ "nosetests", "--cover-branches", "--with-coverage", "--cover-erase", "--verbose", "--cover-package=django_foobar", ] nose.run_exit(argv=argv, defaultTest=os.path.abspath(os.path.dirname(__file__))) if __name__ == "__main__": start(sys.argv)
Bootstrapping Django for the test runner¶
In order to let the test runner and setup script to be able to run Django tests, we need to initialize
Django before running the tests. Enter the following code into tests/__init__.py
.
from __future__ import absolute_import, unicode_literals import os test_runner = None old_config = None os.environ["DJANGO_SETTINGS_MODULE"] = "tests.settings" import django if hasattr(django, "setup"): django.setup() def setup(): global test_runner global old_config # If you want to support Django 1.5 and older, you need # this try-except block. try: from django.test.runner import DiscoverRunner test_runner = DiscoverRunner() except ImportError: from django.test.simple import DjangoTestSuiteRunner test_runner = DjangoTestSuiteRunner() test_runner.setup_test_environment() old_config = test_runner.setup_databases() def teardown(): test_runner.teardown_databases(old_config) test_runner.teardown_test_environment()
Running the test suite¶
Alright, now we have a good setup for running tests!
We will no longer be writing the tests inside the django_foobar
module, so you can delete the
django_foobar/tests.py
file.
Try running the test suite by running the following command from the working directory:
(django-foobar):~/django-foobar$ python setup.py test running test running egg_info writing pbr to django_foobar.egg-info/pbr.json writing django_foobar.egg-info/PKG-INFO writing top-level names to django_foobar.egg-info/top_level.txt writing dependency_links to django_foobar.egg-info/dependency_links.txt writing requirements to django_foobar.egg-info/requires.txt reading manifest file 'django_foobar.egg-info/SOURCES.txt' writing manifest file 'django_foobar.egg-info/SOURCES.txt' running build_ext Name Stmts Miss Branch BrMiss Cover Missing ---------------------------------------------------------------------- django_foobar 0 0 0 0 100% django_foobar.admin 1 1 0 0 0% 1 django_foobar.migrations 0 0 0 0 100% django_foobar.models 1 1 0 0 0% 1 ---------------------------------------------------------------------- TOTAL 2 2 0 0 0% ---------------------------------------------------------------------- Ran 0 tests in 0.406s OK
As you can see, the setup script builds an egg for us and runs the test suite against it. As we haven’t written any actual test cases yet, it will print out the test coverage and report that zero tests were run.
Writing a test case¶
Start by creating a new file in the tests
directory called test_views.py
. The test runner will
pick up any file prefixed with test_
and run the test cases inside it.
We will write a test case for the DeepThoughtView
we created earlier. Open the tests/test_views.py
file and enter the following code inside:
# -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals from django.core.urlresolvers import reverse from django.test import TestCase class DeepThoughtTestCase(TestCase): def test_deepthought_view(self): response = self.client.get(reverse("django_foobar_deepthought")) self.assertEqual(response.content, b"42")
Alright, lets try running the test suite again!
(django-foobar):~/django-foobar$ python setup.py test running test running egg_info writing pbr to django_foobar.egg-info/pbr.json writing django_foobar.egg-info/PKG-INFO writing top-level names to django_foobar.egg-info/top_level.txt writing requirements to django_foobar.egg-info/requires.txt writing dependency_links to django_foobar.egg-info/dependency_links.txt reading manifest file 'django_foobar.egg-info/SOURCES.txt' writing manifest file 'django_foobar.egg-info/SOURCES.txt' running build_ext test_deepthought_view (tests.test_views.DeepThoughtTestCase) ... ok Name Stmts Miss Branch BrMiss Cover Missing ---------------------------------------------------------------------- django_foobar 0 0 0 0 100% django_foobar.admin 1 1 0 0 0% 1 django_foobar.migrations 0 0 0 0 100% django_foobar.models 1 1 0 0 0% 1 django_foobar.views 6 0 0 0 100% ---------------------------------------------------------------------- TOTAL 8 2 0 0 75% ---------------------------------------------------------------------- Ran 1 test in 0.349s
Sweet, the test runner picked up our test case and reported success!
Testing multiple environments¶
Well, that’s good and all, but at the current state, we only know that our code works as it should on the setup we’re using for our development. What if somebody is running Python v2.7 with Django v1.6? Would it work as it should? We don’t really know, so let’s find out!
Tox to the rescue!¶
Tox is a tool for automate testing in Python. It does so by reading
a tox.ini
file where we specify the environments we want to test, and it will create a brand new
virtual environment for that setup and run the test suite against it.
Let’s start by installing tox
and add it to our requirements.txt
file.
(django-foobar):~/django-foobar$ pip install tox (django-foobar):~/django-foobar$ echo "tox" >> requirements.txt
Create a new file tox.ini
in the projects working directory and paste the content below.
[tox] envlist = py27-django1.6, py34-django1.8 [django1.6] deps = Django>=1.6,<1.7 [django1.8] deps = Django>=1.8,<1.9 [testenv] commands = python {toxinidir}/setup.py test [testenv:py27-django1.6] basepython = python2.7 deps = {[django1.6]deps} [testenv:py34-django1.8] basepython = python3.4 deps = {[django1.8]deps}
As you can see we have a [tox]
block in which we defines a list of environments we want to test.
Next, we define some blocks for the different Django versions we want to test. The [testenv]
block
defines the command we want to run, and finally we combine the [testenv]
with the different version
blocks in order to fire up the test runner.
Note
You need to have all the python interpreters you want to test with installed on your system. If you don’t have Python 2.7 installed, the Python 2.7 tests above will fail!
Now we have two different environments we can test: Python 2.7 with Django 1.6, and Python 3.4 with Django 1.8. Let’s try to fire it up!
(django-foobar):~/django-foobar$ tox <snip> ... ... </snip> py27-django1.6: commands succeeded py34-django1.8: commands succeeded congratulations :)
Great! We are now confident that our code works flawlessly with these configurations.
Continuous Integration¶
Continuous Integration is nice. Alright that was yet another opinionated statement from me, but it makes me happy to see my builds go green =)
Travis is my weapon of choice because all my code goes to Github, and Travis
integrates very easily. Create a new file .travis.yml
in your projects working directory and paste the
following code.
language: python python: - "2.7" cache: directories: - pip_download_cache before_install: - mkdir -p $PIP_DOWNLOAD_CACHE install: - pip install tox - pip install -e . script: - tox -e $TOX_ENV env: global: - PIP_DOWNLOAD_CACHE="pip_download_cache" matrix: - TOX_ENV=py27-django1.6 - TOX_ENV=py34-django1.8 notifications: email: false
As you can read out from the configuration, we’ll be using tox
to run the test suite on Travis as well.
You should be able to recognize the tox
environments we created earlier in the travis configuration above.
Time to make the build!
Head over to Travis and hit the “Sign in with Github” button in the top right corner.
Navigate to your profile and locate the repository list. There should be a a flip switch next to the repository name. Flip it to “On”.
Once the flip is on, Travis will start an automated build whenever a new commit is pushed to the Github repository.
Commit and push new stuff to Github.
(django-foobar):~/django-foobar$ git add * (django-foobar):~/django-foobar$ git commit -m "a brand new commit" (django-foobar):~/django-foobar$ git push -u origin master
Enjoy the build!
Holy cow, it worked!
Documenting your library¶
If you have followed this guide step-by-step, you should already have a docs/
directory in the projects
working directory containing a Sphinx project. If you skipped that step, now is a good
time to go back and create a Documentation project.
Inside the docs/
directory you’ll find a file called conf.py
. This is the configuration file which
Sphinx use to build the documentation. The most important settings should already be added in there by the
sphinx-quickstart
command we used earlier, so we’ll just leave that alone.
Writing documentation¶
Most of the time, the reason for writing 3rd party modules is that we believe we have found a use case for some kind of functionality that is so common and/or generic that we can put in some time and effort now, to save time in the long run. Chances are, that other people might find our module useful too, but we need to tell them (and our future selves) how to use it.
It is therefore crucial that we write good documentation and explain how to use the code.
Index¶
Inside the docs/
directory you’ll find a file called index.rst
. Open it in a text editor and it will
look something like this:
.. test documentation master file, created by sphinx-quickstart on Tue Sep 1 15:01:48 2015. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to django-foobar documentation! ======================================= Contents: .. toctree:: :maxdepth: 2 Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search`
Above the Content
, start writing a short introduction for your library. It could be a few lines about the
intended use case, target audience, a poem or something else.
As an exercise, let’s document how we can run the test suite for our package. Create a new file called
01-testing.rst
next to the index.rst
file and modify the .. toctree::
block so it looks like this:
.. toctree:: :maxdepth: 2 01-testing
01-testing¶
Open the newly created 01-testing.rst
file, and write the following code:
Running the test suite ====================== In order to run the test suite for ``django-foobar`` run the following command from the cli: .. code-block:: none $ python setup.py test You should see the tests complete without errors!
Let’s go through some of the directives we have used above:
- Headlines
Sphinx is pretty good at determining headline levels, but you must be consistent within the file. It is also pretty common to keep a consistent style for the entire documentation project.
========== Headline 1 ========== Headline 2 ========== Headline 3 ---------- Headline 4 ..........
.. code-block:: none
This defines a new code block. The
none
argument provided indicates the syntax highlighting we want to use. When demonstrating commands to be run,none
is usually a good choice, but Sphinx supports a lot of different syntax highlighting, likepython
,ruby
,xml
and so on.
- Inline blocks
By using double backticks ``this is an inline block``, you can create
inline blocks
. They are nice for highlighting important words, class names, and so on.
For a more in-depth guide for writing Sphinx docs, see this guide and the Sphinx primer.
Compile the documentation¶
Okay, we have now written some documentation. Let’s compile it to HTML.
Run the following command from the docs/
directory.
$ make html sphinx-build -b html -d _build/doctrees . _build/html Running Sphinx v1.3.1 loading pickled environment... done building [mo]: targets for 0 po files that are out of date building [html]: targets for 1 source files that are out of date updating environment: 0 added, 1 changed, 0 removed reading sources... [100%] 04-documentation looking for now-outdated files... none found pickling environment... done checking consistency... done preparing documents... done writing output... [100%] index generating indices... genindex writing additional pages... search copying static files... done copying extra files... done dumping search index in English (code: en) ... done dumping object inventory... done build succeeded.
Open the docs/_build/html/index.html
file in your web browser.

Read the Docs¶
Read the Docs is a service for hosting documentation. It’s free for open source projects, so we’ll set it up to host the documentation for us. It can be activated as a Github hook like the Travis CI hook, which means that every time we commit changes to the Github repository the documentation will be rebuilt.
Head over to Read the Docs <https://readthedocs.org/> and create an account
From the drop down menu in the top right corner, click “Add project”
Click the “Import from Github” button
Fill in some details
Authenticate with Github if asked, and accept adding the webhook
Done =)
Pack and deploy your masterpiece!¶
Finally, we’re ready to release our little gem into the wild. In order to let users install the library using pip
,
we must upload it to the Python Package Index. Head over there and create an
account.

Next, create a new file called .pypirc
in your $HOME
directory. Put the following content in it.
Replace the username
and password
with the ones you used when creating your account.
# this tells distutils what package indexes you can push to
[distutils]
index-servers =
pypi
[pypi]
repository: https://pypi.python.org/pypi
username: johndoe
password: <your secret password>
Push the library to PyPi¶
Note
This is only meant as a guide line for how to push packages to PyPi. Anybody with a valid account can push content there, however; it might not be such a good idea to push all sorts of useless libraries out there.
The
django-foobar
library written in this guide is a pretty useless library, so it’s no reason to actually push it! Use this as a reference when you have written a real library =)
The manifest file¶
The manifest file specifies what files we want to include in the source distribution we’re going to upload
to PyPi. Go ahead and create a new file called MANIFEST.in
in your projects working directory and put the
following content in it.
include README.rst include LICENSE.txt include requirements.txt include tox.ini recursive-include docs Makefile *.rst *.py *.bat recursive-include tests *.py *.json *.txt
This is a pretty generic template but will be sufficient for most Django projects. You can read more about the MANIFEST.in file here.
Registering your library¶
If you want to reserve the name for your library, but are not quite ready to distribute it yet you can register
the name on PyPi. We’re going to use the setup.py
script we wrote earlier so make sure your current path is
in the projects working directory.
(django-foobar):~/django-foobar$ python setup.py register unning register running egg_info writing pbr to django_foobar.egg-info/pbr.json writing requirements to django_foobar.egg-info/requires.txt writing django_foobar.egg-info/PKG-INFO writing top-level names to django_foobar.egg-info/top_level.txt writing dependency_links to django_foobar.egg-info/dependency_links.txt reading manifest file 'django_foobar.egg-info/SOURCES.txt' writing manifest file 'django_foobar.egg-info/SOURCES.txt' running check Registering django-foobar to https://pypi.python.org/pypi Server response (200): OK
Your library are now registered in the Python Package Index!
Uploading your library¶
In order to upload a source distribution, enter the following command:
(django-foobar):~/django-foobar$ python setup.py sdist upload running sdist running egg_info writing pbr to django_foobar.egg-info/pbr.json writing top-level names to django_foobar.egg-info/top_level.txt writing django_foobar.egg-info/PKG-INFO writing dependency_links to django_foobar.egg-info/dependency_links.txt writing requirements to django_foobar.egg-info/requires.txt reading manifest file 'django_foobar.egg-info/SOURCES.txt' writing manifest file 'django_foobar.egg-info/SOURCES.txt' running check creating django-foobar-1.0 creating django-foobar-1.0/django_foobar creating django-foobar-1.0/django_foobar.egg-info making hard links in django-foobar-1.0... hard linking README.rst -> django-foobar-1.0 hard linking setup.py -> django-foobar-1.0 hard linking django_foobar/__init__.py -> django-foobar-1.0/django_foobar hard linking django_foobar/admin.py -> django-foobar-1.0/django_foobar hard linking django_foobar/models.py -> django-foobar-1.0/django_foobar hard linking django_foobar/tests.py -> django-foobar-1.0/django_foobar hard linking django_foobar/views.py -> django-foobar-1.0/django_foobar hard linking django_foobar.egg-info/PKG-INFO -> django-foobar-1.0/django_foobar.egg-info hard linking django_foobar.egg-info/SOURCES.txt -> django-foobar-1.0/django_foobar.egg-info hard linking django_foobar.egg-info/dependency_links.txt -> django-foobar-1.0/django_foobar.egg-info hard linking django_foobar.egg-info/not-zip-safe -> django-foobar-1.0/django_foobar.egg-info hard linking django_foobar.egg-info/pbr.json -> django-foobar-1.0/django_foobar.egg-info hard linking django_foobar.egg-info/requires.txt -> django-foobar-1.0/django_foobar.egg-info hard linking django_foobar.egg-info/top_level.txt -> django-foobar-1.0/django_foobar.egg-info Writing django-foobar-1.0/setup.cfg creating dist Creating tar archive removing 'django-foobar-1.0' (and everything under it) running upload Submitting dist/django-foobar-1.0.tar.gz to https://pypi.python.org/pypi Server response (200): OK
Congratulations, you have just released a 3rd party Django module on PyPi. It may be a little while before the
library is visible for pip
.
Conclusion¶
During this guide, we have been through creating a working environment, how to structure your project, setting up a test environment suitable for doing Continuous Integration development , writing documentation and deploying the library to PyPi.
This is by no means a definite solution for all kind of projects, and a lot of topics covered here can be done in different ways. As you gain experience, you’ll probably find things in this guide that doesn’t suite your style of development or other things that work better for you or the project you are working on.
But by now you should be able to a project with a basic workflow that allows other people to contribute.
Have fun!