Python语句排序器
项目描述
Python源代码排序器。
对Python模块的内容进行排序,使语句放置在它们依赖项之后,但将分组留给程序员。按类型分组类成员,并强制方法进行拓扑排序。
使旧式代码导航更容易,您始终可以向上滚动以查看某个内容的定义位置,并减少重复工作。
之前
from module import BaseClass
def function():
return _dependency()
def _decorator(fn):
return fn
@_decorator
def _dependency():
return Class()
class Class(BaseClass):
def public_method(self):
return self
def __init__(self):
pass
之后
from module import BaseClass
class Class(BaseClass):
def __init__(self):
pass
def public_method(self):
return self
def _decorator(fn):
return fn
@_decorator
def _dependency():
return Class()
def function():
return _dependency()
安装
SSort可以使用pip手动安装。
$ pip install ssort
用法
要检查文件是否正确排序,请使用–check标志。可以通过传递–diff查看ssort将做出哪些更改。
$ ssort --check --diff path/to/python_module.py
要允许ssort重新排列您的文件,只需不带任何额外标志调用即可。如果ssort需要修改一个black兼容的文件,结果不一定符合black规范。对ssort兼容的文件运行black的结果始终是ssort兼容的。我们建议您在运行ssort后立即使用isort和black重新格式化。
$ ssort src/ tests/; isort src/ tests/; black src/ tests/
您还可以通过设置pre-commit并在您的.pre-commit-config.yaml中注册ssort,来设置ssort在提交前自动运行。
repos:
# ...
- repo: https://github.com/bwhmather/ssort
rev: master
hooks:
- id: ssort
- repo: https://github.com/pycqa/isort
rev: master
hooks:
- id: isort
name: isort (python)
args: [--profile=black]
- repo: https://github.com/psf/black
rev: master
hooks:
- id: black
输出
ssort将排序顶级语句和类体内的语句。
在排序顶级语句时,ssort遵循三条简单规则:
语句必须始终移动到依赖它们的语句之后,除非存在循环。
如果存在循环,循环内语句的顺序不得改变。
如果语句之间没有依赖关系,那么在尽可能的情况下,应保持原始顺序。
这些规则导致低级别构建块被移动到模块的顶部,而高级逻辑则位于底部。有关为什么选择这种顺序的详细信息,请参阅常见问题解答。
排序类体的规则更复杂。类方法通常只从类外部调用,因此通常没有很多相互依赖来推导结构。因此,ssort忽略(延迟)内部和公共方法之间的依赖关系,而是将类语句分成硬编码的组,并按照以下顺序排列:
类文档字符串。
特殊属性,例如__slots__或__doc__。
内部类。
常规属性。
生命周期内部方法,例如__init__或__new__。
公共方法和未使用的私有方法。
其他内部方法,例如__getattr__或__len__。
除了文档字符串外,这个顺序基本上是任意的。它被选择作为当前行业标准实践的代表性。
内部方法在其组内以硬编码的顺序排列。其他组的语句保留其原始顺序。
私有方法应该只从类中的其他方法调用,因此是拓扑混合的。
如果检测到两个语句之间存在类定义时的依赖关系,则优先保持相关语句的相对顺序。
常见问题解答
为什么ssort是自下而上排序而不是自上而下排序?
Python是一种脚本语言,这意味着每个模块的主体都是从上到下逐行评估的。在几乎所有情况下,必须在使用之前定义它们。在可能的情况下尝试反转顺序是难以安全进行的,并且会导致与无法进行自上而下排序的情况不一致。
自上而下排序只有在查找被延迟时才可能
自上而下排序只有在查找被延迟时才可能,但在大多数情况下,查找是立即发生的。
# Broken.
variable = dependency()
def dependency():
...
在这个例子中,当第一行被评估时,Python会尝试在locals()字典中查找dependency,因为定义它的语句尚未被评估,所以会失败。
据我所知,只有一种方法可以引用尚未绑定到的变量,那就是在函数定义中将其封闭。
# Working.
def function():
return dependency()
def dependency():
...
这是因为查找是在调用函数之后延迟的,在这种情况下,直到两个函数都定义了之后才会发生。
自上而下排序失败不安全
在查找被延迟的情况下,查找可能不会延迟足够远,以便在依赖语句之前对其排序。
以下示例按自下而上顺序格式化。
# Hidden runtime dependency example sorted bottom-up.
def _shared_dep():
...
def _decorator(fn):
_shared_dep()
return fn
@_decorator
def top_level():
_shared_dep()
一种天真分析会建议_shared_dep是一个运行时依赖项,可以安全地将其移动到脚本的底部。
# Hidden runtime dependency example sorted top-down using naive analysis.
def _decorator(fn):
_shared_dep()
return fn
@_decorator
def top_level():
_shared_dep()
def _shared_dep():
...
这将在调用_decorator时导致一个NameError,因为此时_shared_dep尚未绑定。
更强大的静态分析可以减轻这个问题,但任何遗漏的硬引用都可能使程序崩溃。自下而上的排序只能在静态分析错过导致循环的引用时强制重新排序。
自顶向下的排序需要对常量和导入进行特殊处理
即使是自顶向下的排序的坚定支持者也不会认为import语句应该被移到文件的底部。
以下是一个例子
from module import first_dep
def second_dep():
...
@decorator
def function():
first_dep()
second_dep()
严格的自顶向下排序会将其重新排序,使得first_dep导入位于文件底部。
from other_module import decorator
@decorator
def function():
first_dep()
second_dep()
def second_dep():
...
from module import first_dep
为什么ssort不允许我配置X?
ssort旨在在整个生态系统内实现Python源文件组织的统一。如果能够实现这一点,那么它将帮助所有熟悉其约定的程序员导航不熟悉的代码库,并减少偏好不同约定的程序员之间的争论。这只有在这些约定不能被改变的情况下才能实现。
为什么创建ssort?
ssort存在是因为它的作者太懒,不愿意在他的文本编辑器中实现跳转到定义功能,决定最好是将世界上所有的Python代码都重新格式化,以便可以通过滚动进行导航。
链接
许可
该项目在MIT许可条款下提供。有关详细信息,请参阅LICENSE。
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源代码分发
构建分发
ssort-0.13.0.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | a7b35e7725fa93bc6bd82839eb70083cf31bd58545357534288d988a4af8ec4d |
|
MD5 | 78677240b2b82f6a4cd8f9075d0b3bd2 |
|
BLAKE2b-256 | 24718dc4671b53999c0629506e89e12fb3af4acfb603edb69f1d3a47ae5c78f2 |
ssort-0.13.0-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | bb33a64403c3769aec9f5d63f086e4355b6fc1dc62b91e1af6117781fb0b6810 |
|
MD5 | 3ab0cdfe3c605ddc1c4f7ebf2df637fd |
|
BLAKE2b-256 | 3dd586fdced8dd31cb10f96d3b694aaccb71bc964b1b1ced898ec9a0a7602f11 |