Debugging Pyparsing:更改所有解析器元素的默认调试操作

Debugging Pyparsing:更改所有解析器元素的默认调试操作,debugging,pyparsing,monkeypatching,Debugging,Pyparsing,Monkeypatching,我想通过添加缩进来提高pyparsing调试输出的可读性。例如,与此相反: Match part at loc 0(1,1) Match subpart1 at loc 0(1,1) Match subsubpart1 at loc 0(1,1) Matched subsubpart1 at loc 10(2,1) -> ... Matched subpart1 at loc 20(3,1) -> ... Match subpart2 at loc 20(3,1) Match sub

我想通过添加缩进来提高pyparsing调试输出的可读性。例如,与此相反:

Match part at loc 0(1,1)
Match subpart1 at loc 0(1,1)
Match subsubpart1 at loc 0(1,1)
Matched subsubpart1 at loc 10(2,1) -> ...
Matched subpart1 at loc 20(3,1) -> ...
Match subpart2 at loc 20(3,1)
Match subsubpart2 at loc 20(3,1)
Matched subsubpart2 at loc 30(4,1) -> ...
Matched subpart2 at loc 40(5,1) -> ...
Matched part at loc 50(6,1) -> ...
我希望将其缩进如下,以便更好地理解解析过程中发生的情况:

Match part at loc 0(1,1)
    Match subpart1 at loc 0(1,1)
        Match subsubpart1 at loc 0(1,1)
        Matched subsubpart1 at loc 10(2,1) -> ...
    Matched subpart1 at loc 20(3,1) -> ...
    Match subpart2 at loc 20(3,1)
        Match subsubpart2 at loc 20(3,1)
        Matched subsubpart2 at loc 30(4,1) -> ...
    Matched subpart2 at loc 40(5,1) -> ...
Matched part at loc 50(6,1) -> ...
因此,在pyparsing.py中,我刚刚将
\u defaultStartDebugAction
\u defaultSuccessDebugAction
\u defaultExceptionDebugAction
更改为:

pos = -1
def _defaultStartDebugAction( instring, loc, expr ):
    global pos
    pos = pos + 1
    print ("\t" * pos + ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))

def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
    print ("\t" * pos + "Matched " + _ustr(expr) + " -> " + str(toks.asList()))
    global pos
    pos = pos - 1

def _defaultExceptionDebugAction( instring, loc, expr, exc ):
    print ("\t" * pos + "Exception raised:" + _ustr(exc))
    global pos
    pos = pos - 1
(我刚刚在输出中添加了
pos
表达式和
“\t”*pos
,以获得所需的结果)

但是,我不喜欢直接篡改pyparsing库。另一方面,我不想在我定义的每个解析器元素上使用
.setDebugActions
方法,我希望它们都使用我修改过的默认调试操作

有没有一种方法可以在不直接篡改pyparsing.py库的情况下实现这一点


谢谢

Python模块与任何其他Python对象一样,您可以使用标准的Python函数装饰方法来操作它们的符号。通常被称为“monkeypatching”,这些可以完全从您自己的代码中完成,而无需修改实际的库源代码

实现此更改的最简单方法是覆盖符号。在代码中,编写:

import pyparsing
# have to import _ustr explicitly, since it does not get pulled in with '*' import
_ustr = pyparsing._ustr

pos = -1
def defaultStartDebugAction_with_indent( instring, loc, expr ):
    global pos
    pos = pos + 1
    print ("\t" * pos + ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))

def defaultSuccessDebugAction_with_indent( instring, startloc, endloc, expr, toks ):
    global pos
    print ("\t" * pos + "Matched " + _ustr(expr) + " -> " + str(toks.asList()))
    pos = pos - 1

def defaultExceptionDebugAction_with_indent( instring, loc, expr, exc ):
    global pos
    print ("\t" * pos + "Exception raised:" + _ustr(exc))
    pos = pos - 1

pyparsing._defaultStartDebugAction = defaultStartDebugAction_with_indent
pyparsing._defaultSuccessDebugAction = defaultSuccessDebugAction_with_indent
pyparsing._defaultExceptionDebugAction = defaultExceptionDebugAction_with_indent
或者,更简洁的版本是将原始方法与代码包装为装饰器:

pos = -1

def incr_pos(fn):
    def _inner(*args):
        global pos
        pos += 1
        print ("\t" * pos , end="")
        return fn(*args)
    return _inner

def decr_pos(fn):
    def _inner(*args):
        global pos
        print ("\t" * pos , end="")
        pos -= 1
        return fn(*args)
    return _inner

import pyparsing
pyparsing._defaultStartDebugAction = incr_pos(pyparsing._defaultStartDebugAction)
pyparsing._defaultSuccessDebugAction = decr_pos(pyparsing._defaultSuccessDebugAction)
pyparsing._defaultExceptionDebugAction = decr_pos(pyparsing._defaultExceptionDebugAction)
这样,如果您更新了pyparsing,并且原始代码发生了更改,那么您的monkeypatch将获得更新,而无需修改原始方法的副本

为了使您的意图更加清晰,并避免重复这些函数名(DRY),这将替换最后3行:

def monkeypatch_decorate(module, name, deco_fn):
    setattr(module, name, deco_fn(getattr(module, name)))

monkeypatch_decorate(pyparsing, "_defaultStartDebugAction", incr_pos)
monkeypatch_decorate(pyparsing, "_defaultSuccessDebugAction", decr_pos)
monkeypatch_decorate(pyparsing, "_defaultExceptionDebugAction", decr_pos)