Skip to content
Closed
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[mypy]
check_untyped_defs = true
2 changes: 1 addition & 1 deletion mypy/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from mypy.version import __version__

try:
from lxml import etree # type: ignore[import-untyped]
from lxml import etree

LXML_INSTALLED = True
except ImportError:
Expand Down
8 changes: 4 additions & 4 deletions mypy/stubtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,10 @@ def verify_mypyfile(
if isinstance(runtime, Missing):
yield Error(object_path, "is not present at runtime", stub, runtime)
return
if not isinstance(runtime, types.ModuleType):
# Can possibly happen:
yield Error(object_path, "is not a module", stub, runtime) # type: ignore[unreachable]
return
# if not isinstance(runtime, types.ModuleType):
# Can possibly happen:
# yield Error(object_path, "is not a module", stub, runtime)
# return

runtime_all_as_set: set[str] | None

Expand Down
14 changes: 9 additions & 5 deletions mypy/suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -651,13 +651,17 @@ def extract_from_decorator(self, node: Decorator) -> FuncDef | None:
if not isinstance(typ, FunctionLike):
return None
for ct in typ.items:
if not (
len(ct.arg_types) == 1
and isinstance(ct.arg_types[0], TypeVarType)
and ct.arg_types[0] == ct.ret_type
):
if len(ct.arg_types) != 1:
return None
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looks like a special case for this decorator:

def f(x: T) -> T:
  return x

you should add a special case in addition to this.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, technically this line is limiting to that special case. And this will even fix the linked issue, two callables of that shape will compare equal AFAIC.

But this also makes the following (completely wrong) deco generate a signature:

def deco(fn: str) -> str: ...

@deco
def foo():
    print()

So I agree there should be one more special case, not just blanket "one-arg function returning its arg unchanged".

Copy link
Copy Markdown

@asottile-sentry asottile-sentry Apr 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that any identity function should be fine here -- if that decorator happens to have the wrong types that's not really this code's problem (it's just trying to unwrap the underlying callable) and I suspect there's many many ways to type an identity function with varying specificity making this particular condition difficult-to-impossible to write correctly exhaustively


arg_type = get_proper_type(ct.arg_types[0])
ret_type = get_proper_type(ct.ret_type)

if isinstance(arg_type, TypeVarType) and arg_type == ret_type:
continue

return None

return node.func

def try_type(self, func: FuncDef, typ: ProperType) -> list[str]:
Expand Down
15 changes: 10 additions & 5 deletions mypy/test/testcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import os
import re
import sys
import types

import pytest

from mypy import build
from mypy.build import Graph
Expand All @@ -24,14 +27,14 @@
)
from mypy.test.update_data import update_testcase_output

lxml: types.ModuleType | None
try:
import lxml # type: ignore[import-untyped]
import importlib

lxml = importlib.import_module("lxml")
except ImportError:
lxml = None


import pytest

# List of files that contain test case descriptions.
# Includes all check-* files with the .test extension in the test-data/unit directory
typecheck_files = find_test_files(pattern="check-*.test")
Expand All @@ -55,8 +58,10 @@ class TypeCheckSuite(DataSuite):
files = typecheck_files

def run_case(self, testcase: DataDrivenTestCase) -> None:
if lxml is None and os.path.basename(testcase.file) == "check-reports.test":
if lxml is None:
# if os.path.basename(testcase.file) == "check-reports.test":
pytest.skip("Cannot import lxml. Is it installed?")
# return
incremental = (
"incremental" in testcase.name.lower()
or "incremental" in testcase.file
Expand Down
9 changes: 7 additions & 2 deletions mypy/test/testcmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import re
import subprocess
import sys
import types

from mypy.test.config import PREFIX, test_temp_dir
from mypy.test.data import DataDrivenTestCase, DataSuite
Expand All @@ -19,11 +20,15 @@
normalize_error_messages,
)

lxml: types.ModuleType | None
try:
import lxml # type: ignore[import-untyped]
import importlib

lxml = importlib.import_module("lxml")
except ImportError:
lxml = None


import pytest

# Path to Python 3 interpreter
Expand All @@ -38,7 +43,7 @@ class PythonCmdlineSuite(DataSuite):
native_sep = True

def run_case(self, testcase: DataDrivenTestCase) -> None:
if lxml is None and os.path.basename(testcase.file) == "reports.test":
if os.path.basename(testcase.file) == "reports.test" and lxml is None:
pytest.skip("Cannot import lxml. Is it installed?")
for step in [1] + sorted(testcase.output2):
test_python_cmdline(testcase, step)
Expand Down
9 changes: 7 additions & 2 deletions mypy/test/testreports.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@

from __future__ import annotations

import importlib.util
import textwrap
import types

from mypy.report import CoberturaPackage, get_line_rate
from mypy.test.helpers import Suite, assert_equal

lxml: types.ModuleType | None
try:
import lxml # type: ignore[import-untyped]
import importlib

lxml = importlib.import_module("lxml")
except ImportError:
lxml = None

Expand All @@ -23,7 +28,7 @@ def test_get_line_rate(self) -> None:

@pytest.mark.skipif(lxml is None, reason="Cannot import lxml. Is it installed?")
def test_as_xml(self) -> None:
import lxml.etree as etree # type: ignore[import-untyped]
import lxml.etree as etree

cobertura_package = CoberturaPackage("foobar")
cobertura_package.covered_lines = 21
Expand Down
19 changes: 19 additions & 0 deletions mypy/test_decorator_suggestion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from typing import Callable, TypeVar
from typing_extensions import ParamSpec

R = TypeVar("R")
P = ParamSpec("P")


def dec(f: Callable[P, R]) -> Callable[P, R]:
return f


@dec
def f() -> None:
print("hello world")


@dec
def foo() -> None:
print()
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/_frozen_importlib.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import importlib.abc
import importlib.machinery
import sys
import types
import types
from _typeshed.importlib import LoaderProtocol
from collections.abc import Mapping, Sequence
from types import ModuleType
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/_frozen_importlib_external.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import _io
import importlib.abc
import importlib.machinery
import sys
import types
import types
from _typeshed import ReadableBuffer, StrOrBytesPath, StrPath
from _typeshed.importlib import LoaderProtocol
from collections.abc import Callable, Iterable, Iterator, Mapping, MutableSequence, Sequence
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/_imp.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
from _typeshed import ReadableBuffer
from importlib.machinery import ModuleSpec
from typing import Any
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/_interpreters.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import types
import types
from collections.abc import Callable, Mapping
from typing import Final, Literal, SupportsIndex
from typing_extensions import TypeAlias
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/asyncio/unix_events.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
from _typeshed import StrPath
from abc import ABCMeta, abstractmethod
from collections.abc import Callable
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/builtins.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import _ast
import _sitebuiltins
import _typeshed
import sys
import types
import types
from _collections_abc import dict_items, dict_keys, dict_values
from _typeshed import (
AnyStr_co,
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/codecs.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import types
import types
from _codecs import *
from _typeshed import ReadableBuffer
from abc import abstractmethod
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/dataclasses.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import enum
import sys
import types
import types
from _typeshed import DataclassInstance
from builtins import type as Type # alias to avoid name clashes with fields named "type"
from collections.abc import Callable, Iterable, Mapping
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/dis.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
from collections.abc import Callable, Iterator
from opcode import * # `dis` re-exports it as a part of public API
from typing import IO, Any, NamedTuple
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/doctest.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
import unittest
from _typeshed import ExcInfo
from collections.abc import Callable
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/email/headerregistry.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import types
import types
from collections.abc import Iterable, Mapping
from datetime import datetime as _datetime
from email._header_value_parser import (
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/enum.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _typeshed
import sys
import types
import types
from _typeshed import SupportsKeysAndGetItem, Unused
from builtins import property as _builtins_property
from collections.abc import Callable, Iterable, Iterator, Mapping
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/functools.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
from _typeshed import SupportsAllComparisons, SupportsItems
from collections.abc import Callable, Hashable, Iterable, Sized
from typing import Any, Generic, Literal, NamedTuple, TypedDict, TypeVar, final, overload
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/http/client.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import email.message
import io
import ssl
import sys
import types
import types
from _typeshed import MaybeNone, ReadableBuffer, SupportsRead, SupportsReadline, WriteableBuffer
from collections.abc import Callable, Iterable, Iterator, Mapping
from socket import socket
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/imp.pyi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import types
import types
from _imp import (
acquire_lock as acquire_lock,
create_dynamic as create_dynamic,
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/importlib/_abc.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
from abc import ABCMeta
from importlib.machinery import ModuleSpec

Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/importlib/abc.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _ast
import sys
import types
import types
from _typeshed import ReadableBuffer, StrPath
from abc import ABCMeta, abstractmethod
from collections.abc import Iterator, Mapping, Sequence
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/importlib/metadata/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import abc
import pathlib
import sys
import types
import types
from _collections_abc import dict_keys, dict_values
from _typeshed import StrPath
from collections.abc import Iterable, Iterator, Mapping
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/importlib/resources/_common.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import sys

# Even though this file is 3.11+ only, Pyright will complain in stubtest for older versions.
if sys.version_info >= (3, 11):
import types
import types
from collections.abc import Callable
from contextlib import AbstractContextManager
from importlib.abc import ResourceReader, Traversable
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/importlib/util.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import importlib.abc
import importlib.machinery
import sys
import types
import types
from _typeshed import ReadableBuffer
from collections.abc import Callable
from importlib._bootstrap import module_from_spec as module_from_spec, spec_from_loader as spec_from_loader
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/inspect.pyi
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import dis
import enum
import sys
import types
import types
from _typeshed import StrPath
from collections import OrderedDict
from collections.abc import AsyncGenerator, Awaitable, Callable, Coroutine, Generator, Mapping, Sequence, Set as AbstractSet
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/marshal.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import builtins
import sys
import types
import types
from _typeshed import ReadableBuffer, SupportsRead, SupportsWrite
from typing import Any
from typing_extensions import TypeAlias
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/pathlib.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
from _typeshed import (
OpenBinaryMode,
OpenBinaryModeReading,
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/socketserver.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
from _socket import _Address, _RetAddress
from _typeshed import ReadableBuffer
from collections.abc import Callable
Expand Down
2 changes: 1 addition & 1 deletion mypy/typeshed/stdlib/trace.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import types
import types
from _typeshed import Incomplete, StrPath, TraceFunction
from collections.abc import Callable, Iterable, Mapping, Sequence
from typing import Any, TypeVar
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -1831,7 +1831,7 @@ F = Callable[[Arg(int, 'x')], int] # E: Invalid argument constructor "__main__.
from typing import Callable, List
from mypy_extensions import Arg, VarArg, KwArg
import mypy_extensions
import types # Needed for type checking
import types # Needed for type checking

def WrongArg(x, y): return y
# Note that for this test, the 'Value of type "int" is not indexable' errors are silly,
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-python312.test
Original file line number Diff line number Diff line change
Expand Up @@ -1671,7 +1671,7 @@ x: Comparable[Good]
y: Comparable[int] # E: Type argument "int" of "Comparable" must be a subtype of "Comparable[Any]"

[case testPEP695TypeAliasWithDifferentTargetTypes]
import types # We need GenericAlias from here, and test stubs don't bring in 'types'
import types # We need GenericAlias from here, and test stubs don't bring in 'types'
from typing import Any, Callable, List, Literal, TypedDict

# Test that various type expressions don't generate false positives as type alias
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/check-type-object-type-inference.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# flags: --python-version 3.9
from typing import TypeVar, Generic, Type
from abc import abstractmethod
import types # Explicitly bring in stubs for 'types'
import types # Explicitly bring in stubs for 'types'

T = TypeVar('T')
class E(Generic[T]):
Expand Down
Loading
Loading