1from __future__ import unicode_literals, absolute_import
2from rchitect._cffi import lib
3
4import operator
5import sys
6import importlib
7from six import text_type
8from types import ModuleType
9
10from .interface import rcopy, robject, rfunction, rcall_p, rcall
11
12
13def get_p(name, envir):
14    return rcall_p(("base", "get"), name, envir=envir)
15
16
17def inject_py_tools():
18
19    def py_import(module):
20        return importlib.import_module(module)
21
22    def py_import_builtins():
23        if sys.version >= "3":
24            return importlib.import_module("builtins")
25        else:
26            return importlib.import_module("__builtin__")
27
28    def py_call(fun, *args, **kwargs):
29        # todo: suuport .asis and .convert
30        if isinstance(fun, text_type):
31            fun = eval(fun)
32        return fun(*args, **kwargs)
33
34    def py_copy(*args):
35        return robject(*args)
36
37    def py_eval(code):
38        return eval(code)
39
40    def py_get_attr(obj, key):
41        if isinstance(obj, ModuleType):
42            try:
43                return importlib.import_module("{}.{}".format(obj.__name__, key))
44            except ImportError:
45                pass
46        return getattr(obj, key)
47
48    def py_get_item(obj, key):
49        return obj[key]
50
51    def py_names(obj):
52        try:
53            return list(k for k in obj.__dict__.keys() if not k.startswith("_"))
54        except Exception:
55            return None
56
57    def py_object(*args):
58        if len(args) == 1:
59            return robject("PyObject", rcopy(args[0]))
60        elif len(args) == 2:
61            return robject("PyObject", rcopy(rcopy(object, args[0]), args[1]))
62
63    def py_print(r):
64        rcall_p("cat", repr(r) + "\n")
65
66    def py_set_attr(obj, key, value):
67        lib.Rf_protect(obj)
68        lib.Rf_protect(key)
69        lib.Rf_protect(value)
70        pyo = rcopy(object, obj)
71        try:
72            setattr(pyo, rcopy(key), rcopy(value))
73        finally:
74            lib.Rf_unprotect(3)
75        return pyo
76
77    def py_set_item(obj, key, value):
78        lib.Rf_protect(obj)
79        lib.Rf_protect(key)
80        lib.Rf_protect(value)
81        pyo = rcopy(object, obj)
82        try:
83            pyo[rcopy(key)] = rcopy(value)
84        finally:
85            lib.Rf_unprotect(3)
86        return pyo
87
88    def py_dict(**kwargs):
89        narg = len(kwargs)
90        for key in kwargs:
91            lib.Rf_protect(kwargs[key])
92        try:
93            return {key: rcopy(kwargs[key]) for key in kwargs}
94        finally:
95            lib.Rf_unprotect(narg)
96
97    def py_tuple(*args):
98        narg = len(args)
99        for a in args:
100            lib.Rf_protect(a)
101        try:
102            return tuple([rcopy(a) for a in args])
103        finally:
104            lib.Rf_unprotect(narg)
105
106    def py_unicode(obj):
107        return text_type(obj)
108
109    def assign(name, value, envir):
110        rcall(("base", "assign"), name, value, envir=envir)
111
112    e = rcall(("base", "new.env"), parent=lib.R_GlobalEnv)
113    kwarg = {"rchitect.py_tools": e}
114    rcall(("base", "options"), **kwarg)
115
116    assign("import", rfunction(py_import, convert=False), e)
117    assign("import_builtins", rfunction(py_import_builtins, convert=False), e)
118    assign("py_call", rfunction(py_call, convert=False), e)
119    assign("py_copy", rfunction(py_copy, convert=True), e)
120    assign("py_eval", rfunction(py_eval, convert=False), e)
121    assign("py_get_attr", rfunction(py_get_attr, convert=False), e)
122    assign("py_get_item", rfunction(py_get_item, convert=False), e)
123    assign("py_object", rfunction(py_object, asis=True, convert=False), e)
124    assign("py_set_attr", rfunction(py_set_attr, invisible=True, asis=True, convert=False), e)
125    assign("py_set_item", rfunction(py_set_item, invisible=True, asis=True, convert=False), e)
126    assign("py_unicode", rfunction(py_unicode, convert=False), e)
127    assign("dict", rfunction(py_dict, asis=True, convert=False), e)
128    assign("tuple", rfunction(py_tuple, asis=True, convert=False), e)
129
130    assign("names.PyObject", rfunction(py_names, convert=True), e)
131    assign("print.PyObject", rfunction(py_print, invisible=True, convert=False), e)
132    assign(".DollarNames.PyObject", rfunction(py_names, convert=True), e)
133    assign("$.PyObject", rfunction(py_get_attr, convert=True), e)
134    assign("[.PyObject", rfunction(py_get_item, convert=True), e)
135    assign("$<-.PyObject", rfunction(py_set_attr, invisible=True, asis=True, convert=False), e)
136    assign("[<-.PyObject", rfunction(py_set_item, invisible=True, asis=True, convert=False), e)
137    assign("&.PyObject", rfunction(operator.and_, invisible=True, convert=False), e)
138    assign("|.PyObject", rfunction(operator.or_, invisible=True, convert=False), e)
139    assign("!.PyObject", rfunction(operator.not_, invisible=True, convert=False), e)
140
141    def attach():
142        parent_frame = rcall("sys.frame", -1)
143        things = [
144            "import",
145            "import_builtins",
146            "py_call",
147            "py_copy",
148            "py_eval",
149            "py_get_attr",
150            "py_get_item",
151            "py_object",
152            "py_set_attr",
153            "py_set_item",
154            "py_unicode",
155            "dict",
156            "tuple",
157            "names.PyObject",
158            "print.PyObject",
159            ".DollarNames.PyObject",
160            "$.PyObject",
161            "[.PyObject",
162            "$<-.PyObject",
163            "[<-.PyObject",
164            "&.PyObject",
165            "|.PyObject",
166            "!.PyObject"
167        ]
168        for thing in things:
169            assign(thing, get_p(thing, e), parent_frame)
170
171    assign("attach", robject(attach, invisible=True), e)
172