[Zope3-checkins] SVN: Zope3/trunk/ Finished my work on the apidoc
tool. In this last milestone I rewrote the
Stephan Richter
srichter at cosmos.phy.tufts.edu
Sat Feb 26 09:16:05 EST 2005
Log message for revision 29309:
Finished my work on the apidoc tool. In this last milestone I rewrote the
ZCML parser once again and rearranged the documentation.
Please let me know, if you have suggestions for improvements.
Changed:
U Zope3/trunk/doc/CHANGES.txt
U Zope3/trunk/doc/TODO.txt
A Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt
U Zope3/trunk/src/zope/app/apidoc/codemodule/__init__.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/configure.zcml
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/directive.pt
D Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/ftests.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/tests.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/text.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcmlfile_index.pt
U Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/configure.zcml
A Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt
D Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/function.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/interfaces.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/module.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt
-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/doc/CHANGES.txt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -29,6 +29,8 @@
- API doctool has received some upgrades:
+ * Code Browser now also shows interfaces and text files.
+
* A new `bookmodule` compiles all our README.txt and other text
documentation files to a nice book-like format.
@@ -285,6 +287,9 @@
- Several changes have been made to the API doc tool:
+ + Rewrote the ZCML file parser to reuse the zope.configuration
+ code. This makes the code much more stable and predictable.
+
+ General inspection utilities are now *publically* available in the
modules: utilities, interface, component, presentation,
classregistry
Modified: Zope3/trunk/doc/TODO.txt
===================================================================
--- Zope3/trunk/doc/TODO.txt 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/doc/TODO.txt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -9,14 +9,6 @@
- Fix final issues relating the new PAS and related UIs
-- The API Doc Tool needs to be updated to reflect latest design changes
-
- o Better support for multi-adapters
-
- o Presentation components are now just adapters
-
- o Services will be utilities
-
- Develop a generic browser:form directive
- Support for iterable sources
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -0,0 +1,322 @@
+=========================
+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 `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.keys()
+ []
+
+
+Module
+------
+
+The `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'
+
+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
+
+ >>> print module['browser'].getPath()
+ zope.app.apidoc.browser
+
+Now, the ``get(key, default=None)`` 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:
+
+ >>> print module['tests'].getPath()
+ zope.app.apidoc.tests
+
+ >>> names = module['tests'].keys()
+ >>> names.sort()
+ >>> names
+ ['Root', 'rootLocation', 'setUp', 'test_suite']
+
+
+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'
+
+ >>> klass.getDocString()[:41]
+ 'Represent the complete API Documentation.'
+
+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
+`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', <unbound method APIDocumentation.get>, None)
+
+
+Let's have a closer look at the `getAttributes()` method. First we create an
+interface called `IBlah` that is implemented by the class `Blah`:
+
+ >>> import zope.interface
+ >>> class IBlah(zope.interface.Interface):
+ ... foo = zope.interface.Attribute('Foo')
+
+ >>> class Blah(object):
+ ... zope.interface.implements(IBlah)
+ ... foo = 'f'
+ ... bar = 'b'
+ ... _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)
+
+ >>> pprint(klass.getAttributes())
+ [('bar', 'b', None),
+ ('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
+
+ >>> class Blah(object):
+ ... zope.interface.implements(IBlah)
+ ...
+ ... 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 documenation:
+
+ >>> pprint(klass.getMethods())
+ [('bar', <unbound method Blah.bar>, None),
+ ('foo', <unbound method Blah.foo>, <InterfaceClass __builtin__.IBlah>)]
+
+
+Function
+--------
+
+Function are pretty much documented in the same way as all other code
+documentation objects and provides a similar API to the classes. A function
+documenation 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.txt')
+ >>> readme = codemodule.text.TextFile(path, 'README.txt', module)
+
+we can ask it for the content of the file:
+
+ >>> print readme.getContent()[:77]
+ =========================
+ Code Documentation Module
+ =========================
+
+
+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)
+
+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 #doctest:+ELLIPSIS
+ <zope.configuration.config.ConfigurationMachine object at ...>
+
+the parser info object,
+
+ >>> root.info
+ File
+ "/opt/zope/Zope3/Zope3-Fresh/src/zope/app/apidoc/codemodule/configure.zcml",
+ line 1.0-53.0
+
+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}
+
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/__init__.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/__init__.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -1,121 +1 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Code Documentation Module
-
-This module is able to take a dotted name of any class and display
-documentation for it.
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-from zope.interface import Interface, implements
-from zope.app import zapi
-from zope.app.i18n import ZopeMessageIDFactory as _
-from zope.app.location.interfaces import ILocation
-
-from zope.app.apidoc.interfaces import IDocumentationModule
-from zope.app.apidoc.classregistry import safe_import
-from zope.app.apidoc.codemodule.module import Module
-
-
-class IAPIDocRootModule(Interface):
- """Marker interface for utilities that represent class browser root
- modules.
-
- The utilities will be simple strings, representing the modules Python
- dotted name.
- """
-
-
-class CodeModule(Module):
- """Represent the Documentation of any possible source code in the packages.
-
- This object extends a module, since it can be seen as some sort of root
- module. However, its sementacs are obviously a bit different::
-
- >>> cm = CodeModule()
-
- >>> cm.getDocString()
- u'Zope 3 root.'
- >>> cm.getFileName()
- ''
- >>> cm.getPath()
- ''
-
- >>> names = cm.keys()
- >>> names.sort()
- >>> names
- [u'zope']
- """
- implements(IDocumentationModule)
-
- # See zope.app.apidoc.interfaces.IDocumentationModule
- title = _('Code Browser')
-
- # See zope.app.apidoc.interfaces.IDocumentationModule
- description = _("""
- This module allows you to get an overview of the modules and classes
- defined in the Zope 3 framework and its supporting packages. There are
- two methods to navigate through the modules to find the classes you are
- interested in.
-
- The first method is to type in some part of the Python path of the class
- and the module will look in the class registry for matches. The menu will
- then return with a list of these matches.
-
- The second method is to click on the "Browse Zope Source" link. In the
- main window, you will see a directory listing with the root Zope 3
- modules. You can click on the module names to discover their content. If a
- class is found, it is represented as a bold entry in the list.
-
- The documentation contents of a class provides you with an incredible
- amount of information. Not only does it tell you about its base classes,
- implemented interfaces, attributes and methods, but it also lists the
- interface that requires a method or attribute to be implemented and the
- permissions required to access it.
- """)
- def __init__(self):
- """Initialize object."""
- super(CodeModule, self).__init__(None, '', None, False)
- self.__isSetup = False
-
- def setup(self):
- """Setup module and class tree."""
- if self.__isSetup:
- return
- for name, mod in zapi.getUtilitiesFor(IAPIDocRootModule):
- self._children[name] = Module(self, name, safe_import(mod))
- self.__isSetup = True
-
- def getDocString(self):
- """See Module class."""
- return _('Zope 3 root.')
-
- def getFileName(self):
- """See Module class."""
- return ''
-
- def getPath(self):
- """See Module class."""
- return ''
-
- def get(self, key, default=None):
- """See zope.app.container.interfaces.IReadContainer."""
- self.setup()
- return super(CodeModule, self).get(key, default)
-
- def items(self):
- """See zope.app.container.interfaces.IReadContainer."""
- self.setup()
- return super(CodeModule, self).items()
+# Make a package
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -0,0 +1,378 @@
+====================================
+Code Browser Presentation Components
+====================================
+
+This document describes the API of the views complementing the varius 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:
+
+ >>> from zope.app import zapi
+ >>> from zope.app.apidoc.interfaces import IDocumentationModule
+ >>> cm = zapi.getUtility(IDocumentationModule, '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:
+
+ >>> details = browser.module.ModuleDetails()
+ >>> details.context = zapi.traverse(cm,
+ ... 'zope/app/apidoc/codemodule/codemodule')
+ >>> from zope.publisher.browser import TestRequest
+ >>> details.request = TestRequest()
+
+`getDoc()`
+~~~~~~~~~~
+
+Get the doc string of the module formatted in STX or ReST.
+
+ >>> print details.getDoc().strip()
+ <div class="document">
+ <p>Code Documentation Module</p>
+ <p>This module is able to take a dotted name of any class and display
+ documentation for it.</p>
+ </div>
+
+`getEntries(columns=True)`
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Return info objects for all modules and classes in this module.
+
+ >>> pprint(details.getEntries(False))
+ [{'isclass': True,
+ 'isfunction': False,
+ 'isinterface': False,
+ 'ismodule': False,
+ 'istextfile': False,
+ 'iszcmlfile': False,
+ 'name': 'CodeModule',
+ 'url': 'http://127.0.0.1/zope/app/apidoc/codemodule/codemodule/CodeModule'}]
+
+`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.
+
+ >>> pprint(details.getBreadCrumbs())
+ [{'name': u'[top]',
+ 'url': 'http://127.0.0.1'},
+ {'name': u'zope',
+ 'url': 'http://127.0.0.1/zope'},
+ {'name': 'app',
+ 'url': 'http://127.0.0.1/zope/app'},
+ {'name': 'apidoc',
+ 'url': 'http://127.0.0.1/zope/app/apidoc'},
+ {'name': 'codemodule',
+ 'url': 'http://127.0.0.1/zope/app/apidoc/codemodule'},
+ {'name': 'codemodule',
+ 'url': 'http://127.0.0.1/zope/app/apidoc/codemodule/codemodule'}]
+
+
+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 = zapi.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:
+
+`getBases()`
+~~~~~~~~~~~
+
+Get all bases of this class.
+
+ >>> pprint(details.getBases())
+ [{'path': 'zope.app.apidoc.codemodule.module.Module',
+ 'url': 'http://127.0.0.1/zope/app/apidoc/codemodule/module/Module'}]
+
+`getKnownSubclasses()`
+~~~~~~~~~~~~~~~~~~~~~~
+Get all known subclasses of this class.
+
+ >>> details.getKnownSubclasses()
+ []
+
+`_listClasses(classes)`
+~~~~~~~~~~~~~~~~~~~~~~~
+
+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/zope/app/apidoc/apidoc/APIDocumentation'},
+ {'path': 'zope.app.apidoc.codemodule.module.Module',
+ 'url': 'http://127.0.0.1/zope/app/apidoc/codemodule/module/Module'}]
+
+`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'
+
+`getInterfaces()`
+~~~~~~~~~~~~~~~~~
+
+Get all implemented interfaces (as paths) of this class.
+
+ >>> pprint(details.getInterfaces())
+ ['zope.app.apidoc.interfaces.IDocumentationModule',
+ 'zope.app.location.interfaces.ILocation',
+ 'zope.app.apidoc.codemodule.interfaces.IModuleDocumentation',
+ 'zope.app.container.interfaces.IReadContainer']
+
+`getAttributes()`
+~~~~~~~~~~~~~~~~~
+
+Get all attributes of this class.
+
+ >>> pprint(details.getAttributes()[1])
+ {'interface': 'zope.app.apidoc.interfaces.IDocumentationModule',
+ 'name': 'title',
+ 'read_perm': None,
+ 'type': 'MessageID',
+ 'type_link': 'zope/i18nmessageid/messageid/MessageID',
+ 'value': "u'Code Browser'",
+ 'write_perm': None}
+
+`getMethods()`
+~~~~~~~~~~~~~~
+Get all methods of this class.
+
+ >>> pprint(details.getMethods()[-2:])
+ [{'doc': u'<div class="document">\nSetup module and class tree.</div>\n',
+ 'interface': None,
+ 'name': 'setup',
+ 'read_perm': None,
+ 'signature': '()',
+ 'write_perm': None},
+ {'doc': u'',
+ 'interface': 'zope.interface.common.mapping.IEnumerableMapping',
+ 'name': 'values',
+ 'read_perm': None,
+ 'signature': '()',
+ 'write_perm': None}]
+
+`getDoc()`
+~~~~~~~~~~
+
+Get the doc string of the class STX formatted.
+
+ >>> print details.getDoc()[:-1]
+ <div class="document">
+ Represent the code browser documentation root</div>
+
+
+Function Details
+----------------
+
+This is the same deal as before, use the path to generate the function
+documentation component:
+
+ >>> details = browser.function.FunctionDetails()
+ >>> details.context = zapi.traverse(cm,
+ ... 'zope/app/apidoc/codemodule/browser/tests/foo')
+ >>> details.request = TestRequest()
+
+Here are the methods:
+
+`getDocString()`
+~~~~~~~~~~~~~~~~
+
+Get the doc string of the function in a rendered format.
+
+ >>> details.getDocString()
+ u'<div class="document">\nThis is the foo function.</div>\n'
+
+`getAttributes()`
+~~~~~~~~~~~~~~~~~
+
+Get all attributes of this function.
+
+ >>> attr = details.getAttributes()[0]
+ >>> pprint(attr)
+ {'name': 'deprecated',
+ 'type': 'bool',
+ 'type_link': '__builtin__/bool',
+ 'value': 'True'}
+
+
+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 = zapi.traverse(cm,
+ ... 'zope/app/apidoc/codemodule/README.txt')
+ >>> details.request = TestRequest()
+
+Here are the methods:
+
+`renderedContent()`
+~~~~~~~~~~~~~~~~~~~
+
+Render the file content to HTML.
+
+ >>> print details.renderedContent()[54:102]
+ <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 = zapi.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:
+
+`fullTagName()`
+~~~~~~~~~~~~~~~
+
+Return the name of the directive, including prefix, if applicable.
+
+ >>> details.fullTagName()
+ u'configure'
+
+`line()`
+~~~~~~~~
+
+Return the line (as a string) at which this directive starts.
+
+ >>> details.line()
+ '1'
+
+`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'
+
+`url()`
+~~~~~~~
+
+Returns the URL of the directive docuemntation in the ZCML documentation
+module.
+
+ >>> details.url()
+ u'http://127.0.0.1/../ZCML/ALL/configure/index.html'
+
+The result is a bit strange, since the ZCML Documentation module is the
+containment root.
+
+`ifaceURL(value, field, rootURL)`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method converts the string value of the field to an interface and then
+crafts a documentation URL for it:
+
+ >>> from zope.configuration.fields import GlobalInterface
+ >>> field = GlobalInterface()
+
+ >>> details.ifaceURL('.interfaces.IZCMLFile', field, '')
+ '/../Interface/zope.app.apidoc.codemodule.interfaces.IZCMLFile/apiindex.html'
+
+`objectURL(value, field, rootURL)`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+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, '')
+ '/../Interface/zope.app.apidoc.codemodule.interfaces.IZCMLFile/apiindex.html'
+
+ >>> details.objectURL('.zcml.ZCMLFile', field, '')
+ '/zope/app/apidoc/codemodule/zcml/ZCMLFile/index.html'
+
+`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/zope/app/apidoc/codemodule/module/Module/index.html',
+ 'value': u'.module.Module',
+ 'values': []}]
+
+`hasSubDirectives()`
+~~~~~~~~~~~~~~~~~~~~
+
+Returns `True`, if the directive has subdirectives; otherwise `False` is
+returned.
+
+ >>> details.hasSubDirectives()
+ True
+
+`getElements()`
+~~~~~~~~~~~~~~~
+
+Returns a list of all sub-directives:
+
+ >>> details.getElements()
+ [<Directive (u'http://namespaces.zope.org/zope', u'allow')>]
+
\ No newline at end of file
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -36,62 +36,18 @@
"""Represents the details of the class."""
def getBases(self):
- """Get all bases of this class.
-
- Example::
-
- The class we are using for this view is
- zope.app.apidoc.classmodule.ClassModule.
-
- >>> import pprint
- >>> from tests import getClassDetailsView
- >>> view = getClassDetailsView()
-
- >>> pprint.pprint(view.getBases())
- [{'path': 'zope.app.apidoc.classmodule.Module',
- 'url': 'http://127.0.0.1/zope/app/apidoc/classmodule/Module'}]
- """
+ """Get all bases of this class."""
return self._listClasses(self.context.getBases())
def getKnownSubclasses(self):
- """Get all known subclasses of this class.
-
- Example::
-
- The class we are using for this view is
- zope.app.apidoc.classmodule.ClassModule.
-
- >>> import pprint
- >>> from tests import getClassDetailsView
- >>> view = getClassDetailsView()
-
- >>> pprint.pprint(view.getKnownSubclasses())
- []
- """
+ """Get all known subclasses of this class."""
entries = self._listClasses(self.context.getKnownSubclasses())
entries.sort(lambda x, y: cmp(x['path'], y['path']))
return entries
def _listClasses(self, classes):
- """Prepare a list of classes for presentation.
-
- Example::
-
- >>> import pprint
- >>> from tests import getClassDetailsView
- >>> view = getClassDetailsView()
- >>> import zope.app.apidoc
- >>> import zope.app.apidoc.classmodule
-
- >>> pprint.pprint(view._listClasses([
- ... zope.app.apidoc.APIDocumentation,
- ... zope.app.apidoc.classmodule.Module]))
- [{'path': 'zope.app.apidoc.APIDocumentation',
- 'url': 'http://127.0.0.1/zope/app/apidoc/APIDocumentation'},
- {'path': 'zope.app.apidoc.classmodule.Module',
- 'url': 'http://127.0.0.1/zope/app/apidoc/classmodule/Module'}]
- """
+ """Prepare a list of classes for presentation."""
info = []
codeModule = zapi.getUtility(IDocumentationModule, "Code")
for cls in classes:
@@ -113,66 +69,18 @@
def getBaseURL(self):
- """Return the URL for the API Documentation Tool.
-
- Example::
-
- >>> from tests import getClassDetailsView
- >>> view = getClassDetailsView()
-
- Note that the following output is a bit different than usual, since
- we have not setup all path elements.
-
- >>> view.getBaseURL()
- 'http://127.0.0.1'
- """
+ """Return the URL for the API Documentation Tool."""
m = zapi.getUtility(IDocumentationModule, "Code")
return zapi.absoluteURL(zapi.getParent(m), self.request)
def getInterfaces(self):
- """Get all implemented interfaces (as paths) of this class.
-
- Example::
-
- The class we are using for this view is
- zope.app.apidoc.classmodule.ClassModule.
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getClassDetailsView
- >>> view = getClassDetailsView()
-
- >>> pprint(view.getInterfaces())
- ['zope.app.apidoc.interfaces.IDocumentationModule',
- 'zope.app.location.interfaces.ILocation',
- 'zope.app.apidoc.classmodule.IModuleDocumentation',
- 'zope.app.container.interfaces.IReadContainer']
- """
+ """Get all implemented interfaces (as paths) of this class."""
return map(getPythonPath, self.context.getInterfaces())
def getAttributes(self):
- """Get all attributes of this class.
-
- Example::
-
- The class we are using for this view is
- zope.app.apidoc.classmodule.ClassModule.
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getClassDetailsView
- >>> view = getClassDetailsView()
-
- >>> attr = view.getAttributes()[1]
- >>> pprint(attr)
- [('interface', 'zope.app.apidoc.interfaces.IDocumentationModule'),
- ('name', 'title'),
- ('read_perm', None),
- ('type', 'MessageID'),
- ('type_link', 'zope.i18nmessageid.messageid.MessageID'),
- ('value', "u'Classes'"),
- ('write_perm', None)]
- """
+ """Get all attributes of this class."""
attrs = []
for name, attr, iface in self.context.getAttributes():
entry = {'name': name,
@@ -190,34 +98,7 @@
def getMethods(self):
- """Get all methods of this class.
-
- Example::
-
- The class we are using for this view is
- zope.app.apidoc.classmodule.ClassModule.
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getClassDetailsView
- >>> view = getClassDetailsView()
-
- >>> methods = view.getMethods()
- >>> pprint(methods[-2:])
- [[('doc', u''),
- ('interface',
- 'zope.interface.common.mapping.IEnumerableMapping'),
- ('name', 'keys'),
- ('read_perm', None),
- ('signature', '()'),
- ('write_perm', None)],
- [('doc', u''),
- ('interface',
- 'zope.interface.common.mapping.IEnumerableMapping'),
- ('name', 'values'),
- ('read_perm', None),
- ('signature', '()'),
- ('write_perm', None)]]
- """
+ """Get all methods of this class."""
methods = []
# remove the security proxy, so that `attr` is not proxied. We could
# unproxy `attr` for each turn, but that would be less efficient.
@@ -237,19 +118,7 @@
def getDoc(self):
- """Get the doc string of the class STX formatted.
-
- Example::
-
- The class we are using for this view is
- zope.app.apidoc.classmodule.ClassModule.
-
- >>> from tests import getClassDetailsView
- >>> view = getClassDetailsView()
-
- >>> print view.getDoc()[23:80]
- <p>Represent the Documentation of any possible class.</p>
- """
+ """Get the doc string of the class STX formatted."""
return renderText(self.context.getDocString() or '',
zapi.getParent(self.context).getPath())
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/configure.zcml 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/configure.zcml 2005-02-26 14:16:04 UTC (rev 29309)
@@ -3,7 +3,7 @@
xmlns:zope="http://namespaces.zope.org/zope">
<page
- for="..CodeModule"
+ for="..codemodule.CodeModule"
permission="zope.app.apidoc.UseAPIDoc"
class=".menu.Menu"
name="menu.html"
@@ -39,7 +39,7 @@
<!-- ZCML File -->
<page
- for="..interfaces.IConfiguration"
+ for="..interfaces.IZCMLFile"
name="index.html"
template="zcmlfile_index.pt"
permission="zope.View"/>
@@ -47,16 +47,8 @@
<page
name="display"
for="..interfaces.IDirective"
- template="displayDirective.pt"
- class=".zcml.DisplayDirective"
+ template="directive.pt"
+ class=".zcml.DirectiveDetails"
permission="zope.ManageContent"/>
- <page
- name="display"
- for="..interfaces.IComment"
- template="displayComment.pt"
- class=".zcml.DisplayComment"
- permission="zope.ManageContent"/>
-
-
</configure>
Copied: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/directive.pt (from rev 29294, Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt)
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt 2005-02-25 03:38:07 UTC (rev 29294)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/directive.pt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -0,0 +1,47 @@
+<div class="directive"
+ tal:attributes="class string:directive ${view/highlight}">
+ <a name="" tal:attributes="name view/line" />
+ <<a href="" tal:attributes="href view/url"
+ ><span class="tagName" tal:content="view/fullTagName">tagName</span></a>
+ <br />
+
+ <span tal:repeat="attr view/attributes">
+
+ <span tal:condition="not: attr/values">
+ <span class="attributeName" tal:content="attr/name">
+ name
+ </span>="<a tal:attributes="href attr/url"><span
+ class="attributeValue"
+ tal:content="attr/value">value</span></a>"
+ </span>
+ <span tal:condition="attr/values">
+ <span class="attributeName" tal:content="attr/name">
+ name
+ </span>="
+ <div tal:repeat="entry attr/values">
+
+ <a tal:attributes="href entry/url"><span
+ class="attributeValue"
+ tal:content="entry/value">value</span></a>
+ </div>
+ "
+ </span>
+ <br />
+ </span>
+
+ <span tal:condition="view/hasSubDirectives">></span>
+ <span tal:condition="not:view/hasSubDirectives">/></span>
+</div>
+
+<div style="margin-left: 1.5em;">
+ <tal:block repeat="element view/getElements">
+ <tal:block replace="structure element/@@display" />
+ </tal:block>
+</div>
+
+<div class="directive"
+ tal:condition="view/hasSubDirectives">
+ </<span class="tagName"
+ tal:content="view/fullTagName" />>
+
+</div>
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -1,30 +0,0 @@
-<div class="directive">
- <<!--a href="" tal:attributes="href view/url"
- --><span class="tagName" tal:content="view/fullTagName">tagName</span><!--/a-->
- <br />
-
- <span tal:repeat="attr view/attributes">
-
- <span class="attributeName" tal:content="attr/name">
- name
- </span>="<!--a tal:attributes="href attr/url"--><span
- class="attributeValue"
- tal:content="attr/value">value</span><!--/a-->"
- <br />
- </span>
-
- <span tal:condition="view/hasSubDirectives">></span>
- <span tal:condition="not:view/hasSubDirectives">/></span>
-</div>
-
-<div style="margin-left: 1.5em;">
- <tal:block repeat="element view/getElements">
- <tal:block replace="structure element/@@display" />
- </tal:block>
-</div>
-
-<div class="directive"
- tal:condition="view/hasSubDirectives">
- </<span class="tagName"
- tal:content="context/getFullTagName" />>
-</div>
Copied: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/ftests.py (from rev 29294, Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py)
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py 2005-02-25 03:38:07 UTC (rev 29294)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/ftests.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -0,0 +1,102 @@
+##############################################################################
+#
+# Copyright (c) 2003, 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Functional Tests for Code Documentation Module.
+
+$Id$
+"""
+import unittest
+from zope.app.testing.functional import BrowserTestCase
+
+class CodeModuleTests(BrowserTestCase):
+ """Just a couple of tests ensuring that the templates render."""
+
+ def testMenu(self):
+ response = self.publish('/++apidoc++/Code/menu.html',
+ basic='mgr:mgrpw')
+ self.assertEqual(response.getStatus(), 200)
+ body = response.getBody()
+ self.assert_(body.find('Zope Source') > 0)
+ self.checkForBrokenLinks(body, '/++apidoc++/Code/menu.html',
+ basic='mgr:mgrpw')
+
+ def testMenuCodeFinder(self):
+ response = self.publish('/++apidoc++/Code/menu.html',
+ basic='mgr:mgrpw',
+ form={'path': 'Code', 'SUBMIT': 'Find'})
+ self.assertEqual(response.getStatus(), 200)
+ body = response.getBody()
+ self.assert_(
+ body.find('zope.app.apidoc.codemodule.codemodule.CodeModule') > 0)
+ self.checkForBrokenLinks(body, '/++apidoc++/Code/menu.html',
+ basic='mgr:mgrpw')
+
+ def testModuleDetailsView(self):
+ response = self.publish('/++apidoc++/Code/zope/app/apidoc/apidoc',
+ basic='mgr:mgrpw')
+ self.assertEqual(response.getStatus(), 200)
+ body = response.getBody()
+ self.assert_(body.find('Zope 3 API Documentation') > 0)
+ self.checkForBrokenLinks(
+ body, '/++apidoc++/Code/zope/app/apidoc/apidoc', basic='mgr:mgrpw')
+
+ def testClassDetailsView(self):
+ response = self.publish(
+ '/++apidoc++/Code/zope/app/apidoc/apidoc/APIDocumentation',
+ basic='mgr:mgrpw')
+ self.assertEqual(response.getStatus(), 200)
+ body = response.getBody()
+ self.assert_(body.find('Represent the complete API Documentation.') > 0)
+ self.checkForBrokenLinks(
+ body, '/++apidoc++/Code/zope/app/apidoc/apidoc/APIDocumentation',
+ basic='mgr:mgrpw')
+
+ def testFunctionDetailsView(self):
+ response = self.publish(
+ '/++apidoc++/Code/zope/app/apidoc/apidoc/handleNamespace',
+ basic='mgr:mgrpw')
+ self.assertEqual(response.getStatus(), 200)
+ body = response.getBody()
+ self.assert_(body.find('handleNamespace(ob, name)') > 0)
+ self.checkForBrokenLinks(
+ body, '/++apidoc++/Code/zope/app/apidoc/apidoc/handleNamesapce',
+ basic='mgr:mgrpw')
+
+ def testTextFileDetailsView(self):
+ response = self.publish(
+ '/++apidoc++/Code/zope/app/apidoc/README.txt/index.html',
+ basic='mgr:mgrpw')
+ self.assertEqual(response.getStatus(), 200)
+ body = response.getBody()
+ self.checkForBrokenLinks(
+ body, '/++apidoc++/Code/zope/app/apidoc/README.txt/index.html',
+ basic='mgr:mgrpw')
+
+ def testZCMLFileDetailsView(self):
+ response = self.publish(
+ '/++apidoc++/Code/zope/app/apidoc/configure.zcml/index.html',
+ basic='mgr:mgrpw')
+ self.assertEqual(response.getStatus(), 200)
+ body = response.getBody()
+ self.checkForBrokenLinks(
+ body, '/++apidoc++/Code/zope/app/apidoc/configure.zcml/index.html',
+ basic='mgr:mgrpw')
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(CodeModuleTests),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -23,36 +23,13 @@
"""Represents the details of the function."""
def getDocString(self):
- r"""Get the doc string of the function in a rendered format.
-
- Example::
-
- >>> from tests import getFunctionDetailsView
- >>> view = getFunctionDetailsView()
-
- >>> view.getDocString()
- u'<p>This is the foo function.</p>\n'
- """
+ """Get the doc string of the function in a rendered format."""
return renderText(self.context.getDocString() or '',
zapi.getParent(self.context).getPath())
def getAttributes(self):
- """Get all attributes of this function.
-
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getFunctionDetailsView
- >>> view = getFunctionDetailsView()
-
- >>> attr = view.getAttributes()[0]
- >>> pprint(attr)
- [('name', 'deprecated'),
- ('type', 'bool'),
- ('type_link', '__builtin__/bool'),
- ('value', 'True')]
- """
+ """Get all attributes of this function."""
return [{'name': name,
'value': `attr`,
'type': type(attr).__name__,
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -28,29 +28,14 @@
from zope.app.apidoc.codemodule.class_ import Class
from zope.app.apidoc.codemodule.function import Function
from zope.app.apidoc.codemodule.text import TextFile
-from zope.app.apidoc.codemodule.zcml import Configuration
+from zope.app.apidoc.codemodule.zcml import ZCMLFile
class ModuleDetails(object):
"""Represents the details of the module."""
def getDoc(self):
- """Get the doc string of the module STX formatted.
-
- Example::
-
- The class we are using for this view is zope.app.apidoc.classmodule.
-
- >>> from tests import getModuleDetailsView
- >>> view = getModuleDetailsView()
-
- >>> print view.getDoc().strip()
- <div class="document">
- <p>Class Documentation Module</p>
- <p>This module is able to take a dotted name of any class and display
- documentation for it.</p>
- </div>
- """
+ """Get the doc string of the module STX formatted."""
text = self.context.getDocString()
if text is None:
return None
@@ -60,32 +45,7 @@
return renderText('\n'.join(lines), self.context.getPath())
def getEntries(self, columns=True):
- """Return info objects for all modules and classes in this module.
-
- Example::
-
- The class we are using for this view is zope.app.apidoc.classmodule.
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getModuleDetailsView
- >>> view = getModuleDetailsView()
-
- >>> entries = view.getEntries(False)
- >>> entries.sort(lambda x, y: cmp(x['name'], y['name']))
- >>> pprint(entries[6:8])
- [[('isclass', False),
- ('isfunction', False),
- ('ismodule', True),
- ('iszcmlfile', False),
- ('name', 'browser'),
- ('url', 'http://127.0.0.1/zope/app/apidoc/classmodule/browser')],
- [('isclass', False),
- ('isfunction', True),
- ('ismodule', False),
- ('iszcmlfile', False),
- ('name', 'cleanUp'),
- ('url', 'http://127.0.0.1/zope/app/apidoc/classmodule/cleanUp')]]
- """
+ """Return info objects for all modules and classes in this module."""
entries = [{'name': name,
'url': zapi.absoluteURL(obj, self.request),
'ismodule': zapi.isinstance(obj, Module),
@@ -94,7 +54,7 @@
'isclass': zapi.isinstance(obj, Class),
'isfunction': zapi.isinstance(obj, Function),
'istextfile': zapi.isinstance(obj, TextFile),
- 'iszcmlfile': zapi.isinstance(obj, Configuration)}
+ 'iszcmlfile': zapi.isinstance(obj, ZCMLFile)}
for name, obj in self.context.items()]
entries.sort(lambda x, y: cmp(x['name'], y['name']))
if columns:
@@ -105,23 +65,7 @@
"""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.
-
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getModuleDetailsView
- >>> view = getModuleDetailsView()
-
- >>> crumbs = [crumb.items() for crumb in view.getBreadCrumbs()]
- >>> pprint(crumbs)
- [[('url', 'http://127.0.0.1'), ('name', u'[top]')],
- [('url', 'http://127.0.0.1/zope'), ('name', u'zope')],
- [('url', 'http://127.0.0.1/zope/app'), ('name', 'app')],
- [('url', 'http://127.0.0.1/zope/app/apidoc'), ('name', 'apidoc')],
- [('url', 'http://127.0.0.1/zope/app/apidoc/classmodule'),
- ('name', 'classmodule')]]
- """
+ way up to the root, but we just want to go to the root module."""
names = self.context.getPath().split('.')
crumbs = []
module = self.context
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/tests.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/tests.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -0,0 +1,108 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for the Code Documentation Module
+
+$Id: tests.py 29269 2005-02-23 22:22:48Z srichter $
+"""
+import os
+import unittest
+from zope.component.interfaces import IFactory
+from zope.configuration import xmlconfig
+from zope.interface import directlyProvides, implements
+from zope.testing import doctest, doctestunit
+
+import zope.app.appsetup.appsetup
+from zope.app.renderer.rest import ReStructuredTextSourceFactory
+from zope.app.renderer.rest import IReStructuredTextSource
+from zope.app.renderer.rest import ReStructuredTextToHTMLRenderer
+from zope.app.testing import placelesssetup, setup, ztapi
+from zope.app.traversing.interfaces import IContainmentRoot
+
+from zope.app.apidoc.interfaces import IDocumentationModule
+from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule
+from zope.app.apidoc.codemodule.codemodule import CodeModule
+from zope.app.apidoc.zcmlmodule import ZCMLModule
+
+# Just for loading purposes
+import zope.app.apidoc.codemodule.browser.module
+import zope.app.apidoc.codemodule.browser.class_
+import zope.app.apidoc.codemodule.browser.function
+import zope.app.apidoc.codemodule.browser.text
+import zope.app.apidoc.codemodule.browser.zcml
+
+def foo(cls, bar=1, *args):
+ """This is the foo function."""
+foo.deprecated = True
+
+def setUp(test):
+ placelesssetup.setUp()
+ setup.setUpTraversal()
+
+ class RootModule(str):
+ implements(IAPIDocRootModule)
+ ztapi.provideUtility(IAPIDocRootModule, RootModule('zope'), "zope")
+
+ module = CodeModule()
+ module.__name__ = ''
+ directlyProvides(module, IContainmentRoot)
+ ztapi.provideUtility(IDocumentationModule, module, "Code")
+
+ module = ZCMLModule()
+ module.__name__ = ''
+ directlyProvides(module, IContainmentRoot)
+ ztapi.provideUtility(IDocumentationModule, module, "ZCML")
+
+ # Register Renderer Components
+ ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory,
+ 'zope.source.rest')
+ ztapi.browserView(IReStructuredTextSource, '',
+ ReStructuredTextToHTMLRenderer)
+ # Cheat and register the ReST factory for STX as well.
+ ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory,
+ 'zope.source.stx')
+
+ meta = os.path.join(os.path.dirname(zope.app.__file__), 'meta.zcml')
+ context = xmlconfig.file(meta, zope.app)
+ meta = os.path.join(os.path.dirname(zope.app.apidoc.__file__), 'meta.zcml')
+ context = xmlconfig.file(meta, zope.app.apidoc, context)
+
+ # Fix up path for tests.
+ global old_context
+ old_context = zope.app.appsetup.appsetup.__config_context
+ zope.app.appsetup.appsetup.__config_context = context
+
+ # Fix up path for tests.
+ global old_source_file
+ old_source_file = zope.app.appsetup.appsetup.__config_source
+ zope.app.appsetup.appsetup.__config_source = os.path.join(
+ os.path.dirname(zope.app.__file__), 'meta.zcml')
+
+
+def tearDown(test):
+ placelesssetup.tearDown()
+ global old_context, old_source_file
+ zope.app.appsetup.appsetup.__config_context = old_context
+ zope.app.appsetup.appsetup.__config_source = old_source_file
+
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('README.txt',
+ setUp=setUp, tearDown=tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(default="test_suite")
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/tests.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/text.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/text.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/text.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -22,6 +22,7 @@
"""Represents the details of the text file."""
def renderedContent(self):
+ """Render the file content to HTML."""
if self.context.path.endswith('.stx'):
format = 'zope.source.stx'
else:
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -16,8 +16,9 @@
$Id$
"""
__docformat__ = "reStructuredText"
-from zope.configuration.fields import GlobalObject, GlobalInterface
+from zope.configuration.fields import GlobalObject, GlobalInterface, Tokens
from zope.interface import implements
+from zope.interface.interfaces import IInterface
from zope.schema import getFieldNamesInOrder, getFieldsInOrder
from zope.schema.interfaces import IFromUnicode
from zope.security.proxy import removeSecurityProxy
@@ -27,6 +28,8 @@
from zope.app.apidoc.interfaces import IDocumentationModule
from zope.app.apidoc.utilities import getPythonPath
+from zope.app.apidoc.codemodule.interfaces import IRootDirective
+
def findDocModule(obj):
if IDocumentationModule.providedBy(obj):
return obj
@@ -44,83 +47,117 @@
valueY = 999999
return cmp(valueX, valueY)
-
-class DisplayComment(object):
- value = property(lambda self: self.context.value)
+class DirectiveDetails(object):
- id = property(lambda self: IUniqueId(self.context).getId())
+ def fullTagName(self):
+ context = removeSecurityProxy(self.context)
+ ns, name = context.name
+ if context.prefixes[ns]:
+ return '%s:%s' %(context.prefixes[ns], name)
+ else:
+ return name
+ def line(self):
+ return str(removeSecurityProxy(self.context).info.line)
-class DisplayDirective(object):
+ def highlight(self):
+ if self.request.get('line') == self.line():
+ return 'highlight'
+ return ''
- id = property(lambda self: IUniqueId(self.context).getId())
-
- fullTagName = property(lambda self: self.context.getFullTagName())
-
def url(self):
- # XXX: Determine URLs of directives that are in all namespaces
context = removeSecurityProxy(self.context)
- ns = context.domElement.namespaceURI
+ ns, name = context.name
ns = ns.replace(':', '_co_')
ns = ns.replace('/', '_sl_')
zcml = zapi.getUtility(IDocumentationModule, 'ZCML')
+ if name not in zcml[ns]:
+ ns = 'ALL'
return '%s/../ZCML/%s/%s/index.html' %(
- zapi.absoluteURL(findDocModule(self), self.request), ns,
- context.domElement.localName)
+ zapi.absoluteURL(findDocModule(self), self.request), ns, name)
+ def ifaceURL(self, value, field, rootURL):
+ bound = field.bind(self.context.context)
+ iface = bound.fromUnicode(value)
+ return rootURL+'/../Interface/%s/apiindex.html' %(getPythonPath(iface))
+
+ def objectURL(self, value, field, rootURL):
+ bound = field.bind(self.context.context)
+ obj = bound.fromUnicode(value)
+ if IInterface.providedBy(obj):
+ return rootURL+'/../Interface/%s/apiindex.html' %(
+ getPythonPath(obj))
+ try:
+ return rootURL + '/%s/index.html' %(
+ getPythonPath(obj).replace('.', '/'))
+ except AttributeError:
+ # probably an instance
+ pass
def attributes(self):
- schema = removeSecurityProxy(self.context.schema)
- resolver = self.context.config.getResolver()
- attrs = [{'name': name, 'value': value, 'url': None}
- for name, value in self.context.getAttributeMap().items()]
+ context = removeSecurityProxy(self.context)
+ attrs = [{'name': (ns and context.prefixes[ns]+':' or '') + name,
+ 'value': value, 'url': None, 'values': []}
+ for (ns, name), value in context.attrs.items()]
+ names = context.schema.names(True)
+ rootURL = zapi.absoluteURL(findDocModule(self), self.request)
for attr in attrs:
- if name in schema:
- field = schema[name]
- elif name+'_' in schema:
- field = schema[name+'_']
- else:
- continue
+ name = (attr['name'] in names) and attr['name'] or attr['name']+'_'
+ field = context.schema.get(name)
+ if zapi.isinstance(field, GlobalInterface):
+ attr['url'] = self.ifaceURL(attr['value'], field, rootURL)
+
+ elif zapi.isinstance(field, GlobalObject):
+ attr['url'] = self.objectURL(attr['value'], field, rootURL)
- # XXX: This is extremly brittle!!!
- # Handle tokens; handle instances
- if isinstance(field, GlobalInterface):
- bound = field.bind(resolver)
- converter = IFromUnicode(bound)
- try:
- value = converter.fromUnicode(attr['value'])
- except: continue
- attr['url'] = '%s/../Interface/%s/apiindex.html' %(
- zapi.absoluteURL(findDocModule(self), self.request),
- getPythonPath(value))
+ elif zapi.isinstance(field, Tokens):
+ field = field.value_type
+ values = attr['value'].strip().split()
+ if len(values) == 1:
+ attr['value'] = values[0]
+ if zapi.isinstance(field, GlobalInterface):
+ attr['url'] = self.ifaceURL(values[0], field, rootURL)
+ elif zapi.isinstance(field, GlobalObject):
+ attr['url'] = self.objectURL(values[0], field, rootURL)
+ break
+
+ for value in values:
+ if zapi.isinstance(field, GlobalInterface):
+ url = self.ifaceURL(value, field, rootURL)
+ elif zapi.isinstance(field, GlobalObject):
+ url = self.objectURL(value, field, rootURL)
+ else:
+ break
+ attr['values'].append({'value': value, 'url': url})
+
- elif isinstance(field, GlobalObject):
- bound = field.bind(resolver)
- converter = IFromUnicode(bound)
- # XXX: Fix later
- try:
- value = converter.fromUnicode(attr['value'])
- except:
- pass
- try:
- attr['url'] = getPythonPath(value)
- except AttributeError: continue
-
# Make sure that the attributes are in the same order they are defined
# in the schema.
- fieldNames = getFieldNamesInOrder(schema)
+ fieldNames = getFieldNamesInOrder(context.schema)
fieldNames = [name.endswith('_') and name[:-1] or name
for name in fieldNames]
attrs.sort(lambda x, y: _compareAttrs(x, y, fieldNames))
- return attrs
+ if not IRootDirective.providedBy(context):
+ return attrs
+ xmlns = []
+ for uri, prefix in context.prefixes.items():
+ name = prefix and ':'+prefix or ''
+ xmlns.append({'name': 'xmlns'+name,
+ 'value': uri,
+ 'url': None,
+ 'values': []})
+
+ xmlns.sort(lambda x, y: cmp(x['name'], y['name']))
+ return xmlns + attrs
+
def hasSubDirectives(self):
- return len(self.context) != 0
+ return len(removeSecurityProxy(self.context).subs) != 0
def getElements(self):
context = removeSecurityProxy(self.context)
- return context.values()
+ return context.subs
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcmlfile_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcmlfile_index.pt 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcmlfile_index.pt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -37,11 +37,16 @@
font-style: italic;
}
+div.highlight {
+ background: #fffbbe;
+ border: 1pt solid #0000c0;
+}
+
</style>
</head>
<body>
- <div tal:replace="structure context/@@display" />
+ <div tal:replace="structure context/rootElement/@@display" />
</body>
</html>
\ No newline at end of file
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -29,53 +29,7 @@
from interfaces import IClassDocumentation
class Class(object):
- """This class represents a class declared in the module.
-
- Setting up a class for documentation is easy. You only need to provide an
- object providing 'IModule' as a parent, the name and the klass itself::
-
- >>> import zope.app.apidoc
- >>> module = Module(None, 'apidoc', zope.app.apidoc)
- >>> klass = Class(module, 'APIDocumentation',
- ... zope.app.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.APIDocumentation'
-
- >>> klass.getDocString()[:41]
- 'Represent the complete API Documentation.'
-
- 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 bases 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
- classRegistry in this module. In our example::
-
- >>> class APIDocSubclass(zope.app.apidoc.APIDocumentation):
- ... pass
- >>> klass2 = Class(module, 'APIDocSubclass', APIDocSubclass)
- >>> klass.getKnownSubclasses()
- [<class 'zope.app.apidoc.classmodule.APIDocSubclass'>]
-
- For a more detailed analysis, you can also retrieve the public attributes
- and methods of this class::
-
- >>> klass.getAttributes()
- []
-
- >>> klass.getMethods()[0]
- ('get', <unbound method APIDocumentation.get>, None)
-
- """
+ """This class represents a class declared in the module."""
implements(ILocation, IClassDocumentation)
def __init__(self, module, name, klass):
@@ -118,31 +72,7 @@
return self.__interfaces
def getAttributes(self):
- """See IClassDocumentation.
-
- Here a detailed example::
-
- >>> from zope.app.apidoc.tests import pprint
-
- >>> class ModuleStub(object):
- ... def getPath(self): return ''
-
- >>> class IBlah(Interface):
- ... foo = Attribute('Foo')
-
- >>> class Blah(object):
- ... implements(IBlah)
- ... foo = 'f'
- ... bar = 'b'
- ... _blah = 'l'
-
- >>> klass = Class(ModuleStub(), 'Blah', Blah)
-
- >>> attrs = klass.getAttributes()
- >>> pprint(attrs)
- [('bar', 'b', None),
- ('foo', 'f', <InterfaceClass zope.app.apidoc.classmodule.IBlah>)]
- """
+ """See IClassDocumentation."""
return [
(name, getattr(self.__klass, name),
getInterfaceForAttribute(name, self.__all_ifaces, asPath=False))
@@ -151,33 +81,7 @@
if not inspect.ismethod(getattr(self.__klass, name))]
def getMethods(self):
- """See IClassDocumentation.
-
- Here a detailed example::
-
- >>> from zope.app.apidoc.tests import pprint
-
- >>> class ModuleStub(object):
- ... def getPath(self): return ''
-
- >>> class IBlah(Interface):
- ... def foo(): pass
-
- >>> class Blah(object):
- ... implements(IBlah)
- ... def foo(self): pass
- ... def bar(self): pass
- ... def _blah(self): pass
-
- >>> klass = Class(ModuleStub(), 'Blah', Blah)
-
- >>> methods = klass.getMethods()
- >>> pprint(methods)
- [('bar', <unbound method Blah.bar>, None),
- ('foo',
- <unbound method Blah.foo>,
- <InterfaceClass zope.app.apidoc.classmodule.IBlah>)]
- """
+ """See IClassDocumentation."""
return [
(name, getattr(self.__klass, name),
getInterfaceForAttribute(name, self.__all_ifaces, asPath=False))
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -0,0 +1,95 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Code Documentation Module
+
+This module is able to take a dotted name of any class and display
+documentation for it.
+
+$Id: __init__.py 29269 2005-02-23 22:22:48Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope.interface import Interface, implements
+from zope.app import zapi
+from zope.app.i18n import ZopeMessageIDFactory as _
+from zope.app.location.interfaces import ILocation
+
+from zope.app.apidoc.interfaces import IDocumentationModule
+from zope.app.apidoc.classregistry import safe_import
+from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule
+from zope.app.apidoc.codemodule.module import Module
+
+
+class CodeModule(Module):
+ """Represent the code browser documentation root"""
+ implements(IDocumentationModule)
+
+ # See zope.app.apidoc.interfaces.IDocumentationModule
+ title = _('Code Browser')
+
+ # See zope.app.apidoc.interfaces.IDocumentationModule
+ description = _("""
+ This module allows you to get an overview of the modules and classes
+ defined in the Zope 3 framework and its supporting packages. There are
+ two methods to navigate through the modules to find the classes you are
+ interested in.
+
+ The first method is to type in some part of the Python path of the class
+ and the module will look in the class registry for matches. The menu will
+ then return with a list of these matches.
+
+ The second method is to click on the "Browse Zope Source" link. In the
+ main window, you will see a directory listing with the root Zope 3
+ modules. You can click on the module names to discover their content. If a
+ class is found, it is represented as a bold entry in the list.
+
+ The documentation contents of a class provides you with an incredible
+ amount of information. Not only does it tell you about its base classes,
+ implemented interfaces, attributes and methods, but it also lists the
+ interface that requires a method or attribute to be implemented and the
+ permissions required to access it.
+ """)
+ def __init__(self):
+ """Initialize object."""
+ super(CodeModule, self).__init__(None, '', None, False)
+ self.__isSetup = False
+
+ def setup(self):
+ """Setup module and class tree."""
+ if self.__isSetup:
+ return
+ for name, mod in zapi.getUtilitiesFor(IAPIDocRootModule):
+ self._children[name] = Module(self, name, safe_import(mod))
+ self.__isSetup = True
+
+ def getDocString(self):
+ """See Module class."""
+ return _('Zope 3 root.')
+
+ def getFileName(self):
+ """See Module class."""
+ return ''
+
+ def getPath(self):
+ """See Module class."""
+ return ''
+
+ def get(self, key, default=None):
+ """See zope.app.container.interfaces.IReadContainer."""
+ self.setup()
+ return super(CodeModule, self).get(key, default)
+
+ def items(self):
+ """See zope.app.container.interfaces.IReadContainer."""
+ self.setup()
+ return super(CodeModule, self).items()
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/configure.zcml 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/configure.zcml 2005-02-26 14:16:04 UTC (rev 29309)
@@ -15,15 +15,19 @@
<allow interface=".interfaces.IFunctionDocumentation" />
</class>
- <class class=".zcml.Configuration">
- <allow interface=".interfaces.IConfiguration" />
+ <class class=".zcml.Directive">
+ <allow interface=".interfaces.IDirective" />
</class>
+ <class class=".zcml.ZCMLFile">
+ <allow interface=".interfaces.IZCMLFile" />
+ </class>
+
<class class=".text.TextFile">
<allow attributes="getContent path" />
</class>
- <class class=".CodeModule">
+ <class class=".codemodule.CodeModule">
<allow interface="..interfaces.IDocumentationModule" />
<allow interface=".interfaces.IModuleDocumentation" />
<allow attributes="rootModules" />
@@ -41,7 +45,7 @@
<utility
provides="..interfaces.IDocumentationModule"
- factory=".CodeModule"
+ factory=".codemodule.CodeModule"
name="Code" />
<include package=".browser" />
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -0,0 +1,34 @@
+=================================
+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.app import zapi
+ >>> from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule
+ >>> list(zapi.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(zapi.getUtilitiesFor(IAPIDocRootModule))
+ [(u'zope', 'zope')]
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/directive.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -1,91 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003, 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Functional Tests for Class Documentation Module.
-
-$Id$
-"""
-import unittest
-from zope.app.testing.functional import BrowserTestCase
-
-class ClassModuleTests(BrowserTestCase):
- """Just a couple of tests ensuring that the templates render."""
-
- def testMenu(self):
- response = self.publish('/++apidoc++/Code/menu.html',
- basic='mgr:mgrpw')
- self.assertEqual(response.getStatus(), 200)
- body = response.getBody()
- self.assert_(body.find('Zope Source') > 0)
- self.checkForBrokenLinks(body, '/++apidoc++/Code/menu.html',
- basic='mgr:mgrpw')
-
- def testMenuClassFinder(self):
- response = self.publish('/++apidoc++/Code/menu.html',
- basic='mgr:mgrpw',
- form={'path': 'Code', 'SUBMIT': 'Find'})
- self.assertEqual(response.getStatus(), 200)
- body = response.getBody()
- self.assert_(body.find('zope.app.apidoc.codemodule.CodeModule') > 0)
- self.checkForBrokenLinks(body, '/++apidoc++/Code/menu.html',
- basic='mgr:mgrpw')
-
- def testModuleDetailsView(self):
- response = self.publish('/++apidoc++/Code/zope/app/apidoc/apidoc',
- basic='mgr:mgrpw')
- self.assertEqual(response.getStatus(), 200)
- body = response.getBody()
- self.assert_(body.find('Zope 3 API Documentation') > 0)
- self.checkForBrokenLinks(
- body, '/++apidoc++/Code/zope/app/apidoc/apidoc', basic='mgr:mgrpw')
-
- def testClassDetailsView(self):
- response = self.publish(
- '/++apidoc++/Code/zope/app/apidoc/apidoc/APIDocumentation',
- basic='mgr:mgrpw')
- self.assertEqual(response.getStatus(), 200)
- body = response.getBody()
- self.assert_(body.find('Represent the complete API Documentation.') > 0)
- self.checkForBrokenLinks(
- body, '/++apidoc++/Code/zope/app/apidoc/apidoc/APIDocumentation',
- basic='mgr:mgrpw')
-
- def testFunctionDetailsView(self):
- response = self.publish(
- '/++apidoc++/Code/zope/app/apidoc/apidoc/handleNamespace',
- basic='mgr:mgrpw')
- self.assertEqual(response.getStatus(), 200)
- body = response.getBody()
- self.assert_(body.find('handleNamespace(ob, name)') > 0)
- self.checkForBrokenLinks(
- body, '/++apidoc++/Code/zope/app/apidoc/apidoc/handleNamesapce',
- basic='mgr:mgrpw')
-
- def testZCMLFileDetailsView(self):
- response = self.publish(
- '/++apidoc++/Code/zope/app/apidoc/configure.zcml/index.html',
- basic='mgr:mgrpw')
- self.assertEqual(response.getStatus(), 200)
- body = response.getBody()
- self.checkForBrokenLinks(
- body, '/++apidoc++/Code/zope/app/apidoc/configure.zcml/index.html',
- basic='mgr:mgrpw')
-
-
-def test_suite():
- return unittest.TestSuite((
- unittest.makeSuite(ClassModuleTests),
- ))
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/function.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/function.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/function.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -23,35 +23,7 @@
from interfaces import IFunctionDocumentation
class Function(object):
- """This class represents a function declared in the module.
-
- Setting up a function for documentation is easy. You only need to provide
- an object providing 'IModule' as a parent, the name and the function
- object itself::
-
- >>> import zope.app.apidoc
- >>> module = Module(None, 'apidoc', zope.app.apidoc)
- >>> func = Function(module, 'handleNamespace',
- ... zope.app.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.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()
- []
- """
+ """This class represents a function declared in the module."""
implements(ILocation, IFunctionDocumentation)
def __init__(self, module, name, func):
@@ -72,27 +44,5 @@
return getFunctionSignature(self.__func)
def getAttributes(self):
- """See IClassDocumentation.
-
- Here a detailed example::
-
- >>> class ModuleStub(object):
- ... def getPath(self): return ''
-
- >>> def foo(bar=1):
- ... pass
-
- >>> func = Function(ModuleStub(), 'foo', foo)
-
- >>> attrs = func.getAttributes()
- >>> attrs.sort()
- >>> print attrs
- []
-
- >>> foo.bar = 'blah'
- >>> attrs = func.getAttributes()
- >>> attrs.sort()
- >>> print attrs
- [('bar', 'blah')]
- """
+ """See IClassDocumentation."""
return self.__func.__dict__.items()
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/interfaces.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/interfaces.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -16,14 +16,22 @@
$Id$
"""
__docformat__ = "reStructuredText"
-from zope.interface import Interface
-from zope.schema import Field, BytesLine, Text
+import zope.interface
+import zope.schema
from zope.app.container.interfaces import IContainer
from zope.app.container.interfaces import IReadContainer
from zope.app.i18n import ZopeMessageIDFactory as _
+class IAPIDocRootModule(zope.interface.Interface):
+ """Marker interface for utilities that represent class browser root
+ modules.
+
+ The utilities will be simple strings, representing the modules Python
+ dotted name.
+ """
+
class IModuleDocumentation(IReadContainer):
"""Representation of a Python module for documentation.
@@ -39,7 +47,7 @@
"""Return the Python path of the module."""
-class IClassDocumentation(Interface):
+class IClassDocumentation(zope.interface.Interface):
"""Representation of a class or type for documentation."""
def getDocString():
@@ -88,7 +96,7 @@
"""
-class IFunctionDocumentation(Interface):
+class IFunctionDocumentation(zope.interface.Interface):
"""Representation of a function for documentation."""
def getDocString():
@@ -107,109 +115,67 @@
second is the attribute object itself.
"""
+class IDirective(zope.interface.Interface):
+ """Representation of a directive in IZCMLFile."""
-class IElement(IContainer):
- """Represents an XML Element in the ZCML Configuration File
+ name = zope.schema.Tuple(
+ title=u'Name',
+ description=u'Name of the directive in the form (Namespace. Name)',
+ required = True)
+
+ schema = zope.schema.Field(
+ title=u'Schema',
+ description=u'Schema describing the directive attributes',
+ required = True)
- The names of the container items is simply their index (as string).
- """
-
- domElement = Field(
- title=_("Mini-DOM Element"),
- description=_("Mini-DOM element representing this configuration "
- "element."),
- required=True)
-
- def toXML():
- """Returns a string completely representing this DOM Element.
+ attrs = zope.schema.Field(
+ title=u'Attributes',
+ description=u'SAX parser representation of the directive\'s attributes',
+ required = True)
- The returned XML should be well formatted, including all correct
- indentations and lines not being long than 80 characters, if possible.
- """
+ context = zope.schema.Field(
+ title=u'Configuration Context',
+ description=u'Configuration context while the directive was parsed.',
+ required = True)
- def getElementType():
- """Return the type of the DOM element.
-
- Possible values are:
+ prefixes = zope.schema.Dict(
+ title=u'Prefixes',
+ description=u'Mapping from namespace URIs to prefixes.',
+ required = True)
- - ELEMENT_NODE (1): An XML tag. If an element is of this type it is a
- standard ZCML directive or sub-directive.
+ info = zope.schema.Field(
+ title=u'Info',
+ description=u'ParserInfo objects containing line and column info.',
+ required = True)
- - COMMENT_NODE (8): An XML comment. Comments are used to explain
- features of the ZCML directives and are thus supported by the editor.
+ __parent__ = zope.schema.Field(
+ title=u'Parent',
+ description=u'Parent Directive',
+ required = True)
- - TEXT_NODE (3): A simple text node. These are commonly ignored by te
- configuration editor, since they are arbitrary and ZCML does not make
- use of text nodes ever. Thus, an element having this type would be
- considered a bug.
- """
+ subs = zope.schema.List(
+ title=u'Sub-Directives',
+ description=u'List of sub-directives',
+ required = True)
- def isFirstChild():
- """Determine whether this element is the first child in its parent."""
- def isLastChild():
- """Determine whether this element is the last child in its parent."""
+class IRootDirective(IDirective):
+ """Marker interface"""
- def validate():
- """Validate the element's data.
- If the validation is successful, `None` should be returned; otherwise
- return a `ValidationError` or a list of validation errors.
+class IZCMLFile(zope.interface.Interface):
+ """ZCML File Object
- While a DOM element always represents a valid XML expression, this might
- not be true for ZCML, since it is just a subset of XML.
- """
-
-
-class IComment(IElement):
- """A special element representing a comment in the configuration."""
-
- value = Text(
- title=_("Comment"),
- description=_("This is the actual comment text. It is automatically "
- "extracted from the DOM element."),
- required=True)
-
-
-class IDirective(IElement):
- """
-
- The element will also expose the attributes of the XML element as attributes
- of this class.
- """
- config = Field()
-
- schema = Field()
-
- def getFullTagName():
- """ """
-
- def getAttribute(name):
- """ """
-
- def getAttributeMap():
- """ """
-
- def removeAttribute(name):
- """ """
-
- def getAvailableSubdirectives():
- """ """
-
-
-class IConfiguration(IDirective):
- """ZCML Configuration Object
-
This is the main object that will manage the configuration of one particular
ZCML configuration file.
"""
- filename = BytesLine(
+ filename = zope.schema.BytesLine(
title=_('Configuration Filename'),
description=_('Path to the configuration file'),
required=True)
- package = BytesLine(
+ package = zope.schema.BytesLine(
title=_('Configuration Package'),
description=_(
'''Specifies the package from which the configuration file will be
@@ -217,24 +183,8 @@
cannot be fully validated and improper ZCML files might be written.'''),
required=False)
- def parse():
- """Parse the ZCML located in the specified file.
-
- If the file does not exist, a configuration will be initialized.
- """
-
- def getSchema(namespaceURI, tagName):
- """Given the namespace and the tag name, lookup the directive's
- schema.
-
- If no schema is found, `None` is returned.
- """
-
- def getNamespacePrefix(namespaceURI):
- """ """
-
- def getNamespaceURI(prefix):
- """ """
-
- def getResolver():
- """ """
+ rootElement = zope.schema.Field(
+ title=_("XML Root Element"),
+ description=_("XML element representing the configuration root."),
+ required=True)
+
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -18,7 +18,7 @@
__docformat__ = 'restructuredtext'
from zope.interface import implements
from zope.app.component.metaconfigure import utility
-from zope.app.apidoc.codemodule import IAPIDocRootModule
+from zope.app.apidoc.codemodule.interfaces import IAPIDocRootModule
class RootModule(str):
implements(IAPIDocRootModule)
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/module.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/module.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/module.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -23,7 +23,7 @@
from zope.interface import implements
from zope.interface.interface import InterfaceClass
from zope.app.location.interfaces import ILocation
-from zope.app.location import locate
+from zope.app.location import LocationProxy
from zope.app.apidoc.classregistry import safe_import
from zope.app.apidoc.utilities import ReadContainerBase
@@ -32,70 +32,15 @@
from zope.app.apidoc.codemodule.class_ import Class
from zope.app.apidoc.codemodule.function import Function
from zope.app.apidoc.codemodule.text import TextFile
-from zope.app.apidoc.codemodule.zcml import Configuration
+from zope.app.apidoc.codemodule.zcml import ZCMLFile
# Ignore these files, since they are not necessary or cannot be imported
# correctly.
-# TODO: I want to be able to specify paths with wildcards later, so that we do
-# not ignore all files/dirs with a certain name.
IGNORE_FILES = ('tests', 'tests.py', 'ftests', 'ftests.py', 'CVS', 'gadfly',
'setup.py', 'introspection.py', 'Mount.py')
class Module(ReadContainerBase):
- """This class represents a Python module.
-
- The module 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 = Module(None, 'apidoc', zope.app.apidoc)
-
- We can now get some of the common module attributes via accessor methods::
-
- >>> module.getDocString()[:24]
- 'Zope 3 API Documentation'
-
- >>> fname = module.getFileName()
- >>> fname = fname.replace('\\\\', '/') # normalize pathname separator
- >>> 'zope/app/apidoc/__init__.py' in fname
- True
-
- >>> module.getPath()
- 'zope.app.apidoc'
-
- 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()
- >>> 'APIDocumentation' in keys
- True
- >>> 'apidocNamespace' in keys
- True
- >>> 'handleNamespace' in keys
- True
-
- >>> print module['browser'].getPath()
- zope.app.apidoc.browser
-
- Now, the ``get(key, default=None)`` 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::
-
- >>> print module['tests'].getPath()
- zope.app.apidoc.tests
-
- >>> names = module['tests'].keys()
- >>> names.sort()
- >>> names
- ['Root', 'pprint', 'rootLocation', 'setUp', 'test_suite']
- """
+ """This class represents a Python module."""
implements(ILocation, IModuleDocumentation)
def __init__(self, parent, name, module, setup=True):
@@ -135,8 +80,8 @@
self._children[name] = Module(self, name, module)
elif os.path.isfile(path) and file.endswith('.zcml'):
- self._children[file] = Configuration(path, self._module,
- self, file)
+ self._children[file] = ZCMLFile(path, self._module,
+ self, file)
elif os.path.isfile(path) and file.endswith('.txt'):
self._children[file] = TextFile(path, file, self)
@@ -157,8 +102,8 @@
if isinstance(attr, (types.ClassType, types.TypeType)):
self._children[name] = Class(self, name, attr)
- if isinstance(attr, (InterfaceClass)):
- self._children[name] = locate(attr, self, name)
+ if isinstance(attr, InterfaceClass):
+ self._children[name] = LocationProxy(attr, self, name)
elif type(attr) is types.FunctionType:
self._children[name] = Function(self, name, attr)
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -15,132 +15,44 @@
$Id$
"""
+import os
import unittest
-from zope.component.interfaces import IFactory
from zope.configuration import xmlconfig
-from zope.interface import Interface, directlyProvides, implements
-from zope.publisher.browser import TestRequest
-from zope.testing.doctestunit import DocTestSuite
+from zope.testing import doctest, doctestunit
-from zope.app import zapi
-from zope.app.location.traversing import LocationPhysicallyLocatable
-from zope.app.renderer.rest import ReStructuredTextSourceFactory
-from zope.app.renderer.rest import IReStructuredTextSource
-from zope.app.renderer.rest import ReStructuredTextToHTMLRenderer
-from zope.app.renderer.stx import StructuredTextSourceFactory
-from zope.app.renderer.stx import IStructuredTextSource
-from zope.app.renderer.stx import StructuredTextToHTMLRenderer
-from zope.app.testing import placelesssetup, ztapi
-from zope.app.traversing.browser import AbsoluteURL, SiteAbsoluteURL
-from zope.app.traversing.interfaces import ITraversable, ITraverser
-from zope.app.traversing.interfaces import IPhysicallyLocatable
-from zope.app.traversing.interfaces import IContainmentRoot
-from zope.app.traversing.adapters import DefaultTraversable
-from zope.app.traversing.adapters import RootPhysicallyLocatable
-from zope.app.traversing.adapters import Traverser
+import zope.app.appsetup.appsetup
+from zope.app.testing import placelesssetup
-from zope.app.apidoc.codemodule import CodeModule, IAPIDocRootModule
-from zope.app.apidoc.codemodule.browser.class_ import ClassDetails
-from zope.app.apidoc.codemodule.browser.function import FunctionDetails
-from zope.app.apidoc.codemodule.browser.module import ModuleDetails
-from zope.app.apidoc.interfaces import IDocumentationModule
-
def setUp(test):
placelesssetup.setUp()
- class RootModule(str):
- implements(IAPIDocRootModule)
- ztapi.provideUtility(IAPIDocRootModule, RootModule('zope'), "zope")
+ meta = os.path.join(os.path.dirname(zope.app.__file__), 'meta.zcml')
+ context = xmlconfig.file(meta, zope.app)
+ meta = os.path.join(os.path.dirname(zope.app.apidoc.__file__), 'meta.zcml')
+ context = xmlconfig.file(meta, zope.app.apidoc, context)
- module = CodeModule()
- module.__name__ = ''
- directlyProvides(module, IContainmentRoot)
- ztapi.provideUtility(IDocumentationModule, module, "Code")
+ # Fix up path for tests.
+ global old_context
+ old_context = zope.app.appsetup.appsetup.__config_context
+ zope.app.appsetup.appsetup.__config_context = context
- ztapi.provideAdapter(
- None, ITraverser, Traverser)
- ztapi.provideAdapter(
- None, ITraversable, DefaultTraversable)
- ztapi.provideAdapter(
- None, IPhysicallyLocatable, LocationPhysicallyLocatable)
- ztapi.provideAdapter(
- IContainmentRoot, IPhysicallyLocatable, RootPhysicallyLocatable)
+def tearDown(test):
+ placelesssetup.tearDown()
+ global old_context
+ zope.app.appsetup.appsetup.__config_context = old_context
- ztapi.browserView(Interface, "absolute_url", AbsoluteURL)
- ztapi.browserView(IContainmentRoot, "absolute_url", SiteAbsoluteURL)
- # Register Renderer Components
- ztapi.provideUtility(IFactory, StructuredTextSourceFactory,
- 'zope.source.stx')
- ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory,
- 'zope.source.rest')
- ztapi.browserView(IStructuredTextSource, '',
- StructuredTextToHTMLRenderer)
- ztapi.browserView(IReStructuredTextSource, '',
- ReStructuredTextToHTMLRenderer)
-
-
-def foo(cls, bar=1, *args):
- """This is the foo function."""
-foo.deprecated = True
-
-
-def getFunctionDetailsView():
- cm = zapi.getUtility(IDocumentationModule, 'Code')
- view = FunctionDetails()
- view.context = zapi.traverse(cm, 'zope/app/apidoc/codemodule/tests/foo')
- view.request = TestRequest()
- return view
-
-
-def getClassDetailsView():
- cm = zapi.getUtility(IDocumentationModule, 'Code')
- view = CodeDetails()
- view.context = zapi.traverse(cm, 'zope/app/apidoc/codemodule/CodeModule')
- view.request = TestRequest()
- return view
-
-
-def getModuleDetailsView():
- cm = zapi.getUtility(IDocumentationModule, 'Code')
- view = ModuleDetails()
- view.context = zapi.traverse(cm, 'zope/app/apidoc/codemodule')
- view.request = TestRequest()
- return view
-
-
-class DirectivesTest(placelesssetup.PlacelessSetup, unittest.TestCase):
-
- template = """
- <configure
- xmlns='http://namespaces.zope.org/apidoc'>
- %s
- </configure>"""
-
- def setUp(self):
- super(DirectivesTest, self).setUp()
- import zope.app.apidoc.codemodule
- self.context = xmlconfig.file('meta.zcml', zope.app.apidoc.codemodule)
-
- def testRootModule(self):
- self.assertEqual(len(list(zapi.getUtilitiesFor(IAPIDocRootModule))), 0)
- xmlconfig.string(
- self.template %'<rootModule module="zope" />', self.context)
-
- self.assertEqual(zapi.getUtilitiesFor(IAPIDocRootModule).next()[0],
- 'zope')
-
-
def test_suite():
return unittest.TestSuite((
- # XXX: Redo browser tests
- #DocTestSuite('zope.app.apidoc.codemodule.browser',
- # setUp=setUp, tearDown=placelesssetup.tearDown),
- DocTestSuite('zope.app.apidoc.codemodule',
- setUp=setUp, tearDown=placelesssetup.tearDown),
- unittest.makeSuite(DirectivesTest),
+ doctest.DocFileSuite('README.txt',
+ setUp=setUp, tearDown=tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ doctest.DocFileSuite('directive.txt',
+ setUp=placelesssetup.setUp,
+ tearDown=placelesssetup.tearDown),
))
if __name__ == '__main__':
- unittest.main()
+ unittest.main(default="test_suite")
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py 2005-02-26 14:16:04 UTC (rev 29309)
@@ -11,236 +11,125 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Configuration File Representation
+"""ZCML File Representation
$Id$
"""
__docformat__ = "reStructuredText"
+from xml.sax import make_parser
+from xml.sax.xmlreader import InputSource
+from xml.sax.handler import feature_namespaces
-from persistent import Persistent
-from xml.dom import minidom
-from xml.parsers.expat import ExpatError
-
from zope.cachedescriptors.property import Lazy
-from zope.configuration import xmlconfig
-from zope.configuration.config import ConfigurationContext
-from zope.configuration.zopeconfigure import IZopeConfigure
-from zope.interface import implements
-from zope.schema import getFields
-from zope.schema.interfaces import IFromUnicode
+from zope.configuration import xmlconfig, config
+from zope.interface import implements, directlyProvides
import zope.app.appsetup.appsetup
from zope.app import zapi
-from zope.app.location import locate
-from zope.app.container.contained import Contained
-from interfaces import IElement, IComment, IDirective, IConfiguration
+from interfaces import IDirective, IRootDirective, IZCMLFile
-context = None
-def getContext():
- global context
- if context is None:
- context = xmlconfig.file(zope.app.appsetup.appsetup.getConfigSource(),
- execute=False)
- return context
+class MyConfigHandler(xmlconfig.ConfigurationHandler, object):
+ """Special configuration handler to generate an XML tree."""
-class Element(Contained):
- """A wrapper for a Mini-DOM Element to provide a Python/Zope-native
- representation.
- """
- implements(IElement)
-
- def __init__(self, dom):
- """Initialize the Element object."""
- self.domElement = dom
+ def __init__(self, context):
+ super(MyConfigHandler, self).__init__(context)
+ self.rootElement = self.currentElement = None
+ self.prefixes = {}
- def _getSubElement(self, dom, index):
- """Helper method to create new element."""
- element = Element(dom)
- locate(element, self, unicode(index))
- return element
+ def startPrefixMapping(self, prefix, uri):
+ self.prefixes[uri] = prefix
- def get(self, key, default=None):
- """See zope.app.container.interfaces.IReadContainer"""
- try:
- return self[key]
- except KeyError:
- return default
+ def startElementNS(self, name, qname, attrs):
+ # The last stack item is parent of the stack item that we are about to
+ # create
+ stackitem = self.context.stack[-1]
+ super(MyConfigHandler, self).startElementNS(name, qname, attrs)
- def keys(self):
- """See zope.app.container.interfaces.IReadContainer"""
- dom = self.domElement
- return [unicode(index) for index in range(len(dom.childNodes))
- if dom.childNodes[index].nodeType != dom.TEXT_NODE]
+ # Get the parser info from the correct context
+ info = self.context.stack[-1].context.info
- def values(self):
- """See zope.app.container.interfaces.IReadContainer"""
- return [self[key] for key in self.keys()]
+ # complex stack items behave a bit different than the other ones, so
+ # we need to handle it separately
+ if isinstance(stackitem, config.ComplexStackItem):
+ schema = stackitem.meta.get(name[1])[0]
+ else:
+ schema = stackitem.context.factory(stackitem.context, name).schema
- def items(self):
- """See zope.app.container.interfaces.IReadContainer"""
- return [(key, self[key]) for key in self.keys()]
+ # Now we have all the necessary information to create the directive
+ element = Directive(name, schema, attrs, stackitem.context, info,
+ self.prefixes)
+ # Now we place the directive into the XML directive tree.
+ if self.rootElement is None:
+ self.rootElement = element
+ else:
+ self.currentElement.subs.append(element)
+
+ element.__parent__ = self.currentElement
+ self.currentElement = element
- def __iter__(self):
- """See zope.app.container.interfaces.IReadContainer"""
- return iter(self.keys())
- def __len__(self):
- """See zope.app.container.interfaces.IReadContainer"""
- return len(self.keys())
+ def endElementNS(self, name, qname):
+ super(MyConfigHandler, self).endElementNS(name, qname)
+ self.currentElement = self.currentElement.__parent__
- def __contains__(self, key):
- """See zope.app.container.interfaces.IReadContainer"""
- try:
- index = int(key)
- except ValueError:
- raise KeyError, '%s cannot be converted to an index.' %key
- return index >= 0 and index < len(self.domElement.childNodes) and \
- self.domElement.childNodes[index] != self.domElement.TEXT_NODE
- def __getitem__(self, key):
- """See zope.app.container.interfaces.IReadContainer"""
- try:
- index = int(key)
- except ValueError:
- raise KeyError, '%s cannot be converted to an index.' %key
- # Create the sub-element from the index and give it a location before
- # returning it.
- element = self._getSubElement(self.domElement.childNodes[index], index)
- locate(element, self, key)
- return element
-
- def getElementType(self):
- """See configeditor.interfaces.IElement"""
- return self.domElement.nodeType
-
-
-class Comment(Element):
- """ """
- implements(IComment)
-
- def getValue(self):
- return self.domElement.nodeValue
- value = property(getValue)
-
-
-class Directive(Element):
- """ """
+class Directive(object):
+ """Representation of a ZCML directive."""
implements(IDirective)
-
- def __init__(self, dom, tagName=None, namespaceURI=None,
- attributes=None, config=None):
- self.domElement = dom
- self.config = config
- # Delay lookup till later
- self.schema = None
-
- def _getSubElement(self, dom, index):
- """Helper method to create new element."""
- if dom.nodeType == dom.ELEMENT_NODE:
- element = Directive(dom, config=self.config)
- element.schema = self.config.getSchema(
- dom.namespaceURI, dom.localName, self.schema)
- elif dom.nodeType == dom.COMMENT_NODE:
- element = Comment(dom)
- else:
- element = Element(dom)
- locate(element, self, unicode(index))
- return element
-
- def getFullTagName(self):
- """See configeditor.interfaces.IDirective"""
- return self.domElement.tagName
- def getAttribute(self, name):
- """See configeditor.interfaces.IDirective"""
- if name not in self.schema and name+'_' not in self.schema:
- raise AttributeError, "'%s' not in schema" %name
- return self.domElement.getAttribute(name)
+ def __init__(self, name, schema, attrs, context, info, prefixes):
+ self.name = name
+ self.schema = schema
+ self.attrs = attrs
+ self.context = context
+ self.info = info
+ self.__parent__ = None
+ self.subs = []
+ self.prefixes = prefixes
- def getAttributeMap(self):
- """See configeditor.interfaces.IDirective"""
- return dict(self.domElement.attributes.items())
-
- def getAvailableSubdirectives(self):
- """ """
- registry = self.config._registry
- return [
- ((ns, name), schema)
- for (ns, name), schema, usedIn, handler, info, parent in registry
- if parent and self.schema.isOrExtends(parent.schema)]
-
+ def __repr__(self):
+ return '<Directive %s>' %str(self.name)
-class Configuration(Directive):
- """Cofiguration Object"""
- implements(IConfiguration)
+class ZCMLFile(object):
+ """Representation of an entire ZCML file."""
+ implements(IZCMLFile)
+
def __init__(self, filename, package, parent=None, name=None):
# Retrieve the directive registry
self.filename = filename
self.package = package
self.__parent__ = parent
self.__name__ = name
- self.config = self
- self.schema = None
-
- def _registry(self):
- return getContext()._docRegistry
- _registry = property(_registry)
-
- def domElement(self):
- domElement = self.parse()
- self.schema = self.getSchema(domElement.namespaceURI,
- domElement.localName)
- return domElement
- domElement = Lazy(domElement)
+ def rootElement(self):
+ # Get the context that was originally generated during startup.
+ context = zope.app.appsetup.appsetup.getConfigContext()
+ context.package = self.package
- def parse(self):
- """See configeditor.interfaces.IConfiguration"""
- return minidom.parse(self.filename).getElementsByTagName('configure')[0]
+ # Since we want to use a custom configuration handler, we need to
+ # instantiate the parser object ourselves
+ parser = make_parser()
+ handler = MyConfigHandler(context)
+ parser.setContentHandler(handler)
+ parser.setFeature(feature_namespaces, True)
- def getSchema(self, namespaceURI, tagName, parentSchema=None):
- """See configeditor.interfaces.IConfiguration"""
- if parentSchema is IZopeConfigure:
- parentSchema = None
- for (ns, name), schema, usedIn, handler, info, pDir in self._registry:
- if ((ns == namespaceURI or ns == '') and name == tagName and
- ((pDir is None and parentSchema is None) or
- (pDir is not None and parentSchema is pDir.schema))):
- return schema
- return None
+ # Now open the file
+ file = open(self.filename)
+ src = InputSource(getattr(file, 'name', '<string>'))
+ src.setByteStream(file)
- def getNamespacePrefix(self, namespaceURI):
- """ """
- for name, value in self.getAttributeMap().items():
- if name.startswith('xmlns') and value == namespaceURI:
- if name == 'xmlns':
- return ''
- else:
- return name[6:]
- return None
+ # and parse it
+ parser.parse(src)
- def getNamespaceURI(self, prefix):
- """ """
- for name, value in self.getAttributeMap().items():
- if name == 'xmlns' and prefix == '':
- return value
- if name.startswith('xmlns') and name.endswith(prefix):
- return value
+ # Finally we retrieve the root element, have it provide a special root
+ # directive interface and give it a location, so that we can do local
+ # lookups.
+ root = handler.rootElement
+ directlyProvides(root, IRootDirective)
+ root.__parent__ = self
+ return root
- return None
-
- def getResolver(self):
- """ """
- if self.package is None:
- return None
- resolver = ConfigurationContext()
- resolver.package = self.package
- resolver.i18n_domain = self.domElement.getAttribute('i18n_domain')
- resolver.i18n_strings = {}
- resolver.actions = []
- from zope.configuration.xmlconfig import ParserInfo
- resolver.info = ParserInfo(self.filename, 0, 0)
- return resolver
+ rootElement = Lazy(rootElement)
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt 2005-02-26 14:13:49 UTC (rev 29308)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt 2005-02-26 14:16:04 UTC (rev 29309)
@@ -5,7 +5,7 @@
<metal:block define-macro="zcml">
<a href=""
tal:attributes="href
- string:../../Code/${zcml/url}/index.html"
+ string:../../Code/${zcml/url}/index.html?line=${zcml/line}#${zcml/line}"
tal:content="zcml/file">
zope/app/configure.zcml
</a>
More information about the Zope3-Checkins
mailing list