wiki:JWSTCodingStandards

The following style guidelines should be followed for all jwst code.

This is based on the PEP-8 guidelines. (http://www.python.org/dev/peps/pep-0008/, but everything you need is in this document.)

Naming conventions

  • Use lowercase or lowercase_with_underscores for:
    • module names (which are also file names)
    • function names
    • class methods
    • instance variables
    • string literals
  • Use CamelCase for:
    • class names
    • custom exception names

Also: always use "new-style" classes (ie, always inherit from object).

  • Use UPPERCASE or UPPERCASE_WITH_UNDERSCORES for:
    • constants
  • Use a leading underscore for private classes, methods, functions, or variables
  • In general, spell out words rather than abbreviating.

Imports

  • from __future__ import division
  • Imports (one per line, except "from X import a, b" is ok) should be grouped in the following order, with each group separated by a blank line:
  1. standard library imports
  2. related third party imports
  3. local jwst specific imports
  • Use relative import syntax when importing from jwst subpackages.
  • For jwst imports, use the fully-qualified path in the import statement only: import the actual classes and functions that you need
  • Do not use "from anything import *".
    • Exception: in a __init__ to define the contents of the namespace
  • The following "import as" abbreviations should be used:

   import numpy as np
   import matplotlib as mpl
   import some.external.lengthy.subpackage as subpackage

Whitespace & layout

  • Use spaces for indents instead of tabs
  • Maximum linelength = 132 characters
  • Use 1 space: around operators, after a comma
  • Use no spaces: when specifying keyword values; between function name and parenthesis: between variable name and indexing square bracket
  • Exceptions: Breaking the whitespace rules is allowed (and even encouraged) if it will lead to more readable code.

Numpy arrays

  • Indices for multidimensional arrays are given in a tuple separated by commas: a[3,3].
  • Use a colon to indicate a complete slice: a[3,:]

Exceptions

Raising them

  • use raise ValueError('meaningful message'), not raise ValueError, 'meaningful message'
  • Never raise AssertionError or use the assert statement (which raises AssertionError) in non-test code: this can result in misleading behavior in the nightly tests, because AssertionErrors are used to indicate failing (failed comparison) rather than erroring (never got to the comparison) tests.
  • Never print error messages to stdout or stderr. Put all the meaningful text in the argument of the exception, and/or use the jwst logger.
  • Never print warning messages to stdout or stderr. Use the jwst logger.
  • Printing to stdout/stderr as a development aid is fine, but please remove it when you're done to prevent batch use from generating a lot of noise

Catching them

  • Always catch the exception into a variable for ease of later debugging:

except Exceptiontype as e:

  • Never use a plain except: always specify exception types that you are catching. If you need to catch everything, use except Exception.

String handling

  • use string methods instead of the string module
  • use pythonic idioms instead of indexing:
    • if x.startswith('foo')
    • if x.endswith('foo')
    • if 'foo' in x

Comparisons

  • for typechecking, use isinstance(variable, ObjectType)
  • use "is" not "==" when comparing to None
  • use "if x:" or "if not x:" to compare to True or False (carefully; remember that non-boolean types will happily evaluate to True or False).

Documentation

  • Please document amply, to explain the purpose, rationale, or tricky bits, by using block comments before each section of code that implements a distinct piece of functionality. Avoid comments that explain the obvious.
  • Use triple double quotes to enclose docstrings.

(This is what the python mode in Emacs recognizes; it does not correctly recognize the use of triple single quotes.)

Data and code

  • Universal mathematical and physical constants (c, h, and so on) may be defined in code but should be encapsulated in a single file.
  • All constants should be stored in their native datatypes (ie, the types by which they will be used). No typecasting should be necessary in order to use a constant read from a datafile.
    • If a constant is used as a string in some places and as a numeric type elsewhere, store it as the numeric type.
    • Strings should be stored in lowercase
  • Use main.util.read_dict(filename) and main.util.write_dict(mydict, 'filename') to read and write these datafiles, instead of reading or writing them directly. (If an applicable higher-level function exists, use it instead, eg for accessing instrument data.)

This will insulate the code from any changes we may make to these file formats in future.

Last modified 5 years ago Last modified on 04/29/14 16:21:05