Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Shaun Stanworth
    @shauns_uk_gitlab

    I think the answer here is that it's not possible, but I'd like to be able to do the equivalent of a Typescript typeof for a function. An example:

    def foo(i: int) -> str:
        return "foo"
    
    
    class Bar:
        def __init__(self, fn: "foo"):
            self.captured = fn
    
        def baz(self):
            return self.captured("123")

    So the fn parameter in Bar constructor I'd like to enforce as matching the signature of foo (somehow). Obviously I could write a separate Callable or protocol, but this feels like duplication.

    ignormies
    @ignormies:matrix.org
    [m]
    I believe you'll need to wait for pep612:
    https://www.python.org/dev/peps/pep-0612/
    Shaun Stanworth
    @shauns_uk_gitlab
    Thank you - it's close to it (particularly the rejected ParametersOf approach) but I think the gap is more about the ergonomics of being able to lift a type from some other variable. Like uses_same_type_as_x: TypeOf[x] = ...(where in this example x happens to be a function) . Had a look through the PEPs and couldn't find anything along those lines. Wonder if a mypy plugin could do this...
    Bryan Forbes
    @bryanforbes
    @hauntsaninja does that mean there are wheels for the 0.790 release?
    Shantanu
    @hauntsaninja
    no it doesn't (i don't have the ability to do that), but it does mean you can download precompiled wheels for mypy master (which is much less painful than building them yourself). it also means it would now be fairly easy to add 3.9 wheels to 0.790 for someone with the ability to upload wheels to pypi
    Václav Brožík
    @vbrozik
    It looks like I have encountered an error in mypy 0.790. if else operator alternation of types compatible with Callable[[Iterable], Sequence] gives incompatible type builtins.object:
    #!/usr/bin/python3.9
    
    from typing import Callable, Iterable, Sequence
    
    deterministic: bool = True
    processlist1: Callable[[Iterable], Sequence] = sorted
    processlist2: Callable[[Iterable], Sequence] = list
    processlist3: Callable[[Iterable], Sequence] = sorted if deterministic else list
    
    reveal_type(sorted)
    reveal_type(list)
    reveal_type(sorted if deterministic else list)
    Python-tests$ mypy --show-error-code creator-callable.py 
    creator-callable.py:8: error: Incompatible types in assignment (expression has type "object", variable has type "Callable[[Iterable[Any]], Sequence[Any]]")  [assignment]
    creator-callable.py:10: note: Revealed type is 'Overload(def [_LT <: builtins._SupportsLessThan] (typing.Iterable[_LT`-1], *, key: None =, reverse: builtins.bool =) -> builtins.list[_LT`-1], def [_T] (typing.Iterable[_T`-1], *, key: def (_T`-1) -> builtins._SupportsLessThan, reverse: builtins.bool =) -> builtins.list[_T`-1])'
    creator-callable.py:11: note: Revealed type is 'Overload(def [_T] () -> builtins.list[_T`1], def [_T] (iterable: typing.Iterable[_T`1]) -> builtins.list[_T`1])'
    creator-callable.py:12: note: Revealed type is 'builtins.object'
    Found 1 error in 1 file (checked 1 source file)
    Callek
    @jwood:mozilla.org
    [m]
    @vbrozik: I'm not a dev, but I'd be interested if its reproduceable in 3.8 or latest dev build wheel of mypy for 3.9 -- since 0.790 did not officially support 3.9 and has no wheels available https://github.com/mypyc/mypy_mypyc-wheels/releases
    Bryan Forbes
    @bryanforbes
    @hauntsaninja thanks for letting me know… is there a way to point pip at a github URL and have it figure out which wheel to download for the arcitechture it’s running on?
    Shantanu
    @hauntsaninja
    not sure. maybe you could do something with --find-links.
    in case it's useful, here's some code in mypy to download all wheels for a given tag: https://github.com/python/mypy/blob/0c5936e08975ce1936c86f559d128cf25d30000e/misc/upload-pypi.py#L37 ... once downloaded, --find-links should work
    Václav Brožík
    @vbrozik
    ...if its reproduceable in 3.8...
    @jwood:mozilla.org thank you, I did not know that the current mypy does not support Python 3.9. I have changed the shebang to #!/usr/bin/python3.8 (I am using the default Python in Ubuntu 20.04: Python 3.8.5) and run mypy with Python 3.8 explicitly. The result is the same :(
    Python-tests$ python3.8 -m mypy --show-error-code creator-callable.py
    creator-callable.py:8: error: Incompatible types in assignment (expression has type "object", variable has type "Callable[[Iterable[Any]], Sequence[Any]]")  [assignment]
    creator-callable.py:10: note: Revealed type is 'Overload(def [_LT <: builtins._SupportsLessThan] (typing.Iterable[_LT`-1], *, key: None =, reverse: builtins.bool =) -> builtins.list[_LT`-1], def [_T] (typing.Iterable[_T`-1], *, key: def (_T`-1) -> builtins._SupportsLessThan, reverse: builtins.bool =) -> builtins.list[_T`-1])'
    creator-callable.py:11: note: Revealed type is 'Overload(def [_T] () -> builtins.list[_T`1], def [_T] (iterable: typing.Iterable[_T`1]) -> builtins.list[_T`1])'
    creator-callable.py:12: note: Revealed type is 'builtins.object'
    Found 1 error in 1 file (checked 1 source file)
    Shantanu
    @hauntsaninja
    @jwood:mozilla.org there are only two caveats to using mypy with 3.9, as mentioned here: https://github.com/python/mypy/issues/9761#issue-751858217 lack of a mypyc compiled wheel just means mypy runs a little slower. no need for FUD :-)
    2 replies
    the type signature for sorted was changed in the typeshed mypy 0.790 uses to enforce that the elements of the iterable are comparable
    this is to allow type checkers to catch issues like sorted([5, None])
    anyway, with a ternary expression, mypy performs what it calls a join to determine the type of the expression
    "join"-ing types means reveal_type(5 if random() else "asdf") reveals object (as opposed to Union[str, int])
    Shantanu
    @hauntsaninja
    it gets more complicated for generics. in particular, mypy almost never infers Any, since that causes code to go without type checking. in your example, you essentially want mypy to get a type with Any in it (Iterable is the same as Iterable[Any]).
    mypy does do what it calls type context, where it takes into account your annotation while making inferences. but not sure the logic is advanced enough for that to apply here.
    Shantanu
    @hauntsaninja
    there's also the question of whether mypy should use a join for ternary. i think it shouldn't, but big changes in inference are often annoying for users. ref https://github.com/python/mypy/issues/9264#issuecomment-674039604 (and the issue that that in turn links to)
    your case is actually very similar to that issue
    Bryan Forbes
    @bryanforbes
    @hauntsaninja thanks for the clue about --find-linkspip install -U --find-links https://github.com/mypyc/mypy_mypyc-wheels/releases/latest mypy works brilliantly
    Christoph Tyralla
    @tyralla

    Hi, is mypy drawing a wrong conclusion in the following example?
    ```from typing import Literal, runtime_checkable, Protocol

    @runtime_checkable
    class A(Protocol):
    x: Literal[0]

    class B:
    x: Literal[0, 1]

    class C(B):
    x: Literal[1]

    b = B()
    if isinstance(b, A): # error: Subclass of "B" and "A" cannot exist: would have incompatible method signatures [unreachable]
    b.x = 0 # error: Statement is unreachable [unreachable]```
    First, it says: "would have incompatible ... signatures". IMO, it should say: "could have incompatible ... signatures".

    Second, it handles the last line as (definitely) unreachable and does not analyse it further. However, it is just eventually unreachable, and mypy thus misses the definite bug in the last line.

    Christoph Tyralla
    @tyralla
    ```
    Christoph Tyralla
    @tyralla
    It doesn't need the Protocols. Maybe this example is clearer (mypy itself does not claim an incompatibility when defining class C1):
    from abc import abstractmethod
    from typing import *
    
    
    class A0:
        f: ClassVar[Literal[0]] = 0
    
    
    class A1:
        f: ClassVar[Literal[1]] = 1
    
    
    class B:
        @property
        @abstractmethod
        def f(self) -> Literal[0, 1]:
            ...
    
        def t(self) -> None:
            if isinstance(self, A0):  # error: Subclass of "B" and "A0" cannot exist: would have incompatible method signatures  [unreachable]
                ...
    
    
    class C1(A0, B):
        ...
    
    
    reveal_type(C1().f)  # Revealed type is 'Literal[0]'
    
    
    class C2(B, A0):  # Definition of "f" in base class "B" is incompatible with definition in base class "A0"  [misc
        ...
    
    
    reveal_type(C2().f)  # Cannot instantiate abstract class 'C2' with abstract attribute 'f'  [abstract]
    5 replies
    Henry Schreiner
    @henryiii

    To me, it seems like this is valid but produces an error in MyPy:

    class BaseDict(TypedDict):
        a: str
    
    class CustomDict(BaseDict):
        b: str
    
    def my_general_fun(x: BaseDict) -> None:
        print(x[“a”], x.get(“b”))

    MyPy will not allow this because BaseDict has no attribute ”b”. But isn’t the point of .get to get an attribute that might be missing?

    Couldn’t find anything exactly matching it in the issues, but it’s tricy to search for.
    Adrian Freund
    @freundTech
    @henryiii I'm not that experienced with mypy, but from my Understanding of PEP589 that should be allowed:
    "Operations with arbitrary str keys (instead of string literals or other expressions with known string values) should generally be rejected. This involves both destructive operations such as setting an item and read-only operations such as subscription expressions. As an exception to the above rule, d.get(e) and e in d should be allowed for TypedDict objects, for an arbitrary expression e with type str. The motivation is that these are safe and can be useful for introspecting TypedDict objects."
    Henry Schreiner
    @henryiii
    This seems to be where it’s being locked in. Sounds a little silly, but since this is a literal check, making this a variable makes it pass.
    I think it should infer the type if it’s a get and known, but if it’s not known, it should return Any (or at the very least, the second part of the get or None)
    I feel the description "arbitrary expression” above includes literal expressions
    Henry Schreiner
    @henryiii
    I’ve put this issue in: python/mypy#9902
    Abc Abc
    @Blackjack37_gitlab
    Hey, I'm trying to use a TypedDict and make a function that only accept values from the TypedDict but when I try to create that function using a Union Mypy complain that the dictionary values are of type object, how can I make him understand the real possible types? This is an example of the problem:
    from typing import Union, TypedDict
    
    def func(arg: Union[str, int]):
        print(arg)
    
    
    class Type(TypedDict, total=False):
        a: str
        b: int
    
    
    c = Type({"a": "a", "b": 2})
    for val in c.values():
        func(val)
    2 replies
    Boni Lindsley
    @BoniLindsley_gitlab
    I am trying to use asynccontextmanager. I think I found a bug with it. Not sure whether its issue should go into mypy or typeshed's repository though. And... it is also certainly possible that I have missed something obvious and it is not a bug.
    Shantanu
    @hauntsaninja
    I'd file a bug on mypy. IIRC mypy already special cases contextlib.contextmanager
    5 replies
    PEP 612 should help here
    Torin Tung Kwok
    @torinkwok

    Hello the community,

    I just posted a question on StackOverflow: Generic types lose their Generic[T, …] base class in the .pyi file generated by stubgen. And I pasted the question here and any hint would be appreciated. :-)

    Let's say here is a very simple class that represents a generic stack and hence is inherited from Generic[T] (§1).

    from typing import TypeVar, Generic, List
    
    T = TypeVar('T')
    
    class Stack(Generic[T]): #1
        def __init__(self) -> None:
            self.items: List[T] = []
    
        def push(self, item: T) -> None:
            self.items.append(item)
    
        def pop(self) -> T:
            return self.items.pop()
    
        def empty(self) -> bool:
            return not self.items

    And then let's generate a stub file .pyi for the module in which the Stack class lies, say, stack.py:

    $ stubgen stack.py --output stubs

    It's obvious that the Generic[T] base class was unexpectedly stripped off (§2). Meanwhile, the type hint for the items property was replaced as Any (§3). Additionally, what makes things more weird is that the stubbed versions of both push and pop still bore the type hint T for the parameter and the return value respectively (§4 and §5).

    from typing import Any, TypeVar
    
    T = TypeVar('T')
    
    class Stack: #2
        items: Any = ... #3
        def __init__(self) -> None: ...
        def push(self, item: T) -> None: ... #4
        def pop(self) -> T: ... #5
        def empty(self) -> bool: ...

    What happened during the generation of the stub? Is there any explanation to justify such a behavior?

    P.S. My mypy version is 0.790.

    Thomas Grainger
    @graingert
    @torinkwok why are you stubgenning an annotated .py?
    mahmoudajawad
    @mahmoudajawad:matrix.org
    [m]
    I have a method that accepts one argument typed as List[Union[str, int, float, bool]], however when I use it with an argument typed as List[str] I get the following errors:
    Argument "literal" to "LITERAL" of "ATTR" has incompatible type "List[str]"; expected "List[Union[str, int, float, bool]]"mypy(error)
    "List" is invariant -- see http://mypy.readthedocs.io/en/latest/common_issues.html#variancemypy(note)
    Consider using "Sequence" instead, which is covariantmypy(note)
    1 reply
    Bryan Fordney
    @bryab
    In mypy is anyone aware of a way to make it "assume" certain custom built-ins? I would like to use it to type-check some scripts for VFX applications (Nuke, Blender, etc) which have their own built-in functions and objects. I'd like to see if I can write stubs for those, but I also would need mypy to "assume" that they have already been imported.
    For example in Blackmagic Fusion there is an object called fusion which does not need to be imported in your scripts; I need mypy to know that it's already available without being explicitly imported.
    Vito De Tullio
    @ZeeD

    can I define a type as the result value of a function?
    I am in this situation: I am using a library that "do stuff" on import. A way to "shut it" is to define an environmental variable before, and I want to do it specifically during the run of the unit tests.
    I was thinking to factor it in a importlib.import_module "wrapper", so I would have

    from package.module import Class
    
    def foo(obj: Class) -> None: ...

    in "normal" normal code, and

    from testsupport import my_import_function
    Class = my_import_function('package.module', 'Class') # this will internally do the "import dance"
    def mock_class_obj() -> Class:
        mock_class_obj = unittest.mock.create_autospec(spec=Class, instance=True)
        # set up behavior...
       return mock_class_obj

    unfortunately I don't get how to write the my_import_function return type... I was thinking something like

    def my_import_function(name: str, class_name: str) -> typing.Type[typing.Any]:
        module = importlib.import_module(name, package)
        return typing.cast(typing.Type[typing.Any], getattr(module, class_name))

    and "it works", but then I have the error error: Variable "mocks.C" is not valid as a type at the signature of mock_class_obj

    2 replies
    baharbabu
    @baharbabu
    Which editor is best for python, pygame
    Callek
    @jwood:mozilla.org
    [m]
    I prefer VSCode, but I have seen many prefer vim, or Emacs, or PyCharm, or .... <etc> - It mostly comes down to what you prefer than anything else
    RK
    @sonthonaxrk

    Hey there. Question about Python typechecking: what tool should I use to check the types of classes with dynamically created methods?

    Let us say we have a Client class that is dynamically created with methods like this:

    >>> client = Client(open_api_spec)
    # Dynamically created method with dynamically added annotations
    >>> client.get_example.__annotations__
    {'return': MySchemaClass}

    What tool should I use to analyse my code?

    I could possibly solve this using code generation, where I would create a Client class with all of the methods and annotations as part of a pre-build step.

    But code generation is a can of worms.

    Daniel J. Beutel
    @danieljanes
    Hi everyone, we've come across a mypy error that shouldn't be an error AFAICT. Shouldn't a function returning a Dict[str, str] be compatible with an argument that expects a function returning a Dict[str, Union[str, int]? Here's the full code example:
    from typing import Callable, Dict, Union
    
    class Foo:
        def __init__(self, bar_fn: Callable[[int], Dict[str, Union[str, int]]]):
            self.bar_fn = bar_fn
    
        def get_dict(self) -> Dict[str, Union[str, int]]:
            return self.bar_fn(1)
    
    
    def fn_1(x: int) -> Dict[str, Union[str, int]]:
        return {"key1": "value1", "key2": 2}
    
    
    Foo(bar_fn=fn_1)  # This works
    
    
    def fn_2(x: int) -> Dict[str, str]:
        return {"key": "value"}
    
    
    Foo(bar_fn=fn_2)  # This raises the following mypy error:
    # [filename].py:23: error: Argument "bar_fn" to "Foo" has incompatible type "Callable[[int], Dict[str, str]]"; expected "Callable[[int], Dict[str, Union[str, int]]]"
    4 replies
    Kyle Altendorf
    @altendky
    i'm looking at trying to catch cases where trio has a parameter defaulted to None and trio-stubs doesn't have that parameter hinted as Optional. https://github.com/python-trio/trio/blob/d203b30f807e43dc9b101de2e52355ebd10b757a/trio/_core/_run.py#L1942 -- https://github.com/python-trio/trio-typing/blob/f32f17b0f242daf2d42407f383ca581d64b6c299/trio-stubs/lowlevel.pyi#L97 i guessed that maybe stubtest would catch this, but it doesn't seem to. is there another approach i should use to find similar cases? or perhaps there is a reason this "can't" be done?
    Kyle Altendorf
    @altendky
    @ignormies:matrix.org that's the idea, yeah, but this is checking separate stubs, not a program using the trio library. in fact, having that and running mypy against qtrio which uses trio is exactly what turned this up. i haven't figured out how to get that to be enforced against the combination of package and stubs.
    ignormies
    @ignormies:matrix.org
    [m]

    trio has a parameter defaulted to None and trio-stubs doesn't have that parameter hinted as Optional

    In this context, would the problem be in trio, or in trio-stubs?