【问题标题】:Capturing traceback from R when an RRuntimeError is raised引发 RRuntimeError 时从 R 捕获回溯
【发布时间】:2017-02-21 12:19:25
【问题描述】:

一个 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 的回溯?

【问题讨论】:

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


    【解决方案1】:

    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() 也会将回溯发送到标准输出,并且(据我所知)没有办法避免这种情况,除非[暂时] 覆盖 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.
                try:
                    e.context = {
                        # :kludge: Have to use `unlist` because `traceback`
                        #   returns a pairlist, which rpy2 doesn't know how
                        #   to repr.
                        '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测试。

    【讨论】:

      【解决方案2】:

      rpy2 可以(大部分)很好地处理 R 对列表。但是,它们的表示(方法__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
      

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-10
      • 2012-05-22
      • 2011-09-01
      • 2015-09-16
      相关资源
      最近更新 更多