Fixed #15796 -- Restructured the contributing documentation and added note about newly added Trac abilities. Many thanks to Julien Phalip.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16284 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2011-05-27 10:49:47 +00:00
parent 69cfee2f16
commit 407f62fd31
18 changed files with 1806 additions and 1750 deletions

View file

@ -0,0 +1,180 @@
=============
Branch policy
=============
In general, the trunk must be kept stable. People should be able to run
production sites against the trunk at any time. Additionally, commits to trunk
ought to be as atomic as possible -- smaller changes are better. Thus, large
feature changes -- that is, changes too large to be encapsulated in a single
patch, or changes that need multiple eyes on them -- must happen on dedicated
branches.
This means that if you want to work on a large feature -- anything that would
take more than a single patch, or requires large-scale refactoring -- you need
to do it on a feature branch. Our development process recognizes two options
for feature branches:
1. Feature branches using a distributed revision control system like
Git_, Mercurial_, Bazaar_, etc.
If you're familiar with one of these tools, this is probably your best
option since it doesn't require any support or buy-in from the Django
core developers.
However, do keep in mind that Django will continue to use Subversion
for the foreseeable future, and this will naturally limit the
recognition of your branch. Further, if your branch becomes eligible
for merging to trunk you'll need to find a core developer familiar
with your DVCS of choice who'll actually perform the merge.
If you do decided to start a distributed branch of Django and choose to
make it public, please add the branch to the `Django branches`_ wiki
page.
2. Feature branches using SVN have a higher bar. If you want a branch
in SVN itself, you'll need a "mentor" among the :doc:`core committers
</internals/committers>`. This person is responsible for actually
creating the branch, monitoring your process (see below), and
ultimately merging the branch into trunk.
If you want a feature branch in SVN, you'll need to ask in
`django-developers`_ for a mentor.
.. _git: http://git-scm.com/
.. _mercurial: http://mercurial.selenic.com/
.. _bazaar: http://bazaar.canonical.com/
.. _django branches: http://code.djangoproject.com/wiki/DjangoBranches
Branch rules
------------
We've got a few rules for branches born out of experience with what makes a
successful Django branch.
DVCS branches are obviously not under central control, so we have no way of
enforcing these rules. However, if you're using a DVCS, following these rules
will give you the best chance of having a successful branch (read: merged back
to trunk).
Developers with branches in SVN, however, **must** follow these rules. The
branch mentor will keep on eye on the branch and **will delete it** if these
rules are broken.
* Only branch entire copies of the Django tree, even if work is only
happening on part of that tree. This makes it painless to switch to a
branch.
* Merge changes from trunk no less than once a week, and preferably every
couple-three days.
In our experience, doing regular trunk merges is often the difference
between a successful branch and one that fizzles and dies.
If you're working on an SVN branch, you should be using `svnmerge.py`_
to track merges from trunk.
* Keep tests passing and documentation up-to-date. As with patches,
we'll only merge a branch that comes with tests and documentation.
.. _svnmerge.py: http://www.orcaware.com/svn/wiki/Svnmerge.py
Once the branch is stable and ready to be merged into the trunk, alert
`django-developers`_.
After a branch has been merged, it should be considered "dead"; write access
to it will be disabled, and old branches will be periodically "trimmed."
To keep our SVN wrangling to a minimum, we won't be merging from a given
branch into the trunk more than once.
Using branches
--------------
To use a branch, you'll need to do two things:
* Get the branch's code through Subversion.
* Point your Python ``site-packages`` directory at the branch's version of
the ``django`` package rather than the version you already have
installed.
Getting the code from Subversion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To get the latest version of a branch's code, check it out using Subversion:
.. code-block:: bash
svn co http://code.djangoproject.com/svn/django/branches/<branch>/
...where ``<branch>`` is the branch's name. See the `list of branch names`_.
Alternatively, you can automatically convert an existing directory of the
Django source code as long as you've checked it out via Subversion. To do the
conversion, execute this command from within your ``django`` directory:
.. code-block:: bash
svn switch http://code.djangoproject.com/svn/django/branches/<branch>/
The advantage of using ``svn switch`` instead of ``svn co`` is that the
``switch`` command retains any changes you might have made to your local copy
of the code. It attempts to merge those changes into the "switched" code. The
disadvantage is that it may cause conflicts with your local changes if the
"switched" code has altered the same lines of code.
(Note that if you use ``svn switch``, you don't need to point Python at the
new version, as explained in the next section.)
.. _list of branch names: http://code.djangoproject.com/browser/django/branches
.. _pointing-python-at-the-new-django-version:
Pointing Python at the new Django version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once you've retrieved the branch's code, you'll need to change your Python
``site-packages`` directory so that it points to the branch version of the
``django`` directory. (The ``site-packages`` directory is somewhere such as
``/usr/lib/python2.4/site-packages`` or
``/usr/local/lib/python2.4/site-packages`` or ``C:\Python\site-packages``.)
The simplest way to do this is by renaming the old ``django`` directory to
``django.OLD`` and moving the trunk version of the code into the directory
and calling it ``django``.
Alternatively, you can use a symlink called ``django`` that points to the
location of the branch's ``django`` package. If you want to switch back, just
change the symlink to point to the old code.
A third option is to use a `path file`_ (``<something>.pth``) which should
work on all systems (including Windows, which doesn't have symlinks
available). First, make sure there are no files, directories or symlinks named
``django`` in your ``site-packages`` directory. Then create a text file named
``django.pth`` and save it to your ``site-packages`` directory. That file
should contain a path to your copy of Django on a single line and optional
comments. Here is an example that points to multiple branches. Just uncomment
the line for the branch you want to use ('Trunk' in this example) and make
sure all other lines are commented::
# Trunk is a svn checkout of:
# http://code.djangoproject.com/svn/django/trunk/
#
/path/to/trunk
# <branch> is a svn checkout of:
# http://code.djangoproject.com/svn/django/branches/<branch>/
#
#/path/to/<branch>
# On windows a path may look like this:
# C:/path/to/<branch>
If you're using Django 0.95 or earlier and installed it using
``python setup.py install``, you'll have a directory called something like
``Django-0.95-py2.4.egg`` instead of ``django``. In this case, edit the file
``setuptools.pth`` and remove the line that references the Django ``.egg``
file. Then copy the branch's version of the ``django`` directory into
``site-packages``.
.. _path file: http://docs.python.org/library/site.html
.. _django-developers: http://groups.google.com/group/django-developers

View file

@ -0,0 +1,190 @@
============
Coding Style
============
Please follow these coding standards when writing code for inclusion in Django.
Python style
------------
* Unless otherwise specified, follow :pep:`8`.
You could use a tool like `pep8.py`_ to check for some problems in this
area, but remember that PEP 8 is only a guide, so respect the style of
the surrounding code as a primary goal.
* Use four spaces for indentation.
* Use underscores, not camelCase, for variable, function and method names
(i.e. ``poll.get_unique_voters()``, not ``poll.getUniqueVoters``).
* Use ``InitialCaps`` for class names (or for factory functions that
return classes).
* In docstrings, use "action words" such as::
def foo():
"""
Calculates something and returns the result.
"""
pass
Here's an example of what not to do::
def foo():
"""
Calculate something and return the result.
"""
pass
Template style
--------------
* In Django template code, put one (and only one) space between the curly
brackets and the tag contents.
Do this:
.. code-block:: html+django
{{ foo }}
Don't do this:
.. code-block:: html+django
{{foo}}
View style
----------
* In Django views, the first parameter in a view function should be called
``request``.
Do this::
def my_view(request, foo):
# ...
Don't do this::
def my_view(req, foo):
# ...
Model style
-----------
* Field names should be all lowercase, using underscores instead of
camelCase.
Do this::
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=40)
Don't do this::
class Person(models.Model):
FirstName = models.CharField(max_length=20)
Last_Name = models.CharField(max_length=40)
* The ``class Meta`` should appear *after* the fields are defined, with
a single blank line separating the fields and the class definition.
Do this::
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=40)
class Meta:
verbose_name_plural = 'people'
Don't do this::
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=40)
class Meta:
verbose_name_plural = 'people'
Don't do this, either::
class Person(models.Model):
class Meta:
verbose_name_plural = 'people'
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=40)
* The order of model inner classes and standard methods should be as
follows (noting that these are not all required):
* All database fields
* Custom manager attributes
* ``class Meta``
* ``def __unicode__()``
* ``def __str__()``
* ``def save()``
* ``def get_absolute_url()``
* Any custom methods
* If ``choices`` is defined for a given model field, define the choices as
a tuple of tuples, with an all-uppercase name, either near the top of
the model module or just above the model class. Example::
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
Use of ``django.conf.settings``
-------------------------------
Modules should not in general use settings stored in ``django.conf.settings``
at the top level (i.e. evaluated when the module is imported). The explanation
for this is as follows:
Manual configuration of settings (i.e. not relying on the
``DJANGO_SETTINGS_MODULE`` environment variable) is allowed and possible as
follows::
from django.conf import settings
settings.configure({}, SOME_SETTING='foo')
However, if any setting is accessed before the ``settings.configure`` line,
this will not work. (Internally, ``settings`` is a ``LazyObject`` which
configures itself automatically when the settings are accessed if it has not
already been configured).
So, if there is a module containing some code as follows::
from django.conf import settings
from django.core.urlresolvers import get_callable
default_foo_view = get_callable(settings.FOO_VIEW)
...then importing this module will cause the settings object to be configured.
That means that the ability for third parties to import the module at the top
level is incompatible with the ability to configure the settings object
manually, or makes it very difficult in some circumstances.
Instead of the above code, a level of laziness or indirection must be used,
such as `django.utils.functional.LazyObject``, ``django.utils.functional.lazy``
or ``lambda``.
Miscellaneous
-------------
* Mark all strings for internationalization; see the :doc:`i18n
documentation </topics/i18n/index>` for details.
* Please don't put your name in the code you contribute. Our policy is to
keep contributors' names in the ``AUTHORS`` file distributed with Django
-- not scattered throughout the codebase itself. Feel free to include a
change to the ``AUTHORS`` file in your patch if you make more than a
single trivial change.
.. _pep8.py: http://pypi.python.org/pypi/pep8/

View file

@ -0,0 +1,15 @@
============
Writing code
============
So you'd like to write some code to improve Django. Awesome! Browse the
following sections to find out how to give your code patches the best
chances to be included in Django core:
.. toctree::
:maxdepth: 1
coding-style
unit-tests
submitting-patches
branch-policy

View file

@ -0,0 +1,160 @@
==================
Submitting patches
==================
We're always grateful for patches to Django's code. Indeed, bug reports
with associated patches will get fixed *far* more quickly than those
without patches.
"Claiming" tickets
------------------
In an open-source project with hundreds of contributors around the world, it's
important to manage communication efficiently so that work doesn't get
duplicated and contributors can be as effective as possible. Hence, our policy
is for contributors to "claim" tickets in order to let other developers know
that a particular bug or feature is being worked on.
If you have identified a contribution you want to make and you're capable of
fixing it (as measured by your coding ability, knowledge of Django internals
and time availability), claim it by following these steps:
* `Create an account`_ to use in our ticket system. If you have an account
but have forgotten your password, you can reset it using the
`password reset page`_.
* If a ticket for this issue doesn't exist yet, create one in our
`ticket tracker`_.
* If a ticket for this issue already exists, make sure nobody else has
claimed it. To do this, look at the "Assigned to" section of the ticket.
If it's assigned to "nobody," then it's available to be claimed.
Otherwise, somebody else is working on this ticket, and you either find
another bug/feature to work on, or contact the developer working on the
ticket to offer your help.
* Log into your account, if you haven't already, by clicking "Login" in
the upper right of the ticket page.
* Claim the ticket by clicking the radio button next to "Accept ticket"
near the bottom of the page, then clicking "Submit changes."
.. _Create an account: https://www.djangoproject.com/accounts/register/
.. _password reset page: https://www.djangoproject.com/accounts/password/reset/
Ticket claimers' responsibility
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once you've claimed a ticket, you have a responsibility to work on that ticket
in a reasonably timely fashion. If you don't have time to work on it, either
unclaim it or don't claim it in the first place!
If there's no sign of progress on a particular claimed ticket for a week or
two, another developer may ask you to relinquish the ticket claim so that it's
no longer monopolized and somebody else can claim it.
If you've claimed a ticket and it's taking a long time (days or weeks) to code,
keep everybody updated by posting comments on the ticket. If you don't provide
regular updates, and you don't respond to a request for a progress report,
your claim on the ticket may be revoked. As always, more communication is
better than less communication!
Which tickets should be claimed?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Of course, going through the steps of claiming tickets is overkill in some
cases. In the case of small changes, such as typos in the documentation or
small bugs that will only take a few minutes to fix, you don't need to jump
through the hoops of claiming tickets. Just submit your patch and be done with
it.
.. _patch-style:
Patch style
-----------
* Make sure your code matches our :doc:`coding-style`.
* Submit patches in the format returned by the ``svn diff`` command.
An exception is for code changes that are described more clearly in
plain English than in code. Indentation is the most common example; it's
hard to read patches when the only difference in code is that it's
indented.
Patches in ``git diff`` format are also acceptable.
* When creating patches, always run ``svn diff`` from the top-level
``trunk`` directory -- i.e., the one that contains ``django``, ``docs``,
``tests``, ``AUTHORS``, etc. This makes it easy for other people to
apply your patches.
* Attach patches to a ticket in the `ticket tracker`_, using the "attach
file" button. Please *don't* put the patch in the ticket description
or comment unless it's a single line patch.
* Name the patch file with a ``.diff`` extension; this will let the ticket
tracker apply correct syntax highlighting, which is quite helpful.
* Check the "Has patch" box on the ticket details. This will make it
obvious that the ticket includes a patch, and it will add the ticket to
the `list of tickets with patches`_.
* The code required to fix a problem or add a feature is an essential part
of a patch, but it is not the only part. A good patch should also
include a regression test to validate the behavior that has been fixed
(and prevent the problem from arising again).
* If the code associated with a patch adds a new feature, or modifies
behavior of an existing feature, the patch should also contain
documentation.
Non-trivial patches
-------------------
A "non-trivial" patch is one that is more than a simple bug fix. It's a patch
that introduces Django functionality and makes some sort of design decision.
If you provide a non-trivial patch, include evidence that alternatives have
been discussed on `django-developers`_. If you're not sure whether your patch
should be considered non-trivial, just ask.
Javascript patches
------------------
.. versionadded:: 1.2
Django's admin system leverages the jQuery framework to increase the
capabilities of the admin interface. In conjunction, there is an emphasis on
admin javascript performance and minimizing overall admin media file size.
Serving compressed or "minified" versions of javascript files is considered
best practice in this regard.
To that end, patches for javascript files should include both the original
code for future development (e.g. "foo.js"), and a compressed version for
production use (e.g. "foo.min.js"). Any links to the file in the codebase
should point to the compressed version.
To simplify the process of providing optimized javascript code, Django
includes a handy script which should be used to create a "minified" version.
This script is located at ``/contrib/admin/media/js/compress.py``.
Behind the scenes, ``compress.py`` is a front-end for Google's
`Closure Compiler`_ which is written in Java. However, the Closure Compiler
library is not bundled with Django directly, so those wishing to contribute
complete javascript patches will need to download and install the library
independently.
The Closure Compiler library requires Java version 6 or higher (Java 1.6 or
higher on Mac OS X). Note that Mac OS X 10.5 and earlier did not ship with
Java 1.6 by default, so it may be necessary to upgrade your Java installation
before the tool will be functional. Also note that even after upgrading Java,
the default `/usr/bin/java` command may remain linked to the previous Java
binary, so relinking that command may be necessary as well.
Please don't forget to run ``compress.py`` and include the ``diff`` of the
minified scripts when submitting patches for Django's javascript.
.. _Closure Compiler: http://code.google.com/closure/compiler/
.. _django-developers: http://groups.google.com/group/django-developers
.. _list of tickets with patches: http://code.djangoproject.com/query?status=new&status=assigned&status=reopened&has_patch=1&order=priority
.. _ticket tracker: http://code.djangoproject.com/newticket

View file

@ -0,0 +1,167 @@
==========
Unit tests
==========
Django comes with a test suite of its own, in the ``tests`` directory of the
Django tarball. It's our policy to make sure all tests pass at all times.
The tests cover:
* Models and the database API (``tests/modeltests/``).
* Everything else in core Django code (``tests/regressiontests``)
* Contrib apps (``django/contrib/<contribapp>/tests``, see below)
We appreciate any and all contributions to the test suite!
The Django tests all use the testing infrastructure that ships with Django for
testing applications. See :doc:`Testing Django applications </topics/testing>`
for an explanation of how to write new tests.
.. _running-unit-tests:
Running the unit tests
----------------------
Quickstart
~~~~~~~~~~
Running the tests requires a Django settings module that defines the
databases to use. To make it easy to get started. Django provides a
sample settings module that uses the SQLite database. To run the tests
with this sample ``settings`` module, ``cd`` into the Django
``tests/`` directory and run:
.. code-block:: bash
./runtests.py --settings=test_sqlite
If you get an ``ImportError: No module named django.contrib`` error,
you need to add your install of Django to your ``PYTHONPATH``. For
more details on how to do this, read
:ref:`pointing-python-at-the-new-django-version`.
Using another ``settings`` module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The included settings module allows you to run the test suite using
SQLite. If you want to test behavior using a different database (and
if you're proposing patches for Django, it's a good idea to test
across databases), you may need to define your own settings file.
To run the tests with different settings, ``cd`` to the ``tests/`` directory
and type:
.. code-block:: bash
./runtests.py --settings=path.to.django.settings
The :setting:`DATABASES` setting in this test settings module needs to define
two databases:
* A ``default`` database. This database should use the backend that
you want to use for primary testing
* A database with the alias ``other``. The ``other`` database is
used to establish that queries can be directed to different
databases. As a result, this database can use any backend you
want. It doesn't need to use the same backend as the ``default``
database (although it can use the same backend if you want to).
If you're using a backend that isn't SQLite, you will need to provide other
details for each database:
* The :setting:`USER` option for each of your databases needs to
specify an existing user account for the database.
* The :setting:`PASSWORD` option needs to provide the password for
the :setting:`USER` that has been specified.
* The :setting:`NAME` option must be the name of an existing database to
which the given user has permission to connect. The unit tests will not
touch this database; the test runner creates a new database whose name
is :setting:`NAME` prefixed with ``test_``, and this test database is
deleted when the tests are finished. This means your user account needs
permission to execute ``CREATE DATABASE``.
You will also need to ensure that your database uses UTF-8 as the default
character set. If your database server doesn't use UTF-8 as a default charset,
you will need to include a value for ``TEST_CHARSET`` in the settings
dictionary for the applicable database.
Running only some of the tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Django's entire test suite takes a while to run, and running every single test
could be redundant if, say, you just added a test to Django that you want to
run quickly without running everything else. You can run a subset of the unit
tests by appending the names of the test modules to ``runtests.py`` on the
command line.
For example, if you'd like to run tests only for generic relations and
internationalization, type:
.. code-block:: bash
./runtests.py --settings=path.to.settings generic_relations i18n
How do you find out the names of individual tests? Look in
``tests/modeltests`` and ``tests/regressiontests`` -- each directory name
there is the name of a test.
If you just want to run a particular class of tests, you can specify a list of
paths to individual test classes. For example, to run the ``TranslationTests``
of the ``i18n`` module, type:
.. code-block:: bash
./runtests.py --settings=path.to.settings i18n.TranslationTests
Going beyond that, you can specify an individual test method like this:
.. code-block:: bash
./runtests.py --settings=path.to.settings i18n.TranslationTests.test_lazy_objects
Running all the tests
~~~~~~~~~~~~~~~~~~~~~
If you want to run the full suite of tests, you'll need to install a number of
dependencies:
* PyYAML_
* Markdown_
* Textile_
* Docutils_
* setuptools_
* memcached_, plus a :ref:`supported Python binding <memcached>`
* gettext_ (:ref:`gettext_on_windows`)
If you want to test the memcached cache backend, you'll also need to define
a :setting:`CACHES` setting that points at your memcached instance.
Each of these dependencies is optional. If you're missing any of them, the
associated tests will be skipped.
.. _PyYAML: http://pyyaml.org/wiki/PyYAML
.. _Markdown: http://pypi.python.org/pypi/Markdown/1.7
.. _Textile: http://pypi.python.org/pypi/textile
.. _docutils: http://pypi.python.org/pypi/docutils/0.4
.. _setuptools: http://pypi.python.org/pypi/setuptools/
.. _memcached: http://www.danga.com/memcached/
.. _gettext: http://www.gnu.org/software/gettext/manual/gettext.html
Contrib apps
------------
Tests for apps in ``django/contrib/`` go in their respective directories under
``django/contrib/``, in a ``tests.py`` file. (You can split the tests over
multiple modules by using a ``tests`` directory in the normal Python way.)
For the tests to be found, a ``models.py`` file must exist (it doesn't
have to have anything in it). If you have URLs that need to be
mapped, put them in ``tests/urls.py``.
To run tests for just one contrib app (e.g. ``markup``), use the same
method as above::
./runtests.py --settings=settings markup