自行车修理工 - 重写Python源代码
项目描述
自行车修理工
BRM是一个Python源代码修改库,可以保证无损失修改的完全往返能力。它通常用于非结构化源代码部分,可以直接在标记上执行修改。
一个简单的例子是TokenTransformer
,我们将每个+
(加号)运算符更改为-
(减号)运算符。
class DestoryAllOfThem(TokenTransformer):
# Replace each PLUS token with a MINUS
def visit_plus(self, token):
return token._replace(string="-")
transformer = DestoryAllOfThem()
assert transformer.transform("(2p) + 2 # with my precious comment") == "(2p) - 2 # with my precious comment"
与任何形式的结构化树表示相比,基于标记的重构的一个优点是,你可以更加自由地进行操作。例如,你想原型化一个新的语法想法,比如一个√
运算符;这里就是了
class SquareRoot(TokenTransformer):
# Register a new token called `squareroot`
def register_squareroot(self):
return "√"
# Match a squareroot followed by a number
@pattern("squareroot", "number")
def remove_varprefix(self, operator, token):
return self.quick_tokenize(f"int({token.string} ** 0.5)")
sqr = SquareRoot()
assert eval(sqr.transform("√9")) == 3
为什么选择BRM
- BRM是一个极其简单、无依赖、纯Python工具,只有500行代码,你可以轻松地将其作为产品使用。
- BRM支持所有新的Python语法,无需等待我们的上游更改。
- BRM支持不完整的文件(以及包含无效Python语法的文件)。
- BRM支持引入新语法并将其永久化用于原型。
如果你需要这些功能之一,BRM可能非常适合。但我必须警告,不要用它来进行复杂的重构任务,因为我们不打算解决这个问题。如果你需要这样的工具,请查看refactor或parso。
永久性
如果你喜欢转换器的概念并在实际代码中使用它们,BRM提供了一个自定义编码,当指定时将自动运行你的转换器。
- 编写转换器
- 将其复制到
~/.brm
文件夹,或者简单地使用cp <file>.py $(python -m brm)
- 在每个文件上指定
# coding: brm
示例
from brm import TokenTransformer, pattern
class AlwaysTrue(TokenTransformer):
STRICT = False
# Make every if/elif statement `True`
@pattern("name", "*any", "colon")
def always_true_if(self, *tokens):
statement, *_, colon = tokens
if statement.string not in {"if", "elif"}:
return
true, = self.quick_tokenize("True")
return (statement, true, colon)
让我们把我们的变压器放到BRM的变压器文件夹中,然后运行我们的示例。
(.venv) [ 9:12ÖS ] [ isidentical@x200:~ ]
$ cat -n r.py
1 # coding: brm
2
3 a = 2
4 if a > 2:
5 print("LOL")
(.venv) [ 9:12ÖS ] [ isidentical@x200:~ ]
$ cp test.py $(python -m brm)
(.venv) [ 9:12ÖS ] [ isidentical@x200:~ ]
$ python r.py
LOL
嗖!
BRM模式语法
对于BRM,Python源代码只是一系列标记。它不会在这些标记之间创建任何关系,甚至不会验证文件在语法上是正确的。例如,看一下下面的文件
if a == x:
2 + 2 # lol
对于BRM,从抽象的角度来看,文件只是以下文本
NAME NAME EQEQUAL NAME COLON NEWLINE INDENT NUMBER PLUS NUMBER COMMENT NEWLINE DEDENT ENDMARKER
并且在内部是这样处理的
如果您想在这里匹配二进制加法运算(2 + 2
),您可以创建带有number, plus, name
的模式。
注意:如果您想可视化您的模式并查看它们匹配的内容,请尝试
examples/visualize.py
。
附加信息
如果您正在使用TokenTransformer
,有一些实用的函数您可以查看
函数 | 返回值 | 描述 | |
---|---|---|---|
quick_tokenize(source: str, *, strip: bool = True) |
List[TokenInfo] |
将给定的source 文本拆分为标记列表。如果strip 为True ,则最后两个标记(NEWLINE ,EOF )将被省略。 |
|
quick_untokenize(tokens: List[TokenInfo]) |
str |
将给定的标记序列转换回表示形式,在标记化时将产生相同的标记(有损转换)。如果您想要完整的往返/无损转换,请使用tokenize.untokenize 。 |
|
directional_length(tokens: List[TokenInfo]) |
int |
计算序列中第一个和最后一个标记之间的线性距离。 | |
shift_all(tokens: List[TokenInfo], x_offset: int, y_offset: int) |
List[TokenInfo] |
将给定序列中的每个标记沿列偏移量x_offset 移动,并沿行号移动y_offset 。返回新的标记列表。 |
|
until(toktype: int, stream: List[TokenInfo]) |
Iterator[TokenInfo] |
在看到类型为toktype 的标记之前产生所有标记。如果没有看到这样的标记,它将引发一个ValueError 。 |
|
_get_type(token: TokenInfo) |
int |
返回给定标记的类型。与until() 一起使用时很有用。(内部使用) |
项目详情
下载文件
下载您平台上的文件。如果您不确定要选择哪个,请了解更多关于安装包的信息。
源分发
brm-0.3.0.tar.gz (9.7 kB 查看哈希值)
构建分发
brm-0.3.0-py2.py3-none-any.whl (9.0 kB 查看哈希值)
关闭
brm-0.3.0.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 37c9275988aebcf052bf2b1811923c21f3c6571a1bea588c8c86040147f325d0 |
|
MD5 | 571ccfe82498ec16a6f27ed505f09198 |
|
BLAKE2b-256 | 65d2848dc4f221f96d33843f3454bfb68ee40b2ec630aa4a249a7d19e94aff05 |