2a7414bb5c415f6212a851263f08a2c2de2637f7
1 # SPDX-License-Identifier: MIT
3 # Copyright (c) 2017 Philippe Proulx <pproulx@efficios.com>
7 from bt2
import utils
as bt2_utils
8 from bt2
import component
as bt2_component
10 # Python plugin path to `_PluginInfo` (cache)
14 def plugin_component_class(component_class
):
15 if not issubclass(component_class
, bt2_component
._UserComponent
):
16 raise TypeError("component class is not a subclass of a user component class")
18 component_class
._bt
_plugin
_component
_class
= None
19 return component_class
23 module_name
, name
, description
=None, author
=None, license
=None, version
=None
25 if module_name
not in sys
.modules
:
27 "cannot find module '{}' in loaded modules".format(module_name
)
30 bt2_utils
._check
_str
(name
)
32 if description
is not None:
33 bt2_utils
._check
_str
(description
)
35 if author
is not None:
36 bt2_utils
._check
_str
(author
)
38 if license
is not None:
39 bt2_utils
._check
_str
(license
)
41 if version
is not None:
42 if not _validate_version(version
):
44 "wrong version: expecting a tuple: (major, minor, patch) or (major, minor, patch, extra)"
47 sys
.modules
[module_name
]._bt
_plugin
_info
= _PluginInfo(
48 name
, description
, author
, license
, version
52 def _validate_version(version
):
56 if not isinstance(version
, tuple):
59 if len(version
) < 3 or len(version
) > 4:
62 if not isinstance(version
[0], int):
65 if not isinstance(version
[1], int):
68 if not isinstance(version
[2], int):
72 if not isinstance(version
[3], str):
79 def __init__(self
, name
, description
, author
, license
, version
):
81 self
.description
= description
83 self
.license
= license
84 self
.version
= version
85 self
.comp_class_addrs
= None
88 # called by the BT plugin system
89 def _try_load_plugin_module(path
):
90 if path
in _plugin_infos
:
91 # do not load module and create plugin info twice for this path
92 return _plugin_infos
[path
]
96 import importlib
.machinery
99 raise TypeError("missing path")
101 # In order to load the module uniquely from its path, even from
102 # different files which have the same basename, we hash the path
103 # and prefix with `bt_plugin_`. This is its key in sys.modules.
105 h
.update(path
.encode())
106 module_name
= "bt_plugin_{}".format(h
.hexdigest())
107 assert module_name
not in sys
.modules
109 # try loading the module: any raised exception is caught by the caller
110 if sys
.version_info
< (3, 5):
111 mod
= importlib
.machinery
.SourceFileLoader(module_name
, path
).load_module()
113 import importlib
.util
115 loader
= importlib
.machinery
.SourceFileLoader(module_name
, path
)
116 spec
= importlib
.util
.spec_from_file_location(module_name
, path
, loader
=loader
)
117 mod
= importlib
.util
.module_from_spec(spec
)
118 sys
.modules
[mod
.__name
__] = mod
119 loader
.exec_module(mod
)
121 # we have the module: look for its plugin info first
122 if not hasattr(mod
, "_bt_plugin_info"):
123 raise RuntimeError("missing '_bt_plugin_info' module attribute")
125 plugin_info
= mod
._bt
_plugin
_info
127 # search for user component classes
128 def is_user_comp_class(obj
):
129 if not inspect
.isclass(obj
):
132 if not hasattr(obj
, "_bt_plugin_component_class"):
137 comp_class_entries
= inspect
.getmembers(mod
, is_user_comp_class
)
138 plugin_info
.comp_class_addrs
= [entry
[1].addr
for entry
in comp_class_entries
]
139 _plugin_infos
[path
] = plugin_info
This page took 0.033489 seconds and 5 git commands to generate.