Directrices Diseño Libreria en Python
Directrices Diseño Libreria en Python
This document gives coding conventions for the Nebula Framework comprising the standard
library in the main Python distribution within the development "Best of the Best Practices"
(BOBP).
The point of having style guidelines is to have a common vocabulary of coding so people can
concentrate on what you’re saying rather than on how you’re saying it. We present global style
rules here so people know the vocabulary, but local style is also important. If code you add to a
file looks drastically different from the existing code around it, it throws readers out of their
rhythm when they go to read it. Avoid this.
__Nebula Framework
1
NEBULA FRAMEWORK
Style guideline V.0
Index
Background 3
Style 5
Naming 5
Names to avoid 6
Naming convention 6
File naming 7
General guideline 7
Main 8
Function length 9
Indentation 9
Imports 9
Package 10
Properties 12
True/False evaluations 14
Exceptions 15
Rules 18
Semicolon 18
Line length 18
Parentheses 18
Whitespace 19
__Nebula Framework
2
NEBULA FRAMEWORK
Style guideline V.0
Classes 23
Signal format 28
Reference 30
Background
Python is the main dynamic language and QML is the user interface markup language used at
Nebula Framework. This style guide is a list of dos and don’ts for Python - Nebula modules.
To help you format code correctly, exist command-line platforms, pycodestyle (previously
known as pep8) who helps you to check your code performance in base to PEP8 facto code style
for Python. Install it by running the following command in your terminal:
pycodestyle optparse.py
__Nebula Framework
3
NEBULA FRAMEWORK
Style guideline V.0
The program autopep8 can be used to automatically reformat code in the PEP 8 style. Install the
program with:
Excluding the --in-place flag will cause the program to output the modified code directly to the
console for review. The --aggressive flag will perform more substantial changes and can be
applied multiple times for greater effect.
__Nebula Framework
4
NEBULA FRAMEWORK
Style guideline V.0
Style
Naming
Function names, variable names, and file names should be descriptive; eschew abbreviation. In
particular, do not use abbreviations that are ambiguous or unfamiliar to readers outside your
module, and do not abbreviate by deleting letters within a word. And of course, in English.
General:
module_name, package_name, ClassName, method_name, ExceptionName,
function_name, GLOBAL_CONSTANT_NAME, global_var_name,
instance_var_name, function_parameter_name, local_var_name.
Always use a .py filename extension. Never use dashes (-).
__Nebula Framework
5
NEBULA FRAMEWORK
Style guideline V.0
Names to avoid
● Single character names except for counters or iterators. You may use “e” as an exception
identifier in try/except statements.
Naming convention
__Nebula Framework
6
NEBULA FRAMEWORK
Style guideline V.0
File naming
Python filenames must have a .py extension and must not contain dashes (-). This allows them to be
imported and unittested. If you want an executable to be accessible without the extension, use a
symbolic link or a simple bash wrapper containing exec "$0.py" "$@".
General guideline
While Python supports making things private by using a leading double underscore __ (aka.
“dunder”) prefix on a name, this is discouraged. Prefer the use of a single underscore. They are
easier to type, read, and to access from small unittests. Lint warnings take care of invalid access
to protected members.
Packages lower_with_under
Exceptions CapWords
__Nebula Framework
7
NEBULA FRAMEWORK
Style guideline V.0
Main
Even a file meant to be used as an executable should be importable and a mere import should not
have the side effect of executing the program’s main functionality. The main functionality should
be in a main() function.
In Python, pydoc as well as unit tests require modules to be importable. Your code should always
check if __name__ == '__main__' before executing your main program so that the main program
is not executed when the module is imported.
def main():
...
All code at the top level will be executed when the module is imported. Be careful not to call
functions, create objects, or perform other operations that should not be executed when the file
is being pydoced.
__Nebula Framework
8
NEBULA FRAMEWORK
Style guideline V.0
Function length
Prefer small and focused functions.
We recognize that long functions are sometimes appropriate, so no hard limit is placed on
function length. If a function exceeds about ~ 60 lines, think about whether it can be broken up
without harming the structure of the program.
Even if your long function works perfectly now, someone modifying it in a few months may add
new behavior. This could result in bugs that are hard to find. Keeping your functions short and
simple makes it easier for other people to read and modify your code.
You could find long and complicated functions when working with some code. Do not be
intimidated by modifying existing code: if working with such a function proves to be difficult,
you find that errors are hard to debug, or you want to use a piece of it in several different
contexts, consider breaking up the function into smaller and more manageable pieces.
Indentation
Use 4 spaces--never tabs. Enough said.
Imports
Reusability mechanism for sharing code from one module to another.
Use import statements for packages and modules only, not for individual classes or functions.
Note that there is an explicit exemption for imports from the typing module.
Try to keep the namespace management convention simple. The source of each identifier is
indicated in a consistent way; x.Obj says that object Obj is defined in module x.
__Nebula Framework
9
NEBULA FRAMEWORK
Style guideline V.0
Yes:
import os
import sys
No:
Do not use relative names in imports. Even if the module is in the same package, use the full
package name. This helps prevent unintentionally importing a package twice.
Package
Import each module using the full pathname location of the module. All new code should import
each module by its full package name.
Yes:
__Nebula Framework
10
NEBULA FRAMEWORK
Style guideline V.0
FLAGS = absl.flags.FLAGS
No: (assume this file lives in doctor/who/ where jodie.py also exists)
# Unclear what module the author wanted and what will be imported. #The actual
import behavior depends on external factors controlling sys.path.
# Which possible jodie module did the author intend to import?
import jodie
The directory the main binary is located in should not be assumed to be in sys.path despite that
happening in some environments. This being the case, code should assume that import jodie
refers to a third party or top level package named jodie, not a local jodie.py.
Do not use mutable objects as default values in the function or method definition.
Yes:
__Nebula Framework
11
NEBULA FRAMEWORK
Style guideline V.0
def foo(a, b: Sequence = ()): # Empty tuple OK since tuples are immutable
...
No:
Properties
A way to wrap method calls for getting and setting an attribute as a standard attribute access
when the computation is lightweight.
Use properties for accessing or setting data where you would normally have used simple,
lightweight accessor or setter methods.
Use properties in new code to access or set data where you would normally have used simple,
lightweight accessor or setter methods. Properties should be created with the @property
decorator.
Inheritance with properties can be non-obvious if the property itself is not overridden. Thus one
must make sure that accessor methods are called indirectly to ensure methods overridden in
subclasses are called by the property (using the Template Method DP).
Yes:
import math
class Square(object):
"""A square with two properties: a writable area and a read-only
perimeter.
To use:
__Nebula Framework
12
NEBULA FRAMEWORK
Style guideline V.0
>>> sq = Square(3)
>>> sq.area
9
>>> sq.perimeter
12
>>> sq.area = 16
>>> sq.side
4
>>> sq.perimeter
16
"""
@property
def area(self):
"""Gets or sets the area of the square."""
return self._get_area()
@area.setter
def area(self, area):
return self._set_area(area)
def _get_area(self):
"""Indirect accessor to calculate the 'area' property."""
return self.side ** 2
@property
def perimeter(self):
return self.side * 4
__Nebula Framework
13
NEBULA FRAMEWORK
Style guideline V.0
True/False evaluations
Use the “implicit” false if at all possible. Python evaluates certain values as False when in a
boolean context. A quick “rule of thumb” is that all “empty” values are considered false, so 0,
None, [], {}, '' all evaluate as false in a boolean context.
Example: if foo: rather than if foo != []:. There are a few caveats that you should keep
in mind though:
● Never use == or != to compare singletons like None. Use is or is not.
● Beware of writing if x: when you really mean if x is not None:-e.g., when
testing whether a variable or argument that defaults to None was set to some other value.
The other value might be a value that’s false in a boolean context!
● Never compare a boolean variable to False using ==. Use if not x: instead. If you
need to distinguish False from None then chain the expressions, such as if not x and
x is not None:.
● For sequences (strings, lists, tuples), use the fact that empty sequences are false, so if
seq: and if not seq: are preferable to if len(seq): and if not len(seq):
respectively.
● When handling integers, implicit false may involve more risk than benefit (i.e.,
accidentally handling None as 0). You may compare a value which is known to be an
integer (and is not the result of len()) against the integer 0.
● Note that '0' (i.e., 0 as string) evaluates to true.
Yes:
__Nebula Framework
14
NEBULA FRAMEWORK
Style guideline V.0
def f(x=None):
if x is None:
x = []
No:
def f(x=None):
x = x or []
Exceptions
Exceptions are a means of breaking out of the normal flow of control of a code block to handle
errors or other exceptional conditions.
__Nebula Framework
15
NEBULA FRAMEWORK
Style guideline V.0
to ensure internal correctness, not to enforce correct usage nor to indicate that some
unexpected event occurred. If an exception is desired in the latter cases, use a raise
statement. For example:
Yes:
Args:
minimum: A port value greater or equal to 1024.
Raises:
ValueError: If the minimum port specified is less than 1024.
ConnectionError: If no available port is found.
Returns:
The new minimum port.
"""
if minimum < 1024:
raise ValueError('Minimum port must be at least 1024, not %d.' % (minimum,))
port = self._find_next_open_port(minimum)
if not port:
raise ConnectionError('Could not connect to service on %d or higher.' %
(minimum,))
assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port,
minimum)
return port
No:
Args:
minimum: A port value greater or equal to 1024.
Returns:
The new minimum port.
__Nebula Framework
16
NEBULA FRAMEWORK
Style guideline V.0
"""
assert minimum >= 1024, 'Minimum port must be at least 1024.'
port = self._find_next_open_port(minimum)
assert port is not None
return port
● Libraries or packages may define their own exceptions. When doing so they must
inherit from an existing exception class. Exception names should end in Error and
should not introduce stutter (foo.FooError).
● Minimize the amount of code in a try/except block. The larger the body of the try, the
more likely that an exception will be raised by a line of code that you didn’t expect to
raise an exception. In those cases, the try/except block hides a real error.
● Use the finally clause to execute code whether or not an exception is raised in the
try block. This is often useful for cleanup, i.e., closing a file.
__Nebula Framework
17
NEBULA FRAMEWORK
Style guideline V.0
Rules
Semicolon
Do not terminate your lines with semicolons, and do not use semicolons to put two statements on
the same line.
Line length
Maximum line length is 80 characters.
Exceptions:
Do not use backslash line continuation except for with statements requiring three or more context
managers.
Parentheses
Use parentheses sparingly.
It is fine, though not required, to use parentheses around tuples. Do not use them in return
statements or conditional statements unless using parentheses for implied line continuation or to
indicate a tuple.
Yes:
if foo:
__Nebula Framework
18
NEBULA FRAMEWORK
Style guideline V.0
bar()
while x:
x = bar()
if x and y:
bar()
if not x:
bar()
# For a 1 item tuple the ()s are more visually obvious than the comma.
onesie = (foo,)
return foo
return spam, beans
return (spam, beans)
for (x, y) in dict.items(): ...
No:
if (x):
bar()
if not(x):
bar()
return (foo)
Whitespace
Follow standard typographic rules for the use of spaces around punctuation.
Yes:
No:
__Nebula Framework
19
NEBULA FRAMEWORK
Style guideline V.0
Yes:
if x == 4:
print(x, y)
x, y = y, x
No:
if x == 4 :
print(x , y)
x , y = y , x
No whitespace before the open paren/bracket that starts an argument list, indexing or slicing.
Surround binary operators with a single space on either side for assignment (=), comparisons (==,
<, >, !=, <>, <=, >=, in, not in, is, is not), and Booleans (and, or, not). Use your better judgment
for the insertion of spaces around arithmetic operators (+, -, *, /, //, %, **, @).
Yes:
spam(1)
dict['key'] = list[index]
x == 1
No:
spam (1)
dict ['key'] = list [index]
x==1
__Nebula Framework
20
NEBULA FRAMEWORK
Style guideline V.0
Never use spaces around = when passing keyword arguments or defining a default parameter
value, with one exception: when a type annotation is present, do use spaces around the = for the
default parameter value.
Yes:
No:
A function must have a docstring, unless it meets all of the following criteria:
A docstring should give enough information to write a call to the function without reading the
function’s code. The docstring should be descriptive ("""Fetches rows from a Bigtable.""") rather
than imperative ("""Fetch rows from a Bigtable."""). 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.
A method that overrides a method from a base class may have a simple docstring sending the
reader to its overridden method’s docstring, such as """See base class.""". The rationale is that
there is no need to repeat in many places documentation that is already present in the base
__Nebula Framework
21
NEBULA FRAMEWORK
Style guideline V.0
method’s docstring. However, if the overriding method’s behavior is substantially different from
the overridden method, or details need to be provided (e.g., documenting additional side effects),
a docstring with at least those differences is required on the overriding method.
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 include required type(s) if the code does not contain a corresponding
type annotation.
If a function accepts *foo (variable length argument lists) and/or **bar (arbitrary keyword
arguments), they should be listed as *foo and **bar.
Describe the type and semantics of the return value. If the function only returns None, this
section is not required. It may also be omitted if the docstring starts with Returns or Yields (e.g.
"""Returns row from Bigtable as a tuple of strings.""") and the opening sentence is sufficient to
describe return value.
Raises:
Retrieves rows pertaining to the given keys from the Table instance
__Nebula Framework
22
NEBULA FRAMEWORK
Style guideline V.0
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:
Raises:
IOError: An error occurred accessing the bigtable.Table object.
"""
Classes
Classes should have a docstring below the class definition describing the class. If your 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.
__Nebula Framework
23
NEBULA FRAMEWORK
Style guideline V.0
Attributes:
likes_spam: A boolean indicating if we like SPAM or not.
eggs: An integer count of the eggs we have laid.
"""
def public_method(self):
"""Performs operation blah."""
If a class inherits from no other base classes, explicitly inherit from object. This also applies to
nested classes.
Yes:
class SampleClass(object):
pass
class OuterClass(object):
class InnerClass(object):
pass
class ChildClass(ParentClass):
"""Explicitly inherits from another class already."""
No:
class SampleClass:
pass
__Nebula Framework
24
NEBULA FRAMEWORK
Style guideline V.0
class OuterClass:
class InnerClass:
pass
Yes:
d = {'hello': 'world'}
# Or:
if 'hello' in d:
print d['hello']
No:
d = {'hello': 'world'}
if d.has_key('hello'):
print d['hello'] # prints 'world'
else:
print 'default_value'
__Nebula Framework
25
NEBULA FRAMEWORK
Style guideline V.0
Generator expressions follow almost the same syntax as list comprehensions but return a
generator instead of a list.
Creating a new list requires more work and uses more memory. If you are just going to loop
through the new list, prefer using an iterator instead.
Yes:
No:
Use list comprehensions when you really need to create a second list, for example if you need to
use the result multiple times.
If your logic is too complicated for a short list comprehension or generator expression, consider
using a generator function instead of returning a list.
Yes:
__Nebula Framework
26
NEBULA FRAMEWORK
Style guideline V.0
yield current_batch
current_batch = []
ield current_batch
y
Yes:
No:
Yes:
No:
__Nebula Framework
27
NEBULA FRAMEWORK
Style guideline V.0
Yes:
No:
f = open('file.txt')
a = f.read()
print a
f.close()
The with statement is better because it will ensure you always close the file, even if an exception
is raised inside the with block.
Obviously, we do not cover all the conventions here, for this you can consult PEP8.
Signal format
The Brain Imaging Data Structure (BIDS) project is a quickly evolving effort among the human
brain imaging research community to create standards allowing researchers to readily organize
and share study data within and between laboratories.
The specification follows the general BIDS: Each subject has a directory of raw data containing
subdirectories for each session and modality. This is accompanied by a dataset_description.json
__Nebula Framework
28
NEBULA FRAMEWORK
Style guideline V.0
file and a metadata file with the suffix _eeg.json, that specifies the task, the EEG system used
(amplifier, hardware filter, cap, placement scheme, etc.)
Figure 1. A prototypical directory tree of a BIDS dataset containing EEG data. At the root level
of the directory, the README, CHANGES, and dataset_description.json files provide basic
information about the dataset. A participants.tsv data file is accompanied by a participants.json
file, which contains the description of the columns in its associated .tsv file. The panel in the
upper right of the figure provides examples on the typical format within a .tsv and .json file.
Usually, each .tsv file is accompanied by a .json file that provides metadata. The EEG data and
anatomical MRI scans are saved per subject within the eeg and anat subdirectories respectively. If
the original data is not supported by BIDS, it can be included in an additional source data
directory. Finally, a stimuli directory contains the stimuli that were presented to the participants
in the experiment.
__Nebula Framework
29
NEBULA FRAMEWORK
Style guideline V.0
Reference
You can check for more in the following documents, and of course the content here is inspired
by:
https://www.python.org/dev/peps/pep-0008/
https://google.github.io/styleguide/pyguide.html
BIDS format:
Pernet, C. R., Appelhoff, S., Flandin, G., Phillips, C., Delorme, A., & Oostenveld, R. (2018,
December 6). BIDS-EEG: an extension to the Brain Imaging Data Structure (BIDS) Specification
for electroencephalography. https://doi.org/10.31234/osf.io/63a4y
__Nebula Framework
30