跳转到主要内容

一个实现各种lints的flake8扩展

项目描述

flake8-pie CircleCI pypi

一个实现各种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,则需要明确提供hourminute

注意:如果您喜欢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

直接返回布尔表达式而不是返回TrueFalse

# 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

删除不必要的anyall生成器。

# 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

项目详情


下载文件

下载适合您平台文件。如果您不确定该选择哪个,请了解更多关于 安装包 的信息。

源分布

flake8-pie-0.16.0.tar.gz (28.3 kB 查看哈希值)

上传时间

构建分布

flake8_pie-0.16.0-py3-none-any.whl (49.2 kB 查看哈希值)

上传时间 Python 3

由以下机构支持