source: framspy/frams.py @ 1081

Last change on this file since 1081 was 1081, checked in by Maciej Komosinski, 3 years ago

Cosmetic

File size: 8.6 KB
RevLine 
[1078]1"""Framsticks as a Python module.
2
3Static FramScript objects are available inside the module under their well known names
4(frams.Simulator, frams.GenePools, etc.)
5
6These objects and all values passed to and from Framsticks are instances of frams.ExtValue.
7Python values are automatically converted to Framstics data types.
8Use frams.ExtValue._makeInt()/_makeDouble()/_makeString()/_makeNull() for explicit conversions.
9Simple values returned from Framsticks can be converted to their natural Python
10counterparts using _value() (or forced to a specific type with  _int()/_double()/_string()).
11
12All non-Framsticks Python attributes start with '_' to avoid conflicts with Framsticks attributes.
13Framsticks names that are Python reserved words are prefixed with 'x' (currently just Simulator.ximport).
14"""
15
16import ctypes, re, sys, os
17
18c_api = None  # will be initialized in init(). Global because ExtValue uses it.
19
20
21class ExtValue(object):
[1081]22        """All Framsticks objects and values are instances of this class."""
23
[1078]24        _reInsideParens = re.compile('\((.*)\)')
25        _reservedWords = ['import']  # this list is scanned during every attribute access, only add what is really clashing with framsticks properties
26        _reservedXWords = ['x' + word for word in _reservedWords]
27        _encoding = 'utf-8'
28
29
30        def __init__(self, arg=None, dontinit=False):
31                if dontinit:
32                        return
33                if isinstance(arg, int):
34                        self._initFromInt(arg)
35                elif isinstance(arg, str):
36                        self._initFromString(arg)
37                elif isinstance(arg, float):
38                        self._initFromDouble(arg)
39                elif arg == None:
40                        self._initFromNull()
41                else:
42                        raise ArgumentError("Can't make ExtValue from '" + str(arg) + "'")
43
44
45        def __del__(self):
46                c_api.extFree(self.__ptr)
47
48
49        def _initFromNull(self):
50                self.__ptr = c_api.extFromNull()
51
52
53        def _initFromInt(self, v):
54                self.__ptr = c_api.extFromInt(v)
55
56
57        def _initFromDouble(self, v):
58                self.__ptr = c_api.extFromDouble(v)
59
60
61        def _initFromString(self, v):
62                self.__ptr = c_api.extFromString(ExtValue._cstringFromPython(v))
63
64
65        @classmethod
66        def _makeNull(cls, v):
67                e = ExtValue(None, True)
68                e._initFromNull()
69                return e
70
71
72        @classmethod
73        def _makeInt(cls, v):
74                e = ExtValue(None, True)
75                e._initFromInt(v)
76                return e
77
78
79        @classmethod
80        def _makeDouble(cls, v):
81                e = ExtValue(None, True)
82                e._initFromDouble(v)
83                return e
84
85
86        @classmethod
87        def _makeString(cls, v):
88                e = ExtValue(None, True)
89                e._initFromString(v)
90                return e
91
92
93        @classmethod
94        def _rootObject(cls):
95                e = ExtValue(None, True)
96                e.__ptr = c_api.rootObject()
97                return e
98
99
100        @classmethod
101        def _stringFromC(cls, cptr):
102                return cptr.decode(ExtValue._encoding)
103
104
105        @classmethod
106        def _cstringFromPython(cls, s):
107                return ctypes.c_char_p(s.encode(ExtValue._encoding))
108
109
110        def _type(self):
111                return c_api.extType(self.__ptr)
112
113
114        def _class(self):
115                cls = c_api.extClass(self.__ptr)
116                if cls == None:
117                        return None
118                else:
119                        return ExtValue._stringFromC(cls)
120
121
122        def _value(self):
123                t = self._type()
124                if t == 0:
125                        return None
126                elif t == 1:
127                        return self._int()
128                elif t == 2:
129                        return self._double()
130                elif t == 3:
131                        return self._string()
132                else:
133                        return self
134
135
136        def _int(self):
137                return c_api.extIntValue(self.__ptr)
138
139
140        def _double(self):
141                return c_api.extDoubleValue(self.__ptr)
142
143
144        def _string(self):
145                return ExtValue._stringFromC(c_api.extStringValue(self.__ptr))
146
147
148        def __str__(self):
149                return self._string()
150
151
152        def __dir__(self):
153                ids = dir(type(self))
154                if self._type() == 4:
155                        for i in range(c_api.extPropCount(self.__ptr)):
156                                name = ExtValue._stringFromC(c_api.extPropId(self.__ptr, i))
157                                if name in ExtValue._reservedWords:
158                                        name = 'x' + name
159                                ids.append(name)
160                return ids
161
162
163        def __getattr__(self, key):
164                if key[0] == '_':
165                        return self.__dict__[key]
166                if key in ExtValue._reservedXWords:
167                        key = key[1:]
168                prop_i = c_api.extPropFind(self.__ptr, ExtValue._cstringFromPython(key))
169                if prop_i < 0:
170                        raise AttributeError('no ' + str(key) + ' in ' + str(self))
171                t = ExtValue._stringFromC(c_api.extPropType(self.__ptr, prop_i))
172                if t[0] == 'p':
173                        arg_types = ExtValue._reInsideParens.search(t)
174                        if arg_types:
175                                arg_types = arg_types.group(1).split(',')  # anyone wants to add argument type validation using param type declarations?
176
177
178                        def fun(*args):
179                                ext_args = []
180                                ext_pointers = []
181                                for a in args:
182                                        if isinstance(a, ExtValue):
183                                                ext = a
184                                        else:
185                                                ext = ExtValue(a)
186                                        ext_args.append(ext)
187                                        ext_pointers.append(ext.__ptr)
188                                ret = ExtValue(None, True)
189                                args_array = (ctypes.c_void_p * len(args))(*ext_pointers)
190                                ret.__ptr = c_api.extPropCall(self.__ptr, prop_i, len(args), args_array)
191                                return ret
192
193
194                        return fun
195                else:
196                        ret = ExtValue(None, True)
197                        ret.__ptr = c_api.extPropGet(self.__ptr, prop_i)
198                        return ret
199
200
201        def __setattr__(self, key, value):
202                if key[0] == '_':
203                        self.__dict__[key] = value
204                else:
205                        if key in ExtValue._reservedXWords:
206                                key = key[1:]
207                        prop_i = c_api.extPropFind(self.__ptr, ExtValue._cstringFromPython(key))
208                        if prop_i < 0:
209                                raise AttributeError("No '" + str(key) + "' in '" + str(self) + "'")
210                        if not isinstance(value, ExtValue):
211                                value = ExtValue(value)
212                        c_api.extPropSet(self.__ptr, prop_i, value.__ptr)
213
214
215        def __getitem__(self, key):
216                return self.get(key)
217
218
219        def __setitem__(self, key, value):
220                return self.set(key, value)
221
222
223        def __len__(self):
224                try:
225                        return self.size._int()
226                except:
227                        return 0
228
229
230        def __iter__(self):
231                class It(object):
232                        def __init__(self, container, frams_it):
233                                self.container = container
234                                self.frams_it = frams_it
235
236
237                        def __iter__(self):
238                                return self
239
240
241                        def __next__(self):
242                                if self.frams_it.next._int() != 0:
243                                        return self.frams_it.value
244                                else:
245                                        raise StopIteration()
246
247                return It(self, self.iterator)
248
249
[1081]250def init(lib_path, *args):
[1078]251        original_dir = os.getcwd()
[1081]252        os.chdir(lib_path)  # because under Windows, frams.dll requires other dll's which reside in the same directory, so we must change current dir for them to be found while loading the main dll
253        global c_api  # access global variable
254        c_api = ctypes.CDLL('frams-objects.so' if os.name == 'posix' else 'frams-objects.dll')
[1078]255        os.chdir(original_dir)
256
257        c_api.init.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_char_p)]
258        c_api.init.restype = None
259        c_api.extFree.argtypes = [ctypes.c_void_p]
260        c_api.extFree.restype = None
261        c_api.extType.argtypes = [ctypes.c_void_p]
262        c_api.extType.restype = ctypes.c_int
263        c_api.extFromNull.argtypes = []
264        c_api.extFromNull.restype = ctypes.c_void_p
265        c_api.extFromInt.argtypes = [ctypes.c_int]
266        c_api.extFromInt.restype = ctypes.c_void_p
267        c_api.extFromDouble.argtypes = [ctypes.c_double]
268        c_api.extFromDouble.restype = ctypes.c_void_p
269        c_api.extFromString.argtypes = [ctypes.c_char_p]
270        c_api.extFromString.restype = ctypes.c_void_p
271        c_api.extIntValue.argtypes = [ctypes.c_void_p]
272        c_api.extIntValue.restype = ctypes.c_int
273        c_api.extDoubleValue.argtypes = [ctypes.c_void_p]
274        c_api.extDoubleValue.restype = ctypes.c_double
275        c_api.extStringValue.argtypes = [ctypes.c_void_p]
276        c_api.extStringValue.restype = ctypes.c_char_p
277        c_api.extClass.argtypes = [ctypes.c_void_p]
278        c_api.extClass.restype = ctypes.c_char_p
279        c_api.extPropCount.argtypes = [ctypes.c_void_p]
280        c_api.extPropCount.restype = ctypes.c_int
281        c_api.extPropId.argtypes = [ctypes.c_void_p, ctypes.c_int]
282        c_api.extPropId.restype = ctypes.c_char_p
283        c_api.extPropType.argtypes = [ctypes.c_void_p, ctypes.c_int]
284        c_api.extPropType.restype = ctypes.c_char_p
285        c_api.extPropFind.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
286        c_api.extPropFind.restype = ctypes.c_int
287        c_api.extPropGet.argtypes = [ctypes.c_void_p, ctypes.c_int]
288        c_api.extPropGet.restype = ctypes.c_void_p
289        c_api.extPropSet.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]
290        c_api.extPropSet.restype = ctypes.c_int
291        c_api.extPropCall.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_void_p]
292        c_api.extPropCall.restype = ctypes.c_void_p
293        c_api.rootObject.argtypes = []
294        c_api.rootObject.restype = ctypes.c_void_p
295
296        c_args = (ctypes.c_char_p * (len(args) + 1))(*([b''] + list(a.encode(ExtValue._encoding) for a in args)))
297        c_api.init(len(args) + 1, c_args)
298        Root = ExtValue._rootObject()
299        for n in dir(Root):
300                if n[0].isalpha():
301                        attr = getattr(Root, n)
302                        if isinstance(attr, ExtValue):
303                                attr = attr._value()
304                        setattr(sys.modules[__name__], n, attr)
305        print('Using Framsticks version: ' + str(Simulator.version_string))
306        print('Home (writable) dir     : ' + home_dir)
307        print('Resources dir           : ' + res_dir)
308        print()
Note: See TracBrowser for help on using the repository browser.