Style Guidelines

This document is based on the WebWare style guidelines (however there are some important differences in approach)

Introduction

Style refers to various aspects of coding including indentation practices, naming conventions, use of design patterns, treatment of constants, etc. We aims to maintain fairly consistent coding style with respect to certain basics as described in this document.

This document is therefore very important for those who routinely develop using Python Web Project libraries or who wish to contribute code.

Consistent source code style conventions are important for several reasons:

  • Consistent conventions reduce the learning curve because users know what to expect from the API.
  • Python Web Project code is open source resulting in many people reading the code in an attempt to understand it, extend it and debug it.
  • The Python Web Project consists of tens of thousands of lines of source code and will undoubtedly continue to grow.

This document divides the conventions into three major categories:

  1. Syntax and Naming
  2. Structure and Patterns
  3. Miscellaneous

Syntax and Naming

Methods and Attributes

Methods and attributes are an important topic because they are used so frequently and therefore have an impact on using the classes, learning them, remembering them, etc.

The first thing that is important to understand is that Python Web Project code is constructed in an object-oriented fashion. This means it is esay to delve right into the heart of the code and create your own classes with slightly different functionality. Most of the time the interfaces documented in the documentation are the easiest to use.

The primary advantages of using methods are:

  • Method implementations can be changed with minimal impact on the users of the class.
  • Subclasses can customize methods to suit their needs and still be used in the usual fashion (as defined by the superclass).

In the case of a method that returns a value, that value may manifest in several ways:

  1. Stored as attribute.
  2. Stored as an attribute, only on demand. (e.g., lazy and cached)
  3. Computed upon every request.
  4. Delegated to another object.

The Python Web Project code stores such information in attributes. This is different from the approach you would take in Java or using WebWare for example.

The advantages of this approach is that code is simpler. Writing form.name is much more intuitive than form.getName() for example and form.name = 'myForm' is more intuitive than form.setName('myForm').

Validating the values being set or performing other operations once a value is set can be done using the Python 2.2 and above property() built-in function. In this way you gain the advantages of all the options listed above.

Abbreviations

Using abbreviations is a common coding practice to reduce typing and make lines shorter. However, removing random characters to abbreviate is a poor way to go about this. For example, transaction could be abbreviated as trnsact or trnsactn, but which letters are left out is not obvious or easy to remember.

In Python Web Project code the general rule is don't abbreviate. If there isn't an extremly obvious and well-used abbreviation for the word to be abbreviated then no abbreviation is made. It doesn't take long to type a few extra characters but it does take time to think about which characters need to be left out of an abbreviation.

Compound Names

Identifiers often consist of multiple names. There are three major styles for handling compound names:

  1. serverSidePath - the Python Web Project convention
  2. serversidepath
  3. server_side_path

Python itself uses all three styles (has_key, getattr, isSet), but the Python Web Project uses only the first which is more readable than the second and easier to type that the third.

This rule also applies to class names such as AuthDatabase and SessionBase.

If identifiers contain an well known acronym then the acronym should be considered a lower case word not upper case as this would confuse with class names which should always start with a capital letter. For example sqlToValue() would be a correct name for a method or function but SqlToValue() and SQLToValue() would not be correct. For a class name the acronym can be used in uppercase eg HTTPServer.

Rules

  • Filenames are lowercase. This is in line with most unix command line utilities and makes imports look more natural.
    Examples: myClass.py session.py
    Negatives: Session.py Template.cgi HTTPServlet.py
  • Line endings are always just POSIX \r and files should be uploaded from Windows in binary mode to make sure the linefeeds aren't tampered with by FTP software.
  • Spaces are used for all indentation, no tabs are used. All indentation should be done with 4 spaces.
    Class names start with a capital letter. For consistency and to make class names prominent in source code. This convention is used in almost every object-oriented language.
    Examples: Servlet HTTPServlet ThreadedAppServer
    Negatives: servlet myClass
  • Method names start with a lower case letter. For consistency and easy of typing. This convention is also used in almost every object-oriented language.
    Examples: respond() isSecure() setTimeout() htForDict()
    Negatives: Respond() IsSecure()
  • Method names do not start with get.
    Examples: status() numRequests()
    Negatives: getStatus() getNumRequests()
  • Data attributes and method attributes used in the internal workings of a class and which are not designed to be accessed by users of the class start with an underscore (_). attributes and methods do not end with an underscore and no functions or attributes use two leading underscores.
    Examples: self._status self._numRequests()
    Negatives: self.status self.__numRequests()
  • Method and attribute names have no underscores after the first character. Capitalization is used instead.
    Examples: self.numRequests() factory.servletForTransaction()
    Negatives: self.num_requests() factory.servlet_for_transaction()
  • Expressions following if, while and return are not enclosed in parentheses. Because this isn't C or Perl. :-)
    Examples: if serialNum>0:
    Negatives: if (serialNum>0):
  • Class definitions and category comments,
    ###
    # Like this
    #
    are preceded by 2 blank lines and followed by one (unless the class implementation is pass to help with spacing and readability.

Structure and Patterns

Classes

Python Web Project Code use classes extensively for the following reasons:

  • Classes allow for subclassing and therefore, a proven method of software extension and customization.
  • Classes allow for creating multiple instances (or objects) to be used in various ways. Examples include caching created objects for increased performance and created multi-threaded servers.
  • Classes can provide for and encourage encapsulation of data, which gives implementers more freedom to improve their software without breaking what depends on it.

By using classes, all three options above are available to the developer on an on-going basis. By using collections of functions, none of the above are readily available.

Note that making classes in Python is extraordinarily easy. Doing so requires one line:

class Foo(SuperFoo):

and the use of self when accessing attributes and methods. The difference in time between creating a class with several methods vs. a set of several functions is essentially zero.

Dictionary-Style Access

Several classes in the Python Web Project code can be thought of in terms of objects keyed by their name. These objects support dictionary-style access but also support a functional interface to the data.

For example the web.form.Form class allows the fields to be accessed in two ways form['fieldName'] or form.get('fieldName'). Python Web Project objects do not use attribute style access. form.fieldName is not used as it is ambigous whether fieldName is to be interpreted as a field or an attribute.

Miscellaneous Notes

If it is obvious that a particular style is being used in a particular source doucment and that style doesn't contridict these style guidelines then that style should be followed.

Permissions

When creating standalone Python programs, you should make them executable by all (chmod a+X filename.py) and must first check them in on UNIX. Otherwise UNIX-based developers using CVS will not have execute permissions by default. Also, that problem cannot be fixed by changing the permissions and committing. Instead, a support request must be made to modify the CVS repository.

Breaking the Rules

Of course, there are times when the rules are broken for good reason. To quote a cliche: "Part of being an expert is knowing when to break the rules."

But regarding style, Python Web Project developers do this very infrequently for the reasons stated in the introduction.