"""
.. module:: climextRemes
:platform: Unix, Mac, Windows
:synopsis: Python wrapper for the climextRemes package.
.. moduleauthor:: Christopher Paciorek <paciorek@berkeley.edu>
"""
version = ""
Fort = None
# As of rpy2 >= 3.0.0, use of NULLType rather than RNULLType
import rpy2.rinterface
if hasattr(rpy2.rinterface, 'NULLType'):
NULLType = rpy2.rinterface.NULLType # rpy2 >= 3.0.0
else:
NULLType = rpy2.rinterface.RNULLType # rpy2 < 3.0.0
"""
def compute_input_map(input_arg_map):
import rpy2
input_map = None
if isinstance(input_arg_map, rpy2.rinterface.RNULLType):
input_map = None
elif isinstance(input_arg_map, rpy2.robjects.vectors.ListVector):
input_map = []
try:
for (i,name) in enumerate(input_arg_map.names):
try:
value = input_arg_map[i]
#print i, name, type(value), isinstance(value, rpy2.robjects.vectors.Vector)
if isinstance(value, rpy2.robjects.vectors.ListVector):
input_map.append( (name, compute_input_map(value)) )
elif isinstance(value, rpy2.robjects.vectors.Vector):
input_map.append((name,value[0]))
elif isinstance(value, rpy2.rinterface.RNULLType):
input_map.append((name,None))
else:
input_map.append((name,None))
except:
input_map.append((name,None))
except:
print "unable to parse", str(input_arg_map)
elif isinstance(input_arg_map, rpy2.robjects.vectors.Vector):
input_map = []
for v in input_arg_map:
result = compute_input_map(v)
input_map.append(result)
elif isinstance(input_arg_map, rpy2.robjects.RObject):
input_map = input_arg_map # TODO handle this case..
else: # what else is there?
input_map = input_arg_map
return input_map
"""
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 NULLType 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)
# As of 0.2.1 changed from curly to straight quote to avoid this error in Py 2.7:
# SyntaxError: Non-ASCII character '\xe2' in file /accounts/gen/vis/paciorek/R/x86_64-pc-linux-gnu-library/3.5/climextRemes/python/climextRemes_wrapper.py on line 317, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
# This is causing extra spaces because can't tell left vs right single quote, so remove until we go back to curly quotes.
# 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) or isinstance(d, rpy2.rinterface.SexpSymbol):
defaults.append(None)
else:
defaults.append(d)
except:
defaults.append(None)
gdoc = __climextRemesHelp__.fetch(method_name)
## As of rpy2 >= 3.4.0 need \\ in key names
use_backslash = True if '\\title' in gdoc.sections.keys() else False
key_names = ['title', 'description']
if use_backslash:
key_names = ['\\' + nm for nm in key_names]
gdoc_help = gdoc.to_docstring(key_names)
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:
key_name = '\\arguments' if use_backslash else 'arguments'
gdoc_arguments = gdoc.to_docstring([key_name])
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())
key_name = '\\details' if use_backslash else 'details'
if key_name in help_keys:
details = gdoc.to_docstring([key_name])
details = quote_args(details, argument_names)
gdoc_help += details
help_keys.remove(key_name)
key_name = '\\value' if use_backslash else 'value'
if key_name in help_keys:
value = gdoc.value()
if use_backslash: # value needs to be handled differently as of rpy2 >= 3.4.0
value = ' '.join(["\n\n" if v == "\n" else v.strip() for v in value[1:]])
value = "\n" + value.strip() + "\n"
else:
value = value.replace("\code{", "'")
value = value.replace("}", "'")
gdoc_help += "value\n-----\n\n" + value + "\n"
help_keys.remove(key_name)
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
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 = [hk.replace("\\", "") for hk in help_keys]
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)
#with conversion.localconverter(myconverter):
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
__initialize_wrapper()
def __set_converter():
## Don't do this within __initialize_wrapper() or get recursion error
## From https://stackoverflow.com/questions/54951506/is-there-a-way-to-return-names-from-r-vectors-matrices-etc-in-rpy2-3-0-0/54954583#54954583
from rpy2 import robjects
myconverter = robjects.conversion.Converter('asymmetric numpy',
template=robjects.numpy2ri.converter)
myconverter.rpy2py.register(rpy2.rinterface_lib.sexp.Sexp,
robjects.default_converter.rpy2py)
## As of rpy2 3.3.0, need to have _map element that looks like:
## {<class 'rpy2.rinterface.SexpS4'>: <rpy2.robjects.conversion.NameClassMap object at 0x7efbfc6e5f10>,
## <class 'rpy2.rinterface.ListSexpVector'>: <rpy2.robjects.conversion.NameClassMap object at 0x7efbfc6e5f50>,
## <class 'rpy2.rinterface_lib.sexp.SexpEnvironment'>: <rpy2.robjects.conversion.NameClassMap object at 0x7efbfc6e5f90>}
## As of rpy2 3.5.0, robjects.default_converter._rpy2py_nc_map is a dict with the converters
## whereas formerly robjects.default_converter._rpy2py_nc_map._map was the dict with the converters,
## so now need that myconverter._rpy2py_nc_map has the full set of elements in
## robjects.default_converter._rpy2py_nc_map.
if hasattr(robjects.conversion.converter,'rpy2py_nc_name'):
if isinstance(robjects.default_converter._rpy2py_nc_map, dict): # >= 3.5.0
myconverter._rpy2py_nc_map.update(robjects.default_converter._rpy2py_nc_map.copy())
else:
myconverter._rpy2py_nc_map.update(robjects.default_converter._rpy2py_nc_map._map.copy(),
default=robjects.default_converter._rpy2py_nc_map._default)
robjects.conversion.set_conversion(myconverter)
if int(rpy2.__version__.split('.')[0]) >= 3:
__set_converter()