Giter Club home page Giter Club logo

flake8-mypy's Introduction

flake8-mypy

NOTE: THIS PROJECT IS DEAD

It was created in early 2017 when Mypy performance was often insufficient for in-editor linting. The Flake8 plugin traded correctness for performance, making Mypy only check a bare minimum of problems. These days Mypy is accelerated with mypyc, as well as uses aggressive caching to speed up incremental checks. It's no longer worth it to use hacks such as flake8-mypy.

What was the project anyway?

A plugin for Flake8 integrating mypy. The idea is to enable limited type checking as a linter inside editors and other tools that already support Flake8 warning syntax and config.

List of warnings

flake8-mypy reserves T4 for all current and future codes, T being the natural letter for typing-related errors. There are other plugins greedily reserving the entire letter T. To this I say: ¯\_(ツ)_/¯.

T400: any typing note.

T484: any typing error (after PEP 484, geddit?).

T498: internal mypy error.

T499: internal mypy traceback, stderr output, or an unmatched line.

I plan to support more fine-grained error codes for specific mypy errors in the future.

Two levels of type checking

mypy shines when given a full program to analyze. You can then use options like --follow-imports or --disallow-untyped-calls to exercise the full transitive closure of your modules, catching errors stemming from bad API usage or incompatible types. That being said, those checks take time, and require access to the entire codebase. For some tools, like an editor with an open file, or a code review tool, achieving this is not trivial. This is where a more limited approach inside a linter comes in.

Flake8 operates on unrelated files, it doesn't perform full program analysis. In other words, it doesn't follow imports. This is a curse and a blessing. We cannot find complex problems and the number of warnings we can safely show without risking false positives is lower. In return, we can provide useful warnings with great performance, usable for realtime editor integration.

As it turns out, in this mode of operation, mypy is still able to provide useful information on the annotations within and at least usage of stubbed standard library and third party libraries. However, for best effects, you will want to use separate configuration for mypy's standalone mode and for usage as a Flake8 plugin.

Configuration

Due to the reasoning above, by default flake8-mypy will operate with options equivalent to the following:

[mypy]
# Specify the target platform details in config, so your developers are
# free to run mypy on Windows, Linux, or macOS and get consistent
# results.
python_version=3.6
platform=linux

# flake8-mypy expects the two following for sensible formatting
show_column_numbers=True
show_error_context=False

# do not follow imports (except for ones found in typeshed)
follow_imports=skip

# since we're ignoring imports, writing .mypy_cache doesn't make any sense
cache_dir=/dev/null

# suppress errors about unsatisfied imports
ignore_missing_imports=True

# allow untyped calls as a consequence of the options above
disallow_untyped_calls=False

# allow returning Any as a consequence of the options above
warn_return_any=False

# treat Optional per PEP 484
strict_optional=True

# ensure all execution paths are returning
warn_no_return=True

# lint-style cleanliness for typing needs to be disabled; returns more errors
# than the full run.
warn_redundant_casts=False
warn_unused_ignores=False

# The following are off by default since they're too noisy.
# Flip them on if you feel adventurous.
disallow_untyped_defs=False
check_untyped_defs=False

If you disagree with the defaults above, you can specify your own mypy configuration by providing the --mypy-config= command-line option to Flake8 (with the .flake8/setup.cfg equivalent being called mypy_config). The value of that option should be a path to a mypy.ini or setup.cfg compatible file. For full configuration syntax, follow mypy documentation.

For the sake of simplicity and readability, the config you provide will fully replace the one listed above. Values left out will be using mypy's own defaults.

Remember that for the best user experience, your linter integration mode shouldn't generally display errors that a full run of mypy wouldn't. This would be confusing.

Note: chaing the follow_imports option might have surprising effects. If the file you're linting with Flake8 has other files around it, then in "silent" or "normal" mode those files will be used to follow imports. This includes imports from typeshed.

Tests

Just run:

python setup.py test

OMG, this is Python 3 only!

Yes, so is mypy. Relax, you can run Flake8 with all popular plugins as a tool perfectly fine under Python 3.5+ even if you want to analyze Python 2 code. This way you'll be able to parse all of the new syntax supported on Python 3 but also effectively all the Python 2 syntax at the same time.

By making the code exclusively Python 3.5+, I'm able to focus on the quality of the checks and re-use all the nice features of the new releases (check out pathlib) instead of wasting cycles on Unicode compatibility, etc.

License

MIT

Change Log

17.8.0

  • avoid raising errors in the default config which don't happen during a full run (disable warn_unused_ignores and warn_redundant_casts)

  • always run type checks from a temporary directory to avoid clashing with unrelated files in the same directory

17.3.3

  • suppress mypy messages about relative imports

17.3.2

  • bugfix: using Flake8 with absolute paths now correctly matches mypy messages

  • bugfix: don't crash on relative imports in the form from . import X

17.3.1

  • switch follow_imports from "silent" to "skip" to avoid name clashing files being used to follow imports within typeshed

  • set MYPYPATH by default to give stubs from typeshed higher priority than local sources

17.3.0

  • performance optimization: skip running mypy over files that contain no annotations or imports from typing

  • bugfix: when running over an entire directory, T484 is now correctly used instead of T499

17.2.0

  • first published version

  • date-versioned

Authors

Glued together by Łukasz Langa.

flake8-mypy's People

Contributors

ambv avatar carljm avatar kaste avatar mauricioabreu avatar myii avatar pixelb avatar revmischa avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

flake8-mypy's Issues

By default, MyPy will ignore modules without __init__.py's

As I'm sure you are aware, in Python3, __init__.py is no longer required for modules.

The only problem is that in MyPy, when the __init__.py file is missing, it won't find the module and since ignore_missing_imports is set the True, the result is that large portions of the code will be ignored.

The fix for this is to set namespace_packages to True

Cannot override writable attribute with a final one

The below code should pass the check:

class MongoDAOBase(abc.ABC):
    collection_name: str = NotImplemented

    @classmethod
    @abc.abstractmethod
    def create_index(cls) -> None:
        pass


class PrivacySettingsDAO(MongoDAOBase):
    collection_name: Final = "privacy_settings" # complains

    @classmethod
    def create_index(cls) -> None:
        pass

However, a T484 Cannot override writable attribute "collection_name" with a final oneis raised. This problem seems to be introduced recently. My local version (which is older) of flake8-mypy and mypy does not complain, but it fails in CI environment (which gets later version). I'm not sure if this is a flake8-mypy problem or mypy problem, so I just ask here first.

Complain if any function arguments are not typed

Assuming we've added a return type to a function (-> AwesomeType:) lets make flake8-mypy complain that you have not typed all the arguments for said function.

# This should cause flake8-mypy to be unhappy
# FIX: def awesome(ambv: bool=False, cooper: int=69) -> bool:
def awesome(ambv=False, cooper=69) -> bool:
    if not ambv and cooper == 69:
        return True
    return False

Error running flake8-mypy

When I run flake8, I just get a bunch of these errors and nothing else from mypy:

/home/ubuntu/.local/lib/python3.6/site-packages is in the MYPYPATH. Please remove it.
See https://mypy.readthedocs.io/en/latest/running_mypy.html#how-mypy-handles-imports for more info

Dead project?

There hasn't been any activity on this repo in quite some time. Is there a new recommended way to integrate mypy with flake8?

mypy.ini picked up implicitly and false defaults not overridden

A mypy.ini in the current directory will be picked up implicitly, even if no config file is specified. This has a bad interaction with how the command line arguments are created, since false values are omitted, so those won't properly override the values in the implicitly picked up mypy.ini

Python 3.7 support

3.7 has been out

https://travis-ci.org/ambv/flake8-mypy/jobs/397937231 builds fail

/home/travis/build/ambv/flake8-mypy/tests/test_mypy.py:30:1: T499 mypy: error: failed to find a Python executable matching version (3, 6), perhaps try --python-executable, or --no-site-packages?

I also get this same error when running my own tests on travis xenial with 3.7:

 FLAKE8-check(ignoring E402 E305 E501 I201 I101 I100 D204 D101 E722 D401 D413 D300 D106) 
[gw0] linux -- Python 3.7.0 /home/travis/virtualenv/python3.7.0/bin/python
/home/travis/build/jetbridge/backend/jetbridge/jbflask.py:1:1: T499 usage: mypy [-h] [-v] [-V] [more options; see below]
/home/travis/build/jetbridge/backend/jetbridge/jbflask.py:2:1: T499             [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...]
/home/travis/build/jetbridge/backend/jetbridge/jbflask.py:3:1: T499 mypy: error: failed to find a Python executable matching version (3, 6), perhaps try --python-executable, or --no-site-packages?

AssertionError in test suite

I downloaded the latest flake8-mypy tarball on PyPI and tried to run its test suite in a clean Debian unstable image. However, testing fails with an AssertionError. The test log is pasted below:

python3.5 -m pytest tests
============================= test session starts ==============================
platform linux -- Python 3.5.4, pytest-3.2.1, py-1.4.34, pluggy-0.4.0
rootdir: /<<PKGBUILDDIR>>, inifile:
collected 7 items

tests/test_mypy.py ...F...

=================================== FAILURES ===================================
_______________________ MypyTestCase.test_invalid_types ________________________

self = <tests.test_mypy.MypyTestCase testMethod=test_invalid_types>

    def test_invalid_types(self) -> None:
        mpc = self.get_mypychecker('invalid_types.py')
        errors = list(mpc.run())
        self.assertEqual(
            errors,
            self.errors(
                T484(5, 0, vars=('Missing return statement',)),
                T484(
                    10,
                    4,
                    vars=(
                        'Incompatible return value type (got "int", expected "str")',
                    ),
                ),
                T484(
                    10,
                    11,
                    vars=(
                        'Unsupported operand types for + ("int" and "str")',
                    ),
                ),
                T400(
                    13,
                    0,
                    vars=(
>                       "unused 'type: ignore' comment",
                    )
                )
            ),
        )
E       AssertionError: Lists differ: [(5, [279 chars]er'>)] != [(5, [279 chars]er'>), (13, 0, "T400 note: unused 'type: ignor[43 chars]r'>)]
E       
E       Second list contains 1 additional elements.
E       First extra element 3:
E       (13, 0, "T400 note: unused 'type: ignore' comment", <class 'flake8_mypy.MypyChecker'>)
E       
E         [(5, 0, 'T484 Missing return statement', <class 'flake8_mypy.MypyChecker'>),
E          (10,
E           4,
E           'T484 Incompatible return value type (got "int", expected "str")',
E           <class 'flake8_mypy.MypyChecker'>),
E          (10,
E           11,
E           'T484 Unsupported operand types for + ("int" and "str")',
E       +   <class 'flake8_mypy.MypyChecker'>),
E       +  (13,
E       +   0,
E       +   "T400 note: unused 'type: ignore' comment",
E           <class 'flake8_mypy.MypyChecker'>)]

tests/test_mypy.py:89: AssertionError
====================== 1 failed, 6 passed in 4.64 seconds ======================

New release?

Any chance of a new release? The latest in PyPI is 17.8.0 and it struggles with Windows (#18).

BTW there's no 17.8.0 tag in this repo.

Improperly handling mypy summary from mypy 0.730 update

Mypy 0.730 introduced a change which adds a summary line when checking files which is on by default.

This is picked up as an unmatched line and reported as a T499 error.

Ideally the --no-error-summary flag would just be passed to mypy, but at the very least, no_error_summary=True needs to be added to the mypy_default.ini when the installed mypy version is >=0.730

mypy_config option should be relative to project root

The mypy_config option should be relative to the project root. For example, I should be able to do the following in my setup.cfg:

[mypy]
...
[flake8]
mypy_config=setup.cfg

That should point mypy to this same setup.cfg. But if you run flake8 from a folder inside the project, setup.cfg gets literally passed in as the config file to mypy, and it can't find it.

This line seems to be the problem. This should be making the path relative to the project root.

issue with round

got this error: T484 Argument 1 to "round" has incompatible type "Union[float, Decimal]"; expected "float"

however that is in fact allowed:

>>> round(Decimal(0.0))
0

Fails to Recognize "coding: utf-8-unix"

Flake8-MyPy fails to recognize Python scripts that use the magic comment containing coding: utf-8-unix as a UTF8 file. This bug has persisted for several versions and I had been fixing it myself ( #12). Although, my fix no longer works in the newest version of flake8-mypy. The fix has already been applied to MyPy itself ( python/mypy#5085 ), but this very helpful Flake8 plugin still lacks the fix.

flake8 --version
3.7.7 (flake8-mypy: 17.8.0, flake8-pyi: 19.3.0, mccabe: 0.6.1, pycodestyle: 2.5.0, pyflakes: 2.1.1, radon: 3.0.1, warn-symbols: 1.1.1) CPython 3.6.7 on Linux

mypy --version
mypy 0.701

mypy and flake8-mypy are giving different results

I've used strace and from what I can see, flake8 is mostly ignoring any defaults or explicit options saying where to find the mypy configuration.

Specifically the file not being treated properly is also a tests/test_foo.py not sure if that makes any difference.

See log from gitter below:

David Novakovic @dpnova 20:40
hey all.. I've got an issue with running mypy vs flake8-mymy and getting different results
it's with a file that's "test_foo.py" - i could flake8 could be ignoring something there

Ivan Levkivskyi @ilevkivskyi 20:41
This may be because mypy-flake8 uses some mypy flags on by default

David Novakovic @dpnova 20:41
I have an explicit mypy.ini
so if either one of them is not respecting it that would certainly be an issue

Ivan Levkivskyi @ilevkivskyi 20:41
are you sure mypy-flake8 is using it?

David Novakovic @dpnova 20:42
no.. I'll run with strace to check
tbh I ran flake8 in verbose mode and it didnt seem to mention mypy at all..

Ivan Levkivskyi @ilevkivskyi 20:43
also are you using flake8-mypy or mypy-flake8?

David Novakovic @dpnova 20:43
flake8-mypy
i didnt know there was another one haha
flake8==3.4.1
flake8-mypy==17.3.3

Ivan Levkivskyi @ilevkivskyi 20:44
@ambv this maybe then a question for you

David Novakovic @dpnova 20:44
from pip freeze
hmm let me check something

Ivan Levkivskyi @ilevkivskyi 20:45
are you using --mypy-config= flag for flake8-mypy?
because you should
see https://github.com/ambv/flake8-mypy#configuration

David Novakovic @dpnova 20:48
doing that made no difference
and this is working in other files..
just not this test file..
  INSERT  dpn  (e) nibble  ~  workspace  nibble  mypy nibble                                                                                                                       1   master 
nibble/bills/tests/test_models.py:8:12: error: Too few arguments for "Bill"
 INSERT  dpn  (e) nibble  ~  workspace  nibble  flake8 nibble                                                                                                                     1   master 
 INSERT  dpn  (e) nibble  ~  workspace  nibble  flake8 nibble --mypy-config=mypy.ini                                                                                                   master 
 INSERT  dpn  (e) nibble  ~  workspace  nibble  cat mypy.ini                                                                                                                           master 
[mypy]
# Specify the target platform details in config, so your developers are
# free to run mypy on Windows, Linux, or macOS and get consistent
# results.
python_version=3.6
platform=linux

# flake8-mypy expects the two following for sensible formatting
show_column_numbers=True
show_error_context=False

# do not follow imports (except for ones found in typeshed)
follow_imports=skip

# suppress errors about unsatisfied imports
ignore_missing_imports=True

# allow untyped calls as a consequence of the options above
disallow_untyped_calls=False

# allow returning Any as a consequence of the options above
warn_return_any=False

# treat Optional per PEP 484
strict_optional=True

# ensure all execution paths are returning
warn_no_return=True

# lint-style cleanliness for typing
warn_redundant_casts=True
warn_unused_ignores=True

# The following are off by default.  Flip them on if you feel
# adventurous.
disallow_untyped_defs=True
check_untyped_defs=True

David Novakovic @dpnova 20:56
can confirm that passing the config location to flake8 actually doesn't load the config

Ivan Levkivskyi @ilevkivskyi 21:00
You can also try ... with the .flake8/setup.cfg equivalent being called mypy_config
besides this suggestion my expertise ends, you could wait for @ambv or just file an issue on the tracker https://github.com/ambv/flake8-mypy/issues

David Novakovic @dpnova 21:05
thanks @ilevkivskyi i actually did just try that to no avail.. thanks for the help!

Flake8 does not respect mypy.ini

I have a mypy.ini file at project root, with Python version set to 3.7.. Running flake8 on any file in that directory still gives me T499 mypy: error: failed to find a Python executable matching version (3, 6). Running mypy standalone works straight out of the box, with or without mypy.ini, without any additional arguments or configuration.

$ which flake8
~/anaconda3/bin/flake8
$ which python
~/anaconda3/bin/python
$ python ~/anaconda3/bin/flake8 multipuller/feed.py 
multipuller/feed.py:1:1: T499 usage: mypy [-h] [-v] [-V] [more options; see below]
multipuller/feed.py:2:1: T499             [-m MODULE] [-p PACKAGE] [-c PROGRAM_TEXT] [files ...]
multipuller/feed.py:3:1: T499 mypy: error: failed to find a Python executable matching version (3, 6), perhaps try --python-executable, or --no-site-packages?
$ python --version
Python 3.7.0 
$ mypy multipuller/feed.py 
multipuller/feed.py:101:8: error: "Dict[str, Any]" has no attribute "entries"
multipuller/feed.py:102:22: error: "Dict[str, Any]" has no attribute "entries"
multipuller/feed.py:112:13: error: "Dict[str, Any]" has no attribute "feed_dict"
multipuller/feed.py:113:15: error: "Dict[str, Any]" has no attribute "feed_dict"
multipuller/feed.py:114:18: error: "Dict[str, Any]" has no attribute "feed_dict"
multipuller/feed.py:117:17: error: "Dict[str, Any]" has no attribute "feed_dict"
$ head -2 mypy.ini 
[mypy]
python_version=3.7

UnicodeError on utf-8 encoded files on Windows

I tried running flake8 on black on Windows, and it fails with:

> flake8 .\black.py
Traceback (most recent call last):
  File "c:\program files (x86)\python36-32\Lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "c:\program files (x86)\python36-32\Lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Users\zsolz\.virtualenvs\black-TlIYXM7K\Scripts\flake8.exe\__main__.py", line 9, in <module>
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8\main\cli.py", line 16, in main
    app.run(argv)
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8\main\application.py", line 396, in run
    self._run(argv)
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8\main\application.py", line 384, in _run
    self.run_checks()
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8\main\application.py", line 310, in run_checks
    self.file_checker_manager.run()
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8\checker.py", line 321, in run
    self.run_serial()
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8\checker.py", line 305, in run_serial
    checker.run_checks()
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8\checker.py", line 579, in run_checks
    self.run_ast_checks()
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8\checker.py", line 493, in run_ast_checks
    for (line_number, offset, text, check) in runner:
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\site-packages\flake8_mypy.py", line 192, in run
    f.write(line)
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\tempfile.py", line 483, in func_wrapper
    return func(*args, **kwargs)
  File "c:\users\zsolz\.virtualenvs\black-tliyxm7k\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u2728' in position 23: character maps to <undefined>

Looks like a7ec00d fixes this but it was never released.

More fine-grained error codes for specific mypy errors

I plan to support more fine-grained error codes for specific mypy errors in the future.

This lack is what prevents me from using this fine lib in my CI pipelines, many not important (for me) types of checks not separated from important ones. I'd greatly appreciate this feature.

Thanks in advance!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.