Skip to content

Commit 18aae47

Browse files
ambvgvanrossum
authored andcommitted
Externalize flake8 linting, introduce additional checks (#2638)
This change is a step towards removing `runtests.py` (see #1673). The exclusion list in the flake8 configuration in `setup.cfg` has been updated to enable running the linter from the root of the project by simply invoking `flake8`. This enables it to leverage its own file discovery and its own multiprocessing queue without excessive subprocessing for linting every file. This gives a minor speed up in local test runs. Before: total time in lint: 130.914682 After: total time in lint: 20.379915 There's an additional speedup on Travis because linting is now only performed on Python 3.6. More importantly, this means flake8 is now running over all files unless explicitly excluded in `setup.cfg`. This will help avoiding unintentional omissions in the future (see comments on #2637). Note: running `flake8` as a single lazy subprocess in `runtests.py` doesn't sacrifice any parallelism because the linter has its own process pool. Minimal whitespace changes were required to `mypy_extensions.py` but in return flake8 will check it now exactly like it checks the rest of the `mypy/*` codebase. Those are also done on #2637 but that hasn't landed yet. Finally, flake8-bugbear and flake8-pyi were added to test requirements to make the linter configuration consistent with typeshed. I hope the additional checks will speed up future pull requests by automating bigger parts of the code review. The pyi plugin enables forward reference support when linting .pyi files. That means it's now possible to run `flake8` inside the typeshed submodule or on arbitrary .pyi files during development (which your editor could do for you), for example on fixtures. See discussion on #2629 on checks that are disabled and why.
1 parent b84f56a commit 18aae47

File tree

6 files changed

+37
-14
lines changed

6 files changed

+37
-14
lines changed

.travis.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ python:
55
- "3.4"
66
# Specifically request 3.5.1 because we need to be compatible with that.
77
- "3.5.1"
8-
- "3.6-dev"
8+
- "3.6"
9+
- "3.7-dev"
910
# Pypy build is disabled because it doubles the travis build time, and it rarely fails
1011
# unless one one of the other builds fails.
1112
# - "pypy3"
@@ -15,4 +16,5 @@ install:
1516
- python setup.py install
1617

1718
script:
18-
- python runtests.py
19+
- python runtests.py -x lint
20+
- if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then flake8; fi

extensions/mypy_extensions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ def _check_fails(cls, other):
2222
pass
2323
return False
2424

25+
2526
def _dict_new(cls, *args, **kwargs):
2627
return dict(*args, **kwargs)
2728

29+
2830
def _typeddict_new(cls, _typename, _fields=None, **kwargs):
2931
if _fields is None:
3032
_fields = kwargs
@@ -33,6 +35,7 @@ def _typeddict_new(cls, _typename, _fields=None, **kwargs):
3335
" but not both")
3436
return _TypedDictMeta(_typename, (), {'__annotations__': dict(_fields)})
3537

38+
3639
class _TypedDictMeta(type):
3740
def __new__(cls, name, bases, ns):
3841
# Create new typed dict class object.

runtests.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,11 @@ def add_python2(self, name: str, *args: str, cwd: Optional[str] = None) -> None:
151151
env = self.env
152152
self.waiter.add(LazySubprocess(name, largs, cwd=cwd, env=env))
153153

154-
def add_flake8(self, name: str, file: str, cwd: Optional[str] = None) -> None:
155-
name = 'lint %s' % name
154+
def add_flake8(self, cwd: Optional[str] = None) -> None:
155+
name = 'lint'
156156
if not self.allow(name):
157157
return
158-
largs = ['flake8', file]
158+
largs = ['flake8', '-j{}'.format(self.waiter.limit)]
159159
env = self.env
160160
self.waiter.add(LazySubprocess(name, largs, cwd=cwd, env=env))
161161

@@ -167,13 +167,9 @@ def list_tasks(self) -> None:
167167
def add_basic(driver: Driver) -> None:
168168
if False:
169169
driver.add_mypy('file setup.py', 'setup.py')
170-
driver.add_flake8('file setup.py', 'setup.py')
171170
driver.add_mypy('file runtests.py', 'runtests.py')
172-
driver.add_flake8('file runtests.py', 'runtests.py')
173171
driver.add_mypy('legacy entry script', 'scripts/mypy')
174-
driver.add_flake8('legacy entry script', 'scripts/mypy')
175172
driver.add_mypy('legacy myunit script', 'scripts/myunit')
176-
driver.add_flake8('legacy myunit script', 'scripts/myunit')
177173
# needs typed_ast installed:
178174
driver.add_mypy('fast-parse', '--fast-parse', 'test-data/samples/hello.py')
179175

@@ -206,7 +202,6 @@ def add_imports(driver: Driver) -> None:
206202
mod = file_to_module(f)
207203
if not mod.endswith('.__main__'):
208204
driver.add_python_string('import %s' % mod, 'import %s' % mod)
209-
driver.add_flake8('module %s' % mod, f)
210205

211206

212207
PYTEST_FILES = ['mypy/test/{}.py'.format(name) for name in [
@@ -411,6 +406,7 @@ def main() -> None:
411406
add_stubs(driver)
412407
add_stdlibsamples(driver)
413408
add_samples(driver)
409+
driver.add_flake8()
414410

415411
if list_only:
416412
driver.list_tasks()

setup.cfg

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
11
[flake8]
22
max-line-length = 99
3-
exclude = mypy/codec/*
4-
# Thing to ignore:
3+
# typeshed and unit test fixtures have .pyi-specific flake8 configuration
4+
exclude =
5+
# Sphinx configuration is irrelevant
6+
docs/source/conf.py,
7+
# external library with incompatible style
8+
lib-typing/*,
9+
# conflicting styles
10+
misc/*,
11+
# external library with incompatible style
12+
pinfer/*,
13+
# conflicting styles
14+
scripts/*,
15+
# tests have more relaxed styling requirements
16+
# fixtures have their own .pyi-specific configuration
17+
test-data/*,
18+
# typeshed has its own .pyi-specific configuration
19+
typeshed/*
20+
21+
# Things to ignore:
522
# E251: spaces around default arg value (against our style)
623
# E128: continuation line under-indented (too noisy)
724
# F401: unused identifiers (useless, as it doesn't see inside # type: comments)
@@ -10,8 +27,10 @@ exclude = mypy/codec/*
1027
# W503: line break before binary operator
1128
# E704: multiple statements on one line (def)
1229
# E402: module level import not at top of file
13-
# B???: flake8-bugbear errors
14-
ignore = E251,E128,F401,W601,E701,W503,E704,E402,B
30+
# B3??: Python 3 compatibility warnings
31+
# B006: use of mutable defaults in function signatures
32+
# B007: Loop control variable not used within the loop body.
33+
ignore = E251,E128,F401,W601,E701,W503,E704,E402,B3,B006,B007
1534

1635
[coverage:run]
1736
branch = true

test-data/.flake8

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../typeshed/.flake8

test-requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
flake8
2+
flake8-bugbear; python_version >= '3.5'
3+
flake8-pyi; python_version >= '3.5'
24
lxml
35
typed-ast>=0.6.1; sys_platform != 'win32'
46
pytest>=2.8

0 commit comments

Comments
 (0)