Cythonized pyparser 无法正常工作,函数参数计数错误
Cythonized pyparser not working properly, getting wrong argument count to functions
我有一个 python 项目来解析一些汇编代码
asm_parser/
- asm.py
- AST.py
- obj_code.py
...
在语法下方,我已将此解析操作设置为 class 成功匹配(init 函数获取标记)
self.dir_map_code_fp = pp.OneOrMore(...).setParseAction(Body)
在 AST.py 函数中 Body.__init__()
代币正在接收
class Body(Node):
def __init__(self, tokens):
super(Body,self).__init__()
self.code = tokens
然后我使用输入文件字符串
在语法上调用 parseString()
self.parser_asm.parseString(string, parseAll=True)
为了隐藏源代码,我正在使用 cythonize 将这些 python 文件转换为 .so 文件。下面是我用来创建 .so 文件的 setup.py 文件
class MyBuildExt(build_ext):
def run(self):
build_ext.run(self)
build_dir = Path(self.build_lib)
root_dir = Path(__file__).parent
target_dir = build_dir if not self.inplace else root_dir
self.copy_file(Path('assembler') / '__init__.py', root_dir, target_dir)
self.copy_file(Path('assembler') / '__main__.py', root_dir, target_dir)
def copy_file(self, path, source_dir, destination_dir):
if not (source_dir / path).exists():
return
shutil.copyfile(str(source_dir / path), str(destination_dir / path))
if __name__ == '__main__':
ext_modules = [
Extension(...) for f in files
]
setup(
name="myasm",
ext_modules=cythonize(ext_modules, nthreads=8),
cmdclass=dict(build_ext=MyBuildExt),
packages=["asm"]
)
创建 so 文件后,我创建了一个 run_asm.py 文件以 运行 asm 代码作为包装器。我将所有so文件模块导入到这个run_asm.py
import argparse
from asm import Preprocessor
if __name__ == "__main__":
argParser = argparse.ArgumentParser(description='Assembler')
argParser.add_argument('-asm', '--asm', required=True, help="Assembly file")
argParser.add_argument('-outdir', '--outdir', required=False, default='.', help="default_img directory")
args = argParser.parse_args()
prep = Preprocessor()
纯 python 形式的项目正在运行。在 cythonized .so 形式的 Argparsing 中,文件读取所有东西都在工作,直到 parseAction()
调用 Body.__init__()
函数。 init函数只需要两个,这里给定四个
Traceback (most recent call last):
File "run_asm.py", line 30, in <module>
prep.generate_ast(f, args.outdir)
File "pkg/asm.py", line 145, in pkg.assembler.Preprocessor.generate_ast
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1206, in parseString
loc, tokens = self._parse( instring, 0 )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1072, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 2923, in parseImpl
loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1072, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 2607, in parseImpl
return e._parse( instring, loc, doActions )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1098, in _parseNoCache
tokens = fn( instring, tokensStart, retTokens )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 819, in wrapper
ret = func(*args[limit[0]:])
File "pkg/AST.py", line 28, in pkg.AST.Body.__init__
TypeError: __init__() takes exactly 2 positional arguments (4 given)
我看了pyparsing.py代码,func
下面是Body.__init__()
函数。在纯 python 版本 limit[0] = 2
中,但 cythonized 版本 limit[0] = 0
因此参数计数在两个版本中发生了变化。我无法获得这方面的更多信息。
def wrapper(*args):
while 1:
try:
ret = func(*args[limit[0]:])
foundArity[0] = True
return ret
我还发现 parseAction()
是具有 0-3 个参数的可调用方法 C{fn(s,loc,toks)}, C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}
。我想知道这与此有什么关系(不知何故弄乱了参数计数)
谁能帮我解决这个问题。我正在使用 intelpython 2.7、pyparsing-2.4.7 和 Cython '0.25.2'
我对 cythonize 不熟悉,一定会研究一下。
Pyparsing 处理各种方法签名的内部代码检查引发的 TypeErrors,以检测 TypeError 是来自它自己的签名测试(它是内部创建的,因此被捕获和处理)还是来自解析操作(这将是用户提供的代码创建的 TypeError,因此必须重新引发)。似乎这种 TypeError 内部与用户提供的检测逻辑无法与 cythonized 代码一起正常工作。
您可以尝试将 Body.__init__
签名从 def __init__(self, tokens):
更改为 def __init__(self, s, loc, tokens):
吗?这将继续在 python 和 cython 版本中工作。
如果有任何方法可以转移到 Python3,我强烈建议您这样做。
即使 Cython '0.29.17'
也有同样的错误。如果您受困于 python2,此解决方法将有所帮助。
即使我将函数定义为 def __init__(self, s, loc, tokens):
错误仍然出现,因为对于匹配相同语法的不同标记序列,将使用不同数量的参数调用 parseAction()
中的注册函数。
由于这种动态行为,我修改了函数以接受可变数量的参数。当 arg count 为 2(自包含)时,第二个是标记,当 count 为 4 时,它是最后一个。所以得到最后一个参数就足够了。
class Body(Node):
def __init__(self, *args):
super(Body,self).__init__()
tokens = args[-1]
self.code = tokens
我有一个 python 项目来解析一些汇编代码
asm_parser/
- asm.py
- AST.py
- obj_code.py
...
在语法下方,我已将此解析操作设置为 class 成功匹配(init 函数获取标记)
self.dir_map_code_fp = pp.OneOrMore(...).setParseAction(Body)
在 AST.py 函数中 Body.__init__()
代币正在接收
class Body(Node):
def __init__(self, tokens):
super(Body,self).__init__()
self.code = tokens
然后我使用输入文件字符串
在语法上调用parseString()
self.parser_asm.parseString(string, parseAll=True)
为了隐藏源代码,我正在使用 cythonize 将这些 python 文件转换为 .so 文件。下面是我用来创建 .so 文件的 setup.py 文件
class MyBuildExt(build_ext):
def run(self):
build_ext.run(self)
build_dir = Path(self.build_lib)
root_dir = Path(__file__).parent
target_dir = build_dir if not self.inplace else root_dir
self.copy_file(Path('assembler') / '__init__.py', root_dir, target_dir)
self.copy_file(Path('assembler') / '__main__.py', root_dir, target_dir)
def copy_file(self, path, source_dir, destination_dir):
if not (source_dir / path).exists():
return
shutil.copyfile(str(source_dir / path), str(destination_dir / path))
if __name__ == '__main__':
ext_modules = [
Extension(...) for f in files
]
setup(
name="myasm",
ext_modules=cythonize(ext_modules, nthreads=8),
cmdclass=dict(build_ext=MyBuildExt),
packages=["asm"]
)
创建 so 文件后,我创建了一个 run_asm.py 文件以 运行 asm 代码作为包装器。我将所有so文件模块导入到这个run_asm.py
import argparse
from asm import Preprocessor
if __name__ == "__main__":
argParser = argparse.ArgumentParser(description='Assembler')
argParser.add_argument('-asm', '--asm', required=True, help="Assembly file")
argParser.add_argument('-outdir', '--outdir', required=False, default='.', help="default_img directory")
args = argParser.parse_args()
prep = Preprocessor()
纯 python 形式的项目正在运行。在 cythonized .so 形式的 Argparsing 中,文件读取所有东西都在工作,直到 parseAction()
调用 Body.__init__()
函数。 init函数只需要两个,这里给定四个
Traceback (most recent call last):
File "run_asm.py", line 30, in <module>
prep.generate_ast(f, args.outdir)
File "pkg/asm.py", line 145, in pkg.assembler.Preprocessor.generate_ast
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1206, in parseString
loc, tokens = self._parse( instring, 0 )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1072, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 2923, in parseImpl
loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1072, in _parseNoCache
loc,tokens = self.parseImpl( instring, preloc, doActions )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 2607, in parseImpl
return e._parse( instring, loc, doActions )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 1098, in _parseNoCache
tokens = fn( instring, tokensStart, retTokens )
File "/u/nalaka/intelpython2/lib/python2.7/site-packages/pyparsing.py", line 819, in wrapper
ret = func(*args[limit[0]:])
File "pkg/AST.py", line 28, in pkg.AST.Body.__init__
TypeError: __init__() takes exactly 2 positional arguments (4 given)
我看了pyparsing.py代码,func
下面是Body.__init__()
函数。在纯 python 版本 limit[0] = 2
中,但 cythonized 版本 limit[0] = 0
因此参数计数在两个版本中发生了变化。我无法获得这方面的更多信息。
def wrapper(*args):
while 1:
try:
ret = func(*args[limit[0]:])
foundArity[0] = True
return ret
我还发现 parseAction()
是具有 0-3 个参数的可调用方法 C{fn(s,loc,toks)}, C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}
。我想知道这与此有什么关系(不知何故弄乱了参数计数)
谁能帮我解决这个问题。我正在使用 intelpython 2.7、pyparsing-2.4.7 和 Cython '0.25.2'
我对 cythonize 不熟悉,一定会研究一下。
Pyparsing 处理各种方法签名的内部代码检查引发的 TypeErrors,以检测 TypeError 是来自它自己的签名测试(它是内部创建的,因此被捕获和处理)还是来自解析操作(这将是用户提供的代码创建的 TypeError,因此必须重新引发)。似乎这种 TypeError 内部与用户提供的检测逻辑无法与 cythonized 代码一起正常工作。
您可以尝试将 Body.__init__
签名从 def __init__(self, tokens):
更改为 def __init__(self, s, loc, tokens):
吗?这将继续在 python 和 cython 版本中工作。
如果有任何方法可以转移到 Python3,我强烈建议您这样做。
即使 Cython '0.29.17'
也有同样的错误。如果您受困于 python2,此解决方法将有所帮助。
即使我将函数定义为 def __init__(self, s, loc, tokens):
错误仍然出现,因为对于匹配相同语法的不同标记序列,将使用不同数量的参数调用 parseAction()
中的注册函数。
由于这种动态行为,我修改了函数以接受可变数量的参数。当 arg count 为 2(自包含)时,第二个是标记,当 count 为 4 时,它是最后一个。所以得到最后一个参数就足够了。
class Body(Node):
def __init__(self, *args):
super(Body,self).__init__()
tokens = args[-1]
self.code = tokens