diff options
| author | Jannis Leidel <jannis@leidel.info> | 2011-05-27 10:49:47 +0000 |
|---|---|---|
| committer | Jannis Leidel <jannis@leidel.info> | 2011-05-27 10:49:47 +0000 |
| commit | 407f62fd31689b6158902d3ffdcde64aa27679a7 (patch) | |
| tree | 3d7b05bf64e764ba7a67df59f5ec49fdf17787d0 /docs/internals/contributing/writing-code | |
| parent | 69cfee2f167f64c15de6bfcd6b9779534132db2f (diff) | |
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
Diffstat (limited to 'docs/internals/contributing/writing-code')
5 files changed, 712 insertions, 0 deletions
diff --git a/docs/internals/contributing/writing-code/branch-policy.txt b/docs/internals/contributing/writing-code/branch-policy.txt new file mode 100644 index 0000000000..08dfe8bc76 --- /dev/null +++ b/docs/internals/contributing/writing-code/branch-policy.txt @@ -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 diff --git a/docs/internals/contributing/writing-code/coding-style.txt b/docs/internals/contributing/writing-code/coding-style.txt new file mode 100644 index 0000000000..616550dcef --- /dev/null +++ b/docs/internals/contributing/writing-code/coding-style.txt @@ -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/ diff --git a/docs/internals/contributing/writing-code/index.txt b/docs/internals/contributing/writing-code/index.txt new file mode 100644 index 0000000000..bd9b2a346a --- /dev/null +++ b/docs/internals/contributing/writing-code/index.txt @@ -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 diff --git a/docs/internals/contributing/writing-code/submitting-patches.txt b/docs/internals/contributing/writing-code/submitting-patches.txt new file mode 100644 index 0000000000..4eb74e1b1e --- /dev/null +++ b/docs/internals/contributing/writing-code/submitting-patches.txt @@ -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 diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt new file mode 100644 index 0000000000..fd9024e1a9 --- /dev/null +++ b/docs/internals/contributing/writing-code/unit-tests.txt @@ -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 |
