What is zope.app.apidoc?¶
This 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.
Documentation is available at https://zopeappapidoc.readthedocs.io/
Overview¶
This 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.
Using the API Dcoumentation¶
The APIDocumentation
class provides
access to all available documentation modules. Documentation modules
are utilities providing IDocumentationModule
:
>>> from zope import component as ztapi
>>> from zope.app.apidoc.interfaces import IDocumentationModule
>>> from zope.app.apidoc.ifacemodule.ifacemodule import InterfaceModule
>>> from zope.app.apidoc.zcmlmodule import ZCMLModule
>>> ztapi.provideUtility(InterfaceModule(), IDocumentationModule,
... 'Interface')
>>> ztapi.provideUtility(ZCMLModule(), IDocumentationModule, 'ZCML')
Now we can instantiate the class (which is usually done when traversing ‘++apidoc++’) and get a list of available modules:
>>> from zope.app.apidoc.apidoc import APIDocumentation
>>> doc = APIDocumentation(None, '++apidoc++')
>>> modules = sorted(doc.keys())
>>> modules
[u'Interface', u'ZCML']
>>> doc['ZCML']
<zope.app.apidoc.zcmlmodule.ZCMLModule 'ZCML' at ...>
Developing a Module¶
Implement a class that realizes the
IDocumentationModule
interface.Register this class as a utility using something like this:
<utility provides="zope.app.apidoc.interfaces.IDocumentationModule" factory=".examplemodule.ExampleModule" name="Example" />
Take care of security by allowing at least
IDocumentationModule
:<class class=".ExampleModule"> <allow interface="zope.app.apidoc.interfaces.IDocumentationModule" /> </class>
Provide a browser view called
menu.html
.Provide another view, usually
index.html
, that can show the details for the various menu items.
Note: There are several modules that come with the product. Just look in them for some guidance.
New Static APIDOC-Version¶
An alternative APIDOC-Version is available through ++apidoc++/static.html
Find and Tree are implemented in Javascript, so it should be possible to do a
“wget” - Offline-Version of APIDOC.
In fact, this package comes with a somewhat smarter version of “wget” that can load a Zope configuration and export the documentation. For more information, see Exporting Static HTML Documentation.
Exporting Static HTML Documentation¶
This package comes with a utility that can be used to create a static on-disk export of all the accessible documentation for an instance.
It is installed as the static-apidoc
command, or it can be used
with python -m zope.app.apidoc.static
.
$ python -m zope.app.apidoc.static --help
/home/docs/checkouts/readthedocs.org/user_builds/zopeappapidoc/envs/issue10/bin/python: No module named app.apidoc
API Reference¶
APIDoc¶
Zope 3 API Documentation
-
class
zope.app.apidoc.apidoc.
APIDocumentation
(parent, name)[source]¶ Bases:
zope.app.apidoc.utilities.ReadContainerBase
The collection of all API documentation.
This documentation is implemented using a simply
IReadContainer
. The items of the container are all registered utilities forIDocumentationModule
.-
get
(key, default=None)[source]¶ Look up an
IDocumentationModule
utility with the given name.If found, a copy of the utility with this object as its parent, created by
withParentAndName()
, will be returned.
-
items
()[source]¶ Return a sorted list of (name, utility) pairs for all registered
IDocumentationModule
objects.Each utility returned will be a child of this object created with
withParentAndName()
.
-
-
class
zope.app.apidoc.apidoc.
apidocNamespace
(ob, request=None)[source]¶ Bases:
object
Used to traverse to an API Documentation.
Instantiating this object with a request will apply the
zope.app.apidoc.browser.skin.APIDOC
skin automatically.
Class Registry¶
Class Registry
-
class
zope.app.apidoc.classregistry.
ClassRegistry
[source]¶ Bases:
dict
A simple registry for classes.
-
zope.app.apidoc.classregistry.
classRegistry
= {}¶ The global class registry object. Cleaned up in tests by
zope.testing.cleanup
.
Component¶
Component Inspection Utilities
-
zope.app.apidoc.component.
getRequiredAdapters
(iface, withViews=False)[source]¶ Get global adapter registrations where the specified interface is required.
-
zope.app.apidoc.component.
getProvidedAdapters
(iface, withViews=False)[source]¶ Get global adapter registrations where this interface is provided.
-
zope.app.apidoc.component.
filterAdapterRegistrations
(regs, iface, level=1)[source]¶ Return only those registrations that match the specifed level
-
zope.app.apidoc.component.
getFactories
(iface)[source]¶ Return the global factory registrations, who will return objects providing this interface.
-
zope.app.apidoc.component.
getUtilities
(iface)[source]¶ Return all global utility registrations that provide the interface.
-
zope.app.apidoc.component.
getRealFactory
(factory)[source]¶ Get the real factory.
Sometimes the original factory is masked by functions. If the function keeps track of the original factory, use it.
-
zope.app.apidoc.component.
getParserInfoInfoDictionary
(info)[source]¶ Return a PT-friendly info dictionary for a parser info object.
-
zope.app.apidoc.component.
getInterfaceInfoDictionary
(iface)[source]¶ Return a PT-friendly info dictionary for an interface.
-
zope.app.apidoc.component.
getTypeInfoDictionary
(type)[source]¶ Return a PT-friendly info dictionary for a type.
-
zope.app.apidoc.component.
getSpecificationInfoDictionary
(spec)[source]¶ Return an info dictionary for one specification.
-
zope.app.apidoc.component.
getAdapterInfoDictionary
(reg)[source]¶ Return a PT-friendly info dictionary for an adapter registration.
-
zope.app.apidoc.component.
getFactoryInfoDictionary
(reg)[source]¶ Return a PT-friendly info dictionary for a factory.
-
zope.app.apidoc.component.
getUtilityInfoDictionary
(reg)[source]¶ Return a PT-friendly info dictionary for a factory.
Stubs for when documentation is disabled.
Interface¶
Interface Inspection Utilities
-
zope.app.apidoc.interface.
getElements
(iface, type=<InterfaceClass zope.interface.interfaces.IElement>)[source]¶ Return a dictionary containing the elements in an interface.
The type specifies whether we are looking for attributes or methods.
-
zope.app.apidoc.interface.
getFieldsInOrder
(iface, _itemkey=<function <lambda>>)[source]¶ Return a list of (name, field) tuples in native interface order.
-
zope.app.apidoc.interface.
getAttributes
(iface)[source]¶ Returns a list of attributes specified in the interface.
-
zope.app.apidoc.interface.
getMethods
(iface)[source]¶ Returns a list of methods specified in the interface.
-
zope.app.apidoc.interface.
getFields
(iface)[source]¶ Returns a list of fields specified in the interface.
-
zope.app.apidoc.interface.
getInterfaceTypes
(iface)[source]¶ Return a list of interface types that are specified for this interface.
Note that you should only expect one type at a time.
-
zope.app.apidoc.interface.
getFieldInterface
(field)[source]¶ Return the interface representing the field.
-
zope.app.apidoc.interface.
getAttributeInfoDictionary
(attr, format=None)[source]¶ Return a page-template-friendly information dictionary.
Interfaces¶
Generic API Documentation Interfaces
-
interface
zope.app.apidoc.interfaces.
IDocumentationModule
[source]¶ Extends:
zope.location.interfaces.ILocation
Zope 3 API Documentation Module
A documentation module contains the documentation for one specific aspect of the framework, such as ZCML directives or interfaces.
The interface is used to register module as utilities.
-
title
¶ Title
The title of the documentation module.
-
description
¶ Module Description
This text describes the functionality of the module.
-
withParentAndName
(parent, name)¶ Return a new object that is a copy of this object, but being located at the given parent and name.
-
Presentation¶
Views/Presentation Utilities
-
zope.app.apidoc.presentation.
getViewFactoryData
(factory)[source]¶ Squeeze some useful information out of the view factory
-
zope.app.apidoc.presentation.
getPresentationType
(iface)[source]¶ Get the presentation type from a layer interface.
-
zope.app.apidoc.presentation.
getViews
(iface, type=<InterfaceClass zope.publisher.interfaces.IRequest>)[source]¶ Get all view registrations for a particular interface.
Static¶
Retrieve Static APIDOC
Utilities¶
Utilties to make the life of Documentation Modules easier.
-
zope.app.apidoc.utilities.
truncateSysPath
(path)[source]¶ Remove the system path prefix from the path.
-
class
zope.app.apidoc.utilities.
ReadContainerBase
[source]¶ Bases:
object
Base for
zope.container.interfaces.IReadContainer
objects.
-
class
zope.app.apidoc.utilities.
DocumentationModuleBase
[source]¶ Bases:
zope.app.apidoc.utilities.ReadContainerBase
Support for implementing a documentation module.
-
zope.app.apidoc.utilities.
getPythonPath
(obj)[source]¶ Return the path of the object in standard Python notation.
This method should try very hard to return a string, even if it is not a valid Python path.
-
zope.app.apidoc.utilities.
isReferencable
(path)[source]¶ Return whether the Python path is referencable.
-
zope.app.apidoc.utilities.
getPermissionIds
(name, checker=<object object>, klass=<object object>)[source]¶ Get the permissions of an attribute.
-
zope.app.apidoc.utilities.
getFunctionSignature
(func, ignore_self=False)¶ Return the signature of a function or method.
-
zope.app.apidoc.utilities.
getPublicAttributes
(obj)[source]¶ Return a list of public attribute names.
-
zope.app.apidoc.utilities.
getInterfaceForAttribute
(name, interfaces=<object object>, klass=<object object>, asPath=True)[source]¶ Determine the interface in which an attribute is defined.
-
zope.app.apidoc.utilities.
columnize
(entries, columns=3)[source]¶ Place a list of entries into columns.
Browser¶
Main API Documentation View
-
class
zope.app.apidoc.browser.apidoc.
APIDocumentationView
[source]¶ Bases:
object
View for the API Documentation
API Documentation macros
-
class
zope.app.apidoc.browser.macros.
APIDocumentationMacros
(context, request)[source]¶ Bases:
zope.app.basicskin.standardmacros.StandardMacros
Page Template METAL macros for API Documentation
-
macro_pages
= ('menu_macros', 'details_macros', 'static_menu_macros')¶ Macro pages
-
API Doc Preference Views
-
class
zope.app.apidoc.browser.preference.
APIDocPreferencesTree
(context, request)[source]¶ Bases:
zope.app.tree.browser.cookie.CookieTreeView
Preferences Tree using the stateful cookie tree.
APIdoc skin.
-
interface
zope.app.apidoc.browser.skin.
apidoc
[source]¶ Extends:
zope.publisher.interfaces.browser.IBrowserRequest
The apidoc layer.
-
interface
zope.app.apidoc.browser.skin.
APIDOC
[source]¶ Extends:
zope.app.apidoc.browser.skin.apidoc
,zope.publisher.interfaces.browser.IDefaultBrowserLayer
The APIDOC skin.
Common Utilities for Browser View
Book¶
Help books.
-
interface
zope.app.apidoc.bookmodule.book.
IBookModule
[source]¶ Extends:
zope.app.apidoc.interfaces.IDocumentationModule
Interface API Documentation Module
This is a marker interface, so that we can write adapters for objects implementing this interface.
-
class
zope.app.apidoc.bookmodule.book.
BookModule
(title, path)[source]¶ Bases:
zope.app.onlinehelp.onlinehelp.OnlineHelp
Represent a book compiled from various
README.rst|txt
and other*.rst|txt
documentation files.-
title
= u'Book'¶ Title.
-
description
= u"\n This is a developer's book compiled from all existing documentation\n files. It is not meant to be a complete or cohesive work, but each chapter\n in itself is a little story. Think about it like a collection of fairy\n tales.\n "¶ Description.
-
Configuration¶
Meta-Configuration Handlers for “apidoc:bookchapter” directive.
-
zope.app.apidoc.bookmodule.metaconfigure.
bookchapter
(_context, id, title, doc_path='/home/docs/checkouts/readthedocs.org/user_builds/zopeappapidoc/envs/issue10/lib/python2.7/site-packages/zope.app.apidoc-4.0.1.dev0-py2.7.egg/zope/app/apidoc/bookmodule/empty.txt', parent='', resources=None)[source]¶ Register a book chapter
Schema for the apidoc:bookchapter
directive
-
interface
zope.app.apidoc.bookmodule.metadirectives.
IBookChapterDirective
[source]¶ Register a new Book Chapter
-
id
¶ Topic Id
Id of the chapter as it will appear in the URL.
-
title
¶ Title
Provides a title for the chapter.
-
doc_path
¶ Path to File
Path to the file that contains the chapter content.
-
parent
¶ Parent Chapter
Id of the parent chapter.
-
resources
¶ A list of resources.
A list of resources which shall be user for the chapter. The resources must be located in the same directory as the chapter.
-
Browser¶
Browser Views for Book
-
class
zope.app.apidoc.bookmodule.browser.
Menu
[source]¶ Bases:
object
Menu View Helper Class
>>> class Chapter(object): ... title = 'Read Me' ... path = 'README.txt' ... ... def getTopicPath(self): ... return self.path[:-4]
>>> class Node(object): ... def __init__(self, context): ... self.context = context
>>> menu = Menu()
>>> chapter = Chapter() >>> node = Node(chapter) >>> menu.getMenuTitle(node) 'Read Me'
>>> menu.getMenuLink(node) 'README/show.html' >>> chapter.path = EMPTYPATH >>> menu.getMenuLink(node)
Code¶
Code Documentation Module
This module is able to take a dotted name of any class and display documentation for it.
-
class
zope.app.apidoc.codemodule.codemodule.
CodeModule
[source]¶ Bases:
zope.app.apidoc.codemodule.module.Module
Represent the code browser documentation root
Initialize object.
-
title
= u'Code Browser'¶ The title.
-
description
= u'\n This module allows you to get an overview of the modules and classes\n defined in the Zope 3 framework and its supporting packages. There are\n two methods to navigate through the modules to find the classes you are\n interested in.\n\n The first method is to type in some part of the Python path of the class\n and the module will look in the class registry for matches. The menu will\n then return with a list of these matches.\n\n The second method is to click on the "Browse Zope Source" link. In the\n main window, you will see a directory listing with the root Zope 3\n modules. You can click on the module names to discover their content. If a\n class is found, it is represented as a bold entry in the list.\n\n The documentation contents of a class provides you with an incredible\n amount of information. Not only does it tell you about its base classes,\n implemented interfaces, attributes and methods, but it also lists the\n interface that requires a method or attribute to be implemented and the\n permissions required to access it.\n '¶ The description.
-
Interfaces¶
Interfaces for code browser
-
interface
zope.app.apidoc.codemodule.interfaces.
IAPIDocRootModule
[source]¶ Marker interface for utilities that represent class browser root modules.
The utilities will be simple strings, representing the modules Python dotted name.
-
interface
zope.app.apidoc.codemodule.interfaces.
IModuleDocumentation
[source]¶ Extends:
zope.container.interfaces.IReadContainer
Representation of a Python module for documentation.
The items of the container are sub-modules and classes.
-
getDocString
()¶ Return the doc string of the module.
-
getFileName
()¶ Return the file name of the module.
-
getPath
()¶ Return the Python path of the module.
-
isPackage
()¶ Return true if this module is a Python package.
-
getDeclaration
()¶ Return the interfaces provided by the module.
The returned value provides zope.interface.interfaces.IDeclaration. To get the list of interfaces, iterate over the returned value. The list will be empty if the module does not provide any interfaces.
-
-
interface
zope.app.apidoc.codemodule.interfaces.
IClassDocumentation
[source]¶ Representation of a class or type for documentation.
-
getDocString
()¶ Return the doc string of the class.
-
getPath
()¶ Return the Python path of the class.
-
getBases
()¶ Return the base classes of the class.
-
getKnownSubclasses
()¶ Return the known subclasses classes of the class.
-
getInterfaces
()¶ Return the interfaces the class implements.
-
getAttributes
()¶ Return a list of 3-tuple attribute information.
The first entry of the 3-tuple is the name of the attribute, the second is the attribute object itself. The third entry is the interface in which the attribute is defined.
Note that only public attributes are returned, meaning only attributes that do not start with an ‘_’-character.
-
getMethods
()¶ Return a list of 3-tuple method information.
The first entry of the 3-tuple is the name of the method, the second is the method object itself. The third entry is the interface in which the method is defined.
Note that only public methods are returned, meaning only methods that do not start with an ‘_’-character.
-
getMethodDescriptors
()¶ Return a list of 3-tuple method descriptor information.
The first entry of the 3-tuple is the name of the method, the second is the method descriptor object itself. The third entry is the interface in which the method is defined.
Note that only public methods are returned, meaning only method descriptors that do not start with an ‘_’-character.
-
getSecurityChecker
()¶ Return the security checker for this class.
Since 99% of the time we are dealing with name-based security checkers, we can look up the get/set permission required for a particular class attribute/method.
-
getConstructor
()¶ Return the __init__ method, or None if there isn’t one.
-
-
interface
zope.app.apidoc.codemodule.interfaces.
IFunctionDocumentation
[source]¶ Representation of a function for documentation.
-
getDocString
()¶ Return the doc string of the function.
-
getPath
()¶ Return the Python path of the function.
-
getSignature
()¶ Return the signature of the function as a string.
-
getAttributes
()¶ Return a list of 2-tuple attribute information.
The first entry of the 2-tuple is the name of the attribute, the second is the attribute object itself.
-
-
interface
zope.app.apidoc.codemodule.interfaces.
IDirective
[source]¶ Representation of a directive in IZCMLFile.
-
name
¶ Name
Name of the directive in the form (Namespace. Name)
-
schema
¶ Schema
Schema describing the directive attributes
-
attrs
¶ Attributes
SAX parser representation of the directive’s attributes
-
context
¶ Configuration Context
Configuration context while the directive was parsed.
-
prefixes
¶ Prefixes
Mapping from namespace URIs to prefixes.
-
info
¶ Info
ParserInfo objects containing line and column info.
-
__parent__
¶ Parent
Parent Directive
-
subs
¶ Sub-Directives
List of sub-directives
-
-
interface
zope.app.apidoc.codemodule.interfaces.
IRootDirective
[source]¶ Extends:
zope.app.apidoc.codemodule.interfaces.IDirective
Marker interface
-
interface
zope.app.apidoc.codemodule.interfaces.
IZCMLFile
[source]¶ ZCML File Object
This is the main object that will manage the configuration of one particular ZCML configuration file.
-
filename
¶ Configuration Filename
Path to the configuration file
-
package
¶ Configuration Package
- Specifies the package from which the configuration file will be
- executed. If you do not specify the package, then the configuration cannot be fully validated and improper ZCML files might be written.
-
rootElement
¶ XML Root Element
XML element representing the configuration root.
-
Classes¶
Class representation for code browser
-
class
zope.app.apidoc.codemodule.class_.
Class
(module, name, klass)[source]¶ Bases:
object
This class represents a class declared in the module.
-
getPath
()[source]¶ See
IClassDocumentation
.
-
getDocString
()[source]¶ See
IClassDocumentation
.
-
getBases
()[source]¶ See
IClassDocumentation
.
-
getKnownSubclasses
()[source]¶ See
IClassDocumentation
.
-
getInterfaces
()[source]¶ See
IClassDocumentation
.
-
getAttributes
()[source]¶ See
IClassDocumentation
.
-
getMethods
()[source]¶ See
IClassDocumentation
.
-
getSecurityChecker
()[source]¶ See
IClassDocumentation
.
-
getConstructor
()[source]¶ See
IClassDocumentation
.
-
Functions¶
Function representation for code browser
Modules¶
Module representation for code browser
-
class
zope.app.apidoc.codemodule.module.
Module
(parent, name, module, setup=True)[source]¶ Bases:
zope.app.apidoc.utilities.ReadContainerBase
This class represents a Python module.
Initialize object.
Text¶
Function representation for code browser
ZCML¶
ZCML File Representation
-
class
zope.app.apidoc.codemodule.zcml.
MyConfigHandler
(context)[source]¶ Bases:
zope.configuration.xmlconfig.ConfigurationHandler
,object
Special configuration handler to generate an XML tree.
Configuration¶
This module handles the ‘apidoc:rootModule’ and ‘apidoc:moduleImport’ namespace directives.
-
zope.app.apidoc.codemodule.metaconfigure.
rootModule
(_context, module)[source]¶ Register a new module as a root module for the class browser.
-
zope.app.apidoc.codemodule.metaconfigure.
moduleImport
(_context, allow)[source]¶ Set the __import_unknown_modules__ flag
apidoc
ZCML namespace directive interfaces
Browser¶
Class Views
-
class
zope.app.apidoc.codemodule.browser.class_.
ClassDetails
[source]¶ Bases:
object
Represents the details of the class.
Function Views
-
class
zope.app.apidoc.codemodule.browser.function.
FunctionDetails
[source]¶ Bases:
object
Represents the details of the function.
Introspector view for content components
-
class
zope.app.apidoc.codemodule.browser.introspector.
annotationsNamespace
(ob, request=None)[source]¶ Bases:
object
Used to traverse to the annotations of an object.
-
class
zope.app.apidoc.codemodule.browser.introspector.
sequenceItemsNamespace
(ob, request=None)[source]¶ Bases:
object
Used to traverse to the values of a sequence.
-
class
zope.app.apidoc.codemodule.browser.introspector.
mappingItemsNamespace
(ob, request=None)[source]¶ Bases:
object
Used to traverse to the values of a mapping.
Important: This might seem like overkill, but we do not know that (1) every mapping has a traverser and (2) whether the location is available. A location might not be available, if we have a mapping in the annotations, for example.
-
class
zope.app.apidoc.codemodule.browser.introspector.
Introspector
(context, request)[source]¶ Bases:
zope.publisher.browser.BrowserView
Introspector browser view
Code Module Menu
Bases:
object
Menu for the Class Documentation Module.
The menu allows for looking for classes by partial names. See findClasses() for the simple search implementation.
Find the classes that match a partial path.
- Examples::
>>> from zope.app.apidoc.codemodule.class_ import Class
Setup the view.
>>> from zope.app.apidoc.codemodule.browser.menu import Menu >>> from zope.publisher.browser import TestRequest >>> menu = Menu() >>> menu.context = apidoc['Code']
Testing the method with various inputs.
>>> menu.request = TestRequest(form={'path': 'menu'}) >>> info = menu.findClasses()
>>> from pprint import pprint >>> pprint(info) [{'path': 'zope.app.apidoc.codemodule.browser.menu.Men', 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/browser/menu/Menu/'}, {'path': 'zope.app.apidoc.ifacemodule.menu.Men', 'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/ifacemodule/menu/Menu/'}...]
>>> menu.request = TestRequest(form={'path': 'illegal name'}) >>> info = menu.findClasses() >>> pprint(info) []
Find all classes
Examples:
Setup the view. >>> from zope.app.apidoc.codemodule.browser.menu import Menu >>> from zope.publisher.browser import TestRequest >>> menu = Menu() >>> menu.context = apidoc['Code'] Make sure we're registered. >>> traverse(menu.context, 'zope/app/apidoc/codemodule/browser/menu/Menu') <zope.app.apidoc.codemodule.class_.Class object at ...> Testing the method with various inputs. >>> menu.request = TestRequest(form={'path': 'Foo'}) >>> info = menu.findAllClasses() >>> info = [x for x in info if x['path'] == 'zope.app.apidoc.codemodule.browser.menu.Menu'] >>> len(info) 1
Module Views
-
zope.app.apidoc.codemodule.browser.module.
formatDocString
(text, module=None, summary=False)[source]¶ Format a doc string for display.
module is either a Python module (from sys.modules) or the dotted name of a module.
If summary is true, the result is plain text and includes only the summary part of the doc string. If summary is false, the result is HTML and includes the whole doc string.
-
class
zope.app.apidoc.codemodule.browser.module.
ModuleDetails
(context, request)[source]¶ Bases:
zope.publisher.browser.BrowserView
Represents the details of a module or package.
Browser utilities for API documentation.
-
class
zope.app.apidoc.codemodule.browser.utilities.
CodeBreadCrumbs
[source]¶ Bases:
object
View that provides breadcrumbs for code objects
Function Views
-
class
zope.app.apidoc.codemodule.browser.text.
TextFileDetails
[source]¶ Bases:
object
Represents the details of the text file.
ZCML Element Views
Interfaces¶
Interface Documentation Module
The interface documentation module retrieves its information from the site manager. Therefore, currently there are no unregsitered interfaces listed in the documentation. This might be good, since unregistered interfaces are usually private and not of interest to a general developer.
-
interface
zope.app.apidoc.ifacemodule.ifacemodule.
IInterfaceModule
[source]¶ Extends:
zope.app.apidoc.interfaces.IDocumentationModule
Interface API Documentation Module
This is a marker interface, so that we can write adapters for objects implementing this interface.
-
class
zope.app.apidoc.ifacemodule.ifacemodule.
InterfaceModule
[source]¶ Bases:
zope.app.apidoc.utilities.DocumentationModuleBase
Represent the Documentation of all Interfaces.
The items of the container are all the interfaces listed in the global site manager.
-
title
= u'Interfaces'¶ The title.
-
description
= u'\n All used and important interfaces are registered through the site\n manager. While it would be possible to just list all attributes, it is\n hard on the user to read such an overfull list. Therefore, interfaces that\n have partial common module paths are bound together.\n\n The documentation of an interface also provides a wide variety of\n information, including of course the declared attributes/fields and\n methods, but also available adapters, and utilities that provide\n this interface.\n '¶ The description.
-
Interfaces¶
Interface Documentation Module Interfaces
-
interface
zope.app.apidoc.ifacemodule.interfaces.
IInterfaceDetailsPreferences
[source]¶ Preferences for API Docs’ Interface Details Screen
It is possible to hide and show various sections of the interface details’ screen. The following preferences allow you to choose the sections to be shown by default.
-
showSpecificRequiredAdapters
¶ Specific Required Interface Adapters
Show specific required interface adapters
-
showExtendedRequiredAdapters
¶ Extended Required Interface Adapters
Show extended required interface adapters
-
showGenericRequiredAdapters
¶ Generic Required Interface Adapters
Show generic required interface adapters
-
showBrowserViews
¶ Browser Views
Show browser views
-
showSpecificBrowserViews
¶ Specific Browser Views
Show specific browser views
-
showExtendedBrowserViews
¶ Extended Browser Views
Show extended browser views
-
showGenericBrowserViews
¶ Generic Browser Views
Show generic browser views
-
showXMLRPCViews
¶ XML-RPC Views
Show XML-RPC views
-
showSpecificXMLRPCViews
¶ Specific XML-RPC Views
Show specific XML-RPC views
-
showExtendedXMLRPCViews
¶ Extended XML-RPC Views
Show extended XML-RPC views
-
showGenericXMLRPCViews
¶ Generic XML-RPC Views
Show generic XML-RPC views
-
showHTTPViews
¶ Generic HTTP Views
Show generic HTTP views
-
showSpecificHTTPViews
¶ Specific HTTP Views
Show specific HTTP views
-
showExtendedHTTPViews
¶ Extended HTTP Views
Show extended HTTP views
-
showGenericHTTPViews
¶ Generic HTTP Views
Show generic HTTP views
-
showFTPViews
¶ FTP Views
Show FTP views
-
showSpecificFTPViews
¶ Specific FTP Views
Show specific FTP views
-
showExtendedFTPViews
¶ Extended FTP Views
Show extended FTP views
-
showGenericFTPViews
¶ Generic FTP Views
Show generic FTP views
-
showOtherViews
¶ Other Views
Show other (unidentified) views
-
showSpecificOtherViews
¶ Specific Other Views
Show specific other views
-
showExtendedOtherViews
¶ Extended Other Views
Show extended other views
-
showGenericOtherViews
¶ Generic Other Views
Show generic other views
-
Browser¶
Interface Details View
-
class
zope.app.apidoc.ifacemodule.browser.
InterfaceDetails
(context, request)[source]¶ Bases:
zope.publisher.browser.BrowserView
View class for an Interface.
-
getId
()[source]¶ Return the id of the field as it is defined for the interface utility.
Example:
>>> from tests import getInterfaceDetails >>> details = getInterfaceDetails() >>> details.getId() 'IFoo'
-
getDoc
()[source]¶ Return the main documentation string of the interface.
Example:
>>> from tests import getInterfaceDetails >>> details = getInterfaceDetails() >>> details.getDoc()[:55] u'<div class="document">\n<p>This is the Foo interface</p>'
-
getBases
()[source]¶ Get all bases of this class
Example:
>>> from tests import getInterfaceDetails >>> details = getInterfaceDetails() >>> details.getBases() ['zope.interface.Interface']
-
getFields
()[source]¶ Return a list of fields in required + alphabetical order.
The required attributes are listed first, then the optional attributes.
-
getClasses
()[source]¶ Get the classes that implement this interface.
Example:
>>> from pprint import pprint >>> from tests import getInterfaceDetails >>> details = getInterfaceDetails() >>> classes = details.getClasses() >>> pprint(classes) [[('path', 'zope.app.apidoc.ifacemodule.tests.Foo'), ('url', 'zope/app/apidoc/ifacemodule/tests/Foo')]]
-
-
class
zope.app.apidoc.ifacemodule.browser.
InterfaceBreadCrumbs
[source]¶ Bases:
object
View that provides breadcrumbs for interface objects
API Documentation macros
-
class
zope.app.apidoc.ifacemodule.macros.
InterfaceDetailsMacros
(context, request)[source]¶ Bases:
zope.app.basicskin.standardmacros.StandardMacros
Page Template METAL macros for Interfaces
-
macro_pages
= ('iface_macros', 'component_macros', 'presentation_macros')¶ Macro pages.
-
Interface Module Browser Menu (Tree)
Get all searchable text from an interface
Bases:
object
Menu for the Interface Documentation Module.
Find the interface that match any text in the documentation strings or a partial path.
Find all interfaces.
Types¶
Interface Types Documentation Module
-
class
zope.app.apidoc.typemodule.type.
TypeInterface
(interface, parent, name)[source]¶ Bases:
zope.app.apidoc.utilities.ReadContainerBase
Representation of the special type interface.
Demonstration:
>>> from zope.interface import Interface >>> class IFoo(Interface): ... pass >>> class IDerivedFoo(IFoo): ... pass >>> from zope import component as ztapi >>> ztapi.provideUtility(IDerivedFoo, IFoo, 'Foo') >>> typeiface = TypeInterface(IFoo, None, None) >>> typeiface.interface <InterfaceClass zope.app.apidoc.typemodule.type.IFoo> >>> typeiface.get('Foo').__class__ <class 'zope.interface.interface.InterfaceClass'> >>> typeiface.items() [(u'Foo', <InterfaceClass zope.app.apidoc.typemodule.type.IDerivedFoo>)]
-
class
zope.app.apidoc.typemodule.type.
TypeModule
[source]¶ Bases:
zope.app.apidoc.utilities.DocumentationModuleBase
Represent the Documentation of all interface types.
Demonstration:
>>> class IFoo(IInterface): ... pass >>> from zope import component as ztapi >>> ztapi.provideUtility(IFoo, IInterface, 'IFoo') >>> module = TypeModule() >>> type = module.get('IFoo') >>> type.interface <InterfaceClass zope.app.apidoc.typemodule.type.IFoo> >>> [type.interface for name, type in module.items()] [<InterfaceClass zope.app.apidoc.typemodule.type.IFoo>]
-
title
= u'Interface Types'¶ Title
-
description
= u'\n Here you can see all registered interface types. When you open the subtree\n of a specific interface type, you can see all the interfaces that provide\n this type. This can be very useful in cases where you want to determine\n all content type interfaces, for example.\n '¶ Description
-
Browser¶
Browser Views for Interface Types
Utilities¶
Utility Documentation Module
-
zope.app.apidoc.utilitymodule.utilitymodule.
encodeName
(name)[source]¶ Encode the name in URL safe base 64.
-
zope.app.apidoc.utilitymodule.utilitymodule.
decodeName
(name)[source]¶ Decode the name as encoded by
encodeName()
.
-
class
zope.app.apidoc.utilitymodule.utilitymodule.
Utility
(parent, reg)[source]¶ Bases:
object
Representation of a utility for the API Documentation
Initialize Utility object.
-
class
zope.app.apidoc.utilitymodule.utilitymodule.
UtilityInterface
(parent, name, interface)[source]¶ Bases:
zope.app.apidoc.utilities.ReadContainerBase
Representation of an interface a utility provides.
-
class
zope.app.apidoc.utilitymodule.utilitymodule.
UtilityModule
[source]¶ Bases:
zope.app.apidoc.utilities.DocumentationModuleBase
Represent the Documentation of all Interfaces.
The items of the container are all utility interfaces registered in the site manager.
-
title
= u'Utilities'¶ Title.
-
description
= u'\n Utilities are also nicely registered in a site manager, so that it is easy\n to create a listing of available utilities. A utility is identified by the\n providing interface and a name, which can be empty. The menu provides you\n with a list of interfaces that utilities provide and as sub-items the\n names of the various implementations.\n\n Again, the documentation of a utility lists all the attributes/fields and\n methods the utility provides and provides a link to the implementation.\n '¶ Description.
-
ZCML¶
ZCML Documentation module
The ZCML documentation module reads all of the meta directives (but does not execute them) and uses the collected data to generate the tree. The result of the evaluation is stored in thread-global variables, so that we have to parse the files only once.
-
class
zope.app.apidoc.zcmlmodule.
Namespace
(parent, name)[source]¶ Bases:
zope.app.apidoc.utilities.ReadContainerBase
Simple namespace object for the ZCML Documentation Module.
This container has
Directive
items as its values.
-
class
zope.app.apidoc.zcmlmodule.
Directive
(ns, name, schema, handler, info, subdirs)[source]¶ Bases:
object
Represents a ZCML Directive.
-
class
zope.app.apidoc.zcmlmodule.
ZCMLModule
[source]¶ Bases:
zope.app.apidoc.utilities.DocumentationModuleBase
Represent the Documentation of all ZCML namespaces.
The items of the container are tuples of globally known namespaces found in the
appsetup config context
.-
title
= u'ZCML Reference'¶ Title.
-
description
= u'\n This module presents you with a complete list of ZCML directives and\n serves therefore well as reference. The menu provides you with a tree that\n organizes the directives by namespaces.\n\n The documentation contents for each directive tells you all the available\n attributes and their semantics. It also provides a link to the interface\n the directive confirms to. If available, it will even tell you the\n file the directive was declared in. At the end a list of available\n subdirectives is given, also listing the implemented interface and\n available attributes.\n '¶ Description.
-
Utility Functions¶
Component Inspection Utilities¶
Once 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.app.apidoc import component
provide 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):
... pass
getRequiredAdapters()
¶
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 import component as ztapi
>>> ztapi.provideAdapter(adapts=(IFoo,), provides=IResult, factory=None)
>>> ztapi.provideAdapter(adapts=(IFoo, IBar), provides=ISpecialResult, factory=None)
>>> ztapi.provideAdapter(adapts=(IFoo, IRequest), provides=ISpecialResult, factory=None)
>>> ztapi.provideHandler(adapts=(IFoo,), factory='stubFactory')
>>> 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 an
zope.publisher.interfaces.IRequest
at 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()
¶
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 the withView
flag, 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 specifying IResult
:
>>> 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()
¶
This package comes with a little tool called the class registry (see The Class Registry). 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 implementer
>>> from zope.app.apidoc.classregistry import classRegistry
>>> @implementer(IFoo)
... class MyFoo(object):
... pass
>>> classRegistry['MyFoo'] = MyFoo
>>> @implementer(IBar)
... class MyBar(object):
... pass
>>> classRegistry['MyBar'] = MyBar
>>> @implementer(IFooBar)
... class MyFooBar(object):
... pass
>>> classRegistry['MyFooBar'] = MyFooBar
Let’s now see whether what results we get:
>>> classes = component.getClasses(IFooBar)
>>> classes.sort()
>>> classes
[('MyFooBar', <class 'zope.app.apidoc.doctest.MyFooBar'>)]
>>> classes = component.getClasses(IFoo)
>>> classes.sort()
>>> classes
[('MyFoo', <class 'zope.app.apidoc.doctest.MyFoo'>),
('MyFooBar', <class 'zope.app.apidoc.doctest.MyFooBar'>)]
getFactories()
¶
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
>>> ztapi.provideUtility(Factory(MyFoo), IFactory, 'MyFoo')
>>> ztapi.provideUtility(Factory(MyBar), IFactory, 'MyBar')
>>> ztapi.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.app.apidoc.doctest.MyFooBar'>>, None, u'')]
>>> regs = list(component.getFactories(IFoo))
>>> regs.sort()
>>> regs
[UtilityRegistration(<BaseGlobalComponents base>, IFactory, 'MyFoo',
<Factory for <class 'zope.app.apidoc.doctest.MyFoo'>>, None, u''),
UtilityRegistration(<BaseGlobalComponents base>, IFactory, 'MyFooBar',
<Factory for <class 'zope.app.apidoc.doctest.MyFooBar'>>, None, u'')]
getUtilities()
¶
Return all utility registrations for utilities that provide the specified interface.
As usual, we have to register some utilities first:
>>> ztapi.provideUtility(MyFoo(), IFoo)
>>> ztapi.provideUtility(MyBar(), IBar)
>>> ztapi.provideUtility(MyFooBar(), IFooBar)
Now let’s have a look what we have:
>>> regs = list(component.getUtilities(IFooBar))
>>> regs.sort()
>>> regs
[UtilityRegistration(<BaseGlobalComponents base>, IFooBar, u'',
<zope.app.apidoc.doctest.MyFooBar object at ...>, None, u'')]
>>> regs = list(component.getUtilities(IFoo))
>>> regs.sort()
>>> regs
[UtilityRegistration(<BaseGlobalComponents base>, IFoo, u'',
<zope.app.apidoc.doctest.MyFoo object at ...>, None, u''),
UtilityRegistration(<BaseGlobalComponents base>, IFooBar, u'',
<zope.app.apidoc.doctest.MyFooBar object at ...>, None, u'')]
getRealFactory()
¶
During registration, factories are commonly masked by wrapper functions. Also,
factories are sometimes also IFactory
instances, which are not referencable,
so that we would like to return the class. If the wrapper objects/functions
play nice, then they provide a factory
attribute 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 = wrapper1
So whether we pass in Factory
,
>>> component.getRealFactory(Factory)
<class 'zope.app.apidoc.doctest.Factory'>
wrapper1
,
>>> component.getRealFactory(wrapper1)
<class 'zope.app.apidoc.doctest.Factory'>
or wrapper2
,
>>> component.getRealFactory(wrapper2)
<class 'zope.app.apidoc.doctest.Factory'>
the answer should always be the Factory
class. 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.app.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.app.apidoc.doctest.Factory'>
getInterfaceInfoDictionary()
¶
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.app.apidoc.doctest', 'name': 'IFoo'}
The functions using this function use it with little care and can also
sometimes pass in None
. In these cases we want to return None
:
>>> component.getInterfaceInfoDictionary(None) is None
True
It’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.app.apidoc.doctest', 'name': 'MyFoo'}
getTypeInfoDictionary()
¶
This function returns the info dictionary of a type.
>>> pprint(component.getTypeInfoDictionary(tuple), width=1)
{'module': '__builtin__',
'name': 'tuple',
'url': '__builtin__/tuple'}
getSpecificationInfoDictionary()
¶
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.app.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()
¶
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:
>>> @implementer(IResult)
... class MyResult(object):
... pass
>>> 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=50)
{'doc': 'doc info',
'factory': 'zope.app.apidoc.doctest.MyResult',
'factory_url': 'zope/app/apidoc/doctest/MyResult',
'name': u'FooToResult',
'provided': {'module': 'zope.app.apidoc.doctest',
'name': 'IResult'},
'required': [{'isInterface': True,
'isType': False,
'module': 'zope.app.apidoc.doctest',
'name': 'IFoo'},
{'isInterface': True,
'isType': False,
'module': 'zope.app.apidoc.doctest',
'name': 'IBar'}],
'zcml': None}
If the factory’s path cannot be referenced, for example if a type has been
created using the type()
builtin function, then the URL of the factory
will be None
:
>>> 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=50)
{'doc': 'doc info',
'factory': 'zope.app.apidoc.doctest.MyResult2',
'factory_url': None,
'name': u'FooToResult',
'provided': {'module': 'zope.app.apidoc.doctest',
'name': 'IResult'},
'required': [{'isInterface': True,
'isType': False,
'module': 'zope.app.apidoc.doctest',
'name': 'IFoo'},
{'isInterface': True,
'isType': False,
'module': 'zope.app.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), '', MyResult, 'doc info')
>>> pprint(component.getAdapterInfoDictionary(reg))
{'doc': 'doc info',
'factory': 'zope.app.apidoc.doctest.MyResult',
'factory_url': 'zope/app/apidoc/doctest/MyResult',
'name': u'',
'provided': None,
'required': [{'isInterface': True,
'isType': False,
'module': 'zope.app.apidoc.doctest',
'name': 'IFoo'},
{'isInterface': True,
'isType': False,
'module': 'zope.app.apidoc.doctest',
'name': 'IBar'}],
'zcml': None}
getFactoryInfoDictionary()
¶
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(
... next(component.getFactories(IFooBar))))
{'description': u'<p>My Foo Bar</p>\n',
'name': u'MyFooBar',
'title': 'MyFooBar',
'url': 'zope/app/apidoc/doctest/MyFooBar'}
If the factory’s path cannot be referenced, for example if a type has been
created using the type()
builtin function, then the URL of the factory
will be None
:
>>> class IMine(Interface):
... pass
>>> class FactoryBase(object):
... def getInterfaces(self): return [IMine]
>>> MyFactoryType = type('MyFactory', (FactoryBase,), {})
>>> from zope.interface import classImplements
>>> classImplements(MyFactoryType, IFactory)
>>> ztapi.provideUtility(MyFactoryType(), IFactory, 'MyFactory')
>>> pprint(component.getFactoryInfoDictionary(
... next(component.getFactories(IMine))), width=50)
{'description': u'',
'name': u'MyFactory',
'title': u'',
'url': None}
getUtilityInfoDictionary()
¶
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(
... next(component.getUtilities(IFooBar))))
{'iface_id': 'zope.app.apidoc.doctest.IFooBar',
'name': u'<i>no name</i>',
'path': 'zope.app.apidoc.doctest.MyFooBar',
'url': 'Code/zope/app/apidoc/doctest/MyFooBar',
'url_name': b'X19ub25hbWVfXw=='}
The Class Registry¶
This 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 the
ClassRegistry.getClassesThatImplement()
method that returns all
classes that implement the passed interface. Another method,
ClassRegistry.getSubclassesOf()
returns all registered
subclassess of the given class.
ClassRegistry
¶
The class registry, subclassing the dictionary type, can be instantiated like any other dictionary:
>>> from zope.app.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, implementer
>>> class IA(Interface):
... pass
>>> class IB(IA):
... pass
>>> class IC(Interface):
... pass
>>> class ID(Interface):
... pass
>>> @implementer(IA)
... class A(object):
... pass
>>> reg['A'] = A
>>> @implementer(IB)
... class B: # Old style on Python 2
... pass
>>> reg['B'] = B
>>> @implementer(IB)
... class B2(object):
... pass
>>> reg['B2'] = B2
>>> @implementer(IC)
... class C(object):
... pass
>>> reg['C'] = C
>>> class A2(A):
... pass
>>> reg['A2'] = A2
Since the registry is just a dictionary, we can ask for all its keys, which are the names of the classes:
>>> names = sorted(reg.keys())
>>> names
['A', 'A2', 'B', 'B2', 'C']
>>> reg['A'] is A
True
There are two API methods specific to the class registry:
ClassRegistry.getClassesThatImplement()
¶
This method returns all classes that implement the specified interface:
>>> from pprint import pprint
>>> pprint(reg.getClassesThatImplement(IA))
[('A', <class 'zope.app.apidoc.doctest.A'>),
('A2', <class 'zope.app.apidoc.doctest.A2'>),
('B', <class 'zope.app.apidoc.doctest.B'>),
('B2', <class 'zope.app.apidoc.doctest.B2'>)]
>>> pprint(reg.getClassesThatImplement(IB))
[('B', <class 'zope.app.apidoc.doctest.B'>),
('B2', <class 'zope.app.apidoc.doctest.B2'>)]
>>> pprint(reg.getClassesThatImplement(IC))
[('C', <class 'zope.app.apidoc.doctest.C'>)]
>>> pprint(reg.getClassesThatImplement(ID))
[]
ClassRegistry.getSubclassesOf()
¶
This method will find all classes that inherit the specified class:
>>> pprint(reg.getSubclassesOf(A))
[('A2', <class '...A2'>)]
>>> pprint(reg.getSubclassesOf(B))
[]
Safe Imports¶
Using the safe_import()
function we can quickly look up modules by minimizing
import calls.
>>> from zope.app.apidoc import classregistry
>>> from zope.app.apidoc.classregistry import safe_import
First we try to find the path in sys.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 the default value.
Here are some examples:
>>> import sys
>>> 'zope.app' in sys.modules
True
>>> safe_import('zope.app') is sys.modules['zope.app']
True
>>> safe_import('weirdname') is None
True
For 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)
>>> with open(filename, 'w') as f:
... _ = f.write('# dummy module\n')
The temporary module is not already imported:
>>> module_name = 'testmodule'
>>> module_name in sys.modules
False
When we try safe_import()
now, we will still get the default value,
because importing new modules is disabled by default:
>>> safe_import(module_name) is None
True
But 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
True
Now 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:
>>> with open(os.path.join(dir, 'alwaysfail.py'), 'w') as f:
... _ = f.write('raise ValueError\n')
>>> sys.path.insert(0, dir)
>>> safe_import('alwaysfail') is None
True
Let’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 ignore zope.app
,
>>> classregistry.IGNORE_MODULES.append('zope.app')
then we cannot import it anymore, even though we know it is available:
>>> safe_import('zope.app') is None
True
Note that all sub-packages are also unavailable:
>>> safe_import('zope.app.apidoc') is None
True
We also need to play nice concerning variables and have to reset the module globals:
>>> classregistry.IGNORE_MODULES.pop()
'zope.app'
>>> classregistry.__import_unknown_modules__ = False
Interface Inspection Utilities¶
This document is a presentation of the utility functions provided by
>>> from zope.app.apidoc import interface
For 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()
¶
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
>>> sorted(interface.getElements(IFoo, type=IMethod).keys())
['blah']
and now the fields:
>>> from zope.schema.interfaces import IField
>>> names = sorted(interface.getElements(IFoo, type=IField).keys())
>>> names
['bar', 'foo']
We can also get all attributes of course.
>>> from zope.interface.interfaces import IAttribute
>>> names = sorted(interface.getElements(IFoo, type=IAttribute).keys())
>>> 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 the
getAttributes()
function.
The default type is zope.interface.interfaces.IElement
which
will simply return all elements of the interface:
>>> names = sorted(interface.getElements(IFoo).keys())
>>> names
['bar', 'baz', 'blah', 'foo']
Note: The interface you pass to this function cannot be proxied! Presentation code often like to wrap interfaces in security proxies and apidoc even uses location proxies for interface.
getFieldsInOrder()
¶
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 _itemkey
argument provides the function that is used to extract
the key on which to order the fields. The default function, which
uses the fields’ order
attribute, 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, _itemkey=lambda x: x[0])]
['bar', 'foo']
getAttributes()
¶
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
[('baz', <zope.interface.interface.Attribute object at ...>)]
getMethods()
¶
This function returns a (name, method) tuple for every declared method in the interface.
>>> methods = sorted(interface.getMethods(IFoo))
>>> methods
[('blah', <zope.interface.interface.Method object at ...>)]
getFields()
¶
This function returns a (name, field) tuple for every declared field in the interface.
>>> sorted(interface.getFields(IFoo))
[('bar', <zope.schema._bootstrapfields.TextLine object at ...>),
('foo', <zope.schema._bootstrapfields.Field object at ...>)]
Note that this returns the same result as getFieldsInOrder()
with the fields
sorted by their order
attribute, except that you cannot specify the sort
function here. This function was mainly provided for symmetry with the other
functions.
getInterfaceTypes()
¶
Interfaces can be categorized/grouped by using interface types. Interface
types simply extend zope.interface.interfaces.IInterface
, which are
basically meta-interfaces. The interface types are then provided by particular
interfaces.
The getInterfaceTypes()
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 our IFoo
interface, there are no types
declared.
>>> interface.getInterfaceTypes(IFoo)
[]
Now we define a new type called IContentType
>>> from zope.interface.interfaces import IInterface
>>> class IContentType(IInterface):
... pass
and 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.app.apidoc.doctest.IContentType>]
Again note that the interface passed to this function cannot be proxied, otherwise this method will pick up the proxy’s interfaces as well.
getFieldInterface()
¶
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 extends
IField
:
>>> from zope.schema.interfaces import IField
>>> class ISpecialField(IField):
... pass
>>> class ISomething(Interface):
... pass
>>> from zope.interface import implementer
>>> @implementer(ISomething, ISpecialField)
... class MyField:
... pass
>>> interface.getFieldInterface(MyField())
<InterfaceClass zope.app.apidoc.doctest.ISpecialField>
getAttributeInfoDictionary()
¶
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()
¶
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()
¶
This function returns a page-template-friendly dictionary for a field:
>>> pprint(interface.getFieldInfoDictionary(IFoo['bar']), width=50)
{'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 Utilities¶
The presentation
module provides some nice utilities to inspect presentation
registrations.
>>> from zope.app.apidoc import presentation
getViewFactoryData()
¶
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 a SimpleViewClass
:
>>> from zope.browserpage.simpleviewclass import SimpleViewClass
>>> view = SimpleViewClass('browser/index.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('\\', '/')[-32:]
>>> from pprint import pprint
>>> pprint(info)
{'path': 'zope.browserpage.simpleviewclass.simple',
'referencable': True,
'resource': None,
'template': 'zope/app/apidoc/browser/index.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 with None
.
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': '__builtin__.int',
'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.app.apidoc.doctest.Factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/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.app.apidoc.doctest.Factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/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
>>> factory.__module__ = 'zope.app.apidoc.doctest' # The testing framework does not set the __module__ correctly
>>> info = presentation.getViewFactoryData(factory)
>>> pprint(info)
{'path': 'zope.app.apidoc.doctest.factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/apidoc/doctest/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 called factory
:
>>> factory.factory = Factory
>>> info = presentation.getViewFactoryData(factory)
>>> pprint(info)
{'path': 'zope.app.apidoc.doctest.Factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/apidoc/doctest/Factory'}
Let’s now have a look at some extremly specific cases. If a view is registered
using the zope:view
directive and a permission is specified, a
ProxyView
class 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.app.apidoc.doctest.Factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/apidoc/doctest/Factory'}
Another use case is when a new type is created by the browser:page
or
browser:view
directive. 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.app.publisher.browser.viewmeta'
>>> info = presentation.getViewFactoryData(new_class)
>>> pprint(info)
{'path': 'zope.app.apidoc.doctest.Factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/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.app.apidoc.doctest.Factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/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)
>>> def wrapper2(*args):
... return wrapper1(*args)
Initially, the documentation is not very helpful:
>>> info = presentation.getViewFactoryData(wrapper2)
>>> pprint(info)
{'path': 'zope.app.apidoc.doctest.wrapper2',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/apidoc/doctest/wrapper2'}
However, if those wrappers play nicely, they provide a factory attribute each step of the way ...
>>> wrapper1.factory = Factory
>>> wrapper2.factory = wrapper1
and the result is finally our original factory:
>>> info = presentation.getViewFactoryData(wrapper2)
>>> pprint(info)
{'path': 'zope.app.apidoc.doctest.Factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/apidoc/doctest/Factory'}
getPresentationType()
¶
In Zope 3, presentation types (i.e. browser, ftp, ...) are defined through
their special request interface, such as IBrowserRequest
or
IFTPRequest
. To complicate matters further, layer interfaces are used in
browser presentations to allow skinning. Layers extend any request type, but
most commonly IBrowserRequest
. 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.app.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.app.apidoc.doctest.ILayer3>
Note that more specific presentation types are considered first. For
example, zope.publisher.interfaces.browser.IBrowserRequest
extends zope.publisher.interfaces.http.IHTTPRequest
, but it
will always determine the presentation type to be an
IBrowserRequest
.
getViews()
¶
This function retrieves all available view registrations for a given
interface and presentation type. The default argument for the
presentation type is zope.publisher.interfaces.IRequest
,
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 import component as ztapi
>>> ztapi.provideAdapter(adapts=(IFoo, IHTTPRequest), provides=Interface, factory=None, name='foo')
>>> ztapi.provideAdapter(adapts=(Interface, IHTTPRequest), provides=Interface, factory=None,
... name='bar')
>>> ztapi.provideAdapter(adapts=(IFoo, IBrowserRequest), provides=Interface, factory=None,
... 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
[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
[AdapterRegistration(<BaseGlobalComponents base>,
[Interface, IHTTPRequest], Interface, 'bar', None, u'')]
filterViewRegistrations()
¶
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. The filterViewRegistrations()
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 the
- specified interface directly.
- EXTENDED_INTERFACE_LEVEL – Only return registrations that require an
- interface that the specified interface extends.
- GENERIC_INTERFACE_LEVEL – Only return registrations that explicitely
- require the
Interface
interface.
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()
>>> ztapi.provideAdapter(adapts=(IContent, IHTTPRequest), provides=Interface, ... factory=None, name='view.html') >>> ztapi.provideAdapter(adapts=(IContent, IHTTPRequest), provides=Interface, ... factory=None, name='edit.html') >>> ztapi.provideAdapter(adapts=(IFile, IHTTPRequest), provides=Interface, ... factory=None, name='view.html') >>> ztapi.provideAdapter(adapts=(Interface, IHTTPRequest), provides=Interface, ... factory=None, 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()
¶
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=50)
{'doc': 'reg info',
'factory': {'path': 'zope.app.apidoc.doctest.Factory',
'referencable': True,
'resource': None,
'template': None,
'url': 'zope/app/apidoc/doctest/Factory'},
'name': u'view.html',
'provided': {'module': 'zope.interface',
'name': 'Interface'},
'read_perm': None,
'required': [{'module': 'zope.app.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 Utilities¶
The utilities module provides some useful helper functions and classes that make the work of the API doctool and inspection code easier.
>>> from zope.app.apidoc import utilities
relativizePath()
¶
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(os.path.dirname(utilities.__file__), 'README.txt')
>>> path = utilities.relativizePath(path)
>>> path.replace('\\', '/') # Be kind to Windows users
'Zope3/zope/app/apidoc/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()
¶
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'
ReadContainerBase
¶
This class serves as a base class for
zope.container.interfaces.IReadContainer
objects that
minimizes the implementation of an IReadContainer
to two methods,
get()
and items()
, since the other methods can be implemented
using these two.
Note that this implementation might be very expensive for certain container,
especially if collecting the items is of high order. However, there are many
scenarios when one has a complete mapping already and simply want to persent
it as an IReadContainer
.
Let’s start by making a simple IReadContainer
implementation using the
class:
>>> class Container(utilities.ReadContainerBase):
... def get(self, key, default=None):
... return {'a': 1, 'b': 2}.get(key, default)
... def items(self):
... return [('a', 1), ('b', 2)]
>>> container = Container()
Now we can use the methods. First get()
>>> container.get('a')
1
>>> container.get('c') is None
True
>>> container['b']
2
and then items()
>>> container.items()
[('a', 1), ('b', 2)]
>>> container.keys()
['a', 'b']
>>> container.values()
[1, 2]
Then naturally, all the other methods work as well:
__getitem__(key)
>>> container['a'] 1 >>> container['c'] Traceback (most recent call last): ... KeyError: 'c'
__contains__(key)
>>> 'a' in container True >>> 'c' in container False
keys()
>>> container.keys() ['a', 'b']
__iter__()
>>> iterator = iter(container) >>> next(iterator) 1 >>> next(iterator) 2 >>> next(iterator) Traceback (most recent call last): ... StopIteration
values()
>>> container.values() [1, 2]
__len__()
>>> len(container) 2
getPythonPath()
¶
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.app.apidoc.doctest.ISample'
and for classes we get the name of the class
>>> class Sample(object):
... def sample(self):
... pass
>>> utilities.getPythonPath(Sample)
'zope.app.apidoc.doctest.Sample'
If a method is passed in, its class path is returned. This works for both bound and unbound methods (note that there is no such thing as an unbound method in Python 3, just functions, but we still get the same results):
>>> utilities.getPythonPath(Sample().sample)
'zope.app.apidoc.doctest.Sample'
>>> utilities.getPythonPath(Sample.sample)
'zope.app.apidoc.doctest.Sample'
Plain functions are also supported:
>>> def sample():
... pass
>>> utilities.getPythonPath(sample)
'zope.app.apidoc.doctest.sample'
Modules are another kind of objects that can return a python path:
>>> utilities.getPythonPath(utilities)
'zope.app.apidoc.utilities'
Passing in None
returns None
:
>>> utilities.getPythonPath(None)
Clearly, instance lookups should fail:
>>> utilities.getPythonPath(Sample())
Traceback (most recent call last):
...
AttributeError: 'Sample' object has no attribute '__name__'
isReferencable()
¶
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.app.apidoc.apidoc.APIDocumentation')
True
>>> utilities.isReferencable('zope.app.apidoc.apidoc.handleNamespace')
True
The first case is None
. When you ask for the python path of None
, you
get None
, so that result should not be referencable:
>>> utilities.isReferencable(None)
False
By 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.app.apidoc.__doc__')
True
Some objects might fake their module name, so that it does not exist:
>>> utilities.isReferencable('foo.bar')
False
On the other hand, you might have a valid module, but non-existent attribute:
>>> utilities.isReferencable('zope.app.apidoc.MyClass')
False
Note that this case is also used for types that are generated using the
type()
function:
>>> mytype = type('MyType', (object,), {})
>>> path = utilities.getPythonPath(mytype)
>>> path
'zope.app.apidoc.doctest.MyType'
>>> utilities.isReferencable(path)
False
Next, 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.app.apidoc.doctest.Singelton')
True
>>> Singelton = Singelton()
>>> utilities.isReferencable('zope.app.apidoc.doctest.Singelton')
False
Finally, the global IGNORE_MODULES
list from the class registry is also
used to give a negative answer. If a module is listed in IGNORE_MODULES
,
then False
is returned.
>>> from zope.app.apidoc import classregistry
>>> classregistry.IGNORE_MODULES.append('zope.app.apidoc')
>>> utilities.isReferencable('zope.app')
True
>>> utilities.isReferencable('zope.app.apidoc')
False
>>> utilities.isReferencable('zope.app.apidoc.apidoc.APIDocumentation')
False
>>> classregistry.IGNORE_MODULES.pop()
'zope.app.apidoc'
>>> utilities.isReferencable('zope.app.apidoc')
True
getPermissionIds()
¶
Get the permissions of a class attribute. The attribute is specified by name.
Either the klass
or the checker
argument must be specified. If the class
is specified, then the checker for it is looked up. Furthermore, this function
only works with INameBasedChecker
checkers. If another checker is found,
None
is 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'
The Sample
class does not know about the attr2
attribute:
>>> entries = utilities.getPermissionIds('attr2', klass=Sample)
>>> print(entries['read_perm'])
n/a
>>> print(entries['write_perm'])
n/a
The Sample2
class does not have a checker:
>>> entries = utilities.getPermissionIds('attr', klass=Sample2)
>>> entries['read_perm'] is None
True
>>> entries['write_perm'] is None
True
Finally, the Sample
class’ attr3
attribute is public:
>>> entries = utilities.getPermissionIds('attr3', klass=Sample)
>>> print(entries['read_perm'])
zope.Public
>>> print(entries['write_perm'])
zope.Public
getFunctionSignature()
¶
Return the signature of a function or method. The func
argument must be 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 the self
argument is removed from the signature, since it
is not essential for documentation; this happens by default on Python
2 for unbound methods, but since Python 3 doesn’t have such a concept
we have to explicitly ask for that behaviour:
We start out with a simple positional argument:
>>> class Klass(object):
... def func(self, attr):
... pass
>>> utilities.getFunctionSignature(Klass.func, ignore_self=True)
'(attr)'
>>> 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, ignore_self=True)
'(attr, *args, **kw)'
>>> 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 method not a ...
A very uncommon, but perfectly valid (in Python 2), case is that tuple arguments are unpacked inside the argument list of the function. Here is an example (we can’t actually test it because it fails on Python 3):
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 syntax
Internal assignment is also not legal:
>>> def func((arg1, arg2=1)):
... pass
Traceback (most recent call last):
...
SyntaxError: invalid syntax
getPublicAttributes()
¶
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. The obj
argument 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 attrs
We 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()
¶
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 the interfaces
or klass
argument must be specified. If interfaces
is not specified, the klass
is used to retrieve a list of
interfaces. interfaces
must be iterable.
asPath
specifies 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, implementer
>>> class I1(Interface):
... attr = Attribute('attr')
>>> class I2(I1):
... def getAttr():
... '''get attr'''
>>> @implementer(I2)
... class Sample(object):
... pass
First we check whether an aatribute can be found in a list of interfaces:
>>> utilities.getInterfaceForAttribute('attr', (I1, I2), asPath=False)
<InterfaceClass zope.app.apidoc.doctest.I1>
>>> utilities.getInterfaceForAttribute('getAttr', (I1, I2), asPath=False)
<InterfaceClass zope.app.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.app.apidoc.doctest.I1>
>>> utilities.getInterfaceForAttribute('getAttr', klass=Sample, asPath=False)
<InterfaceClass zope.app.apidoc.doctest.I2>
By default, asPath
is True
, which means the path of the interface is
returned:
>>> utilities.getInterfaceForAttribute('attr', (I1, I2))
'zope.app.apidoc.doctest.I1'
If no match is found, None
is returned.
>>> utilities.getInterfaceForAttribute('attr2', (I1, I2)) is None
True
>>> utilities.getInterfaceForAttribute('attr2', klass=Sample) is None
True
If both, the interfaces
and klass
argument are missing, raise an error:
>>> utilities.getInterfaceForAttribute('getAttr')
Traceback (most recent call last):
...
ValueError: need to specify interfaces or klass
Similarly, 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 klass
columnize()
¶
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()
¶
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.app.apidoc import apidoc
>>> utilities.getDocFormat(apidoc)
'zope.source.rest'
By default restructured text is returned:
>>> utilities.getDocFormat(object())
'zope.source.rest'
This is a sensible default since much documentation is now written
with Sphinx in mind (which of course defaults to rendering
restructured text). As long as docutils’ error reporting level is set
sufficiently high (severe
), unknown Sphinx directives and slightly
malformed markup do not produce error messages, either on the console
or in the generated HTML.
The __docformat__
attribute can also optionally specify a language field. We
simply ignore it:
>>> class Module(object):
... pass
>>> module = Module()
>>> module.__docformat__ = 'structuredtext en'
>>> utilities.getDocFormat(module)
'zope.source.stx'
dedentString()
¶
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
Lengthy description, giving some more background information and
discuss some edge cases.
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
Root Level
Second Level
>>> def func():
... '''Short description
...
... $$$ print 'example'
... example
...
... And now the description.
... '''
>>> print(utilities.dedentString(func.__doc__))
Short description
$$$ print 'example'
example
And now the description.
renderText()
¶
A function that quickly renders the given text using the specified format.
If the module
argument is specified, the function will try to determine the
format using the module. If the format
argument is given, it is simply
used. Clearly, you cannot specify both, the module
and format
argument.
You specify the format as follows:
>>> utilities.renderText(u'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(u'Hello!\n', module=apidoc)
u'<p>Hello!</p>\n'
Byte input is accepted, so long as it can be decoded:
>>> utilities.renderText(b'Hello!\n', module=apidoc)
u'<p>Hello!</p>\n'
Browser¶
Generic API Doc Views¶
Get a browser started:
>>> from zope.testbrowser.wsgi import Browser
>>> browser = Browser()
>>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
Not Found View¶
The APIDOC skin defines a custom not found view, since it fits the look and feel better and does not have all the O-wrap clutter:
>>> browser.open('http://localhost/++apidoc++/non-existent/')
Traceback (most recent call last):
...
urllib.error.HTTPError: HTTP Error 404: Not Found
>>> try:
... browser.open('http://localhost/++apidoc++/non-existent/')
... except Exception:
... pass
>>> print(browser.contents)
<...
<h1 class="details-header">
Page Not Found
</h1>
<p>
While broken links occur occassionally, they are considered bugs. Please
report any broken link to
<a href="mailto:zope-dev@zope.org">zope-dev@zope.org</a>.
</p>
...
Preferences¶
The APIDOC
skin also does the same for editing preference groups:
>>> browser.open('http://localhost/++preferences++apidoc/InterfaceDetails/apidocIndex.html')
>>> print(browser.contents)
<...
<div class="documentation"><p>Preferences for API Docs' Interface Details Screen</p>
...
API doc when developer mode is disabled¶
The API docs should not be exposed to anybody as they allow introspection of code and files on the file system that should not be exposed through the web.
In this test case, the developer mode was disabled, so we will only see a page informing the user that the API docs are disabled. We do this as we changed the default during the release of Zope 3.3 and many developers will still assume that their instances are running in developer mode, while they aren’t.
>>> from zope.testbrowser.wsgi import Browser
>>> browser = Browser()
>>> browser.handleErrors = False
>>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
>>> browser.open("http://localhost/++apidoc++")
>>> browser.contents
'...API documentation is disabled...'
Code¶
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()
u'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())
[u'BTrees', u'ZConfig', u'ZODB', u'persistent', u'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 __builtin__.IBlie>),
('foo', 'f', <InterfaceClass __builtin__.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 __builtin__.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 (u'http://namespaces.zope.org/zope', u'configure')>
A directive component has some interesting atrributes, such as the name,
>>> root.name
(u'http://namespaces.zope.org/zope', u'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 (u'http://namespaces.zope.org/zope', u'class')>,
<Directive (u'http://namespaces.zope.org/zope', u'class')>]
and finally a list of all prefixes.
>>> pprint(root.prefixes)
{u'http://namespaces.zope.org/apidoc': u'apidoc',
u'http://namespaces.zope.org/browser': u'browser',
u'http://namespaces.zope.org/zope': None}
Code Module specific apidoc Directives¶
The apidoc:rootModule
Directive¶
The rootModule
directive allows you to register a third party Python package
with apidoc’s code browser.
Before we can register a new root module, we need to load the metaconfiguration:
>>> from zope.configuration import xmlconfig
>>> import zope.app.apidoc.codemodule
>>> context = xmlconfig.file('meta.zcml', zope.app.apidoc.codemodule)
Now we can run the directive. First, let’s make sure that no root modules have been registered yet:
>>> from zope.component import getUtilitiesFor
>>> from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule
>>> list(getUtilitiesFor(IAPIDocRootModule))
[]
Now run the registration code:
>>> context = xmlconfig.string('''
... <configure
... xmlns="http://namespaces.zope.org/apidoc">
... <rootModule module="zope" />
... </configure>''', context)
and the root module is available:
>>> list(getUtilitiesFor(IAPIDocRootModule))
[(u'zope', 'zope')]
The apidoc:importModule
Directive¶
The importModule
directive allows you to set the
__import_unknown_modules__
flag of the class registry. When this flag is
set to false, paths will only be looked up in sys.modules
. When set true,
and the sys.modules
lookup fails, the import function of the class
registry tries to import the path. The hook was provided for security reasons,
since uncontrolled importing of modules in a running application is considered
a security hole.
By default the flag is set to false (of course, this depends on the order in which tests are run and what ZCML has been configured or if this was manually changed, so we can’t really rely on the default here):
>>> from zope.app.apidoc import classregistry
>>> classregistry.__import_unknown_modules__ = False
We can now use the directive to set it to true:
>>> context = xmlconfig.string('''
... <configure
... xmlns="http://namespaces.zope.org/apidoc">
... <moduleImport allow="true" />
... </configure>''', context)
>>> classregistry.__import_unknown_modules__
True
We can also set it back to false of course:
>>> context = xmlconfig.string('''
... <configure
... xmlns="http://namespaces.zope.org/apidoc">
... <moduleImport allow="false" />
... </configure>''', context)
>>> classregistry.__import_unknown_modules__
False
Code Browser Presentation Components¶
This document describes the API of the views complementing the various code browser documentation components. The views can be found in
>>> from zope.app.apidoc.codemodule import browser
We will also need the code browser documentation module:
>>> cm = apidoc.get('Code')
The zope
package is already registered and available with the code module.
Module Details¶
The module details are easily created, since we can just use the traversal process to get a module documentation object:
>>> from zope.traversing.api import traverse
>>> _context = traverse(cm, 'zope/app/apidoc/codemodule/codemodule')
>>> from zope.publisher.browser import TestRequest
>>> details = browser.module.ModuleDetails(_context, TestRequest())
module.ModuleDetails.getDoc()
¶
Get the doc string of the module formatted in STX or ReST.
>>> print(details.getDoc().strip())
<p>Code Documentation Module</p>
<p>This module is able to take a dotted name of any class and display
documentation for it.</p>
Module data¶
Return info objects for all classes in this module.
>>> from pprint import pprint
>>> pprint(details.getClasses())
[{'doc': 'Represent the code browser documentation root',
'name': 'CodeModule',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/codemodule/CodeModule'}]
This module doesn’t contain anything else.
>>> pprint(details.getInterfaces())
[]
>>> pprint(details.getModules())
[]
>>> pprint(details.getModuleInterfaces())
[]
>>> pprint(details.getTextFiles())
[]
>>> pprint(details.getZCMLFiles())
[]
>>> pprint(details.getFunctions())
[]
utilities.getBreadCrumbs()
¶
Create breadcrumbs for the module path.
We cannot reuse the the system’s bread crumbs, since they go all the way up to the root, but we just want to go to the root module.
>>> from zope.app.apidoc.codemodule.browser import utilities
>>> bc = utilities.CodeBreadCrumbs()
>>> bc.context = details.context
>>> bc.request = details.request
>>> pprint(bc(), width=1)
[{'name': u'[top]',
'url': 'http://127.0.0.1/++apidoc++/Code'},
{'name': u'zope',
'url': 'http://127.0.0.1/++apidoc++/Code/zope'},
{'name': 'app',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app'},
{'name': 'apidoc',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc'},
{'name': 'codemodule',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule'},
{'name': 'codemodule',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/codemodule'}]
Module Details With Interfaces¶
Let’s also look at a module that defines interfaces:
>>> _context = traverse(cm, 'zope/app/apidoc/interfaces')
>>> details = browser.module.ModuleDetails(_context, TestRequest())
>>> pprint(details.getInterfaces())
[{'doc': 'Zope 3 API Documentation Module',
'name': 'IDocumentationModule',
'path': 'zope.app.apidoc.interfaces.IDocumentationModule',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/interfaces/IDocumentationModule'}]
Module Details With Implementation¶
Let’s also look at a module that implements an interface itself:
>>> _context = traverse(cm, 'zope/lifecycleevent')
>>> details = browser.module.ModuleDetails(_context, TestRequest())
>>> pprint(details.getModuleInterfaces())
[{'name': 'IZopeLifecycleEvent',
'path': 'zope.lifecycleevent.interfaces.IZopeLifecycleEvent'}]
Class Details¶
The class details are easily created, since we can just use the traversal process to get a class documentation object:
>>> details = browser.class_.ClassDetails()
>>> details.context = traverse(
... cm, 'zope/app/apidoc/codemodule/codemodule/CodeModule')
>>> details.request = TestRequest()
Now that we have the details class we can just access the various methods:
class_.ClassDetails.getBases()
¶
Get all bases of this class.
>>> pprint(details.getBases())
[{'path': 'zope.app.apidoc.codemodule.module.Module',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module'}]
class_.ClassDetails.getKnownSubclasses()
¶
Get all known subclasses of this class.
>>> details.getKnownSubclasses()
[]
class_.ClassDetails._listClasses()
¶
Prepare a list of classes for presentation.
>>> import zope.app.apidoc.apidoc
>>> import zope.app.apidoc.codemodule.codemodule
>>> pprint(details._listClasses([
... zope.app.apidoc.apidoc.APIDocumentation,
... zope.app.apidoc.codemodule.codemodule.Module]))
[{'path': 'zope.app.apidoc.apidoc.APIDocumentation',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/apidoc/APIDocumentation'},
{'path': 'zope.app.apidoc.codemodule.module.Module',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module'}]
class_.ClassDetails.getBaseURL()
¶
Return the URL for the API Documentation Tool.
Note that the following output is a bit different than usual, since we have not setup all path elements.
>>> details.getBaseURL()
'http://127.0.0.1/++apidoc++'
class_.ClassDetails.getInterfaces()
¶
Get all implemented interfaces (as paths) of this class.
>>> pprint(details.getInterfaces())
[{'path': 'zope.app.apidoc.interfaces.IDocumentationModule',
'url': 'zope.app.apidoc.interfaces.IDocumentationModule'},
{'path': 'zope.location.interfaces.ILocation',
'url': 'zope.location.interfaces.ILocation'},
{'path': 'zope.app.apidoc.codemodule.interfaces.IModuleDocumentation',
'url': 'zope.app.apidoc.codemodule.interfaces.IModuleDocumentation'},
{'path': 'zope.container.interfaces.IReadContainer',
'url': 'zope.container.interfaces.IReadContainer'}]
class_.ClassDetails.getConstructor()
¶
Get info about the class’ __init__ method, which is its constructor.
>>> pprint(details.getConstructor())
{'doc': u'<p>Initialize object.</p>\n',
'signature': '()'}
class_.ClassDetails.getAttributes()
¶
Get all attributes of this class.
>>> pprint(details.getAttributes()[1])
{'interface': {'path': 'zope.app.apidoc.interfaces.IDocumentationModule',
'url': 'zope.app.apidoc.interfaces.IDocumentationModule'},
'name': 'title',
'read_perm': 'zope.Public',
'type': 'Message',
'type_link': 'zope/i18nmessageid/message/Message',
'value': "u'Code Browser'",
'write_perm': u'n/a'}
class_.ClassDetails.getMethods()
¶
Get all methods of this class.
>>> pprint(details.getMethods()[-3:-1])
[{'doc': u'<p>Setup module and class tree.</p>\n',
'interface': None,
'name': 'setup',
'read_perm': u'n/a',
'signature': '()',
'write_perm': u'n/a'},
{'doc': u'',
'interface': {'path': 'zope.interface.common.mapping.IEnumerableMapping',
'url': 'zope.interface.common.mapping.IEnumerableMapping'},
'name': 'values',
'read_perm': 'zope.Public',
'signature': '()',
'write_perm': u'n/a'}]
class_.ClassDetails.getDoc()
¶
Get the doc string of the class STX formatted.
>>> print(details.getDoc()[:-1])
<p>Represent the code browser documentation root</p>
Function Details¶
This is the same deal as before, use the path to generate the function documentation component:
>>> details = browser.function.FunctionDetails()
>>> details.context = traverse(cm,
... 'zope/app/apidoc/codemodule/browser/tests/foo')
>>> details.request = TestRequest()
Here are the methods:
function.FunctionDetails.getDocString()
¶
Get the doc string of the function in a rendered format.
>>> details.getDocString()
u'<p>This is the foo function.</p>\n'
function.FunctionDetails.getAttributes()
¶
Get all attributes of this function.
>>> attr = details.getAttributes()[0]
>>> pprint(attr)
{'name': 'deprecated',
'type': 'bool',
'type_link': '__builtin__/bool',
'value': 'True'}
function.FunctionDetails.getBaseURL()
¶
Return the URL for the API Documentation Tool.
>>> details.getBaseURL()
'http://127.0.0.1/++apidoc++'
Text File Details¶
This is the same deal as before, use the path to generate the
text file documentation component
:
>>> details = browser.text.TextFileDetails()
>>> details.context = traverse(cm,
... 'zope/app/apidoc/codemodule/README.rst')
>>> details.request = TestRequest()
Here are the methods:
text.TextFileDetails.renderedContent()
¶
Render the file content to HTML.
>>> print(details.renderedContent()[:48])
<h1 class="title">Code Documentation Module</h1>
ZCML File and Directive Details¶
The ZCML file details
are a bit
different, since there is no view class for ZCML files, just a
template. The template then uses the directive details to provide all
the view content:
>>> details = browser.zcml.DirectiveDetails()
>>> zcml = traverse(cm, 'zope/app/apidoc/codemodule/configure.zcml')
>>> details.context = zcml.rootElement
>>> details.request = TestRequest()
>>> details.__parent__ = details.context
Here are the methods for the directive details:
zcml.DirectiveDetails.fullTagName()
¶
Return the name of the directive, including prefix, if applicable.
>>> details.fullTagName()
u'configure'
zcml.DirectiveDetails.line()
¶
Return the line (as a string) at which this directive starts.
>>> details.line()
'1'
zcml.DirectiveDetails.highlight()
¶
It is possible to highlight a directive by passing the line variable as a request variable. If the value of line matches the output of line(), this method returns ‘highlight’ and otherwise ‘’. ‘highlight’ is a CSS class that places a colored box around the directive.
>>> details.highlight()
''
>>> details.request = TestRequest(line='1')
>>> details.highlight()
'highlight'
zcml.DirectiveDetails.url()
¶
Returns the URL of the directive docuemntation in the ZCML documentation module.
>>> details.url()
u'http://127.0.0.1/++apidoc++/ZCML/ALL/configure/index.html'
zcml.DirectiveDetails.objectURL()
¶
This method converts the string value of the field to an object and then crafts a documentation URL for it:
>>> from zope.configuration.fields import GlobalObject
>>> field = GlobalObject()
>>> details.objectURL('.interfaces.IZCMLFile', field, '')
'http://127.0.0.1/++apidoc++/Interface/zope.app.apidoc.codemodule.interfaces.IZCMLFile/index.html'
>>> details.objectURL('.zcml.ZCMLFile', field, '')
'/zope/app/apidoc/codemodule/zcml/ZCMLFile/index.html'
zcml.DirectiveDetails.attributes()
¶
Returns a list of info dictionaries representing all the attributes in the directive. If the directive is the root directive, all namespace declarations will be listed too.
>>> pprint(details.attributes())
[{'name': 'xmlns',
'url': None,
'value': u'http://namespaces.zope.org/zope',
'values': []},
{'name': u'xmlns:apidoc',
'url': None,
'value': u'http://namespaces.zope.org/apidoc',
'values': []},
{'name': u'xmlns:browser',
'url': None,
'value': u'http://namespaces.zope.org/browser',
'values': []}]
>>> details.context = details.context.subs[0]
>>> pprint(details.attributes())
[{'name': u'class',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/codemodule/module/Module/index.html',
'value': u'.module.Module',
'values': []}]
zcml.DirectiveDetails.hasSubDirectives()
¶
Returns True, if the directive has subdirectives; otherwise False is returned.
>>> details.hasSubDirectives()
True
zcml.DirectiveDetails.getElements()
¶
Returns a list of all sub-directives:
>>> details.getElements()
[<Directive (u'http://namespaces.zope.org/zope', u'allow')>]
Other Examples¶
Let’s look at sub-directive that has a namespace:
>>> details = browser.zcml.DirectiveDetails()
>>> zcml = traverse(cm, 'zope/app/apidoc/ftesting-base.zcml')
>>> browser_directive = [x for x in zcml.rootElement.subs if x.name[0].endswith('browser')][0]
>>> details.context = browser_directive
>>> details.request = TestRequest()
>>> details.fullTagName()
'browser:menu'
The exact URL will vary depending on what ZCML has been loaded.
>>> details.url()
'http://127.0.0.1/++apidoc++/.../menu/index.html'
Now one that has some tokens:
>>> details = browser.zcml.DirectiveDetails()
>>> zcml = traverse(cm, 'zope/app/apidoc/enabled.zcml')
>>> adapter_directive = [x for x in zcml.rootElement.subs if x.name[1] == 'adapter'][0]
>>> details.context = adapter_directive
>>> details.__parent__ = details.context
>>> details.request = TestRequest()
>>> pprint(details.attributes())
[{'name': 'factory',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/app/apidoc/apidoc/apidocNamespace/index.html',
'value': '.apidoc.apidocNamespace',
'values': []},
{'name': 'provides',
'url': 'http://127.0.0.1/++apidoc++/Interface/zope.traversing.interfaces.ITraversable/index.html',
'value': 'zope.traversing.interfaces.ITraversable',
'values': []},
{'name': 'for', 'url': None, 'value': '*', 'values': []},
{'name': 'name', 'url': None, 'value': 'apidoc', 'values': []}]
Now one with multiple tokens:
>>> details = browser.zcml.DirectiveDetails()
>>> zcml = traverse(cm, 'zope/traversing/configure.zcml')
>>> adapter_directive = [x for x in zcml.rootElement.subs if x.name[1] == 'adapter']
>>> adapter_directive = [x for x in adapter_directive if ' ' in x.attrs[(None, 'for')]][0]
>>> details.context = adapter_directive
>>> details.__parent__ = details.context
>>> details.request = TestRequest()
>>> pprint(details.attributes())
[{'name': 'factory',
'url': 'http://127.0.0.1/++apidoc++/Code/zope/traversing/namespace/etc/index.html',
'value': 'zope.traversing.namespace.etc',
'values': []},
{'name': 'provides',
'url': 'http://127.0.0.1/++apidoc++/Interface/zope.traversing.interfaces.ITraversable/index.html',
'value': 'zope.traversing.interfaces.ITraversable',
'values': []},
{'name': 'for',
'url': None,
'value': '* zope.publisher.interfaces.IRequest',
'values': [{'url': None, 'value': '*'},
{'url': 'http://127.0.0.1/++apidoc++/Interface/zope.publisher.interfaces.IRequest/index.html',
'value': 'zope.publisher.interfaces.IRequest'}]},
{'name': 'name', 'url': None, 'value': 'etc', 'values': []}]
And now one that is subdirectives:
>>> details = browser.zcml.DirectiveDetails()
>>> zcml = traverse(cm, 'zope/app/apidoc/browser/configure.zcml')
>>> adapter_directive = [x for x in zcml.rootElement.subs if x.name[1] == 'pages'][0]
>>> details.context = adapter_directive.subs[0]
>>> details.__parent__ = details.context
>>> details.request = TestRequest()
>>> details.url()
'http://127.0.0.1/++apidoc++/.../pages/index.html#page'
The Introspector¶
There are several tools that are used to support the introspector
.
>>> from zope.app.apidoc.codemodule.browser import introspector
getTypeLink()
¶
This little helper function returns the path to the type class:
>>> from zope.app.apidoc.apidoc import APIDocumentation
>>> introspector.getTypeLink(APIDocumentation)
'zope/app/apidoc/apidoc/APIDocumentation'
>>> introspector.getTypeLink(dict)
'__builtin__/dict'
>>> introspector.getTypeLink(type(None)) is None
True
++annotations++
Namespace¶
This namespace
is used to traverse into
the annotations of an object.
>>> import zope.interface
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> @zope.interface.implementer(IAttributeAnnotatable)
... class Sample(object):
... pass
>>> sample = Sample()
>>> sample.__annotations__ = {'zope.my.namespace': 'Hello there!'}
>>> ns = introspector.annotationsNamespace(sample)
>>> ns.traverse('zope.my.namespace', None)
'Hello there!'
>>> ns.traverse('zope.my.unknown', None)
Traceback (most recent call last):
...
KeyError: 'zope.my.unknown'
Mapping ++items++
namespace¶
This namespace
allows us to traverse
the items of any mapping:
>>> ns = introspector.mappingItemsNamespace({'mykey': 'myvalue'})
>>> ns.traverse('mykey', None)
'myvalue'
>>> ns.traverse('unknown', None)
Traceback (most recent call last):
...
KeyError: 'unknown'
Sequence ++items++
namespace¶
This namespace
allows us to traverse
the items of any sequence:
>>> ns = introspector.sequenceItemsNamespace(['value1', 'value2'])
>>> ns.traverse('0', None)
'value1'
>>> ns.traverse('2', None)
Traceback (most recent call last):
...
IndexError: list index out of range
>>> ns.traverse('text', None)
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: 'text'
Introspector View¶
The main contents of the introspector view comes from the
introspector view class
. In the following
section we are going to demonstrate the methods used to collect the
data. First we need to create an object though; let’s use a root
folder:
>>> rootFolder
<zope.site.folder.Folder object at ...>
Now we instantiate the view
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> inspect = introspector.Introspector(rootFolder, request)
so that we can start looking at the methods. First we should note that the class documentation view is directly available:
>>> inspect.klassView
<zope.browserpage.simpleviewclass.SimpleViewClass from ...>
>>> inspect.klassView.context
<zope.app.apidoc.codemodule.class_.Class object at ...>
You can get the parent of the inspected object, which is None
for the root
folder:
>>> inspect.parent() is None
True
You can also get the base URL of the request:
>>> inspect.getBaseURL()
'http://127.0.0.1/++apidoc++'
Next you can get a list of all directly provided interfaces:
>>> ifaces = inspect.getDirectlyProvidedInterfaces()
>>> sorted(ifaces)
['zope.component.interfaces.ISite', 'zope.site.interfaces.IRootFolder']
The getProvidedInterfaces()
and getBases()
method simply forwards its
request to the class documentation view. Thus the next method is
getAttributes()
, which collects all sorts of useful information about the
object’s attributes:
>>> pprint(list(inspect.getAttributes()))
[{'interface': None,
'name': 'data',
'read_perm': u'n/a',
'type': 'OOBTree',
'type_link': 'BTrees/OOBTree/OOBTree',
'value': '<BTrees.OOBTree.OOBTree object at ...>',
'value_linkable': True,
'write_perm': u'n/a'}]
Of course, the methods are listed as well:
>>> pprint(list(inspect.getMethods()))
[...
{'doc': u'',
'interface': 'zope.component.interfaces.IPossibleSite',
'name': 'getSiteManager',
'read_perm': 'zope.Public',
'signature': '()',
'write_perm': u'n/a'},
...
{'doc': u'',
'interface': 'zope.container.interfaces.IBTreeContainer',
'name': 'keys',
'read_perm': 'zope.View',
'signature': '(key=None)',
'write_perm': u'n/a'},
{'doc': u'',
'interface': 'zope.component.interfaces.IPossibleSite',
'name': 'setSiteManager',
'read_perm': 'zope.ManageServices',
'signature': '(sm)',
'write_perm': u'n/a'},
...]
The final methods deal with inspecting the objects data further. For exmaple, if we inspect a sequence,
>>> from persistent.list import PersistentList
>>> list = PersistentList(['one', 'two'])
>>> from zope.interface.common.sequence import IExtendedReadSequence
>>> zope.interface.directlyProvides(list, IExtendedReadSequence)
>>> inspect2 = introspector.Introspector(list, request)
we can first determine whether it really is a sequence
>>> inspect2.isSequence()
True
and then get the sequence items:
>>> pprint(inspect2.getSequenceItems())
[{'index': 0,
'value': "'one'",
'value_type': 'str',
'value_type_link': '__builtin__/str'},
{'index': 1,
'value': "'two'",
'value_type': 'str',
'value_type_link': '__builtin__/str'}]
Similar functionality exists for a mapping. But we first have to add an item:
>>> rootFolder['list'] = list
Now let’s have a look:
>>> inspect.isMapping()
True
>>> pprint(inspect.getMappingItems())
[...
{'key': u'list',
'key_string': "u'list'",
'value': "['one', 'two']",
'value_type': 'ContainedProxy',
'value_type_link': 'zope/container/contained/ContainedProxy'},
...]
The final two methods doeal with the introspection of the annotations. If an object is annotatable,
>>> inspect.isAnnotatable()
True
then we can get an annotation mapping:
>>> rootFolder.__annotations__ = {'my.list': list}
>>> pprint(inspect.getAnnotationsInfo())
[{'key': 'my.list',
'key_string': "'my.list'",
'value': "['one', 'two']",
'value_type': 'PersistentList',
'value_type_link': 'persistent/list/PersistentList'}]
And that’s it. Fur some browser-based demonstration see Object Introspector View.
Object Introspector View¶
The “Introspector” view provides access to information about the current
obejct, the context of the introspector view. When in devmode
, the
introspector is simply available as follows:
>>> from zope.testbrowser.wsgi import Browser
>>> browser = Browser()
>>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
>>> browser.handleErrors = False
>>> browser.open('http://localhost/manage')
>>> browser.getLink('Introspector').click()
The page starts with telling you the class/type
>>> browser.getLink('zope.site.folder.Folder').url
'http://localhost/++apidoc++/Code/zope/site/folder/Folder/index.html'
and the name of the object:
>>> '<no name>' in browser.contents
True
Of course, the root folder does not have a name. As you can see the type links directly to the API documentation of the class.
The next section lists all directly provided interfaces. The root
folder directly provides the zope.site.interfaces.ISite
and
zope.site.interfaces.IRootFolder
interface, so we should see
those:
>>> browser.getLink('zope.component.interfaces.ISite').url
'.../++apidoc++/Interface/zope.component.interfaces.ISite/index.html'
>>> browser.getLink('zope.site.interfaces.IRootFolder').url
'...apidoc++/Interface/zope.site.interfaces.IRootFolder/index.html'
The next two section, the implemented interfaces and the base classes,
are not instance specific pieces of information, but they are still
nice to see at this point. For example, a
zope.site.folder.Folder
instance provides the following
interfaces:
>>> browser.getLink('zope.site.interfaces.IFolder').url
'.../++apidoc++/Interface/zope.site.interfaces.IFolder/index.html'
>>> browser.getLink('persistent.interfaces.IPersistent').url
'.../++apidoc++/Interface/persistent.interfaces.IPersistent/index.html'
>>> browser.getLink('zope.component.interfaces.IPossibleSite').url
'.../Interface/zope.component.interfaces.IPossibleSite/index.html'
>>> browser.getLink('zope.location.interfaces.IContained').url
'...doc++/Interface/zope.location.interfaces.IContained/index.html'
The base classes of the Folder
are as follows:
>>> browser.getLink('zope.site.site.SiteManagerContainer').url
'...apidoc++/Code/zope/site/site/SiteManagerContainer/index.html'
Now that we described the component and class level of the object, the view dives into some details. First it lists the attributes/properties of the object, including the value of the attribute. This is information can be very useful when debugging an application. The only attribute of the folder is the data attribute:
>>> print(browser.contents)
<!DOCTYPE...
...
<h2>Attributes/Properties</h2>
<div class="indent">
<ul class="attr-list">
<li>
<b><code>data</code></b>
...
<br />
<i>Value:</i>
<a href="http://localhost/++attribute++data/@@introspector.html">
<code><BTrees.OOBTree.OOBTree object at ...></code>
</a>
<br />
<span class="small">
<i>Permissions:</i>
n/a
<span>(read)</span>,
n/a
<span>(write)</span>
</span>
</li>
</ul>
</div>
...
There are, however, several methods since the full mapping interface is implemented. Like for the class method documentation, the method’s signature, doc string, permissions and the interface the method is declared in. Here an example:
>>> print(browser.contents)
<!DOCTYPE...
...
<h2>Methods</h2>
<div class="indent">
<ul class="attr-list">
<li>
<b><code>get(key, default=None)</code>
</b><br />
<div class="inline documentation"><p>See interface <cite>IReadContainer</cite></p>
</div>
<span class="small">
<i>Interface:</i>
<a href="...">zope.interface.common.mapping.IReadMapping</a><br />
</span>
<span class="small">
<i>Permissions:</i>
zope.View
<span>(read)</span>,
n/a
<span>(write)</span>
</span>
</li>
...
</ul>
</div>
...
Towards the bottom of the page, there are some optional sections. Some objects, for example our root folder, are inheritely mappings or sequences. Their data then is often hard to see in the attributes section, so they are provided in a aseparate section. To see anything useful, we have to add an object to the folder first:
>>> import re
>>> browser.getLink(re.compile('^File$')).click()
>>> from io import BytesIO
>>> browser.getControl('Data').value = BytesIO(b'content')
>>> browser.getControl(name='add_input_name').value = 'file.txt'
>>> browser.getControl('Add').click()
>>> browser.getLink('Introspector').click()
Now the introspector will show the file and allow you to click on it:
>>> print(browser.contents)
<!DOCTYPE...
...
<div>
<h2>Mapping Items</h2>
<div class="indent">
<ul class="attr-list">
<li>
<b>
<code>'file.txt'</code>
</b>
<br />
<a href="++items++file.txt/@@introspector.html">
<code><zope.app.file.file.File object at ...></code>
</a>
(<span>type:</span>
<a href="http://localhost/++apidoc++/Code/zope/container/contained/ContainedProxy/index.html">
<code>ContainedProxy</code></a>)
...
The final section of the introspector displays the annotations that are declared for the object. The standard annotation that almost every object provides is the Dublin Core:
>>> print(browser.contents)
<!DOCTYPE...
...
<h2>Annotations</h2>
<div class="indent">
<ul class="attr-list">
<li>
<b>
<code>'zope.app.dublincore.ZopeDublinCore'</code>
</b>
<br />
<a href="++annotations++zope.app.dublincore.ZopeDublinCore/@@introspector.html">
<code>...</code>
</a>
(<span>type:</span>
<a href="http://localhost/++apidoc++/Code/zope/dublincore/annotatableadapter/ZDCAnnotationData/index.html">
<code>ZDCAnnotationData</code></a>)
</li>
</ul>
</div>
</div>
</div>
...
As you can see you can click on the annotation to discover it further;
the exact constructor signature varies depending on Python version
(some versions report *args, **kwargs
, others report dict=None,
**kwargs
):
>>> browser.getLink('ZDCAnnotationData').click()
>>> print(browser.contents)
<!DOCTYPE...
...
<h2 ...>Constructor</h2>
<div class="indent">
<div>
<b><code>__init__(..., **kwargs)</code>
</b><br />
<div class="inline documentation"></div>
</div>
...
That’s it! The introspector view has a lot more potential, but that’s for someone else to do.
Interfaces¶
The Interface Documentation Module¶
This documentation module allows you to inspect all aspects of an
interface and its role within the Zope 3 framework. The module
can be instantiated like all other documentation
modules:
>>> from zope.app.apidoc.ifacemodule.ifacemodule import InterfaceModule
>>> module = InterfaceModule()
After registering an interface
>>> from zope.interface import Interface
>>> class IFoo(Interface):
... pass
>>> from zope.component.interface import provideInterface
>>> provideInterface(None, IFoo)
>>> provideInterface('IFoo', IFoo)
Now let’s lookup an interface that is registered.
>>> module.get('IFoo')
<InterfaceClass __builtin__.IFoo>
>>> module.get(IFoo.__module__ + '.IFoo')
<InterfaceClass __builtin__.IFoo>
Now we find an interface that is not in the site manager, but exists.
>>> module.get('zope.app.apidoc.interfaces.IDocumentationModule')
<InterfaceClass zope.app.apidoc.interfaces.IDocumentationModule>
Finally, you can list all registered interfaces:
>>> ifaces = sorted(module.items())
>>> from pprint import pprint
>>> pprint(ifaces)
[...
(u'IFoo', <InterfaceClass __builtin__.IFoo>),
...
(u'__builtin__.IFoo', <InterfaceClass __builtin__.IFoo>),
...]
Utilities¶
The Utilities Documentation Module¶
This documentation module organizes all registered utilities by their provided interface and then by the name of the utility.
UtilityModule
¶
This class represents the documentation of all utility interfaces. The
items of the container are all UtilityInterface
instances.
Let’s start by creating a utility documentation module:
>>> from zope.app.apidoc.utilitymodule.utilitymodule import UtilityModule
>>> module = UtilityModule()
To make the documentation module useful, we have to register a utility, so why not the documentation module itself?
>>> from zope.app.apidoc.interfaces import IDocumentationModule
>>> from zope import component as ztapi
>>> ztapi.provideUtility(module, IDocumentationModule, 'Utility')
Now we can get a single utility interface by path:
>>> module.get('zope.app.apidoc.interfaces.IDocumentationModule')
<zope.app.apidoc.utilitymodule.utilitymodule.UtilityInterface ...>
and list all available interfaces:
>>> module.items()
[...
('zope.app.apidoc.interfaces.IDocumentationModule',
<zope.app.apidoc.utilitymodule.utilitymodule.UtilityInterface ...>),
...
('zope.security.interfaces.IPermission',
<zope.app.apidoc.utilitymodule.utilitymodule.UtilityInterface ...>),
...]
UtilityInterface
¶
Representation of an interface a utility provides.
First we create a utility interface documentation instance:
>>> from zope.app.apidoc.utilitymodule.utilitymodule import UtilityInterface
>>> ut_iface = UtilityInterface(
... module,
... 'zope.app.apidoc.interfaces.IDocumentationModule',
... IDocumentationModule)
Now we can get the utility:
>>> ut_iface.get('Utility').component
<zope.app.apidoc.utilitymodule.utilitymodule.UtilityModule object at ...>
Unnamed utilities are special, since they can be looked up in different ways:
>>> ztapi.provideUtility(module, IDocumentationModule, '')
>>> ut_iface.get('').component
<zope.app.apidoc.utilitymodule.utilitymodule.UtilityModule object at ...>
>>> from zope.app.apidoc.utilitymodule.utilitymodule import NONAME
>>> ut_iface.get(NONAME).component
<zope.app.apidoc.utilitymodule.utilitymodule.UtilityModule object at ...>
If you try to get a non-existent utility, None
is returned:
>>> ut_iface.get('foo') is None
True
You can get a list of available utilities as well, of course:
>>> ut_iface.items()
[...
(b'VXRpbGl0eQ==', <...apidoc.utilitymodule.utilitymodule.Utility ...>),
(b'X19ub25hbWVfXw==', <...apidoc.utilitymodule.utilitymodule.Utility ...>)]
Bu what are those strange names? Since utility names can be any string, it is
hard to deal with them in a URL. Thus the system will advertise and use the
names in their BASE64
encoded form. However, because it is easier in the
Python API to use the real utility names, utilities can be looked up in their
original form as well.
Encoding and Decoding Names¶
The utility names are en- and decoded using two helper methods:
>>> from zope.app.apidoc.utilitymodule.utilitymodule import encodeName
>>> from zope.app.apidoc.utilitymodule.utilitymodule import decodeName
Round trips of encoding
and decoding
should be possible:
>>> encoded = encodeName(u'Some Utility')
>>> encoded
b'U29tZSBVdGlsaXR5'
>>> decodeName(encoded)
u'Some Utility'
If a string is not encoded, the decoding process will simply return the original string:
>>> decodeName(u'Some Utility')
u'Some Utility'
ZCML¶
The ZCML Documentation Module¶
This documentation module provides you with a complete reference of all directives available on your Zope 3 installation.
ZCMLModule
¶
The ZCML module class manages all available ZCML namespaces. Once we initialize the module
>>> from zope.app.apidoc.zcmlmodule import ZCMLModule
>>> module = ZCMLModule()
it evaluates all meta directives and creates the namspace list:
>>> module.get('http://namespaces.zope.org/browser').getFullName()
'http://namespaces.zope.org/browser'
You can also access the namespace via its encoded form:
>>> module.get(
... 'http_co__sl__sl_namespaces.zope.org_sl_browser').getFullName()
'http://namespaces.zope.org/browser'
and via its short form:
>>> module.get('browser').getFullName()
'http://namespaces.zope.org/browser'
If the module does not exist, the usual None
is returned:
>>> module.get('foo') is None
True
You can also list all namespaces:
>>> names = [n for n, ns in module.items()]
>>> 'ALL' in names
True
>>> 'http_co__sl__sl_namespaces.zope.org_sl_browser' in names
True
>>> 'http_co__sl__sl_namespaces.zope.org_sl_meta' in names
True
Namespace
¶
Simple namespace object for the ZCML Documentation Module.
The namespace manages a particular ZCML namespace. The object always
expects the parent to be a ZCMLModule
instance. So let’s
create a namespace:
>>> module = ZCMLModule()
>>> from zope.app.apidoc.zcmlmodule import Namespace, _clear
>>> _clear()
>>> ns = Namespace(ZCMLModule(), 'http://namespaces.zope.org/browser')
We can now get its short name, which is the name without the URL prefix:
>>> ns.getShortName()
'browser'
and its full name in unquoted form:
>>> ns.getFullName()
'http://namespaces.zope.org/browser'
or even quoted:
>>> ns.getQuotedName()
'http_co__sl__sl_namespaces.zope.org_sl_browser'
One can get a directive using the common mapping interface:
>>> ns.get('pages').__name__
'pages'
>>> ns.get('foo') is None
True
>>> print('\n'.join([name for name, dir in ns.items()][:3]))
addMenuItem
addform
containerViews
quoteNS()
¶
Quotes a namespace to make it URL-secure.
>>> from zope.app.apidoc.zcmlmodule import quoteNS
>>> quoteNS('http://namespaces.zope.org/browser')
'http_co__sl__sl_namespaces.zope.org_sl_browser'
unquoteNS()
¶
Un-quotes a namespace from a URL-secure version.
>>> from zope.app.apidoc.zcmlmodule import unquoteNS
>>> unquoteNS('http_co__sl__sl_namespaces.zope.org_sl_browser')
'http://namespaces.zope.org/browser'
CHANGES¶
4.0.1 (unreleased)¶
- Host documentation at https://zopeappapidoc.readthedocs.io/
4.0.0 (2017-05-25)¶
- Add support for Python 3.4, 3.5, 3.6 and PyPy.
- The long-deprecated layer configuration was removed. It was only
ever available if the
deprecatedlayers
ZCML feature was installed. - Modernize some of the templates.
zope.app.apidoc
can now be used with Chameleon 3.2 via z3c.pt and z3c.ptcompat. - Declared install dependency on
zope.app.exception
. - Docstrings are treated as UTF-8 on Python 2.
- Handle keyword only arguments and annotations in function signatures on Python 3.
- Change the default documentation format to
restructuredtext
for modules that do not specify a__docformat__
. Previously it wasstructuredtext
(STX).
3.7.5 (2010-09-12)¶
- Define
__file__
in doctests to make them pass under Python 2.4.
3.7.4 (2010-09-01)¶
- Prefer the standard library’s doctest module to the one from zope.testing.
- Remove unneeded dependencies zope.app.component and zope.app.container
3.7.3 (2010-07-14)¶
- Apply refactoring from #153309.
- Fix LP bug 605057: ZCML links were no longer working (Guilherme Salgado)
3.7.2 (2010-03-07)¶
- Adapted tests for Python2.4
3.7.1 (2010-01-05)¶
- Updated tests to work with zope.publisher 3.12 (using
zope.login
).
3.7.0 (2009-12-22)¶
- Updated tests to work with latest
zope.testing
and usezope.browserpage
in favor ofzope.app.pagetemplate
.
3.6.8 (2009-11-18)¶
- Updated the tests after moving
IPossibleSite
andISite
tozope.component
.
3.6.7 (2009-09-29)¶
- Updated the tests after moving
ITraverser
back tozope.traversing
.
3.6.6 (2009-09-15)¶
- Made the tests work again with the most recent Zope Toolkit KGS.
3.6.5 (2009-07-24)¶
- Update documentation file in
zope.site
fromREADME.txt
tosite.txt
.
3.6.4 (2009-07-23)¶
- The
IContained
interface moved tozope.location.interfaces
. Make a test pass.
3.6.3 (2009-05-16)¶
- Explicitly defined default views.
- Replace relative url links with absolute ones.
- Added
z3c
packages to the code browser. - Made
bin/static-apidoc
principally working (publisher and webserver mode). There are still some files which are not correctly fetched.
3.6.2 (2009-03-17)¶
- Adapt principal registry book chapter to a new place, as it was moved from zope.app.security to zope.principalregistry.
- Remove zcml slugs and old zpkg-related files.
3.6.1 (2009-02-04)¶
- When a module provides an interface or has an __all__ attribute, use one of those for the module documentation. Fixes LP #323375.
- Undid broken link to
savepoint.txt
caused in 3.6.0. The latest version of the transaction package puts savepoint.txt in thetests
subpackage. - Expanded the presentation of module documentation.
- Class documentation now includes constructor information.
3.6.0 (2009-01-31)¶
- Use zope.container instead of zope.app.container.
- Use zope.site instead of zope.app.component and zope.app.folder (in at least a few places).
savepoint.txt
moved from ZODB’s test directory a level up – we follow.- Make compatible with new zope.traversing and zope.location.
3.5.0 (2009-01-17)¶
- Adapted transaction book chapters for new transaction egg. The README.txt was removed and savepoint.txt was moved. Also add chapter about dooming transactions (doom.txt).
- Changed mailing list address to zope-dev at zope.org, because zope3-dev is retired now.
- Cleaned up dependencies.
3.4.3 (2007-11-10)¶
- Fix https://bugs.launchpad.net/zope3/+bug/161737: Misleading text in the interface viewer.
- Fix https://bugs.launchpad.net/zope3/+bug/161190: The zope3-dev mailinglist has been retired, point to zope-dev.
3.4.2 (2007-10-30)¶
- Avoid deprecation warnings for
ZopeMessageFactory
.
3.4.1 (2007-10-23)¶
- Avoid deprecation warnings.
3.4.0 (2007-10-10)¶
- Improved package meta-data.
- Fixed the code to at least gracefully ignore unzipped eggs. Eventually we want to handle eggs well.
3.4.0a1 (2007-04-22)¶
- Initial release independent of the main Zope tree.
Project URLs¶
- https://pypi.python.org/pypi/zope.app.apidoc (PyPI entry and downloads)