Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve documentation about writing type annotations #5218

Merged
merged 2 commits into from
Apr 7, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions docs/dev/style.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,42 @@ Of course, if this import style fundamentally cannot be used, do not let this
block submitting a pull request for the code as we will definitely grant
exceptions.

## Typing based import cycles
## Type annotations

Cirq makes extensive use of type annotations as defined by
[PEP 484](https://peps.python.org/pep-0484/). All new code should use type
annotations where possible, especially on public classes and functions to serve
as documentation, but also on internal code so that the mypy typechecker can
help catch coding errors.

For documentation purposes in particular, type annotations should match the way
classes and functions are accessed by cirq users, which is typically on the
top-level `cirq` namespace (for example, users use `cirq.Sampler` even though
the sampler class is defined in `cirq.work.sampler.Sampler`). Code in cirq-core
typically cannot import and use `cirq.Sampler` directly because this could
create an import cycle where modules import each other (perhaps indirectly).
Instead, the import of the top-level `cirq` library can be guarded by the
`TYPE_CHECKING` constant provided by `typing`, and the type annotation can be
quoted so that it is not evaluated when the module is imported but rather during
type-checking:

An import cycle is where modules need to import each other (perhaps indirectly).
Sometimes in order to add a type annotation you have to add an import which
causes a cycle. To avoid this we use the `TYPE_CHECKING` constant provided
by `typing`:
```python
from typing import TYPE_CHECKING

if TYPE_CHECKING:
# pylint: disable=unused-import
import module.that.causes.cycle
```
Note that if you do this you will need to use the string version of the type,
```python
def my_func() -> 'module.that.causes.cycle.MyClass':
pass
import cirq

def accepts_sampler(sampler: 'cirq.Sampler') -> None:
...
```

Use top-level `cirq.*` annotations like this when annotating new public types
and classes. Older code may not adhere to this style and should be updated.

Note that type annotations may need to be quoted like this in other situations
as well, such as when an annotation is a "forward reference" to a class defined
later in the same file.

## Nomenclature

Using consistent wording across Cirq is important for lowering users
Expand Down