mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Issues with solving value constrained type var in presence of Any

Open donn opened this issue 1 year ago • 7 comments

Bug Report

In 1.11.0, classes that inherit from os.PathLike could be used with os.path methods. As of 3.12, these methods claim to accept "any object implementing the os.PathLike protocol". However, in 1.12.0, mypy emits an error.

To Reproduce

import os


class MyPath(os.PathLike):
    def __init__(self, path: str):
        super().__init__()
        self.path = path

    def __fspath__(self):
        return self.path


print(os.path.abspath(MyPath(".")))

Expected Behavior

Unless I'm missing something, MyPath should be valid to pass, no?

Actual Behavior

pathlike.py:13: error: Value of type variable "AnyStr" of "abspath" cannot be "MyPath | Any"

Your Environment

  • Mypy version used: 1.12.0
  • Mypy command-line flags: N/A
  • Mypy configuration options from mypy.ini (and other config files): N/A
  • Python version used: 3.12

donn avatar Oct 15 '24 07:10 donn

Bisects to https://github.com/python/mypy/pull/17458 , probably caused by https://github.com/python/typeshed/pull/12208 Are you interested in opening a PR to typeshed reverting that change?

Note explicitly inheriting from os.PathLike[str] will fix.

hauntsaninja avatar Oct 15 '24 08:10 hauntsaninja

~~Looks like the same change may have broken Python 3.8 support of passing a StrPath to these methods. I know 3.8 just went EOL, but I thought I'd let others know in case they also get the Value of type variable "AnyStr" of "abspath" cannot be "Union[str, PathLike[Any], Any]" [type-var] error on Python 3.8.~~ Edit: See my other comment below

Setuptools failure: https://github.com/pypa/setuptools/pull/4688 & https://github.com/pypa/setuptools/actions/runs/11389961011/job/31690481419?pr=4688#step:9:68

Avasam avatar Oct 17 '24 18:10 Avasam

Are you interested in picking up reverting that typeshed PR?

hauntsaninja avatar Oct 17 '24 18:10 hauntsaninja

Nevermind, after failing to replicate in a typeshed test, and further investigation, mine was an issue with a setuptools declaration that was revealed by mypy 1.12 https://github.com/pypa/setuptools/blob/89b44013c79d2295ac0941e91b6904c0ce5522ba/setuptools/_path.py#L14-L17

if sys.version_info >= (3, 9):
    StrPath: TypeAlias = Union[str, os.PathLike[str]]  #  Same as _typeshed.StrPath
else:
    StrPath: TypeAlias = Union[str, os.PathLike]

Changing to:

if TYPE_CHECKING:
    StrPath: TypeAlias = Union[str, os.PathLike[str]]  #  Same as _typeshed.StrPath
else:
    # Python 3.8 support
    StrPath: TypeAlias = Union[str, os.PathLike]

Which explains why I was only seeing this on 3.8. As far as I'm concerned, I don't see my case as a regression, but rather a mypy finding a missing generic param it didn't see before.

Avasam avatar Oct 17 '24 18:10 Avasam

For OP's issue and another related regression I found in setuptools: https://github.com/python/typeshed/pull/12837

Avasam avatar Oct 17 '24 19:10 Avasam

For the purposes of making further changes to mypy, here's a repro that's independent of abspath in typeshed:

# mypy: disable-error-code=empty-body
import os
from typing import AnyStr

class MyPath(os.PathLike):
    def __init__(self, path: str):
        self.path = path

    def __fspath__(self):
        return self.pat

def abspath(path: os.PathLike[AnyStr] | AnyStr) -> AnyStr: ...

reveal_type(abspath(MyPath(".")))

hauntsaninja avatar Oct 17 '24 19:10 hauntsaninja

1.12.1 reverts the typeshed change, so there is no regression. Underlying issue still remains, so changing title. Possibly same thing as https://github.com/python/mypy/issues/11880

(Also linking that https://github.com/python/mypy/issues/3644 was the fix that led to the change in typeshed being attempted)

hauntsaninja avatar Oct 20 '24 01:10 hauntsaninja