Index: Doc/lib/libtypes.tex =================================================================== --- Doc/lib/libtypes.tex (revision 50546) +++ Doc/lib/libtypes.tex (working copy) @@ -180,6 +180,20 @@ \function{buffer()}\bifuncindex{buffer} function. \end{datadesc} +\begin{datadesc}{DictProxyType} +The type of dict proxies, such as \code{TypeType.__dict__}. +\end{datadesc} + +\begin{datadesc}{NotImplementedType} +The type of \code{NotImplemented} +\end{datadesc} + +\begin{datadesc}{GetSetterType} +The type of objects defined in extension modules with \code{PyGetSetDef}, such +as \code{FrameType.f_locals} or \code{array.array.typecode}. +\versionadded{2.5} +\end{datadesc} + \begin{datadesc}{StringTypes} A sequence containing \code{StringType} and \code{UnicodeType} used to facilitate easier checking for any string object. Using this is more Index: Doc/lib/libinspect.tex =================================================================== --- Doc/lib/libinspect.tex (revision 50546) +++ Doc/lib/libinspect.tex (working copy) @@ -187,6 +187,14 @@ \versionadded{2.3} \end{funcdesc} +\begin{funcdesc}{isgetsetter}{object} + Return true if the object is a getsetter. + + Getsetters are attributes defined in extension modules via + \code{PyGetSetDef} structures. +\versionadded{2.5} +\end{funcdesc} + \subsection{Retrieving source code \label{inspect-source}} Index: Lib/inspect.py =================================================================== --- Lib/inspect.py (revision 50546) +++ Lib/inspect.py (working copy) @@ -89,6 +89,13 @@ is not guaranteed.""" return (hasattr(object, "__set__") and hasattr(object, "__get__")) +def isgetsetter(object): + """Return true if the object is a getset descriptor. + + Getsetters are specialized descriptors defined in extension modules. + Examples are frame object's f_locals and array.array.typecode.""" + return isinstance(object, types.GetSetterType) + def isfunction(object): """Return true if the object is a user-defined function. Index: Lib/pydoc.py =================================================================== --- Lib/pydoc.py (revision 50546) +++ Lib/pydoc.py (working copy) @@ -318,6 +318,7 @@ # identifies something in a way that pydoc itself has issues handling; # think 'super' and how it is a descriptor (which raises the exception # by lacking a __name__ attribute) and an instance. + if inspect.isgetsetter(object): return self.docdata(*args) try: if inspect.ismodule(object): return self.docmodule(*args) if inspect.isclass(object): return self.docclass(*args) @@ -333,7 +334,7 @@ name and ' ' + repr(name), type(object).__name__) raise TypeError, message - docmodule = docclass = docroutine = docother = fail + docmodule = docclass = docroutine = docother = docproperty = docdata = fail def getdocloc(self, object): """Return the location of module docs or None""" @@ -915,6 +916,10 @@ lhs = name and '%s = ' % name or '' return lhs + self.repr(object) + def docdata(self, object, name=None, mod=None, cl=None): + """Produce html documentation for a data descriptor.""" + return self._docdescriptor(name, object, mod) + def index(self, dir, shadowed=None): """Generate an HTML index for a directory of modules.""" modpkgs = [] @@ -1268,6 +1273,10 @@ """Produce text documentation for a property.""" return self._docdescriptor(name, object, mod) + def docdata(self, object, name=None, mod=None, cl=None): + """Produce text documentation for a data descriptor.""" + return self._docdescriptor(name, object, mod) + def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None): """Produce text documentation for a data object.""" repr = self.repr(object) @@ -1397,6 +1406,10 @@ return 'module ' + thing.__name__ if inspect.isbuiltin(thing): return 'built-in function ' + thing.__name__ + if inspect.isgetsetter(thing): + return 'data descriptor %s.%s.%s' % ( + thing.__objclass__.__module__, thing.__objclass__.__name__, + thing.__name__) if inspect.isclass(thing): return 'class ' + thing.__name__ if inspect.isfunction(thing): @@ -1453,6 +1466,7 @@ if not (inspect.ismodule(object) or inspect.isclass(object) or inspect.isroutine(object) or + inspect.isgetsetter(object) or isinstance(object, property)): # If the passed object is a piece of data or an instance, # document its available methods instead of its value. Index: Lib/types.py =================================================================== --- Lib/types.py (revision 50546) +++ Lib/types.py (working copy) @@ -85,5 +85,6 @@ DictProxyType = type(TypeType.__dict__) NotImplementedType = type(NotImplemented) +GetSetterType = type(FrameType.f_locals) del sys, _f, _g, _C, _x # Not for export Index: Lib/test/test_inspect.py =================================================================== --- Lib/test/test_inspect.py (revision 50546) +++ Lib/test/test_inspect.py (working copy) @@ -40,10 +40,11 @@ self.failIf(other(obj), 'not %s(%s)' % (other.__name__, exp)) class TestPredicates(IsTestBase): - def test_eleven(self): + def test_twelve(self): # Doc/lib/libinspect.tex claims there are 11 such functions count = len(filter(lambda x:x.startswith('is'), dir(inspect))) - self.assertEqual(count, 11, "There are %d (not 11) is* functions" % count) + self.assertEqual(count, 12, + "There are %d (not 12) is* functions" % count) def test_excluding_predicates(self): self.istest(inspect.isbuiltin, 'sys.exit') @@ -58,6 +59,7 @@ self.istest(inspect.istraceback, 'tb') self.istest(inspect.isdatadescriptor, '__builtin__.file.closed') self.istest(inspect.isdatadescriptor, '__builtin__.file.softspace') + self.istest(inspect.isgetsetter, 'type(tb.tb_frame).f_locals') def test_isroutine(self): self.assert_(inspect.isroutine(mod.spam))