Optional static typing for Python 3 and 2 (PEP 484)

Overview

mypy logo

Mypy: Optional Static Typing for Python

Build Status Chat at https://gitter.im/python/typing Checked with mypy

Got a question? Join us on Gitter!

We don't have a mailing list; but we are always happy to answer questions on gitter chat. If you are sure you've found a bug please search our issue trackers for a duplicate before filing a new issue:

What is mypy?

Mypy is an optional static type checker for Python. You can add type hints (PEP 484) to your Python programs, and use mypy to type check them statically. Find bugs in your programs without even running them!

You can mix dynamic and static typing in your programs. You can always fall back to dynamic typing when static typing is not convenient, such as for legacy code.

Here is a small example to whet your appetite (Python 3):

from typing import Iterator

def fib(n: int) -> Iterator[int]:
    a, b = 0, 1
    while a < n:
        yield a
        a, b = b, a + b

See the documentation for more examples.

For Python 2.7, the standard annotations are written as comments:

def is_palindrome(s):
    # type: (str) -> bool
    return s == s[::-1]

See the documentation for Python 2 support.

Mypy is in development; some features are missing and there are bugs. See 'Development status' below.

Requirements

You need Python 3.5 or later to run mypy. You can have multiple Python versions (2.x and 3.x) installed on the same system without problems.

In Ubuntu, Mint and Debian you can install Python 3 like this:

$ sudo apt-get install python3 python3-pip

For other Linux flavors, macOS and Windows, packages are available at

https://www.python.org/getit/

Quick start

Mypy can be installed using pip:

$ python3 -m pip install -U mypy

If you want to run the latest version of the code, you can install from git:

$ python3 -m pip install -U git+git://github.com/python/mypy.git

Now, if Python on your system is configured properly (else see "Troubleshooting" below), you can type-check the statically typed parts of a program like this:

$ mypy PROGRAM

You can always use a Python interpreter to run your statically typed programs, even if they have type errors:

$ python3 PROGRAM

You can also try mypy in an online playground (developed by Yusuke Miyazaki).

IDE, Linter Integrations, and Pre-commit

Mypy can be integrated into popular IDEs:

Mypy can also be set up as a pre-commit hook using pre-commit mirrors-mypy.

Web site and documentation

Documentation and additional information is available at the web site:

http://www.mypy-lang.org/

Or you can jump straight to the documentation:

https://mypy.readthedocs.io/

Troubleshooting

Depending on your configuration, you may have to run pip like this:

$ python3 -m pip install -U mypy

This should automatically install the appropriate version of mypy's parser, typed-ast. If for some reason it does not, you can install it manually:

$ python3 -m pip install -U typed-ast

If the mypy command isn't found after installation: After python3 -m pip install, the mypy script and dependencies, including the typing module, will be installed to system-dependent locations. Sometimes the script directory will not be in PATH, and you have to add the target directory to PATH manually or create a symbolic link to the script. In particular, on macOS, the script may be installed under /Library/Frameworks:

/Library/Frameworks/Python.framework/Versions/<version>/bin

In Windows, the script is generally installed in \PythonNN\Scripts. So, type check a program like this (replace \Python34 with your Python installation path):

C:\>\Python34\python \Python34\Scripts\mypy PROGRAM

Working with virtualenv

If you are using virtualenv, make sure you are running a python3 environment. Installing via pip3 in a v2 environment will not configure the environment to run installed modules from the command line.

$ python3 -m pip install -U virtualenv
$ python3 -m virtualenv env

Quick start for contributing to mypy

If you want to contribute, first clone the mypy git repository:

$ git clone https://github.com/python/mypy.git

From the mypy directory, use pip to install mypy:

$ cd mypy
$ python3 -m pip install -U .

Replace python3 with your Python 3 interpreter. You may have to do the above as root. For example, in Ubuntu:

$ sudo python3 -m pip install -U .

Now you can use the mypy program just as above. In case of trouble see "Troubleshooting" above.

NOTE: Installing with sudo can be a security risk. Please try with the --user flag first. $ python3 -m pip install --user -U .

Tests

The basic way to run tests:

$ pip3 install -r test-requirements.txt
$ python2 -m pip install -U typing
$ ./runtests.py

For more on the tests, such as how to write tests and how to control which tests to run, see Test README.md.

Development status

Mypy is beta software, but it has already been used in production for several years at Dropbox and in many other organizations, and it has an extensive test suite.

See the roadmap if you are interested in plans for the future.

Changelog

Follow mypy's updates on the blog: https://mypy-lang.blogspot.com/

Issue tracker

Please report any bugs and enhancement ideas using the mypy issue tracker: https://github.com/python/mypy/issues

If you have any questions about using mypy or types, please ask in the typing gitter instead: https://gitter.im/python/typing

Compiled version of mypy

We have built a compiled version of mypy using the mypyc compiler for mypy-annotated Python code. It is approximately 4 times faster than interpreted mypy and is available (and the default) for 64-bit Windows, macOS, and Linux.

To install an interpreted mypy instead, use:

$ python3 -m pip install --no-binary mypy -U mypy

If you wish to test out the compiled version of a development version of mypy, you can directly install a binary from https://github.com/mypyc/mypy_mypyc-wheels/releases/latest.

Help wanted

Any help in testing, development, documentation and other tasks is highly appreciated and useful to the project. There are tasks for contributors of all experience levels. If you're just getting started, ask on the gitter chat for ideas of good beginner issues.

For more details, see the file CONTRIBUTING.md.

License

Mypy is licensed under the terms of the MIT License (see the file LICENSE).

Comments
  • Support for python 3.10 match statement

    Support for python 3.10 match statement

    Description

    This PR will add support for the python 3.10 match statement to mypy.

    Current progress:

    • [x] parser and ast nodes
    • [x] semantic analysis
    • [x] type-checking
      • [x] as-pattern
      • [x] or-pattern
      • [x] literal-pattern
      • [x] value-pattern
      • [x] capture-pattern
      • [x] wildcard-pattern
      • [x] sequence-pattern
      • [x] mapping-pattern
      • [x] class-pattern
    • [x] Lots of tests

    Test Plan

    Some tests have been added, but they don't pass yet. There will be a lot more tests in the future.

    I'm currently developing and testing on cpython 3.10.0b1 and will make sure to update to newer versions every now and then.

    opened by freundTech 110
  • Support for pyproject.toml

    Support for pyproject.toml

    PEP518 says that pyproject.toml is to support the minimum build requirements. I want to consider mypy as part of the minimum build on my package.

    For example Pip uses a [tool.towncrier] section on pyproject.toml to generate a correctly updated NEWS.rst as part of its build. One can considers typing correctness as important to the distributed source pakcage as an well documented NEWS.rst. Other example is Black that also has it section on pyproject.toml.

    Maybe you think that this is a silly feature request and that setup.cfg must be used instead, Pip or Flit or whatever can setup mypy after all. But an TOML module will be added to the standard library sooner or later, than could mypy accept this feature and antecipate TOML supporting pyproject.toml today?

    feature needs discussion topic-developer 
    opened by pslacerda 72
  • Release 0.920 planning

    Release 0.920 planning

    I will be releasing mypy 0.920 soon. The release branch will be cut at a7d6e68541e1c6b52338dbe2e3f4a7055a033483. Please post here any PRs that need to be merged and cherry-picked.

    priority-0-high 
    opened by ilevkivskyi 59
  • Protocols

    Protocols

    This is an implementation of protocols proposed in PEP 544. This PR adds support for:

    • generic protocols (including inference for protocols)
    • recursive protocols
    • special support for Type[] and isinstance()
    • structural subtyping for Callable and Tuple
    • other things

    For example, now one can do this:

    class Linked(Protocol[T]):
        val: T
        def next(self) -> 'Linked[T]': ...
    
    class L:
        val: int
        def next(self) -> 'L': ...
    
    def last(seq: Linked[T]) -> T:
        ...
    
    reveal_type(last(L()))  # Revealed type is 'builtins.int*'
    

    In general, the PR is practically feature complete, the main missing thing now is structural join/meet for partially overlapping protocols. For example, sometimes an explicit annotation is needed:

    class A(Protocol):
        one: int
        def __len__(self) -> int: ...
    
    class B(Protocol):
        another: int
        def __len__(self) -> int: ...
    
    a: A
    b: B
    reveal_type([a, b])  # Revealed type is 'builtins.list[builtins.object*]'
    
    y: List[Sized] = [a, b]  # This works OK
    

    The reason for this is that I decided to re-use Instances for protocols, and real structural join/meet would require creating a "fake" TypeInfo to describe the resulting protocol. However, I have encountered problems with serialization/de-serialization of "fake" TypeInfos and postponed this feature (as proposed by Jukka). On the other hand, reusing Instances for protocols allowed to implement this in a very simple way. The PR is very small and 2/3 of it are extensive tests.

    There is something I encountered while working on this PR. It looks like structural subtyping is significantly slower than nominal. This is why I also implement "subtype cache" for Instances, so that there is a net win in speed of few percent (even when I locally updated typeshed replacing all ABC in typing with protocols).


    In terms of work-flow, I would be happy if people will try this PR and give also feedback on behaviour, not just a code review. I will soon submit a PR to typeshed with updates for typing stubs, and a PR with runtime implementation. As well, a PR to PEPs repo with an updated draft that takes into account comments that appeared so far.

    @JukkaL @ambv @gvanrossum

    topic-pep-484 
    opened by ilevkivskyi 57
  • Basic ParamSpec Concatenate and literal support

    Basic ParamSpec Concatenate and literal support

    Description

    I was planning on adding a ParamSpec-based interface to something I'm making but... it turns out I need Concatenate and Z[[int]] syntax.

    Closes #11833 Closes #12276 (needs test) Closes #12257 (needs test; not sure how to test cache issues) Refs #8645 External ref https://github.com/python/typeshed/issues/4827

    This PR adds a new Parameters proper type to represent parameters (more later in this description), along with adding a Concatenate operator.

    Test Plan

    I copied all (seemingly relevant) tests from PEP 612. I plan on copying test cases from issues and thinking of a few of my own later.

    Notes

    (not a real section but seemed important enough)

    • Concatenate support does not use a ProperType. That would be too much new code for an operator, in my opinion. Thus, it prepends to a ParamSpecType's .prefix.
    • I would really really like CallableType to take in a parameters: ParamSpecType | Parameters -- this would simplify some code, and it fits better in your head. However, this would be a breaking change, so I did not do this (along with the fact that making basic changes in this direction led to 300 type errors when self-checking). ~~- Concatenate was super unspecified by the PEP in my opinion. I ended up making it work wherever ParamSpec could be (or so I think)... Which means Concatenate[int, Concatenate[str, P]] works!~~
    • Error messages could be improved, but I'm not sure where I can get the context to improve those.
    opened by A5rocks 55
  • Import handling is confusing and misleading

    Import handling is confusing and misleading

    I tried mypy and was alarmed to see it unable to find imports that are clearly available. Reading the explanations in #1293 and #1339, I now understand why it doesn't merrily parse third-party code that will only add to a growing pile of unannotated code.

    But this is a really bad first experience. I install something that claims to understand Python code, and it's confused by imports? Then it gives me two suggestions, neither of which is seems like the right advice:

    note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
    

    I shouldn't try to set MYPYPATH, that's silly busy-work that if successful will only lead me into the unannotated third-party module trap. The imports aren't missing, so why would --ignore-missing-imports help? NOTE: using --ignore-missing-imports silences the warnings, but the option is misnamed: the imports are not missing.

    Reading the help, I see --follow-imports, so I try those options. I try --follow-imports=silent, but that still complains about the imports. I try --follow-imports=skip, and that also still complains about the imports. Both of these sound like exactly what I need, and neither changes the behavior much:

    $ mypy --version
    mypy 0.560
    $ mypy census.py
    census.py:16: error: Cannot find module named 'aiohttp'
    census.py:16: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
    census.py:17: error: Cannot find module named 'async_timeout'
    census.py:18: error: Cannot find module named 'attr'
    census.py:20: error: Cannot find module named 'opaque_keys'
    census.py:21: error: Cannot find module named 'opaque_keys.edx'
    census.py:21: error: Cannot find module named 'opaque_keys.edx.keys'
    helpers.py:3: error: No library stub file for module 'lxml'
    helpers.py:3: note: (Stub files are from https://github.com/python/typeshed)
    helpers.py:4: error: No library stub file for module 'lxml.html'
    $ mypy --follow-imports=silent census.py
    census.py:16: error: Cannot find module named 'aiohttp'
    census.py:16: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
    census.py:17: error: Cannot find module named 'async_timeout'
    census.py:18: error: Cannot find module named 'attr'
    census.py:20: error: Cannot find module named 'opaque_keys'
    census.py:21: error: Cannot find module named 'opaque_keys.edx'
    census.py:21: error: Cannot find module named 'opaque_keys.edx.keys'
    $ mypy --follow-imports=skip census.py
    census.py:16: error: Cannot find module named 'aiohttp'
    census.py:16: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
    census.py:17: error: Cannot find module named 'async_timeout'
    census.py:18: error: Cannot find module named 'attr'
    census.py:20: error: Cannot find module named 'opaque_keys'
    census.py:21: error: Cannot find module named 'opaque_keys.edx'
    census.py:21: error: Cannot find module named 'opaque_keys.edx.keys'
    $ mypy --follow-imports=error census.py
    census.py:16: error: Cannot find module named 'aiohttp'
    census.py:16: note: (Perhaps setting MYPYPATH or using the "--ignore-missing-imports" flag would help)
    census.py:17: error: Cannot find module named 'async_timeout'
    census.py:18: error: Cannot find module named 'attr'
    census.py:20: error: Cannot find module named 'opaque_keys'
    census.py:21: error: Cannot find module named 'opaque_keys.edx'
    census.py:21: error: Cannot find module named 'opaque_keys.edx.keys'
    census.py:23: note: Import of 'html_writer' ignored
    census.py:23: note: (Using --follow-imports=error, module not passed on command line)
    census.py:24: note: Import of 'site_patterns' ignored
    census.py:27: note: Import of 'sites' ignored
    $ mypy --ignore-missing-imports census.py
    $
    
    priority-0-high topic-usability 
    opened by nedbat 49
  • Mypy

    Mypy "strict mode" for static compilation

    Problem statement:

    "Could there be some way to write a library like numpy so that a single codebase could simultaneously target CPython and the newer compilers, while achieving competitive speed in all cases? If so, what would it take to make that happen? If not, then what’s the next-best alternative?"**

    Proposed Solution: a "PyIR" that can be consumed by various compilers. Details here: https://docs.google.com/document/d/1jGksgI96LdYQODa9Fca7EttFEGQfNODphVmbCX0DD1k/edit

    Question for Mypy: A cython subset seems to be the recommended source format. Can a "strict mode" mypy be used instead to output this IR? Advantages include more expressive than cython (generics etc), bootstrap off mypy work and less fragmentation.

    Excerpts from discussion on gitter:

    @njsmith

    at pycon this year Jukka and the mypy team were very interested in the idea of somehow using their static type stuff in (something like, this doesn't exist) "strict" mode to help with this

    @kmod

    I think the issue is that "programmer productivity types" fundamentally != "compiler-userful types"
    
    For example, are subclasses subtypes?
    
    If you pick either yes or no, then the type system becomes non-useful to one community or the other
    

    bonus: Where would dynd's datashape play in? If so, can Dynd's datashape be used as a mypy plugin to annotate array types? @insertinterestingnamehere

    feature needs discussion priority-2-low 
    opened by datnamer 49
  • Simple dependent types

    Simple dependent types

    [This is based on a discussion between me and @gvanrossum last week. I'm writing this down so that we won't forget about this.]

    Several stdlib functions have signatures where the return type depends on the value of an argument. Examples:

    • open returns an IO[str] or IO[bytes] depending on whether the mode argument has 'b' as a substring.
    • subprocess.check_output returns a str or bytes depending on the value of the boolean universal_newlines argument.

    A simple way to support these would be to introduce a few additional types that work with str and bool literals:

    • A string pattern type that can describe the contents of a string literal, perhaps using a regular expression.
    • Types for False and True.

    For example, if we had FalseType and TrueType, we could write a function whose return value depends on the value of a boolean argument:

    @overload
    def f(x: FalseType) -> bytes: ...
    @overload
    def f(x: TrueType) -> str: ...
    
    def f(x: Any) -> Any:
        if x:
            return 'x'
        else:
            return b'x'
    
    reveal_type(f(False))  # bytes
    reveal_type(f(True)  # str
    

    Not sure about this one:

    ...
    x = bool('')
    reveal_type(f(x))  # Union[str, bytes] since we don't know the boolean value statically?
    

    We could also have a generic class where a generic type argument depends on the value of an argument to __init__. Not sure how we should represent these -- here is one potential approach:

    class C(Generic[AnyStr]):
        @overload
        @returntype('C[str]')
        def __init__(self, x: TrueType) -> None: ...
        @overload
        @returntype('C[bytes]')
        def __init__(self, x: FalseType) -> None: ...
        ...
    
    reveal_type(C(True))  # C[str]
    

    Alternatively, we could use __new__, but this would be problematic if there is no corresponding method defined at runtime.

    needs discussion 
    opened by JukkaL 47
  • Cannot assign to field of Callable type

    Cannot assign to field of Callable type

    Consider this example:

    from typing import Callable
    
    class A:
        f = None  # type: Callable[[int], int]
    
        def __init__(self, g: Callable[[int], int]) -> None:
            self.f = g
    

    mypy reports:

    trial.py: In member "__init__" of class "A":
    trial.py, line 7: Cannot assign to a method
    trial.py, line 7: Invalid method type
    trial.py, line 7: Incompatible types in assignment (expression has type Callable[[int], int], variable has type Callable[[], int])
    

    while I'd expect this to work.

    Note that there is a second error in the reporting of the type of the variable.

    Also, this passes type checking (correctly):

    f = None  # type: Callable[[int], int]
    
    def g(x: int) -> int: return 0
    
    f = g
    
    bug priority-0-high size-large false-positive topic-descriptors affects-typeshed 
    opened by spkersten 47
  • Implement the descriptor protocol

    Implement the descriptor protocol

    This is an attempt to implement the descriptor protocol (as per https://github.com/python/mypy/issues/244).

    However, it currently is suffering from being being unable to resolve type variables during assignment, and I'm not sure what I would need to resolve that. For instance, using this implementation of properties:

    from typing import Any, Text, TypeVar, Optional, Type, Generic, Callable, Union
    from operator import attrgetter
    
    T = TypeVar('T')
    G = TypeVar('G')
    S = TypeVar('S')
    
    class MyProperty(Generic[T, G]):
        def __init__(
            self,
            fget: Callable[[T], G],
            fset: Optional[Callable[[T, G], None]] = None,
            fdel: Optional[Callable[[T], None]] = None,
            doc: Optional[Text] = None,
        ) -> None:
            self._getter = fget
            self._setter = fset
            self._deleter = fdel
            if doc:
                self.__doc__ = doc
            else:
                self.__doc__ = fget.__doc__
    
        def setter(self, fset: Callable[[T, G], None]):
            return MyProperty(self._getter, fset, self._deleter, self.__doc__)
    
        def deleter(self, fdel: Callable[[T], None]):
            return MyProperty(self._getter, self._setter, fdel, self.__doc__)
    
        def __get__(self, instance: Optional[T], owner: Type[T]) -> Union['MyProperty[T, G]', G]:
            if instance is None:
                return self
    
            return self._getter(instance)
    
        def __set__(self, instance: T, value: G) -> None:
            if self._setter:
                self._setter(instance, value)
            else:
                raise Exception()
    
        def __delete__(self, instance: T) -> None:
            if self._deleter:
                self._deleter(instance)
            else:
                raise Exception()
    
    class NonGenericNonDataDescriptor(Generic[T]):
        def __init__(self, value: int) -> None:
            self._value = value  # type: int
    
        def __get__(self, instance: Optional[T], owner: Type[T]) -> int:
            return self._value
    
    class NonGenericDataDescriptor(Generic[T]):
        def __init__(self, value: int) -> None:
            self._value = value  # type: int
    
        def __get__(self, instance: Optional[T], owner: Type[T]) -> Union['NonGenericDataDescriptor[T]', int]:
            if instance is None:
                return self
    
            return self._value
    
        def __set__(self, instance: T, value: int) -> None:
            self._value = value
    
    
    class Test:
        my_unique_name = MyProperty(attrgetter('foo'))  # type: MyProperty[Test, int]
        ten = NonGenericNonDataDescriptor(10)  # type: NonGenericNonDataDescriptor[Test]
        some_int = NonGenericDataDescriptor(5)  # type: NonGenericDataDescriptor[Test]
    
        @MyProperty
        def my_other_name(self):
            return self.bar
    
        def __init__(self) -> None:
            self.foo = 0
            self.bar = "ten"
    
    def f() -> None:
        t = Test()
    
        t.my_unique_name = 1
        t.my_unique_name + 1
    
        t.ten + 1
    
        t.some_int = 7
        t.some_int + 1
    

    When checked with mypy, we get the following errors:

    $ mypy --fast-parser test_descriptors.py --show-traceback
    
    test_descriptors.py: note: In function "f":
    test_descriptors.py:85: error: Incompatible types in assignment (expression has type "int", variable has type "G")
    test_descriptors.py:86: error: Unsupported operand types for + ("Union[MyProperty[Test, int], int]" and "int")
    

    The second error is because we don't have overloading outside of stub files (see https://github.com/python/mypy/issues/1136), I think, but the former is the one I'm not sure how to resolve.

    opened by cpennington 46
  • Allow using TypedDict for more precise typing of **kwds

    Allow using TypedDict for more precise typing of **kwds

    There are some situations where a user wants to have more precisely typed **kwds. Current syntax only allows homogeneous **kwds:

    def fun(x: int, *, **options: str) -> None:
        ...
    

    However, in situations with many heterogeneous options listing all options in the signature could be verbose and will require rewriting some existing code. There is a vague idea to allow TypedDict for such situations. For example:

    class Options(TypedDict):
        timeout: int
        alternative: str
        on_error: Callable[[int], None]
        on_timeout: Callable[[], None]
        ...
    
    def fun(x: int, *, **options: Options) -> None:
        ...
    

    Maybe for such cases the TypedDict used should be automatically understood as defined with total=False. Also it is worth mentioning that this feature will allow reusing the TypedDicts in modules where several functions have same (or similar) option sets.

    feature topic-typed-dict priority-1-normal 
    opened by ilevkivskyi 44
  • Unexpected comparison-overlap error for identity comparison of optionals

    Unexpected comparison-overlap error for identity comparison of optionals

    Bug Report

    mypy generates "error: Non-overlapping identity check" for identity comparison between optionals, even though None has the same identity as None. This is especially confusing for the x is y is None pattern, which I would expect to be valid as long as x and y are optional.

    To Reproduce

    def foo(x: int | None, y: str | None) -> None:
        if x is y:
            print('x and y have same identity!')
    
    foo(None, None)
    

    Actual Behavior

    $ python repr.py
    x and y have same identity!
    
    $ mypy --strict repr.py
    repr.py:2: error: Non-overlapping identity check (left operand type: "Optional[int]", right operand type: "Optional[str]")  [comparison-overlap]
    Found 1 error in 1 file (checked 1 source file)
    

    Your Environment

    • Mypy version used: 0.991
    • Mypy command-line flags: --strict
    • Mypy configuration options from mypy.ini (and other config files): None
    • Python version used: 3.10.8
    bug 
    opened by Cebtenzzre 0
  • Enums do not exhaustively match correctly

    Enums do not exhaustively match correctly

    Bug Report

    When I transform a value into an enum, an error occurs in the match case construct. If you convert the value in advance, there will be no error. Same issue #14109 #14264 .

    To Reproduce

    import typing
    import enum
    
    class Color(enum.StrEnum):
        RED = enum.auto()
        GREEN = enum.auto()
        BLUE = enum.auto()
    
    def test(color: str) -> str:
        match Color(color):
            case Color.RED:
                return 'red'
            case Color.GREEN:
                return 'green'
            case Color.BLUE:
                return 'blue'
            case _ as unreachable:
                typing.assert_never(unreachable)
    

    https://mypy-play.net/?mypy=latest&python=3.11&gist=d28ae2af9f4545ca1c302476d8e4c782

    import typing
    import enum
    
    class Color(enum.StrEnum):
        RED = enum.auto()
        GREEN = enum.auto()
        BLUE = enum.auto()
    
    def test(color: str) -> str:
        color = Color(color)
        match color:
            case Color.RED:
                return 'red'
            case Color.GREEN:
                return 'green'
            case Color.BLUE:
                return 'blue'
            case _ as unreachable:
                typing.assert_never(unreachable)
    

    https://mypy-play.net/?mypy=latest&python=3.11&gist=eab4deab65eb38a49649a46a2adc1e42

    Actual Behavior

    In the first example:

    main.py:18: error: Argument 1 to "assert_never" has incompatible type "Color"; expected "NoReturn"  [arg-type]
    Found 1 error in 1 file (checked 1 source file)
    

    In the second example:

    Success: no issues found in 1 source file
    

    Your Environment

    • Mypy version used: mypy 0.991 (compiled: yes)
    • Mypy command-line flags: N/A
    • Mypy configuration options from mypy.ini (and other config files): N/A
    • Python version used: 3.11.1
    bug topic-match-statement topic-reachability 
    opened by Be3y4uu-K0T 0
  • Why is `Callable` assumed to be a user defined function?

    Why is `Callable` assumed to be a user defined function?

    The following should be an error, but it currently is not.

    from collections.abc import Callable
    from typing import Any
    
    
    def f(call: Callable[..., Any]) -> None:
        print(call.__name__)  # why is there no error here?
    

    IMO the last line should cause a mypy error to the effect of "Callable" has no attribute "__name__". The callable protocol generally does not define __name__.

    To further drive this point home, add the following piece:

    class Bar:
        def __call__(self) -> None:
            print(f"hi mom")
    
    
    f(Bar())  # this is valid
    print(Bar().__name__)  # this is an error
    

    This means that

    1. Bar is correctly viewed as being a Callable subtype (structurally) and
    2. it is also correctly identified to not have the __name__ attribute by mypy.
    3. Yet when something is annotated as Callable, mypy just assumes it has the __name__ attribute. 🤨

    Correct me if I am wrong, but these points cannot logically all be true.


    The documentation of the Callable ABC clearly states that it is a class that defines the __call__ method. Nowhere does it mention the need for a Callable class to define __name__ (or anything else for that matter).

    There is also no mention of any attributes/methods other than __call__ in the glossary entry for callable.

    Lastly, the relevant section on Callable types of the standard type hierarchy chapter in the data model documentation again broadly defines them as

    types to which the function call operation [...] can be applied

    and further down even explicitly states the following:

    Instances of arbitrary classes can be made callable by defining a __call__() method in their class.


    I realize that user defined functions do always have the __name__ attribute (as well as a bunch of others listed in the aforementioned data model docs). But this should make them a subtype of Callable.

    Yet it seems as though mypy treats a Callable as a user defined function. My example f above can be changed to any of the attributes of user defined functions, such as __kwdefaults__ for example and it would still pass mypy checks. This seems wildly inconsistent with all the documentation I could find, as well as logically inconsistent in itself.

    I can only assume that there is some historic/pragmatic explanation for this, but I could not find it.

    What is the reasoning behind this?


    I found a discussion in #5958 that seems to be related, but found no answer to my question.

    opened by daniil-berg 6
  • Avoid false

    Avoid false "Incompatible return value type" errors when dealing with `isinstance`, constrained type variables and multiple inheritance (Fixes #13800)

    Avoid false "Incompatible return value type" errors when dealing with isinstance, constrained type variables and multiple inheritance (Fixes #13800).

    The idea is to make a union of the current expanded return type and the previously expanded return types if the latter are among the bases of intersections generated by isinstance checks.

    opened by tyralla 2
  • A single [import] error can hide many other errors in completely unrelated code

    A single [import] error can hide many other errors in completely unrelated code

    I work on a large legacy codebase with thousands of type errors. I have found recently that our configuration had ignore_missing_imports = True to account for the absence of a many of 3rd-party deps in our typechecking venv. In an attempt to improve typechecking strictness, I added a per-package stanza to enable ignore_missing_imports = False for import paths belonging to our internal code.

    I found that:

    • this revealed a handful of cases where import statements in if TYPE_CHECKING: block had invalid/outdated paths
    • the presence of even a single such invalid import in the entire codebase, even in a file that is not imported anywhere, will mask most of the existing errors from mypy's output, even though mypy does appear to check the same number of files

    For instance, prior to enabling the stricter import check I get:

    ...
    Found 2830 errors in 815 files (checked 11667 source files)
    

    with the stricter import check, if any import path is invalid, I get:

    ...
    Found 182 errors in 78 files (checked 11667 source files)
    

    This is on macOS, with mypy 0.971

    Unfortunately the codebase is not public and I have not yet managed to create a minimal reproducer.

    bug 
    opened by huguesb 3
  • stubgen: Allow aliases below the top level

    stubgen: Allow aliases below the top level

    (Explain how this PR changes mypy.)

    stubgen currently allows a variable to be an alias to another, but only at the module level.

    For example:

    def func() -> int:
        return 2
    
    aliased_func = func
    
    class Foo:
        def meth() -> int:
            return 2
        
        aliased_meth = meth
    

    produces:

    def func() -> int: ...
    aliased_func = func
    
    class Foo:
        def meth() -> int: ...
        aliased_meth: Incomplete   # <--- should be  `aliased_meth = meth`
    

    At the class level, these aliased variables are marked as Incomplete.

    In my experience, enabling aliases below the top level produces better stubs.

    I'm not sure what the original reservations were around use of these aliases. If the concerns about class-level aliases are still valid, I can add an option to enable them.

    opened by chadrik 0
Owner
Python
Repositories related to the Python Programming language
Python
Flashcards - A flash card application with 2 optional command line arguments

Flashcards A flash card application with 2 optional command line arguments impor

Özgür Yildirim 2 Jul 15, 2022
A static type analyzer for Python code

pytype - ?? ✔ Pytype checks and infers types for your Python code - without requiring type annotations. Pytype can: Lint plain Python code, flagging c

Google 4k Dec 31, 2022
Static type checker for Python

Static type checker for Python Speed Pyright is a fast type checker meant for large Python source bases. It can run in a “watch” mode and performs fas

Microsoft 9.2k Jan 3, 2023
Tool for automatically reordering python imports. Similar to isort but uses static analysis more.

reorder_python_imports Tool for automatically reordering python imports. Similar to isort but uses static analysis more. Installation pip install reor

Anthony Sottile 589 Dec 26, 2022
A static-analysis bot for Github

Imhotep, the peaceful builder. What is it? Imhotep is a tool which will comment on commits coming into your repository and check for syntactic errors

Justin Abrahms 221 Nov 10, 2022
Simple Python style checker in one Python file

pycodestyle (formerly called pep8) - Python style guide checker pycodestyle is a tool to check your Python code against some of the style conventions

Python Code Quality Authority 4.7k Jan 1, 2023
The strictest and most opinionated python linter ever!

wemake-python-styleguide Welcome to the strictest and most opinionated python linter ever. wemake-python-styleguide is actually a flake8 plugin with s

wemake.services 2.1k Jan 1, 2023
A plugin for Flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle.

flake8-bugbear A plugin for Flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycode

Python Code Quality Authority 869 Dec 30, 2022
A Python Parser

parso - A Python Parser Parso is a Python parser that supports error recovery and round-trip parsing for different Python versions (in multiple Python

Dave Halter 520 Dec 26, 2022
A simple program which checks Python source files for errors

Pyflakes A simple program which checks Python source files for errors. Pyflakes analyzes programs and detects various errors. It works by parsing the

Python Code Quality Authority 1.2k Dec 30, 2022
Performant type-checking for python.

Pyre is a performant type checker for Python compliant with PEP 484. Pyre can analyze codebases with millions of lines of code incrementally – providi

Facebook 6.2k Jan 4, 2023
Tool to check the completeness of MANIFEST.in for Python packages

check-manifest Are you a Python developer? Have you uploaded packages to the Python Package Index? Have you accidentally uploaded broken packages with

Marius Gedminas 270 Dec 26, 2022
A python documentation linter which checks that the docstring description matches the definition.

Darglint A functional docstring linter which checks whether a docstring's description matches the actual function/method implementation. Darglint expe

Terrence Reilly 463 Dec 31, 2022
Flake8 plugin that checks import order against various Python Style Guides

flake8-import-order A flake8 and Pylama plugin that checks the ordering of your imports. It does not check anything else about the imports. Merely tha

Python Code Quality Authority 270 Nov 24, 2022
Flake8 extension for checking quotes in python

Flake8 Extension to lint for quotes. Major update in 2.0.0 We automatically encourage avoiding escaping quotes as per PEP 8. To disable this, use --no

Zachary Heller 157 Dec 13, 2022
Check for python builtins being used as variables or parameters

Flake8 Builtins plugin Check for python builtins being used as variables or parameters. Imagine some code like this: def max_values(list, list2):

Gil Forcada Codinachs 98 Jan 8, 2023
flake8 plugin to run black for checking Python coding style

flake8-black Introduction This is an MIT licensed flake8 plugin for validating Python code style with the command line code formatting tool black. It

Peter Cock 146 Dec 15, 2022
Custom Python linting through AST expressions

bellybutton bellybutton is a customizable, easy-to-configure linting engine for Python. What is this good for? Tools like pylint and flake8 provide, o

H. Chase Stevens 249 Dec 31, 2022
Unbearably fast O(1) runtime type-checking in pure Python.

Look for the bare necessities, the simple bare necessities. Forget about your worries and your strife. — The Jungle Book.

beartype 1.4k Jan 1, 2023