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.py
butprinter.py
- Without underscore if possible, that is
mymodule.py
is better thanmy_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 thefloor()
function:from mathlib import (floor, other_math_calculation)
It is strictly forbidden. Even if we import
mathlib
because we need it, we shall not usefloor()
from it.In
mathexercices.py
we 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 ..mymodule
instead offrom mylib import mymodule
do not import full namespaces
This
from mymodule import *
is forbidden, but also thisimport 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