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 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
#!/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.pybutprinter.py - Without underscore if possible, that is
mymodule.pyis better thanmy_module.pyas 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.pywe need to use thefloor()function:from mathlib import (floor, other_math_calculation)
It is strictly forbidden. Even if we import
mathlibbecause we need it, we shall not usefloor()from it.In
mathexercices.pywe shall re-import thefloor()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 ..mymoduleinstead offrom mylib import mymoduledo not import full namespaces
This
from mymodule import *is forbidden, but also thisimport mymoduleis 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