Coding Standards

Javascript coding style

Javascript rules style guides

In order to keep the javascript code consistent, we provide ESLint rules

Download here a .eslintrc sample file.

eslint configuration file
/* eslint import/no-commonjs:off */
/* eslint-env node */

module.exports = {
  'root': true,
  'env': {
    'browser': true,
  },
  'extends': [
    'eslint:recommended'
  ],
  'plugins': [
    'html'
  ],
  'rules': {
    'array-bracket-spacing': [ 'error', 'always' ],
    'block-spacing': 'error',
    'brace-style': 'error',
    'comma-dangle': [ 'error', 'always-multiline' ],
    'comma-spacing': 'error',
    'curly':[ 'error', 'multi-line', 'consistent' ],
    'eol-last': 'error',
    'indent': [ 'error', 2 ],
    'keyword-spacing': 'error',
    'linebreak-style': 'error',
    'no-spaced-func': 'error',
    'no-trailing-spaces': 'error',
    'object-curly-spacing': [ 'error', 'always' ],
    'quotes': [ 'error', 'single', { 'avoidEscape': true } ],
    'semi': 'error',
    'semi-spacing': 'error',
  },
  'parserOptions': {
    'sourceType': 'script',
  },
};

ESLint install

Dépendencies

Install the last stable NodeJS (and NPM, which comes by default with node)

Put the correct Dev Dependencies in your package.json

"devDependencies": {
  "eslint": "^3.16.1",
  "eslint-plugin-html": "^2.0.1"
}

then you just have to go in your project’s working repository and type

cd <project-root>
npm install

ESLint is then locally installed.

Running the test validation

This tests javascript and the local polymer elements.

If you have a custom script line in your package.json like this

"scripts": {
    "lint": "eslint"
},

then you can run the lint by typing

cd <project-root>
npm run lint -- <html_or_js_file_path>

Pre commit hook

Each developper shall install locally a pre-commit hook.

Important

A pre commit hook lives here in the project: .git/hooks/pre-commit and shall be an executable file (chmod +x .git/hooks/pre-commit)

You can download here the pre commit hook

The pre-commit hook
#!/usr/bin/env bash

export PATH=$PATH:./node_modules/.bin

commit_files=$(git diff --cached --name-only --diff-filter=ACM)

has_error=0
for file in $commit_files; do

  # Validation du code Javascript via ESLint
  if [[ "$file" =~ .(html|js)$ ]]; then
    eslint "$file"
    exit_code=$?
    [ "$exit_code" != '0' ] && has_error=1;
  fi

done

exit $has_error

It launches the js validation before the commit.

Tips

Sometimes it is a annoying to have a lint on a bunch of code you actually know that it will work but your linter says “dude, it’s NOK”.

Here is a list of tips to tell your linter that it’s OK then.

  • the globals

Example. Let’s assume you have imported a javascript called cookies.js and this file exports a global variable docCookies. You will use it later on in your script but the linter will tell you that the variable hasn’t been declared. Just put a comment in order to declare this variable as a global one.

<script src="../../vendor/cookies.js"></script>
<script>
/* global Polymer, docCookies */

Python coding style

First of all, have a close look at the PEP 8 coding style proposal. We mostly follow the pep8 conventions. This is our major coding standards conventions.

Install the pep8 tool:

sudo apt-get install python-pep8

You can automatically verify the pep8 compliance of your code by typing:

pep8 <filename.py>

This chapter describes coding requirements and conventions for working with python.

To keep it short

  • class names are CamelCase
  • functions/methods are lowercase and _ separated

Important

please don’t use uppercase for constants. this habits comes from the C language, which is not pythonic.

Line’s length

80 chars is not a limit, but don’t make too long lines, let’s say 100~110 characters seems to be enough. Remember that your python file can be opened in a small terminal.

forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first',
           'make_dict', 'unwrap_from_path', 'read_only',
           'read_write', 'getowner', 'set_contexts')

Use parenthesis if your line is too long, it’s a block statement in python.

Please don’t use \, it’s an old habit

if re.match(name_regexp, name) is None and not name.startswith('_') \
    and name not in forbidden_names \
    and not name.startswith('impl_') \
    and not name.startswith('cfgimpl_'):
    ...
    ...

use parenthesis instead

if (re.match(name_regexp, name) is None and not name.startswith('_')
    and name not in forbidden_names
    and not name.startswith('impl_')
    and not name.startswith('cfgimpl_')):
    ...
    ...

Docstrings

When coding a function, class, ... don’t forget to write a docstring, and not a oneline docstring, a multiline one:

def my_function():
    """my multinine
    docstring
    """

Put triple quotes and the closing triple quote in a new line.

Here is an example of a docstring documenting a function:

def retrieve_json(json_url):
  """
  Retrieves and pretty prints indented json from a given url

  :param str json_url: full url of the json file
  :return: None
  :rtype: str
  :raises IOError: if the json cannot be retrieved
  """

Please have a look at the Lists paragraph for further explanations on how to document the code.

Subfolders

Please make a proper folder subdirectories when you create a project, that is:

<project_name>/src/
                  bin/<project_name> # executable file
                  bin/<project_name>clin # command line interface
                  <project_name>/submodule.py
              /doc/

Coding guide

The samuraï rule

The samuraï rule
A function shall return the expected result, or... kill itself (that is, raise and exception).

A function is half-coded if the cases where it fails is not handled.

>>> def function_raise(x):
...   if (...):
...     raise TypeError("Not the right type")
...   else:
...     return x + 1
...
>>> try:
...   e = function_raise("one string")
... except TypeError, e:
...   print e
...
Not the right type
>>>

Use appropriate or user defined exceptions:

try:
    with urlopen(json_url) as resp:
        contents = resp.read().decode()
        pprint(loads(contents))
except HTTPError as e:
    raise e
except:
    raise IOError("The json {0} cannot be retrieved".format(json_url))

Unnamed arguments in a function

Please name them args and kwargs:

>>> def my_fonction(*args, **kwargs):
...   print("arguments : ", str(args))
...   print("named argumments : ", str(kwargs))
...
>>> my_fonction("toto", "titi", tutu=2, tata=3)
arguments :  ('toto', 'titi')
named argumments : {'tata': 3, 'tutu': 2}
>>>

Don’t explicitly return None

This function:

>>> def my_function(a, b):
...     """this is my func docstring"""
...

is equivalent to:

>>> def my_function(a, b):
...     """this is my func docstring"""
...     return None

There are no procedures in python (a procedure returns nothing). It means that a function return always someting. Even if you don’t return something, it returns None, which is something:

>>> result = my_function(1, 2)
>>> print(result)
None
>>> print(my_function(1, 2))
None

So don’t make some code like:

>>> if a == 2:
...   return 'hello'
... else:
...   return None
...

Base types’ boolean coercion

Carefull about the boolean coersion possiblities of the base types:

>>> l = ["a", "b", "c"]
>>> s = ""
>>> assert s is False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
>>>
>>> if not s:
...   s.join(l)
'abc'
>>>

works fine. But what if s is None ? The first assertion works fine, but not the join.

Use isinstance() instead of type()

Use isinstance() instead of type(). Why ? because:

>>> class MyString(str): pass
...
>>> s = MyString()
>>> type(s) == str
False
>>> isinstance(s, str)
True
>>>

if you make a test with isinstance, it will be more pythonic, more duck typed.

String templating

Please always use numbers inside the brackets:

>>> s = "ssdfsdf {0} sdfsdfsdf {1}".format("blah", "blih")

or named arguments.

Namespaces

Naming conventions

  • Do not choose a name in plural. That is, not printers.py but printer.py
  • Without underscore if possible, that is mymodule.py is better than my_module.py as far as it is readable.
  • no camel case for the module’s names !

The import statement

The way you import python modules is very, very important.

  • imports must be ordered:

    • first, the standard library imports
    • then the external library imports
    • then the internal imports
  • there are two ways to arrange an import line :

    • single line imports:

      from spam import func
      from spam import myvar
      from spam import another_func
      
    • multi lines imports:

      import (spam, eggs, apples, fruits,
              and, so, on)
      

      if you are using multiline imports, use () instead of \, using the backslash is an old habit:

      from spam import func, myvar, ... \\
        another_func
      

      write it like this instead:

      from spam import (func, myvar, ...
        another_func)
      
  • Never use hidden modules

    a hidden module is a module that comes from elsewhere

    For example, in a module named mathlib.py:

    from math import floor
    floor(.6)
    def other_math_calculation():
      ...
    

    then in another module mathexercice.py we need to use the floor() function:

    from mathlib import (floor, other_math_calculation)
    

    It is strictly forbidden. Even if we import mathlib because we need it, we shall not use floor() from it.

    In mathexercices.py we shall re-import the floor() function:

    from math import floor
    from mathexercice import other_math_calculation
    

Important

never use a function that comes from outside its namespace

  • use relative imports instead of absolute ones, that is import ..mymodule instead of from mylib import mymodule

  • do not import full namespaces

    This from mymodule import * is forbidden, but also this import mymodule is forbidden too. You have to explicitely name the function or class you need to use:

    from mymodule import myfunc, myclass
    

Standard open data formats

We shall use open datas and open formats, our most used data structure is

JSON
JSON is The most widely spread data interchange format Have a look at the json website
YAML
More human readable format
XML
Even more human readable but less easy to manipulate