Skip to content

[1.16 regression] a cast is both needed and redundant at the same time #19170

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

Open
hynek opened this issue May 30, 2025 · 3 comments · May be fixed by #19118
Open

[1.16 regression] a cast is both needed and redundant at the same time #19170

hynek opened this issue May 30, 2025 · 3 comments · May be fixed by #19118
Labels
bug mypy got something wrong topic-casts

Comments

@hynek
Copy link
Member

hynek commented May 30, 2025

Bug Report

Since 1.16, structlog's package type check fails with:

src/structlog/stdlib.py:1160: error: Redundant cast to "MutableMapping[str, Any]"  [redundant-cast]
                ed = p(logger, meth_name, cast(EventDict, ed))
                                          ^
Found 1 error in 1 file (checked 1 source file)

If I remove the cast, I get:

src/structlog/stdlib.py:1160: error: Argument 3 has incompatible type "Mapping[str, Any] | str | bytes | bytearray | tuple[Any, ...]"; expected
"MutableMapping[str, Any]"  [arg-type]
                ed = p(logger, meth_name, ed)
                                          ^~
Found 1 error in 1 file (checked 1 source file)

If I add a reveal_type, I get on both 1.15 & 1.16:

src/structlog/stdlib.py:1160: note: Revealed type is "typing.MutableMapping[builtins.str, Any]"
src/structlog/stdlib.py:1160: note: Revealed type is "Union[typing.Mapping[builtins.str, Any], builtins.str, builtins.bytes, builtins.bytearray, builtins.tuple[Any, ...]]"

So I guess Mypy got somehow smarter/confused about that?

To Reproduce

  • git clone git@github.com:hynek/structlog.git
  • git checkout d948027
  • run tox -e mypy-pkg

I really tried to create a minimal reproducer, but given that I don't quite understand what's going on, I've failed.

The relevant code is here: https://github.com/hynek/structlog/blob/e941e337d312eaf256595d9d09da4542c5e94d0b/src/structlog/stdlib.py#L1160

The types are defined here: https://github.com/hynek/structlog/blob/e941e337d312eaf256595d9d09da4542c5e94d0b/src/structlog/typing.py#L61-L76

Expected Behavior

I would expect it to keep working, or at least decide whether or not I need the cast. 🤓

Actual Behavior

I don't seem to find a way to make the code pass except using Any all over the place I guess.

Your Environment

edit I managed to work around it with the help of @Tinche but it still looks like I managed to break poor little Mypy.

@hynek hynek added the bug mypy got something wrong label May 30, 2025
@hauntsaninja
Copy link
Collaborator

Thanks! Probably proximal cause is #18588

If you'd like to upgrade to 1.16, p(logger, meth_name, cast(Any, ed)) is probably a foolproof workaround

@hauntsaninja
Copy link
Collaborator

hauntsaninja commented May 30, 2025

Minimised repro:

from typing import Callable, cast

class X: ...

ProcessorReturnValue = X | str | bytes
Processor = Callable[[X], ProcessorReturnValue]

def main_cast(p: Processor) -> None:
    ed: ProcessorReturnValue
    ed = cast(X, ...)

    for _ in range(5):
        ed = p(cast(X, ed))

def main_no_cast(p: Processor) -> None:
    ed: ProcessorReturnValue
    ed = cast(X, ...)

    for _ in range(5):
        ed = p(ed)

I guess the cast is redundant the second time through the loop...

@tyralla
Copy link
Collaborator

tyralla commented May 30, 2025

Yes, I hope we just have to handle codes.REDUNDANT_CAST the same way as codes.REDUNDANT_EXPR in #19118. Maybe there are more such candidates? (UNUSED_IGNORE or so)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong topic-casts
Projects
None yet
4 participants