configurator.py
92 lines
| 3.4 KiB
| text/x-python
|
PythonLexer
r7 | import inspect | |||
r20 | import logging | |||
r7 | ||||
from pyramid.config import Configurator | ||||
r20 | log = logging.getLogger(__name__) | |||
r7 | ||||
r153 | ||||
r7 | class InspectProxy(object): | |||
""" | ||||
Proxy to the `inspect` module that allows us to use the pyramid include | ||||
mechanism for cythonized modules without source file. | ||||
""" | ||||
def _get_cyfunction_func_code(self, cyfunction): | ||||
""" | ||||
Unpack the `func_code` attribute of a cython function. | ||||
""" | ||||
if inspect.ismethod(cyfunction): | ||||
cyfunction = cyfunction.im_func | ||||
r153 | return getattr(cyfunction, "func_code") | |||
r7 | ||||
def getmodule(self, *args, **kwds): | ||||
""" | ||||
Simple proxy to `inspect.getmodule`. | ||||
""" | ||||
return inspect.getmodule(*args, **kwds) | ||||
def getsourcefile(self, obj): | ||||
""" | ||||
Proxy to `inspect.getsourcefile` or `inspect.getfile` depending on if | ||||
it's called to look up the source file that contains the magic pyramid | ||||
`includeme` callable. | ||||
For cythonized modules the source file may be deleted. Therefore we | ||||
return the result of `inspect.getfile` instead. In the case of the | ||||
`configurator.include` method this is OK, because the result is passed | ||||
to `os.path.dirname` which strips the file name. So it doesn't matter | ||||
if we return the path to the source file or another file in the same | ||||
directory. | ||||
""" | ||||
# Check if it's called to look up the source file that contains the | ||||
# magic pyramid `includeme` callable. | ||||
r153 | if getattr(obj, "__name__") == "includeme": | |||
r7 | try: | |||
return inspect.getfile(obj) | ||||
except TypeError as e: | ||||
# Cython functions are not recognized as functions by the | ||||
# inspect module. We have to unpack the func_code attribute | ||||
# ourself. | ||||
r153 | if "cyfunction" in e.message: | |||
r7 | obj = self._get_cyfunction_func_code(obj) | |||
return inspect.getfile(obj) | ||||
raise | ||||
else: | ||||
return inspect.getsourcefile(obj) | ||||
class CythonCompatConfigurator(Configurator): | ||||
""" | ||||
Customized configurator to replace the inspect class attribute with | ||||
a custom one that is cython compatible. | ||||
""" | ||||
r153 | ||||
r7 | inspect = InspectProxy() | |||
r20 | ||||
def register_appenlight_plugin(config, plugin_name, plugin_config): | ||||
def register(): | ||||
r153 | log.warning("Registering plugin: {}".format(plugin_name)) | |||
r20 | if plugin_name not in config.registry.appenlight_plugins: | |||
config.registry.appenlight_plugins[plugin_name] = { | ||||
r153 | "javascript": None, | |||
"static": None, | ||||
"css": None, | ||||
"celery_tasks": None, | ||||
"celery_beats": None, | ||||
"fulltext_indexer": None, | ||||
"sqlalchemy_migrations": None, | ||||
"default_values_setter": None, | ||||
"header_html": None, | ||||
"resource_types": [], | ||||
"url_gen": None, | ||||
r20 | } | |||
r153 | config.registry.appenlight_plugins[plugin_name].update(plugin_config) | |||
r20 | # inform AE what kind of resource types we have available | |||
# so we can avoid failing when a plugin is removed but data | ||||
# is still present in the db | ||||
r153 | if plugin_config.get("resource_types"): | |||
config.registry.resource_types.extend(plugin_config["resource_types"]) | ||||
r20 | ||||
r153 | config.action("appenlight_plugin={}".format(plugin_name), register) | |||