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") |