Skip to content

Contributing Style Guide

Oliver Roick edited this page Oct 5, 2017 · 8 revisions

Python

General rules

We write Python3.

We follow PEP8 conventions throughout all our Python code. Key principles include:

  • Always use spaces for indentation. Four spaces make one tab.
  • Maximum line length is 79 characters.
  • Always encode source files in UTF-8.

Imports

Try to keep your imports small and only import those definitions of a module that you actually need in your script.

from django.views.generic import CreateView, TemplateView

If you, however, need many definitions from a single module it's more readable to import the module and call the definitions from the module.

Don't do:

from django.views.generic import (CreateView, TemplateView, ListView,
    UpdateView, DeleteView)

Do this instead:

from django.views import generic as generic_views

(...)

generic_views.CreateView(...)

Never import * from a module. This can significantly affect performance and might have other unwanted consequences.

Don't do this, ever:

from django.views import *

A few words on strings

Use triple-double quotes for doc strings:

def get_members(self):
    """Returns all members"""
    return self.members

Make interpolated strings readable:

"{org_name} has {num_members} members.".format(
    org_name="Habitat for Humanity",
    num_members=10
)

Never use string concatenation—it makes internationalisation impossible.

Opening files

Always open files using a context manager. That way the file is always closed when the block finishes, even if an exception is raised at some point.

with open('some/path') as open_file:
    file_content = open_file.read()

Documentation and Comments

Functions and Methods

As used in this section "function" applies to methods, function, and generators.

A function must have a docstring, unless it meets all of the following criteria:

  • not externally visible
  • very short
  • obvious

A docstring should give enough information to write a call to the function without reading the function's code. A docstring should describe the function's calling syntax and its semantics, not its implementation. For tricky code, comments alongside the code are more appropriate than using docstrings.

For large functions (functions longer than 20 lines), certain aspects of a function should be documented in special sections, listed below. Each section begins with a heading line, which ends with a colon. Sections should be indented two spaces, except for the heading.

Args:

: List each parameter by name. A description should follow the name, and be separated by a colon and a space. If the description is too long to fit on a single 80-character line, use a hanging indent of 2 or 4 spaces (be consistent with the rest of the file).

: The description should mention required type(s) and the meaning of the argument.

: If a function accepts *foo (variable length argument lists) and/or **bar (arbitrary keyword arguments), they should be listed as *foo and **bar.

Returns: (or Yields: for generators)

: Describe the type and semantics of the return value. If the function only returns None, this section is not required.

Raises:

: List all exceptions that are relevant to the interface.

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
    """
    Fetches rows from a Bigtable.

    Retrieves rows pertaining to the given keys from the Table instance
    represented by big_table.  Silly things may happen if
    other_silly_variable is not None.

    Args:
        big_table: An open Bigtable Table instance.
        keys: A sequence of strings representing the key of each table row
            to fetch.
        other_silly_variable: Another optional variable, that has a much
            longer name than the other args, and which does nothing.

    Returns:
        A dict mapping keys to the corresponding table row data
        fetched. Each row is represented as a tuple of strings. For
        example:

        {'Serak': ('Rigel VII', 'Preparer'),
         'Zim': ('Irk', 'Invader'),
         'Lrrr': ('Omicron Persei 8', 'Emperor')}

        If a key from the keys argument is missing from the dictionary,
        then that row was not found in the table.

    Raises:
        IOError: An error occurred accessing the bigtable.Table object.
    """
    pass

Classes

Classes should have a doc string below the class definition describing the class. If a large class has public attributes, they should be documented here in an Attributes section and follow the same formatting as a function's Args section.

class SampleClass(object):
    """
    Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

Block and Inline Comments

The final place to have comments is in tricky parts of the code. If you're going to have to explain it at the next code review, you should comment it now. Complicated operations get a few lines of comments before the operations commence. Non-obvious ones get comments at the end of the line.

# We use a weighted dictionary search to find out where i is in
# the array.  We extrapolate position based on the largest num
# in the array and the array size and then do binary search to
# get the exact number.

if i & (i-1) == 0:        # true if i is a power of 2

To improve legibility, these comments should be at least 2 spaces away from the code.

On the other hand, never describe the code. Assume the person reading the code knows Python (though not what you're trying to do) better than you do.

# BAD COMMENT: Now go through the b array and make sure whenever i occurs
# the next element is i+1

Text editors

Use the IDE or text editor you personally prefer.

The repository contains an EditorConfig file, which helps developers maintain consistent coding styles between different editors and IDEs. EditorConfig plugins are available for most editors:

Lint your code using Flake8 for potential errors before committing. Flake8 provider are available for several text editors:

Javascript

Airbnb has pulled together comprehensive ES6 and React guides that we follow for everything JavaScript.

Use ESLint to lint your JS code:

Clone this wiki locally