Repository: bitcoin/bitcoin
File: test/lint/lint-python.py (Python)

Code before:
    'E703,'  # statement ends with a semicolon
    'E711,'  # comparison to None should be 'if cond is None:'
    'E714,'  # test for object identity should be "is not"
    'E721,'  # do not compare types, use "isinstance()"
    'E722,'  # do not use bare 'except'
    'E742,'  # do not define classes named "l", "O", or "I"
    'E743,'  # do not define functions named "l", "O", or "I"
    'E901,'  # SyntaxError: invalid syntax
    'E902,'  # TokenError: EOF in multi-line string
    'F401,'  # module imported but unused
    'F402,'  # import module from line N shadowed by loop variable
    'F403,'  # 'from foo_module import *' used; unable to detect undefined names
    'F404,'  # future import(s) name after other statements
    'F405,'  # foo_function may be undefined, or defined from star imports: bar_module
    'F406,'  # "from module import *" only allowed at module level
    'F407,'  # an undefined __future__ feature name was imported
    'F601,'  # dictionary key name repeated with different values
    'F602,'  # dictionary key variable name repeated with different values
    'F621,'  # too many expressions in an assignment with star-unpacking
    'F622,'  # two or more starred expressions in an assignment (a, *b, *c = d)
    'F631,'  # assertion test is a tuple, which are always True
    'F632,'  # use ==/!= to compare str, bytes, and int literals
    'F701,'  # a break statement outside of a while or for loop
    'F702,'  # a continue statement outside of a while or for loop
    'F703,'  # a continue statement in a finally block in a loop
    'F704,'  # a yield or yield from statement outside of a function
    'F705,'  # a return statement with arguments inside a generator
    'F706,'  # a return statement outside of a function/method
    'F707,'  # an except: block as not the last exception handler
    'F811,'  # redefinition of unused name from line N
    'F812,'  # list comprehension redefines 'foo' from line N
    'F821,'  # undefined name 'Foo'
    'F822,'  # undefined name name in __all__
    'F823,'  # local variable name … referenced before assignment
    'F831,'  # duplicate argument name in function definition
    'F841,'  # local variable 'foo' is assigned to but never used
    'W191,'  # indentation contains tabs
    'W291,'  # trailing whitespace
    'W292,'  # no newline at end of file
    'W293,'  # blank line contains whitespace
    'W601,'  # .has_key() is deprecated, use "in"
    'W602,'  # deprecated form of raising exception
    'W603,'  # "<>" is deprecated, use "!="
    'W604,'  # backticks are deprecated, use "repr()"
    'W605,'  # invalid escape sequence "x"
    'W606,'  # 'async' and 'await' are reserved keywords starting with Python 3.7
)


def check_dependencies():
    for dep in DEPS:

Review comment (suggestion):
In commit: `lint: Remove python lint rules that are SyntaxError`

Nit: I believe all of F701-F707 result in `SyntaxError` and should be removed

<details>

<summary> The following examples resulted in SyntaxError's for Python 2.7.18 </summary>

f701.py:
```
def func(x):
    if x > 5:
        break

for i in range(10):
    func(i)        # <--- call function
```

f702.py:
```
def func(x):
    if x > 5:
        continue

for i in range(10):
    func(i)
```

f704.py:
```
step = 1

for x in range(0, 10, step):
  for y in range(0, 10, step):
    yield (x,y)
```

f706.py:
```
step = 1

for x in range(0, 10, step):
  for y in range(0, 10, step):
    return (x,y)
```

f707.py:
```
try:
    x = 1 / 0
except ZeroDivisionError:
    print("Divided by zero")
except:
    print("Generic exception")
except ValueError:
    print("Value error")
```

</details>

Code after:
#!/usr/bin/env python3
#
# Copyright (c) 2022 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

"""
Check for specified mypy warnings in python files.
"""

import os
from pathlib import Path
import subprocess

from importlib.metadata import metadata, PackageNotFoundError

# Customize mypy cache dir via environment variable
cache_dir = Path(__file__).parent.parent / ".mypy_cache"
os.environ["MYPY_CACHE_DIR"] = str(cache_dir)

DEPS = ['lief', 'mypy', 'pyzmq']

# Only .py files in test/functional and contrib/devtools have type annotations
# enforced.
MYPY_FILES_ARGS = ['git', 'ls-files', 'test/functional/*.py', 'contrib/devtools/*.py']


def check_dependencies():
    for dep in DEPS:
        try:
            metadata(dep)
        except PackageNotFoundError:
            print(f"Skipping Python linting since {dep} is not installed.")
            exit(0)


def main():
    check_dependencies()

    mypy_files = subprocess.check_output(MYPY_FILES_ARGS).decode("utf-8").splitlines()
    mypy_args = ['mypy', '--show-error-codes'] + mypy_files

    try:
        subprocess.check_call(mypy_args)
    except subprocess.CalledProcessError:
        exit(1)


if __name__ == "__main__":
    main()