Code Documentation Module¶
The code documentation module package
>>> from zope.app.apidoc import codemodule
provides systematic and autogenerated documentation about the content of your Zope 3 related Python packages. The code module can be created like this:
>>> cm = codemodule.codemodule.CodeModule()
>>> cm.getDocString()
'Zope 3 root.'
This object extends the
zope.app.apidoc.codemodule.module.Module
class, since it can
be seen as some sort of root package. However, its sementacs are
obviously a bit different:
>>> cm.getFileName()
''
>>> cm.getPath()
''
>>> cm.isPackage()
True
>>> sorted(cm.keys())
['BTrees', 'ZConfig', 'ZODB', 'builtins', 'persistent', 'transaction', ...]
Module¶
The module.Module
class represents a Python module or package
in the documentation tree. It can be easily setup by simply passing
the parent module, the module name (not the entire Python path) and
the Python module instance itself:
>>> import zope.app.apidoc
>>> module = codemodule.module.Module(None, 'apidoc', zope.app.apidoc)
We can now get some of the common module attributes via accessor methods:
>>> module.getDocString() is None
True
>>> fname = module.getFileName()
>>> fname = fname.replace('\\', '/') # Fix for Windows users
>>> 'zope/app/apidoc/__init__.py' in fname
True
>>> module.getPath()
'zope.app.apidoc'
>>> module.isPackage()
True
>>> m2 = codemodule.module.Module(
... None, 'apidoc', zope.app.apidoc.apidoc)
>>> m2.isPackage()
False
The setup for creating the sub module and class tree is automatically called during initialization, so that the sub-objects are available as soon as you have the object:
>>> keys = module.keys()
>>> 'codemodule' in keys
True
>>> 'meta.zcml' in keys
True
>>> import zope.app.apidoc.browser
>>> print(module['browser'].getPath())
zope.app.apidoc.browser
Now, the module.Module.get()
is actually much smarter than you might
originally suspect, since it can actually get to more objects than it
promises. If a key is not found in the module’s children, it tries to
import the key as a module relative to this module.
For example, while tests
directories are not added to the module and
classes hierarchy (since they do not provide or implement any API), we can
still get to them:
>>> import zope.app.apidoc.tests
>>> print(module['tests'].getPath())
zope.app.apidoc.tests
>>> names = sorted(module['tests'].keys())
>>> names
['BrowserTestCase', 'LayerDocFileSuite', 'LayerDocTestSuite', 'Root', ...]
Classes¶
Setting up a class for documentation is not much harder. You only need to
provide an object providing IModule
as a parent, the name and the klass
itself:
>>> import zope.app.apidoc.apidoc
>>> module = codemodule.module.Module(
... None, 'apidoc', zope.app.apidoc.apidoc)
>>> klass = codemodule.class_.Class(module, 'APIDocumentation',
... zope.app.apidoc.apidoc.APIDocumentation)
This class provides data about the class in an accessible format. The Python path and doc string are easily retrieved using:
>>> klass.getPath()
'zope.app.apidoc.apidoc.APIDocumentation'
>>> "The collection of all API documentation" in klass.getDocString()
True
A list of base classes can also be retrieved. The list only includes
direct bases, so if we have class Blah
, which extends Bar
, which
extends Foo
, then the base of Blah
is just Bar
. In our example this
looks like this:
>>> klass.getBases()
(<class 'zope.app.apidoc.utilities.ReadContainerBase'>,)
In the other direction, you can get a list of known subclasses. The list
only includes those subclasses that are registered with the global
zope.app.apidoc.classregistry.classRegistry
dictionary. In our example:
>>> class APIDocSubclass(zope.app.apidoc.apidoc.APIDocumentation):
... pass
>>> klass2 = codemodule.class_.Class(module, 'APIDocSubclass', APIDocSubclass)
>>> klass.getKnownSubclasses()
[<class 'APIDocSubclass'>]
For a more detailed analysis, you can also retrieve the public attributes and methods of this class:
>>> klass.getAttributes()
[]
>>> klass.getMethods()[0]
('get', <function APIDocumentation.get at ...>,
<InterfaceClass zope.interface.common.mapping.IReadMapping>)
>>> klass.getConstructor()
<function APIDocumentation.__init__ at ...>
Let’s have a closer look at the class_.Class.getAttributes()
method. First we create an
interface called IBlah
that is implemented by the class Blah
:
>>> import zope.interface
>>> class IBlie(zope.interface.Interface):
... bli = zope.interface.Attribute('Blie')
>>> class IBlah(IBlie):
... foo = zope.interface.Attribute('Foo')
>>> @zope.interface.implementer(IBlah)
... class Blah(object):
... foo = 'f'
... bar = 'b'
... bli = 'i'
... _blah = 'l'
The Blah
class also implements a public and private attribute that is not
listed in the interface. Now we create the class documentation wrapper:
>>> klass = codemodule.class_.Class(module, 'Blah', Blah)
>>> from pprint import pprint
>>> pprint(klass.getAttributes())
[('bar', 'b', None),
('bli', 'i', <InterfaceClass builtins.IBlie>),
('foo', 'f', <InterfaceClass builtins.IBlah>)]
So, the function returns a list of tuples of the form (name, value,
interface), where the interface is the interface in which the attribute was
declared. The interface is None
, if the attribute was not declared. Also
note that attributes starting with an underscore are ignored.
Let’s now have a look at how methods are looked up returned. So we create a
new IBlah
interface, this time describing methods, and then its
implementation Blah
, which has some other additional methods:
>>> class IBlah(zope.interface.Interface):
... def foo(): pass
>>> @zope.interface.implementer(IBlah)
... class Blah(object):
...
...
... def foo(self):
... pass
... def bar(self):
... pass
... def _blah(self):
... pass
Now we create the class documentation wrapper:
>>> klass = codemodule.class_.Class(module, 'Blah', Blah)
and get the method documentation:
>>> pprint(klass.getMethods())
[('bar', <function Blah.bar at ...>, None),
('foo', <function Blah.foo at ...>, <InterfaceClass builtins.IBlah>)]
Function¶
Functions are pretty much documented in the same way as all other code
documentation objects and provides a similar API to the classes. A
function documentation object
is quickly
created:
>>> func = codemodule.function.Function(
... module, 'handleNamespace',
... zope.app.apidoc.apidoc.handleNamespace)
This class provides data about the function in an accessible format. The Python path, signature and doc string are easily retrieved using:
>>> func.getPath()
'zope.app.apidoc.apidoc.handleNamespace'
>>> func.getSignature()
'(ob, name)'
>>> func.getDocString()
'Used to traverse to an API Documentation.'
For a more detailed analysis, you can also retrieve the attributes of the function
>>> func.getAttributes()
[]
but this function has none as most functions. So let’s create a new function
>>> def foo(bar=1):
... pass
>>> func = codemodule.function.Function(module, 'foo', foo)
which originally does not have any attributes
>>> func.getAttributes()
[]
but if we add an attribute, it will be listed:
>>> foo.blah = 1
>>> func.getAttributes()
[('blah', 1)]
Text File¶
Text files
represent plain-text documentation
files like this one. Once we have a text file documentation object
>>> import os
>>> path = os.path.join(os.path.dirname(codemodule.__file__), 'README.rst')
>>> readme = codemodule.text.TextFile(path, 'README.rst', module)
we can ask it for the content of the file:
>>> "Code Documentation Module" in readme.getContent()
True
ZCML File¶
ZCML file documentation objects
present
configuration files and parse the file content to provide some
advanced markup. The object is easily instantiated:
>>> path = os.path.join(os.path.dirname(codemodule.__file__),
... 'configure.zcml')
>>> module = codemodule.module.Module(None, 'zope.app.apidoc.codemodule',
... zope.app.apidoc.codemodule)
>>> zcml = codemodule.zcml.ZCMLFile(path, module, module, 'configure.zcml')
The interesting attribute of the object is the rootElement
, since it
contains the root XML element and thus the entire XML tree. The rootElement
attribute is a lazy property, so that it is not loaded until accessed for the
first time:
>>> root = zcml.rootElement
>>> root
<Directive ('http://namespaces.zope.org/zope', 'configure')>
A directive component has some interesting atrributes, such as the name,
>>> root.name
('http://namespaces.zope.org/zope', 'configure')
the schema that describes the directive,
>>> root.schema
<InterfaceClass zope.configuration.zopeconfigure.IZopeConfigure>
the attributes of the XML element,
>>> dict(root.attrs)
{}
the configuration context for the directive, which can be used to resolve objects and/or generate absolute paths of files,
>>> root.context
<zope.configuration.config.ConfigurationMachine object at ...>
the parser info object,
>>> info = repr(root.info)
>>> info = info.replace('\\', '/') # Windows fix
>>> print(info)
File ".../zope/app/apidoc/codemodule/configure.zcml", ...
the sub-directives,
>>> root.subs[:2]
[<Directive ('http://namespaces.zope.org/zope', 'class')>,
<Directive ('http://namespaces.zope.org/zope', 'class')>]
and finally a list of all prefixes.
>>> pprint(root.prefixes)
{'http://namespaces.zope.org/apidoc': 'apidoc',
'http://namespaces.zope.org/browser': 'browser',
'http://namespaces.zope.org/zope': None}