Package: zope.apidoc
This Zope 3 package provides helper utilities to discover your Application API
and the Zopen Component Registry.ContentsZope 3 API DocumentationComponent Inspection UtilitiesgetRequiredAdapters(iface, withViews=False)getProvidedAdapters(iface, withViews=False)getClasses(iface)getFactories(ifaces)getUtilities(iface)getRealFactory(factory)getInterfaceInfoDictionary(iface)getTypeInfoDictionary(type)getSpecificationInfoDictionary(spec)getAdapterInfoDictionary(reg)getFactoryInfoDictionary(reg)getUtilityInfoDictionary(name, factory)Interface Inspection UtilitiesgetElements(iface, type=IElement)getFieldsInOrder(iface, _itemsorter=…)getAttributes(iface)getMethods(iface)getFields(iface)getInterfaceTypes(iface)getFieldInterface(field)getAttributeInfoDictionary(attr, format=’restructuredtext’)getMethodInfoDictionary(method, format=’restructuredtext’)getFieldInfoDictionary(field, format=’restructuredtext’)Presentation Inspection UtilitiesgetViewFactoryData(factory)getPresentationType(iface)getViews(iface, type=IRequest)filterViewRegistrations(regs, iface, level=SPECIFC_INTERFACE_LEVEL)getViewInfoDictionary(reg)Miscellaneous UtilitiesrelativizePath(path)truncateSysPath(path)getPythonPath(obj)isReferencable(path)getPermissionIds(name, checker=_marker, klass=_marker)getFunctionSignature(func)getPublicAttributes(obj)getInterfaceForAttribute(name, interfaces=_marker, klass=_marker, asPath=True)columnize(entries, columns=3)getDocFormat(module)dedentString(text)renderText(text, module=None, format=None)The Class RegistrygetClassesThatImplement(iface)getSubclassesOf(klass)Safe ImportsCHANGESZope 3 API DocumentationThis Zope 3 package provides fully dynamic API documentation of Zope 3 and
registered add-on components. The package is very extensible and can be easily
extended by implementing new modules.Besides being an application, the API doctool also provides several public
APIs to extract information from various objects used by Zope 3.utilities – Miscellaneous classes and functions that aid all documentation
modules. They are broadly usable.interface – This module contains functions to inspect interfaces and
schemas.component – This modules provides utility functions to lookup components
given an interface.presentation – Presentation components are generally more complex than
others, so a separate utilities module is provided to inspect views.classregistry – Here a simple dictionary-based registry for all known
classes is provided. It allows us to search in classes.Component Inspection UtilitiesOnce you have an interface, you really want to discover on how this interface
interacts with other components in Zope 3. The functions in>>> from zope.apidoc import componentprovide you with utilities to make those discoveries. The functions are
explained in detail in this document. Before we start though, we have to have
some interfaces to work with:>>> from zope.interface import Interface
>>> class IFoo(Interface):
...     pass>>> class IBar(Interface):
...     pass>>> class IFooBar(IFoo, IBar):
...     pass>>> class IResult(Interface):
...     pass>>> class ISpecialResult(IResult):
...     passgetRequiredAdapters(iface, withViews=False)This function returns adapter registrations for adapters that require the
specified interface. So let’s create some adapter registrations:>>> from zope.publisher.interfaces import IRequest
>>> from zope.component import provideAdapter, provideHandler
>>> provideAdapter(None, (IFoo,), IResult)
>>> provideAdapter(None, (IFoo, IBar), ISpecialResult)
>>> provideAdapter(None, (IFoo, IRequest), ISpecialResult)
>>> provideHandler('stubFactory', (IFoo,))>>> regs = list(component.getRequiredAdapters(IFoo))
>>> regs.sort()
>>> regs
[AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IBar], ISpecialResult, u'', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo], IResult, u'', None, u''),
 HandlerRegistration(<BaseGlobalComponents base>,
                     [IFoo], u'', 'stubFactory', u'')]Note how the adapter requiring anIRequestat the end of the required
interfaces is neglected. This is because it is recognized as a view and views
are not returned by default. But you can simply turn this flag on:>>> regs = list(component.getRequiredAdapters(IFoo, withViews=True))
>>> regs.sort()
>>> regs
[AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IBar], ISpecialResult, u'', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IRequest], ISpecialResult, u'', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo], IResult, u'', None, u''),
 HandlerRegistration(<BaseGlobalComponents base>,
                     [IFoo], u'', 'stubFactory', u'')]The function will also pick up registrations that have required interfaces the
specified interface extends:>>> regs = list(component.getRequiredAdapters(IFoo))
>>> regs.sort()
>>> regs
[AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IBar], ISpecialResult, u'', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo], IResult, u'', None, u''),
 HandlerRegistration(<BaseGlobalComponents base>,
                     [IFoo], u'', 'stubFactory', u'')]And all of the required interfaces are considered, of course:>>> regs = list(component.getRequiredAdapters(IBar))
>>> regs.sort()
>>> regs
[AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IBar], ISpecialResult, u'', None, u'')]getProvidedAdapters(iface, withViews=False)Of course, we are also interested in the adapters that provide a certain
interface. This function returns those adapter registrations, again ignoring
views by default.>>> regs = list(component.getProvidedAdapters(ISpecialResult))
>>> regs.sort()
>>> regs
[AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IBar], ISpecialResult, u'', None, u'')]And by specifying thewithViewflag, we get views as well:>>> regs = list(component.getProvidedAdapters(ISpecialResult, withViews=True))
>>> regs.sort()
>>> regs
[AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IBar], ISpecialResult, u'', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IRequest], ISpecialResult, u'', None, u'')]We can of course also ask for adapters specifyingIResult:>>> regs = list(component.getProvidedAdapters(IResult, withViews=True))
>>> regs.sort()
>>> regs
[AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IBar], ISpecialResult, u'', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IRequest], ISpecialResult, u'', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo], IResult, u'', None, u'')]getClasses(iface)This package comes with a little tool called the class registry
(seeclassregistry.txt). It provides a dictionary of all classes in the
visible packages. This function utilizes the registry to retrieve all classes
that implement the specified interface.Let’s start by creating and registering some classes:>>> from zope.interface import implements
>>> from zope.apidoc.classregistry import classRegistry>>> class MyFoo(object):
...     implements(IFoo)
>>> classRegistry['MyFoo'] = MyFoo>>> class MyBar(object):
...     implements(IBar)
>>> classRegistry['MyBar'] = MyBar>>> class MyFooBar(object):
...     implements(IFooBar)
>>> classRegistry['MyFooBar'] = MyFooBarLet’s now see whether what results we get:>>> classes = component.getClasses(IFooBar)
>>> classes.sort()
>>> classes
[('MyFooBar', <class 'zope.apidoc.doctest.MyFooBar'>)]>>> classes = component.getClasses(IFoo)
>>> classes.sort()
>>> classes
[('MyFoo', <class 'zope.apidoc.doctest.MyFoo'>),
 ('MyFooBar', <class 'zope.apidoc.doctest.MyFooBar'>)]getFactories(ifaces)Return the factory registrations of the factories that will return objects
providing this interface.Again, the first step is to create some factories:>>> from zope.component.factory import Factory
>>> from zope.component.interfaces import IFactory
>>> from zope.component import provideUtility
>>> provideUtility(Factory(MyFoo), IFactory, 'MyFoo')
>>> provideUtility(Factory(MyBar), IFactory, 'MyBar')
>>> provideUtility(
...     Factory(MyFooBar, 'MyFooBar', 'My Foo Bar'), IFactory, 'MyFooBar')Let’s see whether we will be able to get them:>>> regs = list(component.getFactories(IFooBar))
>>> regs.sort()
>>> regs
[UtilityRegistration(<BaseGlobalComponents base>,
    IFactory, 'MyFooBar',
    <Factory for <class 'zope.apidoc.doctest.MyFooBar'>>, None, u'')]>>> regs = list(component.getFactories(IFoo))
>>> regs.sort()
>>> regs
[UtilityRegistration(<BaseGlobalComponents base>, IFactory, 'MyFoo',
             <Factory for <class 'zope.apidoc.doctest.MyFoo'>>, None, u''),
 UtilityRegistration(<BaseGlobalComponents base>, IFactory, 'MyFooBar',
          <Factory for <class 'zope.apidoc.doctest.MyFooBar'>>, None, u'')]getUtilities(iface)Return all utility registrations for utilities that provide the specified
interface.As usual, we have to register some utilities first:>>> provideUtility(MyFoo(), IFoo)
>>> provideUtility(MyBar(), IBar)
>>> provideUtility(MyFooBar(), IFooBar)Now let’s have a look what we have:>>> regs = list(component.getUtilities(IFooBar))
>>> regs.sort()
>>> regs #doctest:+ELLIPSIS
[UtilityRegistration(<BaseGlobalComponents base>, IFooBar, u'',
                     <zope.apidoc.doctest.MyFooBar object at ...>, None, u'')]>>> regs = list(component.getUtilities(IFoo))
>>> regs.sort()
>>> regs #doctest:+ELLIPSIS
[UtilityRegistration(<BaseGlobalComponents base>, IFoo, u'',
                     <zope.apidoc.doctest.MyFoo object at ...>, None, u''),
 UtilityRegistration(<BaseGlobalComponents base>, IFooBar, u'',
                     <zope.apidoc.doctest.MyFooBar object at ...>, None, u'')]getRealFactory(factory)During registration, factories are commonly masked by wrapper functions. Also,
factories are sometimes alsoIFactoryinstances, which are not referencable,
so that we would like to return the class. If the wrapper objects/functions
play nice, then they provide afactoryattribute that points to the next
wrapper or the original factory.The task of this function is to remove all the factory wrappers and make sure
that the returned factory is referencable.>>> class Factory(object):
...     pass>>> def wrapper1(*args):
...     return Factory(*args)
>>> wrapper1.factory = Factory>>> def wrapper2(*args):
...     return wrapper1(*args)
>>> wrapper2.factory = wrapper1So whether we pass inFactory,>>> component.getRealFactory(Factory)
<class 'zope.apidoc.doctest.Factory'>wrapper1,>>> component.getRealFactory(wrapper1)
<class 'zope.apidoc.doctest.Factory'>orwrapper2,>>> component.getRealFactory(wrapper2)
<class 'zope.apidoc.doctest.Factory'>the answer should always be theFactoryclass. Next we are going to pass in
an instance, and again we should get our class aas a result:>>> factory = Factory()
>>> component.getRealFactory(factory)
<class 'zope.apidoc.doctest.Factory'>Even, if the factory instance is wrapped, we should get the factory class:>>> def wrapper3(*args):
...     return factory(*args)
>>> wrapper3.factory = factory>>> component.getRealFactory(wrapper3)
<class 'zope.apidoc.doctest.Factory'>getInterfaceInfoDictionary(iface)This function returns a small info dictionary for an interface. It only
reports the module and the name. This is useful for cases when we only want to
list interfaces in the context of other components, like adapters and
utilities.>>> from pprint import pprint
>>> pprint(component.getInterfaceInfoDictionary(IFoo), width=1)
{'module': 'zope.apidoc.doctest', 'name': 'IFoo'}The functions using this function use it with little care and can also
sometimes pass inNone. In these cases we want to returnNone:>>> component.getInterfaceInfoDictionary(None) is None
TrueIt’s also possible for this function to be passed a
zope.interface.declarations.Implements instance.  For instance, this function
is sometimes used to analyze the required elements of an adapter registration:
if an adapter or subscriber is registered against a class, then the required
element will be an Implements instance.  In this case, we currently believe
that we want to return the module and name of the object that the Implements
object references.  This may change.>>> from zope.interface import implementedBy
>>> pprint(component.getInterfaceInfoDictionary(implementedBy(MyFoo)), width=1)
{'module': 'zope.apidoc.doctest', 'name': 'MyFoo'}getTypeInfoDictionary(type)This function returns the info dictionary of a type.>>> pprint(component.getTypeInfoDictionary(tuple), width=1)
{'module': '__builtin__',
 'name': 'tuple',
 'url': '__builtin__/tuple'}getSpecificationInfoDictionary(spec)Thsi function returns an info dictionary for the given specification. A
specification can either be an interface or class. If it is an interface, it
simply returns the interface dictionary:>>> pprint(component.getSpecificationInfoDictionary(IFoo))
{'isInterface': True,
 'isType': False,
 'module': 'zope.apidoc.doctest',
 'name': 'IFoo'}In addition to the usual interface infos, there are two flags indicating
whether the specification was an interface or type. In our case it is an
interface.Let’s now look at the behavior when passing a type:>>> import zope.interface
>>> tupleSpec = zope.interface.implementedBy(tuple)>>> pprint(component.getSpecificationInfoDictionary(tupleSpec))
{'isInterface': False,
 'isType': True,
 'module': '__builtin__',
 'name': 'tuple',
 'url': '__builtin__/tuple'}For the type, we simply reuse the type info dictionary function.getAdapterInfoDictionary(reg)This function returns a page-template-friendly dictionary representing the
data of an adapter registration in an output-friendly format.Let’s first create an adapter registration:>>> class MyResult(object):
...     implements(IResult)>>> from zope.component.registry import AdapterRegistration
>>> reg = AdapterRegistration(None, (IFoo, IBar), IResult, 'FooToResult',
...                            MyResult, 'doc info')And now get the info dictionary:>>> pprint(component.getAdapterInfoDictionary(reg), width=1)
{'doc': 'doc info',
 'factory': 'zope.apidoc.doctest.MyResult',
 'factory_url': 'zope/apidoc/doctest/MyResult',
 'name': u'FooToResult',
 'provided': {'module': 'zope.apidoc.doctest',
              'name': 'IResult'},
 'required': [{'isInterface': True,
               'isType': False,
               'module': 'zope.apidoc.doctest',
               'name': 'IFoo'},
              {'isInterface': True,
               'isType': False,
               'module': 'zope.apidoc.doctest',
               'name': 'IBar'}],
 'zcml': None}If the factory’s path cannot be referenced, for example if a type has been
created using thetype()builtin function, then the URL of the factory
will beNone:>>> MyResultType = type('MyResult2', (object,), {})
>>> from zope.interface import classImplements
>>> classImplements(MyResultType, IResult)>>> reg = AdapterRegistration(None, (IFoo, IBar), IResult, 'FooToResult',
...                            MyResultType, 'doc info')
>>> pprint(component.getAdapterInfoDictionary(reg), width=1)
{'doc': 'doc info',
 'factory': 'zope.apidoc.doctest.MyResult2',
 'factory_url': None,
 'name': u'FooToResult',
 'provided': {'module': 'zope.apidoc.doctest',
              'name': 'IResult'},
 'required': [{'isInterface': True,
               'isType': False,
               'module': 'zope.apidoc.doctest',
               'name': 'IFoo'},
              {'isInterface': True,
               'isType': False,
               'module': 'zope.apidoc.doctest',
               'name': 'IBar'}],
 'zcml': None}This function can also handle subscription registrations, which are pretty
much like adapter registrations, except that they do not have a name. So let’s
see how the function handles subscriptions:>>> from zope.component.registry import HandlerRegistration
>>> reg = HandlerRegistration(None, (IFoo, IBar), u'', MyResult, 'doc info')>>> pprint(component.getAdapterInfoDictionary(reg))
{'doc': 'doc info',
 'factory': 'zope.apidoc.doctest.MyResult',
 'factory_url': 'zope/apidoc/doctest/MyResult',
 'name': u'',
 'provided': None,
 'required': [{'isInterface': True,
               'isType': False,
               'module': 'zope.apidoc.doctest',
               'name': 'IFoo'},
              {'isInterface': True,
               'isType': False,
               'module': 'zope.apidoc.doctest',
               'name': 'IBar'}],
 'zcml': None}getFactoryInfoDictionary(reg)This function returns a page-template-friendly dictionary representing the
data of a factory (utility) registration in an output-friendly format.Luckily we have already registered some factories, so we just reuse their
registrations:>>> pprint(component.getFactoryInfoDictionary(
...     component.getFactories(IFooBar).next()))
{'description': u'<p>My Foo Bar</p>\n',
 'name': u'MyFooBar',
 'title': 'MyFooBar',
 'url': 'zope/apidoc/doctest/MyFooBar'}If the factory’s path cannot be referenced, for example if a type has been
created using thetype()builtin function, then the URL of the factory
will beNone:>>> class IMine(Interface):
...     pass>>> class FactoryBase(object):
...     def getInterfaces(self): return [IMine]>>> MyFactoryType = type('MyFactory', (FactoryBase,), {})
>>> from zope.interface import classImplements
>>> classImplements(MyFactoryType, IFactory)
>>> provideUtility(MyFactoryType(), IFactory, 'MyFactory')>>> pprint(component.getFactoryInfoDictionary(
...     component.getFactories(IMine).next()), width=1)
{'description': u'',
 'name': u'MyFactory',
 'title': u'',
 'url': None}getUtilityInfoDictionary(name, factory)This function returns a page-template-friendly dictionary representing the
data of a utility registration in an output-friendly format.Luckily we have already registered some utilities, so we just reuse their
registrations:>>> pprint(component.getUtilityInfoDictionary(
...     component.getUtilities(IFooBar).next()))
{'iface_id': 'zope.apidoc.doctest.IFooBar',
 'name': u'<i>no name</i>',
 'path': 'zope.apidoc.doctest.MyFooBar',
 'url': 'Code/zope/apidoc/doctest/MyFooBar',
 'url_name': 'X19ub25hbWVfXw=='}Interface Inspection UtilitiesThis document is a presentation of the utility functions provided by>>> from zope.apidoc import interfaceFor the following demonstrations, we need a nice interface that we can inspect:>>> from zope.interface import Interface, Attribute
>>> from zope.schema import Field, TextLine>>> class IFoo(Interface):
...     foo = Field(title=u"Foo")
...
...     bar = TextLine(title=u"Bar",
...                    description=u"The Bar",
...                    required=True,
...                    default=u"My Bar")
...
...     baz = Attribute('baz',
...                     'This is the baz attribute')
...
...     def blah(one, two, three=None, *args, **kwargs):
...         """This is the `blah` method."""getElements(iface, type=IElement)Return a dictionary containing all elements in an interface. The type
specifies whether we are looking for attributes, fields or methods. So let’s
look at an example.First, let’s get the methods of an interface:>>> from zope.interface.interfaces import IMethod
>>> interface.getElements(IFoo, type=IMethod).keys()
['blah']and now the fields:>>> from zope.schema.interfaces import IField
>>> names = interface.getElements(IFoo, type=IField).keys()
>>> names.sort()
>>> names
['bar', 'foo']We can also get all attributes of course.>>> from zope.interface.interfaces import IAttribute
>>> names = interface.getElements(IFoo, type=IAttribute).keys()
>>> names.sort()
>>> names
['bar', 'baz', 'blah', 'foo']You might be surprised by the above result, since the fields and methods are
again included. However, fields and methods are just attributes and thus
extend the simple attribute implementation. If you want to get a list of
attributes that does not include fields and methods, see thegetAttributes(iface)function.The default type isIElementwhich will simply return all elements of the
interface:>>> names = interface.getElements(IFoo).keys()
>>> names.sort()
>>> names
['bar', 'baz', 'blah', 'foo']Note: The interface you pass to this functioncannotbe proxied!
Presentation code often like to wrap interfaces in security proxies and apidoc
even uses location proxies for interface.getFieldsInOrder(iface, _itemsorter=…)For presentation purposes we often want fields to have the a certain order,
most comonly the order they have in the interface. This function returns a
list of (name, field) tuples in a specified order.The_itemsorterargument provides the function that is used to order the
fields. The default function, which sorts by the fields’orderattribute,
should be the correct one for 99% of your needs.Reusing the interface created above, we check the output:>>> [n for n, a in interface.getFieldsInOrder(IFoo)]
['foo', 'bar']By changing the sort method to sort by names, we get:>>> [n for n, a in interface.getFieldsInOrder(
...       IFoo, _itemsorter=lambda x, y: cmp(x[0], y[0]))]
['bar', 'foo']getAttributes(iface)This function returns a (name, attr) tuple for every attribute in the
interface. Note that this function will only return pure attributes; it
ignores methods and fields.>>> attrs = interface.getAttributes(IFoo)
>>> attrs.sort()
>>> attrs #doctest: +ELLIPSIS
[('baz', <zope.interface.interface.Attribute object at ...>)]getMethods(iface)This function returns a (name, method) tuple for every declared method in the
interface.>>> methods = interface.getMethods(IFoo)
>>> methods.sort()
>>> methods #doctest: +ELLIPSIS
[('blah', <zope.interface.interface.Method object at ...>)]getFields(iface)This function returns a (name, field) tuple for every declared field in the
interface.>>> interface.getFields(IFoo) #doctest: +ELLIPSIS
[('foo', <zope.schema._bootstrapfields.Field object at ...>),
 ('bar', <zope.schema._bootstrapfields.TextLine object at ...>)]Note that this returns the same result asgetFieldsInOrder()with the fields
sorted by theirorderattribute, except that you cannot specify the sort
function here. This function was mainly provided for symmetry with the other
functions.getInterfaceTypes(iface)Interfaces can be categorized/grouped by using interface types. Interface
types simply extendzope.interface.interfaces.IInterface, which are
basically meta-interfaces. The interface types are then provided by particular
interfaces.ThegetInterfaceTypes()function returns a list of interface types that are
provided for the specified interface. Note that you commonly expect only one
type per interface, though.Before we assign any type to ourIFoointerface, there are no types
declared.>>> interface.getInterfaceTypes(IFoo)
[]Now we define a new type calledIContentType>>> from zope.interface.interfaces import IInterface
>>> class IContentType(IInterface):
...     passand have our interface provide it:>>> from zope.interface import directlyProvides
>>> directlyProvides(IFoo, IContentType)Note that ZCML has some more convenient methods of doing this. Now let’s get
the interface types again:>>> interface.getInterfaceTypes(IFoo)
[<InterfaceClass zope.apidoc.doctest.IContentType>]Again note that the interface passed to this functioncannotbe proxied,
otherwise this method will pick up the proxy’s interfaces as well.getFieldInterface(field)This function tries pretty hard to determine the best-matching interface that
represents the field. Commonly the field class has the same name as the field
interface (minus an “I”). So this is our first choice:>>> from zope.schema import Text, Int
>>> interface.getFieldInterface(Text())
<InterfaceClass zope.schema.interfaces.IText>>>> interface.getFieldInterface(Int())
<InterfaceClass zope.schema.interfaces.IInt>If the name matching method fails, it picks the first interface that extendsIField:>>> from zope.schema.interfaces import IField
>>> class ISpecialField(IField):
...     pass
>>> class ISomething(Interface):
...     pass>>> from zope.interface import implements
>>> class MyField:
...     implements(ISomething, ISpecialField)>>> interface.getFieldInterface(MyField())
<InterfaceClass zope.apidoc.doctest.ISpecialField>getAttributeInfoDictionary(attr, format=’restructuredtext’)This function returns a page-template-friendly dictionary for a simple
attribute:>>> from pprint import pprint
>>> pprint(interface.getAttributeInfoDictionary(IFoo['baz']))
{'doc': u'<p>This is the baz attribute</p>\n',
 'name': 'baz'}getMethodInfoDictionary(method, format=’restructuredtext’)This function returns a page-template-friendly dictionary for a method:>>> pprint(interface.getMethodInfoDictionary(IFoo['blah'])) #doc
{'doc':
   u'<p>This is the <cite>blah</cite> method.</p>\n',
 'name': 'blah',
 'signature': '(one, two, three=None, *args, **kwargs)'}getFieldInfoDictionary(field, format=’restructuredtext’)This function returns a page-template-friendly dictionary for a field:>>> pprint(interface.getFieldInfoDictionary(IFoo['bar']), width=1)
{'class': {'name': 'TextLine',
           'path': 'zope/schema/_bootstrapfields/TextLine'},
 'default': "u'My Bar'",
 'description': u'<p>The Bar</p>\n',
 'iface': {'id': 'zope.schema.interfaces.ITextLine',
           'name': 'ITextLine'},
 'name': 'bar',
 'required': True,
 'required_string': u'required',
 'title': u'Bar'}Presentation Inspection UtilitiesThepresentationmodule provides some nice utilities to inspect presentation
registrations.>>> from zope.apidoc import presentationgetViewFactoryData(factory)This function tries really hard to determine the correct information about a
view factory. For example, when you create a page, a new type is dynamically
generated upon registration. Let’s look at a couple examples.First, let’s inspect a case where a simple browser page was configured without
a special view class. In these cases the factory is aSimpleViewClass:>>> from zope.browserpage.simpleviewclass import SimpleViewClass
>>> view = SimpleViewClass('sample.pt')
>>> info = presentation.getViewFactoryData(view)Before we can check the result, we have to make sure that all Windows paths
are converted to Unix-like paths. We also clip off instance-specific parts of
the template path:>>> info['template'] = info['template'].replace('\\', '/')[-21:]
>>> from pprint import pprint
>>> pprint(info)
{'path': 'zope.browserpage.simpleviewclass.simple',
 'referencable': True,
 'resource': None,
 'template': 'zope/apidoc/sample.pt',
 'template_obj': <BoundPageTemplateFile of None>,
 'url': 'zope/browserpage/simpleviewclass/simple'}So in the result above we see what the function returns. It is a dictionary
(converted to a list for test purposes) that contains the Python path of the
view class, a flag that specifies whether the factory can be referenced and
thus be viewed by the class browser, the (page) template used for the view and
the URL under which the factory will be found in the class browser. Some
views, like icons, also use resources to provide their data. In these cases
the name of the resource will be provided. Of course, not in all cases all
values will be available. Empty values are marked withNone.Believe it or not, in some cases the factory is just a simple type. In these
cases we cannot retrieve any useful information:>>> info = presentation.getViewFactoryData(3)
>>> pprint(info)
{'path': None,
 'referencable': False,
 'resource': None,
 'template': None,
 'url': None}In some cases factories are callable class instances, where we cannot directly
have a referencable name, so we lookup the class and use its name:>>> class Factory(object):
...     pass>>> info = presentation.getViewFactoryData(Factory())
>>> pprint(info)
{'path': 'zope.apidoc.doctest.Factory',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': 'zope/apidoc/doctest/Factory'}One of the more common cases, however, is that the factory is a class or
type. In this case we can just retrieve the reference directly:>>> info = presentation.getViewFactoryData(Factory)
>>> pprint(info)
{'path': 'zope.apidoc.doctest.Factory',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': 'zope/apidoc/doctest/Factory'}When factories are created by a directive, they can also be functions. In
those cases we just simply return the function path:>>> def factory():
...     pass# The testing framework does not set the __module__ correctly
>>> factory.__module__ = ‘__builtin__’>>> info = presentation.getViewFactoryData(factory)
>>> pprint(info)
{'path': '__builtin__.factory',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': '__builtin__/factory'}However, the function is rather unhelpful, since it will be the same for all
views that use that code path. For this reason the function keeps track of the
original factory component in a function attribute calledfactory:>>> factory.factory = Factory>>> info = presentation.getViewFactoryData(factory)
>>> pprint(info)
{'path': 'zope.apidoc.doctest.Factory',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': 'zope/apidoc/doctest/Factory'}Let’s now have a look at some extremly specific cases. If a view is registered
using thezope:viewdirective and a permission is specified, aProxyViewclass instance is created that references its original factory:>>> class ProxyView(object):
...
...     def __init__(self, factory):
...         self.factory = factory
>>> proxyView = ProxyView(Factory)>>> info = presentation.getViewFactoryData(proxyView)
>>> pprint(info)
{'path': 'zope.apidoc.doctest.Factory',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': 'zope/apidoc/doctest/Factory'}Another use case is when a new type is created by thebrowser:pageorbrowser:viewdirective. In those cases the true/original factory is really
the first base class. Those cases are detected by inspecting the__module__string of the type:>>> new_class = type(Factory.__name__, (Factory,), {})
>>> new_class.__module__ = 'zope.browserpage.viewmeta'>>> info = presentation.getViewFactoryData(new_class)
>>> pprint(info)
{'path': 'zope.apidoc.doctest.Factory',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': 'zope/apidoc/doctest/Factory'}The same sort of thing happens for XML-RPC views, except that those are
wrapped twice:>>> new_class = type(Factory.__name__, (Factory,), {})
>>> new_class.__module__ = 'zope.app.publisher.xmlrpc.metaconfigure'>>> new_class2 = type(Factory.__name__, (new_class,), {})
>>> new_class2.__module__ = 'zope.app.publisher.xmlrpc.metaconfigure'>>> info = presentation.getViewFactoryData(new_class2)
>>> pprint(info)
{'path': 'zope.apidoc.doctest.Factory',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': 'zope/apidoc/doctest/Factory'}Finally, it sometimes happens that a factory is wrapped and the wrapper is
wrapped in return:>>> def wrapper1(*args):
...     return Factory(*args)
>>> wrapper1.__module__ = None>>> def wrapper2(*args):
...     return wrapper1(*args)
>>> wrapper2.__module__ = NoneInitially, the documentation is not very helpful:>>> info = presentation.getViewFactoryData(wrapper2)
>>> pprint(info)
{'path': 'None.wrapper2',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': 'None/wrapper2'}However, if those wrappers play nicely, they provide a factory attribute each
step of the way …>>> wrapper1.factory = Factory
>>> wrapper2.factory = wrapper1and the result is finally our original factory:>>> info = presentation.getViewFactoryData(wrapper2)
>>> pprint(info)
{'path': 'zope.apidoc.doctest.Factory',
 'referencable': True,
 'resource': None,
 'template': None,
 'url': 'zope/apidoc/doctest/Factory'}getPresentationType(iface)In Zope 3, presentation types (i.e. browser, ftp, …) are defined through
their special request interface, such asIBrowserRequestorIFTPRequest. To complicate matters further, layer interfaces are used in
browser presentations to allow skinning. Layers extend any request type, but
most commonlyIBrowserRequest. This function inspects the request interface
of any presentation multi-adapter and determines its type, which is returned
in form of an interface.>>> from zope.apidoc.presentation import getPresentationType
>>> from zope.publisher.interfaces.http import IHTTPRequest
>>> from zope.publisher.interfaces.browser import IBrowserRequest>>> class ILayer1(IBrowserRequest):
...     pass>>> presentation.getPresentationType(ILayer1)
<InterfaceClass zope.publisher.interfaces.browser.IBrowserRequest>>>> class ILayer2(IHTTPRequest):
...     pass>>> presentation.getPresentationType(ILayer2)
<InterfaceClass zope.publisher.interfaces.http.IHTTPRequest>If the function cannot determine the presentation type, the interface itself
is returned:>>> from zope.interface import Interface
>>> class ILayer3(Interface):
...     pass>>> presentation.getPresentationType(ILayer3)
<InterfaceClass zope.apidoc.doctest.ILayer3>Note that more specific presentation types are considered first. For example,IBrowserRequestextendsIHTTPRequest, but it will always determine the
presentation type to be anIBrowserRequest.getViews(iface, type=IRequest)This function retrieves all available view registrations for a given interface
and presentation type. The default argument for the presentation type isIRequest, which will effectively return all views for the specified
interface.To see how this works, we first have to register some views:>>> class IFoo(Interface):
...     pass>>> from zope.component import provideAdapter
>>> provideAdapter(None, (IFoo, IHTTPRequest), Interface, name='foo')
>>> provideAdapter(None, (Interface, IHTTPRequest), Interface,
...                name='bar')
>>> provideAdapter(None, (IFoo, IBrowserRequest), Interface,
...                name='blah')Now let’s see what we’ve got. If we do not specify a type, all registrations
should be returned:>>> regs = list(presentation.getViews(IFoo))
>>> regs.sort()
>>> regs #doctest:+ELLIPSIS
[AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IBrowserRequest], Interface, 'blah', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [IFoo, IHTTPRequest], Interface, 'foo', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                     [Interface, IHTTPRequest], Interface, 'bar', None, u'')]>>> regs = list(presentation.getViews(Interface, IHTTPRequest))
>>> regs.sort()
>>> regs #doctest:+ELLIPSIS
[AdapterRegistration(<BaseGlobalComponents base>,
                     [Interface, IHTTPRequest], Interface, 'bar', None, u'')]filterViewRegistrations(regs, iface, level=SPECIFC_INTERFACE_LEVEL)Oftentimes the amount of views that are being returned for a particular
interface are too much to show at once. It is then good to split the view into
categories. ThefilterViewRegistrations()function allows you to filter the
views on how specific they are to the interface. Here are the three levels you
can select from:SPECIFC_INTERFACE_LEVEL – Only return registrations that require thespecified interface directly.EXTENDED_INTERFACE_LEVEL – Only return registrations that require aninterface that the specified interface extends.GENERIC_INTERFACE_LEVEL – Only return registrations that explicitelyrequire theInterfaceinterface.So, let’s see how this is done. We first need to create a couple of interfaces
and register some views:>>> class IContent(Interface):
...     pass
>>> class IFile(IContent):
...     passClear out the registries first, so we know what we have.
>>> from zope.testing.cleanup import cleanUp
>>> cleanUp()>>> provideAdapter(None, (IContent, IHTTPRequest), Interface,
...                name='view.html')
>>> provideAdapter(None, (IContent, IHTTPRequest), Interface,
...                name='edit.html')
>>> provideAdapter(None, (IFile, IHTTPRequest), Interface,
...                name='view.html')
>>> provideAdapter(None, (Interface, IHTTPRequest), Interface,
...                name='view.html')Now we get all the registrations:>>> regs = list(presentation.getViews(IFile, IHTTPRequest))Let’s now filter those registrations:>>> result = list(presentation.filterViewRegistrations(
...     regs, IFile, level=presentation.SPECIFIC_INTERFACE_LEVEL))
>>> result.sort()
>>> result
[AdapterRegistration(<BaseGlobalComponents base>,
                   [IFile, IHTTPRequest], Interface, 'view.html', None, u'')]>>> result = list(presentation.filterViewRegistrations(
...     regs, IFile, level=presentation.EXTENDED_INTERFACE_LEVEL))
>>> result.sort()
>>> result
[AdapterRegistration(<BaseGlobalComponents base>,
                [IContent, IHTTPRequest], Interface, 'edit.html', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                [IContent, IHTTPRequest], Interface, 'view.html', None, u'')]>>> result = list(presentation.filterViewRegistrations(
...     regs, IFile, level=presentation.GENERIC_INTERFACE_LEVEL))
>>> result.sort()
>>> result
[AdapterRegistration(<BaseGlobalComponents base>,
               [Interface, IHTTPRequest], Interface, 'view.html', None, u'')]You can also specify multiple levels at once using the Boolean OR operator,
since all three levels are mutually exclusive.>>> result = list(presentation.filterViewRegistrations(
...     regs, IFile, level=presentation.SPECIFIC_INTERFACE_LEVEL |
...                        presentation.EXTENDED_INTERFACE_LEVEL))
>>> result.sort()
>>> result
[AdapterRegistration(<BaseGlobalComponents base>,
                [IContent, IHTTPRequest], Interface, 'edit.html', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                [IContent, IHTTPRequest], Interface, 'view.html', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
                [IFile, IHTTPRequest], Interface, 'view.html', None, u'')]>>> result = list(presentation.filterViewRegistrations(
...     regs, IFile, level=presentation.SPECIFIC_INTERFACE_LEVEL |
...                        presentation.GENERIC_INTERFACE_LEVEL))
>>> result.sort()
>>> result
[AdapterRegistration(<BaseGlobalComponents base>,
              [IFile, IHTTPRequest], Interface, 'view.html', None, u''),
 AdapterRegistration(<BaseGlobalComponents base>,
              [Interface, IHTTPRequest], Interface, 'view.html', None, u'')]getViewInfoDictionary(reg)Now that we have all these utilities to select the registrations, we need to
prepare the them for output. For page templates the best data structures are
dictionaries and tuples/lists. This utility will generate an informational
dictionary for the specified registration.Let’s first create a registration:>>> from zope.component.registry import AdapterRegistration
>>> reg = AdapterRegistration(None, (IFile, Interface, IHTTPRequest),
...                           Interface, 'view.html', Factory, 'reg info')>>> pprint(presentation.getViewInfoDictionary(reg), width=1)
{'doc': 'reg info',
 'factory': {'path': 'zope.apidoc.doctest.Factory',
             'referencable': True,
             'resource': None,
             'template': None,
             'url': 'zope/apidoc/doctest/Factory'},
 'name': u'view.html',
 'provided': {'module': 'zope.interface',
              'name': 'Interface'},
 'read_perm': None,
 'required': [{'module': 'zope.apidoc.doctest',
               'name': 'IFile'},
              {'module': 'zope.interface',
               'name': 'Interface'},
              {'module': 'zope.publisher.interfaces.http',
               'name': 'IHTTPRequest'}],
 'type': 'zope.publisher.interfaces.http.IHTTPRequest',
 'write_perm': None,
 'zcml': None}Miscellaneous UtilitiesThe utilities module provides some useful helper functions and classes that
make the work of the API doctool and inspection code easier.>>> from zope.apidoc import utilitiesrelativizePath(path)When dealing with files, such as page templates and text files, and not with
Python paths, it is necessary to keep track of the the absolute path of the
file. However, for presentation purposes, the absolute path is inappropriate
and we are commonly interested in the path starting at the Zope 3 root
directory. This function attempts to remove the absolute path to the root
directory and replaces it with “Zope3”.>>> import os
>>> path = os.path.join(utilities.BASEDIR, 'src', 'zope', 'README.txt')>>> utilities.BASEDIR in path
True>>> path = utilities.relativizePath(path)>>> utilities.BASEDIR in path
False# Be kind to Windows users
>>> path.replace(’', ‘/’)
‘Zope3/src/zope/README.txt’If the base path is not found in a particular path, the original path is
returned:>>> otherpath = 'foo/bar/blah.txt'
>>> utilities.relativizePath(otherpath)
'foo/bar/blah.txt'truncateSysPath(path)In some cases it is useful to just know the path after the sys path of a
module. For example, you have a path of a file in a module. To look up the
module, the simplest to do is to retrieve the module path and look into the
system’s modules list.>>> import sys
>>> sysBase = sys.path[0]>>> utilities.truncateSysPath(sysBase + '/some/module/path')
'some/module/path'If there is no matching system path, then the whole path is returned:>>> utilities.truncateSysPath('some/other/path')
'some/other/path'getPythonPath(obj)Return the path of the object in standard Python dot-notation.This function makes only sense for objects that provide a name, since we
cannot determine the path otherwise. Instances, for example, do not have a__name__attribute, so we would expect them to fail.For interfaces we simply get>>> from zope.interface import Interface
>>> class ISample(Interface):
...     pass>>> utilities.getPythonPath(ISample)
'zope.apidoc.doctest.ISample'and for classes>>> class Sample(object):
...     def sample(self):
...         pass>>> utilities.getPythonPath(Sample.sample)
'zope.apidoc.doctest.Sample'One can also pass functions>>> def sample():
...     pass>>> utilities.getPythonPath(sample)
'zope.apidoc.doctest.sample'and even methods. If a method is passed in, its class path is returned.>>> utilities.getPythonPath(Sample.sample)
'zope.apidoc.doctest.Sample'Modules are another kind of objects that can return a python path:>>> utilities.getPythonPath(utilities)
'zope.apidoc.utilities'Passing inNonereturnsNone:>>> utilities.getPythonPath(None)Clearly, instance lookups should fail:>>> utilities.getPythonPath(Sample())
Traceback (most recent call last):
...
AttributeError: 'Sample' object has no attribute '__name__'isReferencable(path)Determine whether a path can be referenced in the API doc, usually by the code
browser module. Initially you might think that all objects that have paths can
be referenced somehow. But that’s not true, partially by design of apidoc, but
also due to limitations of the Python language itself.First, here are some cases that work:>>> utilities.isReferencable('zope')
True
>>> utilities.isReferencable('zope.app')
True
>>> utilities.isReferencable('zope.apidoc.classregistry.ClassRegistry')
True
>>> utilities.isReferencable('zope.apidoc.utilities.isReferencable')
TrueThe first case isNone. When you ask for the python path ofNone, you
getNone, so that result should not be referencable:>>> utilities.isReferencable(None)
FalseBy design we also do not document any private classes and functions:>>> utilities.isReferencable('some.path.to._Private')
False
>>> utilities.isReferencable('some.path.to.__Protected')
False
>>> utilities.isReferencable('zope.apidoc.__doc__')
TrueSome objects might fake their module name, so that it does not exist:>>> utilities.isReferencable('foo.bar')
FalseOn the other hand, you might have a valid module, but non-existent attribute:>>> utilities.isReferencable('zope.apidoc.MyClass')
FalseNote that this case is also used for types that are generated using thetype()function:>>> mytype = type('MyType', (object,), {})
>>> path = utilities.getPythonPath(mytype)
>>> path
'zope.apidoc.doctest.MyType'>>> utilities.isReferencable(path)
FalseNext, since API doc does not allow the documentation of instances yet, it
is not possible to document singletons, so they are not referencable:>>> class Singelton(object):
...     pass>>> utilities.isReferencable('zope.apidoc.doctest.Singelton')
True>>> Singelton = Singelton()>>> utilities.isReferencable('zope.apidoc.doctest.Singelton')
FalseFinally, the globalIGNORE_MODULESlist from the class registry is also
used to give a negative answer. If a module is listed inIGNORE_MODULES,
thenFalseis returned.>>> import classregistry
>>> classregistry.IGNORE_MODULES.append('zope.apidoc')>>> utilities.isReferencable('zope.app')
True
>>> utilities.isReferencable('zope.apidoc')
False
>>> utilities.isReferencable('zope.apidoc.apidoc.APIDocumentation')
False>>> classregistry.IGNORE_MODULES.pop()
'zope.apidoc'
>>> utilities.isReferencable('zope.apidoc')
TruegetPermissionIds(name, checker=_marker, klass=_marker)Get the permissions of a class attribute. The attribute is specified by name.Either theklassor thecheckerargument must be specified. If the class
is specified, then the checker for it is looked up. Furthermore, this function
only works withINameBasedCheckercheckers. If another checker is found,Noneis returned for the permissions.We start out by defining the class and then the checker for it:>>> from zope.security.checker import Checker, defineChecker
>>> from zope.security.checker import CheckerPublic>>> class Sample(object):
...     attr = 'value'
...     attr3 = 'value3'>>> class Sample2(object):
...      pass>>> checker = Checker({'attr': 'zope.Read', 'attr3': CheckerPublic},
...                   {'attr': 'zope.Write', 'attr3': CheckerPublic})
>>> defineChecker(Sample, checker)Now let’s see how this function works:>>> entries = utilities.getPermissionIds('attr', klass=Sample)
>>> entries['read_perm']
'zope.Read'
>>> entries['write_perm']
'zope.Write'>>> from zope.security.checker import getCheckerForInstancesOf
>>> entries = utilities.getPermissionIds('attr',
...                                      getCheckerForInstancesOf(Sample))
>>> entries['read_perm']
'zope.Read'
>>> entries['write_perm']
'zope.Write'TheSampleclass does not know about theattr2attribute:>>> entries = utilities.getPermissionIds('attr2', klass=Sample)
>>> print entries['read_perm']
n/a
>>> print entries['write_perm']
n/aTheSample2class does not have a checker:>>> entries = utilities.getPermissionIds('attr', klass=Sample2)
>>> entries['read_perm'] is None
True
>>> print entries['write_perm'] is None
TrueFinally, theSampleclass’attr3attribute is public:>>> entries = utilities.getPermissionIds('attr3', klass=Sample)
>>> print entries['read_perm']
zope.Public
>>> print entries['write_perm']
zope.PublicgetFunctionSignature(func)Return the signature of a function or method. Thefuncargumentmustbe a
generic function or a method of a class.First, we get the signature of a function that has a specific positional and
keyword argument:>>> def func(attr, attr2=None):
...     pass
>>> utilities.getFunctionSignature(func)
'(attr, attr2=None)'Here is a function that has an unspecified amount of keyword arguments:>>> def func(attr, **kw):
...     pass
>>> utilities.getFunctionSignature(func)
'(attr, **kw)'And here we mix specified and unspecified keyword arguments:>>> def func(attr, attr2=None, **kw):
...     pass
>>> utilities.getFunctionSignature(func)
'(attr, attr2=None, **kw)'In the next example we have unspecified positional and keyword arguments:>>> def func(*args, **kw):
...     pass
>>> utilities.getFunctionSignature(func)
'(*args, **kw)'And finally an example, where we have on unspecified keyword arguments without
any positional arguments:>>> def func(**kw):
...     pass
>>> utilities.getFunctionSignature(func)
'(**kw)'Next we test whether the signature is correctly determined for class
methods. Note that theselfargument is removed from the signature, since it
is not essential for documentation.We start out with a simple positional argument:>>> class Klass(object):
...     def func(self, attr):
...         pass
>>> utilities.getFunctionSignature(Klass.func)
'(attr)'Next we have specific and unspecified positional arguments as well as
unspecified keyword arguments:>>> class Klass(object):
...     def func(self, attr, *args, **kw):
...         pass
>>> utilities.getFunctionSignature(Klass.func)
'(attr, *args, **kw)'If you do not pass a function or method to the function, it will fail:>>> utilities.getFunctionSignature('func')
Traceback (most recent call last):
...
TypeError: func must be a function or methodA very uncommon, but perfectly valid, case is that tuple arguments are
unpacked inside the argument list of the function. Here is an example:>>> def func((arg1, arg2)):
...     pass
>>> utilities.getFunctionSignature(func)
'((arg1, arg2))'Even default assignment is allowed:>>> def func((arg1, arg2)=(1, 2)):
...     pass
>>> utilities.getFunctionSignature(func)
'((arg1, arg2)=(1, 2))'However, lists of this type are not allowed inside the argument list:>>> def func([arg1, arg2]):
...     pass
Traceback (most recent call last):
...
SyntaxError: invalid syntaxInternal assignment is also not legal:>>> def func((arg1, arg2=1)):
...     pass
Traceback (most recent call last):
...
SyntaxError: invalid syntaxgetPublicAttributes(obj)Return a list of public attribute names for a given object.This excludes any attribute starting with ‘_’, which includes attributes of
the form__attr__, which are commonly considered public, but they are so
special that they are excluded. Theobjargument can be either a classic
class, type or instance of the previous two. Note that the term “attributes”
here includes methods and properties.First we need to create a class with some attributes, properties and methods:>>> class Nonattr(object):
...     def __get__(*a):
...         raise AttributeError('nonattr')>>> class Sample(object):
...     attr = None
...     def __str__(self):
...         return ''
...     def func(self):
...         pass
...     def _getAttr(self):
...         return self.attr
...     attr2 = property(_getAttr)
...
...     nonattr = Nonattr() # Should not show up in public attrsWe can simply pass in the class and get the public attributes:>>> attrs = utilities.getPublicAttributes(Sample)
>>> attrs.sort()
>>> attrs
['attr', 'attr2', 'func']Note that we exclude attributes that would raise attribute errors,
like our silly Nonattr.But an instance of that class will work as well.>>> attrs = utilities.getPublicAttributes(Sample())
>>> attrs.sort()
>>> attrs
['attr', 'attr2', 'func']The function will also take inheritance into account and return all inherited
attributes as well:>>> class Sample2(Sample):
...     attr3 = None>>> attrs = utilities.getPublicAttributes(Sample2)
>>> attrs.sort()
>>> attrs
['attr', 'attr2', 'attr3', 'func']getInterfaceForAttribute(name, interfaces=_marker, klass=_marker, asPath=True)Determine the interface in which an attribute is defined. This function is
nice, if you have an attribute name which you retrieved from a class and want
to know which interface requires it to be there.Either theinterfacesorklassargument must be specified. Ifinterfacesis not specified, theklassis used to retrieve a list of
interfaces.interfacesmust be iterable.asPathspecifies whether the dotted name of the interface or the interface
object is returned.First, we need to create some interfaces and a class that implements them:>>> from zope.interface import Interface, Attribute, implements
>>> class I1(Interface):
...     attr = Attribute('attr')>>> class I2(I1):
...     def getAttr():
...         '''get attr'''>>> class Sample(object):
...     implements(I2)First we check whether an aatribute can be found in a list of interfaces:>>> utilities.getInterfaceForAttribute('attr', (I1, I2), asPath=False)
<InterfaceClass zope.apidoc.doctest.I1>
>>> utilities.getInterfaceForAttribute('getAttr', (I1, I2), asPath=False)
<InterfaceClass zope.apidoc.doctest.I2>Now we are repeating the same lookup, but using the class, instead of a list
of interfaces:>>> utilities.getInterfaceForAttribute('attr', klass=Sample, asPath=False)
<InterfaceClass zope.apidoc.doctest.I1>
>>> utilities.getInterfaceForAttribute('getAttr', klass=Sample, asPath=False)
<InterfaceClass zope.apidoc.doctest.I2>By default,asPathisTrue, which means the path of the interface is
returned:>>> utilities.getInterfaceForAttribute('attr', (I1, I2))
'zope.apidoc.doctest.I1'If no match is found,Noneis returned.>>> utilities.getInterfaceForAttribute('attr2', (I1, I2)) is None
True
>>> utilities.getInterfaceForAttribute('attr2', klass=Sample) is None
TrueIf both, theinterfacesandklassargument are missing, raise an error:>>> utilities.getInterfaceForAttribute('getAttr')
Traceback (most recent call last):
...
ValueError: need to specify interfaces or klassSimilarly, it does not make sense if both are specified:>>> utilities.getInterfaceForAttribute('getAttr', interfaces=(I1,I2),
...                                    klass=Sample)
Traceback (most recent call last):
...
ValueError: must specify only one of interfaces and klasscolumnize(entries, columns=3)This function places a list of entries into columns.Here are some examples:>>> utilities.columnize([1], 3)
[[1]]>>> utilities.columnize([1, 2], 3)
[[1], [2]]>>> utilities.columnize([1, 2, 3], 3)
[[1], [2], [3]]>>> utilities.columnize([1, 2, 3, 4], 3)
[[1, 2], [3], [4]]>>> utilities.columnize([1], 2)
[[1]]>>> utilities.columnize([1, 2], 2)
[[1], [2]]>>> utilities.columnize([1, 2, 3], 2)
[[1, 2], [3]]>>> utilities.columnize([1, 2, 3, 4], 2)
[[1, 2], [3, 4]]getDocFormat(module)This function inspects a module to determine the supported documentation
format. The function returns a valid renderer source factory id.If the__docformat__module attribute is specified, its value will be used
to look up the factory id:>>> from zope.apidoc import utilities
>>> utilities.getDocFormat(utilities)
'zope.source.rest'By default structured text is returned:>>> from zope.apidoc import tests
>>> utilities.getDocFormat(tests)
'zope.source.stx'This is a sensible default, since we only decided later in development to
endorse restructured text, so that many files are still in the structured text
format. All converted and new modules will have the__docformat__attribute.The__docformat__attribute can also optionally specify a language field. We
simply ignore it:>>> class Module(object):
...     pass
>>> module = Module()
>>> module.__docformat__ = 'restructuredtext en'
>>> utilities.getDocFormat(module)
'zope.source.rest'dedentString(text)Before doc strings can be processed using STX or ReST they must be dendented,
since otherwise the output will be incorrect. Let’s have a look at some
docstrings and see how they are correctly dedented.Let’s start with a simple one liner. Nothing should happen:>>> def func():
...     '''One line documentation string'''>>> utilities.dedentString(func.__doc__)
'One line documentation string'Now what about one line docstrings that start on the second line? While this
format is discouraged, it is frequently used:>>> def func():
...     '''
...     One line documentation string
...     '''>>> utilities.dedentString(func.__doc__)
'\nOne line documentation string\n'We can see that the leading whitespace on the string is removed, but not the
newline character. Let’s now try a simple multi-line docstring:>>> def func():
...     '''Short description
...
...     Lengthy description, giving some more background information and
...     discuss some edge cases.
...     '''>>> print utilities.dedentString(func.__doc__)
Short description
<BLANKLINE>
Lengthy description, giving some more background information and
discuss some edge cases.
<BLANKLINE>Again, the whitespace was removed only after the first line. Also note that
the function determines the indentation level correctly. So what happens if
there are multiple indentation levels? The smallest amount of indentation is
chosen:>>> def func():
...     '''Short description
...
...     Root Level
...
...       Second Level
...     '''>>> print utilities.dedentString(func.__doc__)
Short description
<BLANKLINE>
Root Level
<BLANKLINE>
  Second Level
<BLANKLINE>>>> def func():
...     '''Short description
...
...       $$$ print 'example'
...       example
...
...     And now the description.
...     '''>>> print utilities.dedentString(func.__doc__)
Short description
<BLANKLINE>
  $$$ print 'example'
  example
<BLANKLINE>
And now the description.
<BLANKLINE>renderText(text, module=None, format=None)A function that quickly renders the given text using the specified format.If themoduleargument is specified, the function will try to determine the
format using the module. If theformatargument is given, it is simply
used. Clearly, you cannot specify both, themoduleandformatargument.You specify the format as follows:>>> utilities.renderText('Hello!\n', format='zope.source.rest')
u'<p>Hello!</p>\n'Note that the format string must be a valid source factory id; if the factory
id is not given, ‘zope.source.stx’ is used. Thus, specifying the module is
often safer (if available):>>> utilities.renderText('Hello!\n', module=utilities)
u'<p>Hello!</p>\n'The Class RegistryThis little registry allows us to quickly query a complete list of classes
that are defined and used by Zope 3. The prime feature of the class is thegetClassesThatImplement(iface)method that returns all classes that
implement the passed interface. Another method,getSubclassesOf(klass)returns all registered subclassess of the given class.The class registry, subclassing the dictionary type, can be instantiated like
any other dictionary:>>> from zope.apidoc.classregistry import ClassRegistry
>>> reg = ClassRegistry()Let’s now add a couple of classes to registry. The classes should implement
some interfaces, so that we can test all methods on the class registry:>>> from zope.interface import Interface, implements>>> class IA(Interface):
...      pass
>>> class IB(IA):
...      pass
>>> class IC(Interface):
...      pass
>>> class ID(Interface):
...      pass>>> class A(object):
...    implements(IA)
>>> reg['A'] = A>>> class B:
...    implements(IB)
>>> reg['B'] = B>>> class B2(object):
...    implements(IB)
>>> reg['B2'] = B2>>> class C(object):
...    implements(IC)
>>> reg['C'] = C
>>> class A2(A):
...    pass
>>> reg['A2'] = A2Since the registry is just a dictionary, we can ask for all its keys, which
are the names of the classes:>>> names = reg.keys()
>>> names.sort()
>>> names
['A', 'A2', 'B', 'B2', 'C']>>> reg['A'] is A
TrueThere are two API methods specific to the class registry:getClassesThatImplement(iface)This method returns all classes that implement the specified interface:>>> from pprint import pprint
>>> pprint(reg.getClassesThatImplement(IA)) #doctest:+ELLIPSIS
[('A', <class 'A'>),
 ('B', <class __builtin__.B at ...>),
 ('A2', <class 'A2'>),
 ('B2', <class 'B2'>)]>>> pprint(reg.getClassesThatImplement(IB)) #doctest:+ELLIPSIS
[('B', <class __builtin__.B at ...>),
 ('B2', <class 'B2'>)]>>> pprint(reg.getClassesThatImplement(IC))
[('C', <class 'C'>)]>>> pprint(reg.getClassesThatImplement(ID))
[]getSubclassesOf(klass)This method will find all classes that inherit the specified class:>>> pprint(reg.getSubclassesOf(A))
[('A2', <class 'A2'>)]>>> pprint(reg.getSubclassesOf(B))
[]Safe ImportsUsing thesafe_import()we can quickly look up modules by minimizing
import calls.>>> from zope.apidoc import classregistry
>>> from zope.apidoc.classregistry import safe_importFirst we try to find the path insys.modules, since this lookup is much
more efficient than importing it. If it was not found, we go back and try
to import the path. For security reasons, importing new modules is disabled by
default, unless the global__import_unknown_modules__variable is set to
true. If that also fails, we return thedefaultvalue.Here are some examples:>>> import sys
>>> 'zope' in sys.modules
True

>>> safe_import('zope') is sys.modules['zope']
True

>>> safe_import('weirdname') is None
TrueFor this example, we’ll create a dummy module:>>> import os
>>> import tempfile
>>> dir = tempfile.mkdtemp()
>>> filename = os.path.join(dir, 'testmodule.py')
>>> sys.path.insert(0, dir)
>>> f = open(filename, 'w')
>>> f.write('# dummy module\n')
>>> f.close()The temporary module is not already imported:>>> module_name = 'testmodule'
>>> module_name in sys.modules
FalseWhen we trysafe_import()now, we will still get thedefaultvalue,
because importing new modules is disabled by default:>>> safe_import(module_name) is None
TrueBut once we activate the__import_unknown_modules__hook, the module
should be imported:>>> classregistry.__import_unknown_modules__ = True>>> safe_import(module_name).__name__ == module_name
True
>>> module_name in sys.modules
TrueNow clean up the temporary module, just to play nice:>>> del sys.modules[module_name]Importing some code we cannot control, such as twisted, might raise errors
when imported without having a certain environment. In those cases, the safe
import should prevent the error from penetrating:>>> open(os.path.join(dir, 'alwaysfail.py'), 'w').write('raise ValueError\n')
>>> sys.path.insert(0, dir)>>> safe_import('alwaysfail') is None
TrueLet’s clean up the python path and temporary files:>>> del sys.path[0]
>>> import shutil
>>> shutil.rmtree(dir)Another method to explicitely turning off the import of certain modules is to
declare that they should be ignored. For example, if we tell the class
registry to ignorezope,>>> classregistry.IGNORE_MODULES.append('zope')then we cannot import it anymore, even though we know it is available:>>> safe_import('zope') is None
TrueNote that all sub-packages are also unavailable:>>> safe_import('zope.apidoc') is None
TrueWe also need to play nice concerning variables and have to reset the module
globals:>>> classregistry.IGNORE_MODULES.pop()
'zope'
>>> classregistry.__import_unknown_modules__ = FalseCHANGES1.0.0 (2013-02-25)Initial release independent ofzope.app.api.