8000 Add content from typeshed/CONTRIBUTING.md by yangdanny97 · Pull Request #1882 · python/typing · GitHub
[go: up one dir, main page]

Skip to content

Add content from typeshed/CONTRIBUTING.md #1882

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

Merged
merged 15 commits into from
Dec 17, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

< 8000 label class="SelectMenu-item" role="menuitem"> Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
format and fix link
  • Loading branch information
yangdanny97 committed Dec 12, 2024
commit 0cc549ecd7c022e3a06918e12f2e928f61166575
70 changes: 37 additions & 33 deletions docs/guides/writing_stubs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,15 @@ Incomplete Stubs

When writing new stubs, it is not necessary to fully annotate all arguments,
return types, and fields. Some items may be left unannotated or
annotated with `_typeshed.Incomplete` (`documentation <https://github.com/python/typeshed/blob/main/stdlib/_typeshed/README.md>`_).::
annotated with ``_typeshed.Incomplete`` (`documentation <https://github.com/python/typeshed/blob/main/stdlib/_typeshed/README.md>`_)::

from _typeshed import Incomplete

field: Incomplete # unannotated

def foo(x): ... # unannotated argument and return type

`Incomplete` can also be used for partially known types::
``_typeshed.Incomplete`` can also be used for partially known types::

def foo(x: Incomplete | None = None) -> list[Incomplete]: ...

Expand Down Expand Up @@ -267,39 +267,16 @@ annotated function ``bar()``::

def bar(x: str, y, *, z=...): ...

`Any` vs. `Incomplete`
----------------------
``Any`` vs. ``Incomplete``
--------------------------

While `Incomplete` is a type alias of `Any`, they serve difference purposes:
`Incomplete` is a placeholder where a proper type might be substituted.
It's a "to do" item and should be replaced if possible. `Any` is used when
it's not possible to accurately type an item using the current type system.
It should be used sparingly.
While ``Incomplete`` is a type alias of ``Any``, they serve difference purposes:
``Incomplete`` is a placeholder where a proper type might be substituted.
It's a "to do" item and should be replaced if possible.

The `Any` trick
---------------

In cases where a function or method can return `None`, but where forcing the
user to explicitly check for `None` can be detrimental, use
`_typeshed.MaybeNone` (an alias to `Any`), instead of `None`.

Consider the following (simplified) signature of `re.Match[str].group`::

class Match:
def group(self, group: str | int, /) -> str | MaybeNone: ...

This avoid forcing the user to check for `None`::

match = re.fullmatch(r"\d+_(.*)", some_string)
assert match is not None
name_group = match.group(1) # The user knows that this will never be None
return name_group.uper() # This typo will be flagged by the type checker

In this case, the user of `match.group()` must be prepared to handle a `str`,
but type checkers are happy with `if name_group is None` checks, because we're
saying it can also be something else than an `str`.

This is sometimes called "the Any trick".
``Any`` is used when it's not possible to accurately type an item using the current
type system. It should be used sparingly, as described in the :ref:`using-any`
section of the style guide.

Attribute Access
----------------
Expand Down Expand Up @@ -799,6 +776,8 @@ all type checkers::
def foo(x: int | str) -> int | None: ... # recommended
def foo(x: Union[int, str]) -> Optional[int]: ... # ok

.. _using-any:

Using `Any` and `object`
------------------------

Expand All @@ -814,6 +793,31 @@ that some function can accept literally anything: in those cases use
When using `Any`, document the reason for using it in a comment. Ideally,
document what types could be used.

The `Any` Trick
-----------------

In cases where a function or method can return ``None``, but where forcing the
user to explicitly check for ``None`` can be detrimental, use
``_typeshed.MaybeNone`` (an alias to ``Any``), instead of ``None``.

Consider the following (simplified) signature of ``re.Match[str].group``::

class Match:
def group(self, group: str | int, /) -> str | MaybeNone: ...

This avoid forcing the user to check for ``None``::

match = re.fullmatch(r"\d+_(.*)", some_string)
assert match is not None
name_group = match.group(1) # The user knows that this will never be None
return name_group.uper() # This typo will be flagged by the type checker

In this case, the user of ``match.group()`` must be prepared to handle a ``str``,
but type checkers are happy with ``if name_group is None`` checks, because we're
saying it can also be something else than an ``str``.

This is sometimes called "the Any trick".

Context Managers
----------------

Expand Down
Loading
0