summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-11-25 21:52:11 -0500
committerChris McDonough <chrism@plope.com>2011-11-25 21:52:11 -0500
commit8b6f09d965a6e637b795a8268c310c81fcb43a10 (patch)
tree92cbbfa6fea594ceb3669c84fd49ca8328cc5da9
parent5e92f34f019e2e6e06ff4c0b5c019349591f9a43 (diff)
downloadpyramid-8b6f09d965a6e637b795a8268c310c81fcb43a10.tar.gz
pyramid-8b6f09d965a6e637b795a8268c310c81fcb43a10.tar.bz2
pyramid-8b6f09d965a6e637b795a8268c310c81fcb43a10.zip
add rudimentary object description code
-rw-r--r--TODO.txt14
-rw-r--r--pyramid/config/__init__.py2
-rw-r--r--pyramid/config/adapters.py4
-rw-r--r--pyramid/config/factories.py9
-rw-r--r--pyramid/config/routes.py3
-rw-r--r--pyramid/config/views.py9
-rw-r--r--pyramid/util.py66
7 files changed, 100 insertions, 7 deletions
diff --git a/TODO.txt b/TODO.txt
index f13cd5c6c..ed215138e 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -8,6 +8,20 @@ Must-Have
- Fix SQLA tutorial to match alchemy scaffold.
+- Introspection:
+
+ * More specific filename/lineno info instead of opaque string (or a way to
+ parse the opaque string into filename/lineno info).
+
+ * categorize() return value ordering not right yet.
+
+ * implement ptweens and proutes based on introspection instead of current
+ state of affairs.
+
+ * introspection hiding for directives?
+
+ * usage docs.
+
Nice-to-Have
------------
diff --git a/pyramid/config/__init__.py b/pyramid/config/__init__.py
index d7e95b7e9..e993d0700 100644
--- a/pyramid/config/__init__.py
+++ b/pyramid/config/__init__.py
@@ -34,6 +34,7 @@ from pyramid.settings import aslist
from pyramid.threadlocal import manager
from pyramid.util import DottedNameResolver
from pyramid.util import WeakOrderedSet
+from pyramid.util import object_description
from pyramid.config.adapters import AdaptersConfiguratorMixin
from pyramid.config.assets import AssetsConfiguratorMixin
@@ -219,6 +220,7 @@ class Configurator(
basepath = None
includepath = ()
info = ''
+ object_description = staticmethod(object_description)
def __init__(self,
registry=None,
diff --git a/pyramid/config/adapters.py b/pyramid/config/adapters.py
index 620464ed3..04571bec3 100644
--- a/pyramid/config/adapters.py
+++ b/pyramid/config/adapters.py
@@ -29,7 +29,7 @@ class AdaptersConfiguratorMixin(object):
self.registry.registerHandler(subscriber, iface)
intr = self.introspectable('subscribers',
id(subscriber),
- repr(subscriber),
+ self.object_description(subscriber),
'subscriber')
intr['subscriber'] = subscriber
intr['interfaces'] = iface
@@ -62,7 +62,7 @@ class AdaptersConfiguratorMixin(object):
intr = self.introspectable(
'response adapters',
discriminator,
- repr(adapter),
+ self.object_description(adapter),
'response adapter')
intr['adapter'] = adapter
intr['type'] = type_or_iface
diff --git a/pyramid/config/factories.py b/pyramid/config/factories.py
index 6cc90a80b..2ab9fc7db 100644
--- a/pyramid/config/factories.py
+++ b/pyramid/config/factories.py
@@ -27,7 +27,8 @@ class FactoriesConfiguratorMixin(object):
self.registry.registerUtility(factory, IRootFactory)
self.registry.registerUtility(factory, IDefaultRootFactory) # b/c
- intr = self.introspectable('root factories', None, repr(factory),
+ intr = self.introspectable('root factories', None,
+ self.object_description(factory),
'root factory')
intr['factory'] = factory
self.action(IRootFactory, register, introspectables=(intr,))
@@ -50,7 +51,8 @@ class FactoriesConfiguratorMixin(object):
factory = self.maybe_dotted(factory)
def register():
self.registry.registerUtility(factory, ISessionFactory)
- intr = self.introspectable('session factory', None, repr(factory),
+ intr = self.introspectable('session factory', None,
+ self.object_description(factory),
'session factory')
intr['factory'] = factory
self.action(ISessionFactory, register, introspectables=(intr,))
@@ -74,7 +76,8 @@ class FactoriesConfiguratorMixin(object):
factory = self.maybe_dotted(factory)
def register():
self.registry.registerUtility(factory, IRequestFactory)
- intr = self.introspectable('request factory', None, repr(factory),
+ intr = self.introspectable('request factory', None,
+ self.object_description(factory),
'request factory')
intr['factory'] = factory
self.action(IRequestFactory, register, introspectables=(intr,))
diff --git a/pyramid/config/routes.py b/pyramid/config/routes.py
index 46f69300d..0ab380ec1 100644
--- a/pyramid/config/routes.py
+++ b/pyramid/config/routes.py
@@ -365,7 +365,8 @@ class RoutesConfiguratorMixin(object):
mapper = self.get_routes_mapper()
- intr = self.introspectable('routes', name, name, 'route')
+ intr = self.introspectable('routes', name,
+ '%s (%s)' % (name, pattern), 'route')
intr['name'] = name
intr['pattern'] = pattern
intr['factory'] = factory
diff --git a/pyramid/config/views.py b/pyramid/config/views.py
index f4e7bb1db..12193b478 100644
--- a/pyramid/config/views.py
+++ b/pyramid/config/views.py
@@ -931,7 +931,14 @@ class ViewsConfiguratorMixin(object):
xhr, accept, header, path_info, match_param]
discriminator.extend(sorted([hash(x) for x in custom_predicates]))
discriminator = tuple(discriminator)
- view_intr = self.introspectable('views', discriminator, repr(view),
+ if inspect.isclass(view) and attr:
+ view_desc = 'method %r of %s' % (
+ attr, self.object_description(view))
+ else:
+ view_desc = self.object_description(view)
+ view_intr = self.introspectable('views',
+ discriminator,
+ view_desc,
'view')
view_intr.update(
dict(name=name,
diff --git a/pyramid/util.py b/pyramid/util.py
index 3eb4b3fed..fd3bcd48d 100644
--- a/pyramid/util.py
+++ b/pyramid/util.py
@@ -1,5 +1,7 @@
+import inspect
import pkg_resources
import sys
+import types
import weakref
from pyramid.compat import string_types
@@ -228,3 +230,67 @@ def strings_differ(string1, string2):
return invalid_bits != 0
+def object_description(object):
+ """ Produce a human-consumable string description of ``object``, usually
+ involving a Python dotted name. For example:
+
+ .. code-block:: python
+
+ >>> object_description(None)
+ 'None'
+ >>> from xml.dom import minidom
+ >>> object_description(minidom)
+ 'module xml.dom.minidom'
+ >>> object_description(minidom.Attr)
+ 'class xml.dom.minidom.Attr'
+ >>> object_description(minidom.Attr.appendChild)
+ 'method appendChild of class xml.dom.minidom.Attr'
+ >>>
+
+ If this method cannot identify the type of the object, a generic
+ description ala ``object <object.__name__>`` will be returned.
+
+ If the object passed is already a string, it is simply returned. If it
+ is a boolean, an integer, a list, a tuple, a set, or ``None``, a
+ (possibly shortened) string representation is returned.
+ """
+ if isinstance(object, string_types):
+ return object
+ if isinstance(object, (bool, int, float, long, types.NoneType)):
+ return str(object)
+ if isinstance(object, (tuple, set)):
+ return shortrepr(object, ')')
+ if isinstance(object, list):
+ return shortrepr(object, ']')
+ if isinstance(object, dict):
+ return shortrepr(object, '}')
+ module = inspect.getmodule(object)
+ modulename = module.__name__
+ if inspect.ismodule(object):
+ return 'module %s' % modulename
+ if inspect.ismethod(object):
+ oself = getattr(object, '__self__', None)
+ if oself is None:
+ oself = getattr(object, 'im_self', None)
+ oself.__class__
+ return 'method %s of class %s.%s' (object.__name__, modulename,
+ oself.__class__.__name___)
+
+ if inspect.isclass(object):
+ dottedname = '%s.%s' % (modulename, object.__name__)
+ return 'class %s' % dottedname
+ if inspect.isfunction(object):
+ dottedname = '%s.%s' % (modulename, object.__name__)
+ return 'function %s' % dottedname
+ if inspect.isbuiltin(object):
+ dottedname = '%s.%s' % (modulename, object.__name__)
+ return 'builtin %s' % dottedname
+ if hasattr(object, '__name__'):
+ return 'object %s' % object.__name__
+ return 'object %s' % str(object)
+
+def shortrepr(object, closer):
+ r = str(object)
+ if len(r) > 100:
+ r = r[:100] + '... %s' % closer
+ return r