Project import generated by Copybara.

PiperOrigin-RevId: 222009069
This commit is contained in:
Google Python team 2018-11-18 18:21:51 -08:00 committed by Gregory P. Smith [Google LLC]
parent ad22a7536d
commit 5b06d2d794

View File

@ -59,7 +59,7 @@ Make sure you run `pylint` on your code.
Suppress warnings if they are inappropriate so that other issues are not hidden. Suppress warnings if they are inappropriate so that other issues are not hidden.
To suppress warnings, you can set a line-level comment: To suppress warnings, you can set a line-level comment:
```python {.good} ```python
dict = 'something awful' # Bad Idea... pylint: disable=redefined-builtin dict = 'something awful' # Bad Idea... pylint: disable=redefined-builtin
``` ```
@ -90,7 +90,7 @@ Unused argument warnings can be suppressed by deleting the variables at the
beginning of the function. Always include a comment explaining why you are beginning of the function. Always include a comment explaining why you are
deleting it. "Unused." is sufficient. For example: deleting it. "Unused." is sufficient. For example:
```python {.good} ```python
def viking_cafe_order(spam, beans, eggs=None): def viking_cafe_order(spam, beans, eggs=None):
del beans, eggs # Unused by vikings. del beans, eggs # Unused by vikings.
return spam + spam + spam return spam + spam + spam
@ -140,7 +140,7 @@ name with no prefix.
For example the module `sound.effects.echo` may be imported as follows: For example the module `sound.effects.echo` may be imported as follows:
```python {.good} ```python
from sound.effects import echo from sound.effects import echo
... ...
echo.EchoFilter(input, output, delay=0.7, atten=4) echo.EchoFilter(input, output, delay=0.7, atten=4)
@ -176,7 +176,7 @@ All new code should import each module by its full package name.
Imports should be as follows: Imports should be as follows:
```python {.good} ```python
# Reference in code with complete name. # Reference in code with complete name.
import absl.flags import absl.flags
@ -228,7 +228,7 @@ Exceptions must follow certain conditions:
statement. For example: statement. For example:
```python {.good} ```python
Yes: Yes:
def connect_to_next_port(self, minimum): def connect_to_next_port(self, minimum):
"""Connects to the next available port. """Connects to the next available port.
@ -250,7 +250,7 @@ Exceptions must follow certain conditions:
return port return port
``` ```
```python {.bad} ```python
No: No:
def connect_to_next_port(self, minimum): def connect_to_next_port(self, minimum):
"""Connects to the next available port. """Connects to the next available port.
@ -289,7 +289,7 @@ Exceptions must follow certain conditions:
- When capturing an exception, use `as` rather than a comma. For example: - When capturing an exception, use `as` rather than a comma. For example:
```python {.good} ```python
try: try:
raise Error() raise Error()
except Error as error: except Error as error:
@ -402,7 +402,7 @@ expression, `for` clause, filter expression. Multiple `for` clauses or filter
expressions are not permitted. Use loops instead when things get more expressions are not permitted. Use loops instead when things get more
complicated. complicated.
```python {.good} ```python
Yes: Yes:
result = [mapping_expr for value in iterable if filter_expr] result = [mapping_expr for value in iterable if filter_expr]
@ -436,7 +436,7 @@ Yes:
if jelly_bean.color == 'black') if jelly_bean.color == 'black')
``` ```
```python {.bad} ```python
No: No:
result = [complicated_transform( result = [complicated_transform(
x, some_argument=x+1) x, some_argument=x+1)
@ -486,7 +486,7 @@ dictionaries, and files. The built-in types define iterator methods, too. Prefer
these methods to methods that return lists, except that you should not mutate a these methods to methods that return lists, except that you should not mutate a
container while iterating over it. container while iterating over it.
```python {.good} ```python
Yes: for key in adict: ... Yes: for key in adict: ...
if key not in adict: ... if key not in adict: ...
if obj in alist: ... if obj in alist: ...
@ -494,7 +494,7 @@ Yes: for key in adict: ...
for k, v in dict.iteritems(): ... for k, v in dict.iteritems(): ...
``` ```
```python {.bad} ```python
No: for key in adict.keys(): ... No: for key in adict.keys(): ...
if not adict.has_key(key): ... if not adict.has_key(key): ...
for line in afile.readlines(): ... for line in afile.readlines(): ...
@ -636,7 +636,7 @@ Okay to use with the following caveat:
Do not use mutable objects as default values in the function or method Do not use mutable objects as default values in the function or method
definition. definition.
```python {.good} ```python
Yes: def foo(a, b=None): Yes: def foo(a, b=None):
if b is None: if b is None:
b = [] b = []
@ -647,7 +647,7 @@ Yes: def foo(a, b: Sequence = ()): # Empty tuple OK since tuples are immutable
... ...
``` ```
```python {.bad} ```python
No: def foo(a, b=[]): No: def foo(a, b=[]):
... ...
No: def foo(a, b=time.time()): # The time the module was loaded??? No: def foo(a, b=time.time()): # The time the module was loaded???
@ -697,7 +697,7 @@ 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 to ensure methods overridden in subclasses are called by the property (using the
Template Method DP). Template Method DP).
```python {.good} ```python
Yes: import math Yes: import math
class Square(object): class Square(object):
@ -792,7 +792,7 @@ Use the "implicit" false if at all possible, e.g., `if foo:` rather than
known to be an integer (and is not the result of `len()`) against the known to be an integer (and is not the result of `len()`) against the
integer 0. integer 0.
```python {.good} ```python
Yes: if not users: Yes: if not users:
print('no users') print('no users')
@ -807,7 +807,7 @@ Use the "implicit" false if at all possible, e.g., `if foo:` rather than
x = [] x = []
``` ```
```python {.bad} ```python
No: if len(users) == 0: No: if len(users) == 0:
print('no users') print('no users')
@ -844,7 +844,7 @@ generally preferable.
We do not use any Python version which does not support these features, so there We do not use any Python version which does not support these features, so there
is no reason not to use the new styles. is no reason not to use the new styles.
```python {.good} ```python
Yes: words = foo.split(':') Yes: words = foo.split(':')
[x[1] for x in my_list if x[2] == 5] [x[1] for x in my_list if x[2] == 5]
@ -854,7 +854,7 @@ Yes: words = foo.split(':')
fn(*args, **kwargs) fn(*args, **kwargs)
``` ```
```python {.bad} ```python
No: words = string.split(foo, ':') No: words = string.split(foo, ':')
map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list)) map(lambda x: x[1], filter(lambda x: x[2] == 5, my_list))
@ -880,7 +880,7 @@ occurs, the name is treated as a global variable.
An example of the use of this feature is: An example of the use of this feature is:
```python {.good} ```python
def get_adder(summand1): def get_adder(summand1):
"""Returns a function that adds numbers to a given number.""" """Returns a function that adds numbers to a given number."""
def adder(summand2): def adder(summand2):
@ -901,7 +901,7 @@ experienced Lisp and Scheme (and Haskell and ML and ...) programmers.
Can lead to confusing bugs. Such as this example based on Can lead to confusing bugs. Such as this example based on
[PEP-0227](http://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0227/): [PEP-0227](http://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0227/):
```python {.bad} ```python
i = 4 i = 4
def foo(x): def foo(x):
def bar(): def bar():
@ -939,7 +939,7 @@ converting ordinary methods into dynamically computed attributes. However, the
decorator syntax allows for user-defined decorators as well. Specifically, for decorator syntax allows for user-defined decorators as well. Specifically, for
some function `my_decorator`, this: some function `my_decorator`, this:
```python {.good} ```python
class C(object): class C(object):
@my_decorator @my_decorator
def method(self): def method(self):
@ -949,7 +949,7 @@ class C(object):
is equivalent to: is equivalent to:
```python {.good} ```python
class C(object): class C(object):
def method(self): def method(self):
# method body ... # method body ...
@ -1085,7 +1085,7 @@ Use of `from __future__ import` statements is encouraged. All new code should
contain the following and existing code should be updated to be compatible when contain the following and existing code should be updated to be compatible when
possible: possible:
```python {.good} ```python
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
@ -1135,13 +1135,13 @@ modules.
Type annotations (or "type hints") are for function or method arguments and Type annotations (or "type hints") are for function or method arguments and
return values: return values:
```python {.good} ```python
def func(a: int) -> List[int]: def func(a: int) -> List[int]:
``` ```
You can also declare the type of a variable using a special comment: You can also declare the type of a variable using a special comment:
```python {.good} ```python
a = SomeFunc() # type: SomeType a = SomeFunc() # type: SomeType
``` ```
@ -1196,7 +1196,7 @@ Make use of Python's [implicit line joining inside parentheses, brackets and
braces](http://docs.python.org/reference/lexical_analysis.html#implicit-line-joining). braces](http://docs.python.org/reference/lexical_analysis.html#implicit-line-joining).
If necessary, you can add an extra pair of parentheses around an expression. If necessary, you can add an extra pair of parentheses around an expression.
```python {.good} ```python
Yes: foo_bar(self, width, height, color='black', design=None, x='foo', Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
emphasis=None, highlight=0) emphasis=None, highlight=0)
@ -1207,19 +1207,19 @@ Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
When a literal string won't fit on a single line, use parentheses for implicit When a literal string won't fit on a single line, use parentheses for implicit
line joining. line joining.
```python {.good} ```python
x = ('This will build a very long long ' x = ('This will build a very long long '
'long long long long long long string') 'long long long long long long string')
``` ```
Within comments, put long URLs on their own line if necessary. Within comments, put long URLs on their own line if necessary.
```python {.good} ```python
Yes: # See details at Yes: # See details at
# http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html
``` ```
```python {.bad} ```python
No: # See details at No: # See details at
# http://www.example.com/us/developer/documentation/api/content/\ # http://www.example.com/us/developer/documentation/api/content/\
# v2.0/csv_file_name_extension_full_specification.html # v2.0/csv_file_name_extension_full_specification.html
@ -1229,20 +1229,20 @@ It is permissible to use backslash continuation when defining a `with` statement
whose expressions span three or more lines. For two lines of expressions, use a whose expressions span three or more lines. For two lines of expressions, use a
nested `with` statement: nested `with` statement:
```python {.good} ```python
Yes: with very_long_first_expression_function() as spam, \ Yes: with very_long_first_expression_function() as spam, \
very_long_second_expression_function() as beans, \ very_long_second_expression_function() as beans, \
third_thing() as eggs: third_thing() as eggs:
place_order(eggs, beans, spam, beans) place_order(eggs, beans, spam, beans)
``` ```
```python {.bad} ```python
No: with VeryLongFirstExpressionFunction() as spam, \ No: with VeryLongFirstExpressionFunction() as spam, \
VeryLongSecondExpressionFunction() as beans: VeryLongSecondExpressionFunction() as beans:
PlaceOrder(eggs, beans, spam, beans) PlaceOrder(eggs, beans, spam, beans)
``` ```
```python {.good} ```python
Yes: with very_long_first_expression_function() as spam: Yes: with very_long_first_expression_function() as spam:
with very_long_second_expression_function() as beans: with very_long_second_expression_function() as beans:
place_order(beans, spam) place_order(beans, spam)
@ -1261,7 +1261,7 @@ 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 them in return statements or conditional statements unless using parentheses for
implied line continuation or to indicate a tuple. implied line continuation or to indicate a tuple.
```python {.good} ```python
Yes: if foo: Yes: if foo:
bar() bar()
while x: while x:
@ -1278,7 +1278,7 @@ Yes: if foo:
for (x, y) in dict.items(): ... for (x, y) in dict.items(): ...
``` ```
```python {.bad} ```python
No: if (x): No: if (x):
bar() bar()
if not(x): if not(x):
@ -1299,7 +1299,7 @@ you should align wrapped elements either vertically, as per the examples in the
in which case there should be nothing after the open parenthesis or bracket on in which case there should be nothing after the open parenthesis or bracket on
the first line. the first line.
```python {.good} ```python
Yes: # Aligned with opening delimiter Yes: # Aligned with opening delimiter
foo = long_function_name(var_one, var_two, foo = long_function_name(var_one, var_two,
var_three, var_four) var_three, var_four)
@ -1329,7 +1329,7 @@ Yes: # Aligned with opening delimiter
} }
``` ```
```python {.bad} ```python
No: # Stuff on first line forbidden No: # Stuff on first line forbidden
foo = long_function_name(var_one, var_two, foo = long_function_name(var_one, var_two,
var_three, var_four) var_three, var_four)
@ -1360,7 +1360,7 @@ element. The presence of a trailing comma is also used as a hint to our Python
code auto-formatter [YAPF](https://pypi.org/project/yapf/) to direct it to auto-format the container code auto-formatter [YAPF](https://pypi.org/project/yapf/) to direct it to auto-format the container
of items to one item per line when the `,` after the final element is present. of items to one item per line when the `,` after the final element is present.
```python {.good} ```python
Yes: golomb3 = [0, 1, 3] Yes: golomb3 = [0, 1, 3]
Yes: golomb4 = [ Yes: golomb4 = [
0, 0,
@ -1370,7 +1370,7 @@ Yes: golomb4 = [
] ]
``` ```
```python {.bad} ```python
No: golomb4 = [ No: golomb4 = [
0, 0,
1, 1,
@ -1396,24 +1396,24 @@ Follow standard typographic rules for the use of spaces around punctuation.
No whitespace inside parentheses, brackets or braces. No whitespace inside parentheses, brackets or braces.
```python {.good} ```python
Yes: spam(ham[1], {eggs: 2}, []) Yes: spam(ham[1], {eggs: 2}, [])
``` ```
```python {.bad} ```python
No: spam( ham[ 1 ], { eggs: 2 }, [ ] ) No: spam( ham[ 1 ], { eggs: 2 }, [ ] )
``` ```
No whitespace before a comma, semicolon, or colon. Do use whitespace after a No whitespace before a comma, semicolon, or colon. Do use whitespace after a
comma, semicolon, or colon except at the end of the line. comma, semicolon, or colon except at the end of the line.
```python {.good} ```python
Yes: if x == 4: Yes: if x == 4:
print(x, y) print(x, y)
x, y = y, x x, y = y, x
``` ```
```python {.bad} ```python
No: if x == 4 : No: if x == 4 :
print(x , y) print(x , y)
x , y = y , x x , y = y , x
@ -1422,20 +1422,20 @@ No: if x == 4 :
No whitespace before the open paren/bracket that starts an argument list, No whitespace before the open paren/bracket that starts an argument list,
indexing or slicing. indexing or slicing.
```python {.good} ```python
Yes: spam(1) Yes: spam(1)
``` ```
```python {.bad} ```python
No: spam (1) No: spam (1)
``` ```
```python {.good} ```python
Yes: dict['key'] = list[index] Yes: dict['key'] = list[index]
``` ```
```python {.bad} ```python
No: dict ['key'] = list [index] No: dict ['key'] = list [index]
``` ```
@ -1444,11 +1444,11 @@ Surround binary operators with a single space on either side for assignment
Booleans (`and, or, not`). Use your better judgment for the insertion of spaces Booleans (`and, or, not`). Use your better judgment for the insertion of spaces
around arithmetic operators (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `@`). around arithmetic operators (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `@`).
```python {.good} ```python
Yes: x == 1 Yes: x == 1
``` ```
```python {.bad} ```python
No: x<1 No: x<1
``` ```
@ -1457,12 +1457,12 @@ Only use spaces around the '=' sign defining a default parameter value
[when a type annotation is present](#typing-default-values), [when a type annotation is present](#typing-default-values),
do not use spaces around '=' for default parameter values otherwise. do not use spaces around '=' for default parameter values otherwise.
```python {.good} ```python
Yes: def complex(real, imag=0.0): return Magic(r=real, i=imag) Yes: def complex(real, imag=0.0): return Magic(r=real, i=imag)
Yes: def complex(real, imag: float = 0.0): return Magic(r=real, i=imag) Yes: def complex(real, imag: float = 0.0): return Magic(r=real, i=imag)
``` ```
```python {.bad} ```python
No: def complex(real, imag = 0.0): return Magic(r = real, i = imag) No: def complex(real, imag = 0.0): return Magic(r = real, i = imag)
No: def complex(real, imag: float=0.0): return Magic(r = real, i = imag) No: def complex(real, imag: float=0.0): return Magic(r = real, i = imag)
``` ```
@ -1470,7 +1470,7 @@ No: def complex(real, imag: float=0.0): return Magic(r = real, i = imag)
Don't use spaces to vertically align tokens on consecutive lines, since it Don't use spaces to vertically align tokens on consecutive lines, since it
becomes a maintenance burden (applies to `:`, `#`, `=`, etc.): becomes a maintenance burden (applies to `:`, `#`, `=`, etc.):
```python {.good} ```python
Yes: Yes:
foo = 1000 # comment foo = 1000 # comment
long_name = 2 # comment that should not be aligned long_name = 2 # comment that should not be aligned
@ -1481,7 +1481,7 @@ Yes:
} }
``` ```
```python {.bad} ```python
No: No:
foo = 1000 # comment foo = 1000 # comment
long_name = 2 # comment that should not be aligned long_name = 2 # comment that should not be aligned
@ -1592,7 +1592,7 @@ Sections should be indented two spaces, except for the heading.
[*Raises:*](#doc-function-raises) {#doc-function-raises} [*Raises:*](#doc-function-raises) {#doc-function-raises}
: List all exceptions that are relevant to the interface. : List all exceptions that are relevant to the interface.
```python {.good} ```python
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None): def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
"""Fetches rows from a Bigtable. """Fetches rows from a Bigtable.
@ -1633,7 +1633,7 @@ If your class has public attributes, they should be documented here in an
`Attributes` section and follow the same formatting as a `Attributes` section and follow the same formatting as a
[function's `Args`](#doc-function-args) section. [function's `Args`](#doc-function-args) section.
```python {.good} ```python
class SampleClass(object): class SampleClass(object):
"""Summary of class here. """Summary of class here.
@ -1664,7 +1664,7 @@ review](http://en.wikipedia.org/wiki/Code_review), you should comment it
now. Complicated operations get a few lines of comments before the operations now. Complicated operations get a few lines of comments before the operations
commence. Non-obvious ones get comments at the end of the line. commence. Non-obvious ones get comments at the end of the line.
```python {.good} ```python
# We use a weighted dictionary search to find out where i is in # We use a weighted dictionary search to find out where i is in
# the array. We extrapolate position based on the largest num # the array. We extrapolate position based on the largest num
# in the array and the array size and then do binary search to # in the array and the array size and then do binary search to
@ -1679,7 +1679,7 @@ code.
On the other hand, never describe the code. Assume the person reading the code On the other hand, never describe the code. Assume the person reading the code
knows Python (though not what you're trying to do) better than you do. knows Python (though not what you're trying to do) better than you do.
```python {.bad} ```python
# BAD COMMENT: Now go through the b array and make sure whenever i occurs # BAD COMMENT: Now go through the b array and make sure whenever i occurs
# the next element is i+1 # the next element is i+1
``` ```
@ -1709,7 +1709,7 @@ punctuation, spelling, and grammar help with that goal.
If a class inherits from no other base classes, explicitly inherit from If a class inherits from no other base classes, explicitly inherit from
`object`. This also applies to nested classes. `object`. This also applies to nested classes.
```python {.good} ```python
Yes: class SampleClass(object): Yes: class SampleClass(object):
pass pass
@ -1725,7 +1725,7 @@ Yes: class SampleClass(object):
``` ```
```python {.bad} ```python
No: class SampleClass: No: class SampleClass:
pass pass
@ -1750,7 +1750,7 @@ Use the `format` method or the `%` operator for formatting strings, even when
the parameters are all strings. Use your best judgement to decide between `+` the parameters are all strings. Use your best judgement to decide between `+`
and `%` (or `format`) though. and `%` (or `format`) though.
```python {.good} ```python
Yes: x = a + b Yes: x = a + b
x = '%s, %s!' % (imperative, expletive) x = '%s, %s!' % (imperative, expletive)
x = '{}, {}'.format(first, second) x = '{}, {}'.format(first, second)
@ -1759,7 +1759,7 @@ Yes: x = a + b
x = f'name: {name}; score: {n}' # Python 3.6+ x = f'name: {name}; score: {n}' # Python 3.6+
``` ```
```python {.bad} ```python
No: x = '%s%s' % (a, b) # use + in this case No: x = '%s%s' % (a, b) # use + in this case
x = '{}{}'.format(a, b) # use + in this case x = '{}{}'.format(a, b) # use + in this case
x = first + ', ' + second x = first + ', ' + second
@ -1772,7 +1772,7 @@ results in quadratic rather than linear running time. Instead, add each
substring to a list and `''.join` the list after the loop terminates (or, write substring to a list and `''.join` the list after the loop terminates (or, write
each substring to a `io.BytesIO` buffer). each substring to a `io.BytesIO` buffer).
```python {.good} ```python
Yes: items = ['<table>'] Yes: items = ['<table>']
for last_name, first_name in employee_list: for last_name, first_name in employee_list:
items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name)) items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name))
@ -1780,7 +1780,7 @@ Yes: items = ['<table>']
employee_table = ''.join(items) employee_table = ''.join(items)
``` ```
```python {.bad} ```python
No: employee_table = '<table>' No: employee_table = '<table>'
for last_name, first_name in employee_list: for last_name, first_name in employee_list:
employee_table += '<tr><td>%s, %s</td></tr>' % (last_name, first_name) employee_table += '<tr><td>%s, %s</td></tr>' % (last_name, first_name)
@ -1792,14 +1792,14 @@ or `"` and stick with it. It is okay to use the other quote character on a
string to avoid the need to `\\` escape within the string. `gpylint` enforces string to avoid the need to `\\` escape within the string. `gpylint` enforces
this. this.
```python {.good} ```python
Yes: Yes:
Python('Why are you hiding your eyes?') Python('Why are you hiding your eyes?')
Gollum("I'm scared of lint errors.") Gollum("I'm scared of lint errors.")
Narrator('"Good!" thought a happy Python reviewer.') Narrator('"Good!" thought a happy Python reviewer.')
``` ```
```python {.bad} ```python
No: No:
Python("Why are you hiding your eyes?") Python("Why are you hiding your eyes?")
Gollum('The lint. It burns. It burns us.') Gollum('The lint. It burns. It burns us.')
@ -1812,13 +1812,13 @@ use `'''` for all non-docstring multi-line strings if and only if they also use
often cleaner to use implicit line joining since multi-line strings do not flow often cleaner to use implicit line joining since multi-line strings do not flow
with the indentation of the rest of the program: with the indentation of the rest of the program:
```python {.good} ```python
Yes: Yes:
print("This is much nicer.\n" print("This is much nicer.\n"
"Do it this way.\n") "Do it this way.\n")
``` ```
```python {.bad} ```python
No: No:
print("""This is pretty ugly. print("""This is pretty ugly.
Don't do this. Don't do this.
@ -1858,7 +1858,7 @@ file is poor practice, for several reasons:
The preferred way to manage files is using the ["with" The preferred way to manage files is using the ["with"
statement](http://docs.python.org/reference/compound_stmts.html#the-with-statement): statement](http://docs.python.org/reference/compound_stmts.html#the-with-statement):
```python {.good} ```python
with open("hello.txt") as hello_file: with open("hello.txt") as hello_file:
for line in hello_file: for line in hello_file:
print(line) print(line)
@ -1867,7 +1867,7 @@ with open("hello.txt") as hello_file:
For file-like objects that do not support the "with" statement, use For file-like objects that do not support the "with" statement, use
`contextlib.closing()`: `contextlib.closing()`:
```python {.good} ```python
import contextlib import contextlib
with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page: with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page:
@ -1890,7 +1890,7 @@ The main purpose is to have a consistent `TODO` format that can be searched to
find out how to get more details upon request. A `TODO` is not a commitment that find out how to get more details upon request. A `TODO` is not a commitment that
the person referenced will fix the problem. Thus when you create a `TODO`, it is almost always your name that is given. the person referenced will fix the problem. Thus when you create a `TODO`, it is almost always your name that is given.
```python {.good} ```python
# TODO(kl@gmail.com): Use a "*" here for string repetition. # TODO(kl@gmail.com): Use a "*" here for string repetition.
# TODO(Zeke) Change this to use relations. # TODO(Zeke) Change this to use relations.
``` ```
@ -1907,12 +1907,12 @@ Imports should be on separate lines.
E.g.: E.g.:
```python {.good} ```python
Yes: import os Yes: import os
import sys import sys
``` ```
```python {.bad} ```python
No: import os, sys No: import os, sys
``` ```
@ -1923,7 +1923,7 @@ grouped with the order being most generic to least generic:
1. Python standard library imports. For example: 1. Python standard library imports. For example:
```python {.good} ```python
import sys import sys
``` ```
@ -1931,7 +1931,7 @@ grouped with the order being most generic to least generic:
module or package imports. For example: module or package imports. For example:
```python {.good} ```python
import tensorflow as tf import tensorflow as tf
``` ```
@ -1939,7 +1939,7 @@ grouped with the order being most generic to least generic:
sub-package imports. For example: sub-package imports. For example:
```python {.good} ```python
from otherproject.ai import mind from otherproject.ai import mind
``` ```
@ -1948,7 +1948,7 @@ grouped with the order being most generic to least generic:
sub-package as this file. For example: sub-package as this file. For example:
```python {.good} ```python
from myproject.backend.hgwells import time_machine from myproject.backend.hgwells import time_machine
``` ```
@ -1962,7 +1962,7 @@ Within each grouping, imports should be sorted lexicographically, ignoring case,
according to each module's full package path. Code may optionally place a blank according to each module's full package path. Code may optionally place a blank
line between import sections. line between import sections.
```python {.good} ```python
import collections import collections
import queue import queue
import sys import sys
@ -1997,13 +1997,13 @@ the entire statement fits on one line. In particular, you can never do so with
`try`/`except` since the `try` and `except` can't both fit on the same line, and `try`/`except` since the `try` and `except` can't both fit on the same line, and
you can only do so with an `if` if there is no `else`. you can only do so with an `if` if there is no `else`.
```python {.good} ```python
Yes: Yes:
if foo: bar(foo) if foo: bar(foo)
``` ```
```python {.bad} ```python
No: No:
if foo: bar(foo) if foo: bar(foo)
@ -2204,7 +2204,7 @@ 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 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. program so that the main program is not executed when the module is imported.
```python {.good} ```python
def main(): def main():
... ...
@ -2269,7 +2269,7 @@ Try to follow the existing [indentation](#indentation) rules.
After annotating, many function signatures will become "one parameter per line". After annotating, many function signatures will become "one parameter per line".
```python {.good} ```python
def my_method(self, def my_method(self,
first_var: int, first_var: int,
second_var: Foo, second_var: Foo,
@ -2281,7 +2281,7 @@ Always prefer breaking between variables, and not for example between variable
names and type annotations. However, if everything fits on the same line, names and type annotations. However, if everything fits on the same line,
go for it. go for it.
```python {.good} ```python
def my_method(self, first_var: int) -> int: def my_method(self, first_var: int) -> int:
... ...
``` ```
@ -2289,7 +2289,7 @@ def my_method(self, first_var: int) -> int:
If the combination of the function name, the last parameter, and the return type If the combination of the function name, the last parameter, and the return type
is too long, indent by 4 in a new line. is too long, indent by 4 in a new line.
```python {.good} ```python
def my_method( def my_method(
self, first_var: int) -> Tuple[MyLongType1, MyLongType1]: self, first_var: int) -> Tuple[MyLongType1, MyLongType1]:
... ...
@ -2299,7 +2299,7 @@ When the return type does not fit on the same line as the last parameter, the
preferred way is to indent the parameters by 4 on a new line and align the preferred way is to indent the parameters by 4 on a new line and align the
closing parenthesis with the def. closing parenthesis with the def.
```python {.good} ```python
Yes: Yes:
def my_method( def my_method(
self, **kw_args: Optional[MyLongType] self, **kw_args: Optional[MyLongType]
@ -2310,7 +2310,7 @@ def my_method(
`pylint` allows you to move the closing parenthesis to a new line and align `pylint` allows you to move the closing parenthesis to a new line and align
with the opening one, but this is less readable. with the opening one, but this is less readable.
```python {.bad} ```python
No: No:
def my_method(self, def my_method(self,
**kw_args: Optional[MyLongType] **kw_args: Optional[MyLongType]
@ -2321,7 +2321,7 @@ def my_method(self,
As in the examples above, prefer not to break types. However, sometimes they are As in the examples above, prefer not to break types. However, sometimes they are
too long to be on a single line (try to keep sub-types unbroken). too long to be on a single line (try to keep sub-types unbroken).
```python {.good} ```python
def my_method( def my_method(
self, self,
first_var: Tuple[List[MyLongType1], first_var: Tuple[List[MyLongType1],
@ -2335,7 +2335,7 @@ If a single name and type is too long, consider using an
[alias](#typing-aliases) for the type. The last resort is to break after the [alias](#typing-aliases) for the type. The last resort is to break after the
colon and indent by 4. colon and indent by 4.
```python {.good} ```python
Yes: Yes:
def my_function( def my_function(
long_variable_name: long_variable_name:
@ -2344,7 +2344,7 @@ def my_function(
... ...
``` ```
```python {.bad} ```python
No: No:
def my_function( def my_function(
long_variable_name: long_module_name. long_variable_name: long_module_name.
@ -2361,7 +2361,7 @@ If you need to use a class name from the same module that is not yet defined --
for example, if you need the class inside the class declaration, or if you use a for example, if you need the class inside the class declaration, or if you use a
class that is defined below -- use a string for the class name. class that is defined below -- use a string for the class name.
```python {.good} ```python
class MyClass(object): class MyClass(object):
def __init__(self, def __init__(self,
@ -2377,12 +2377,12 @@ when combining an argument annotation with a default value, use spaces around
the = sign (but only for those arguments that have both an annotation and a the = sign (but only for those arguments that have both an annotation and a
default). default).
```python {.good} ```python
Yes: Yes:
def func(a: int = 0) -> int: def func(a: int = 0) -> int:
... ...
``` ```
```python {.bad} ```python
No: No:
def func(a:int=0) -> int: def func(a:int=0) -> int:
... ...
@ -2401,7 +2401,7 @@ Use explicit `Optional` instead of implicit `Optional`. Earlier versions of PEP
484 allowed `a: Text = None` to be interpretted as `a: Optional[Text] = None`, 484 allowed `a: Text = None` to be interpretted as `a: Optional[Text] = None`,
but that is no longer the preferred behavior. but that is no longer the preferred behavior.
```python {.good} ```python
Yes: Yes:
def func(a: Optional[Text], b: Optional[Text] = None) -> Text: def func(a: Optional[Text], b: Optional[Text] = None) -> Text:
... ...
@ -2409,7 +2409,7 @@ def multiple_nullable_union(a: Union[None, Text, int]) -> Text
... ...
``` ```
```python {.bad} ```python
No: No:
def nullable_union(a: Union[None, Text]) -> Text: def nullable_union(a: Union[None, Text]) -> Text:
... ...
@ -2428,7 +2428,7 @@ returned tuples). If the alias is used only in this module, it should be
For example, if the name of module together with the type is too long: For example, if the name of module together with the type is too long:
```python {.good} ```python
SomeType = module_with_long_name.TypeWithLongName SomeType = module_with_long_name.TypeWithLongName
``` ```
@ -2444,7 +2444,7 @@ You can disable type checking on a line with the special comment
`pytype` has a disable option for specific errors (similar to lint): `pytype` has a disable option for specific errors (similar to lint):
```python {.good} ```python
# pytype: disable=attribute-error # pytype: disable=attribute-error
``` ```
@ -2455,7 +2455,7 @@ You can disable type checking on a line with the special comment
If an internal variable has a type that is hard or impossible to infer, you can If an internal variable has a type that is hard or impossible to infer, you can
supply it as a special comment: supply it as a special comment:
```python {.good} ```python
a = SomeUndecoratedFunction() # type: Foo a = SomeUndecoratedFunction() # type: Foo
``` ```
<a id="s3.19.9-tuples"></a> <a id="s3.19.9-tuples"></a>
@ -2466,7 +2466,7 @@ Unlike Lists, which can only have a single type, Tuples can have either a single
repeated type or a set number of elements with different types. The latter is repeated type or a set number of elements with different types. The latter is
commonly used as return type from a function. commonly used as return type from a function.
```python {.good} ```python
a = [1, 2, 3] # type: List[int] a = [1, 2, 3] # type: List[int]
b = (1, 2, 3) # type: Tuple[int, ...] b = (1, 2, 3) # type: Tuple[int, ...]
c = (1, "2", 3.5) # type: Tuple[int, Text, float] c = (1, "2", 3.5) # type: Tuple[int, Text, float]
@ -2482,7 +2482,7 @@ function `TypeVar` is a common way to use them.
Example: Example:
```python {.good} ```python
from typing import List, TypeVar from typing import List, TypeVar
T = TypeVar("T") T = TypeVar("T")
... ...
@ -2492,7 +2492,7 @@ def next(l: List[T]) -> T:
A TypeVar can be constrained: A TypeVar can be constrained:
```python {.good} ```python
AddableType = TypeVar("AddableType", int, float, Text) AddableType = TypeVar("AddableType", int, float, Text)
def add(a: AddableType, b: AddableType) -> AddableType: def add(a: AddableType, b: AddableType) -> AddableType:
return a + b return a + b
@ -2502,7 +2502,7 @@ A common predefined type variable in the `typing` module is `AnyStr`. Use it for
multiple annotations that can be `bytes` or `unicode` and must all be the same multiple annotations that can be `bytes` or `unicode` and must all be the same
type. type.
```python {.good} ```python
from typing import AnyStr from typing import AnyStr
def check_length(x: AnyStr) -> AnyStr: def check_length(x: AnyStr) -> AnyStr:
if len(x) <= 42: if len(x) <= 42:
@ -2514,40 +2514,55 @@ def check_length(x: AnyStr) -> AnyStr:
<a id="typing-strings"></a> <a id="typing-strings"></a>
#### 3.19.11 Strings types #### 3.19.11 Strings types
When annotating functions that take or return strings, avoid using `str`, The proper type for annotating strings depends on what versions of Python the
because it means different things in Python 2 and Python 3. In Python 2, `str` code is intended for.
is `bytes`; in Python 3, it is `unicode`. Whenever possible, it is best to be
explicit:
```python {.bad} For Python 3 only code, prefer to use `str`. `Text` is also acceptable. Be
consistent in using one or the other.
For Python 2 compatible code, use `Text`. In some rare cases, `str` may make
sense; typically to aid compatiblity when the return types aren't the same
between the two Python versions. Avoid using `unicode`: it doesn't exist in
Python 3.
The reason this discreprency exists is because `str` means different things
depending on the Python version.
```python
No: No:
def f(x: str) -> str: def py2_code(x: str) -> unicode:
... ...
``` ```
For code that deals with byte arrays, use `bytes`. For code that deals with binary data, use `bytes`.
```python {.good} ```python
def f(x: bytes) -> bytes: def deals_with_binary_data(x: bytes) -> bytes:
... ...
``` ```
For code that processes text data (`str` or `unicode` in Python 2, `str` in For Python 2 compatible code that processes text data (`str` or `unicode` in
Python 3), use `Text`. Python 2, `str` in Python 3), use `Text`. For Python 3 only code that process
text data, prefer `str`.
```python {.good} ```python
from typing import Text from typing import Text
... ...
def f(x: Text) -> Text: def py2_compatible(x: Text) -> Text:
...
def py3_only(x: str) -> str:
... ...
``` ```
If the type can be either byte arrays or text, use `Union`. If the type can be either bytes or text, use `Union`, with the appropriate text
type.
```python {.good} ```python
from typing import Text, Union from typing import Text, Union
... ...
def f(x: Union[bytes, Text]) -> Union[bytes, Text]: def py2_compatible(x: Union[bytes, Text]) -> Union[bytes, Text]:
...
def py3_only(x: Union[bytes, str]) -> Union[bytes, str]:
... ...
``` ```
@ -2565,7 +2580,7 @@ For classes from the `typing` module, always import the class itself. You are
explicitly allowed to import multiple specific classes on one line from the explicitly allowed to import multiple specific classes on one line from the
`typing` module. Ex: `typing` module. Ex:
```python {.good} ```python
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
``` ```
@ -2575,7 +2590,7 @@ not be defined in your Python code, typed or not. If there is a collision
between a type and an existing name in a module, import it using between a type and an existing name in a module, import it using
`import x as y`. `import x as y`.
```python {.good} ```python
from typing import Any as AnyType from typing import Any as AnyType
``` ```
@ -2601,7 +2616,7 @@ Imports that are needed only for type annotations can be placed within an
- There should be no empty lines in the typing imports list. - There should be no empty lines in the typing imports list.
- Sort this list as if it were a regular imports list. - Sort this list as if it were a regular imports list.
```python {.good} ```python
import typing import typing
if typing.TYPE_CHECKING: if typing.TYPE_CHECKING:
import sketch import sketch
@ -2622,7 +2637,7 @@ Replace modules that create circular dependency imports with `Any`. Set an
this module (any attribute of Any is Any). Alias definitions should be separated this module (any attribute of Any is Any). Alias definitions should be separated
from the last import by one line. from the last import by one line.
```python {.good} ```python
from typing import Any from typing import Any
some_mod = Any # some_mod.py imports this module. some_mod = Any # some_mod.py imports this module.
@ -2640,12 +2655,12 @@ def my_method(self, var: some_mod.SomeType) -> None:
When annotating, prefer to specify type parameters for generic types; otherwise, When annotating, prefer to specify type parameters for generic types; otherwise,
[the generics' parameters will be assumed to be `Any`](https://www.python.org/dev/peps/pep-0484/#the-any-type). [the generics' parameters will be assumed to be `Any`](https://www.python.org/dev/peps/pep-0484/#the-any-type).
```python {.good} ```python
def get_names(employee_ids: List[int]) -> Dict[int, Any]: def get_names(employee_ids: List[int]) -> Dict[int, Any]:
... ...
``` ```
```python {.bad} ```python
# These are both interpreted as get_names(employee_ids: List[Any]) -> Dict[Any, Any] # These are both interpreted as get_names(employee_ids: List[Any]) -> Dict[Any, Any]
def get_names(employee_ids: list) -> Dict: def get_names(employee_ids: list) -> Dict:
... ...
@ -2658,12 +2673,12 @@ If the best type parameter for a generic is `Any`, make it explicit, but
remember that in many cases [`TypeVar`](#typing-type-var) might be more remember that in many cases [`TypeVar`](#typing-type-var) might be more
appropriate: appropriate:
```python {.bad} ```python
def get_names(employee_ids: List[Any]) -> Dict[Any, Text]: def get_names(employee_ids: List[Any]) -> Dict[Any, Text]:
"""Returns a mapping from employee ID to employee name for given IDs.""" """Returns a mapping from employee ID to employee name for given IDs."""
``` ```
```python {.good} ```python
T = TypeVar('T') T = TypeVar('T')
def get_names(employee_ids: List[T]) -> Dict[T, Text]: def get_names(employee_ids: List[T]) -> Dict[T, Text]:
"""Returns a mapping from employee ID to employee name for given IDs.""" """Returns a mapping from employee ID to employee name for given IDs."""