Project import generated by Copybara.

PiperOrigin-RevId: 510217476
pull/716/merge
Google Python team 2023-02-16 12:44:30 -08:00 committed by Gregory P. Smith [Google LLC]
parent f924e89a56
commit e065b55718
1 changed files with 169 additions and 264 deletions

View File

@ -75,7 +75,7 @@ See README.md for details.
+ [3.19.7 Ignoring Types](#s3.19.7-ignoring-types)
+ [3.19.8 Typing Variables](#s3.19.8-typing-variables)
+ [3.19.9 Tuples vs Lists](#s3.19.9-tuples-vs-lists)
+ [3.19.10 TypeVars](#s3.19.10-typevars)
+ [3.19.10 Type variables](#s3.19.10-typevars)
+ [3.19.11 String types](#s3.19.11-string-types)
+ [3.19.12 Imports For Typing](#s3.19.12-imports-for-typing)
+ [3.19.13 Conditional Imports](#s3.19.13-conditional-imports)
@ -97,7 +97,7 @@ of *dos and don'ts* for Python programs.
To help you format code correctly, we've created a [settings file for Vim](google_python_style.vim). For Emacs, the default settings should be fine.
Many teams use the [yapf](https://github.com/google/yapf/)
Many teams use the [Black](https://github.com/psf/black) or [Pyink](https://github.com/google/pyink)
auto-formatter to avoid arguing over formatting.
@ -161,7 +161,8 @@ Suppress warnings if they are inappropriate so that other issues are not hidden.
To suppress warnings, you can set a line-level comment:
```python
dict = 'something awful' # Bad Idea... pylint: disable=redefined-builtin
def do_PUT(self): # WSGI name, so pylint: disable=invalid-name
...
```
`pylint`
@ -185,7 +186,7 @@ pylint --list-msgs
To get more information on a particular message, use:
```shell
pylint --help-msg=C6409
pylint --help-msg=invalid-name
```
Prefer `pylint: disable` to the deprecated older form `pylint: disable-msg`.
@ -195,7 +196,7 @@ beginning of the function. Always include a comment explaining why you are
deleting it. "Unused." is sufficient. For example:
```python
def viking_cafe_order(spam: str, beans: str, eggs: Optional[str] = None) -> str:
def viking_cafe_order(spam: str, beans: str, eggs: str | None = None) -> str:
del beans, eggs # Unused by vikings.
return spam + spam + spam
```
@ -347,7 +348,7 @@ No:
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
code should assume that `import jodie` refers to a third-party or top-level
package named `jodie`, not a local `jodie.py`.
@ -494,7 +495,7 @@ Avoid mutable global state.
<a id="global-variables-definition"></a>
#### 2.5.1 Definition
Module level values or class attributes that can get mutated during program
Module-level values or class attributes that can get mutated during program
execution.
<a id="s2.5.2-pros"></a>
@ -568,8 +569,8 @@ variables defined in enclosing scopes.
Allows definition of utility classes and functions that are only used inside of
a very limited scope. Very
[ADT](http://www.google.com/url?sa=D&q=http://en.wikipedia.org/wiki/Abstract_data_type)-y.
Commonly used for implementing decorators.
[ADT](https://en.wikipedia.org/wiki/Abstract_data_type)-y. Commonly used for
implementing decorators.
<a id="s2.6.3-cons"></a>
<a id="263-cons"></a>
@ -973,7 +974,7 @@ definition.
Yes: def foo(a, b=None):
if b is None:
b = []
Yes: def foo(a, b: Optional[Sequence] = None):
Yes: def foo(a, b: Sequence | None = None):
if b is None:
b = []
Yes: def foo(a, b: Sequence = ()): # Empty tuple OK since tuples are immutable.
@ -1197,8 +1198,8 @@ experienced Lisp and Scheme (and Haskell and ML and ...) programmers.
<a id="lexical-scoping-cons"></a>
#### 2.16.3 Cons
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/):
Can lead to confusing bugs, such as this example based on
[PEP-0227](https://peps.python.org/pep-0227/):
```python
i = 4
@ -1300,11 +1301,11 @@ decorator runs (at import time, perhaps from `pydoc` or other tools). A
decorator that is called with valid parameters should (as much as possible) be
guaranteed to succeed in all cases.
Decorators are a special case of "top level code" - see [main](#s3.17-main) for
Decorators are a special case of "top-level code" - see [main](#s3.17-main) for
more discussion.
Never use `staticmethod` unless forced to in order to integrate with an API
defined in an existing library. Write a module level function instead.
defined in an existing library. Write a module-level function instead.
Use `classmethod` only when writing a named constructor, or a class-specific
routine that modifies necessary global state such as a process-wide cache.
@ -1323,8 +1324,8 @@ or `__eq__` are implemented as Python methods) and their atomicity should not be
relied upon. Neither should you rely on atomic variable assignment (since this
in turn depends on dictionaries).
Use the Queue module's `Queue` data type as the preferred way to communicate
data between threads. Otherwise, use the threading module and its locking
Use the `queue` module's `Queue` data type as the preferred way to communicate
data between threads. Otherwise, use the `threading` module and its locking
primitives. Prefer condition variables and `threading.Condition` instead of
using lower-level locks.
@ -1460,11 +1461,11 @@ Use other `from __future__` import statements as you see fit.
### 2.21 Type Annotated Code
You can annotate Python code with type hints according to
[PEP-484](https://www.python.org/dev/peps/pep-0484/), and type-check the code at
build time with a type checking tool like [pytype](https://github.com/google/pytype).
[PEP-484](https://peps.python.org/pep-0484/), and type-check the code at build
time with a type checking tool like [pytype](https://github.com/google/pytype).
Type annotations can be in the source or in a
[stub pyi file](https://www.python.org/dev/peps/pep-0484/#stub-files). Whenever
[stub pyi file](https://peps.python.org/pep-0484/#stub-files). Whenever
possible, annotations should be in the source. Use pyi files for third-party or
extension modules.
@ -1483,7 +1484,7 @@ def func(a: int) -> list[int]:
```
You can also declare the type of a variable using similar
[PEP-526](https://www.python.org/dev/peps/pep-0526/) syntax:
[PEP-526](https://peps.python.org/pep-0526/) syntax:
```python
a: SomeType = some_func()
@ -1554,23 +1555,53 @@ Explicit exceptions to the 80 character limit:
- Long import statements.
- URLs, pathnames, or long flags in comments.
- Long string module level constants not containing whitespace that would be
- Long string module-level constants not containing whitespace that would be
inconvenient to split across lines such as URLs or pathnames.
- Pylint disable comments. (e.g.: `# pylint: disable=invalid-name`)
Do not use backslash line continuation except for `with` statements requiring
three or more context managers.
Do not use a backslash for
[explicit line continuation](https://docs.python.org/3/reference/lexical_analysis.html#explicit-line-joining).
Make use of Python's
Instead, 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.
Note that this rule doesn't prohibit backslash-escaped newlines within strings
(see [below](#strings)).
```python
Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
emphasis=None, highlight=0)
```
if (width == 0 and height == 0 and
```python
Yes: if (width == 0 and height == 0 and
color == 'red' and emphasis == 'strong'):
(bridge_questions.clarification_on
.average_airspeed_of.unladen_swallow) = 'African or European?'
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
No: if width == 0 and height == 0 and \
color == 'red' and emphasis == 'strong':
bridge_questions.clarification_on \
.average_airspeed_of.unladen_swallow = 'African or European?'
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)
```
When a literal string won't fit on a single line, use parentheses for implicit
@ -1581,6 +1612,37 @@ x = ('This will build a very long long '
'long long long long long long string')
```
Prefer to break lines at the highest possible syntactic level. If you must break
a line twice, break it at the same syntactic level both times.
```python
Yes: bridgekeeper.answer(
name="Arthur", quest=questlib.find(owner="Arthur", perilous=True))
answer = (a_long_line().of_chained_methods()
.that_eventually_provides().an_answer())
if (
config is None
or 'editor.language' not in config
or config['editor.language'].use_spaces is False
):
use_tabs()
```
```python
No: bridgekeeper.answer(name="Arthur", quest=questlib.find(
owner="Arthur", perilous=True))
answer = a_long_line().of_chained_methods().that_eventually_provides(
).an_answer()
if (config is None or 'editor.language' not in config or config[
'editor.language'].use_spaces is False):
use_tabs()
```
Within comments, put long URLs on their own line if necessary.
```python
@ -1594,29 +1656,6 @@ No: # See details at
# v2.0/csv_file_name_extension_full_specification.html
```
It is permissible to use backslash continuation when defining a `with` statement
with three or more context managers. For two context managers, use a nested
`with` statement:
```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
No: with VeryLongFirstExpressionFunction() as spam, \
VeryLongSecondExpressionFunction() as beans:
PlaceOrder(beans, spam)
```
```python
Yes: with very_long_first_expression_function() as spam:
with very_long_second_expression_function() as beans:
place_order(beans, spam)
```
Make note of the indentation of the elements in the line continuation examples
above; see the [indentation](#s3.4-indentation) section for explanation.
@ -1753,151 +1792,7 @@ No: # Stuff on first line forbidden.
Trailing commas in sequences of items are recommended only when the closing
container token `]`, `)`, or `}` does not appear on the same line as the final
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
Yes: golomb3 = [0, 1, 3]
Yes: golomb4 = [
0,
1,
4,
6,
]
```
```python
No: golomb4 = [
0,
1,
4,
6
]
```
<a id="s3.5-blank-lines"></a>
<a id="35-blank-lines"></a>
<a id="blank-lines"></a>
### 3.5 Blank Lines
Two blank lines between top-level definitions, be they function or class
definitions. One blank line between method definitions and between the docstring
of a `class` and the first method. No blank line following a `def` line. Use
single blank lines as you judge appropriate within functions or methods.
Blank lines need not be anchored to the definition. For example, related
comments immediately preceding function, class, and method definitions can make
sense. Consider if your comment might be more useful as part of the docstring.
<a id="s3.6-whitespace"></a>
<a id="36-whitespace"></a>
<a id="whitespace"></a>
### 3.6 Whitespace
Follow standard typographic rules for the use of spaces around punctuation.
No whitespace inside parentheses, brackets or braces.
```python
Yes: spam(ham[1], {'eggs': 2}, [])
```
```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
Yes: if x == 4:
print(x, y)
x, y = y, x
```
```python
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.
```python
Yes: spam(1)
```
```python
No: spam (1)
```
```python
Yes: dict['key'] = list[index]
```
```python
No: dict ['key'] = list [index]
```
No trailing whitespace.
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 (`+`, `-`, `*`, `/`, `//`, `%`, `**`, `@`).
```python
Yes: x == 1
```
```python
No: x<1
```
Never use spaces around `=` when passing keyword arguments or defining a default
parameter value, with one exception:
[when a type annotation is present](#typing-default-values), *do* use spaces
around the `=` for the default parameter value.
```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
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)
```
Don't use spaces to vertically align tokens on consecutive lines, since it
becomes a maintenance burden (applies to `:`, `#`, `=`, etc.):
```python
Yes:
foo = 1000 # comment
long_name = 2 # comment that should not be aligned
dictionary = {
'foo': 1,
'long_name': 2,
}
```
```python
No:
foo = 1000 # comment
long_name = 2 # comment that should not be aligned
dictionary = {
'foo' : 1,
'long_name': 2,
}
```
code auto-formatter
<a id="Python_Interpreter"></a>
<a id="s3.7-shebang-line"></a>
<a id="37-shebang-line"></a>
@ -1908,7 +1803,7 @@ No:
Most `.py` files do not need to start with a `#!` line. Start the main file of a
program with
`#!/usr/bin/env python3` (to support virtualenvs) or `#!/usr/bin/python3` per
[PEP-394](https://www.python.org/dev/peps/pep-0394/).
[PEP-394](https://peps.python.org/pep-0394/).
This line is used by the kernel to find the Python interpreter, but is ignored by Python when importing modules. It is only necessary on a file intended to be executed directly.
@ -1933,15 +1828,14 @@ Python uses *docstrings* to document code. A docstring is a string that is the
first statement in a package, module, class or function. These strings can be
extracted automatically through the `__doc__` member of the object and are used
by `pydoc`.
(Try running `pydoc` on your module to see how it looks.) Always use the three
double-quote `"""` format for docstrings (per
[PEP 257](https://www.google.com/url?sa=D&q=http://www.python.org/dev/peps/pep-0257/)).
A docstring should be organized as a summary line (one physical line not
exceeding 80 characters) terminated by a period, question mark, or exclamation
point. When writing more (encouraged), this must be followed by a blank line,
followed by the rest of the docstring starting at the same cursor position as
the first quote of the first line. There are more formatting guidelines for
docstrings below.
(Try running `pydoc` on your module to see how it looks.) Always use the
three-double-quote `"""` format for docstrings (per
[PEP 257](https://peps.python.org/pep-0257/)). A docstring should be organized
as a summary line (one physical line not exceeding 80 characters) terminated by
a period, question mark, or exclamation point. When writing more (encouraged),
this must be followed by a blank line, followed by the rest of the docstring
starting at the same cursor position as the first quote of the first line. There
are more formatting guidelines for docstrings below.
<a id="s3.8.2-comments-in-modules"></a>
<a id="382-modules"></a>
@ -1950,12 +1844,12 @@ docstrings below.
<a id="module-docs"></a>
#### 3.8.2 Modules
Every file should contain license boilerplate. Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL)
Every file should contain license boilerplate. Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL).
Files should start with a docstring describing the contents and usage of the
module.
```python
"""A one line summary of the module or program, terminated by a period.
"""A one-line summary of the module or program, terminated by a period.
Leave one blank line. The rest of this docstring should contain an
overall description of the module or program. Optionally, it may also
@ -2081,9 +1975,10 @@ aptly described using a one-line docstring.
part of the API).
```python
def fetch_smalltable_rows(table_handle: smalltable.Table,
keys: Sequence[Union[bytes, str]],
require_all_keys: bool = False,
def fetch_smalltable_rows(
table_handle: smalltable.Table,
keys: Sequence[bytes | str],
require_all_keys: bool = False,
) -> Mapping[bytes, tuple[str, ...]]:
"""Fetches rows from a Smalltable.
@ -2118,9 +2013,10 @@ def fetch_smalltable_rows(table_handle: smalltable.Table,
Similarly, this variation on `Args:` with a line break is also allowed:
```python
def fetch_smalltable_rows(table_handle: smalltable.Table,
keys: Sequence[Union[bytes, str]],
require_all_keys: bool = False,
def fetch_smalltable_rows(
table_handle: smalltable.Table,
keys: Sequence[bytes | str],
require_all_keys: bool = False,
) -> Mapping[bytes, tuple[str, ...]]:
"""Fetches rows from a Smalltable.
@ -2179,7 +2075,11 @@ class SampleClass:
"""
def __init__(self, likes_spam: bool = False):
"""Inits SampleClass with blah."""
"""Initializes the instance based on spam preference.
Args:
likes_spam: Defines if instance exhibits this preference.
"""
self.likes_spam = likes_spam
self.eggs = 0
@ -2293,6 +2193,7 @@ Yes: x = f'name: {name}; score: {n}'
x = '%s, %s!' % (imperative, expletive)
x = '{}, {}'.format(first, second)
x = 'name: %s; score: %d' % (name, n)
x = 'name: %(name)s; score: %(score)d' % {'name':name, 'score':n}
x = 'name: {}; score: {}'.format(name, n)
x = a + b
```
@ -2309,7 +2210,7 @@ be optimized on CPython, that is an implementation detail. The conditions under
which an optimization applies are not easy to predict and may change. Instead,
add each substring to a list and `''.join` the list after the loop terminates,
or write each substring to an `io.StringIO` buffer. These techniques
consistently have amortized-linear run time complexity.
consistently have amortized-linear run-time complexity.
```python
Yes: items = ['<table>']
@ -2388,6 +2289,11 @@ Don't do this.
will collapse common leading spaces in each line.""")
```
Note that using a backslash here does not violate the prohibition against
[explicit line continuation](#line-length); in this case, the backslash is
[escaping a newline](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)
in a string literal.
<a id="s3.10.1-logging"></a>
<a id="3101-logging"></a>
<a id="logging"></a>
@ -2644,7 +2550,7 @@ grouped from most generic to least generic:
```
5. **Deprecated:** application-specific imports that are part of the same
top level
top-level
sub-package as this file. For example:
@ -2782,8 +2688,8 @@ Always use a `.py` filename extension. Never use dashes.
- counters or iterators (e.g. `i`, `j`, `k`, `v`, et al.)
- `e` as an exception identifier in `try/except` statements.
- `f` as a file handle in `with` statements
- private [`TypeVar`s](#typing-type-var) with no constraints (e.g. `_T`,
`_U`, `_V`)
- private [type variables](#typing-type-var) with no constraints (e.g.
`_T = TypeVar("_T")`, `_P = ParamSpec("_P")`)
Please be mindful not to abuse single-character naming. Generally speaking,
descriptiveness should be proportional to the name's scope of visibility.
@ -2826,11 +2732,11 @@ Always use a `.py` filename extension. Never use dashes.
a class. ("wait -- did I write `import StringIO` or `from StringIO import
StringIO`?")
- Underscores may appear in *unittest* method names starting with `test` to
separate logical components of the name, even if those components use
CapWords. One possible pattern is `test<MethodUnderTest>_<state>`; for
example `testPop_EmptyStack` is okay. There is no One Correct Way to name
test methods.
- New *unit test* files follow PEP 8 compliant lower\_with\_under method
names, for example, `test_<method_under_test>_<state>`. For consistency(\*)
with legacy modules that follow CapWords function names, underscores may
appear in method names starting with `test` to separate logical components
of the name. One possible pattern is `test<MethodUnderTest>_<state>`.
<a id="s3.16.3-file-naming"></a>
<a id="3163-file-naming"></a>
@ -3015,8 +2921,7 @@ the function into smaller and more manageable pieces.
<a id="typing-general"></a>
#### 3.19.1 General Rules
* Familiarize yourself with
[PEP-484](https://www.python.org/dev/peps/pep-0484/).
* Familiarize yourself with [PEP-484](https://peps.python.org/pep-0484/).
* In methods, only annotate `self`, or `cls` if it is necessary for proper
type information. e.g.,
@ -3061,7 +2966,7 @@ def my_method(
self,
first_var: int,
second_var: Foo,
third_var: Optional[Bar],
third_var: Bar | None,
) -> int:
...
```
@ -3084,7 +2989,7 @@ parenthesis with the `def`:
Yes:
def my_method(
self,
other_arg: Optional[MyLongType],
other_arg: MyLongType | None,
) -> tuple[MyLongType1, MyLongType1]:
...
```
@ -3107,7 +3012,7 @@ opening one, but this is less readable.
```python
No:
def my_method(self,
other_arg: Optional[MyLongType],
other_arg: MyLongType | None,
) -> dict[OtherLongType, MyLongType]:
...
```
@ -3185,8 +3090,7 @@ class OtherClass:
<a id="typing-default-values"></a>
#### 3.19.4 Default Values
As per
[PEP-008](https://www.python.org/dev/peps/pep-0008/#other-recommendations), use
As per [PEP-008](https://peps.python.org/pep-0008/#other-recommendations), use
spaces around the `=` *only* for arguments that have both a type annotation and
a default value.
@ -3211,18 +3115,18 @@ def func(a:int=0) -> int:
In the Python type system, `NoneType` is a "first class" type, and for typing
purposes, `None` is an alias for `NoneType`. If an argument can be `None`, it
has to be declared! You can use `Union`, but if there is only one other type,
use `Optional`.
has to be declared! You can use `|` union type expressions (recommended in new
Python 3.10+ code), or the older `Optional` and `Union` syntaxes.
Use explicit `Optional` instead of implicit `Optional`. Earlier versions of PEP
484 allowed `a: str = None` to be interpreted as `a: Optional[str] = None`, but
that is no longer the preferred behavior.
Use explicit `X | None` instead of implicit. Earlier versions of PEP 484 allowed
`a: str = None` to be interpreted as `a: str | None = None`, but that is no
longer the preferred behavior.
```python
Yes:
def func(a: Optional[str], b: Optional[str] = None) -> str:
def modern_or_union(a: str | int | None, b: str | None = None) -> str:
...
def multiple_nullable_union(a: Union[None, str, int]) -> str:
def union_optional(a: Union[str, int, None], b: Optional[str] = None) -> str:
...
```
@ -3245,19 +3149,13 @@ def implicit_optional(a: str = None) -> str:
You can declare aliases of complex types. The name of an alias should be
CapWorded. If the alias is used only in this module, it should be \_Private.
For example, if the name of the module together with the name of the type is too
long:
<!-- Annotate below with `typing.TypeAlias` for 3.10. -->
Note that the `: TypeAlias` annotation is only supported in versions 3.10+.
```python
_LossAndGradient = tuple[tf.Tensor, tf.Tensor]
ComplexTFMap = Mapping[str, _LossAndGradient]
_LossAndGradient: TypeAlias = tuple[tf.Tensor, tf.Tensor]
ComplexTFMap: TypeAlias = Mapping[str, _LossAndGradient]
```
Other examples are complex nested types and multiple return variables from a
function (as a tuple).
<a id="s3.19.7-ignoring-types"></a>
<a id="s3.19.7-ignore"></a>
<a id="3197-ignoring-types"></a>
@ -3325,23 +3223,31 @@ c: tuple[int, str, float] = (1, "2", 3.5)
<a id="typing-type-var"></a>
<a id="typevars"></a>
#### 3.19.10 TypeVars
#### 3.19.10 Type variables
The Python type system has
[generics](https://www.python.org/dev/peps/pep-0484/#generics). The factory
function `TypeVar` is a common way to use them.
[generics](https://peps.python.org/pep-0484/#generics). A type variable, such as
`TypeVar` and `ParamSpec`, is a common way to use them.
Example:
```python
from typing import TypeVar
from collections.abc import Callable
from typing import ParamSpec, TypeVar
_P = ParamSpec("_P")
_T = TypeVar("_T")
...
def next(l: list[_T]) -> _T:
return l.pop()
def print_when_called(f: Callable[_P, _T]) -> Callable[_P, _T]:
def inner(*args: P.args, **kwargs: P.kwargs) -> R:
print('Function was called')
return f(*args, **kwargs)
return inner
```
A TypeVar can be constrained:
A `TypeVar` can be constrained:
```python
AddableType = TypeVar("AddableType", int, float, str)
@ -3360,8 +3266,8 @@ def check_length(x: AnyStr) -> AnyStr:
raise ValueError()
```
A TypeVar must have a descriptive name, unless it meets all of the following
criteria:
A type variable must have a descriptive name, unless it meets all of the
following criteria:
* not externally visible
* not constrained
@ -3369,6 +3275,7 @@ criteria:
```python
Yes:
_T = TypeVar("_T")
_P = ParamSpec("_P")
AddableType = TypeVar("AddableType", int, float, str)
AnyFunction = TypeVar("AnyFunction", bound=Callable)
```
@ -3376,6 +3283,7 @@ Yes:
```python
No:
T = TypeVar("T")
P = ParamSpec("P")
_T = TypeVar("_T", int, float, str)
_F = TypeVar("_F", bound=Callable)
```
@ -3418,7 +3326,7 @@ line from the `typing` and `collections.abc` modules. Ex:
```python
from collections.abc import Mapping, Sequence
from typing import Any, Union
from typing import Any, Generic
```
Given that this way of importing adds items to the local namespace, names in
@ -3460,7 +3368,7 @@ def generate_foo_scores(foo: Set[str]) -> List[float]:
Use conditional imports only in exceptional cases where the additional imports
needed for type checking must be avoided at runtime. This pattern is
discouraged; alternatives such as refactoring the code to allow top level
discouraged; alternatives such as refactoring the code to allow top-level
imports should be preferred.
Imports that are needed only for type annotations can be placed within an `if
@ -3496,8 +3404,8 @@ because each module has to depend on the other.
Replace modules that create circular dependency imports with `Any`. Set an
[alias](#typing-aliases) with a meaningful name, and use the real type name from
this module (any attribute of Any is Any). Alias definitions should be separated
from the last import by one line.
this module (any attribute of `Any` is `Any`). Alias definitions should be
separated from the last import by one line.
```python
from typing import Any
@ -3517,21 +3425,18 @@ def my_method(self, var: "some_mod.SomeType") -> None:
#### 3.19.15 Generics
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://peps.python.org/pep-0484/#the-any-type).
```python
# Yes:
def get_names(employee_ids: list[int]) -> dict[int, Any]:
def get_names(employee_ids: Sequence[int]) -> Mapping[int, str]:
...
```
```python
# No:
# 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:
# This is interpreted as get_names(employee_ids: Sequence[Any]) -> Mapping[Any, Any]
def get_names(employee_ids: Sequence) -> Mapping:
...
```
@ -3541,14 +3446,14 @@ appropriate:
```python
# No:
def get_names(employee_ids: list[Any]) -> dict[Any, str]:
def get_names(employee_ids: Sequence[Any]) -> Mapping[Any, str]:
"""Returns a mapping from employee ID to employee name for given IDs."""
```
```python
# Yes:
_T = TypeVar('_T')
def get_names(employee_ids: list[_T]) -> dict[_T, str]:
def get_names(employee_ids: Sequence[_T]) -> Mapping[_T, str]:
"""Returns a mapping from employee ID to employee name for given IDs."""
```