示例#1
0
    def __doc__(self):
        doc = ['Python representation of an R function.']
        description = help.docstring(self.__rpackagename__,
                                     self.__rname__,
                                     sections=['description'])
        doc.append(description)

        fm = _formals_fixed(self)
        names = fm.do_slot('names')
        doc.append(self.__rname__+'(')
        for key, val in self._prm_translate.items():
            if key == '___':
                description = ('(was "..."). R ellipsis '
                               '(any number of parameters)')
            else:
                description = _repr_argval(fm[names.index(val)])
            if description is None:
                doc.append('    %s,' % key)
            else:
                doc.append('    %s = %s,' % (key, description))
        doc.extend((')', ''))
        package = help.Package(self.__rpackagename__)
        page = package.fetch(self.__rname__)
        for item in page.arguments():
            description = item.value
            description = description.replace('\n', '')
            description, count = pattern_link.subn(r'\1', description)
            description, count = pattern_code.subn(r'`\1`', description)
            description, count = pattern_samp.subn(r'`\1`', description)
            doc.append(' '.join((item.name, ': ', description, ',')))
            doc.append('')
        return os.linesep.join(doc)
示例#2
0
    def __doc__(self):
        doc = [
            'Wrapper around an R function.', '',
            'The docstring below is built from the R documentation.', ''
        ]

        description = help.docstring(self.__rpackagename__,
                                     self.__rname__,
                                     sections=['\\description'])
        doc.append(description)

        fm = _formals_fixed(self)
        names = fm.do_slot('names')
        doc.append(self.__rname__ + '(')
        for key, val in self._prm_translate.items():
            if key == '___':
                description = ('(was "..."). R ellipsis '
                               '(any number of parameters)')
            else:
                description = _repr_argval(fm[names.index(val)])
            if description is None:
                doc.append('    %s,' % key)
            else:
                doc.append('    %s = %s,' % (key, description))
        doc.extend((')', ''))
        package = help.Package(self.__rpackagename__)
        page = package.fetch(self.__rname__)
        doc.append('Args:')
        for item in page.arguments():
            description = ('%s  ' % os.linesep).join(item.value)
            doc.append(' '.join(('  ', item.name, ': ', description)))
            doc.append('')

        doc.append(
            help.docstring(self.__rpackagename__,
                           self.__rname__,
                           sections=['\\details']))

        return os.linesep.join(doc)
示例#3
0
 def test_init(self):
     base_help = rh.Package('base')
     assert base_help.name == 'base'
示例#4
0
 def test_description(self):
     base_help = rh.Package('base')
     p = base_help.fetch('print')
     d = p.description()
     assert isinstance(d, str)
     assert len(d) > 0
示例#5
0
 def test_usage(self):
     base_help = rh.Package('base')
     p = base_help.fetch('print')
     d = p.usage()
     assert isinstance(d, str)
     assert len(d) > 0
示例#6
0
 def test_fetch(self):
     base_help = rh.Package('base')
     f = base_help.fetch('print')
     assert 'title' in f.sections.keys()
示例#7
0
 def test_to_docstring(self):
     base_help = rh.Package('base')
     p = base_help.fetch('print')
     ds = p.to_docstring()
     assert ds[:5] == 'title'
def __initialize_wrapper():
  global version, Fort

  import numpy
  import pandas
  import rpy2
  import rpy2.robjects as robjects
  import rpy2.robjects.help as rh
  import rpy2.robjects.numpy2ri as numpy2ri
  from rpy2.robjects.packages import importr
  import fnmatch
  import os
  import re
  from rpy2.robjects import pandas2ri

  #rpy2.robjects.activate()
  pandas2ri.activate()
  numpy2ri.activate()

  root_dir = os.path.dirname(os.path.realpath(__file__))

  __extRemes__ = importr("extRemes")
  __climextRemes__ = importr("climextRemes")
  __climextRemesHelp__ = rh.Package("climextRemes")

  __version__ = robjects.r('''
  packageVersion("climextRemes")
  ''')[0]

  __version__ = ".".join([str(f) for f in __version__])
  version = __version__

  Fort = pandas.DataFrame(robjects.r('''
  data(Fort)
  ord <- order(Fort$year, Fort$month, Fort$day) 
  Fort <- Fort[ord, ]
  '''))
  
  examples = {}
  examples_dir = "{0}/../examples".format(root_dir)
  for file in os.listdir(examples_dir):
    if fnmatch.fnmatch(file, '*_examples.py'):
        filename = examples_dir + "/" + file
        with open(filename, "r") as infile:
          key = file.replace("_examples.py", "")
          value = infile.read()
          examples[key] = value

  arguments_dir = "{0}/../python_help".format(root_dir)
  for file in os.listdir(arguments_dir):
    if fnmatch.fnmatch(file, '*_args.txt'):
        filename = arguments_dir + "/" + file
        with open(filename, "r") as infile:
          key = file.replace("_args.txt", "")
          value = infile.read()
          examples[key + "_arguments"] = value

  #print("examples", examples.keys())

  class climextRemesReturnObject(object):
    def __init__(self):
       pass
    def __repr__(self):
      return str(self.__dict__.keys())

  def __parseResult(obj):
    result = None

    if hasattr(obj, 'names') == False:
      return obj

    #print obj.names, rpy2.rinterface.NULL, type(obj), rpy2.rinterface.RNULLType

    if obj.names is rpy2.rinterface.NULL or \
       type(obj.names) is rpy2.rinterface.RNULLType or \
       (len(obj.names) == 1 and obj.names[0].replace(".","").isdigit()):
      if isinstance(obj, robjects.Vector) and len(obj) == 1:
        result = obj[0]
      else:
        result = robjects.conversion.ri2py(obj)
    elif isinstance(obj, robjects.Vector):
      result = climextRemesReturnObject()
      result.names = numpy.array(obj.names)
      for i in range(len(obj.names)):
        #print obj.names[i]
        result.__dict__[obj.names[i] + "_r"] = numpy.array(obj[i])
        result.__dict__[obj.names[i]] = __parseResult(obj[i])
  
    return result
 
  def __climextRemesWrapFunction(method_name, override_examples):

    names = []
    defaults = []
    signature = robjects.r('''
    library(climextRemes)
    as.list(args({0}))
    '''.format(method_name))

    def quote_args(text, arg_names):
        text = re.sub("( " + " | ".join(arg_names) + " )", "‘\\1’", text)
        text = text.replace("‘ ", "‘")
        text = text.replace(" ’", "’")
        return(text)
    
    for (i,name) in  enumerate(signature.names):
       if len(name) > 0:
         name = name.replace(".","_")
         names.append(name)
         try:
            d = signature[i][0]
            if isinstance(d, rpy2.robjects.robject.RObject):
               defaults.append(None)
            else:
               defaults.append(d)
         except:
            defaults.append(None)

    gdoc = __climextRemesHelp__.fetch(method_name)

    gdoc_help = gdoc.to_docstring(['title', 'description'])

    if method_name + "_arguments" in override_examples:
      new_arguments = override_examples[method_name + "_arguments"]
      arguments = new_arguments.split("@param ")
      new_arguments = "arguments\n"
      new_arguments += "---------\n"
      argument_names = []
      for arg in arguments[1:]:
        n_arg = arg.split(" ")
        argument_names.append(n_arg[0])
        n_arg[0] = n_arg[0] + ":"
        arg = " ".join(n_arg)
        new_arguments += arg + "\n"

      #new_arguments = new_arguments.replace("@param ", "")
      #gdoc_help += "arguments\n"
      #gdoc_help += "----------\n"
      #gdoc_help += new_arguments #.replace("\n", "\n\n")

      #gdoc_help.replace("\n\ndetails\n", "\n" + new_arguments + "\n\ndetails\n")
      gdoc_help += new_arguments
       
    else:
      gdoc_arguments = gdoc.to_docstring(["arguments"])
      res = gdoc_arguments.split("\n")
      output = ""
      argument_names = []
      for r in res:
        r2 = r.split()
        if len(r2) >= 2:
          argument_names.append(r2[0])
          r2[0] = r2[0] + ":"
          r2 = " ".join(r2)
          output += " " + r2 + "\n"
        else:
          output += r + "\n"
      gdoc_help += output + "\n\n"

    #method = getattr(__climextRemes__, method_name)
    #arglist = method.formals().names

    help_keys = list(gdoc.sections.keys())

    if "details" in help_keys:
        details = gdoc.to_docstring(["details"])
        details = quote_args(details, argument_names)
        gdoc_help += details
        help_keys.remove('details')
        
    if "value" in help_keys:
        value = gdoc.value()
        value = value.replace("\code{", "‘")
        value = value.replace("}", "’")    
        gdoc_help += "value\n-----\n\n" + value + "\n"
        help_keys.remove('value')
        
    if "usage" in help_keys: help_keys.remove('usage')  # this is the R usage so exclude
    if "alias" in help_keys: help_keys.remove('alias')  # this is the R alias so exclude
    if "arguments" in help_keys: help_keys.remove('arguments')  # handled separately
    if "examples" in help_keys: help_keys.remove('examples')  # handled separately
    if "name" in help_keys: help_keys.remove('name')  # this is redundant so exclude

    if "title" in help_keys: help_keys.remove('title')  # handled separately
    if "description" in help_keys: help_keys.remove('description')  # handled separately

    others = gdoc.to_docstring(help_keys)
    others = quote_args(others, argument_names)
    gdoc_help += others
    
    if method_name in override_examples:
        gdoc_help += "examples\n"
        gdoc_help += "--------\n"
        gdoc_help += ">>> " + override_examples[method_name].replace("\n", "\n... ")

        #index = gdoc_help.find("examples")
        #if index >= 0:
        #    gdoc_help = gdoc_help[0:index]
        #    if method_name in override_examples:
        #        gdoc_help += "examples\n"
        #        gdoc_help += "---------\n"
        #        gdoc_help += override_examples[method_name].replace("\n", "\n\n")
        
    # some cleanup
    gdoc_help = gdoc_help.replace("title\n-----", "\n", 1)  # 'title' is extraneous
    gdoc_help = gdoc_help.replace("\n \n", "\n\n")
    gdoc_help = gdoc_help.replace("---\n\n\n", "---\n")
    gdoc_help = gdoc_help.replace("\n\n\n", "\n\n")
    
    help_keys.extend(["arguments", "examples", "description", "details", "value"])
    for help in help_keys:  # Sphinx thinks repeated characters are section titles
       gdoc_help = gdoc_help.replace(help + "\n" + "-"*len(help), "**" + help  + "**\n")

    gdoc_help = gdoc_help.replace('TRUE', 'True')
    gdoc_help = gdoc_help.replace('FALSE', 'False')
    gdoc_help = gdoc_help.replace('NULL', 'None')

    def decorator(*args, **kwargs):
      #print kwargs, args
      new_args = []
      new_kwargs = {}
      for a in args:
        if isinstance(a, dict):
          new_args.append(rpy2.robjects.vectors.ListVector(a))
        else:
          if a is None:
              a = rpy2.rinterface.NULL
          new_args.append(a)
      
      for b in kwargs.keys():
          if isinstance(kwargs[b], dict):
              new_kwargs[b] = rpy2.robjects.vectors.ListVector(kwargs[b])
          else:
              if b is None:
                 b = rpy2.rinterface.NULL
              new_kwargs[b] = kwargs[b]
        
      method = getattr(__climextRemes__, method_name)
      retobj = method(*new_args, **new_kwargs)
      #return __parseResult(retobj)
      return compute_input_map(retobj)

    decorator.__doc__ = gdoc_help
    decorator.__name__ = method_name + "_"
    decorator.__names__ = names
    decorator.__defaults__ = tuple(defaults)

    argstr = ", ".join(names)
    fakefunc = "def %s(%s):\n    return %s(%s)\n" % (method_name, argstr, method_name + "_", argstr)
    fakefunc_code = compile(fakefunc, "fakesource", "exec")
    fakeglobals = {}
    eval(fakefunc_code, {method_name + "_": decorator}, fakeglobals)

    f_with_good_sig = fakeglobals[method_name]
    f_with_good_sig.__doc__ = gdoc_help
    f_with_good_sig.__name__ = method_name
    f_with_good_sig.__defaults__ = tuple(defaults)

    return f_with_good_sig

  for __i__ in __climextRemes__._exported_names:
    result = __climextRemesWrapFunction(__i__, examples)
    globals()[__i__] = result
示例#9
0
 def test_init(self):
     base_help = rh.Package('base')
     p = base_help.fetch('print')
     assert tuple(p.sections.keys())[0] == 'title'
示例#10
0
 def test_usage(self):
     base_help = rh.Package('base')
     p = base_help.fetch('print')
     d = p.usage()
     assert all(isinstance(x, str) for x in d)
     assert len(d) > 0
示例#11
0
 def testToDocstring(self):
     base_help = rh.Package('base')
     p = base_help.fetch('print')
     ds = p.to_docstring()
     self.assertEqual('title', ds[:5])
示例#12
0
 def testInit(self):
     base_help = rh.Package('base')
     self.assertEqual('NULL', base_help.object2alias['NULL'])
示例#13
0
def importr(packname, newname=None, verbose=False):
    """ Wrapper around rpy2.robjects.packages.importr, 
    adding the following features:
    
    - package instance added to the pseudo-module 'packages'

    - automatic pydoc generation from the R help pages

    """

    assert isinstance(packname, str)
    packinstance = _importr(packname, on_conflict='warn')

    # fix the package name (dots possible in R package names)
    if newname is None:
        newname = packname.replace('.', '_')

    Packages().__dict__[newname] = packinstance

    ## Currently too slow for a serious usage: R's introspection
    ## of S4 classes is not fast enough
    # d = {}
    # for cn in methods.get_classnames(packname):
    #     class AutoS4(RS4):
    #         __metaclass__ = methods.RS4Auto_Type
    #         __rpackagename__ = packname
    #         __rname__ = cn
    #     newcn = cn.replace('.', '_')
    #     d[newcn] = AutoS4
    # S4Classes().__dict__[newname] = d

    p_latex_code = re.compile('\\\\code{([^}]+)}')
    p_latex_link = re.compile('\\\\link{([^}]+)}')
    p_latex_any_curly = re.compile('\\\\[^ ]+{([^}]+)}')
    p_latex_any = re.compile('\\\\([^ ]+)')
    p_latex_usage = re.compile(
        '\\\\method{(?P<method>[^}]+)}{(?P<class>[^}]+)}(?P<signature>.+)')

    doc = rhelp.Package(packname)
    for obj_name in packinstance.__dict__:
        obj = packinstance.__dict__[obj_name]
        # ignore class-defined attributes to only consider
        # the ones defined dynamically
        if hasattr(type(packinstance), obj_name):
            continue
        try:
            p = doc.fetch(obj.__rname__)
        except rhelp.HelpNotFoundError as hnfe:
            # No R documentation could be found for the object
            if verbose:
                print('Pydoc generator: no help for "%s"' % (obj_name, ))
            continue
        except AttributeError as ae:
            # No __rname__ for the object
            print('Pydoc generator: oddity with "%s"' % (obj_name, ))
            continue
        except:
            print('Pydoc generator: oddity with "%s" ("%s")' %
                  (obj_name, obj.__rname__))
            continue

        if obj_name in packinstance._exported_names:
            exported = True
        else:
            exported = False
            #if verbose:
            #    print('Pydoc generator: "%s" not exported' %(obj_name, ))
            #continue

        docstring = [
            p.title(),
            '[ %s - %s exported ]' % (p._type, 'not' if not exported else ''),
            '** Experimental dynamic conversion of the associated R documentation **'
        ]

        tmp = p.description()
        tmp = re.sub(p_latex_any_curly, "'\\1'", tmp)
        docstring.append(tmp)
        docstring.append('')

        tmp_usage = p.usage().split(linesep)
        for i, row in enumerate(tmp_usage):
            tmp_m = p_latex_usage.match(row)
            if tmp_m is not None:
                tmp_usage[i] = '%s_%s%s' % (tmp_m.group('method'),
                                            tmp_m.group('class'),
                                            tmp_m.group('signature'))
        tmp_usage = linesep.join(tmp_usage)
        docstring.extend([tmp_usage, ''])

        if obj_name not in packinstance._exported_names:
            tmp = p.seealso()
            tmp = re.sub(p_latex_code, "'\\1'", tmp)
            tmp = re.sub(p_latex_any_curly, '\\1', tmp)
            tmp = re.sub(p_latex_any, "'\\1'", tmp)
            docstring.extend(['', 'See Also:', tmp])
            docstring = linesep.join(docstring)
            obj.__doc__ = docstring
            continue

        try:
            arguments = p.arguments()
        except KeyError as ke:
            #FIXME: no arguments - should the handling differ a bit ?
            arguments = tuple()
        # Assume uniqueness of values in the dict. This is making sense since
        # parameters to the function should have unique names ans... this appears to be enforced
        # by R when declaring a function

        arguments = OrderedDict(arguments)

        if hasattr(obj, '_prm_translate'):
            docstring.extend(['', 'Parameters:', ''])
            for k, v in obj._prm_translate.items():
                try:
                    tmp = arguments[v]
                    tmp = re.sub(p_latex_code, "'\\1'", tmp)
                    tmp = re.sub(p_latex_any_curly, '\\1', tmp)
                    tmp = re.sub(p_latex_any, "'\\1'", tmp)
                    docstring.append('%s -- %s' % (k, tmp))
                except KeyError:
                    # This is an inconsistency in the R documentation
                    # (the parameter in the function's signature does
                    # not have an entry in the R documentation).
                    # Do nothing.
                    #
                    if verbose:
                        print(
                            'Pydoc generator: no help for parameter "%s" in %s'
                            % (k, obj_name))
                    docstring.append(
                        '%s -- [error fetching the documentation]' % (k))
                    #print('Pydoc generator: oddity with R\'s "%s" over the parameter "%s"' %(obj_name, v))

        tmp = p.value()
        tmp = re.sub(p_latex_code, "'\\1'", tmp)
        tmp = re.sub(p_latex_any, '\\1', tmp)

        docstring.extend(['', 'Returns:', tmp])
        tmp = p.seealso()
        tmp = re.sub(p_latex_code, "'\\1'", tmp)
        tmp = re.sub(p_latex_any_curly, '\\1', tmp)
        tmp = re.sub(p_latex_any, "'\\1'", tmp)
        docstring.extend(['', 'See Also:', tmp])
        docstring = linesep.join(docstring)
        obj.__doc__ = docstring
    return packinstance
示例#14
0
 def testToDocstring(self):
     base_help = rh.Package('base')
     p = base_help.fetch('RdUtils')
     ds = p.to_docstring()
     self.assertEqual('title', ds[0])
     self.assertEqual('-----', ds[2])
示例#15
0
 def testInit(self):
     base_help = rh.Package('base')
     p = base_help.fetch('RdUtils')
     self.assertEqual('title', p.sections.keys()[0])
示例#16
0
 def testFetch(self):
     base_help = rh.Package('base')
     f = base_help.fetch('RdUtils')
     self.assertTrue('title' in f.sections.keys())
示例#17
0
    def __new__(mcs, name, bases, cls_dict):
        try:
            cls_rname = cls_dict['__rname__']
        except KeyError as ke:
            cls_rname = name

        try:
            cls_rpackagename = cls_dict['__rpackagename__']
        except KeyError as ke:
            cls_rpackagename = None

        try:
            cls_attr_translation = cls_dict['__attr_translation__']
        except KeyError as ke:
            cls_attr_translation = {}
        try:
            cls_meth_translation = cls_dict['__meth_translation__']
        except KeyError as ke:
            cls_meth_translation = {}

        cls_def = getclassdef(cls_rname, cls_rpackagename)
    
        # documentation / help
        if cls_rpackagename is None:
            cls_dict['__doc__'] = "Undocumented class from the R workspace."
        else:
            pack_help = rhelp.Package(cls_rpackagename)
            page_help = None
            try:
                #R's classes are sometimes documented with a prefix 'class.'
                page_help = pack_help.fetch(cls_def.__rname__ + "-class")
            except rhelp.HelpNotFoundError as hnf:
                pass
            if page_help is None:
                try:
                    page_help = pack_help.fetch(cls_def.__rname__)
                except rhelp.HelpNotFoundError as hnf:
                    pass
            if page_help is None:
                cls_dict['__doc__'] = 'Unable to fetch R documentation for the class'
            else:
                cls_dict['__doc__'] = ''.join(page_help.to_docstring())
        
        for slt_name in cls_def.slots:
            #FIXME: sanity check on the slot name
            try:
                slt_name = cls_attr_translation[slt_name]
            except KeyError as ke:
                # no translation: abort
                pass

            #FIXME: isolate the slot documentation and have it here
            cls_dict[slt_name] = property(lambda self: self.do_slot(slt_name),
                                          None, None,
                                          None)

        # Now tackle the methods
        all_generics = methods_env['getGenerics']()
        findmethods = methods_env['findMethods']

        # does not seem elegant, but there is probably nothing else to do
        # than loop across all generics
        r_cls_rname = StrSexpVector((cls_rname, ))
        for funcname in all_generics:
            all_methods = findmethods(StrSexpVector((funcname, )), 
                                      classes = r_cls_rname)

            # skip if no methods (issue #301). R's findMethods() result
            # does not have an attribute "names" if of length zero.
            if len(all_methods) == 0:
                continue
            # all_methods contains all method/signature pairs
            # having the class we are considering somewhere in the signature
            # (the R/S4 systems allows multiple dispatch)
            for name, meth in zip(all_methods.do_slot("names"), all_methods):
                # R/S4 is storing each method/signature as a string, 
                # with the argument type separated by the character '#'
                # We will re-use that name for the Python name
                # (no multiple dispatch in python, the method name
                # will not be enough), replacing the '#'s with '__'s.
                signature = name.split("#")
                meth_name = '__'.join(signature)
                # function names ending with '<-' indicate that the function
                # is a setter of some sort. We reflect that by adding a 'set_'
                # prefix to the Python name (and of course remove the suffix '<-').
                if funcname.endswith('<-'):
                    meth_name = 'set_' + funcname[:-2] + '__' + meth_name
                else:
                    meth_name = funcname + '__' + meth_name
                # finally replace remaining '.'s in the Python name with '_'s
                meth_name = meth_name.replace('.', '_')
                
            #FIXME: sanity check on the function name
                try:
                    meth_name = cls_meth_translation[meth_name]
                except KeyError as ke:
                    # no translation: abort
                    pass

            #FIXME: isolate the slot documentation and have it here
                
                if meth_name in cls_dict:
                    raise Error("Duplicated attribute/method name.")
                cls_dict[meth_name] = meth

        return type.__new__(mcs, name, bases, cls_dict)
示例#18
0
 def test_repr(self):
     base_help = rh.Package('base')
     assert isinstance(repr(base_help), str)
示例#19
0
 def testInit(self):
     base_help = rh.Package('base')
     p = base_help.fetch('print')
     self.assertEqual('title', tuple(p.sections.keys())[0])
示例#20
0
 def testInit(self):
     base_help = rh.Package('base')
     self.assertEqual('base', base_help.name)