一个实现各种lints的flake8扩展
项目描述
flake8-pie

一个实现各种lints的flake8扩展
lints
PIE781: assign-and-return
基于Clippy的 let_and_return
和Microsoft的TSLint规则 no-unnecessary-local-variable
.
有关此lint结构的更多信息,请参阅随附的博客文章.
示例
# error
def foo():
x = bar()
return x
# allowed
def foo():
x, _ = bar()
return x
PIE783: celery-explicit-names
警告关于没有明确命名的Celery任务定义。
注意:此lint在将任何具有.task()
方法或被调用为shared_task()
的装饰器视为Celery装饰器方面有点天真。
示例
# error
@app.task()
def foo():
pass
# ok
@app.task(name="app_name.tasks.foo")
def foo():
pass
PIE784: celery-explicit-crontab-args
Celery提供的crontab
类对初学者来说有一些默认参数可能会令人惊讶。具体来说,crontab(hour="0,12")
不会在午夜和中午运行任务,它将在那两个小时的每一分钟运行任务。这个代码检查会将其视为错误,迫使您写出crontab(hour="0, 12", minute="*")
。
此外,这个代码检查有点复杂,因为它要求您指定比您提供的大时间增量更小的每个增量。因此,如果您提供了days_of_week
,则需要明确提供hour
和minute
。
注意:如果您喜欢crontab()
的默认行为,则可以禁用此代码检查或将kwarg
值传递为"*"
,例如,minutes="*"
。
此外,由于这个代码检查本质上是对crontab()
函数调用的一种简单搜索,如果您有一个同名函数,则会导致误报。
PIE785: celery-require-tasks-expire
如果Celery任务没有过期时间,它们可能会成堆。
这强制在celery beat配置字典和.apply_async()
调用中都指定过期时间。
关于这个代码检查的简单性,同样适用。
PIE786: precise-exception-handlers
在捕获异常时要精确。裸的except:
处理程序、捕获BaseException
或捕获Exception
可能会导致意外的错误。
示例
# error
try:
save_file(name="export.csv")
except:
pass
# error
try:
save_file(name="export.csv")
except BaseException:
pass
# error
try:
save_file(name="export.csv")
except Exception:
pass
# error
try:
save_file(name="export.csv")
except (ValueError, Exception):
pass
# ok
try:
save_file(name="export.csv")
except OSError:
pass
PIE787: no-len-condition
在Python中,空集合是虚假的,因此当在if语句/表达式中检查空集时,调用len()
是不必要的。
与显式标量进行比较是允许的。
# error
if len(foo): ...
if not len(foo): ...
# ok
if foo: ...
if not foo: ...
if len(foo) > 0: ...
if len(foo) == 0: ...
PIE788: no-bool-condition
if语句/表达式的测试参数将评估其真实性,因此调用bool()
是不必要的。
与True
/False
进行比较是允许的。
# error
if bool(foo): ...
if not bool(foo): ...
# ok
if foo: ...
if not foo: ...
if bool(foo) is True: ...
if bool(foo) is False: ...
PIE789: prefer-isinstance-type-compare
使用type()
不考虑子类,类型检查器也不会细化类型,请使用isinstance
代替。
# error
if type(foo) == str: ...
if type(foo) is str: ...
if type(foo) in [int, str]: ...
# ok
if isinstance(foo, str): ...
if isinstance(foo, (int, str)): ...
PIE790: no-unnecessary-pass
在定义具有空体的class
或函数时,pass
是不必要的。
# error
class BadError(Exception):
"""
some doc comment
"""
pass
def foo() -> None:
"""
some function
"""
pass
# ok
class BadError(Exception):
"""
some doc comment
"""
def foo() -> None:
"""
some function
"""
PIE791: no-pointless-statements
没有赋值或断言的比较可能是打字错误。
# error
"foobar" in data
res.json() == []
user.is_authenticated() is True
# ok
assert "foobar" in data
foo = res.json() == []
use.is_authenticated()
PIE792: no-inherit-object
在Python 3中,从object
继承不是必需的。
# error
class Foo(object):
...
# ok
class Foo:
...
PIE793: prefer-dataclass
尝试找到无意中遗漏了@dataclass
装饰器的情况。
# error
class Foo:
z: dict[int, int]
def __init__(self) -> None: ...
class Bar:
x: list[str]
# ok
class Bar(Foo):
z: dict[int, int]
@dataclass
class Bar:
x: list[str]
PIE794: dupe-class-field-definitions
查找重复的字段定义,这可能在大型ORM模型定义中发生。
# error
class User(BaseModel):
email = fields.EmailField()
# ...80 more properties...
email = fields.EmailField()
# ok
class User(BaseModel):
email = fields.EmailField()
# ...80 more properties...
PIE795: prefer-stdlib-enums
不要在类上定义各种常量属性,而应使用stdlib enum,类型检查器支持类型细化。
# error
class Foo:
A = "A"
B = "B"
C = "C"
# ok
import enum
class Foo(enum.Enum):
A = "A"
B = "B"
C = "C"
PIE796: prefer-unique-enums
默认情况下,stdlib enum允许多个字段名映射到相同的值,这个代码检查要求每个枚举值都是唯一的。
# error
class Foo(enum.Enum):
A = "A"
B = "B"
C = "C"
D = "C"
# ok
class Foo(enum.Enum):
A = "A"
B = "B"
C = "C"
D = "D"
PIE797: no-unnecessary-if-expr
直接调用bool()
而不是重新实现其功能。
# error
foo(is_valid=True if buzz() else False)
# ok
foo(is_valid=bool(buzz()))
PIE798: no-unnecessary-class
不要使用类来命名空间函数,而应使用模块。
# error
class UserManager:
class User(NamedTuple):
name: str
@classmethod
def update_user(cls, user: User) -> None:
...
@staticmethod
def sync_users() -> None:
...
# ok
class User(NamedTuple):
name: str
def update_user(user: User) -> None:
...
def sync_users() -> None:
...
PIE799: prefer-col-init
检查在创建集合时传递值,而不是创建一个空集合然后插入。
# error
bars = []
bar = bar()
bars.append(bar)
# ok
bar = bar()
bars = [bar]
# error
s = deque()
s.append(foo)
# ok
s = deque([foo])
PIE800: no-unnecessary-spread
检查不必要的字典解包。
# error
{**foo, **{"bar": 10}}
# ok
{**foo, "bar": 10}
PIE801: prefer-simple-return
直接返回布尔表达式而不是返回True
和False
。
# error
def main():
if foo > 5:
return True
return False
# error
def main():
if foo > 5:
return True
else:
return False
# ok
def main():
return foo > 5
PIE802: prefer-simple-any-all
删除不必要的any
和all
生成器。
# error
any([x.id for x in bar])
all([x.id for x in bar])
# ok
all(x.id for x in bar)
any(x.id for x in bar)
any({x.id for x in bar})
PIE803: prefer-logging-interpolation
在记录之前不要格式化字符串。让logging
进行参数插值。
这允许Sentry聚合日志,防止在插值失败时引发异常,并在禁用日志级别时提高性能。请参阅"PyCQA/pylint#1788"。
# error
logger.info("Login error for %s" % user)
logger.info("Login error for %s, %s" % (user_id, name))
# error
logger.info("Login error for {}".format(user))
logger.info("Login error for {}, {}".format(user_id, name))
# error
logger.info(f"Login error for {user}")
logger.info(f"Login error for {user_id}, {name}")
# ok
logger.info("Login error for %s", user)
logger.info("Login error for %s, %s", user_id, name)
PIE804: no-unnecessary-dict-kwargs
只要字典的键是有效的Python标识符名称,我们就可以安全地删除周围的字典。
# error
foo(**{"bar": True})
# ok
foo(bar=True)
foo(**buzz)
foo(**{"bar foo": True})
dev
# install dependencies
poetry install
s/lint
s/test
PIE805: prefer-literal
当前仅检查字节字符串字面量。
# error
"foo".encode()
# ok
b"foo"
"😀".encode()
PIE806: no-assert-except
不要使用 assert
和捕获异常,而是使用 if 语句。
# error
try:
assert "@" in bar
except AssertionError:
...
# ok
if "@" in bar:
...
PIE807: 优先使用内置列表
lambda: []
与内置的 list
相等
# error
@dataclass
class Foo:
foo: List[str] = field(default_factory=lambda: [])
# ok
@dataclass
class Foo:
foo: List[str] = field(default_factory=list)
PIE808: 优先使用简单范围
在某些情况下,我们可以省略 range
的第一个参数,因为默认起始位置是 0。
# err
range(0, 10)
# ok
range(10)
range(x, 10)
range(0, 10, x)
PIE809: Django 优先使用批量操作
批量创建多个对象,而不是执行 O(N) 次查询。
# error
[Item.objects.create(item) for item in items]
# error
[Item.objects.create(item) for item in [bar for bar in buzz]]
# error
(Item.objects.create(item) for item in items)
# ok
Item.objects.insert(items)
Item.objects.create(item)
开发
检查抽象语法树 (AST)
您可以使用 astpretty
来输出代码片段的 AST。
./.venv/bin/astpretty <(pbpaste)
将新版本上传到 PyPi
# increment `Flake8PieCheck.version` and pyproject.toml `version`
# build new distribution files and upload to pypi
# Note: this will ask for login credentials
rm -rf dist && poetry publish --build
项目详情
下载文件
下载适合您平台文件。如果您不确定该选择哪个,请了解更多关于 安装包 的信息。