The Gaudi Framework  master (60ee365e)
Loading...
Searching...
No Matches
cpluginsvc.py
Go to the documentation of this file.
11
12# cpluginsvc is a ctypes-based wrapper for the C-exposed API of GaudiPluginService
13__doc__ = """
14cpluginsvc is a ctypes-based wrapper for the C-API of the GaudiPluginService.
15
16e.g.:
17
18>>> from GaudiPluginService import cpluginsvc
19>>> for _,f in cpluginsvc.factories().items():
20... try:
21... f.load()
22... except Exception:
23... print ("** could not load [%s] for factory [%s]" % (f.library, f.name))
24... continue
25... print(f)
26... for k,v in f.properties.iteritems():
27... print ("\t%s: %s" % (k,v))
28"""
29
30import ctypes
31import ctypes.util
32import os
33import platform
34
35__all__ = (
36 "Registry",
37 "registry",
38 "factories",
39 "Factory",
40 "Property",
41)
42
43_lib_basename = {
44 "Darwin": "libGaudiPluginService.dylib",
45 "Windows": "libGaudiPluginService.dll",
46 "Linux": "libGaudiPluginService.so",
47}[platform.system()]
48
49
51 """Locate libGaudiPluginService, searching library path env vars explicitly."""
52 search_vars = (
53 ["DYLD_LIBRARY_PATH", "LD_LIBRARY_PATH"]
54 if platform.system() == "Darwin"
55 else ["LD_LIBRARY_PATH"]
56 )
57 for var in search_vars:
58 for directory in os.environ.get(var, "").split(os.pathsep):
59 if not directory:
60 continue
61 candidate = os.path.join(directory, _lib_basename)
62 if os.path.exists(candidate):
63 return candidate
64 # Fall back to bare name and let the dynamic linker resolve it
65 return _lib_basename
66
67
68_lib = ctypes.CDLL(_find_library(), ctypes.RTLD_GLOBAL)
69
70
71class Registry(ctypes.Structure):
72 """Registry holds the list of factories known by the gaudi PluginService."""
73
74 _fields_ = [("_registry", ctypes.c_void_p)]
75
76 @property
77 def factories(self):
78 facts = {}
79 n = _lib.cgaudi_pluginsvc_get_factory_size(self)
80 for i in range(n):
81 f = _lib.cgaudi_pluginsvc_get_factory_at(self, i)
82 facts[f.name] = f
83 return facts
84
85 pass
86
87
88_instance = None
89
90
92 """registry returns the singleton-like instance of the plugin service."""
93
94 global _instance
95 if _instance:
96 return _instance
97 _instance = _lib.cgaudi_pluginsvc_instance()
98 return _instance
99
100
102 """
103 factories returns the list of components factory informations known to the plugin service
104 """
105 return registry().factories
106
107
108class Factory(ctypes.Structure):
109 """
110 Factory holds informations about a component's factory:
111 - its name
112 - the library hosting that component
113 - the type of component (algorithm, service, tool, ...)
114 - the return type of this factory
115 - the C++ class name of that component
116 - the properties which may decorate that component.
117 """
118
119 _fields_ = [
120 ("_registry", Registry),
121 ("_id", ctypes.c_char_p),
122 ]
123
124 @property
125 def name(self):
126 return self._id.decode("ascii")
127
128 @property
129 def library(self):
130 return _lib.cgaudi_factory_get_library(self).decode("ascii")
131
132 @property
133 def type(self):
134 return _lib.cgaudi_factory_get_type(self).decode("ascii")
135
136 @property
137 def classname(self):
138 return _lib.cgaudi_factory_get_classname(self).decode("ascii")
139
140 @property
141 def properties(self):
142 props = {}
143 nprops = _lib.cgaudi_factory_get_property_size(self)
144 for i in range(nprops):
145 prop = _lib.cgaudi_factory_get_property_at(self, i)
146 props[prop.key] = prop.value
147 return props
148
149 def load(self):
150 """load the C++ library hosting this factory"""
151 return ctypes.CDLL(self.library, ctypes.RTLD_GLOBAL)
152
153 def __repr__(self):
154 return "<Factory id=%s library=%s type=%s class=%s props=%d>" % (
155 self.name,
156 self.library,
157 self.type,
159 len(self.properties),
160 )
161
162 pass
163
164
165class Property(ctypes.Structure):
166 """
167 Property is a pair (key, value) optionally decorating a factory.
168 It is used to attach additional informations about a factory.
169 """
170
171 _fields_ = [
172 ("_registry", Registry),
173 ("_id", ctypes.c_char_p),
174 ("_key", ctypes.c_char_p),
175 ]
176
177 @property
178 def key(self):
179 return _lib.cgaudi_property_get_key(self).decode("ascii")
180
181 @property
182 def value(self):
183 return _lib.cgaudi_property_get_value(self).decode("ascii")
184
185 pass
186
187
188_functions_list = [
189 (
190 "cgaudi_pluginsvc_instance",
191 [],
192 Registry,
193 ),
194 (
195 "cgaudi_pluginsvc_get_factory_size",
196 [Registry],
197 ctypes.c_int,
198 ),
199 (
200 "cgaudi_pluginsvc_get_factory_at",
201 [Registry, ctypes.c_int],
202 Factory,
203 ),
204 (
205 "cgaudi_factory_get_library",
206 [Factory],
207 ctypes.c_char_p,
208 ),
209 (
210 "cgaudi_factory_get_type",
211 [Factory],
212 ctypes.c_char_p,
213 ),
214 (
215 "cgaudi_factory_get_classname",
216 [Factory],
217 ctypes.c_char_p,
218 ),
219 (
220 "cgaudi_factory_get_property_size",
221 [Factory],
222 ctypes.c_int,
223 ),
224 (
225 "cgaudi_factory_get_property_at",
226 [Factory, ctypes.c_int],
227 Property,
228 ),
229 (
230 "cgaudi_property_get_key",
231 [Property],
232 ctypes.c_char_p,
233 ),
234 (
235 "cgaudi_property_get_value",
236 [Property],
237 ctypes.c_char_p,
238 ),
239 (
240 "cgaudi_pluginsvc_plugin_search_path",
241 [],
242 ctypes.c_char_p,
243 ),
244]
245
246for f in _functions_list:
247 n = f[0]
248 func = getattr(_lib, n)
249 func.argtypes = f[1]
250 func.restype = f[2]
251 if len(f) == 4:
252 func.errcheck = f[3]
253 pass
254
255
256GAUDI_DEFAULT_PLUGIN_PATH = [
257 p
258 for p in _lib.cgaudi_pluginsvc_plugin_search_path().decode().split(os.pathsep)
259 if p
260]
261
262
263if __name__ == "__main__":
264 print("instance: %s" % registry())
265 print("factories: %d" % len(factories()))
266 for _, f in factories().items():
267 try:
268 f.load()
269 except Exception:
270 print("** could not load [%s] for factory [%s]" % (f.library, f.name))
271 continue
272 print(f)
273 for k, v in f.properties.items():
274 print("\t%s: %s" % (k, v))
275
276# EOF