Mercurial > repos > petr-novak > repeatrxplorer
comparison lib/r2py.py @ 0:1d1b9e1b2e2f draft
Uploaded
| author | petr-novak |
|---|---|
| date | Thu, 19 Dec 2019 10:24:45 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:1d1b9e1b2e2f |
|---|---|
| 1 #!/usr/bin/env python3 | |
| 2 import os | |
| 3 import atexit | |
| 4 import socket | |
| 5 import time | |
| 6 import config | |
| 7 import pyRserve | |
| 8 | |
| 9 def shutdown(port): | |
| 10 try: | |
| 11 conn = pyRserve.connect(port=port) | |
| 12 print("Shutting down Rserv...", end="") | |
| 13 conn.shutdown() | |
| 14 print("Done") | |
| 15 except pyRserve.rexceptions.RConnectionRefused: | |
| 16 print("connection to Rserve refused, server is probably already down") | |
| 17 | |
| 18 def get_open_port(): | |
| 19 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
| 20 s.bind(("", 0)) | |
| 21 s.listen(1) | |
| 22 port = s.getsockname()[1] | |
| 23 s.close() | |
| 24 return port | |
| 25 | |
| 26 # find free port | |
| 27 def create_connection(): | |
| 28 '''Start R Rserver and test connection, port is | |
| 29 stored in config.RSERVE_PORT | |
| 30 ''' | |
| 31 config.RSERVE_PORT = get_open_port() | |
| 32 print('Trying to start Rserve...',) | |
| 33 os.system( | |
| 34 "R CMD Rserve --RS-port {} -q --no-save ".format(config.RSERVE_PORT)) | |
| 35 # wait for server to start accepting connections | |
| 36 time.sleep(1) | |
| 37 try: | |
| 38 conn = pyRserve.connect(port=config.RSERVE_PORT) | |
| 39 print("connection OK") | |
| 40 conn.close() | |
| 41 atexit.register(shutdown, config.RSERVE_PORT) | |
| 42 return config.RSERVE_PORT | |
| 43 except: | |
| 44 print("Connection with Rserve was not established!") | |
| 45 raise | |
| 46 | |
| 47 | |
| 48 class setFunctionName(): | |
| 49 # decorator | |
| 50 | |
| 51 def __init__(self, f, name): | |
| 52 self.f = f | |
| 53 self.name = name | |
| 54 | |
| 55 def __call__(self, *args, **kwargs): | |
| 56 return self.f(self.name, *args, **kwargs) | |
| 57 | |
| 58 | |
| 59 def convert_types(fn): | |
| 60 ''' decorator function to convert type for r2py''' | |
| 61 allowed_classes = [str, int, float, list, bool, type(None)] | |
| 62 # everything else is converted to str | |
| 63 | |
| 64 def fn_wrapper(*args, **kwargs): | |
| 65 new_args = list(args) | |
| 66 new_kwargs = kwargs | |
| 67 for i, value in enumerate(args): | |
| 68 if any(type(value) is i for i in allowed_classes): | |
| 69 new_args[i] = value | |
| 70 else: | |
| 71 new_args[i] = str(value) | |
| 72 for i, value in kwargs.items(): | |
| 73 if any(type(value) is i for i in allowed_classes): | |
| 74 new_kwargs[i] = value | |
| 75 else: | |
| 76 new_kwargs[i] = str(value) | |
| 77 return fn(*new_args, **new_kwargs) | |
| 78 | |
| 79 return fn_wrapper | |
| 80 | |
| 81 | |
| 82 class R(): | |
| 83 | |
| 84 def __init__(self, source, verbose=False): | |
| 85 ''' Code in file should defined R functions which will be linked to python function | |
| 86 purpose of this is to make it memory efficient - rserve connection will be closed | |
| 87 after every exetion so memory is released. | |
| 88 warning - Source code is executed each time function is used so it should only | |
| 89 contain function definition!! | |
| 90 | |
| 91 ''' | |
| 92 self.source = os.path.realpath(source) | |
| 93 conn = pyRserve.connect(port=config.RSERVE_PORT) | |
| 94 conn.voidEval("source('{}', chdir=TRUE)".format(self.source)) | |
| 95 # if single object is define then fn return str! conversion neccessary | |
| 96 object_names = list(conn.r.ls()) | |
| 97 if verbose: | |
| 98 print("R function loaded:", end=" ") | |
| 99 for i in object_names: | |
| 100 ## skip these objects - not compatible with older version of rserve | |
| 101 ## and not needed to be accessed from python | |
| 102 if i in ['DT_OPTIONS', 'HTMLHEADER', 'WD', 'options', | |
| 103 'htmlheader', 'options', 'xcolor_code', 'TANDEM_RANKS', 'RANKS_TANDEM',]: | |
| 104 continue | |
| 105 try: | |
| 106 obj = getattr(conn.r, i) | |
| 107 if isinstance(obj, pyRserve.rconn.RFuncProxy): | |
| 108 if verbose: | |
| 109 print(i, end=" ") | |
| 110 @convert_types | |
| 111 def rwrapper(fname, *args, **kwargs): | |
| 112 c = pyRserve.connect(port=config.RSERVE_PORT) | |
| 113 c.r.setwd(os.getcwd()) | |
| 114 c.voidEval("source('{}',chdir=TRUE)".format(self.source)) | |
| 115 fn = getattr(c.r, fname) | |
| 116 out = fn(*args, **kwargs) | |
| 117 c.close() | |
| 118 return out | |
| 119 rwrapper = setFunctionName(rwrapper, i) | |
| 120 setattr(self, i, rwrapper) | |
| 121 del(rwrapper) | |
| 122 except: | |
| 123 print("skipping :", i) | |
| 124 pass | |
| 125 if verbose: | |
| 126 print("\r") |
