diff options
| -rw-r--r-- | CHANGES.txt | 3 | ||||
| -rw-r--r-- | docs/narr/advconfig.rst | 4 | ||||
| -rw-r--r-- | pyramid/config/__init__.py | 8 | ||||
| -rw-r--r-- | pyramid/config/util.py | 19 | ||||
| -rw-r--r-- | pyramid/interfaces.py | 60 | ||||
| -rw-r--r-- | pyramid/registry.py | 37 |
6 files changed, 64 insertions, 67 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index c1a4f0216..6f30d506c 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -25,6 +25,9 @@ Features This function sets up Python logging according to the logging configuration in a PasteDeploy ini file. +- Configuration conflict reporting is reported in a more understandable way + ("Line 11 in file..." vs. a repr of a tuple of similar info). + Bug Fixes --------- diff --git a/docs/narr/advconfig.rst b/docs/narr/advconfig.rst index 7b62b1a73..a6db5f58e 100644 --- a/docs/narr/advconfig.rst +++ b/docs/narr/advconfig.rst @@ -87,8 +87,8 @@ that ends something like this: Conflicting configuration actions For: ('view', None, '', None, <InterfaceClass pyramid.interfaces.IView>, None, None, None, None, None, False, None, None, None) - ('app.py', 14, '<module>', 'config.add_view(hello_world)') - ('app.py', 17, '<module>', 'config.add_view(hello_world)') + Line 14 of file app.py in <module>: 'config.add_view(hello_world)' + Line 17 of file app.py in <module>: 'config.add_view(hello_world)' This traceback is trying to tell us: diff --git a/pyramid/config/__init__.py b/pyramid/config/__init__.py index c2f004896..d4dc0247f 100644 --- a/pyramid/config/__init__.py +++ b/pyramid/config/__init__.py @@ -526,9 +526,9 @@ class Configurator( if autocommit: if callable is not None: callable(*args, **kw) - for introspectable in introspectables: - if introspector is not None: - introspector.register(introspectable, action_info) + if introspector is not None: + for introspectable in introspectables: + introspectable.register(introspector, action_info) else: self.action_state.action( @@ -1008,7 +1008,7 @@ class ActionState(object): del t, v, tb if introspector is not None: for introspectable in introspectables: - introspector.register(introspectable, info) + introspectable.register(introspector, info) finally: if clear: diff --git a/pyramid/config/util.py b/pyramid/config/util.py index cbec2e0c2..3fcb5d154 100644 --- a/pyramid/config/util.py +++ b/pyramid/config/util.py @@ -1,3 +1,4 @@ +import collections import re import traceback @@ -19,6 +20,20 @@ from hashlib import md5 MAX_ORDER = 1 << 30 DEFAULT_PHASH = md5().hexdigest() +_ActionInfo = collections.namedtuple( + 'ActionInfo', + ('filename', 'lineno', 'function', 'linerepr') + ) + +class ActionInfo(_ActionInfo): + # this is a namedtuple subclass for (minor) backwards compat + slots = () + def __str__(self): + return ( + 'Line %s of file %s in %s: %r' % ( + self.lineno, self.filename, self.function, self.linerepr) + ) + 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""" @@ -29,9 +44,9 @@ def action_method(wrapped): if info is None: try: f = traceback.extract_stack(limit=3) - info = f[-2] + info = ActionInfo(*f[-2]) except: # pragma: no cover - info = '' + info = ActionInfo('<unknown>', 0, '<unknown>', '<unknown>') self._ainfo.append(info) try: result = wrapped(self, *arg, **kw) diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py index 475b52313..2ff74e40b 100644 --- a/pyramid/interfaces.py +++ b/pyramid/interfaces.py @@ -903,38 +903,6 @@ class IIntrospector(Interface): ``discriminator``). Return the empty sequence if no relations for exist.""" - def register(introspectable, action_info=''): - """ Register an IIntrospectable with this introspector. This method - is invoked during action execution. Adds the introspectable and its - relations to the introspector. ``introspectable`` should be an - object implementing IIntrospectable. ``action_info`` should be a - string representing the call that registered this introspectable - (e.g. with line numbers, etc). Pseudocode for an implementation of - this method: - - .. code-block:: python - - def register(self, introspectable, action_info=''): - i = introspectable - i.action_info = action_info - self.add(introspectable) - for category_name, discriminator in i.relations: - self.relate(( - i.category_name, i.discriminator), - (category_name, discriminator)) - - for category_name, discriminator in i.unrelations: - self.unrelate(( - i.category_name, i.discriminator), - (category_name, discriminator)) - - The introspectable you wished to be related to or unrelated from must - have already been added via - :meth:`pyramid.interfaces.IIntrospector.add` (or by this method, - which implies an add) before this method is called; a :exc:`KeyError` - will result if this is not true. - """ - def add(intr): """ Add the IIntrospectable ``intr`` (use instead of :meth:`pyramid.interfaces.IIntrospector.add` when you have a custom @@ -983,14 +951,6 @@ class IIntrospectable(Interface): discriminator = Attribute('introspectable discriminator (within category) ' '(must be hashable)') discriminator_hash = Attribute('an integer hash of the discriminator') - relations = Attribute('A sequence of ``(category_name, discriminator)`` ' - 'pairs indicating the relations that this ' - 'introspectable wants to establish when registered ' - 'with the introspector') - unrelations = Attribute('A sequence of ``(category_name, discriminator)`` ' - 'pairs indicating the relations that this ' - 'introspectable wants to break when registered ' - 'with the introspector') action_info = Attribute('A string representing the caller that invoked ' 'the creation of this introspectable (usually ' 'managed by IIntrospector during registration)') @@ -1007,6 +967,26 @@ class IIntrospectable(Interface): the ``category_name`` and ``discriminator``) during action execution. """ + def register(introspector, action_info=''): + """ Register this IIntrospectable with an introspector. This method + is invoked during action execution. Adds the introspectable and its + relations to the introspector. ``introspector`` should be an + object implementing IIntrospector. ``action_info`` should be a + string representing the call that registered this introspectable + (e.g. with line numbers, etc). Pseudocode for an implementation of + this method: + + .. code-block:: python + + def register(self, introspector, action_info): + self.action_info = action_info + introspector.add(self) + for methodname, category_name, discriminator in self._relations: + method = getattr(introspector, methodname) + method((i.category_name, i.discriminator), + (category_name, discriminator)) + """ + # configuration phases: a lower phase number means the actions associated # with this phase will be executed earlier than those with later phase # numbers. The default phase number is 0, FTR. diff --git a/pyramid/registry.py b/pyramid/registry.py index 947643252..b081980b0 100644 --- a/pyramid/registry.py +++ b/pyramid/registry.py @@ -166,38 +166,37 @@ class Introspector(object): raise KeyError((category_name, discriminator)) return self._refs.get(intr, []) - def register(self, introspectable, action_info=''): - introspectable.action_info = action_info - self.add(introspectable) - for category_name, discriminator in introspectable.relations: - self.relate(( - introspectable.category_name, introspectable.discriminator), - (category_name, discriminator)) - - for category_name, discriminator in introspectable.unrelations: - self.unrelate(( - introspectable.category_name, introspectable.discriminator), - (category_name, discriminator)) - @implementer(IIntrospectable) class Introspectable(dict): - order = 0 # mutated by introspector.add/introspector.add_intr - action_info = '' # mutated by introspector.register + order = 0 # mutated by introspector.add + action_info = '' # mutated by introspectable.register def __init__(self, category_name, discriminator, title, type_name): self.category_name = category_name self.discriminator = discriminator self.title = title self.type_name = type_name - self.relations = [] - self.unrelations = [] + self._relations = [] def relate(self, category_name, discriminator): - self.relations.append((category_name, discriminator)) + self._relations.append((True, category_name, discriminator)) def unrelate(self, category_name, discriminator): - self.unrelations.append((category_name, discriminator)) + self._relations.append((False, category_name, discriminator)) + + def register(self, introspector, action_info): + self.action_info = action_info + introspector.add(self) + for relate, category_name, discriminator in self._relations: + if relate: + method = introspector.relate + else: + method = introspector.unrelate + method( + (self.category_name, self.discriminator), + (category_name, discriminator) + ) @property def discriminator_hash(self): |
