当引发RRuntimeError时从R捕获回溯

时间:2016-10-12 15:50:56

标签: python-2.7 python-2.x rpy2 traceback

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捕获回溯?

2 个答案:

答案 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