The Gaudi Framework  master (bdbe7744)
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 f"<Factory id={self.name} library={self.library} type={self.type} class={self.classname} props={len(self.properties)}>"
155
156 pass
157
158
159class Property(ctypes.Structure):
160 """
161 Property is a pair (key, value) optionally decorating a factory.
162 It is used to attach additional informations about a factory.
163 """
164
165 _fields_ = [
166 ("_registry", Registry),
167 ("_id", ctypes.c_char_p),
168 ("_key", ctypes.c_char_p),
169 ]
170
171 @property
172 def key(self):
173 return _lib.cgaudi_property_get_key(self).decode("ascii")
174
175 @property
176 def value(self):
177 return _lib.cgaudi_property_get_value(self).decode("ascii")
178
179 pass
180
181
182_functions_list = [
183 (
184 "cgaudi_pluginsvc_instance",
185 [],
186 Registry,
187 ),
188 (
189 "cgaudi_pluginsvc_get_factory_size",
190 [Registry],
191 ctypes.c_int,
192 ),
193 (
194 "cgaudi_pluginsvc_get_factory_at",
195 [Registry, ctypes.c_int],
196 Factory,
197 ),
198 (
199 "cgaudi_factory_get_library",
200 [Factory],
201 ctypes.c_char_p,
202 ),
203 (
204 "cgaudi_factory_get_type",
205 [Factory],
206 ctypes.c_char_p,
207 ),
208 (
209 "cgaudi_factory_get_classname",
210 [Factory],
211 ctypes.c_char_p,
212 ),
213 (
214 "cgaudi_factory_get_property_size",
215 [Factory],
216 ctypes.c_int,
217 ),
218 (
219 "cgaudi_factory_get_property_at",
220 [Factory, ctypes.c_int],
221 Property,
222 ),
223 (
224 "cgaudi_property_get_key",
225 [Property],
226 ctypes.c_char_p,
227 ),
228 (
229 "cgaudi_property_get_value",
230 [Property],
231 ctypes.c_char_p,
232 ),
233 (
234 "cgaudi_pluginsvc_plugin_search_path",
235 [],
236 ctypes.c_char_p,
237 ),
238]
239
240for f in _functions_list:
241 n = f[0]
242 func = getattr(_lib, n)
243 func.argtypes = f[1]
244 func.restype = f[2]
245 if len(f) == 4:
246 func.errcheck = f[3]
247 pass
248
249
250GAUDI_DEFAULT_PLUGIN_PATH = [
251 p
252 for p in _lib.cgaudi_pluginsvc_plugin_search_path().decode().split(os.pathsep)
253 if p
254]
255
256
257if __name__ == "__main__":
258 print(f"instance: {registry()}")
259 print(f"factories: {len(factories())}")
260 for _, f in factories().items():
261 try:
262 f.load()
263 except Exception:
264 print(f"** could not load [{f.library}] for factory [{f.name}]")
265 continue
266 print(f)
267 for k, v in f.properties.items():
268 print(f"\t{k}: {v}")
269
270# EOF