Skip to content

Commit

Permalink
Merge branch 'master' into fix/16808-stubgen-include-private-issue
Browse files Browse the repository at this point in the history
  • Loading branch information
nautics889 authored Feb 2, 2024
2 parents 53bbd3e + 3f58c2d commit 1ca45db
Show file tree
Hide file tree
Showing 336 changed files with 3,737 additions and 5,138 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ repos:
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.9.1 # must match test-requirements.txt
rev: 24.1.1 # must match test-requirements.txt
hooks:
- id: black
exclude: '^(test-data/)'
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.4 # must match test-requirements.txt
rev: v0.1.15 # must match test-requirements.txt
hooks:
- id: ruff
args: [--exit-non-zero-on-fix]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ To report a bug or request an enhancement:

To discuss a new type system feature:

- discuss at [typing-sig mailing list](https://mail.python.org/archives/list/typing[email protected]/)
- there is also some historical discussion [here](https://github.com/python/typing/issues)
- discuss at [discuss.python.org](https://discuss.python.org/c/typing/32)
- there is also some historical discussion at the [typing-sig mailing list](https://mail.python.org/archives/list/[email protected]/) and the [python/typing repo](https://github.com/python/typing/issues)

What is mypy?
-------------
Expand Down
4 changes: 4 additions & 0 deletions docs/source/config_file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
The mypy configuration file
===========================

Mypy is very configurable. This is most useful when introducing typing to
an existing codebase. See :ref:`existing-code` for concrete advice for
that situation.

Mypy supports reading configuration settings from a file with the following precedence order:

1. ``./mypy.ini``
Expand Down
23 changes: 7 additions & 16 deletions docs/source/error_codes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,6 @@ Most error codes are shared between multiple related error messages.
Error codes may change in future mypy releases.



Displaying error codes
----------------------

Error codes are displayed by default. Use :option:`--hide-error-codes <mypy --hide-error-codes>`
or config ``hide_error_codes = True`` to hide error codes. Error codes are shown inside square brackets:

.. code-block:: text
$ mypy prog.py
prog.py:1: error: "str" has no attribute "trim" [attr-defined]
It's also possible to require error codes for ``type: ignore`` comments.
See :ref:`ignore-without-code<code-ignore-without-code>` for more information.


.. _silence-error-codes:

Silencing errors based on error codes
Expand Down Expand Up @@ -121,3 +105,10 @@ Similar logic works for disabling error codes globally. If a given error code
is a subcode of another one, it will be mentioned in the documentation for the narrower
code. This hierarchy is not nested: there cannot be subcodes of other
subcodes.


Requiring error codes
---------------------

It's possible to require error codes be specified in ``type: ignore`` comments.
See :ref:`ignore-without-code<code-ignore-without-code>` for more information.
21 changes: 14 additions & 7 deletions docs/source/existing_code.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ invocation to your codebase, or adding your mypy invocation to
existing tools you use to run tests, like ``tox``.

* Make sure everyone runs mypy with the same options. Checking a mypy
:ref:`configuration file <config-file>` into your codebase can help
with this.
:ref:`configuration file <config-file>` into your codebase is the
easiest way to do this.

* Make sure everyone type checks the same set of files. See
:ref:`specifying-code-to-be-checked` for details.
Expand All @@ -48,7 +48,7 @@ A simple CI script could look something like this:

.. code-block:: text
python3 -m pip install mypy==0.971
python3 -m pip install mypy==1.8
# Run your standardised mypy invocation, e.g.
mypy my_project
# This could also look like `scripts/run_mypy.sh`, `tox run -e mypy`, `make mypy`, etc
Expand All @@ -74,6 +74,11 @@ You could even invert this, by setting ``ignore_errors = True`` in your global
config section and only enabling error reporting with ``ignore_errors = False``
for the set of modules you are ready to type check.

The per-module configuration that mypy's configuration file allows can be
extremely useful. Many configuration options can be enabled or disabled
only for specific modules. In particular, you can also enable or disable
various error codes on a per-module basis, see :ref:`error-codes`.

Fixing errors related to imports
--------------------------------

Expand All @@ -89,7 +94,7 @@ that it can't find, that don't have types, or don't have stub files:
Sometimes these can be fixed by installing the relevant packages or
stub libraries in the environment you're running ``mypy`` in.

See :ref:`ignore-missing-imports` for a complete reference on these errors
See :ref:`fix-missing-imports` for a complete reference on these errors
and the ways in which you can fix them.

You'll likely find that you want to suppress all errors from importing
Expand Down Expand Up @@ -118,13 +123,15 @@ codebase, use a config like this:
ignore_missing_imports = True
If you get a large number of errors, you may want to ignore all errors
about missing imports, for instance by setting :confval:`ignore_missing_imports`
to true globally. This can hide errors later on, so we recommend avoiding this
about missing imports, for instance by setting
:option:`--disable-error-code=import-untyped <mypy --ignore-missing-imports>`.
or setting :confval:`ignore_missing_imports` to true globally.
This can hide errors later on, so we recommend avoiding this
if possible.

Finally, mypy allows fine-grained control over specific import following
behaviour. It's very easy to silently shoot yourself in the foot when playing
around with these, so it's mostly recommended as a last resort. For more
around with these, so this should be a last resort. For more
details, look :ref:`here <follow-imports>`.

Prioritise annotating widely imported modules
Expand Down
22 changes: 13 additions & 9 deletions docs/source/running_mypy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -305,16 +305,20 @@ not catch errors in its use.
The ``.*`` after ``foobar`` will ignore imports of ``foobar`` modules
and subpackages in addition to the ``foobar`` top-level package namespace.

3. To suppress *all* missing import errors for *all* libraries in your codebase,
invoke mypy with the :option:`--ignore-missing-imports <mypy --ignore-missing-imports>` command line flag or set
the :confval:`ignore_missing_imports`
config file option to True
in the *global* section of your mypy config file::
3. To suppress *all* missing import errors for *all* untyped libraries
in your codebase, use :option:`--disable-error-code=import-untyped <mypy --ignore-missing-imports>`.
See :ref:`code-import-untyped` for more details on this error code.

You can also set :confval:`disable_error_code`, like so::

[mypy]
ignore_missing_imports = True
disable_error_code = import-untyped


We recommend using this approach only as a last resort: it's equivalent
You can also set the :option:`--ignore-missing-imports <mypy --ignore-missing-imports>`
command line flag or set the :confval:`ignore_missing_imports` config file
option to True in the *global* section of your mypy config file. We
recommend avoiding ``--ignore-missing-imports`` if possible: it's equivalent
to adding a ``# type: ignore`` to all unresolved imports in your codebase.


Expand Down Expand Up @@ -387,11 +391,11 @@ this error, try:
installing into the environment you expect by running pip like
``python -m pip ...``.

2. Reading the :ref:`finding-imports` section below to make sure you
3. Reading the :ref:`finding-imports` section below to make sure you
understand how exactly mypy searches for and finds modules and modify
how you're invoking mypy accordingly.

3. Directly specifying the directory containing the module you want to
4. Directly specifying the directory containing the module you want to
type check from the command line, by using the :confval:`mypy_path`
or :confval:`files` config file options,
or by using the ``MYPYPATH`` environment variable.
Expand Down
3 changes: 2 additions & 1 deletion mypy/applytype.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ def apply_generic_arguments(
bound or constraints, instead of giving an error.
"""
tvars = callable.variables
assert len(tvars) == len(orig_types)
min_arg_count = sum(not tv.has_default() for tv in tvars)
assert min_arg_count <= len(orig_types) <= len(tvars)
# Check that inferred type variable values are compatible with allowed
# values and bounds. Also, promote subtype values to allowed values.
# Create a map from type variable id to target type.
Expand Down
1 change: 1 addition & 0 deletions mypy/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
The function build() is the main interface to this module.
"""

# TODO: More consistent terminology, e.g. path/fnam, module/id, state/file

from __future__ import annotations
Expand Down
42 changes: 21 additions & 21 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,16 @@ def check_second_pass(
# print("XXX in pass %d, class %s, function %s" %
# (self.pass_num, type_name, node.fullname or node.name))
done.add(node)
with self.tscope.class_scope(
active_typeinfo
) if active_typeinfo else nullcontext():
with self.scope.push_class(
active_typeinfo
) if active_typeinfo else nullcontext():
with (
self.tscope.class_scope(active_typeinfo)
if active_typeinfo
else nullcontext()
):
with (
self.scope.push_class(active_typeinfo)
if active_typeinfo
else nullcontext()
):
self.check_partial(node)
return True

Expand Down Expand Up @@ -3802,9 +3806,11 @@ def check_multi_assignment_from_tuple(
if star_lv:
list_expr = ListExpr(
[
self.temp_node(rv_type, context)
if not isinstance(rv_type, UnpackType)
else StarExpr(self.temp_node(rv_type.type, context))
(
self.temp_node(rv_type, context)
if not isinstance(rv_type, UnpackType)
else StarExpr(self.temp_node(rv_type.type, context))
)
for rv_type in star_rv_types
]
)
Expand Down Expand Up @@ -6593,8 +6599,7 @@ def check_subtype(
notes: list[str] | None = None,
code: ErrorCode | None = None,
outer_context: Context | None = None,
) -> bool:
...
) -> bool: ...

@overload
def check_subtype(
Expand All @@ -6608,8 +6613,7 @@ def check_subtype(
*,
notes: list[str] | None = None,
outer_context: Context | None = None,
) -> bool:
...
) -> bool: ...

def check_subtype(
self,
Expand Down Expand Up @@ -7083,14 +7087,12 @@ def conditional_types_with_intersection(
type_ranges: list[TypeRange] | None,
ctx: Context,
default: None = None,
) -> tuple[Type | None, Type | None]:
...
) -> tuple[Type | None, Type | None]: ...

@overload
def conditional_types_with_intersection(
self, expr_type: Type, type_ranges: list[TypeRange] | None, ctx: Context, default: Type
) -> tuple[Type, Type]:
...
) -> tuple[Type, Type]: ...

def conditional_types_with_intersection(
self,
Expand Down Expand Up @@ -7348,15 +7350,13 @@ def visit_type_var(self, t: TypeVarType) -> None:
@overload
def conditional_types(
current_type: Type, proposed_type_ranges: list[TypeRange] | None, default: None = None
) -> tuple[Type | None, Type | None]:
...
) -> tuple[Type | None, Type | None]: ...


@overload
def conditional_types(
current_type: Type, proposed_type_ranges: list[TypeRange] | None, default: Type
) -> tuple[Type, Type]:
...
) -> tuple[Type, Type]: ...


def conditional_types(
Expand Down
42 changes: 26 additions & 16 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2132,11 +2132,13 @@ def infer_function_type_arguments(
unknown = UninhabitedType()
unknown.ambiguous = True
inferred_args = [
expand_type(
a, {v.id: unknown for v in list(callee_type.variables) + free_vars}
(
expand_type(
a, {v.id: unknown for v in list(callee_type.variables) + free_vars}
)
if a is not None
else None
)
if a is not None
else None
for a in poly_inferred_args
]
else:
Expand Down Expand Up @@ -2825,6 +2827,7 @@ def infer_overload_return_type(
# Return early if possible; otherwise record info, so we can
# check for ambiguity due to 'Any' below.
if not args_contain_any:
self.chk.store_types(m)
return ret_type, infer_type
p_infer_type = get_proper_type(infer_type)
if isinstance(p_infer_type, CallableType):
Expand Down Expand Up @@ -4711,6 +4714,7 @@ class LongName(Generic[T]): ...
item = get_proper_type(
set_any_tvars(
alias,
[],
ctx.line,
ctx.column,
self.chk.options,
Expand Down Expand Up @@ -4808,21 +4812,29 @@ def apply_type_arguments_to_callable(
tp = get_proper_type(tp)

if isinstance(tp, CallableType):
if len(tp.variables) != len(args) and not any(
isinstance(v, TypeVarTupleType) for v in tp.variables
):
min_arg_count = sum(not v.has_default() for v in tp.variables)
has_type_var_tuple = any(isinstance(v, TypeVarTupleType) for v in tp.variables)
if (
len(args) < min_arg_count or len(args) > len(tp.variables)
) and not has_type_var_tuple:
if tp.is_type_obj() and tp.type_object().fullname == "builtins.tuple":
# TODO: Specialize the callable for the type arguments
return tp
self.msg.incompatible_type_application(len(tp.variables), len(args), ctx)
self.msg.incompatible_type_application(
min_arg_count, len(tp.variables), len(args), ctx
)
return AnyType(TypeOfAny.from_error)
return self.apply_generic_arguments(tp, self.split_for_callable(tp, args, ctx), ctx)
if isinstance(tp, Overloaded):
for it in tp.items:
if len(it.variables) != len(args) and not any(
isinstance(v, TypeVarTupleType) for v in it.variables
):
self.msg.incompatible_type_application(len(it.variables), len(args), ctx)
min_arg_count = sum(not v.has_default() for v in it.variables)
has_type_var_tuple = any(isinstance(v, TypeVarTupleType) for v in it.variables)
if (
len(args) < min_arg_count or len(args) > len(it.variables)
) and not has_type_var_tuple:
self.msg.incompatible_type_application(
min_arg_count, len(it.variables), len(args), ctx
)
return AnyType(TypeOfAny.from_error)
return Overloaded(
[
Expand Down Expand Up @@ -6032,14 +6044,12 @@ def bool_type(self) -> Instance:
return self.named_type("builtins.bool")

@overload
def narrow_type_from_binder(self, expr: Expression, known_type: Type) -> Type:
...
def narrow_type_from_binder(self, expr: Expression, known_type: Type) -> Type: ...

@overload
def narrow_type_from_binder(
self, expr: Expression, known_type: Type, skip_non_overlapping: bool
) -> Type | None:
...
) -> Type | None: ...

def narrow_type_from_binder(
self, expr: Expression, known_type: Type, skip_non_overlapping: bool = False
Expand Down
9 changes: 4 additions & 5 deletions mypy/checkpattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,10 @@ def visit_sequence_pattern(self, o: SequencePattern) -> PatternType:
narrowed_inner_types = []
inner_rest_types = []
for inner_type, new_inner_type in zip(inner_types, new_inner_types):
(
narrowed_inner_type,
inner_rest_type,
) = self.chk.conditional_types_with_intersection(
new_inner_type, [get_type_range(inner_type)], o, default=new_inner_type
(narrowed_inner_type, inner_rest_type) = (
self.chk.conditional_types_with_intersection(
new_inner_type, [get_type_range(inner_type)], o, default=new_inner_type
)
)
narrowed_inner_types.append(narrowed_inner_type)
inner_rest_types.append(inner_rest_type)
Expand Down
Loading

0 comments on commit 1ca45db

Please sign in to comment.