Create Python coding guidelines authored by Moreau Nicolas's avatar Moreau Nicolas
# Purpose
This documents aims at defining standard coding rules for all Python code in the application. It is based on \[PEP 8\](<https://www.python.org/dev/peps/pep-0008/>).
## Code Lay-out
Use 4 spaces per indentation level.
Continuation lines should align wrapped elements either vertically using Python's implicit line joining inside parentheses, brackets and braces, or using a _hanging indent_
Correct:
`# Aligned with opening delimiter.`
`foo = long_function_name(var_one, var_two,`
` var_three, var_four)`
`# Add 4 spaces (an extra level of indentation) to distinguish arguments from the rest.`
`def long_function_name(`
` var_one, var_two, var_three,`
` var_four):`
` print(var_one)`
`# Hanging indents should add a level.`
`foo = long_function_name(`
` var_one, var_two,`
` var_three, var_four)`
Wrong:
`# Arguments on first line forbidden when not using vertical alignment.`
`foo = long_function_name(var_one, var_two,`
` var_three, var_four)`
`# Further indentation required as indentation is not distinguishable.`
`def long_function_name(`
` var_one, var_two, var_three,`
` var_four):`
` print(var_one)`
The 4-space rule is optional for continuation lines.
The closing brace/bracket/parenthesis on multiline constructs may either line up under the first non-whitespace character of the last line of list, as in:
`my_list = [`
` 1, 2, 3,`
` 4, 5, 6,`
` ]`
`result = some_function_that_takes_arguments(`
` 'a', 'b', 'c',`
` 'd', 'e', 'f',`
` )`
or it may be lined up under the first character of the line that starts the multiline construct, as in:
`my_list = [`
` 1, 2, 3,`
` 4, 5, 6,`
`]`
`result = some_function_that_takes_arguments(`
` 'a', 'b', 'c',`
` 'd', 'e', 'f',`
`)`
### Maximum Line Length
Limit all lines to a maximum of 99 characters.
For flowing long blocks of text with fewer structural restrictions (docstrings or comments), the line length should be limited to 75 characters.
### A Line Should Break Before a Binary Operator?
`# easy to match operators with operands`
`income = (gross_wages`
` + taxable_interest`
` + (dividends - qualified_dividends)`
` - ira_deduction`
` - student_loan_interest)`
### Blank lines
Surround top-level function and class definitions with two blank lines.
Method definitions inside a class are surrounded by a single blank line.
Extra blank lines may be used (sparingly) to separate groups of related functions. Blank lines may be omitted between a bunch of related one-liners (e.g. a set of dummy implementations).
Use blank lines in functions, sparingly, to indicate logical sections.
### Imports
Imports should usually be on separate lines:
`import os`
`import sys`
`from subprocess import Popen, PIPE`
Wrong :
`import sys, os`
Imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants.
Imports should be grouped in the following order:
1. Standard library imports.
2. Related third party imports.
3. Local application/library specific imports.
You should put a blank line between each group of imports.
Wildcard imports (from <module> import \*) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools.
## Whitespace in Expressions and Statements
Avoid trailing whitespace anywhere. Because it's usually invisible, it can be confusing: e.g. a backslash followed by a space and a newline does not count as a line continuation marker. Some editors don't preserve it and many projects (like CPython itself) have pre-commit hooks that reject it.
Always surround these binary operators with a single space on either side: assignment (=), augmented assignment (+=, <span dir="">-=</span> etc.), comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not), Booleans (and, or, not).
If operators with different priorities are used, consider adding whitespace around the operators with the lowest priority(ies). Use your own judgment; however, never use more than one space, and always have the same amount of whitespace on both sides of a binary operator:
Correct :
`i = i + 1`
`submitted += 1`
`x = x*2 - 1`
`hypot2 = x*x + y*y`
`c = (a+b) * (a-b)`
Wrong :
`i=i+1`
`submitted +=1`
`x = x * 2 - 1`
`hypot2 = x x + y y`
`c = (a + b) * (a - b)`
Function annotations should use the normal rules for colons and always have spaces around the <span dir="">-></span> arrow if present
`def munge(input: AnyStr): ...`
`def munge() -> PosInt: ...`
Multiple statements on the same line) are generally discouraged
## Comments
Comments should be complete sentences. The first word should be capitalized, unless it is an identifier that begins with a lower case letter (never alter the case of identifiers!).
Block comments generally consist of one or more paragraphs built out of complete sentences, with each sentence ending in a period.
## Documentation Strings
The documentation will follow the (numpy convention )\[<https://numpydoc.readthedocs.io/en/latest/format.html>\].
### Sections
#### Short summary
A one-line summary that does not use variable names or the function name, e.g.
`def add(a, b):`
` """The sum of two numbers.`
` """`
#### Extended Summary
A few sentences giving an extended description. This section should be used to clarify _functionality_, not to discuss implementation detail or background theory, which should rather be explored in the [<span dir="">Notes</span>](https://numpydoc.readthedocs.io/en/latest/format.html#notes) section below. You may refer to the parameters and the function name, but parameter descriptions still belong in the [<span dir="">Parameters</span>](https://numpydoc.readthedocs.io/en/latest/format.html#params) section.
#### Parameters
Description of the function arguments, keywords and their respective types.
`Parameters`
`----------`
`x : type`
` Description of parameter x.`
`y`
` Description of parameter y (with type not specified).`
Enclose variables in single backticks. The colon must be preceded by a space, or omitted if the type is absent.
For the parameter types, be as precise as possible. Below are a few examples of parameters and their types.
`Parameters`
`----------`
`filename : str`
`copy : bool`
`dtype : data-type`
`iterable : iterable object`
`shape : int or tuple of int`
`files : list of str`
If it is not necessary to specify a keyword argument, use optional :
`x : int, optional`
#### Returns
Explanation of the returned values and their types. Similar to the [<span dir="">Parameters</span>](https://numpydoc.readthedocs.io/en/latest/format.html#params) section, except the name of each return value is optional. The type of each return value is always required:
`Returns`
`-------`
`int`
` Description of anonymous integer return value.`
#### Yields
Explanation of the yielded values and their types. This is relevant to generators only. Similar to the [<span dir="">Returns</span>](https://numpydoc.readthedocs.io/en/latest/format.html#returns) section in that the name of each value is optional, but the type of each value is always required:
`Yields`
`------`
`int`
` Description of the anonymous integer return value.`
####
#### Notes
An optional section that provides additional information about the code, possibly including a discussion of the algorithm.
`Notes`
`-----`
`The FFT is a fast implementation of the discrete Fourier transform`
#### Hinting
All function parameters and returned values types should be hinted :
`def greeting(name: str) -> str:`
` return 'Hello ' + name`
### Documenting classes
Use the same sections as outlined above (all except Returns are applicable). The constructor (__init__) should also be documented here, the Parameters section of the docstring details the constructor’s parameters.
An Attributes section, located below the Parameters section, may be used to describe non-method attributes of the class:
`An AtAttributes`
`----------`
`x : float`
` The X coordinate.`
`y : float`
` The Y coordinate.`
## Naming Conventions
### Package and Module Names
Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability. Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.
### Class Names
Class names should normally use the CapWords convention.
### Function and Variable Names
Function names should be mixedCase.
### Method Names and Instance Variables
Method names and instance variables should be mixedCase.
### Constants
Constants are usually defined on a module level and written in all capital letters with underscores separating words. Examples include MAX_OVERFLOW and TOTAL.
## Programming Recommendations
* Comparisons to singletons like None should always be done with is or is not, never the equality operators.
* Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier:
Correct:
`def f(x): return 2*x`
Wrong:
`f = lambda x: 2*x`
* Use <span dir="">''.startswith()</span> and <span dir="">''.endswith()</span> instead of string slicing to check for prefixes or suffixes.
* Don't compare boolean values to True or False using == or is False/ is True
`# Correct:`
`if greeting:`
\ No newline at end of file