Style refers to various aspects of coding including indentation practices, naming conventions, use of design patterns, treatment of constants, etc. One of the goals of Webware is 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 Webware or who wish to contribute code, although ordinary users may still find it interesting and useful in understanding the Webware APIs.
Consistent source code style conventions are important for several reasons:
This document divides the conventions into three major categories:
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 Webware is constructed in an object-oriented fashion, including full encapsulation of object attributes. In other words, you communicate and use objects completely via their methods (except that classes and subclasses access their own attributes – somebody's got to).
The primary advantages of using methods are:
In the case of a method that returns a value, that value may manifest in several ways:
By requiring that object access is done solely through methods, the implementer of the class is free to switch between the techniques above.
Keeping that in mind, it is apparent that naming conventions are needed for attributes, the methods that return them and the methods that set them. Let's suppose the basic "thing" is status
. The convention then is:
_status
- the attributestatus()
- the retrieval methodsetStatus()
- the setter methodThe underscore that precedes the attribute denotes that it is semi-private and allows for a cleanly named retrieval method. The status()
and setStatus()
convention originated many years ago with Smalltalk and proved successful with that language as well as others, including Objective-C.
Some styles prefix the retrieval method with get
, but Webware does not for the sake of brevity and because there are methods for which it is not always clear if a get
prefix would make sense.
Methods that return a Boolean are prefixed with is
or has
to make their semantics more obvious. Examples include request.isSecure()
, user.isActive()
and response.hasHeader()
.
Webware classes divide their methods into logical groups called categories purely for organizational purposes. This often helps in understanding the interface of a class, especially when looking at its summary.
Upon installation, Webware generates HTML summaries for each Python source file. See the summary of WebKit.HTTPResponse for an example.
By convention, a category is named with a comment beginning and ending with two pound signs, ##
, with two blanks lines before and one blank line after.
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.
The typical technique in Webware is to use the first whole syllable of the word. For example, trans
is easy to remember, pronounce and type.
Attributes and methods that return the number of some kind of object are quite common. Suppose that the objects in questions are requests. Possible styles include numRequests
, numberOfRequests
, requestCount
and so on. Webware uses the first style in all cases, for consistency:
numRequests
If there is a corresponding attribute, it should have the same name (prefixed by an underscore).
Identifiers often consist of multiple names. There are three major styles for handling compound names:
serverSidePath
- the Webware conventionserversidepath
server_side_path
Python itself uses all three styles (has_key
, getattr
, isSet
), but Webware 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 HTTPRequest
and ServletFactory
.
Names of object-oriented Webware components are often suffixed with Kit, as in WebKit and MiddleKit.
The occasional component that serves as a collective library (rather than an OO framework) is suffixed with Utils, as in MiscUtils and WebUtils.
What follows is a list of additional syntax and naming rules that are actually policed by the checksrc utility, described later in this document.
Servlet.py WebKit.cgi HTTPServlet.py
myClass.py session.py
Webware/bin/
that are intended solely for command line use are left in all lower case similar to other command line programs such as grep and find.\r
(on POSIX systems).\r
and confusion in the SVN repository which is hosted on Unix.\r\n
and \n
upon check out and check in, since we have set the svn:eol-style
property to native
.Servlet HTTPServlet ThreadedAppServer
servlet myClass
respond() isSecure() setTimeout() htForDict()
Respond() IsSecure() SetTimeout() HtForDict()
status() numRequests()
getStatus() getNumRequests()
self._status self._numRequests
self.status self.numRequests
self.numRequests() factory.servletForTransaction()
self.num_requests() factory.servlet_for_transaction()
if serialNum>0:
if (serialNum>0):
## Transactions ## def transaction(self): return self._transaction ## Values ## def hasValue(self, name): return self._fields.has_key(name) or self._cookies.has_key(name)
pass
.def function(a, b): """Do X and return a list."""
def function(a, b): """function(a, b) -> list"""
@@ yyyy-mm-dd initials: comment
.# @@ 2000-05-03 ce: This is bogus. Disregard for now.
# I think this is bogus !!
Webware overwhelmingly uses classes rather than collections of functions for several reasons:
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.
Specific numbers and strings often appear in source code for determining things such as the size of a cache, the duration before timeout, the name of the server and so on. Rather than place these values directly in source, Webware provides configuration files that are easily discerned and edited by users, without requiring a walk through the source.
Webware uses ordinary Python dictionaries for configuration files for several reasons:
eval()
function).By convention, these configuration files:
.config
extension.Configs/
subdirectory or in the same directory as the program.WebKit provides a Configurable
mix-in class that is used to read configuration files. It allows subclasses to say self.setting('Something')
so that the use of configuration information is easy and recognizable throughout the code.
Several classes in Webware store dictionaries of objects keyed by their name. HTTPRequest
is one such class which stores a dictionary of form fields. The convention for providing an interface to this information is as follows:
## Fields ## def field(self, name, default=_NoDefault): def hasField(self, name): def fields(self):
A typical use would be:
req.field('city')
which returns the field value of the given name or raises an exception if there is none. Like the get()
method of Python's dictionary type, a second parameter can be specified which will be returned if the value is not found:
req.field('city', None)
req.hasField('city')
is a convenience method that returns True
if the value exists, False
otherwise.
req.fields()
returns the entire dictionary so that users have complete access to the full suite of dictionary methods such as keys()
, values()
, items()
, etc. Users of this method are trusted not to modify the dictionary in any way. A paranoid class may choose to return a copy of the dictionary to help reduce abuse (although Webware classes normally do not for performance reasons).
In cases where the user of the class should be able to modify the named objects, the following methods are provided:
def setValue(self, name, value): def delValue(self, name):
Often Python programmers will provide dictionary-style access to their objects by implementing __getitem__
so that users may say:
req['city']
Webware generally avoids this approach for two reasons. The first and most important is that Webware classes often have more than one set of named objects. For example, HTTPRequest has both fields and cookies. HTTPResponse has both cookies and headers. These objects have their own namespaces, making the semantics of obj['name']
ambiguous. Also, the occasional class that has only one dictionary could potentially have more in the future.
The second reason is the readability provided by expressions such as response.cookie(name)
which states clearly what is being asked for.
In those cases where objects provide dictionary-like access, the class is typically a lightweight container that is naturally thought of in terms of its dictionary components. Usually these classes inherit from UserDict
.
Webware consists of multiple components that follow particular conventions, not only for the sake of consistency, but also to enable scripts to manipulate them (such as generating documentation upon installation).
Example components include WebKit, PSP and MiscUtils.
These conventions are not yet formally documented, however if you quickly browse through a couple components, some conventions about directory structure and source code become apparent.
Also, if a component serves as a WebKit plug-in, then there are additional conventions for them to follow in order to work correctly. See Plug-ins in the WebKit User's Guide.
Some features that have been introduced in newer Python versions, like properties or decorators, could be used to create more readable code. However, since we want Webware to be backward compatible, these newer features should currently not be used. In future versions of Webware we may certainly lift these restrictions and adapt the style guidelines accordingly.
When creating standalone Python scripts, like those found in Webware/bin, you should set the svn:executable
property when you check them in to the SVN repository. Otherwise Unix-based developers will not have execute permissions after checking the scripts out.
Those who actually develop Webware should send messages to webware-devel@lists.sourceforge.net when they update the repository.
The subject should contain the word "update" so that release notes can be easily compiled.
Note that automatic messages from SVN are not a good substitute for these types of messages which are more informative and more easily compiled into interesting release notes.
Of course, there are times when the rules are broken for good reason. To quote a cliché: "Part of being an expert is knowing when to break the rules."
But regarding style, Webware developers do this very infrequently for the reasons stated in the introduction.
checksrc.py
is a program located in Webware/bin
used to check the syntax and naming conventions in the actual Webware source code. You can invoke the program with -h
or --help
to get information on how to use it and there is a good doc string at the top of file if you're interested in more details. checksrc.py
should be run periodically and especially before each release of Webware.
You can also use pylint
(available from Logilab.org) for this purpose, which can be easily integrated in most IDEs. A suitable rcfile .pylintrc
has been placed in the Webware root directory.
A list of future work for this document: