From e5ee6e0dc7cdcd958b9acab11626d859c9a2ed42 2016-06-10 10:06:04 From: Marcin Lulek Date: 2016-06-10 10:06:04 Subject: [PATCH] search: cython compatible configurator --- diff --git a/backend/src/appenlight/__init__.py b/backend/src/appenlight/__init__.py index e43950c..e334325 100644 --- a/backend/src/appenlight/__init__.py +++ b/backend/src/appenlight/__init__.py @@ -31,7 +31,7 @@ import appenlight.lib.encryption as encryption from authomatic.providers import oauth2, oauth1 from authomatic import Authomatic -from pyramid.config import Configurator, PHASE3_CONFIG +from pyramid.config import PHASE3_CONFIG from pyramid.authentication import AuthTktAuthenticationPolicy from pyramid.authorization import ACLAuthorizationPolicy from pyramid_mailer.mailer import Mailer @@ -44,6 +44,7 @@ from redlock import Redlock from sqlalchemy import engine_from_config from appenlight.celery import configure_celery +from appenlight.lib.configurator import CythonCompatConfigurator from appenlight.lib import cache_regions from appenlight.lib.ext_json import json from appenlight.security import groupfinder, AuthTokenAuthenticationPolicy @@ -91,11 +92,12 @@ def main(global_config, **settings): # Create the Pyramid Configurator. settings['_mail_url'] = settings['mailing.app_url'] - config = Configurator(settings=settings, - authentication_policy=authentication_policy, - authorization_policy=authorization_policy, - root_factory='appenlight.security.RootFactory', - default_permission='view') + config = CythonCompatConfigurator( + settings=settings, + authentication_policy=authentication_policy, + authorization_policy=authorization_policy, + root_factory='appenlight.security.RootFactory', + default_permission='view') config.set_default_csrf_options(require_csrf=True, header='X-XSRF-TOKEN') config.add_view_deriver('appenlight.predicates.csrf_view', name='csrf_view') @@ -131,8 +133,8 @@ def main(global_config, **settings): config.include('ziggurat_foundations.ext.pyramid.sign_in') es_server_list = aslist(settings['elasticsearch.nodes']) redis_url = settings['redis.url'] - log.info('Elasticsearch server list: {}'.format(es_server_list)) - log.info('Redis server: {}'.format(redis_url)) + log.warning('Elasticsearch server list: {}'.format(es_server_list)) + log.warning('Redis server: {}'.format(redis_url)) config.registry.es_conn = pyelasticsearch.ElasticSearch(es_server_list) config.registry.redis_conn = redis.StrictRedis.from_url(redis_url) diff --git a/backend/src/appenlight/lib/configurator.py b/backend/src/appenlight/lib/configurator.py new file mode 100644 index 0000000..31cfa29 --- /dev/null +++ b/backend/src/appenlight/lib/configurator.py @@ -0,0 +1,61 @@ +import inspect + +from pyramid.config import Configurator + + +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 + return getattr(cyfunction, 'func_code') + + 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. + if getattr(obj, '__name__') == 'includeme': + 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. + if 'cyfunction' in e.message: + 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. + """ + inspect = InspectProxy()