source: framspy/frams.py @ 1083

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

Allowed to override the default name of frams-objects.dll/so

File size: 9.0 KB
Line 
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):
22        """All Framsticks objects and values are instances of this class. Read the documentation of the 'frams' module for more information."""
23
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
250def init(lib_path, lib_name, *args):
251        """
252        Initializes the connection to Framsticks dll/so.
253
254        :param lib_path: the path where the dll/so file can be found
255        :param lib_name: the name of the dll/so (a complete name including file name extension) or None if you want to use the default name
256        :param args: optional arguments to pass to Framsticks initialization (try "-h")
257        """
258        original_dir = os.getcwd()
259        os.chdir(lib_path)  # because under Windows, frams-objects.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
260        global c_api  # access global variable to initialize it
261        c_api = ctypes.CDLL(lib_name if lib_name is not None else 'frams-objects.so' if os.name == 'posix' else 'frams-objects.dll')
262        os.chdir(original_dir)
263
264        c_api.init.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_char_p)]
265        c_api.init.restype = None
266        c_api.extFree.argtypes = [ctypes.c_void_p]
267        c_api.extFree.restype = None
268        c_api.extType.argtypes = [ctypes.c_void_p]
269        c_api.extType.restype = ctypes.c_int
270        c_api.extFromNull.argtypes = []
271        c_api.extFromNull.restype = ctypes.c_void_p
272        c_api.extFromInt.argtypes = [ctypes.c_int]
273        c_api.extFromInt.restype = ctypes.c_void_p
274        c_api.extFromDouble.argtypes = [ctypes.c_double]
275        c_api.extFromDouble.restype = ctypes.c_void_p
276        c_api.extFromString.argtypes = [ctypes.c_char_p]
277        c_api.extFromString.restype = ctypes.c_void_p
278        c_api.extIntValue.argtypes = [ctypes.c_void_p]
279        c_api.extIntValue.restype = ctypes.c_int
280        c_api.extDoubleValue.argtypes = [ctypes.c_void_p]
281        c_api.extDoubleValue.restype = ctypes.c_double
282        c_api.extStringValue.argtypes = [ctypes.c_void_p]
283        c_api.extStringValue.restype = ctypes.c_char_p
284        c_api.extClass.argtypes = [ctypes.c_void_p]
285        c_api.extClass.restype = ctypes.c_char_p
286        c_api.extPropCount.argtypes = [ctypes.c_void_p]
287        c_api.extPropCount.restype = ctypes.c_int
288        c_api.extPropId.argtypes = [ctypes.c_void_p, ctypes.c_int]
289        c_api.extPropId.restype = ctypes.c_char_p
290        c_api.extPropType.argtypes = [ctypes.c_void_p, ctypes.c_int]
291        c_api.extPropType.restype = ctypes.c_char_p
292        c_api.extPropFind.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
293        c_api.extPropFind.restype = ctypes.c_int
294        c_api.extPropGet.argtypes = [ctypes.c_void_p, ctypes.c_int]
295        c_api.extPropGet.restype = ctypes.c_void_p
296        c_api.extPropSet.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p]
297        c_api.extPropSet.restype = ctypes.c_int
298        c_api.extPropCall.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_void_p]
299        c_api.extPropCall.restype = ctypes.c_void_p
300        c_api.rootObject.argtypes = []
301        c_api.rootObject.restype = ctypes.c_void_p
302
303        c_args = (ctypes.c_char_p * (len(args) + 1))(*([b''] + list(a.encode(ExtValue._encoding) for a in args)))
304        c_api.init(len(args) + 1, c_args)
305        Root = ExtValue._rootObject()
306        for n in dir(Root):
307                if n[0].isalpha():
308                        attr = getattr(Root, n)
309                        if isinstance(attr, ExtValue):
310                                attr = attr._value()
311                        setattr(sys.modules[__name__], n, attr)
312        print('Using Framsticks version: ' + str(Simulator.version_string))
313        print('Home (writable) dir     : ' + home_dir)
314        print('Resources dir           : ' + res_dir)
315        print()
Note: See TracBrowser for help on using the repository browser.