mirror of
https://github.com/pre-commit/pre-commit-hooks.git
synced 2026-03-30 10:16:54 +00:00
Compare commits
23 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1dff44d3a | ||
|
|
a77d5edb63 | ||
|
|
5dcc56558c | ||
|
|
a780519d03 | ||
|
|
6e513a2e71 | ||
|
|
401fb65f54 | ||
|
|
e59bbe6db7 | ||
|
|
ce6aed3bbe | ||
|
|
459b301556 | ||
|
|
d2cf95b9cf | ||
|
|
f4e025486b | ||
|
|
1592578eeb | ||
|
|
3fed74c572 | ||
|
|
a804ba5239 | ||
|
|
9ba250d7b3 | ||
|
|
b51ca91889 | ||
|
|
8e6ea961b7 | ||
|
|
3411068391 | ||
|
|
a2cdab0afe | ||
|
|
9148219126 | ||
|
|
3ab664f766 | ||
|
|
0925e7a9d1 | ||
|
|
e5e94e8702 |
9 changed files with 37 additions and 39 deletions
4
.github/workflows/main.yml
vendored
4
.github/workflows/main.yml
vendored
|
|
@ -10,10 +10,10 @@ jobs:
|
||||||
main-windows:
|
main-windows:
|
||||||
uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1
|
uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1
|
||||||
with:
|
with:
|
||||||
env: '["py39"]'
|
env: '["py310"]'
|
||||||
os: windows-latest
|
os: windows-latest
|
||||||
main-linux:
|
main-linux:
|
||||||
uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1
|
uses: asottile/workflows/.github/workflows/tox.yml@v1.8.1
|
||||||
with:
|
with:
|
||||||
env: '["py39", "py310", "py311", "py312"]'
|
env: '["py310", "py311", "py312", "py313"]'
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
|
|
|
||||||
|
|
@ -10,23 +10,23 @@ repos:
|
||||||
- id: name-tests-test
|
- id: name-tests-test
|
||||||
- id: requirements-txt-fixer
|
- id: requirements-txt-fixer
|
||||||
- repo: https://github.com/asottile/setup-cfg-fmt
|
- repo: https://github.com/asottile/setup-cfg-fmt
|
||||||
rev: v2.8.0
|
rev: v3.2.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: setup-cfg-fmt
|
- id: setup-cfg-fmt
|
||||||
- repo: https://github.com/asottile/reorder-python-imports
|
- repo: https://github.com/asottile/reorder-python-imports
|
||||||
rev: v3.15.0
|
rev: v3.16.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
args: [--py39-plus, --add-import, 'from __future__ import annotations']
|
args: [--py310-plus, --add-import, 'from __future__ import annotations']
|
||||||
- repo: https://github.com/asottile/add-trailing-comma
|
- repo: https://github.com/asottile/add-trailing-comma
|
||||||
rev: v3.2.0
|
rev: v4.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: add-trailing-comma
|
- id: add-trailing-comma
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v3.20.0
|
rev: v3.21.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args: [--py39-plus]
|
args: [--py310-plus]
|
||||||
- repo: https://github.com/hhatto/autopep8
|
- repo: https://github.com/hhatto/autopep8
|
||||||
rev: v2.3.2
|
rev: v2.3.2
|
||||||
hooks:
|
hooks:
|
||||||
|
|
@ -36,6 +36,6 @@ repos:
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8
|
- id: flake8
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: v1.17.1
|
rev: v1.19.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
entry: check-case-conflict
|
entry: check-case-conflict
|
||||||
language: python
|
language: python
|
||||||
- id: check-docstring-first
|
- id: check-docstring-first
|
||||||
name: check docstring is first
|
name: check docstring is first (deprecated)
|
||||||
description: checks a common error of defining a docstring after code.
|
description: checks a common error of defining a docstring after code.
|
||||||
entry: check-docstring-first
|
entry: check-docstring-first
|
||||||
language: python
|
language: python
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
6.0.0 - 2024-08-09
|
6.0.0 - 2025-08-09
|
||||||
==================
|
==================
|
||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,6 @@ Require literal syntax when initializing empty or zero Python builtin types.
|
||||||
#### `check-case-conflict`
|
#### `check-case-conflict`
|
||||||
Check for files with names that would conflict on a case-insensitive filesystem like MacOS HFS+ or Windows FAT.
|
Check for files with names that would conflict on a case-insensitive filesystem like MacOS HFS+ or Windows FAT.
|
||||||
|
|
||||||
#### `check-docstring-first`
|
|
||||||
Checks for a common error of placing code before the docstring.
|
|
||||||
|
|
||||||
#### `check-executables-have-shebangs`
|
#### `check-executables-have-shebangs`
|
||||||
Checks that non-binary executables have a proper shebang.
|
Checks that non-binary executables have a proper shebang.
|
||||||
|
|
||||||
|
|
@ -207,6 +204,8 @@ Trims trailing whitespace.
|
||||||
|
|
||||||
- `check-byte-order-marker`: instead use fix-byte-order-marker
|
- `check-byte-order-marker`: instead use fix-byte-order-marker
|
||||||
- `fix-encoding-pragma`: instead use [`pyupgrade`](https://github.com/asottile/pyupgrade)
|
- `fix-encoding-pragma`: instead use [`pyupgrade`](https://github.com/asottile/pyupgrade)
|
||||||
|
- `check-docstring-first`: fundamentally flawed, deprecated without replacement.
|
||||||
|
|
||||||
|
|
||||||
### As a standalone package
|
### As a standalone package
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,36 +26,37 @@ class Call(NamedTuple):
|
||||||
class Visitor(ast.NodeVisitor):
|
class Visitor(ast.NodeVisitor):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
ignore: Sequence[str] | None = None,
|
ignore: set[str],
|
||||||
allow_dict_kwargs: bool = True,
|
allow_dict_kwargs: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.builtin_type_calls: list[Call] = []
|
self.builtin_type_calls: list[Call] = []
|
||||||
self.ignore = set(ignore) if ignore else set()
|
|
||||||
self.allow_dict_kwargs = allow_dict_kwargs
|
self.allow_dict_kwargs = allow_dict_kwargs
|
||||||
|
self._disallowed = BUILTIN_TYPES.keys() - ignore
|
||||||
|
|
||||||
def _check_dict_call(self, node: ast.Call) -> bool:
|
def _check_dict_call(self, node: ast.Call) -> bool:
|
||||||
return self.allow_dict_kwargs and bool(node.keywords)
|
return self.allow_dict_kwargs and bool(node.keywords)
|
||||||
|
|
||||||
def visit_Call(self, node: ast.Call) -> None:
|
def visit_Call(self, node: ast.Call) -> None:
|
||||||
if not isinstance(node.func, ast.Name):
|
if (
|
||||||
# Ignore functions that are object attributes (`foo.bar()`).
|
# Ignore functions that are object attributes (`foo.bar()`).
|
||||||
# Assume that if the user calls `builtins.list()`, they know what
|
# Assume that if the user calls `builtins.list()`, they know what
|
||||||
# they're doing.
|
# they're doing.
|
||||||
return
|
isinstance(node.func, ast.Name) and
|
||||||
if node.func.id not in set(BUILTIN_TYPES).difference(self.ignore):
|
node.func.id in self._disallowed and
|
||||||
return
|
(node.func.id != 'dict' or not self._check_dict_call(node)) and
|
||||||
if node.func.id == 'dict' and self._check_dict_call(node):
|
not node.args
|
||||||
return
|
):
|
||||||
elif node.args:
|
|
||||||
return
|
|
||||||
self.builtin_type_calls.append(
|
self.builtin_type_calls.append(
|
||||||
Call(node.func.id, node.lineno, node.col_offset),
|
Call(node.func.id, node.lineno, node.col_offset),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.generic_visit(node)
|
||||||
|
|
||||||
|
|
||||||
def check_file(
|
def check_file(
|
||||||
filename: str,
|
filename: str,
|
||||||
ignore: Sequence[str] | None = None,
|
*,
|
||||||
|
ignore: set[str],
|
||||||
allow_dict_kwargs: bool = True,
|
allow_dict_kwargs: bool = True,
|
||||||
) -> list[Call]:
|
) -> list[Call]:
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, 'rb') as f:
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ conflicts and keep the file nicely ordered.
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
from collections.abc import Callable
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Callable
|
|
||||||
from typing import IO
|
from typing import IO
|
||||||
|
|
||||||
PASS = 0
|
PASS = 0
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ packages = find:
|
||||||
install_requires =
|
install_requires =
|
||||||
ruamel.yaml>=0.15
|
ruamel.yaml>=0.15
|
||||||
tomli>=1.1.0;python_version<"3.11"
|
tomli>=1.1.0;python_version<"3.11"
|
||||||
python_requires = >=3.9
|
python_requires = >=3.10
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
exclude =
|
exclude =
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,6 @@ t1 = ()
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def visitor():
|
|
||||||
return Visitor()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
('expression', 'calls'),
|
('expression', 'calls'),
|
||||||
[
|
[
|
||||||
|
|
@ -85,7 +80,8 @@ def visitor():
|
||||||
('builtins.tuple()', []),
|
('builtins.tuple()', []),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_non_dict_exprs(visitor, expression, calls):
|
def test_non_dict_exprs(expression, calls):
|
||||||
|
visitor = Visitor(ignore=set())
|
||||||
visitor.visit(ast.parse(expression))
|
visitor.visit(ast.parse(expression))
|
||||||
assert visitor.builtin_type_calls == calls
|
assert visitor.builtin_type_calls == calls
|
||||||
|
|
||||||
|
|
@ -102,7 +98,8 @@ def test_non_dict_exprs(visitor, expression, calls):
|
||||||
('builtins.dict()', []),
|
('builtins.dict()', []),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_dict_allow_kwargs_exprs(visitor, expression, calls):
|
def test_dict_allow_kwargs_exprs(expression, calls):
|
||||||
|
visitor = Visitor(ignore=set())
|
||||||
visitor.visit(ast.parse(expression))
|
visitor.visit(ast.parse(expression))
|
||||||
assert visitor.builtin_type_calls == calls
|
assert visitor.builtin_type_calls == calls
|
||||||
|
|
||||||
|
|
@ -114,17 +111,18 @@ def test_dict_allow_kwargs_exprs(visitor, expression, calls):
|
||||||
('dict(a=1, b=2, c=3)', [Call('dict', 1, 0)]),
|
('dict(a=1, b=2, c=3)', [Call('dict', 1, 0)]),
|
||||||
("dict(**{'a': 1, 'b': 2, 'c': 3})", [Call('dict', 1, 0)]),
|
("dict(**{'a': 1, 'b': 2, 'c': 3})", [Call('dict', 1, 0)]),
|
||||||
('builtins.dict()', []),
|
('builtins.dict()', []),
|
||||||
|
pytest.param('f(dict())', [Call('dict', 1, 2)], id='nested'),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_dict_no_allow_kwargs_exprs(expression, calls):
|
def test_dict_no_allow_kwargs_exprs(expression, calls):
|
||||||
visitor = Visitor(allow_dict_kwargs=False)
|
visitor = Visitor(ignore=set(), allow_dict_kwargs=False)
|
||||||
visitor.visit(ast.parse(expression))
|
visitor.visit(ast.parse(expression))
|
||||||
assert visitor.builtin_type_calls == calls
|
assert visitor.builtin_type_calls == calls
|
||||||
|
|
||||||
|
|
||||||
def test_ignore_constructors():
|
def test_ignore_constructors():
|
||||||
visitor = Visitor(
|
visitor = Visitor(
|
||||||
ignore=('complex', 'dict', 'float', 'int', 'list', 'str', 'tuple'),
|
ignore={'complex', 'dict', 'float', 'int', 'list', 'str', 'tuple'},
|
||||||
)
|
)
|
||||||
visitor.visit(ast.parse(BUILTIN_CONSTRUCTORS))
|
visitor.visit(ast.parse(BUILTIN_CONSTRUCTORS))
|
||||||
assert visitor.builtin_type_calls == []
|
assert visitor.builtin_type_calls == []
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue