Permalink
Browse files

docs; todo; coverage for Introspector

  • Loading branch information...
1 parent 47e1f73 commit 57a0d7765c54031e6ac83881b536712316f22c45 @mcdonc mcdonc committed Nov 30, 2011
Showing with 291 additions and 25 deletions.
  1. +6 −0 CHANGES.txt
  2. +3 −2 TODO.txt
  3. +11 −4 docs/api/config.rst
  4. +6 −0 docs/api/interfaces.rst
  5. +25 −0 docs/api/registry.rst
  6. +16 −7 pyramid/interfaces.py
  7. +12 −12 pyramid/registry.py
  8. +212 −0 pyramid/tests/test_registry.py
View
@@ -28,6 +28,12 @@ Features
- Configuration conflict reporting is reported in a more understandable way
("Line 11 in file..." vs. a repr of a tuple of similar info).
+- New APIs: ``pyramid.registry.Introspectable``,
+ ``pyramid.config.Configurator.introspector``,
+ ``pyramid.config.Configurator.introspectable``,
+ ``pyramid.registry.Registry.introspector``. See API docs of related
+ modules for more info.
+
Bug Fixes
---------
View
@@ -6,8 +6,9 @@ Must-Have
- Introspection:
- * More specific filename/lineno info instead of opaque string (or a way to
- parse the opaque string into filename/lineno info).
+ * Narrative docs.
+
+ * Test with pyramid_zcml (wrt action_info / actions.append).
* categorize() return value ordering not right yet.
View
@@ -94,16 +94,23 @@
.. automethod:: set_renderer_globals_factory(factory)
- .. attribute:: introspector
-
- The :term:`introspector` associated with this configuration.
-
.. attribute:: introspectable
A shortcut attribute which points to the
:class:`pyramid.registry.Introspectable` class (used during
directives to provide introspection to actions).
+ This attribute is new as of :app:`Pyramid` 1.3.
+
+ .. attribute:: introspector
+
+ The :term:`introspector` related to this configuration. It is an
+ instance implementing the :class:`pyramid.interfaces.IIntrospector`
+ interface. If the Configurator constructor was supplied with an
+ ``introspector`` argument, this attribute will be that value.
+ Otherwise, it will be an instance of a default introspector type.
+
+ This attribute is new as of :app:`Pyramid` 1.3.
.. attribute:: global_registries
View
@@ -68,3 +68,9 @@ Other Interfaces
.. autointerface:: IResponse
:members:
+ .. autointerface:: IIntrospectable
+ :members:
+
+ .. autointerface:: IIntrospector
+ :members:
+
View
@@ -14,3 +14,28 @@
accessed as ``request.registry.settings`` or
``config.registry.settings`` in a typical Pyramid application.
+ .. attribute:: introspector
+
+ When a registry is set up (or created) by a :term:`Configurator`, the
+ registry will be decorated with an instance named ``introspector``
+ implementing the :class:`pyramid.interfaces.IIntrospector` interface.
+ See also :attr:`pyramid.config.Configurator.introspector``.
+
+ When a registry is created "by hand", however, this attribute will not
+ exist until set up by a configurator.
+
+ This attribute is often accessed as ``request.registry.introspector`` in
+ a typical Pyramid application.
+
+ This attribute is new as of :app:`Pyramid` 1.3.
+
+.. class:: Introspectable
+
+ The default implementation of the interface
+ :class:`pyramid.interfaces.IIntrospectable` used by framework exenders.
+ An instance of this class is is created when
+ :attr:`pyramid.config.Configurator.introspectable` is called.
+
+ This class is new as of :app:`Pyramid` 1.3.
+
+
View
@@ -865,13 +865,13 @@ def get(category_name, discriminator, default=None):
discriminator (or discriminator hash) ``discriminator``. If it does
not exist in the introspector, return the value of ``default`` """
- def get_category(category_name, sort_fn=None):
+ def get_category(category_name, sort_key=None):
""" Get a sequence of dictionaries in the form
``[{'introspectable':IIntrospectable, 'related':[sequence of related
IIntrospectables]}, ...]`` where each introspectable is part of the
- category associated with ``category_name`` . If ``sort_fn`` is
+ category associated with ``category_name`` . If ``sort_key`` is
``None``, the sequence will be returned in the order the
- introspectables were added to the introspector. Otherwise, sort_fn
+ introspectables were added to the introspector. Otherwise, sort_key
should be a function that accepts an IIntrospectable and returns a
value from it (ala the ``key`` function of Python's ``sorted``
callable)."""
@@ -880,13 +880,13 @@ def categories():
""" Return a sorted sequence of category names known by
this introspector """
- def categorized(sort_fn=None):
+ def categorized(sort_key=None):
""" Get a sequence of tuples in the form ``[(category_name,
[{'introspectable':IIntrospectable, 'related':[sequence of related
IIntrospectables]}, ...])]`` representing all known
- introspectables. If ``sort_fn`` is ``None``, each introspectables
+ introspectables. If ``sort_key`` is ``None``, each introspectables
sequence will be returned in the order the introspectables were added
- to the introspector. Otherwise, sort_fn should be a function that
+ to the introspector. Otherwise, sort_key should be a function that
accepts an IIntrospectable and returns a value from it (ala the
``key`` function of Python's ``sorted`` callable)."""
@@ -941,7 +941,8 @@ class IIntrospectable(Interface):
""" An introspectable object used for configuration introspection. In
addition to the methods below, objects which implement this interface
must also implement all the methods of Python's
- ``collections.MutableMapping`` (the "dictionary interface")."""
+ ``collections.MutableMapping`` (the "dictionary interface"), and must be
+ hashable."""
title = Attribute('Text title describing this introspectable')
type_name = Attribute('Text type name describing this introspectable')
@@ -987,6 +988,14 @@ def register(self, introspector, action_info):
(category_name, discriminator))
"""
+ def __hash__():
+
+ """ Introspectables must be hashable. The typical implementation of
+ an introsepectable's __hash__ is::
+
+ return hash((self.category_name,) + (self.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.
View
@@ -103,32 +103,32 @@ def get(self, category_name, discriminator, default=None):
intr = category.get(discriminator, default)
return intr
- def get_category(self, category_name, sort_fn=None):
- if sort_fn is None:
- sort_fn = operator.attrgetter('order')
+ def get_category(self, category_name, sort_key=None):
+ if sort_key is None:
+ sort_key = operator.attrgetter('order')
category = self._categories[category_name]
values = category.values()
- values = sorted(set(values), key=sort_fn)
+ values = sorted(set(values), key=sort_key)
return [{'introspectable':intr, 'related':self.related(intr)} for
intr in values]
- def categories(self):
- return sorted(self._categories.keys())
-
- def categorized(self, sort_fn=None):
+ def categorized(self, sort_key=None):
L = []
for category_name in self.categories():
- L.append((category_name, self.get_category(category_name, sort_fn)))
+ L.append((category_name, self.get_category(category_name,sort_key)))
return L
+ def categories(self):
+ return sorted(self._categories.keys())
+
def remove(self, category_name, discriminator):
intr = self.get(category_name, discriminator)
if intr is None:
return
- L = self._refs.pop((category_name, discriminator), [])
+ L = self._refs.pop(intr, [])
for d in L:
L2 = self._refs[d]
- L2.remove((category_name, discriminator))
+ L2.remove(intr)
category = self._categories[intr.category_name]
del category[intr.discriminator]
del category[intr.discriminator_hash]
@@ -170,7 +170,7 @@ def related(self, intr):
class Introspectable(dict):
order = 0 # mutated by introspector.add
- action_info = '' # mutated by introspectable.register
+ action_info = None # mutated by introspectable.register
def __init__(self, category_name, discriminator, title, type_name):
self.category_name = category_name
Oops, something went wrong.

0 comments on commit 57a0d77

Please sign in to comment.