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)
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)
def test_init(self): base_help = rh.Package('base') assert base_help.name == 'base'
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
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
def test_fetch(self): base_help = rh.Package('base') f = base_help.fetch('print') assert 'title' in f.sections.keys()
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
def test_init(self): base_help = rh.Package('base') p = base_help.fetch('print') assert tuple(p.sections.keys())[0] == 'title'
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
def testToDocstring(self): base_help = rh.Package('base') p = base_help.fetch('print') ds = p.to_docstring() self.assertEqual('title', ds[:5])
def testInit(self): base_help = rh.Package('base') self.assertEqual('NULL', base_help.object2alias['NULL'])
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
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])
def testInit(self): base_help = rh.Package('base') p = base_help.fetch('RdUtils') self.assertEqual('title', p.sections.keys()[0])
def testFetch(self): base_help = rh.Package('base') f = base_help.fetch('RdUtils') self.assertTrue('title' in f.sections.keys())
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)
def test_repr(self): base_help = rh.Package('base') assert isinstance(repr(base_help), str)
def testInit(self): base_help = rh.Package('base') p = base_help.fetch('print') self.assertEqual('title', tuple(p.sections.keys())[0])
def testInit(self): base_help = rh.Package('base') self.assertEqual('base', base_help.name)