summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt3
-rw-r--r--docs/narr/advconfig.rst4
-rw-r--r--pyramid/config/__init__.py8
-rw-r--r--pyramid/config/util.py19
-rw-r--r--pyramid/interfaces.py60
-rw-r--r--pyramid/registry.py37
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):