Начинающий программист
Опытный программист
Есть 2 способа ускорить чтение и понимания кода:
From Python…
def fib(n): a, b = 0, 1 while a < n: yield a a, b = b, a+b
…to statically typed Python
def fib(n: int) -> Iterator[int]: a, b = 0, 1 while a < n: yield a a, b = b, a+b
.pre-commit-config.yaml
default_stages: [commit, push] repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.2.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files - id: check-ast - id: check-merge-conflict - repo: https://github.com/python/black rev: 22.3.0 hooks: - id: black - repo: https://github.com/pycqa/isort rev: 5.10.1 hooks: - id: isort name: isort (python) - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: - id: flake8 additional_dependencies: [ yastyleguide==0.1.0 ]
import ast code = "one_plus_two = 1 + 2" tree = ast.parse(code) print(ast.dump(tree, indent=4))
Module( body=[ Assign( targets=[ Name(id='one_plus_two', ctx=Store())], value=BinOp( left=Constant(value=1), op=Add(), right=Constant(value=2)))], type_ignores=[])
import ast code = "one_plus_two = 1 + 2" tree = ast.parse(code) for node in ast.walk(tree): print(node.__class__.__name__)
Module Assign Name BinOp Store Constant Add Constant
for name, value in ast.iter_fields(tree): print(name, value)
body [<ast.Assign object at 0x7fa888f0a6b0>] type_ignores []
for node in ast.iter_child_nodes(tree): print(node.__class__.__name__)
Assign
import ast class BinOpVisitor(ast.NodeVisitor): def visit_BinOp(self, node): print(f"found BinOp at line: {node.lineno}") self.generic_visit(node) code = "one_plus_two = 1 + 2" tree = ast.parse(code) BinOpVisitor().visit(tree)
found BinOp at line: 1
from typing import Any, Generator, Tuple __version__ = "0.1.0" ERROR = Tuple[int, int, str, Any] ERROR_GENERATOR = Generator[ERROR, None, None] class NoConstantPlugin: name = __name__ version = __version__ def __init__(self, tree: ast.AST): self._tree = tree def run(self) -> ERROR_GENERATOR: visitor = Visitor() visitor.visit(self._tree) for line, col, msg in visitor.errors: yield line, col, msg, type(self)
import ast class Visitor(ast.NodeVisitor): errors: list[tuple[int, int, str]] = [] def visit_Constant(self, node: ast.AST): if node.value not in (0, 1, 10, 100): self.errors.append((node.lineno, node.col_offset, "NAC100 Not allowed CONSTANT in code")) self.generic_visit(node)
Теперь запустим
code = "one_plus_two = 1 + 2" tree = ast.parse(code) next(NoConstantPlugin(tree).run())
(1, 19, 'NAC100 Not allowed CONSTANT in code', __main__.NoConstantPlugin)
setup.py
flake8_entry_point = # ... setuptools.setup( # snip ... entry_points={ flake8_entry_point: [ 'NAC = flake8_example:NoConstantPlugin', ], }, # snip ... )
pyproject.toml
[tool.poetry.plugins."flake8.extension"] NAC = "flake8_example:NoConstantPlugin"