Skip to content

RAVEN Code Standards

Paul Talbot edited this page Apr 29, 2019 · 5 revisions

Code standards are important to maintain code readability and a reasonable similarity in branding throughout the code architecture. Here we outline the coding practices for the RAVEN project.

Python

Tabs, Spacing, and Line Lengths

  • Use 2 spaces for each indent level. Use spaces, not tabs.

  • Function definitions should have at least one line of whitespace afterwards.

  • Multiple statements on one line are not allowed. For example the following is forbidden:

# not like this!
if makeAnimal: self.raiseAMessage("we just increased the MOOSE herd population")

and should be changed to:

# this way!
if makeAnimal: 
  self.raiseAMessage("we just increased the MOOSE herd population")
  • Tuple unpacking and packing should only be used when needed. For example:
# not like this!
a, b = 0, 1

should be rewritten to be:

# this way!
a = 0
b = 1

However, using it for function returns and swapping is allowed, since it saves temporary variables:

a, b = b, a

or:

a, b = funct()

are allowed.

  • Lines longer than 120 characters should be split if possible.

Naming Conventions

  • Class names should start with a Capital letter. Other variables should be camelBack case. Underscores should not be used in variable names, except in the case of private and protected variable prefixes.

  • Private variables start with two __underscores. Protected variables should start with one _underscore.

Exceptions

  • except: with no exception should only be used in extraordinary circumstances; instead something like except KeyError: or except Exception as e: print(repr(e)) would be better so only the provided exception is ignored or something is done with the exception.

Python 3 compatability

  • For python 2 code, it should have:
from __future__ import division, print_function, unicode_literals, absolute_import
import warnings
warnings.simplefilter('default',DeprecationWarning)

before any code to simplify porting between python 2 and 3. (Importing unicode_literals can be skipped if it causes problems and this is discussed with other developers.)

Function and Class Documentation Strings

  • Functions should have a ​docstring, which is right after the line defining the function and are between triple quotes """.
  • The triple quotes should be on their own line, and an additional level of indentation should be provided for the documentation comments.
  • Each input should be listed in the fashion below, starting with @ In, then the name of the input, the type of the input, (optional) and a brief description.
  • Each output should be listed similarly to the inputs, the line starting with @ Out, the name of the output variable, followed by the type of the output, and a brief description of it. The outputs must be listed in the order returned, and can be listed as a single returned tuple or on multiple lines if it can improve clarity. See examples below. In the event the return object is not a named variable [and it is not possible to do so (e.g. the method is very short and an addition of a named variable does not represent an added value for the readability of the code)], the name of the method should be listed instead.
  • Other comments not at the start of a function, method or class should use the # character to start them. Lines beginning with a # should be indented to match the line(s) of code they refer to.

Examples:

def sqr(x):
  """
    Returns the square of the argument.
    @ In, x, float, number to be squared
    @ Out, result, float, square of x
  """
  result = x*x #square by multiplying
  return result

def sqrWithOptionalArg(x=2.0):
  """
    Returns the square of the argument.
    @ In, x, float, optional, number to be squared
    @ Out, (x,result), tuple(float,float), original value and square of x
  """
  result = x*x #square by multiplying
  return x,result

def sqrWithMultOut(x=2.0):
  """
    Returns the square of the argument.
    @ In, x, float, optional, number to be squared
    @ Out, x, float, original value of x
    @ Out, result, float, square of x
  """
  result = x*x #square by multiplying
  return x,result

def printWolf():
  """
    Print the message 'Wolf'
    @ In, None
    @ Out, None
  """
  #prints "Wolf" to stdout
  print("Wolf")

def returnSize(x):
  """
    Return the size of an array
    @ In, x, numpy.array, the array whose size needs to be determined
    @ Out, returnSize, int, the size of the array 'x'
  """
  return x.size

Module Importing

  • The so-called "wild importing" approach is FORBIDDEN, i.e. :
# not like this!
from aModule import *
  • Rather than editing the system python path to load modules, a hierarchal structure should be used. For example, instead of
  # not like this!
  sys.path.append('/path/to/moduleGroup')
  import myModule

an effort should be made to make moduleGroup a true module by including a __init__.py file, then import by

  # this way!
  import moduleGroup.myModule