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.
To suppress warnings, you can set a line-level comment:
```python {.good}
```python
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
deleting it. "Unused." is sufficient. For example:
```python {.good}
```python
def viking_cafe_order(spam, beans, eggs=None):
del beans, eggs # Unused by vikings.
return spam + spam + spam
@ -140,7 +140,7 @@ name with no prefix.
For example the module `sound.effects.echo` may be imported as follows:
```python {.good}
```python
from sound.effects import echo
...
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:
```python {.good}
```python
# Reference in code with complete name.
import absl.flags
@ -228,7 +228,7 @@ Exceptions must follow certain conditions:
statement. For example:
```python {.good}
```python
Yes:
def connect_to_next_port(self, minimum):
"""Connects to the next available port.
@ -250,7 +250,7 @@ Exceptions must follow certain conditions:
return port
```
```python {.bad}
```python
No:
def connect_to_next_port(self, minimum):
"""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:
```python {.good}
```python
try:
raise 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
complicated.
```python {.good}
```python
Yes:
result = [mapping_expr for value in iterable if filter_expr]
@ -436,7 +436,7 @@ Yes:
if jelly_bean.color == 'black')
```
```python {.bad}
```python
No:
result = [complicated_transform(
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
container while iterating over it.
```python {.good}
```python
Yes: for key in adict: ...
if key not in adict: ...
if obj in alist: ...
@ -494,7 +494,7 @@ Yes: for key in adict: ...
for k, v in dict.iteritems(): ...
```
```python {.bad}
```python
No: for key in adict.keys(): ...
if not adict.has_key(key): ...
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
definition.
```python {.good}
```python
Yes: def foo(a, b=None):
if b is None:
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=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
Template Method DP).
```python {.good}
```python
Yes: import math
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
integer 0.
```python {.good}
```python
Yes: if not users:
print('no users')
@ -807,7 +807,7 @@ Use the "implicit" false if at all possible, e.g., `if foo:` rather than
x = []
```
```python {.bad}
```python
No: if len(users) == 0:
print('no users')
@ -844,7 +844,7 @@ generally preferable.
We do not use any Python version which does not support these features, so there
is no reason not to use the new styles.
```python {.good}
```python
Yes: words = foo.split(':')
[x[1] for x in my_list if x[2] == 5]
@ -854,7 +854,7 @@ Yes: words = foo.split(':')
fn(*args, **kwargs)
```
```python {.bad}
```python
No: words = string.split(foo, ':')
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:
```python {.good}
```python
def get_adder(summand1):
"""Returns a function that adds numbers to a given number."""
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
[PEP-0227](http://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0227/):
```python {.bad}
```python
i = 4
def foo(x):
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
some function `my_decorator`, this:
```python {.good}
```python
class C(object):
@my_decorator
def method(self):
@ -949,7 +949,7 @@ class C(object):
is equivalent to:
```python {.good}
```python
class C(object):
def method(self):
# 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
possible:
```python {.good}
```python
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
@ -1135,13 +1135,13 @@ modules.
Type annotations (or "type hints") are for function or method arguments and
return values:
```python {.good}
```python
def func(a: int) -> List[int]:
```
You can also declare the type of a variable using a special comment:
```python {.good}
```python
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).
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',
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
line joining.
```python {.good}
```python
x = ('This will build a very long long '
'long long long long long long string')
```
Within comments, put long URLs on their own line if necessary.
```python {.good}
```python
Yes: # See details at
# 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
# http://www.example.com/us/developer/documentation/api/content/\
# 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
nested `with` statement:
```python {.good}
```python
Yes: with very_long_first_expression_function() as spam, \
very_long_second_expression_function() as beans, \
third_thing() as eggs:
place_order(eggs, beans, spam, beans)
```
```python {.bad}
```python
No: with VeryLongFirstExpressionFunction() as spam, \
VeryLongSecondExpressionFunction() as beans:
PlaceOrder(eggs, beans, spam, beans)
```
```python {.good}
```python
Yes: with very_long_first_expression_function() as spam:
with very_long_second_expression_function() as beans:
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
implied line continuation or to indicate a tuple.
```python {.good}
```python
Yes: if foo:
bar()
while x:
@ -1278,7 +1278,7 @@ Yes: if foo:
for (x, y) in dict.items(): ...
```
```python {.bad}
```python
No: if (x):
bar()
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
the first line.
```python {.good}
```python
Yes: # Aligned with opening delimiter
foo = long_function_name(var_one, var_two,
var_three, var_four)
@ -1329,7 +1329,7 @@ Yes: # Aligned with opening delimiter
}
```
```python {.bad}
```python
No: # Stuff on first line forbidden
foo = long_function_name(var_one, var_two,
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
of items to one item per line when the `,` after the final element is present.
```python {.good}
```python
Yes: golomb3 = [0, 1, 3]
Yes: golomb4 = [
0,
@ -1370,7 +1370,7 @@ Yes: golomb4 = [
]
```
```python {.bad}
```python
No: golomb4 = [
0,
1,
@ -1396,24 +1396,24 @@ Follow standard typographic rules for the use of spaces around punctuation.
No whitespace inside parentheses, brackets or braces.
```python {.good}
```python
Yes: spam(ham[1], {eggs: 2}, [])
```
```python {.bad}
```python
No: spam( ham[ 1 ], { eggs: 2 }, [ ] )
```
No whitespace before a comma, semicolon, or colon. Do use whitespace after a
comma, semicolon, or colon except at the end of the line.
```python {.good}
```python
Yes: if x == 4:
print(x, y)
x, y = y, x
```
```python {.bad}
```python
No: if x == 4 :
print(x , y)
x , y = y , x
@ -1422,20 +1422,20 @@ No: if x == 4 :
No whitespace before the open paren/bracket that starts an argument list,
indexing or slicing.
```python {.good}
```python
Yes: spam(1)
```
```python {.bad}
```python
No: spam (1)
```
```python {.good}
```python
Yes: dict['key'] = list[index]
```
```python {.bad}
```python
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
around arithmetic operators (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `@`).
```python {.good}
```python
Yes: x == 1
```
```python {.bad}
```python
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),
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: 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: 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
becomes a maintenance burden (applies to `:`, `#`, `=`, etc.):
```python {.good}
```python
Yes:
foo = 1000 # comment
long_name = 2 # comment that should not be aligned
@ -1481,7 +1481,7 @@ Yes:
}
```
```python {.bad}
```python
No:
foo = 1000 # comment
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}
: List all exceptions that are relevant to the interface.
```python {.good}
```python
def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
"""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
[function's `Args`](#doc-function-args) section.
```python {.good}
```python
class SampleClass(object):
"""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
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
# the array. We extrapolate position based on the largest num
# 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
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
# 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
`object`. This also applies to nested classes.
```python {.good}
```python
Yes: class SampleClass(object):
pass
@ -1725,7 +1725,7 @@ Yes: class SampleClass(object):
```
```python {.bad}
```python
No: class SampleClass:
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 `+`
and `%` (or `format`) though.
```python {.good}
```python
Yes: x = a + b
x = '%s, %s!' % (imperative, expletive)
x = '{}, {}'.format(first, second)
@ -1759,7 +1759,7 @@ Yes: x = a + b
x = f'name: {name}; score: {n}' # Python 3.6+
```
```python {.bad}
```python
No: x = '%s%s' % (a, b) # use + in this case
x = '{}{}'.format(a, b) # use + in this case
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
each substring to a `io.BytesIO` buffer).
```python {.good}
```python
Yes: items = ['<table>']
for last_name, first_name in employee_list:
items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name))
@ -1780,7 +1780,7 @@ Yes: items = ['<table>']
employee_table = ''.join(items)
```
```python {.bad}
```python
No: employee_table = '<table>'
for last_name, first_name in employee_list:
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
this.
```python {.good}
```python
Yes:
Python('Why are you hiding your eyes?')
Gollum("I'm scared of lint errors.")
Narrator('"Good!" thought a happy Python reviewer.')
```
```python {.bad}
```python
No:
Python("Why are you hiding your eyes?")
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
with the indentation of the rest of the program:
```python {.good}
```python
Yes:
print("This is much nicer.\n"
"Do it this way.\n")
```
```python {.bad}
```python
No:
print("""This is pretty ugly.
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"
statement](http://docs.python.org/reference/compound_stmts.html#the-with-statement):
```python {.good}
```python
with open("hello.txt") as hello_file:
for line in hello_file:
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
`contextlib.closing()`:
```python {.good}
```python
import contextlib
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
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(Zeke) Change this to use relations.
```
@ -1907,12 +1907,12 @@ Imports should be on separate lines.
E.g.:
```python {.good}
```python
Yes: import os
import sys
```
```python {.bad}
```python
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:
```python {.good}
```python
import sys
```
@ -1931,7 +1931,7 @@ grouped with the order being most generic to least generic:
module or package imports. For example:
```python {.good}
```python
import tensorflow as tf
```
@ -1939,7 +1939,7 @@ grouped with the order being most generic to least generic:
sub-package imports. For example:
```python {.good}
```python
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:
```python {.good}
```python
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
line between import sections.
```python {.good}
```python
import collections
import queue
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
you can only do so with an `if` if there is no `else`.
```python {.good}
```python
Yes:
if foo: bar(foo)
```
```python {.bad}
```python
No:
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
program so that the main program is not executed when the module is imported.
```python {.good}
```python
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".
```python {.good}
```python
def my_method(self,
first_var: int,
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,
go for it.
```python {.good}
```python
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
is too long, indent by 4 in a new line.
```python {.good}
```python
def my_method(
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
closing parenthesis with the def.
```python {.good}
```python
Yes:
def my_method(
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
with the opening one, but this is less readable.
```python {.bad}
```python
No:
def my_method(self,
**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
too long to be on a single line (try to keep sub-types unbroken).
```python {.good}
```python
def my_method(
self,
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
colon and indent by 4.
```python {.good}
```python
Yes:
def my_function(
long_variable_name:
@ -2344,7 +2344,7 @@ def my_function(
...
```
```python {.bad}
```python
No:
def my_function(
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
class that is defined below -- use a string for the class name.
```python {.good}
```python
class MyClass(object):
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
default).
```python {.good}
```python
Yes:
def func(a: int = 0) -> int:
...
```
```python {.bad}
```python
No:
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`,
but that is no longer the preferred behavior.
```python {.good}
```python
Yes:
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:
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:
```python {.good}
```python
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):
```python {.good}
```python
# 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
supply it as a special comment:
```python {.good}
```python
a = SomeUndecoratedFunction() # type: Foo
```
<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
commonly used as return type from a function.
```python {.good}
```python
a = [1, 2, 3] # type: List[int]
b = (1, 2, 3) # type: Tuple[int, ...]
c = (1, "2", 3.5) # type: Tuple[int, Text, float]
@ -2482,7 +2482,7 @@ function `TypeVar` is a common way to use them.
Example:
```python {.good}
```python
from typing import List, TypeVar
T = TypeVar("T")
...
@ -2492,7 +2492,7 @@ def next(l: List[T]) -> T:
A TypeVar can be constrained:
```python {.good}
```python
AddableType = TypeVar("AddableType", int, float, Text)
def add(a: AddableType, b: AddableType) -> AddableType:
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
type.
```python {.good}
```python
from typing import AnyStr
def check_length(x: AnyStr) -> AnyStr:
if len(x) <= 42:
@ -2514,40 +2514,55 @@ def check_length(x: AnyStr) -> AnyStr:
<a id="typing-strings"></a>
#### 3.19.11 Strings types
When annotating functions that take or return strings, avoid using `str`,
because it means different things in Python 2 and Python 3. In Python 2, `str`
is `bytes`; in Python 3, it is `unicode`. Whenever possible, it is best to be
explicit:
The proper type for annotating strings depends on what versions of Python the
code is intended for.
```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:
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}
def f(x: bytes) -> bytes:
```python
def deals_with_binary_data(x: bytes) -> bytes:
...
```
For code that processes text data (`str` or `unicode` in Python 2, `str` in
Python 3), use `Text`.
For Python 2 compatible code that processes text data (`str` or `unicode` in
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
...
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
...
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
`typing` module. Ex:
```python {.good}
```python
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
`import x as y`.
```python {.good}
```python
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.
- Sort this list as if it were a regular imports list.
```python {.good}
```python
import typing
if typing.TYPE_CHECKING:
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
from the last import by one line.
```python {.good}
```python
from typing import Any
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,
[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]:
...
```
```python {.bad}
```python
# These are both interpreted as get_names(employee_ids: List[Any]) -> Dict[Any, Any]
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
appropriate:
```python {.bad}
```python
def get_names(employee_ids: List[Any]) -> Dict[Any, Text]:
"""Returns a mapping from employee ID to employee name for given IDs."""
```
```python {.good}
```python
T = TypeVar('T')
def get_names(employee_ids: List[T]) -> Dict[T, Text]:
"""Returns a mapping from employee ID to employee name for given IDs."""