From d579f2104de139e0b0fc5d6c81aabb2f826e5e54 Mon Sep 17 00:00:00 2001 From: Michael Merickel <michael@merickel.org> Date: Fri, 19 Oct 2018 03:45:13 +0200 Subject: [PATCH] move predicate-related code into pyramid.config.predicates --- src/pyramid/config/actions.py | 64 ++++++++++++++++++++++++++++++-- 1 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/pyramid/config/actions.py b/src/pyramid/config/actions.py index 353ed5e..9c1227d 100644 --- a/src/pyramid/config/actions.py +++ b/src/pyramid/config/actions.py @@ -1,18 +1,19 @@ +import functools import itertools import operator import sys +import traceback +from zope.interface import implementer from pyramid.compat import reraise - -from pyramid.config.util import ActionInfo - from pyramid.exceptions import ( ConfigurationConflictError, ConfigurationError, ConfigurationExecutionError, ) - +from pyramid.interfaces import IActionInfo from pyramid.registry import undefer +from pyramid.util import is_nonstr_iter class ActionConfiguratorMixin(object): @@ -152,6 +153,7 @@ finally: self.end() self.action_state = ActionState() # old actions have been processed + # this class is licensed under the ZPL (stolen from Zope) class ActionState(object): @@ -523,3 +525,57 @@ order=order, introspectables=introspectables, ) + + +@implementer(IActionInfo) +class ActionInfo(object): + def __init__(self, file, line, function, src): + self.file = file + self.line = line + self.function = function + self.src = src + + def __str__(self): + srclines = self.src.split('\n') + src = '\n'.join(' %s' % x for x in srclines) + return 'Line %s of file %s:\n%s' % (self.line, self.file, src) + + +def action_method(wrapped): + """ Wrapper to provide the right conflict info report data when a method + that calls Configurator.action calls another that does the same. Not a + documented API but used by some external systems.""" + + def wrapper(self, *arg, **kw): + if self._ainfo is None: + self._ainfo = [] + info = kw.pop('_info', None) + # backframes for outer decorators to actionmethods + backframes = kw.pop('_backframes', 0) + 2 + if is_nonstr_iter(info) and len(info) == 4: + # _info permitted as extract_stack tuple + info = ActionInfo(*info) + if info is None: + try: + f = traceback.extract_stack(limit=4) + + # Work around a Python 3.5 issue whereby it would insert an + # extra stack frame. This should no longer be necessary in + # Python 3.5.1 + last_frame = ActionInfo(*f[-1]) + if last_frame.function == 'extract_stack': # pragma: no cover + f.pop() + info = ActionInfo(*f[-backframes]) + except Exception: # pragma: no cover + info = ActionInfo(None, 0, '', '') + self._ainfo.append(info) + try: + result = wrapped(self, *arg, **kw) + finally: + self._ainfo.pop() + return result + + if hasattr(wrapped, '__name__'): + functools.update_wrapper(wrapper, wrapped) + wrapper.__docobj__ = wrapped + return wrapper -- Gitblit v1.9.3