Python类通过rpy2执行R函数,我希望能够在R函数生成错误的情况下从R捕获回溯。
R代码是遗留的,因此修改它将是非常危险的;我更喜欢在Python方面做点什么。
这是目前Python代码的样子:
from rpy2.rinterface import RRuntimeError
from rpy2.robjects import DataFrame
from rpy2.robjects.packages import InstalledPackage
class RAdapter(BaseRAdapter):
_module = None # type: InstalledPackage
def call_raw(self, function_name, *args, **kwargs):
# type: (str, tuple, dict) -> DataFrame
"""
Invokes an R function and returns the result as a DataFrame.
"""
try:
return getattr(self._module, function_name)(*args, **kwargs)
except RRuntimeError as e:
# :todo: Capture traceback from R and attach to `e`.
e.context = {'r_traceback': '???'}
raise
...
我应该如何修改call_raw
以便在R函数导致错误的情况下从R捕获回溯?
答案 0 :(得分:2)
traceback()
是在R中生成错误回溯的首选函数。使用rpy2.robjects.r
,您可以评估traceback()
函数并将结果直接存储到Python变量中。
rpy2 v2.8.x的注意事项:traceback()
的结果是一个pairlist,rpy2 can work with just fine,但有an issue that prevents repr
from working correctly。为了使代码更容易调试,它使用unlist
将pairlist转换为列表。
请注意traceback()
也会将回溯发送到stdout,除了[暂时]覆盖sys.stdout
之外,我无法(我知道)避免这种情况。
这里有RAdapter.call_raw()
如何捕获R追溯:
from rpy2.rinterface import RRuntimeError
from rpy2.robjects import DataFrame
from rpy2.robjects.packages import InstalledPackage
class RAdapter(BaseRAdapter):
_module = None # type: InstalledPackage
def call_raw(self, function_name, *args, **kwargs):
# type: (str, tuple, dict) -> DataFrame
"""
Invokes an R function and returns the result as a DataFrame.
"""
try:
return getattr(self._module, function_name)(*args, **kwargs)
except RRuntimeError as e:
# Attempt to capture the traceback from R.
# noinspection SpellCheckingInspection
try:
# noinspection SpellCheckingInspection
e.context = {
# :kludge: Have to use `unlist` because `traceback`
# returns a pairlist, which rpy2 doesn't know how
# to handle.
'r_traceback': '\n'.join(r('unlist(traceback())'))
}
except Exception as traceback_exc:
e.context = {
'r_traceback':
'(an error occurred while getting traceback from R)',
'r_traceback_err': traceback_exc,
}
raise
...
使用rpy2==2.8.3
进行测试。
答案 1 :(得分:1)
rpy2
可以处理R pairlists(大部分)。但是,它们的表示(方法__repr__
)似乎有一个错误:R向量的一般__repr__
使用切片,切片不适用于pairlist对象。
>>> from rpy2.robjects import baseenv
>>> opts = baseenv['.Options']
>>> opts.typeof # this is a pairlist
2
>>> print(opts) # working
...
>>> str(opts) # working
>>> opts.items() # working
>>> repr(opts) # ValueError: Cannot handle R type 2