Skip to content

Type error randomly raised when using a decorator and a type: ignore comment #18125

Closed
@Viicos

Description

@Viicos
Contributor

To Reproduce

  1. Create a new environment with pydantic==2.9.2 installed.
  2. Create a file t.py:
from typing import Any

from typing_extensions import Self

from pydantic import BaseModel, model_validator
from pydantic.functional_validators import ModelWrapValidatorHandler


class WrapModelValidator(BaseModel):
    @model_validator(mode='wrap')  # type: ignore[arg-type]  # pyright: ignore[reportArgumentType]
    def no_classmethod(cls, value: Any, handler: ModelWrapValidatorHandler[Self]) -> Self: ...
  1. Run mypy --cache-dir=/dev/null --python-version 3.10 --disable-error-code empty-body --warn-unused-ignores t.py

Mypy will randomly raise:

t.py:10: error: Unused "type: ignore" comment  [unused-ignore]

And sometimes suceed.

Sorry I couldn't provide more details, the issue is really weird and it seems like mypy doesn't produce fully reproducible results in this case.

Your Environment

  • Mypy version used: 1.13.0
  • Mypy command-line flags: --cache-dir=/dev/null --python-version 3.10 --disable-error-code empty-body --warn-unused-ignores
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.12

Activity

brianschubert

brianschubert commented on Nov 9, 2024

@brianschubert
Collaborator

Thanks! I can reproduce this locally. This is certainly a weird one!

So far I've narrowed this down to some non-deterministic behavior of is_subtype (specifically during this invocation).

What's quite interesting is that the nondeterministic behavior isn't just between mypy runs, but also between invocations of is_subtype with the same arguments during the same run (here's a video demo in my debugger).

sterliakov

sterliakov commented on Apr 22, 2025

@sterliakov
Collaborator

Okay, this is really indeterminate. mypy.solve.solve_one is order-sensitive and iterates over sets. The following patch (not a fix, but only a proof) makes mypy output on this snippet completely reproducible.

diff --git a/mypy/solve.py b/mypy/solve.py
index 57988790a..a6d9cfcd7 100644
--- a/mypy/solve.py
+++ b/mypy/solve.py
@@ -214,7 +214,7 @@ def solve_iteratively(
             break
         # Solve each solvable type variable separately.
         s_batch.remove(solvable_tv)
-        result = solve_one(lowers[solvable_tv], uppers[solvable_tv])
+        result = solve_one(sorted(lowers[solvable_tv], key=str), sorted(uppers[solvable_tv], key=str))
         solutions[solvable_tv] = result
         if result is None:
             # TODO: support backtracking lower/upper bound choices and order within SCCs.

The problematic case is solving the following set of constraints:

[1677 :> type[Self`0], 1677 :> Self`0, 1677 <: Self`0]

for Self`1667 where Self`0 has default=Any, upper_bound=p.WrapModelValidator. If the iteration starts with Self`0, we solve 1677 to Any, otherwise we conclude that deps can't be satisfied (None).

This problem stems from non-commutative join and meet implementation.

hauntsaninja

hauntsaninja commented on Apr 22, 2025

@hauntsaninja
Collaborator

Ah I ran into that in #16979 (comment) as well

added a commit that references this issue on May 26, 2025
2debb86
hauntsaninja

hauntsaninja commented on May 26, 2025

@hauntsaninja
Collaborator

Spent some time today looking at a few of these nondeterminism issues.

#19149 is a fix for this (it makes mypy consistently emit the error)

added a commit that references this issue on May 27, 2025
27d118b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrong

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @hauntsaninja@brianschubert@sterliakov@Viicos

      Issue actions

        Type error randomly raised when using a decorator and a `type: ignore` comment · Issue #18125 · python/mypy