[Zope3-checkins] SVN: Zope3/trunk/ Milestone checkin of my apidoc
tool refactorings. More to come. See
Stephan Richter
srichter at cosmos.phy.tufts.edu
Wed Feb 23 17:22:49 EST 2005
Log message for revision 29269:
Milestone checkin of my apidoc tool refactorings. More to come. See
CHANGES.txt for a list of changes.
Changed:
U Zope3/trunk/doc/CHANGES.txt
U Zope3/trunk/package-includes/apidoc-meta.zcml
U Zope3/trunk/src/zope/app/apidoc/README.txt
D Zope3/trunk/src/zope/app/apidoc/TODO.txt
U Zope3/trunk/src/zope/app/apidoc/__init__.py
A Zope3/trunk/src/zope/app/apidoc/apidoc.py
U Zope3/trunk/src/zope/app/apidoc/browser/apidoc.css
U Zope3/trunk/src/zope/app/apidoc/browser/apidoc.py
U Zope3/trunk/src/zope/app/apidoc/browser/configure.zcml
D Zope3/trunk/src/zope/app/apidoc/classmodule/
A Zope3/trunk/src/zope/app/apidoc/classregistry.py
A Zope3/trunk/src/zope/app/apidoc/classregistry.txt
A Zope3/trunk/src/zope/app/apidoc/codemodule/
U Zope3/trunk/src/zope/app/apidoc/codemodule/__init__.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/__init__.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_index.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/configure.zcml
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayClosingElement.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayComment.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function_index.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/menu.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/menu.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module_index.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/text.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/textfile_index.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcmlfile_index.pt
D Zope3/trunk/src/zope/app/apidoc/codemodule/browser.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py
D Zope3/trunk/src/zope/app/apidoc/codemodule/class_index.pt
U Zope3/trunk/src/zope/app/apidoc/codemodule/configure.zcml
U Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/function.py
D Zope3/trunk/src/zope/app/apidoc/codemodule/function_index.pt
A Zope3/trunk/src/zope/app/apidoc/codemodule/interfaces.py
D Zope3/trunk/src/zope/app/apidoc/codemodule/menu.pt
U Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/module.py
D Zope3/trunk/src/zope/app/apidoc/codemodule/module_index.pt
U Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/text.py
A Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py
D Zope3/trunk/src/zope/app/apidoc/codemodule/zcmlfile_index.pt
A Zope3/trunk/src/zope/app/apidoc/component.py
A Zope3/trunk/src/zope/app/apidoc/component.txt
U Zope3/trunk/src/zope/app/apidoc/configure.zcml
A Zope3/trunk/src/zope/app/apidoc/ifacemodule/README.txt
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/__init__.py
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.py
A Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt
A Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/configure.zcml
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/ftests.py
A Zope3/trunk/src/zope/app/apidoc/ifacemodule/iface_macros.pt
A Zope3/trunk/src/zope/app/apidoc/ifacemodule/ifacemodule.py
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/index.pt
A Zope3/trunk/src/zope/app/apidoc/ifacemodule/macros.py
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py
A Zope3/trunk/src/zope/app/apidoc/ifacemodule/presentation_macros.pt
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/tests.py
A Zope3/trunk/src/zope/app/apidoc/interface.py
A Zope3/trunk/src/zope/app/apidoc/interface.txt
A Zope3/trunk/src/zope/app/apidoc/presentation.py
A Zope3/trunk/src/zope/app/apidoc/presentation.txt
U Zope3/trunk/src/zope/app/apidoc/tests.py
U Zope3/trunk/src/zope/app/apidoc/utilities.py
A Zope3/trunk/src/zope/app/apidoc/utilities.txt
A Zope3/trunk/src/zope/app/apidoc/utilitymodule/README.txt
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/__init__.py
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.py
A Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/configure.zcml
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/ftests.py
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/index.pt
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/tests.py
A Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py
U Zope3/trunk/src/zope/app/apidoc/version.txt
D Zope3/trunk/src/zope/app/apidoc/viewmodule/
A Zope3/trunk/src/zope/app/apidoc/zcmlmodule/README.txt
U Zope3/trunk/src/zope/app/apidoc/zcmlmodule/__init__.py
U Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py
A Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.txt
U Zope3/trunk/src/zope/app/apidoc/zcmlmodule/index.pt
U Zope3/trunk/src/zope/app/apidoc/zcmlmodule/tests.py
U Zope3/trunk/src/zope/app/introspector/introspector.pt
-=-
Modified: Zope3/trunk/doc/CHANGES.txt
===================================================================
--- Zope3/trunk/doc/CHANGES.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/doc/CHANGES.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -10,23 +10,6 @@
New features
- - When raising the Unauthorized exception, the security checker
- now passes the object in question in addition to the attribute
- name and missing permission. This should make debugging easier.
-
- - You can declare "features" provided by your package with the new
- <meta:provides feature="name" /> ZCML directive. The presence of these
- features can be tested with the new zcml:condition attribute.
-
- - ZCML supports conditional directives using the zcml:condition
- attribute. The value of the attribute is an expression of the
- form "verb arguments". Currently the only recognized verb is "have",
- and it takes a single name of a feature as an argument.
-
- If the expression is true, the element the attribute is attached to
- will be used, otherwise the element and its descendents will be
- ignored.
-
- API doctool has received some upgrades:
* A new `bookmodule` compiles all our README.txt and other text
@@ -36,6 +19,11 @@
`IContentType`) and then let's you see all interfaces providing this
type (for example `IFile`)
+ * Views are now shown in the Interface details screen.
+
+ * Adapters are split into three categories: specific, extended, and
+ generic.
+
- Zope 3 can now listen on specified network interfaces only. Example
of a server section in zope.conf:
@@ -265,6 +253,22 @@
Restructuring
+ - Several changes have been made to the API doc tool:
+
+ + General inspection utilities are now *publically* available in the
+ modules: utilities, interface, component, presentation,
+ classregistry
+
+ + The interface details view has been broken up into macros, so that
+ the HTML code snippets can be reused.
+
+ + Converted most tests to text files.
+
+ + Moved code from `__init__.py` files to modules.
+
+ + Removed `viewmodule`, since its functionality has been merged into
+ the interface details view.
+
- Changed the test-counting mechanism for doctests. Now a
doctest count a test for every example that is preceeded by
prose. (Although a doctest will never count less than 1 test.)
@@ -420,10 +424,6 @@
Instead of `rename(container, oldName, newName)`, one should use
`IContainerItemRenamer(container).renameItem(oldName, newName)`.
- - Deprecated _configureCopy in zope.app.copypastemove.ObjectCopier. To
- configure a recently copied object, suscribe to IObjectCopiedEvent for
- the type of object you're interested in configuring.
-
Bug Fixes
- When I converted layers and skins to interfaces, I got the layer part
@@ -489,8 +489,6 @@
- If the content-type was text/*, HTTPResponse.write re-set the
content-length header to the first chunk of data.
- - Object copy events weren't dispatched for object sublocations.
-
Much thanks to everyone who contributed to this release:
Jim Fulton, Fred Drake, Philipp von Weitershausen, Stephan Richter,
Modified: Zope3/trunk/package-includes/apidoc-meta.zcml
===================================================================
--- Zope3/trunk/package-includes/apidoc-meta.zcml 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/package-includes/apidoc-meta.zcml 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,5 +1,5 @@
<configure xmlns:meta="http://namespaces.zope.org/meta">
- <include package="zope.app.apidoc.classmodule" file="meta.zcml"/>
+ <include package="zope.app.apidoc.codemodule" file="meta.zcml"/>
<include package="zope.app.apidoc.bookmodule" file="meta.zcml"/>
<meta:provides feature="apidoc" />
</configure>
Modified: Zope3/trunk/src/zope/app/apidoc/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/README.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/README.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,11 +1,61 @@
+========================
Zope 3 API Documentation
========================
-This Zope 3 product provides a fully dynamic API documentation of Zope 3 and
-registered add-on components. The product is very extensible and can be easily
+This Zope 3 package provides fully dynamic API documentation of Zope 3 and
+registered add-on components. The package is very extensible and can be easily
extended by implementing new modules.
+Besides being an application, the API doctool also provides several public
+APIs to extract information from various objects used by Zope 3.
+ * utilities -- Miscellaneous classes and functions that aid all documentation
+ modules. They are broadly usable.
+
+ * interface -- This module contains functions to inspect interfaces and
+ schemas.
+
+ * component -- This modules provides utility functions to lookup components
+ given an interface.
+
+ * presentation -- Presentation components are generally more complex than
+ others, so a separate utilities module is provided to inspect views.
+
+ * classregistry -- Here a simple dictionary-based registry for all known
+ classes is provided. It allows us to search in classes.
+
+
+Using the API Dcoumentation
+---------------------------
+
+The `APIDocumentation` class provides access to all available documentation
+modules. Documentation modules are utilities providing `IDocumentationModule`:
+
+
+ >>> from zope.app.testing import ztapi
+ >>> from zope.app.apidoc.interfaces import IDocumentationModule
+ >>> from zope.app.apidoc.ifacemodule.ifacemodule import InterfaceModule
+ >>> from zope.app.apidoc.zcmlmodule import ZCMLModule
+
+ >>> ztapi.provideUtility(IDocumentationModule, InterfaceModule(),
+ ... 'Interface')
+ >>> ztapi.provideUtility(IDocumentationModule, ZCMLModule(), 'ZCML')
+
+Now we can instantiate the class (which is usually done when traversing
+'++apidoc++') and get a list of available modules:
+
+ >>> from zope.app.apidoc.apidoc import APIDocumentation
+ >>> doc = APIDocumentation(None, '++apidoc++')
+
+ >>> modules = doc.keys()
+ >>> modules.sort()
+ >>> modules
+ [u'Interface', u'ZCML']
+
+ >>> doc['ZCML'] #doctest:+ELLIPSIS
+ <zope.app.apidoc.zcmlmodule.ZCMLModule object at ...>
+
+
Developing a Module
-------------------
Deleted: Zope3/trunk/src/zope/app/apidoc/TODO.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/TODO.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/TODO.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,6 +0,0 @@
-TO DO
-=====
-
-- better README.txt
-
-- Refactor some of the views, so that templates can be reused
Modified: Zope3/trunk/src/zope/app/apidoc/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/__init__.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/__init__.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,84 +1,2 @@
-##############################################################################
-#
-# 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.
-#
-##############################################################################
-"""Zope 3 API Documentation
+# Make a package
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-from zope.interface import implements
-
-from zope.app import zapi
-from zope.app.location import locate
-from zope.app.location.interfaces import ILocation
-
-from interfaces import IDocumentationModule
-from utilities import ReadContainerBase
-
-class APIDocumentation(ReadContainerBase):
- r"""Represent the complete API Documentation.
-
- This documentation is implemented using a simply `IReadContainer`. The
- items of the container are all registered utilities for
- `IDocumentationModule`.
-
- Demonstration:
-
- >>> doc = APIDocumentation(None, '++apidoc++')
- >>> doc.get('ZCML').title
- u'ZCML Reference'
-
- >>> doc.get('Documentation') is None
- True
-
- >>> print '\n'.join([id for id, mod in doc.items()])
- Interface
- ZCML
- """
-
- implements(ILocation)
-
- def __init__(self, parent, name):
- self.__parent__ = parent
- self.__name__ = name
-
- def get(self, key, default=None):
- """See zope.app.container.interfaces.IReadContainer"""
- utility = zapi.queryUtility(IDocumentationModule, key, default)
- if utility != default:
- locate(utility, self, key)
- return utility
-
- def items(self):
- """See zope.app.container.interfaces.IReadContainer"""
- items = list(zapi.getUtilitiesFor(IDocumentationModule))
- items.sort()
- utils = []
- for key, value in items:
- locate(value, self, key)
- utils.append((key, value))
- return utils
-
-class apidocNamespace(object):
- """Used to traverse to an API Documentation."""
- def __init__(self, ob, request=None):
- self.context = ob
-
- def traverse(self, name, ignore):
- return handleNamespace(self.context, name)
-
-def handleNamespace(ob, name):
- """Used to traverse to an API Documentation."""
- return APIDocumentation(ob, '++apidoc++'+name)
-
Added: Zope3/trunk/src/zope/app/apidoc/apidoc.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/apidoc.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/apidoc.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,71 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Zope 3 API Documentation
+
+$Id: __init__.py 26777 2004-07-27 08:12:32Z hdima $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.interface import implements
+
+from zope.app import zapi
+from zope.app.location import locate
+from zope.app.location.interfaces import ILocation
+
+from interfaces import IDocumentationModule
+from utilities import ReadContainerBase
+
+class APIDocumentation(ReadContainerBase):
+ """Represent the complete API Documentation.
+
+ This documentation is implemented using a simply `IReadContainer`. The
+ items of the container are all registered utilities for
+ `IDocumentationModule`.
+ """
+ implements(ILocation)
+
+ def __init__(self, parent, name):
+ self.__parent__ = parent
+ self.__name__ = name
+
+ def get(self, key, default=None):
+ """See zope.app.container.interfaces.IReadContainer"""
+ utility = zapi.queryUtility(IDocumentationModule, key, default)
+ if utility != default:
+ locate(utility, self, key)
+ return utility
+
+ def items(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ items = list(zapi.getUtilitiesFor(IDocumentationModule))
+ items.sort()
+ utils = []
+ for key, value in items:
+ locate(value, self, key)
+ utils.append((key, value))
+ return utils
+
+
+class apidocNamespace(object):
+ """Used to traverse to an API Documentation."""
+ def __init__(self, ob, request=None):
+ self.context = ob
+
+ def traverse(self, name, ignore):
+ return handleNamespace(self.context, name)
+
+def handleNamespace(ob, name):
+ """Used to traverse to an API Documentation."""
+ return APIDocumentation(ob, '++apidoc++'+name)
+
Property changes on: Zope3/trunk/src/zope/app/apidoc/apidoc.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/browser/apidoc.css
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/browser/apidoc.css 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/browser/apidoc.css 2005-02-23 22:22:48 UTC (rev 29269)
@@ -73,6 +73,11 @@
padding: 2px 0.5em 2px 0.5em;
}
+h4 {
+ font-size: 90%;
+ font-style: italic;
+}
+
p.breadcrumbs {
padding: 2pt;
border: solid 1px black;
Modified: Zope3/trunk/src/zope/app/apidoc/browser/apidoc.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/browser/apidoc.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/browser/apidoc.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -25,21 +25,7 @@
"""View for the API Documentation"""
def getModuleList(self):
- """Get a list of all available documentation modules.
-
- Example::
-
- >>> from zope.app.apidoc import APIDocumentation
- >>> from zope.publisher.browser import TestRequest
-
- >>> view = APIDocumentationView()
- >>> view.request = TestRequest()
- >>> view.context = APIDocumentation(None, '++apidoc++')
- >>> info = view.getModuleList()
- >>> info = [(i['name'], i['title']) for i in info]
- >>> print info
- [(u'Interface', u'Interfaces'), (u'ZCML', u'ZCML Reference')]
- """
+ """Get a list of all available documentation modules."""
items = list(self.context.items())
items.sort()
result = []
Modified: Zope3/trunk/src/zope/app/apidoc/browser/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/browser/configure.zcml 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/browser/configure.zcml 2005-02-23 22:22:48 UTC (rev 29269)
@@ -27,7 +27,7 @@
/>
<pages
- for="zope.app.apidoc.APIDocumentation"
+ for="zope.app.apidoc.apidoc.APIDocumentation"
class=".apidoc.APIDocumentationView"
permission="zope.app.apidoc.UseAPIDoc">
Added: Zope3/trunk/src/zope/app/apidoc/classregistry.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classregistry.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/classregistry.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,60 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Class Registry
+
+$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+import sys
+
+from zope.app import zapi
+
+class ClassRegistry(dict):
+ """A simple registry for classes."""
+
+ def getClassesThatImplement(self, iface):
+ """Return all class items that implement iface.
+
+ Methods returns a list of 2-tuples of the form (path, class).
+ """
+ return [(path, klass) for path, klass in self.items()
+ if iface.implementedBy(klass)]
+
+ def getSubclassesOf(self, klass):
+ """Return all class items that are proper subclasses of klass.
+
+ Methods returns a list of 2-tuples of the form (path, class).
+ """
+ return [(path, klass2) for path, klass2 in self.items()
+ if issubclass(klass2, klass) and klass2 is not klass]
+
+
+classRegistry = ClassRegistry()
+
+def cleanUp():
+ classRegistry.clear()
+
+from zope.testing.cleanup import addCleanUp
+addCleanUp(cleanUp)
+
+
+def safe_import(path, default=None):
+ """Import a given path as efficiently as possible and without failure."""
+ module = sys.modules.get(path, default)
+ if module is default:
+ try:
+ module = __import__(path, {}, {}, ('*',))
+ except ImportError:
+ return default
+ return module
Added: Zope3/trunk/src/zope/app/apidoc/classregistry.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classregistry.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/classregistry.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,146 @@
+==================
+The Class Registry
+==================
+
+This little registry allows us to quickly query a complete list of classes
+that are defined and used by Zope 3. The prime feature of the class is the
+'getClassesThatImplement(iface)' method that returns all classes that
+implement the passed interface. Another method, 'getSubclassesOf(klass)'
+returns all registered subclassess of the given class.
+
+The class registry, subclassing the dictionary type, can be instantiated like
+any other dictionary:
+
+ >>> from zope.app.apidoc.classregistry import ClassRegistry
+ >>> reg = ClassRegistry()
+
+Let's now add a couple of classes to registry. The classes should implement
+some interfaces, so that we can test all methods on the class registry:
+
+ >>> from zope.interface import Interface, implements
+
+ >>> class IA(Interface):
+ ... pass
+ >>> class IB(IA):
+ ... pass
+ >>> class IC(Interface):
+ ... pass
+ >>> class ID(Interface):
+ ... pass
+
+ >>> class A(object):
+ ... implements(IA)
+ >>> reg['A'] = A
+
+ >>> class B:
+ ... implements(IB)
+ >>> reg['B'] = B
+
+ >>> class B2(object):
+ ... implements(IB)
+ >>> reg['B2'] = B2
+
+ >>> class C(object):
+ ... implements(IC)
+ >>> reg['C'] = C
+ >>> class A2(A):
+ ... pass
+ >>> reg['A2'] = A2
+
+Since the registry is just a dictionary, we can ask for all its keys, which
+are the names of the classes:
+
+ >>> names = reg.keys()
+ >>> names.sort()
+ >>> names
+ ['A', 'A2', 'B', 'B2', 'C']
+
+ >>> reg['A'] is A
+ True
+
+There are two API methods specific to the class registry:
+
+`getClassesThatImplement(iface)`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method returns all classes that implement the specified interface:
+
+ >>> pprint(reg.getClassesThatImplement(IA)) #doctest:+ELLIPSIS
+ [('A', <class 'A'>),
+ ('B', <class __builtin__.B at ...>),
+ ('A2', <class 'A2'>),
+ ('B2', <class 'B2'>)]
+
+ >>> pprint(reg.getClassesThatImplement(IB)) #doctest:+ELLIPSIS
+ [('B', <class __builtin__.B at ...>),
+ ('B2', <class 'B2'>)]
+
+ >>> pprint(reg.getClassesThatImplement(IC))
+ [('C', <class 'C'>)]
+
+ >>> pprint(reg.getClassesThatImplement(ID))
+ []
+
+`getSubclassesOf(klass)`
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method will find all classes that inherit the specified class:
+
+ >>> pprint(reg.getSubclassesOf(A))
+ [('A2', <class 'A2'>)]
+
+ >>> pprint(reg.getSubclassesOf(B))
+ []
+
+
+Safe Imports
+------------
+
+Using the `safe_import()` we can quickly look up modules by minimizing import
+calls.
+
+ >>> from zope.app.apidoc.classregistry import safe_import
+
+First we try to find the path in 'sys.modules', since this lookup is much
+more efficient than importing it. If it was not found, we go back and try
+to import the path. If that also fails, we return the 'default' value.
+
+Here are some examples::
+
+ >>> import sys
+ >>> 'zope.app' in sys.modules
+ True
+
+ >>> safe_import('zope.app') is sys.modules['zope.app']
+ True
+
+ >>> safe_import('weirdname') is None
+ True
+
+For this example, we'll create a dummy module:
+
+ >>> import os
+ >>> here = os.path.dirname(__file__)
+ >>> filename = os.path.join(here, 'testmodule.py')
+ >>> f = open(filename, 'w')
+ >>> f.write('# dummy module\n')
+ >>> f.close()
+
+The temporary module is not already imported, but will be once
+we've called safe_import():
+
+ >>> module_name = 'zope.app.apidoc.testmodule'
+ >>> module_name in sys.modules
+ False
+ >>> safe_import(module_name).__name__ == module_name
+ True
+ >>> module_name in sys.modules
+ True
+
+Now clean up the temporary module, just to play nice:
+
+ >>> os.unlink(filename)
+ >>> if os.path.exists(filename + 'c'):
+ ... os.unlink(filename + 'c')
+ >>> if os.path.exists(filename + 'o'):
+ ... os.unlink(filename + 'o')
Copied: Zope3/trunk/src/zope/app/apidoc/codemodule (from rev 29222, Zope3/trunk/src/zope/app/apidoc/classmodule)
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/__init__.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/__init__.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Class Documentation Module
+"""Code Documentation Module
This module is able to take a dotted name of any class and display
documentation for it.
@@ -19,34 +19,15 @@
$Id$
"""
__docformat__ = 'restructuredtext'
-
-import os
-import sys
-import inspect
-from types import ClassType, TypeType, FunctionType
-
-import zope
-import zope.deprecation
-from zope.security.checker import getCheckerForInstancesOf
-from zope.interface import Interface, Attribute, implements, implementedBy
-
+from zope.interface import Interface, implements
from zope.app import zapi
-from zope.app.container.interfaces import IReadContainer
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.utilities import ReadContainerBase
-from zope.app.apidoc.utilities import getPythonPath
-from zope.app.apidoc.utilities import getPublicAttributes
-from zope.app.apidoc.utilities import getInterfaceForAttribute
-from zope.app.apidoc.utilities import getFunctionSignature
+from zope.app.apidoc.classregistry import safe_import
+from zope.app.apidoc.codemodule.module import Module
-# 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 IAPIDocRootModule(Interface):
"""Marker interface for utilities that represent class browser root
@@ -56,510 +37,14 @@
dotted name.
"""
-class IModuleDocumentation(IReadContainer):
- """Representation of a Python module for documentation.
- The items of the container are sub-modules and classes.
- """
- def getDocString():
- """Return the doc string of the module."""
+class CodeModule(Module):
+ """Represent the Documentation of any possible source code in the packages.
- def getFileName():
- """Return the file name of the module."""
-
- def getPath():
- """Return the Python path of the module."""
-
-
-class IClassDocumentation(Interface):
- """Representation of a class or type for documentation."""
-
- def getDocString():
- """Return the doc string of the class."""
-
- def getPath():
- """Return the Python path of the class."""
-
- def getBases():
- """Return the base classes of the class."""
-
- def getKnownSubclasses():
- """Return the known subclasses classes of the class."""
-
- def getInterfaces():
- """Return the interfaces the class implements."""
-
- def getAttributes():
- """Return a list of 3-tuple attribute information.
-
- The first entry of the 3-tuple is the name of the attribute, the
- second is the attribute object itself. The third entry is the
- interface in which the attribute is defined.
-
- Note that only public attributes are returned, meaning only attributes
- that do not start with an '_'-character.
- """
-
- def getMethods():
- """Return a list of 3-tuple method information.
-
- The first entry of the 3-tuple is the name of the method, the
- second is the method object itself. The third entry is the
- interface in which the method is defined.
-
- Note that only public methods are returned, meaning only methods
- that do not start with an '_'-character.
- """
-
- def getSecurityChecker():
- """Return the security checker for this class.
-
- Since 99% of the time we are dealing with name-based security
- checkers, we can look up the get/set permission required for a
- particular class attribute/method.
- """
-
-class IFunctionDocumentation(Interface):
- """Representation of a function for documentation."""
-
- def getDocString():
- """Return the doc string of the function."""
-
- def getPath():
- """Return the Python path of the function."""
-
- def getSignature():
- """Return the signature of the function as a string."""
-
- def getAttributes():
- """Return a list of 2-tuple attribute information.
-
- The first entry of the 2-tuple is the name of the attribute, the
- second is the attribute object itself.
- """
-
-class IZCMLFileDocumentation(Interface):
- """Representation of a function for documentation."""
-
- path = Attribute('Full path of the ZCML file.')
-
-
-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']
- """
- implements(ILocation, IModuleDocumentation)
-
- def __init__(self, parent, name, module, setup=True):
- """Initialize object."""
- self.__parent__ = parent
- self.__name__ = name
- self.__module = module
- self.__children = {}
- if setup:
- self.__setup()
-
- def __setup(self):
- """Setup the module sub-tree."""
- # Detect packages
- if hasattr(self.__module, '__file__') and \
- (self.__module.__file__.endswith('__init__.py') or
- self.__module.__file__.endswith('__init__.pyc')or
- self.__module.__file__.endswith('__init__.pyo')):
- dir = os.path.dirname(self.__module.__file__)
- for file in os.listdir(dir):
- if file in IGNORE_FILES:
- continue
- path = os.path.join(dir, file)
-
- if os.path.isdir(path) and '__init__.py' in os.listdir(path):
- fullname = self.__module.__name__ + '.' + file
- module = safe_import(fullname)
- if module is not None:
- self.__children[file] = Module(self, file, module)
-
- elif os.path.isfile(path) and file.endswith('.py') and \
- not file.startswith('__init__'):
- name = file[:-3]
- fullname = self.__module.__name__ + '.' + name
- module = safe_import(fullname)
- if module is not None:
- self.__children[name] = Module(self, name, module)
-
- elif os.path.isfile(path) and file.endswith('.zcml'):
- self.__children[file] = ZCMLFile(self, file, path)
-
- # Setup classes in module, if any are available.
- zope.deprecation.__show__.off()
- for name in self.__module.__dict__.keys():
- attr = getattr(self.__module, name)
- # We do not want to register duplicates or non-"classes"
- if hasattr(attr, '__module__') and \
- attr.__module__ == self.__module.__name__:
-
- if type(attr) in (ClassType, TypeType) and \
- attr.__name__ == name:
- self.__children[attr.__name__] = Class(self, name, attr)
-
- elif type(attr) is FunctionType and not name.startswith('_'):
- self.__children[attr.__name__] = Function(self, name, attr)
- zope.deprecation.__show__.on()
-
-
- def getDocString(self):
- """See IModule."""
- return self.__module.__doc__
-
- def getFileName(self):
- """See IModule."""
- return self.__module.__file__
-
- def getPath(self):
- """See IModule."""
- return self.__module.__name__
-
- def get(self, key, default=None):
- """See zope.app.container.interfaces.IReadContainer."""
- obj = self.__children.get(key, default)
- if obj is not default:
- return obj
-
- # We are actually able to find much more than we promise
- if self.getPath():
- path = self.getPath() + '.' + key
- else:
- path = key
- obj = safe_import(path)
- if obj is not None:
- return Module(self, key, obj)
-
- return default
-
- def items(self):
- """See zope.app.container.interfaces.IReadContainer."""
- return self.__children.items()
-
-
-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)
-
- """
- implements(ILocation, IClassDocumentation)
-
- def __init__(self, module, name, klass):
- self.__parent__ = module
- self.__name__ = name
- self.__klass = klass
-
- # Setup interfaces that are implemented by this class.
- self.__interfaces = list(implementedBy(klass))
- all_ifaces = {}
- for iface in self.__interfaces:
- all_ifaces[getPythonPath(iface)] = iface
- for base in [base for base in iface.__bases__]:
- all_ifaces[getPythonPath(base)] = base
- self.__all_ifaces = all_ifaces.values()
-
- # Register the class with the global class registry.
- global classRegistry
- classRegistry[self.getPath()] = klass
-
- def getPath(self):
- """See IClassDocumentation."""
- return self.__parent__.getPath() + '.' + self.__name__
-
- def getDocString(self):
- """See IClassDocumentation."""
- return self.__klass.__doc__
-
- def getBases(self):
- """See IClassDocumentation."""
- return self.__klass.__bases__
-
- def getKnownSubclasses(self):
- """See IClassDocumentation."""
- global classRegistry
- return [k for n, k in classRegistry.getSubclassesOf(self.__klass)]
-
- def getInterfaces(self):
- """See IClassDocumentation."""
- 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>)]
- """
- return [
- (name, getattr(self.__klass, name),
- getInterfaceForAttribute(name, self.__all_ifaces, asPath=False))
-
- for name in getPublicAttributes(self.__klass)
- 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>)]
- """
- return [
- (name, getattr(self.__klass, name),
- getInterfaceForAttribute(name, self.__all_ifaces, asPath=False))
-
- for name in getPublicAttributes(self.__klass)
- if inspect.ismethod(getattr(self.__klass, name))]
-
- def getSecurityChecker(self):
- """See IClassDocumentation."""
- return getCheckerForInstancesOf(self.__klass)
-
-
-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()
- []
- """
- implements(ILocation, IFunctionDocumentation)
-
- def __init__(self, module, name, func):
- self.__parent__ = module
- self.__name__ = name
- self.__func = func
-
- def getPath(self):
- """See IFunctionDocumentation."""
- return self.__parent__.getPath() + '.' + self.__name__
-
- def getDocString(self):
- """See IFunctionDocumentation."""
- return self.__func.__doc__
-
- def getSignature(self):
- """See IFunctionDocumentation."""
- 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')]
- """
- return self.__func.__dict__.items()
-
-
-class ZCMLFile(object):
- """Represent the documentation of any ZCML file.
-
- This object in itself is rather simple, since it only stores the full path
- of the ZCML file and its location in the documentation tree.
-
- >>> zcml = ZCMLFile(None, 'foo.zcml', '/Zope3/src/zope/app/foo.zcml')
- >>> zcml.__parent__ is None
- True
- >>> zcml.__name__
- 'foo.zcml'
- >>> zcml.path
- '/Zope3/src/zope/app/foo.zcml'
- """
-
- implements(ILocation, IZCMLFileDocumentation)
-
- def __init__(self, module, name, path):
- """Initialize the object."""
- self.__parent__ = module
- self.__name__ = name
- self.path = path
-
-
-class ClassModule(Module):
- """Represent the Documentation of any possible class.
-
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 = ClassModule()
+ >>> cm = CodeModule()
>>> cm.getDocString()
u'Zope 3 root.'
@@ -570,13 +55,13 @@
>>> names = cm.keys()
>>> names.sort()
- >>> names == [u'zope']
- True
+ >>> names
+ [u'zope']
"""
implements(IDocumentationModule)
# See zope.app.apidoc.interfaces.IDocumentationModule
- title = _('Classes')
+ title = _('Code Browser')
# See zope.app.apidoc.interfaces.IDocumentationModule
description = _("""
@@ -602,13 +87,16 @@
""")
def __init__(self):
"""Initialize object."""
- super(ClassModule, self).__init__(None, '', None, False)
+ super(CodeModule, self).__init__(None, '', None, False)
self.__isSetup = False
- def __setup(self):
+ def setup(self):
"""Setup module and class tree."""
+ if self.__isSetup:
+ return
for name, mod in zapi.getUtilitiesFor(IAPIDocRootModule):
- self._Module__children[name] = Module(self, name, safe_import(mod))
+ self._children[name] = Module(self, name, safe_import(mod))
+ self.__isSetup = True
def getDocString(self):
"""See Module class."""
@@ -624,161 +112,10 @@
def get(self, key, default=None):
"""See zope.app.container.interfaces.IReadContainer."""
- if self.__isSetup is False:
- self.__setup()
- self.__isSetup = True
- return super(ClassModule, self).get(key, default)
+ self.setup()
+ return super(CodeModule, self).get(key, default)
def items(self):
"""See zope.app.container.interfaces.IReadContainer."""
- if self.__isSetup is False:
- self.__setup()
- self.__isSetup = True
- return super(ClassModule, self).items()
-
-
-class ClassRegistry(dict):
- """A simple registry for classes.
-
- This little registry allows us to quickly query a complete list of classes
- that are defined and used by Zope 3. The prime feature of the class is the
- 'getClassesThatImplement(iface)' method that returns all classes that
- implement the passed interface. Another method, 'getSubclassesOf(klass)'
- returns all registered subclassess of the given class.
-
- Here is the registry in action::
-
- >>> reg = ClassRegistry()
-
- >>> class IA(Interface):
- ... pass
- >>> class IB(IA):
- ... pass
- >>> class IC(Interface):
- ... pass
- >>> class ID(Interface):
- ... pass
-
- >>> class A(object):
- ... implements(IA)
- >>> reg['A'] = A
- >>> class B:
- ... implements(IB)
- >>> reg['B'] = B
- >>> class B2(object):
- ... implements(IB)
- >>> reg['B2'] = B2
- >>> class C(object):
- ... implements(IC)
- >>> reg['C'] = C
- >>> class A2(A):
- ... pass
- >>> reg['A2'] = A2
-
- >>> names = reg.keys()
- >>> names.sort()
- >>> names
- ['A', 'A2', 'B', 'B2', 'C']
-
- >>> reg['A'] is A
- True
-
- >>> def names(l):
- ... l = [n for n, k in l]
- ... l.sort()
- ... return l
-
- >>> names(reg.getClassesThatImplement(IA))
- ['A', 'A2', 'B', 'B2']
- >>> names(reg.getClassesThatImplement(IB))
- ['B', 'B2']
- >>> names(reg.getClassesThatImplement(IC))
- ['C']
- >>> names(reg.getClassesThatImplement(ID))
- []
-
- >>> names(reg.getSubclassesOf(A))
- ['A2']
- >>> names(reg.getSubclassesOf(B))
- []
-
- """
-
- def getClassesThatImplement(self, iface):
- """Return all class items that implement iface.
-
- Methods returns a list of 2-tuples of the form (path, class).
- """
- return [(path, klass) for path, klass in self.items()
- if iface.implementedBy(klass)]
-
- def getSubclassesOf(self, klass):
- """Return all class items that are proper subclasses of klass.
-
- Methods returns a list of 2-tuples of the form (path, class).
- """
- return [(path, klass2) for path, klass2 in self.items()
- if issubclass(klass2, klass) and klass2 is not klass]
-
-
-classRegistry = ClassRegistry()
-
-def cleanUp():
- classRegistry.clear()
-
-from zope.testing.cleanup import addCleanUp
-addCleanUp(cleanUp)
-
-
-def safe_import(path, default=None):
- r"""Import a given path as efficiently as possible and without failure.
-
- First we try to find the path in 'sys.modules', since this lookup is much
- more efficient than importing it. If it was not found, we go back and try
- to import the path. If that also fails, we return the 'default' value.
-
- Here are some examples::
-
- >>> 'zope.app' in sys.modules
- True
- >>> safe_import('zope.app') is sys.modules['zope.app']
- True
-
- >>> safe_import('weirdname') is None
- True
-
- For this example, we'll create a dummy module:
-
- >>> here = os.path.dirname(__file__)
- >>> filename = os.path.join(here, 'testmodule.py')
- >>> f = open(filename, 'w')
- >>> f.write('# dummy module\n')
- >>> f.close()
-
- The temporary module is not already imported, but will be once
- we've called safe_import():
-
- >>> module_name = __name__ + '.testmodule'
- >>> module_name in sys.modules
- False
- >>> safe_import(module_name).__name__ == module_name
- True
- >>> module_name in sys.modules
- True
- >>> del sys.modules[module_name]
-
- Now clean up the temporary module, just to play nice:
-
- >>> os.unlink(filename)
- >>> if os.path.exists(filename + 'c'):
- ... os.unlink(filename + 'c')
- >>> if os.path.exists(filename + 'o'):
- ... os.unlink(filename + 'o')
- """
- module = sys.modules.get(path, default)
- if module is default:
- try:
- module = __import__(path, {}, {}, ('*',))
- except ImportError:
- return default
- return module
+ self.setup()
+ return super(CodeModule, self).items()
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/__init__.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/__init__.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1 @@
+# Make a package.
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/__init__.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/class_.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,255 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Class Views
+
+$Id: browser.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+import types
+from zope.proxy import removeAllProxies
+from zope.security.proxy import removeSecurityProxy
+
+from zope.app import zapi
+from zope.app.apidoc.interfaces import IDocumentationModule
+from zope.app.apidoc.utilities import getPythonPath, getPermissionIds
+from zope.app.apidoc.utilities import renderText, getFunctionSignature
+
+
+def getTypeLink(type):
+ if type is types.NoneType:
+ return None
+ path = getPythonPath(type)
+ return path.replace('.', '/')
+
+class ClassDetails(object):
+ """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'}]
+ """
+ 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())
+ []
+ """
+ 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'}]
+ """
+ info = []
+ codeModule = zapi.getUtility(IDocumentationModule, "Code")
+ for cls in classes:
+ # We need to removeAllProxies because the security checkers for
+ # zope.app.container.contained.ContainedProxy and
+ # zope.app.i18n.messagecatalog.MessageCatalog prevent us from
+ # accessing __name__ and __module__.
+ unwrapped_cls = removeAllProxies(cls)
+ path = getPythonPath(unwrapped_cls)
+ try:
+ klass = zapi.traverse(codeModule, path.replace('.', '/'))
+ url = zapi.absoluteURL(klass, self.request)
+ except TraversalError:
+ # If one of the classes is implemented in C, we will not
+ # be able to find it.
+ url = None
+ info.append({'path': path, 'url': url})
+ return info
+
+
+ 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'
+ """
+ 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']
+ """
+ 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)]
+ """
+ attrs = []
+ for name, attr, iface in self.context.getAttributes():
+ entry = {'name': name,
+ 'value': `attr`,
+ 'type': type(attr).__name__,
+ 'type_link': getTypeLink(type(attr)),
+ 'interface': getPythonPath(iface)}
+ # Since checkers do not have security declarations on their API,
+ # we have to remove the security wrapper to get to the API calls.
+ checker = self.context.getSecurityChecker()
+ entry.update(
+ getPermissionIds(name, removeSecurityProxy(checker)))
+ attrs.append(entry)
+ return attrs
+
+
+ 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)]]
+ """
+ methods = []
+ # remove the security proxy, so that `attr` is not proxied. We could
+ # unproxy `attr` for each turn, but that would be less efficient.
+ #
+ # `getPermissionIds()` also expects the class's security checker not
+ # to be proxied.
+ klass = removeSecurityProxy(self.context)
+ for name, attr, iface in klass.getMethods():
+ entry = {'name': name,
+ 'signature': getFunctionSignature(attr),
+ 'doc': renderText(attr.__doc__ or '',
+ zapi.getParent(self.context).getPath()),
+ 'interface': getPythonPath(iface)}
+ entry.update(getPermissionIds(name, klass.getSecurityChecker()))
+ methods.append(entry)
+ return methods
+
+
+ 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>
+ """
+ return renderText(self.context.getDocString() or '',
+ zapi.getParent(self.context).getPath())
+
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/class_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,176 @@
+<html metal:use-macro="views/apidoc_macros/details">
+<body metal:fill-slot="contents">
+
+ <h1 class="details-header"
+ tal:content="context/getPath">
+ zope.app.Klass
+ </h1>
+
+ <div class="indent">
+ <div class="documentation" tal:content="structure view/getDoc">
+ Here is the doc string
+ </div>
+ </div>
+
+
+ <h2 class="details-section" i18n:translate="">Bases</h2>
+
+ <div class="indent"
+ tal:define="bases view/getBases">
+
+ <ul class="attr-list" tal:condition="bases">
+ <li tal:repeat="base bases">
+ <a href=""
+ tal:attributes="href string:${base/url}/index.html"
+ tal:content="base/path"
+ tal:condition="base/url" />
+ <div tal:condition="not: base/url">
+ <span tal:replace="base/path" />
+ <span i18n:translate="">(C-based class)</span>
+ </div>
+ </li>
+ </ul>
+
+ <p tal:condition="not: bases">
+ <em i18n:translate="">There are no base classes.</em>
+ </p>
+
+ </div>
+
+ <h2 class="details-section" i18n:translate="">Implemented Interfaces</h2>
+
+ <div class="indent"
+ tal:define="ifaces view/getInterfaces">
+
+ <ul class="attr-list" tal:condition="ifaces">
+ <li tal:repeat="iface ifaces">
+ <a href=""
+ tal:attributes="href
+ string:${view/getBaseURL}/Interface/$iface/apiindex.html"
+ tal:content="iface" />
+ </li>
+ </ul>
+
+ <p tal:condition="not: ifaces">
+ <em i18n:translate="">There are no implemented interfaces.</em>
+ </p>
+
+ </div>
+
+
+ <h2 class="details-section" i18n:translate="">Attributes/Properties</h2>
+
+ <div class="indent"
+ tal:define="attributes view/getAttributes">
+
+ <ul class="attr-list" tal:condition="attributes">
+
+ <li tal:repeat="attr attributes">
+ <b><code tal:content="attr/name">attr</code></b>
+ <tal:omit-tag condition="not: attr/type_link">
+ (type: <code tal:content="attr/type" />)
+ </tal:omit-tag>
+ <tal:omit-tag condition="attr/type_link">
+ (<span i18n:translate="">type:</span>
+ <a href=""
+ tal:attributes="href
+ string:${view/getBaseURL}/Code/${attr/type_link}/index.html">
+ <code tal:content="attr/type" /></a>)
+ </tal:omit-tag>
+ <br/>
+ <i i18n:translate="">Value:</i>
+ <code tal:content="attr/value">u''</code><br />
+
+ <span class="small" tal:condition="attr/interface">
+ <i i18n:translate="">Interface:</i>
+ <a href=""
+ tal:attributes="href
+ string:${view/getBaseURL}/Interface/${attr/interface}/apiindex.html"
+ tal:content="attr/interface">Iface</a><br />
+ </span>
+ <span class="small"
+ tal:condition="python: attr['read_perm'] and attr['write_perm']">
+ <i i18n:translate="">Permissions:</i>
+ <span tal:replace="attr/read_perm">zope.View</span>
+ <span i18n:translate="">(read)</span>,
+ <span tal:replace="attr/write_perm">zope.View</span>
+ <span i18n:translate="">(write)</span>
+ </span>
+ </li>
+
+ </ul>
+
+ <p tal:condition="not: attributes">
+ <em i18n:translate="">There are no attributes in this class.</em>
+ </p>
+
+ </div>
+
+
+ <h2 class="details-section" i18n:translate="">Methods</h2>
+
+ <div class="indent"
+ tal:define="methods view/getMethods">
+
+ <ul class="attr-list" tal:condition="methods">
+
+ <li tal:repeat="method view/getMethods">
+ <b><code
+ tal:content="string:${method/name}${method/signature}" />
+ </b><br>
+ <div class="inline-documentation" tal:content="structure method/doc">
+ method desc
+ </div>
+
+ <span class="small" tal:condition="method/interface">
+ <i i18n:translate="">Interface:</i>
+ <a href=""
+ tal:attributes="href
+ string:${view/getBaseURL}/Interface/${method/interface}/apiindex.html"
+ tal:content="method/interface">Iface</a><br/>
+ </span>
+
+ <span class="small"
+ tal:condition="python: method['read_perm'] and method['write_perm']">
+ <i i18n:translate="">Permissions:</i>
+ <span tal:replace="method/read_perm">zope.View</span>
+ <span i18n:translate="">(read)</span>,
+ <span tal:replace="method/write_perm">zope.View</span>
+ <span i18n:translate="">(write)</span>
+ </span>
+ </li>
+
+ </ul>
+
+ <p tal:condition="not: methods">
+ <em i18n:translate="">There are no methods in this class.</em>
+ </p>
+
+ </div>
+
+ <h2 class="details-section" i18n:translate="">Known Subclasses</h2>
+
+ <div class="indent"
+ tal:define="subclasses view/getKnownSubclasses">
+
+ <ul class="attr-list" tal:condition="subclasses">
+ <li tal:repeat="cls subclasses">
+ <a href=""
+ tal:attributes="href string:${cls/url}/index.html"
+ tal:content="cls/path"
+ tal:condition="cls/url" />
+ <div tal:condition="not: cls/url">
+ <span tal:replace="cls/path" />
+ <span i18n:translate="">(C-based class)</span>
+ </div>
+ </li>
+ </ul>
+
+ <p tal:condition="not: subclasses">
+ <em i18n:translate="">There are no known subclasses.</em>
+ </p>
+
+ </div>
+
+</body>
+</html>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_index.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/configure.zcml 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/configure.zcml 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,62 @@
+<configure
+ xmlns="http://namespaces.zope.org/browser"
+ xmlns:zope="http://namespaces.zope.org/zope">
+
+ <page
+ for="..CodeModule"
+ permission="zope.app.apidoc.UseAPIDoc"
+ class=".menu.Menu"
+ name="menu.html"
+ template="menu.pt" />
+
+ <page
+ for="..interfaces.IModuleDocumentation"
+ permission="zope.app.apidoc.UseAPIDoc"
+ class=".module.ModuleDetails"
+ name="index.html"
+ template="module_index.pt" />
+
+ <page
+ for="..interfaces.IClassDocumentation"
+ permission="zope.app.apidoc.UseAPIDoc"
+ class=".class_.ClassDetails"
+ name="index.html"
+ template="class_index.pt" />
+
+ <page
+ for="..interfaces.IFunctionDocumentation"
+ permission="zope.app.apidoc.UseAPIDoc"
+ class=".function.FunctionDetails"
+ name="index.html"
+ template="function_index.pt" />
+
+ <page
+ for="..text.TextFile"
+ permission="zope.app.apidoc.UseAPIDoc"
+ class=".text.TextFileDetails"
+ name="index.html"
+ template="textfile_index.pt" />
+
+ <!-- ZCML File -->
+ <page
+ for="..interfaces.IConfiguration"
+ name="index.html"
+ template="zcmlfile_index.pt"
+ permission="zope.View"/>
+
+ <page
+ name="display"
+ for="..interfaces.IDirective"
+ template="displayDirective.pt"
+ class=".zcml.DisplayDirective"
+ permission="zope.ManageContent"/>
+
+ <page
+ name="display"
+ for="..interfaces.IComment"
+ template="displayComment.pt"
+ class=".zcml.DisplayComment"
+ permission="zope.ManageContent"/>
+
+
+</configure>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayClosingElement.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/displayClosingElement.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayClosingElement.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,3 @@
+<div class="directive">
+ </<span class="tagName" tal:content="context/tagName">tagName</span>>
+</div>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayClosingElement.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayComment.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/displayComment.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayComment.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,4 @@
+<br />
+<div class="commentElement">
+ <!-- <tal:block replace="view/value" /> -->
+</div>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayComment.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/displayDirective.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,30 @@
+<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>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/displayDirective.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/function.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,61 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Function Views
+
+$Id: browser.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope.app import zapi
+from zope.app.apidoc.utilities import getPythonPath, renderText
+
+class FunctionDetails(object):
+ """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'
+ """
+ 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')]
+ """
+ return [{'name': name,
+ 'value': `attr`,
+ 'type': type(attr).__name__,
+ 'type_link': getPythonPath(type(attr)).replace('.', '/')}
+
+ for name, attr in self.context.getAttributes()]
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/function_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,61 @@
+<html metal:use-macro="views/apidoc_macros/details">
+<body metal:fill-slot="contents">
+
+ <h1 class="details-header"
+ tal:content="context/getPath">
+ zope.app.function
+ </h1>
+
+ <h2 class="details-section" i18n:translate="">Signature</h2>
+
+ <div class="indent">
+ <b><code
+ tal:content="string:${context/zope:name}${context/getSignature}" />
+ </b>
+ </div>
+
+ <div tal:condition="context/getDocString">
+ <h2 class="details-section" i18n:translate="">Documentation String</h2>
+
+ <div class="indent">
+ <div class="documentation" tal:content="structure view/getDocString">
+ Here is the doc string
+ </div>
+ </div>
+ </div>
+
+ <div
+ tal:define="attributes view/getAttributes"
+ tal:condition="attributes">
+
+ <h2 class="details-section" i18n:translate="">Attributes</h2>
+
+ <div class="indent">
+
+ <ul class="attr-list">
+
+ <li tal:repeat="attr attributes">
+ <b><code tal:content="attr/name">attr</code></b>
+ <tal:omit-tag condition="not: attr/type_link">
+ (<span i18n:translate="">type:</span>
+ <code tal:content="attr/type" />)
+ </tal:omit-tag>
+ <tal:omit-tag condition="attr/type_link">
+ (<span i18n:translate="">type:</span>
+ <a href=""
+ tal:attributes="href
+ string:${view/getBaseURL}/Code/${attr/type_link}/index.html">
+ <code tal:content="attr/type" /></a>)
+ </tal:omit-tag>
+ <br/>
+ <i i18n:translate="">Value:</i>
+ <code tal:content="attr/value">u''</code><br />
+ </li>
+
+ </ul>
+
+ </div>
+ </div>
+
+</body>
+</html>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function_index.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/menu.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/menu.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/menu.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,34 @@
+<html metal:use-macro="views/apidoc_macros/menu">
+<body>
+
+ <div metal:fill-slot="menu" class="small">
+
+ <div tal:define="classes view/findClasses"
+ tal:condition="classes">
+
+ <a href="" target="main"
+ tal:repeat="info classes"
+ tal:attributes="href info/url"
+ tal:content="info/path">
+ /zope/app/Application
+ </a>
+ </div>
+
+ <div>
+ <span i18n:translate="">Class Finder:</span> <br/>
+ <i i18n:translate="">(Enter partial Python path)</i></div>
+ <form action="menu.html" method="post">
+ <input type="text" name="path"
+ style="font-size: 80%; width=95%" />
+ <input type="submit" name="SUBMIT" value="Find"
+ i18n:attributes="value find-button" style="font-size: 80%"/>
+ </form>
+
+ <p style="font-size: 120%">
+ <a href="./index.html" target="main" i18n:translate="">Browse
+ Zope Source</a>
+ </p>
+ </div>
+
+</body>
+</html>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/menu.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/menu.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/menu.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/menu.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,98 @@
+##############################################################################
+#
+# 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 Module Menu
+
+$Id: browser.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope.app import zapi
+from zope.app.apidoc.interfaces import IDocumentationModule
+from zope.app.apidoc.classregistry import classRegistry
+
+class Menu(object):
+ """Menu for the Class Documentation Module.
+
+ The menu allows for looking for classes by partial names. See
+ `findClasses()` for the simple search implementation.
+ """
+
+ def findClasses(self):
+ """Find the classes that match a partial path.
+
+ Examples::
+
+ >>> from zope.app.apidoc.tests import pprint
+ >>> from zope.app.apidoc.classmodule import Class
+ >>> cm = zapi.getUtility(IDocumentationModule, 'Class')
+ >>> mod = cm['zope']['app']['apidoc']['classmodule']['browser']
+
+ Setup a couple of classes and register them.
+
+ >>> class Foo(object):
+ ... pass
+ >>> mod._Module__children['Foo'] = Class(mod, 'Foo', Foo)
+ >>> class Foo2(object):
+ ... pass
+ >>> mod._Module__children['Foo2'] = Class(mod, 'Foo2', Foo2)
+ >>> class Blah(object):
+ ... pass
+ >>> mod._Module__children['Blah'] = Class(mod, 'Blah', Blah)
+
+ Setup the view.
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> menu = Menu()
+ >>> menu.context = None
+
+ Testing the method with various inputs.
+
+ >>> menu.request = TestRequest(form={'path': 'Foo'})
+ >>> info = menu.findClasses()
+
+ >>> pprint(info)
+ [[('path', 'zope.app.apidoc.classmodule.browser.Foo'),
+ ('url',
+ 'http://127.0.0.1/zope/app/apidoc/classmodule/browser/Foo')],
+ [('path', 'zope.app.apidoc.classmodule.browser.Foo2'),
+ ('url',
+ 'http://127.0.0.1/zope/app/apidoc/classmodule/browser/Foo2')]]
+
+ >>> menu.request = TestRequest(form={'path': 'o2'})
+ >>> info = menu.findClasses()
+ >>> pprint(info)
+ [[('path', 'zope.app.apidoc.classmodule.browser.Foo2'),
+ ('url',
+ 'http://127.0.0.1/zope/app/apidoc/classmodule/browser/Foo2')]]
+
+ >>> menu.request = TestRequest(form={'path': 'Blah'})
+ >>> info = menu.findClasses()
+ >>> pprint(info)
+ [[('path', 'zope.app.apidoc.classmodule.browser.Blah'),
+ ('url',
+ 'http://127.0.0.1/zope/app/apidoc/classmodule/browser/Blah')]]
+ """
+ path = self.request.get('path', None)
+ if path is None:
+ return []
+ classModule = zapi.getUtility(IDocumentationModule, "Code")
+ results = []
+ for p in classRegistry.keys():
+ if p.find(path) >= 0:
+ klass = zapi.traverse(classModule, p.replace('.', '/'))
+ results.append(
+ {'path': p,
+ 'url': zapi.absoluteURL(klass, self.request)
+ })
+ results.sort(lambda x, y: cmp(x['path'], y['path']))
+ return results
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/menu.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/module.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,142 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Module Views
+
+$Id: browser.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope.interface.interface import InterfaceClass
+from zope.security.proxy import removeSecurityProxy
+from zope.proxy import removeAllProxies
+
+from zope.app import zapi
+from zope.app.i18n import ZopeMessageIDFactory as _
+
+from zope.app.apidoc.utilities import renderText, columnize
+from zope.app.apidoc.codemodule.module import Module
+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
+
+
+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>
+ """
+ text = self.context.getDocString()
+ if text is None:
+ return None
+ lines = text.strip().split('\n')
+ # Get rid of possible CVS id.
+ lines = [line for line in lines if not line.startswith('$Id')]
+ 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')]]
+ """
+ entries = [{'name': name,
+ 'url': zapi.absoluteURL(obj, self.request),
+ 'ismodule': zapi.isinstance(obj, Module),
+ 'isinterface': zapi.isinstance(
+ removeAllProxies(obj), InterfaceClass),
+ 'isclass': zapi.isinstance(obj, Class),
+ 'isfunction': zapi.isinstance(obj, Function),
+ 'istextfile': zapi.isinstance(obj, TextFile),
+ 'iszcmlfile': zapi.isinstance(obj, Configuration)}
+ for name, obj in self.context.items()]
+ entries.sort(lambda x, y: cmp(x['name'], y['name']))
+ if columns:
+ entries = columnize(entries)
+ return entries
+
+ def getBreadCrumbs(self):
+ """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')]]
+ """
+ names = self.context.getPath().split('.')
+ crumbs = []
+ module = self.context
+ # I really need the class here, so remove the proxy.
+ while removeSecurityProxy(module).__class__ is Module:
+ crumbs.append(
+ {'name': zapi.name(module),
+ 'url': zapi.absoluteURL(module, self.request)}
+ )
+ module = zapi.getParent(module)
+
+ crumbs.append(
+ {'name': _('[top]'),
+ 'url': zapi.getMultiAdapter(
+ (module, self.request), name='absolute_url')()} )
+
+ crumbs.reverse()
+ return crumbs
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/module_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,57 @@
+<html metal:use-macro="views/apidoc_macros/details">
+<body metal:fill-slot="contents">
+
+ <h1 class="details-header" i18n:translate="">Zope 3 Code Browser</h1>
+
+ <p class="breadcrumbs">
+ <span tal:repeat="entry view/getBreadCrumbs">
+ <a href=""
+ tal:attributes="href string:${entry/url}/index.html"
+ tal:content="entry/name" />
+ <tal:omit-tag condition="not: repeat/entry/end">/</tal:omit-tag>
+ </span>
+ </p>
+
+ <div class="highlight"
+ tal:define="doc view/getDoc"
+ tal:condition="doc"
+ tal:content="structure doc">
+ Module Documentation
+ </div>
+
+
+ <table width="100%" valign="top"><tr>
+
+ <td tal:repeat="column view/getEntries"><ul>
+ <li tal:repeat="entry column">
+ <a href=""
+ tal:condition="entry/ismodule"
+ tal:attributes="href string:./${entry/name}/index.html"
+ tal:content="entry/name" />
+ <a href=""
+ tal:condition="entry/isinterface"
+ tal:attributes="href string:./${entry/name}/apiindex.html"
+ tal:content="structure string:<b><i>${entry/name}</i></b>" />
+ <a href=""
+ tal:condition="entry/isclass"
+ tal:attributes="href string:./${entry/name}/index.html"
+ tal:content="structure string:<b>${entry/name}</b>" />
+ <a href=""
+ tal:condition="entry/isfunction"
+ tal:attributes="href string:./${entry/name}/index.html"
+ tal:content="structure string:<i>${entry/name}</i>" />
+ <a href=""
+ tal:condition="entry/iszcmlfile"
+ tal:attributes="href string:./${entry/name}/index.html"
+ tal:content="structure string:<i>${entry/name}</i>" />
+ <a href=""
+ tal:condition="entry/istextfile"
+ tal:attributes="href string:./${entry/name}/index.html"
+ tal:content="structure string:<i>${entry/name}</i>" />
+ </li>
+ </ul></td>
+
+ </tr></table>
+
+</body>
+</html>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module_index.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/text.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/text.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/text.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Function Views
+
+$Id: browser.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope.app.apidoc.utilities import renderText
+
+class TextFileDetails(object):
+ """Represents the details of the text file."""
+
+ def renderedContent(self):
+ if self.context.path.endswith('.stx'):
+ format = 'zope.source.stx'
+ else:
+ format = 'zope.source.rest'
+ return renderText(self.context.getContent(), format=format)
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/text.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/textfile_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/textfile_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/textfile_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,10 @@
+<html metal:use-macro="views/apidoc_macros/details">
+<body metal:fill-slot="contents">
+
+ <div class="documentation"
+ tal:content="structure view/renderedContent">
+ file content
+ </div>
+
+</body>
+</html>
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/textfile_index.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/zcml.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,126 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""ZCML Element Views
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+from zope.configuration.fields import GlobalObject, GlobalInterface
+from zope.interface import implements
+from zope.schema import getFieldNamesInOrder, getFieldsInOrder
+from zope.schema.interfaces import IFromUnicode
+from zope.security.proxy import removeSecurityProxy
+
+from zope.app import zapi
+from zope.app.tree.interfaces import IUniqueId
+from zope.app.apidoc.interfaces import IDocumentationModule
+from zope.app.apidoc.utilities import getPythonPath
+
+def findDocModule(obj):
+ if IDocumentationModule.providedBy(obj):
+ return obj
+ return findDocModule(zapi.getParent(obj))
+
+def _compareAttrs(x, y, nameOrder):
+ if x['name'] in nameOrder:
+ valueX = nameOrder.index(x['name'])
+ else:
+ valueX = 999999
+
+ if y['name'] in nameOrder:
+ valueY = nameOrder.index(y['name'])
+ else:
+ valueY = 999999
+
+ return cmp(valueX, valueY)
+
+
+class DisplayComment(object):
+
+ value = property(lambda self: self.context.value)
+
+ id = property(lambda self: IUniqueId(self.context).getId())
+
+
+class DisplayDirective(object):
+
+ 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 = ns.replace(':', '_co_')
+ ns = ns.replace('/', '_sl_')
+ zcml = zapi.getUtility(IDocumentationModule, 'ZCML')
+ return '%s/../ZCML/%s/%s/index.html' %(
+ zapi.absoluteURL(findDocModule(self), self.request), ns,
+ context.domElement.localName)
+
+
+ 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()]
+
+ for attr in attrs:
+ if name in schema:
+ field = schema[name]
+ elif name+'_' in schema:
+ field = schema[name+'_']
+ else:
+ continue
+
+ # 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 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 = [name.endswith('_') and name[:-1] or name
+ for name in fieldNames]
+ attrs.sort(lambda x, y: _compareAttrs(x, y, fieldNames))
+
+ return attrs
+
+ def hasSubDirectives(self):
+ return len(self.context) != 0
+
+ def getElements(self):
+ context = removeSecurityProxy(self.context)
+ return context.values()
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcmlfile_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser/zcmlfile_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcmlfile_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,47 @@
+<html>
+<head>
+ <style type="text/css" media="all">
+
+.directive {
+ font-family: monospace;
+ padding: 1px;
+ margin: 2px 0px;
+}
+
+.tagName {
+ color: darkred;
+}
+
+.attributeName {
+ color: blue;
+}
+
+.attributeValue {
+ color: darkgreen;
+}
+
+.commentElement {
+ font-family: monospace;
+ font-style: italic;
+ padding: 1px;
+ margin: 2px 0px;
+ color: darkblue;
+}
+
+.editElement {
+ background-color: EEEEEE;
+}
+
+.required {
+ font-weight: bold;
+ font-style: italic;
+}
+
+ </style>
+</head>
+<body>
+
+ <div tal:replace="structure context/@@display" />
+
+</body>
+</html>
\ No newline at end of file
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcmlfile_index.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/browser.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,752 +0,0 @@
-##############################################################################
-#
-# 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.
-#
-##############################################################################
-"""Class Documentation Module Views
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-import re
-from types import TypeType, ClassType, FunctionType, ModuleType
-import xml.dom.minidom
-import xml.sax.saxutils
-
-from zope.configuration import docutils, xmlconfig
-from zope.configuration.config import ConfigurationContext
-from zope.configuration.fields import GlobalObject, Tokens
-from zope.app.traversing.interfaces import TraversalError
-from zope.interface.interface import InterfaceClass
-from zope.proxy import removeAllProxies
-from zope.schema import getFieldsInOrder
-from zope.security.proxy import removeSecurityProxy
-
-import zope.app
-from zope.app import zapi
-from zope.app.i18n import ZopeMessageIDFactory as _
-from zope.app.apidoc.classmodule import Module, Class, Function, ZCMLFile
-from zope.app.apidoc.classmodule import classRegistry
-from zope.app.apidoc.interfaces import IDocumentationModule
-from zope.app.apidoc.utilities import getPythonPath, renderText, columnize
-from zope.app.apidoc.utilities import getPermissionIds, getFunctionSignature
-from zope.app.apidoc.utilities import getPublicAttributes
-from zope.app.apidoc.utilities import getInterfaceForAttribute
-from zope.app.apidoc.zcmlmodule import quoteNS
-
-
-class Menu(object):
- """Menu for the Class Documentation Module.
-
- The menu allows for looking for classes by partial names. See
- `findClasses()` for the simple search implementation.
- """
-
- def findClasses(self):
- """Find the classes that match a partial path.
-
- Examples::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from zope.app.apidoc.classmodule import Class
- >>> cm = zapi.getUtility(IDocumentationModule, 'Class')
- >>> mod = cm['zope']['app']['apidoc']['classmodule']['browser']
-
- Setup a couple of classes and register them.
-
- >>> class Foo(object):
- ... pass
- >>> mod._Module__children['Foo'] = Class(mod, 'Foo', Foo)
- >>> class Foo2(object):
- ... pass
- >>> mod._Module__children['Foo2'] = Class(mod, 'Foo2', Foo2)
- >>> class Blah(object):
- ... pass
- >>> mod._Module__children['Blah'] = Class(mod, 'Blah', Blah)
-
- Setup the view.
-
- >>> from zope.publisher.browser import TestRequest
- >>> menu = Menu()
- >>> menu.context = None
-
- Testing the method with various inputs.
-
- >>> menu.request = TestRequest(form={'path': 'Foo'})
- >>> info = menu.findClasses()
-
- >>> pprint(info)
- [[('path', 'zope.app.apidoc.classmodule.browser.Foo'),
- ('url',
- 'http://127.0.0.1/zope/app/apidoc/classmodule/browser/Foo')],
- [('path', 'zope.app.apidoc.classmodule.browser.Foo2'),
- ('url',
- 'http://127.0.0.1/zope/app/apidoc/classmodule/browser/Foo2')]]
-
- >>> menu.request = TestRequest(form={'path': 'o2'})
- >>> info = menu.findClasses()
- >>> pprint(info)
- [[('path', 'zope.app.apidoc.classmodule.browser.Foo2'),
- ('url',
- 'http://127.0.0.1/zope/app/apidoc/classmodule/browser/Foo2')]]
-
- >>> menu.request = TestRequest(form={'path': 'Blah'})
- >>> info = menu.findClasses()
- >>> pprint(info)
- [[('path', 'zope.app.apidoc.classmodule.browser.Blah'),
- ('url',
- 'http://127.0.0.1/zope/app/apidoc/classmodule/browser/Blah')]]
- """
- path = self.request.get('path', None)
- if path is None:
- return []
- classModule = zapi.getUtility(IDocumentationModule, "Class")
- results = []
- for p in classRegistry.keys():
- if p.find(path) >= 0:
- klass = zapi.traverse(classModule, p.replace('.', '/'))
- results.append(
- {'path': p,
- 'url': zapi.absoluteURL(klass, self.request)
- })
- results.sort(lambda x, y: cmp(x['path'], y['path']))
- return results
-
-
-_obj_attr_re = r'(?P<start><%s.*?%s=".*?)(?P<value>%s)(?P<end>".*?>)'
-_attrname_re = r'(?P<start><.*?%s.*?)(?P<attr>%s)(?P<end>=".*?".*?>)'
-directives = {}
-
-class ZCMLFileDetails(ConfigurationContext):
- """Represents the details of the ZCML file."""
-
- def __init__(self, context, request):
- self.context = context
- self.request = request
- # TODO: This is not the best way to do this. We really need to revisit
- # the entire implementation and move more to the ZCMLFile object.
- package = removeSecurityProxy(
- zapi.getParent(context))._Module__module
- # Keep track of the package that is used for relative paths
- self._package_stack = [package]
- # Keep track of completed actions, so none is executed twice
- self._done = []
- # Kepp track of the parent node, so that we know whether we deal with
- # a directive or sub-directive
- self._parent_node_info = None
-
- # See zope.configuration.config.ConfigurationContext
- # The package is used to resolve relative paths.
- package = property(lambda self: self._package_stack[-1])
-
- # All registered directives. The availability of directives depends on
- # whether we a re looking for a directive or a sub-directive.
- directives = property(lambda self: directives[self._parent_node_info])
-
- 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'
- """
- m = zapi.getUtility(IDocumentationModule, "Class")
- return zapi.absoluteURL(zapi.getParent(m), self.request)
-
- def getHTMLContents(self):
- """Return an HTML markup version of the ZCML file with links to other
- documentation modules."""
- if not directives:
- self._makeDocStructure()
- dom = xml.dom.minidom.parse(self.context.path)
- self.text = file(self.context.path, 'r').read()
- self.text = xml.sax.saxutils.escape(self.text)
- self.text = self.text.replace(' ', ' ')
- self.text = self.text.replace('\n', '<br />\n')
-
- # Link interface and other object references
- for node in dom.childNodes:
- self._linkObjectReferences(node)
-
- # Link ZCML directives
- for node in dom.childNodes:
- self._linkDirectives(node)
-
- # Color directive attributes
- for node in dom.childNodes:
- self._colorAttributeNames(node)
-
- # Color comments
- self._colorComments()
-
- return self.text
-
- def _colorComments(self):
- self.text = self.text.replace('<!--',
- '<span style="color: red"><!--')
- self.text = self.text.replace('-->',
- '--></span>')
-
- def _colorAttributeNames(self, node):
- if node.nodeType in (node.TEXT_NODE, node.COMMENT_NODE):
- return
-
- for attrName in node.attributes.keys():
- disc = ('color attribute name', node.tagName, attrName)
- if disc in self._done:
- continue
-
- expr = re.compile(_attrname_re %(node.tagName, attrName),
- re.DOTALL)
- self.text = re.sub(
- expr,
- r'\1<span class="attribute">\2</span>\3',
- self.text)
-
- self._done.append(disc)
-
- for child in node.childNodes:
- self._colorAttributeNames(child)
-
-
- def _linkDirectives(self, node):
- if node.nodeType in (node.TEXT_NODE, node.COMMENT_NODE):
- return
-
- if (node.tagName,) in self._done:
- return
-
- if node.namespaceURI in self.directives.keys() and \
- node.localName in self.directives[node.namespaceURI].keys():
- namespace = quoteNS(node.namespaceURI)
- else:
- namespace = 'ALL'
-
- self.text = self.text.replace(
- '<'+node.tagName,
- '<<a class="tagname" href="%s/ZCML/%s/%s/index.html">%s</a>' %(
- self.getBaseURL(), namespace, node.localName, node.tagName))
-
- self.text = self.text.replace(
- '</'+node.tagName+'>',
- '</<a class="tagname" '
- 'href="%s/ZCML/%s/%s/index.html">%s</a>>' %(
- self.getBaseURL(), namespace, node.localName, node.tagName))
-
- self._done.append((node.tagName,))
-
- for child in node.childNodes:
- self._linkDirectives(child)
-
-
- def _linkObjectReferences(self, node):
- if node.nodeType in (node.TEXT_NODE, node.COMMENT_NODE):
- return
-
- if node.localName == 'configure' and node.hasAttribute('package'):
- self._package_stack.push(
- self.resolve(node.getAttribute('package')))
-
- for child in node.childNodes:
- self._linkObjectReferences(child)
-
- namespace = self.directives.get(node.namespaceURI, self.directives[''])
- directive = namespace.get(node.localName)
- if directive is None:
- # Try global namespace
- directive = self.directives[''].get(node.localName)
-
- for name, field in getFieldsInOrder(directive[0]):
- if node.hasAttribute(name.strip('_')):
- self._evalField(field, node)
-
- if node.localName == 'configure' and node.hasAttribute('package'):
- self._package_stack.pop()
-
-
- def _evalField(self, field, node, attrName=None, dottedName=None):
- bound = field.bind(self)
- if attrName is None:
- attrName = field.getName().strip('_')
- if dottedName is None:
- dottedName = node.getAttribute(attrName)
-
- if isinstance(field, Tokens) and \
- isinstance(field.value_type, GlobalObject):
-
- tokens = [token.strip()
- for token in node.getAttribute(attrName).split(' \n\t')
- if token.strip() != '']
-
- for token in tokens:
- self._evalField(field.value_type, node, attrName, dottedName)
-
- if isinstance(field, GlobalObject):
- obj = bound.fromUnicode(dottedName)
- disc = (node.tagName, attrName, dottedName)
-
- if disc in self._done:
- return
-
- if isinstance(obj, InterfaceClass):
- expr = re.compile(_obj_attr_re %(
- node.tagName, attrName, dottedName.replace('.', r'\.')),
- re.DOTALL)
- path = obj.__module__ + '.' + obj.__name__
- self.text = re.sub(
- expr,
- r'\1<a class="objectref" '
- r'href="%s/Interface/%s/apiindex.html">\2</a>\3' %(
- self.getBaseURL(), path),
- self.text)
-
- elif isinstance(obj, (TypeType, ClassType, FunctionType)):
- expr = re.compile(_obj_attr_re %(
- node.tagName, attrName, dottedName.replace('.', r'\.')),
- re.DOTALL)
- path = (obj.__module__ + '.' + obj.__name__).replace('.', '/')
- self.text = re.sub(
- expr,
- r'\1<a class="objectref" '
- r'href="%s/Class/%s/index.html">\2</a>\3' %(
- self.getBaseURL(), path),
- self.text)
-
- elif isinstance(obj, ModuleType):
- expr = re.compile(_obj_attr_re %(
- node.tagName, attrName, dottedName.replace('.', r'\.')),
- re.DOTALL)
- path = obj.__name__.replace('.', '/')
- self.text = re.sub(
- expr,
- r'\1<a class="objectref" '
- r'href="%s/Class/%s/index.html">\2</a>\3' %(
- self.getBaseURL(), path),
- self.text)
-
- self._done.append(disc)
-
- def _makeDocStructure(self):
- # Some trivial caching
- global directives
- context = xmlconfig.file(
- zope.app.appsetup.appsetup.getConfigSource(),
- execute=False)
- namespaces, subdirs = docutils.makeDocStructures(context)
-
- for ns_name, dirs in namespaces.items():
- for dir_name, dir in dirs.items():
- parent = directives.setdefault(None, {})
- namespace = parent.setdefault(ns_name, {})
- namespace[dir_name] = dir
-
- for parent_info, dirs in subdirs.items():
- for dir in dirs:
- parent = directives.setdefault(parent_info, {})
- namespace = parent.setdefault(dir[0], {})
- namespace[dir[1]] = dir[2:]
-
-
-class FunctionDetails(object):
- """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'
- """
- 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')]
- """
- return [{'name': name,
- 'value': `attr`,
- 'type': type(attr).__name__,
- 'type_link': _getTypePath(type(attr)).replace('.', '/')}
-
- for name, attr in self.context.getAttributes()]
-
-
-class ClassDetails(object):
- """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'}]
- """
- 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())
- []
- """
- 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'}]
- """
- info = []
- classModule = zapi.getUtility(IDocumentationModule, "Class")
- for cls in classes:
- # We need to removeAllProxies because the security checkers for
- # zope.app.container.contained.ContainedProxy and
- # zope.app.i18n.messagecatalog.MessageCatalog prevent us from
- # accessing __name__ and __module__.
- unwrapped_cls = removeAllProxies(cls)
- path = getPythonPath(unwrapped_cls)
- try:
- klass = zapi.traverse(classModule, path.replace('.', '/'))
- url = zapi.absoluteURL(klass, self.request)
- except TraversalError:
- # If one of the classes is implemented in C, we will not
- # be able to find it.
- url = None
- info.append({'path': path, 'url': url})
- return info
-
-
- 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'
- """
- m = zapi.getUtility(IDocumentationModule, "Class")
- 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']
- """
- 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)]
- """
- attrs = []
- for name, attr, iface in self.context.getAttributes():
- entry = {'name': name,
- 'value': `attr`,
- 'type': type(attr).__name__,
- 'type_link': _getTypePath(type(attr)),
- 'interface': getPythonPath(iface)}
- # Since checkers do not have security declarations on their API,
- # we have to remove the security wrapper to get to the API calls.
- checker = self.context.getSecurityChecker()
- entry.update(
- getPermissionIds(name, removeSecurityProxy(checker)))
- attrs.append(entry)
- return attrs
-
-
- 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)]]
- """
- methods = []
- # remove the security proxy, so that `attr` is not proxied. We could
- # unproxy `attr` for each turn, but that would be less efficient.
- #
- # `getPermissionIds()` also expects the class's security checker not
- # to be proxied.
- klass = removeSecurityProxy(self.context)
- for name, attr, iface in klass.getMethods():
- entry = {'name': name,
- 'signature': getFunctionSignature(attr),
- 'doc': renderText(attr.__doc__ or '',
- zapi.getParent(self.context).getPath()),
- 'interface': getPythonPath(iface)}
- entry.update(getPermissionIds(name, klass.getSecurityChecker()))
- methods.append(entry)
- return methods
-
-
- 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>
- """
- return renderText(self.context.getDocString() or '',
- zapi.getParent(self.context).getPath())
-
-
-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>
- """
- text = self.context.getDocString()
- if text is None:
- return None
- lines = text.strip().split('\n')
- # Get rid of possible CVS id.
- lines = [line for line in lines if not line.startswith('$Id')]
- 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')]]
- """
- entries = [{'name': name,
- 'url': zapi.absoluteURL(obj, self.request),
- 'ismodule': zapi.isinstance(obj, Module),
- 'isclass': zapi.isinstance(obj, Class),
- 'isfunction': zapi.isinstance(obj, Function),
- 'iszcmlfile': zapi.isinstance(obj, ZCMLFile)}
- for name, obj in self.context.items()]
- entries.sort(lambda x, y: cmp(x['name'], y['name']))
- if columns:
- entries = columnize(entries)
- return entries
-
- def getBreadCrumbs(self):
- """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')]]
- """
- names = self.context.getPath().split('.')
- crumbs = []
- module = self.context
- # I really need the class here, so remove the proxy.
- while removeSecurityProxy(module).__class__ is Module:
- crumbs.append(
- {'name': zapi.name(module),
- 'url': zapi.absoluteURL(module, self.request)}
- )
- module = zapi.getParent(module)
-
- crumbs.append(
- {'name': _('[top]'),
- 'url': zapi.getMultiAdapter(
- (module, self.request), name='absolute_url')()} )
-
- crumbs.reverse()
- return crumbs
-
-
-def _getTypePath(type):
- """Return the path of the type.
-
- Here some examples::
-
- >>> class Foo(object):
- ... pass
-
- >>> _getTypePath(type(Foo()))
- 'zope.app.apidoc.classmodule.browser.Foo'
-
- >>> _getTypePath(type(3))
- '__builtin__.int'
- """
- path = getPythonPath(type)
- return path
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/class_.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,190 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Class representation for code browser
+
+$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+import inspect
+
+from zope.interface import implements, implementedBy
+from zope.security.checker import getCheckerForInstancesOf
+from zope.app.location.interfaces import ILocation
+
+from zope.app.apidoc.classregistry import classRegistry
+from zope.app.apidoc.utilities import getInterfaceForAttribute
+from zope.app.apidoc.utilities import getPublicAttributes
+from zope.app.apidoc.utilities import getPythonPath
+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)
+
+ """
+ implements(ILocation, IClassDocumentation)
+
+ def __init__(self, module, name, klass):
+ self.__parent__ = module
+ self.__name__ = name
+ self.__klass = klass
+
+ # Setup interfaces that are implemented by this class.
+ self.__interfaces = list(implementedBy(klass))
+ all_ifaces = {}
+ for iface in self.__interfaces:
+ all_ifaces[getPythonPath(iface)] = iface
+ for base in [base for base in iface.__bases__]:
+ all_ifaces[getPythonPath(base)] = base
+ self.__all_ifaces = all_ifaces.values()
+
+ # Register the class with the global class registry.
+ global classRegistry
+ classRegistry[self.getPath()] = klass
+
+ def getPath(self):
+ """See IClassDocumentation."""
+ return self.__parent__.getPath() + '.' + self.__name__
+
+ def getDocString(self):
+ """See IClassDocumentation."""
+ return self.__klass.__doc__
+
+ def getBases(self):
+ """See IClassDocumentation."""
+ return self.__klass.__bases__
+
+ def getKnownSubclasses(self):
+ """See IClassDocumentation."""
+ global classRegistry
+ return [k for n, k in classRegistry.getSubclassesOf(self.__klass)]
+
+ def getInterfaces(self):
+ """See IClassDocumentation."""
+ 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>)]
+ """
+ return [
+ (name, getattr(self.__klass, name),
+ getInterfaceForAttribute(name, self.__all_ifaces, asPath=False))
+
+ for name in getPublicAttributes(self.__klass)
+ 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>)]
+ """
+ return [
+ (name, getattr(self.__klass, name),
+ getInterfaceForAttribute(name, self.__all_ifaces, asPath=False))
+
+ for name in getPublicAttributes(self.__klass)
+ if inspect.ismethod(getattr(self.__klass, name))]
+
+ def getSecurityChecker(self):
+ """See IClassDocumentation."""
+ return getCheckerForInstancesOf(self.__klass)
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py
___________________________________________________________________
Name: svn:eol-style
+ native
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/class_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/class_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/class_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,175 +0,0 @@
-<html metal:use-macro="views/apidoc_macros/details">
-<body metal:fill-slot="contents">
-
- <h1 class="details-header"
- tal:content="context/getPath">
- zope.app.Klass
- </h1>
-
- <div class="indent">
- <div class="documentation" tal:content="structure view/getDoc">
- Here is the doc string
- </div>
- </div>
-
-
- <h2 class="details-section" i18n:translate="">Bases</h2>
-
- <div class="indent"
- tal:define="bases view/getBases">
-
- <ul class="attr-list" tal:condition="bases">
- <li tal:repeat="base bases">
- <a href=""
- tal:attributes="href string:${base/url}/index.html"
- tal:content="base/path"
- tal:condition="base/url" />
- <div tal:condition="not: base/url">
- <span tal:replace="base/path" />
- <span i18n:translate="">(C-based class)</span>
- </div>
- </li>
- </ul>
-
- <p tal:condition="not: bases">
- <em i18n:translate="">There are no base classes.</em>
- </p>
-
- </div>
-
- <h2 class="details-section" i18n:translate="">Implemented Interfaces</h2>
-
- <div class="indent"
- tal:define="ifaces view/getInterfaces">
-
- <ul class="attr-list" tal:condition="ifaces">
- <li tal:repeat="iface ifaces">
- <a href=""
- tal:attributes="href
- string:${view/getBaseURL}/Interface/$iface/apiindex.html"
- tal:content="iface" />
- </li>
- </ul>
-
- <p tal:condition="not: ifaces">
- <em i18n:translate="">There are no implemented interfaces.</em>
- </p>
-
- </div>
-
-
- <h2 class="details-section" i18n:translate="">Attributes/Properties</h2>
-
- <div class="indent"
- tal:define="attributes view/getAttributes">
-
- <ul class="attr-list" tal:condition="attributes">
-
- <li tal:repeat="attr attributes">
- <b><code tal:content="attr/name">attr</code></b>
- <tal:omit-tag condition="not: attr/type_link">
- (type: <code tal:content="attr/type" />)
- </tal:omit-tag>
- <tal:omit-tag condition="attr/type_link">
- (<span i18n:translate="">type:</span>
- <a href=""
- tal:attributes="href string:./index.html?path=${attr/type_link}">
- <code tal:content="attr/type" /></a>)
- </tal:omit-tag>
- <br/>
- <i i18n:translate="">Value:</i>
- <code tal:content="attr/value">u''</code><br />
-
- <span class="small" tal:condition="attr/interface">
- <i i18n:translate="">Interface:</i>
- <a href=""
- tal:attributes="href
- string:${view/getBaseURL}/Interface/${attr/interface}/apiindex.html"
- tal:content="attr/interface">Iface</a><br />
- </span>
- <span class="small"
- tal:condition="python: attr['read_perm'] and attr['write_perm']">
- <i i18n:translate="">Permissions:</i>
- <span tal:replace="attr/read_perm">zope.View</span>
- <span i18n:translate="">(read)</span>,
- <span tal:replace="attr/write_perm">zope.View</span>
- <span i18n:translate="">(write)</span>
- </span>
- </li>
-
- </ul>
-
- <p tal:condition="not: attributes">
- <em i18n:translate="">There are no attributes in this class.</em>
- </p>
-
- </div>
-
-
- <h2 class="details-section" i18n:translate="">Methods</h2>
-
- <div class="indent"
- tal:define="methods view/getMethods">
-
- <ul class="attr-list" tal:condition="methods">
-
- <li tal:repeat="method view/getMethods">
- <b><code
- tal:content="string:${method/name}${method/signature}" />
- </b><br>
- <div class="inline-documentation" tal:content="structure method/doc">
- method desc
- </div>
-
- <span class="small" tal:condition="method/interface">
- <i i18n:translate="">Interface:</i>
- <a href=""
- tal:attributes="href
- string:${view/getBaseURL}/Interface/${method/interface}/apiindex.html"
- tal:content="method/interface">Iface</a><br/>
- </span>
-
- <span class="small"
- tal:condition="python: method['read_perm'] and method['write_perm']">
- <i i18n:translate="">Permissions:</i>
- <span tal:replace="method/read_perm">zope.View</span>
- <span i18n:translate="">(read)</span>,
- <span tal:replace="method/write_perm">zope.View</span>
- <span i18n:translate="">(write)</span>
- </span>
- </li>
-
- </ul>
-
- <p tal:condition="not: methods">
- <em i18n:translate="">There are no methods in this class.</em>
- </p>
-
- </div>
-
- <h2 class="details-section" i18n:translate="">Known Subclasses</h2>
-
- <div class="indent"
- tal:define="subclasses view/getKnownSubclasses">
-
- <ul class="attr-list" tal:condition="subclasses">
- <li tal:repeat="cls subclasses">
- <a href=""
- tal:attributes="href string:${cls/url}/index.html"
- tal:content="cls/path"
- tal:condition="cls/url" />
- <div tal:condition="not: cls/url">
- <span tal:replace="cls/path" />
- <span i18n:translate="">(C-based class)</span>
- </div>
- </li>
- </ul>
-
- <p tal:condition="not: subclasses">
- <em i18n:translate="">There are no known subclasses.</em>
- </p>
-
- </div>
-
-</body>
-</html>
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/configure.zcml 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/configure.zcml 2005-02-23 22:22:48 UTC (rev 29269)
@@ -3,25 +3,29 @@
xmlns:apidoc="http://namespaces.zope.org/apidoc"
xmlns:browser="http://namespaces.zope.org/browser">
- <class class=".Module">
- <allow interface=".IModuleDocumentation" />
+ <class class=".module.Module">
+ <allow interface=".interfaces.IModuleDocumentation" />
</class>
- <class class=".Class">
- <allow interface=".IClassDocumentation" />
+ <class class=".class_.Class">
+ <allow interface=".interfaces.IClassDocumentation" />
</class>
- <class class=".Function">
- <allow interface=".IFunctionDocumentation" />
+ <class class=".function.Function">
+ <allow interface=".interfaces.IFunctionDocumentation" />
</class>
- <class class=".ZCMLFile">
- <allow interface=".IZCMLFileDocumentation" />
+ <class class=".zcml.Configuration">
+ <allow interface=".interfaces.IConfiguration" />
</class>
- <class class=".ClassModule">
- <allow interface="zope.app.apidoc.interfaces.IDocumentationModule" />
- <allow interface=".IModuleDocumentation" />
+ <class class=".text.TextFile">
+ <allow attributes="getContent path" />
+ </class>
+
+ <class class=".CodeModule">
+ <allow interface="..interfaces.IDocumentationModule" />
+ <allow interface=".interfaces.IModuleDocumentation" />
<allow attributes="rootModules" />
</class>
@@ -36,43 +40,10 @@
<apidoc:rootModule module="zope" />
<utility
- provides="zope.app.apidoc.interfaces.IDocumentationModule"
- factory=".ClassModule"
- name="Class" />
+ provides="..interfaces.IDocumentationModule"
+ factory=".CodeModule"
+ name="Code" />
- <browser:page
- for=".ClassModule"
- permission="zope.app.apidoc.UseAPIDoc"
- class=".browser.Menu"
- name="menu.html"
- template="menu.pt" />
+ <include package=".browser" />
- <browser:page
- for=".IModuleDocumentation"
- permission="zope.app.apidoc.UseAPIDoc"
- class=".browser.ModuleDetails"
- name="index.html"
- template="module_index.pt" />
-
- <browser:page
- for=".IClassDocumentation"
- permission="zope.app.apidoc.UseAPIDoc"
- class=".browser.ClassDetails"
- name="index.html"
- template="class_index.pt" />
-
- <browser:page
- for=".IFunctionDocumentation"
- permission="zope.app.apidoc.UseAPIDoc"
- class=".browser.FunctionDetails"
- name="index.html"
- template="function_index.pt" />
-
- <browser:page
- for=".IZCMLFileDocumentation"
- permission="zope.View"
- class=".browser.ZCMLFileDetails"
- name="index.html"
- template="zcmlfile_index.pt" />
-
</configure>
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/ftests.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/ftests.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -22,63 +22,63 @@
"""Just a couple of tests ensuring that the templates render."""
def testMenu(self):
- response = self.publish('/++apidoc++/Class/menu.html',
+ 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++/Class/menu.html',
+ self.checkForBrokenLinks(body, '/++apidoc++/Code/menu.html',
basic='mgr:mgrpw')
def testMenuClassFinder(self):
- response = self.publish('/++apidoc++/Class/menu.html',
+ response = self.publish('/++apidoc++/Code/menu.html',
basic='mgr:mgrpw',
- form={'path': 'Class', 'SUBMIT': 'Find'})
+ form={'path': 'Code', 'SUBMIT': 'Find'})
self.assertEqual(response.getStatus(), 200)
body = response.getBody()
- self.assert_(body.find('zope.app.apidoc.classmodule.ClassModule') > 0)
- self.checkForBrokenLinks(body, '/++apidoc++/Class/menu.html',
+ 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++/Class/zope/app/apidoc/',
+ 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++/Class/zope/app/apidoc/',
- basic='mgr:mgrpw')
+ self.checkForBrokenLinks(
+ body, '/++apidoc++/Code/zope/app/apidoc/apidoc', basic='mgr:mgrpw')
def testClassDetailsView(self):
response = self.publish(
- '/++apidoc++/Class/zope/app/apidoc/APIDocumentation',
+ '/++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++/Class/zope/app/apidoc/APIDocumentation',
+ body, '/++apidoc++/Code/zope/app/apidoc/apidoc/APIDocumentation',
basic='mgr:mgrpw')
def testFunctionDetailsView(self):
response = self.publish(
- '/++apidoc++/Class/zope/app/apidoc/handleNamespace',
+ '/++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++/Class/zope/app/apidoc/handleNamesapce',
+ body, '/++apidoc++/Code/zope/app/apidoc/apidoc/handleNamesapce',
basic='mgr:mgrpw')
def testZCMLFileDetailsView(self):
response = self.publish(
- '/++apidoc++/Class/zope/app/configure.zcml',
+ '/++apidoc++/Code/zope/app/apidoc/configure.zcml/index.html',
basic='mgr:mgrpw')
self.assertEqual(response.getStatus(), 200)
body = response.getBody()
self.checkForBrokenLinks(
- body, '/++apidoc++/Class/zope/app/configure.zcml',
+ body, '/++apidoc++/Code/zope/app/apidoc/configure.zcml/index.html',
basic='mgr:mgrpw')
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/function.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/function.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/function.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,98 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Function representation for code browser
+
+$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope.interface import implements
+from zope.app.location.interfaces import ILocation
+
+from zope.app.apidoc.utilities import getFunctionSignature
+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()
+ []
+ """
+ implements(ILocation, IFunctionDocumentation)
+
+ def __init__(self, module, name, func):
+ self.__parent__ = module
+ self.__name__ = name
+ self.__func = func
+
+ def getPath(self):
+ """See IFunctionDocumentation."""
+ return self.__parent__.getPath() + '.' + self.__name__
+
+ def getDocString(self):
+ """See IFunctionDocumentation."""
+ return self.__func.__doc__
+
+ def getSignature(self):
+ """See IFunctionDocumentation."""
+ 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')]
+ """
+ return self.__func.__dict__.items()
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/function.py
___________________________________________________________________
Name: svn:eol-style
+ native
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/function_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/function_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/function_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,61 +0,0 @@
-<html metal:use-macro="views/apidoc_macros/details">
-<body metal:fill-slot="contents">
-
- <h1 class="details-header"
- tal:content="context/getPath">
- zope.app.function
- </h1>
-
- <h2 class="details-section" i18n:translate="">Signature</h2>
-
- <div class="indent">
- <b><code
- tal:content="string:${context/zope:name}${context/getSignature}" />
- </b>
- </div>
-
- <div tal:condition="context/getDocString">
- <h2 class="details-section" i18n:translate="">Documentation String</h2>
-
- <div class="indent">
- <div class="documentation" tal:content="structure view/getDocString">
- Here is the doc string
- </div>
- </div>
- </div>
-
- <div
- tal:define="attributes view/getAttributes"
- tal:condition="attributes">
-
- <h2 class="details-section" i18n:translate="">Attributes</h2>
-
- <div class="indent">
-
- <ul class="attr-list">
-
- <li tal:repeat="attr attributes">
- <b><code tal:content="attr/name">attr</code></b>
- <tal:omit-tag condition="not: attr/type_link">
- (<span i18n:translate="">type:</span>
- <code tal:content="attr/type" />)
- </tal:omit-tag>
- <tal:omit-tag condition="attr/type_link">
- (<span i18n:translate="">type:</span>
- <a href=""
- tal:attributes="href
- string:${view/getBaseURL}/Class/${attr/type_link}/index.html">
- <code tal:content="attr/type" /></a>)
- </tal:omit-tag>
- <br/>
- <i i18n:translate="">Value:</i>
- <code tal:content="attr/value">u''</code><br />
- </li>
-
- </ul>
-
- </div>
- </div>
-
-</body>
-</html>
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/interfaces.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/interfaces.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,240 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Interfaces for code browser
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+from zope.interface import Interface
+from zope.schema import Field, BytesLine, Text
+
+from zope.app.container.interfaces import IContainer
+from zope.app.container.interfaces import IReadContainer
+from zope.app.i18n import ZopeMessageIDFactory as _
+
+
+class IModuleDocumentation(IReadContainer):
+ """Representation of a Python module for documentation.
+
+ The items of the container are sub-modules and classes.
+ """
+ def getDocString():
+ """Return the doc string of the module."""
+
+ def getFileName():
+ """Return the file name of the module."""
+
+ def getPath():
+ """Return the Python path of the module."""
+
+
+class IClassDocumentation(Interface):
+ """Representation of a class or type for documentation."""
+
+ def getDocString():
+ """Return the doc string of the class."""
+
+ def getPath():
+ """Return the Python path of the class."""
+
+ def getBases():
+ """Return the base classes of the class."""
+
+ def getKnownSubclasses():
+ """Return the known subclasses classes of the class."""
+
+ def getInterfaces():
+ """Return the interfaces the class implements."""
+
+ def getAttributes():
+ """Return a list of 3-tuple attribute information.
+
+ The first entry of the 3-tuple is the name of the attribute, the
+ second is the attribute object itself. The third entry is the
+ interface in which the attribute is defined.
+
+ Note that only public attributes are returned, meaning only attributes
+ that do not start with an '_'-character.
+ """
+
+ def getMethods():
+ """Return a list of 3-tuple method information.
+
+ The first entry of the 3-tuple is the name of the method, the
+ second is the method object itself. The third entry is the
+ interface in which the method is defined.
+
+ Note that only public methods are returned, meaning only methods
+ that do not start with an '_'-character.
+ """
+
+ def getSecurityChecker():
+ """Return the security checker for this class.
+
+ Since 99% of the time we are dealing with name-based security
+ checkers, we can look up the get/set permission required for a
+ particular class attribute/method.
+ """
+
+
+class IFunctionDocumentation(Interface):
+ """Representation of a function for documentation."""
+
+ def getDocString():
+ """Return the doc string of the function."""
+
+ def getPath():
+ """Return the Python path of the function."""
+
+ def getSignature():
+ """Return the signature of the function as a string."""
+
+ def getAttributes():
+ """Return a list of 2-tuple attribute information.
+
+ The first entry of the 2-tuple is the name of the attribute, the
+ second is the attribute object itself.
+ """
+
+
+class IElement(IContainer):
+ """Represents an XML Element in the ZCML Configuration File
+
+ 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.
+
+ The returned XML should be well formatted, including all correct
+ indentations and lines not being long than 80 characters, if possible.
+ """
+
+ def getElementType():
+ """Return the type of the DOM element.
+
+ Possible values are:
+
+ - ELEMENT_NODE (1): An XML tag. If an element is of this type it is a
+ standard ZCML directive or sub-directive.
+
+ - COMMENT_NODE (8): An XML comment. Comments are used to explain
+ features of the ZCML directives and are thus supported by the editor.
+
+ - 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.
+ """
+
+ 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."""
+
+ 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.
+
+ 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(
+ title=_('Configuration Filename'),
+ description=_('Path to the configuration file'),
+ required=True)
+
+ package = BytesLine(
+ title=_('Configuration Package'),
+ description=_(
+ '''Specifies the package from which the configuration file will be
+ executed. If you do not specify the package, then the configuration
+ cannot be fully validated and improper ZCML files might be written.'''),
+ 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():
+ """ """
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/interfaces.py
___________________________________________________________________
Name: svn:eol-style
+ native
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/menu.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/menu.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/menu.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,34 +0,0 @@
-<html metal:use-macro="views/apidoc_macros/menu">
-<body>
-
- <div metal:fill-slot="menu" class="small">
-
- <div tal:define="classes view/findClasses"
- tal:condition="classes">
-
- <a href="" target="main"
- tal:repeat="info classes"
- tal:attributes="href info/url"
- tal:content="info/path">
- /zope/app/Application
- </a>
- </div>
-
- <div>
- <span i18n:translate="">Class Finder:</span> <br/>
- <i i18n:translate="">(Enter partial Python path)</i></div>
- <form action="menu.html" method="post">
- <input type="text" name="path"
- style="font-size: 80%; width=95%" />
- <input type="submit" name="SUBMIT" value="Find"
- i18n:attributes="value find-button" style="font-size: 80%"/>
- </form>
-
- <p style="font-size: 120%">
- <a href="./index.html" target="main" i18n:translate="">Browse
- Zope Source</a>
- </p>
- </div>
-
-</body>
-</html>
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/metaconfigure.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/metaconfigure.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -18,7 +18,7 @@
__docformat__ = 'restructuredtext'
from zope.interface import implements
from zope.app.component.metaconfigure import utility
-from zope.app.apidoc.classmodule import IAPIDocRootModule
+from zope.app.apidoc.codemodule import IAPIDocRootModule
class RootModule(str):
implements(IAPIDocRootModule)
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/module.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/module.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/module.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,200 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Module representation for code browser
+
+$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+import os
+import types
+
+import zope
+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.apidoc.classregistry import safe_import
+from zope.app.apidoc.utilities import ReadContainerBase
+from interfaces import IModuleDocumentation
+
+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
+
+# 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']
+ """
+ implements(ILocation, IModuleDocumentation)
+
+ def __init__(self, parent, name, module, setup=True):
+ """Initialize object."""
+ self.__parent__ = parent
+ self.__name__ = name
+ self._module = module
+ self._children = {}
+ if setup:
+ self.__setup()
+
+ def __setup(self):
+ """Setup the module sub-tree."""
+ # Detect packages
+ if hasattr(self._module, '__file__') and \
+ (self._module.__file__.endswith('__init__.py') or
+ self._module.__file__.endswith('__init__.pyc')or
+ self._module.__file__.endswith('__init__.pyo')):
+ dir = os.path.dirname(self._module.__file__)
+ for file in os.listdir(dir):
+ if file in IGNORE_FILES:
+ continue
+ path = os.path.join(dir, file)
+
+ if os.path.isdir(path) and '__init__.py' in os.listdir(path):
+ fullname = self._module.__name__ + '.' + file
+ module = safe_import(fullname)
+ if module is not None:
+ self._children[file] = Module(self, file, module)
+
+ elif os.path.isfile(path) and file.endswith('.py') and \
+ not file.startswith('__init__'):
+ name = file[:-3]
+ fullname = self._module.__name__ + '.' + name
+ module = safe_import(fullname)
+ if module is not None:
+ 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)
+
+ elif os.path.isfile(path) and file.endswith('.txt'):
+ self._children[file] = TextFile(path, file, self)
+
+ # Setup classes in module, if any are available.
+ zope.deprecation.__show__.off()
+ for name in self._module.__dict__.keys():
+ attr = getattr(self._module, name)
+ # We do not want to register duplicates or instances
+ if hasattr(attr, '__module__') and \
+ attr.__module__ == self._module.__name__:
+
+ if not hasattr(attr, '__name__') or \
+ attr.__name__ != name or \
+ name.startswith('_'):
+ continue
+
+ 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)
+
+ elif type(attr) is types.FunctionType:
+ self._children[name] = Function(self, name, attr)
+
+ zope.deprecation.__show__.on()
+
+
+ def getDocString(self):
+ """See IModule."""
+ return self._module.__doc__
+
+ def getFileName(self):
+ """See IModule."""
+ return self._module.__file__
+
+ def getPath(self):
+ """See IModule."""
+ return self._module.__name__
+
+ def get(self, key, default=None):
+ """See zope.app.container.interfaces.IReadContainer."""
+ obj = self._children.get(key, default)
+ if obj is not default:
+ return obj
+
+ # We are actually able to find much more than we promise
+ if self.getPath():
+ path = self.getPath() + '.' + key
+ else:
+ path = key
+ obj = safe_import(path)
+ if obj is not None:
+ return Module(self, key, obj)
+
+ return default
+
+ def items(self):
+ """See zope.app.container.interfaces.IReadContainer."""
+ return self._children.items()
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/module.py
___________________________________________________________________
Name: svn:eol-style
+ native
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/module_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/module_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/module_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,49 +0,0 @@
-<html metal:use-macro="views/apidoc_macros/details">
-<body metal:fill-slot="contents">
-
- <h1 class="details-header" i18n:translate="">Zope 3 Class Browser</h1>
-
- <p class="breadcrumbs">
- <span tal:repeat="entry view/getBreadCrumbs">
- <a href=""
- tal:attributes="href string:${entry/url}/index.html"
- tal:content="entry/name" />
- <tal:omit-tag condition="not: repeat/entry/end">/</tal:omit-tag>
- </span>
- </p>
-
- <div class="highlight"
- tal:define="doc view/getDoc"
- tal:condition="doc"
- tal:content="structure doc">
- Module Documentation
- </div>
-
-
- <table width="100%" valign="top"><tr>
-
- <td tal:repeat="column view/getEntries"><ul>
- <li tal:repeat="entry column">
- <a href=""
- tal:condition="entry/ismodule"
- tal:attributes="href string:./${entry/name}/index.html"
- tal:content="entry/name" />
- <a href=""
- tal:condition="entry/isclass"
- tal:attributes="href string:./${entry/name}/index.html"
- tal:content="structure string:<b>${entry/name}</b>" />
- <a href=""
- tal:condition="entry/isfunction"
- tal:attributes="href string:./${entry/name}/index.html"
- tal:content="structure string:<i>${entry/name}</i>" />
- <a href=""
- tal:condition="entry/iszcmlfile"
- tal:attributes="href string:./${entry/name}/index.html"
- tal:content="structure string:<i>${entry/name}</i>" />
- </li>
- </ul></td>
-
- </tr></table>
-
-</body>
-</html>
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/tests.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/tests.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Tests for the Class Documentation Module
+"""Tests for the Code Documentation Module
$Id$
"""
@@ -39,9 +39,10 @@
from zope.app.traversing.adapters import RootPhysicallyLocatable
from zope.app.traversing.adapters import Traverser
-from zope.app.apidoc.classmodule import ClassModule, IAPIDocRootModule
-from zope.app.apidoc.classmodule.browser import ClassDetails, ModuleDetails
-from zope.app.apidoc.classmodule.browser import FunctionDetails
+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
@@ -52,10 +53,10 @@
implements(IAPIDocRootModule)
ztapi.provideUtility(IAPIDocRootModule, RootModule('zope'), "zope")
- module = ClassModule()
+ module = CodeModule()
module.__name__ = ''
directlyProvides(module, IContainmentRoot)
- ztapi.provideUtility(IDocumentationModule, module, "Class")
+ ztapi.provideUtility(IDocumentationModule, module, "Code")
ztapi.provideAdapter(
None, ITraverser, Traverser)
@@ -86,25 +87,25 @@
def getFunctionDetailsView():
- cm = zapi.getUtility(IDocumentationModule, 'Class')
+ cm = zapi.getUtility(IDocumentationModule, 'Code')
view = FunctionDetails()
- view.context = zapi.traverse(cm, 'zope/app/apidoc/classmodule/tests/foo')
+ view.context = zapi.traverse(cm, 'zope/app/apidoc/codemodule/tests/foo')
view.request = TestRequest()
return view
def getClassDetailsView():
- cm = zapi.getUtility(IDocumentationModule, 'Class')
- view = ClassDetails()
- view.context = zapi.traverse(cm, 'zope/app/apidoc/classmodule/ClassModule')
+ 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, 'Class')
+ cm = zapi.getUtility(IDocumentationModule, 'Code')
view = ModuleDetails()
- view.context = zapi.traverse(cm, 'zope/app/apidoc/classmodule')
+ view.context = zapi.traverse(cm, 'zope/app/apidoc/codemodule')
view.request = TestRequest()
return view
@@ -119,8 +120,8 @@
def setUp(self):
super(DirectivesTest, self).setUp()
- import zope.app.apidoc.classmodule
- self.context = xmlconfig.file('meta.zcml', zope.app.apidoc.classmodule)
+ 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)
@@ -133,10 +134,11 @@
def test_suite():
return unittest.TestSuite((
- DocTestSuite('zope.app.apidoc.classmodule.browser',
+ # 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),
- DocTestSuite('zope.app.apidoc.classmodule',
- setUp=setUp, tearDown=placelesssetup.tearDown),
unittest.makeSuite(DirectivesTest),
))
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/text.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/text.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/text.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,35 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Function representation for code browser
+
+$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+from zope.interface import implements
+from zope.app.location.interfaces import ILocation
+
+class TextFile(object):
+ """This class represents a function declared in the module."""
+ implements(ILocation)
+
+ def __init__(self, path, name, package):
+ self.path = path
+ self.__parent__ = package
+ self.__name__ = name
+
+ def getContent(self):
+ file = open(self.path, 'r')
+ content = file.read()
+ file.close()
+ return content
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/text.py
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/zcml.py 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,246 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Configuration File Representation
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+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
+
+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
+
+context = None
+def getContext():
+ global context
+ if context is None:
+ context = xmlconfig.file(zope.app.appsetup.appsetup.getConfigSource(),
+ execute=False)
+ return context
+
+
+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 _getSubElement(self, dom, index):
+ """Helper method to create new element."""
+ element = Element(dom)
+ locate(element, self, unicode(index))
+ return element
+
+ def get(self, key, default=None):
+ """See zope.app.container.interfaces.IReadContainer"""
+ try:
+ return self[key]
+ except KeyError:
+ return default
+
+ 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]
+
+ def values(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ return [self[key] for key in self.keys()]
+
+ def items(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ return [(key, self[key]) for key in self.keys()]
+
+ 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 __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):
+ """ """
+ 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 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)]
+
+
+class Configuration(Directive):
+ """Cofiguration Object"""
+ implements(IConfiguration)
+
+ 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 parse(self):
+ """See configeditor.interfaces.IConfiguration"""
+ return minidom.parse(self.filename).getElementsByTagName('configure')[0]
+
+ 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
+
+ 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
+
+ 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
+
+ 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
Property changes on: Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py
___________________________________________________________________
Name: svn:eol-style
+ native
Deleted: Zope3/trunk/src/zope/app/apidoc/codemodule/zcmlfile_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classmodule/zcmlfile_index.pt 2005-02-19 02:03:28 UTC (rev 29222)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/zcmlfile_index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,15 +0,0 @@
-<html metal:use-macro="views/apidoc_macros/details">
-<body metal:fill-slot="contents">
-
- <h1 class="details-header"
- tal:content="context/path">
- zope.app.Klass
- </h1>
-
- <code class="zcml" tal:content="structure view/getHTMLContents">
- <configure> </configure>
- </code>
-
-
-</body>
-</html>
Added: Zope3/trunk/src/zope/app/apidoc/component.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/component.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/component.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,207 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Component Inspection Utilities
+
+$Id: browser.py 29199 2005-02-17 22:38:55Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+import types
+
+from zope.component.interfaces import IFactory
+from zope.component.site import AdapterRegistration, UtilityRegistration
+from zope.interface import Interface
+from zope.publisher.interfaces import IRequest
+
+from zope.app import zapi
+from zope.app.apidoc.utilities import getPythonPath, relativizePath
+from zope.app.apidoc.utilities import renderText
+from zope.app.apidoc.classregistry import classRegistry
+
+SPECIFIC_INTERFACE_LEVEL = 1
+EXTENDED_INTERFACE_LEVEL = 2
+GENERIC_INTERFACE_LEVEL = 4
+
+def getRequiredAdapters(iface, withViews=False):
+ """Get adapter registrations where the specified interface is required."""
+ gsm = zapi.getGlobalSiteManager()
+ for reg in gsm.registrations():
+ # Only get adapters
+ if not isinstance(reg, AdapterRegistration):
+ continue
+ # Ignore views
+ if not withViews and reg.required[-1] and \
+ reg.required[-1].isOrExtends(IRequest):
+ continue
+ # Only get the adapters for which this interface is required
+ for required_iface in reg.required:
+ if iface.isOrExtends(required_iface):
+ yield reg
+
+
+def getProvidedAdapters(iface, withViews=False):
+ """Get adapter registrations where this interface is provided."""
+ gsm = zapi.getGlobalSiteManager()
+ for reg in gsm.registrations():
+ # Only get adapters
+ if not isinstance(reg, AdapterRegistration):
+ continue
+ # Ignore views
+ if not withViews and reg.required[-1] and \
+ reg.required[-1].isOrExtends(IRequest):
+ continue
+ # Only get adapters for which this interface is provided
+ if not reg.provided.isOrExtends(iface):
+ continue
+ yield reg
+
+
+def filterAdapterRegistrations(regs, iface, level=SPECIFIC_INTERFACE_LEVEL):
+ """Return only those registrations that match the specifed level"""
+ for reg in regs:
+ if level & GENERIC_INTERFACE_LEVEL:
+ for required_iface in reg.required:
+ if required_iface in (Interface, None):
+ yield reg
+ continue
+
+ if level & EXTENDED_INTERFACE_LEVEL:
+ for required_iface in reg.required:
+ if required_iface is not Interface and \
+ iface.extends(required_iface):
+ yield reg
+ continue
+
+ if level & SPECIFIC_INTERFACE_LEVEL:
+ for required_iface in reg.required:
+ if required_iface is iface:
+ yield reg
+ continue
+
+
+def getClasses(iface):
+ """Get the classes that implement this interface."""
+ return classRegistry.getClassesThatImplement(iface)
+
+
+def getFactories(iface):
+ """Return the factory registrations, who will return objects providing this
+ interface."""
+ gsm = zapi.getGlobalSiteManager()
+ for reg in gsm.registrations():
+ if not isinstance(reg, UtilityRegistration):
+ continue
+ if reg.provided is not IFactory:
+ continue
+ interfaces = reg.component.getInterfaces()
+ try:
+ if interfaces.isOrExtends(iface):
+ yield reg
+ except AttributeError:
+ for interface in interfaces:
+ if interface.isOrExtends(iface):
+ yield reg
+ break
+
+
+def getUtilities(iface):
+ """Return all utility registrations that provide the interface."""
+ gsm = zapi.getGlobalSiteManager()
+ for reg in gsm.registrations():
+ if not isinstance(reg, UtilityRegistration):
+ continue
+ if reg.provided.isOrExtends(iface):
+ yield reg
+
+
+def getRealFactory(factory):
+ """Get the real factory.
+
+ Sometimes the original factory is masked by functions. If the function
+ keeps track of the original factory, use it.
+ """
+ if isinstance(factory, types.FunctionType) and hasattr(factory, 'factory'):
+ return factory.factory
+ return factory
+
+
+def getParserInfoInfoDictionary(info):
+ """Return a PT-friendly info dictionary for a parser info object."""
+ return {'file': relativizePath(info.file),
+ 'url': relativizePath(info.file)[10:],
+ 'line': info.line,
+ 'eline': info.eline,
+ 'column': info.column,
+ 'ecolumn': info.ecolumn}
+
+
+def getInterfaceInfoDictionary(iface):
+ """Return a PT-friendly info dictionary for an interface."""
+ return {'module': iface.__module__, 'name': iface.getName()}
+
+
+def getAdapterInfoDictionary(reg):
+ """Return a PT-friendly info dictionary for an adapter registration."""
+ factory = getRealFactory(reg.value)
+ path = getPythonPath(factory)
+ if isinstance(factory, types.MethodType):
+ url = None
+ else:
+ url = path.replace('.', '/')
+ if isinstance(reg.doc, (str, unicode)):
+ doc = reg.doc
+ zcml = None
+ else:
+ doc = None
+ zcml = getParserInfoInfoDictionary(reg.doc)
+
+ return {
+ 'provided': getInterfaceInfoDictionary(reg.provided),
+ 'required': [getInterfaceInfoDictionary(iface)
+ for iface in reg.required
+ if iface is not None],
+ 'name': getattr(reg, 'name', None),
+ 'factory': path,
+ 'factory_url': url,
+ 'doc': doc,
+ 'zcml': zcml}
+
+
+def getFactoryInfoDictionary(reg):
+ """Return a PT-friendly info dictionary for a factory."""
+ factory = reg.component
+ if type(factory) in (types.ClassType, types.TypeType):
+ klass = factory
+ else:
+ klass = factory.__class__
+ path = getPythonPath(klass)
+
+ return {'name': reg.name or '<i>no name</i>',
+ 'title': getattr(factory, 'title', u''),
+ 'description': renderText(getattr(factory, 'description', u''),
+ module=klass.__module__),
+ 'url': path.replace('.', '/')}
+
+
+def getUtilityInfoDictionary(reg):
+ """Return a PT-friendly info dictionary for a factory."""
+ if type(reg.component) in (types.ClassType, types.TypeType):
+ klass = reg.component
+ else:
+ klass = reg.component.__class__
+
+ path = getPythonPath(klass)
+ return {'name': reg.name or '<i>no name</i>',
+ 'url_name': reg.name or '__noname__',
+ 'path': path,
+ 'url': path.replace('.', '/')}
Added: Zope3/trunk/src/zope/app/apidoc/component.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/component.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/component.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,265 @@
+==============================
+Component Inspection Utilities
+==============================
+
+Once you have an interface, you really want to discover on how this interface
+interacts with other components in Zope 3. The functions in
+
+ >>> from zope.app.apidoc import component
+
+provide you with utilities to make those discoveries. The functions are
+explained in detail in this document. Before we start though, we have to have
+some interfaces to work with:
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface):
+ ... pass
+
+ >>> class IBar(Interface):
+ ... pass
+
+ >>> class IFooBar(IFoo, IBar):
+ ... pass
+
+ >>> class IResult(Interface):
+ ... pass
+
+ >>> class ISpecialResult(IResult):
+ ... pass
+
+
+`getRequiredAdapters(iface, withViews=False)`
+---------------------------------------------
+
+This function returns adapter registrations for adapters that require the
+specified interface. So let's create some adapter registrations:
+
+ >>> from zope.publisher.interfaces import IRequest
+ >>> from zope.app.testing import ztapi
+ >>> ztapi.provideAdapter((IFoo,), IResult, None)
+ >>> ztapi.provideAdapter((IFoo, IBar), ISpecialResult, None)
+ >>> ztapi.provideAdapter((IFoo, IRequest), ISpecialResult, None)
+
+ >>> regs = list(component.getRequiredAdapters(IFoo))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('IFoo', 'IBar'), 'ISpecialResult', '', None, ''),
+ AdapterRegistration(('IFoo',), 'IResult', '', None, '')]
+
+Note how the adapter requiring an `IRequest` at the end of the required
+interfaces is neglected. This is because it is recognized as a view and views
+are not returned by default. But you can simply turn this flag on:
+
+ >>> regs = list(component.getRequiredAdapters(IFoo, withViews=True))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('IFoo', 'IBar'), 'ISpecialResult', '', None, ''),
+ AdapterRegistration(('IFoo', 'IRequest'), 'ISpecialResult', '', None, ''),
+ AdapterRegistration(('IFoo',), 'IResult', '', None, '')]
+
+The function will also pick up registrations that have required interfaces the
+specified interface extends:
+
+ >>> regs = list(component.getRequiredAdapters(IFoo))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('IFoo', 'IBar'), 'ISpecialResult', '', None, ''),
+ AdapterRegistration(('IFoo',), 'IResult', '', None, '')]
+
+And all of the required interfaces are considered, of course:
+
+ >>> regs = list(component.getRequiredAdapters(IBar))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('IFoo', 'IBar'), 'ISpecialResult', '', None, '')]
+
+
+`getProvidedAdapters(iface, withViews=False)`
+---------------------------------------------
+
+Of course, we are also interested in the adapters that provide a certain
+interface. This function returns those adapter registrations, again ignoring
+views by default.
+
+ >>> regs = list(component.getProvidedAdapters(ISpecialResult))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('IFoo', 'IBar'), 'ISpecialResult', '', None, '')]
+
+And by specifying the `withView` flag, we get views as well:
+
+ >>> regs = list(component.getProvidedAdapters(ISpecialResult, withViews=True))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('IFoo', 'IBar'), 'ISpecialResult', '', None, ''),
+ AdapterRegistration(('IFoo', 'IRequest'), 'ISpecialResult', '', None, '')]
+
+We can of course also ask for adapters specifying `IResult`:
+
+ >>> regs = list(component.getProvidedAdapters(IResult, withViews=True))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('IFoo', 'IBar'), 'ISpecialResult', '', None, ''),
+ AdapterRegistration(('IFoo', 'IRequest'), 'ISpecialResult', '', None, ''),
+ AdapterRegistration(('IFoo',), 'IResult', '', None, '')]
+
+
+`getClasses(iface)`
+-------------------
+
+This package comes with a little tool called the class registry
+(see `classregistry.txt`). It provides a dictionary of all classes in the
+visible packages. This function utilizes the registry to retrieve all classes
+that implement the specified interface.
+
+Let's start by creating and registering some classes:
+
+ >>> from zope.interface import implements
+ >>> from zope.app.apidoc.classregistry import classRegistry
+
+ >>> class MyFoo(object):
+ ... implements(IFoo)
+ >>> classRegistry['MyFoo'] = MyFoo
+
+ >>> class MyBar(object):
+ ... implements(IBar)
+ >>> classRegistry['MyBar'] = MyBar
+
+ >>> class MyFooBar(object):
+ ... implements(IFooBar)
+ >>> classRegistry['MyFooBar'] = MyFooBar
+
+Let's now see whether what results we get:
+
+ >>> classes = component.getClasses(IFooBar)
+ >>> classes.sort()
+ >>> classes
+ [('MyFooBar', <class 'MyFooBar'>)]
+
+ >>> classes = component.getClasses(IFoo)
+ >>> classes.sort()
+ >>> classes
+ [('MyFoo', <class 'MyFoo'>), ('MyFooBar', <class 'MyFooBar'>)]
+
+
+`getFactories(ifaces)`
+----------------------
+
+Return the factory registrations of the factories that will return objects
+providing this interface.
+
+Again, the first step is to create some factories:
+
+ >>> from zope.component.factory import Factory
+ >>> from zope.component.interfaces import IFactory
+ >>> ztapi.provideUtility(IFactory, Factory(MyFoo), 'MyFoo')
+ >>> ztapi.provideUtility(IFactory, Factory(MyBar), 'MyBar')
+ >>> ztapi.provideUtility(IFactory,
+ ... Factory(MyFooBar, 'MyFooBar', 'My Foo Bar'), 'MyFooBar')
+
+Let's see whether we will be able to get them:
+
+ >>> regs = list(component.getFactories(IFooBar))
+ >>> regs.sort()
+ >>> regs
+ [UtilityRegistration('IFactory', 'MyFooBar',
+ <Factory for <class 'MyFooBar'>>, '')]
+
+ >>> regs = list(component.getFactories(IFoo))
+ >>> regs.sort()
+ >>> regs
+ [UtilityRegistration('IFactory', 'MyFoo',
+ <Factory for <class 'MyFoo'>>, ''),
+ UtilityRegistration('IFactory', 'MyFooBar',
+ <Factory for <class 'MyFooBar'>>, '')]
+
+
+`getUtilities(iface)`
+---------------------
+
+Return all utility registrations for utilities that provide the specified
+interface.
+
+As usual, we have to register some utilities first:
+
+ >>> ztapi.provideUtility(IFoo, MyFoo())
+ >>> ztapi.provideUtility(IBar, MyBar())
+ >>> ztapi.provideUtility(IFooBar, MyFooBar())
+
+Now let's have a look what we have:
+
+ >>> regs = list(component.getUtilities(IFooBar))
+ >>> regs.sort()
+ >>> regs #doctest:+ELLIPSIS
+ [UtilityRegistration('IFooBar', '', <MyFooBar object at ...>, '')]
+
+ >>> regs = list(component.getUtilities(IFoo))
+ >>> regs.sort()
+ >>> regs #doctest:+ELLIPSIS
+ [UtilityRegistration('IFoo', '', <MyFoo object at ...>, ''),
+ UtilityRegistration('IFooBar', '', <MyFooBar object at ...>, '')]
+
+
+`getAdapterInfoDictionary(reg)`
+-------------------------------
+
+
+This function returns a page-template-friendly dictionary representing the
+data of an adapter registration in an output-friendly format.
+
+Let's first create an adapter registration:
+
+ >>> class MyResult(object):
+ ... implements(IResult)
+
+ >>> from zope.component.site import AdapterRegistration
+ >>> reg = AdapterRegistration((IFoo, IBar), IResult, 'FooToResult',
+ ... MyResult, 'doc info')
+
+And now get the info dictionary:
+
+ >>> pprint(component.getAdapterInfoDictionary(reg))
+ {'doc': 'doc info',
+ 'factory': '__builtin__.MyResult',
+ 'factory_url': '__builtin__/MyResult',
+ 'name': 'FooToResult',
+ 'provided': {'module': '__builtin__',
+ 'name': 'IResult'},
+ 'required': [{'module': '__builtin__',
+ 'name': 'IFoo'},
+ {'module': '__builtin__',
+ 'name': 'IBar'}],
+ 'zcml': None}
+
+`getFactoryInfoDictionary(reg)`
+-------------------------------
+
+This function returns a page-template-friendly dictionary representing the
+data of a factory (utility) registration in an output-friendly format.
+
+Luckily we have already registered some factories, so we just reuse their
+registrations:
+
+ >>> pprint(component.getFactoryInfoDictionary(
+ ... component.getFactories(IFooBar).next()))
+ {'description': u'<div class="document">\nMy Foo Bar</div>\n',
+ 'name': 'MyFooBar',
+ 'title': 'MyFooBar',
+ 'url': 'zope/component/factory/Factory'}
+
+
+`getUtilityInfoDictionary(name, factory)`
+-----------------------------------------
+
+This function returns a page-template-friendly dictionary representing the
+data of a utility registration in an output-friendly format.
+
+Luckily we have already registered some utilities, so we just reuse their
+registrations:
+
+ >>> pprint(component.getUtilityInfoDictionary(
+ ... component.getUtilities(IFooBar).next()))
+ {'name': '<i>no name</i>',
+ 'path': '__builtin__.MyFooBar',
+ 'url': '__builtin__/MyFooBar',
+ 'url_name': '__noname__'}
\ No newline at end of file
Modified: Zope3/trunk/src/zope/app/apidoc/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/configure.zcml 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/configure.zcml 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,5 +1,6 @@
<configure
xmlns="http://namespaces.zope.org/zope"
+ xmlns:apidoc="http://namespaces.zope.org/apidoc"
i18n_domain="zope">
<permission
@@ -7,7 +8,7 @@
title="[zope.app.apidoc.UseAPIDoc] Access Online API documentation"
/>
- <class class=".APIDocumentation">
+ <class class=".apidoc.APIDocumentation">
<require
interface="zope.app.container.interfaces.IReadContainer"
permission="zope.ManageApplication"
@@ -17,23 +18,59 @@
<view
name="apidoc" type="*"
provides="zope.app.traversing.interfaces.ITraversable" for="*"
- factory=".apidocNamespace"
+ factory=".apidoc.apidocNamespace"
/>
<adapter
name="apidoc"
provides="zope.app.traversing.interfaces.ITraversable" for="*"
- factory=".apidocNamespace"
+ factory=".apidoc.apidocNamespace"
/>
+ <!-- Register Public API Dcoumentation -->
+
+ <apidoc:bookchapter
+ id="inspect"
+ title="Inspection API"
+ />
+ <apidoc:bookchapter
+ id="interface"
+ title="Interfaces"
+ doc_path="interface.txt"
+ parent="inspect"
+ />
+ <apidoc:bookchapter
+ id="component"
+ title="Components"
+ doc_path="component.txt"
+ parent="inspect"
+ />
+ <apidoc:bookchapter
+ id="presentation"
+ title="Presentation"
+ doc_path="presentation.txt"
+ parent="inspect"
+ />
+ <apidoc:bookchapter
+ id="misc"
+ title="Miscellaneous"
+ doc_path="utilities.txt"
+ parent="inspect"
+ />
+ <apidoc:bookchapter
+ id="classregistry"
+ title="Class Registry"
+ doc_path="classregistry.txt"
+ parent="inspect"
+ />
+
<include package=".browser" />
<!-- API Documentation Modules -->
<include package=".bookmodule" />
- <include package=".classmodule" />
+ <include package=".codemodule" />
<include package=".ifacemodule" />
<include package=".typemodule" />
<include package=".utilitymodule" />
- <include package=".viewmodule" />
<include package=".zcmlmodule" />
</configure>
Added: Zope3/trunk/src/zope/app/apidoc/ifacemodule/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/README.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/README.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,42 @@
+==================================
+The Interface Documentation Module
+==================================
+
+This documentation module allows you to inspect all aspects of an interface
+and its role within the Zope 3 framework. The module can be instantiated like
+all other documentation modules:
+
+ >>> from zope.app.apidoc.ifacemodule.ifacemodule import InterfaceModule
+ >>> module = InterfaceModule()
+
+After registering an interface
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface):
+ ... pass
+
+ >>> from zope.app.component.interface import provideInterface
+ >>> provideInterface(None, IFoo)
+ >>> provideInterface('IFoo', IFoo)
+
+Now let's lookup an interface that is registered.
+
+ >>> module.get('IFoo')
+ <InterfaceClass __builtin__.IFoo>
+
+ >>> module.get('__builtin__.IFoo')
+ <InterfaceClass __builtin__.IFoo>
+
+
+Now we find an interface that is not in the site manager, but exists.
+
+ >>> module.get('zope.app.apidoc.interfaces.IDocumentationModule')
+ <InterfaceClass zope.app.apidoc.interfaces.IDocumentationModule>
+
+Finally, you can list all registered interfaces:
+
+ >>> ifaces = module.items()
+ >>> ifaces.sort()
+ >>> pprint(ifaces)
+ [(u'IFoo', <InterfaceClass __builtin__.IFoo>),
+ (u'__builtin__.IFoo', <InterfaceClass __builtin__.IFoo>)]
Property changes on: Zope3/trunk/src/zope/app/apidoc/ifacemodule/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/__init__.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/__init__.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,113 +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.
-#
-##############################################################################
-"""Interface Documentation Module
-
-The interface documentation module retrieves its information from the
-site manager. Therefore, currently there are no unregsitered interfaces
-listed in the documentation. This might be good, since unregistered interfaces
-are usually private and not of interest to a general developer.
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-from zope.app import zapi
-from zope.interface import implements
-from zope.app.apidoc.interfaces import IDocumentationModule
-from zope.app.apidoc.utilities import ReadContainerBase
-from zope.app.location import LocationProxy
-from zope.app.component.interface \
- import queryInterface, searchInterfaceUtilities
-from zope.app.i18n import ZopeMessageIDFactory as _
-
-class IInterfaceModule(IDocumentationModule):
- """Interface API Documentation Module
-
- This is a marker interface, so that we can write adapters for objects
- implementing this interface.
- """
-
-class InterfaceModule(ReadContainerBase):
- r"""Represent the Documentation of all Interfaces.
-
- This documentation is implemented using a simple `IReadContainer`. The
- items of the container are all the interfaces listed in the closest
- site manager and above.
-
- Demonstration::
-
- >>> module = InterfaceModule()
-
- Lookup an interface that is registered.
-
- >>> module.get('IInterfaceModule').getName()
- 'IInterfaceModule'
-
- >>> id = 'zope.app.apidoc.interfaces.IDocumentationModule'
- >>> module.get(id).getName()
- 'IDocumentationModule'
-
- Here we find an interface that is not in the site manager, but exists.
-
- >>> module.get('zope.app.content.interfaces.IContentType').getName()
- 'IContentType'
-
- >>> print '\n'.join([id for id, iface in module.items()])
- IInterfaceModule
- zope.app.apidoc.interfaces.IDocumentationModule
- """
-
- implements(IInterfaceModule)
-
- # See zope.app.apidoc.interfaces.IDocumentationModule
- title = _('Interfaces')
-
- # See zope.app.apidoc.interfaces.IDocumentationModule
- description = _("""
- All used and important interfaces are registered through the site
- manager. While it would be possible to just list all attributes, it is
- hard on the user to read such an overfull list. Therefore, interfaces that
- have partial common module paths are bound together.
-
- The documentation of an interface also provides a wide variety of
- information, including of course the declared attributes/fields and
- methods, but also available adapters, and utilities that provide
- this interface.
- """)
-
- def get(self, key, default=None):
- """See zope.app.interfaces.container.IReadContainer"""
- iface = queryInterface(key, default)
- if iface is default:
- # Yeah, we find more items than we claim to have! This way we can
- # handle all interfaces using this module. :-)
- parts = key.split('.')
- try:
- mod = __import__('.'.join(parts[:-1]), {}, {}, ('*',))
- except ImportError:
- iface = default
- else:
- iface = getattr(mod, parts[-1], default)
-
- if not iface is default:
- iface = LocationProxy(iface, self, key)
-
- return iface
-
- def items(self):
- """See zope.app.interfaces.container.IReadContainer"""
- items = list(searchInterfaceUtilities(self))
- items.sort()
- items = [(i[0], LocationProxy(i[1], self, i[0])) for i in items]
- return items
+# Make a package
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -16,211 +16,42 @@
$Id$
"""
__docformat__ = 'restructuredtext'
+from zope.interface import Interface
-from types import FunctionType, MethodType, ClassType, TypeType
-from zope.component.site import AdapterRegistration
-from zope.interface.declarations import providedBy
-from zope.interface.interfaces import IMethod, IInterface
-from zope.proxy import removeAllProxies
from zope.publisher.interfaces import IRequest
from zope.publisher.interfaces.browser import ILayer
-from zope.schema.interfaces import IField
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
+from zope.publisher.interfaces.http import IHTTPRequest
+from zope.publisher.interfaces.ftp import IFTPRequest
from zope.security.proxy import removeSecurityProxy
+from zope.proxy import removeAllProxies
from zope.app import zapi
+from zope.app.publisher.browser import BrowserView
+
from zope.app.apidoc.utilities import getPythonPath, renderText
-from zope.app.apidoc.classmodule import classRegistry
+from zope.app.apidoc.apidoc import APIDocumentation
+from zope.app.apidoc import classregistry
+from zope.app.apidoc import interface, component, presentation
-def _get(iface, type):
- """Return a dictionary containing all the attributes in an interface.
+def findAPIDocumentationRoot(obj, request):
+ if zapi.isinstance(obj, APIDocumentation):
+ return zapi.absoluteURL(obj, request)
+ return findAPIDocumentationRoot(zapi.getParent(obj), request)
- The type specifies whether we are looking for attributes or methods.
-
- Example::
-
- >>> from zope.interface import Interface, Attribute
- >>> from zope.schema import Field
-
- >>> class IFoo(Interface):
- ... foo = Field()
- ... bar = Field()
- ... def blah():
- ... pass
-
- >>> _get(IFoo, IMethod).keys()
- ['blah']
-
- >>> names = _get(IFoo, IField).keys()
- >>> names.sort()
- >>> names
- ['bar', 'foo']
- """
- # We really just want the attributes to be unproxied, since there are no
- # security declarations for generic interface attributes, but we need to
- # be able to get to the info.
- # We remove the Proxy on the interface, so we save ourselves the work of
- # removing it later individually from each attribute.
- iface = removeAllProxies(iface)
- items = {}
- for name in iface:
- attr = iface[name]
- if type.providedBy(attr):
- items[name] = attr
- return items
-
-
-def _getInOrder(iface, type,
- _itemsorter=lambda x, y: cmp(x[1].order, y[1].order)):
- """Return a list of (name, value) tuples in native interface order.
-
- The type specifies whether we are looking for attributes or methods. The
- `_itemsorter` argument provides the function that is used to order the
- fields. The default function should be the correct one for 99% of your
- needs.
-
- Example::
-
- >>> from zope.interface import Interface, Attribute
- >>> from zope.schema import Field
-
- >>> class IFoo(Interface):
- ... foo = Field()
- ... bar = Field()
- ... def blah():
- ... pass
-
- >>> [n for n, a in _getInOrder(IFoo, IMethod)]
- ['blah']
-
- >>> [n for n, a in _getInOrder(IFoo, IField)]
- ['foo', 'bar']
- """
- items = _get(iface, type).items()
- items.sort(_itemsorter)
- return items
-
-
-def _getFieldInterface(field):
- """Return PT-friendly dict about the field's interface.
-
- Examples::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from zope.interface import implements, Interface
-
- >>> class IField(Interface):
- ... pass
- >>> class ISpecialField(IField):
- ... pass
- >>> class Field(object):
- ... implements(IField)
- >>> class SpecialField(object):
- ... implements(ISpecialField)
- >>> class ExtraField(SpecialField):
- ... pass
-
- >>> info = _getFieldInterface(Field())
- >>> pprint(info)
- [('id', 'zope.app.apidoc.ifacemodule.browser.IField'),
- ('name', 'IField')]
-
- >>> info = _getFieldInterface(SpecialField())
- >>> pprint(info)
- [('id', 'zope.app.apidoc.ifacemodule.browser.ISpecialField'),
- ('name', 'ISpecialField')]
-
- >>> info = _getFieldInterface(ExtraField())
- >>> pprint(info)
- [('id', 'zope.app.apidoc.ifacemodule.browser.ISpecialField'),
- ('name', 'ISpecialField')]
- """
- # This is bad, but due to bootstrapping, directlyProvidedBy does
- # not work
- name = field.__class__.__name__
- ifaces = list(providedBy(field))
- # Usually fields have interfaces with the same name (with an 'I')
- for iface in ifaces:
- if iface.getName() == 'I' + name:
- return {'name': iface.getName(), 'id': getPythonPath(iface)}
- # Giving up...
- return {'name': ifaces[0].getName(), 'id': getPythonPath(ifaces[0])}
-
-
-def _getFieldClass(field):
- """Return PT-friendly dict about the field's class.
-
- Examples::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from zope.interface import implements, Interface
-
- >>> class IField(Interface):
- ... pass
- >>> class ISpecialField(IField):
- ... pass
- >>> class Field(object):
- ... implements(IField)
- >>> class SpecialField(object):
- ... implements(ISpecialField)
- >>> class ExtraField(SpecialField):
- ... pass
-
- >>> info = _getFieldClass(Field())
- >>> pprint(info)
- [('name', 'Field'),
- ('path', 'zope/app/apidoc/ifacemodule/browser/Field')]
-
- >>> info = _getFieldClass(SpecialField())
- >>> pprint(info)
- [('name', 'SpecialField'),
- ('path', 'zope/app/apidoc/ifacemodule/browser/SpecialField')]
-
- >>> info = _getFieldClass(ExtraField())
- >>> pprint(info)
- [('name', 'ExtraField'),
- ('path', 'zope/app/apidoc/ifacemodule/browser/ExtraField')]
- """
- class_ = field.__class__
- return {'name': class_.__name__,
- 'path': getPythonPath(class_).replace('.', '/')}
-
-
-def _getRequiredCSS(field):
- """Return a CSS class name that represents whether the field is required.
-
- Examples::
-
- >>> class Field(object):
- ... required = False
-
- >>> field = Field()
- >>> _getRequiredCSS(field)
- 'optional'
- >>> field.required = True
- >>> _getRequiredCSS(field)
- 'required'
-
- """
- if field.required:
- return 'required'
- else:
- return 'optional'
-
-
-def _getRealFactory(factory):
- """Get the real factory.
-
- Sometimes the original factory is masked by functions. If the function
- keeps track of the original factory, use it.
- """
- if isinstance(factory, FunctionType) and hasattr(factory, 'factory'):
- return factory.factory
- return factory
-
-
-class InterfaceDetails(object):
+class InterfaceDetails(BrowserView):
"""View class for an Interface."""
+ def __init__(self, context, request):
+ super(InterfaceDetails, self).__init__(context, request)
+ self._prepareViews()
+ try:
+ self.apidocRoot = findAPIDocumentationRoot(context, request)
+ except TypeError:
+ # Probably context without location; it's a test
+ self.apidocRoot = ''
+
def getId(self):
"""Return the id of the field as it is defined for the interface
utility.
@@ -264,263 +95,97 @@
def getTypes(self):
"""Return a list of interface types that are specified for this
- interface.
-
- Note that you should only expect one type at a time.
-
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getInterfaceDetails, IFoo
- >>> from zope.interface import Interface, directlyProvides
- >>> class IType(Interface):
- ... pass
-
- >>> details = getInterfaceDetails()
- >>> details.getTypes()
- []
-
- >>> directlyProvides(IFoo, IType)
- >>> type = details.getTypes()[0]
- >>> pprint(type)
- [('name', 'IType'),
- ('path', 'zope.app.apidoc.ifacemodule.browser.IType')]
-
- Cleanup
-
- >>> directlyProvides(IFoo, [])
- """
+ interface."""
# We have to really, really remove all proxies, since self.context (an
# interface) is usually security proxied and location proxied. To get
# the types, we need all proxies gone, otherwise the proxies'
# interfaces are picked up as well.
- context = removeAllProxies(self.context)
- types = list(providedBy(context))
- types.remove(IInterface)
+ iface = removeAllProxies(self.context)
return [{'name': type.getName(),
'path': getPythonPath(type)}
- for type in types]
+ for type in interface.getInterfaceTypes(iface)]
def getAttributes(self):
- r"""Return a list of attributes in the order they were specified.
-
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getInterfaceDetails
- >>> details = getInterfaceDetails()
-
- >>> attrs = details.getAttributes()
- >>> pprint(attrs)
- [[('doc', u'<p>This is bar.</p>\n'), ('name', 'bar')],
- [('doc', u'<p>This is foo.</p>\n'), ('name', 'foo')]]
- """
+ """Return a list of attributes in the order they were specified."""
# The `Interface` and `Attribute` class have no security declarations,
# so that we are not able to access any API methods on proxied
# objects. If we only remove security proxies, the location proxy's
# module will be returned.
iface = removeAllProxies(self.context)
- attrs = []
- for name in iface:
- attr = iface[name]
- if not IMethod.providedBy(attr) and not IField.providedBy(attr):
- attrs.append(attr)
- return [{'name': attr.getName(),
- 'doc': renderText(attr.getDoc() or '', iface.__module__)}
- for attr in attrs]
+ return [interface.getAttributeInfoDictionary(attr)
+ for name, attr in interface.getAttributes(iface)]
def getMethods(self):
- r"""Return a list of methods in the order they were specified.
-
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getInterfaceDetails
- >>> details = getInterfaceDetails()
-
- >>> methods = details.getMethods()
- >>> pprint(methods)
- [[('doc', u'<p>This is blah.</p>\n'),
- ('name', 'blah'),
- ('signature', '()')],
- [('doc', u'<p>This is get.</p>\n'),
- ('name', 'get'),
- ('signature', '(key, default=None)')]]
- """
+ """Return a list of methods in the order they were specified."""
# The `Interface` class have no security declarations, so that we are
# not able to access any API methods on proxied objects. If we only
# remove security proxies, the location proxy's module will be
# returned.
- return [{'name': method.getName(),
- 'signature': method.getSignatureString(),
- 'doc': renderText(
- method.getDoc() or '',
- removeAllProxies(self.context).__module__)}
- for method in _get(self.context, IMethod).values()]
-
+ iface = removeAllProxies(self.context)
+ return [interface.getMethodInfoDictionary(method)
+ for name, method in interface.getMethods(iface)]
+
def getFields(self):
r"""Return a list of fields in required + alphabetical order.
The required attributes are listed first, then the optional
- attributes.
-
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getInterfaceDetails
- >>> details = getInterfaceDetails()
-
- >>> fields = details.getFields()
- >>> pprint(fields)
- [[('class',
- [('name', 'TextLine'),
- ('path', 'zope/schema/_bootstrapfields/TextLine')]),
- ('default', "u'Foo'"),
- ('description', u'<p>Title</p>\n'),
- ('iface',
- [('id', 'zope.schema.interfaces.ITextLine'),
- ('name', 'ITextLine')]),
- ('name', 'title'),
- ('required', True),
- ('required_css', 'required'),
- ('title', u'')],
- [('class',
- [('name', 'Text'),
- ('path', 'zope/schema/_bootstrapfields/Text')]),
- ('default', "u'Foo.'"),
- ('description', u'<p>Desc</p>\n'),
- ('iface',
- [('id', 'zope.schema.interfaces.IText'), ('name', 'IText')]),
- ('name', 'description'),
- ('required', False),
- ('required_css', 'optional'),
- ('title', u'')]]
- """
+ attributes."""
# The `Interface` class have no security declarations, so that we are
# not able to access any API methods on proxied objects. If we only
# remove security proxies, the location proxy's module will be
# returned.
- _itemsorter = lambda x, y: cmp(
- (x[1].required and '1' or '2', x[0].lower()),
- (y[1].required and '1' or '2', y[0].lower()))
- fields = map(lambda x: x[1], _getInOrder(
- self.context, IField, _itemsorter=_itemsorter))
- return [{'name': self._getFieldName(field),
- 'iface': _getFieldInterface(field),
- 'class': _getFieldClass(field),
- 'required': field.required,
- 'required_css': _getRequiredCSS(field),
- 'default': repr(field.default),
- 'title': field.title,
- 'description': renderText(
- field.description or '',
- removeAllProxies(self.context).__module__)}
- for field in fields]
+ iface = removeAllProxies(self.context)
+ # Make sure that the required fields are shown first
+ sorter = lambda x, y: cmp((not x[1].required, x[0].lower()),
+ (not y[1].required, y[0].lower()))
+ return [interface.getFieldInfoDictionary(field)
+ for name, field in interface.getFieldsInOrder(iface, sorter)]
- def _getFieldName(self, field):
- return field.getName()
+ def getSpecificRequiredAdapters(self):
+ """Get adapters where this interface is required."""
+ # Must remove security and location proxies, so that we have access to
+ # the API methods and class representation.
+ iface = removeAllProxies(self.context)
+ regs = component.getRequiredAdapters(iface)
+ regs = component.filterAdapterRegistrations(
+ regs, iface,
+ level=component.SPECIFIC_INTERFACE_LEVEL)
+ regs = [component.getAdapterInfoDictionary(reg)
+ for reg in regs]
+ return regs
- def getRequiredAdapters(self):
- """Get adapters where this interface is required.
+ def getExtendedRequiredAdapters(self):
+ """Get adapters where this interface is required."""
+ # Must remove security and location proxies, so that we have access to
+ # the API methods and class representation.
+ iface = removeAllProxies(self.context)
+ regs = component.getRequiredAdapters(iface)
+ regs = component.filterAdapterRegistrations(
+ regs, iface,
+ level=component.EXTENDED_INTERFACE_LEVEL)
+ regs = [component.getAdapterInfoDictionary(reg)
+ for reg in regs]
+ return regs
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getInterfaceDetails
- >>> details = getInterfaceDetails()
-
- >>> adapters = details.getRequiredAdapters()
- >>> adapters.sort()
- >>> pprint(adapters[0])
- [('factory',
- 'zope.app.location.traversing.LocationPhysicallyLocatable'),
- ('factory_url',
- 'zope/app/location/traversing/LocationPhysicallyLocatable'),
- ('name', ''),
- ('provided',
- 'zope.app.traversing.interfaces.IPhysicallyLocatable'),
- ('required', [])]
- """
- sm = zapi.getSiteManager()
- # Must remove security proxies, so that we have access to the API
- # methods.
- iface = removeSecurityProxy(self.context)
- adapters = []
- for reg in sm.registrations():
- # Only grab adapters
- if not isinstance(reg, AdapterRegistration):
- continue
- # Only grab the adapters for which this interface is required
- if reg.required and reg.required[0] is not None and \
- iface not in reg.required:
- continue
- # Ignore views and layers
- if IInterface.providedBy(reg.required[-1]) and (
- reg.required[-1].isOrExtends(IRequest) or
- reg.required[-1].isOrExtends(ILayer)):
- continue
- factory = _getRealFactory(reg.value)
- path = getPythonPath(factory)
- if type(factory) in (FunctionType, MethodType):
- url = None
- else:
- url = path.replace('.', '/')
- adapters.append({
- 'provided': getPythonPath(reg.provided),
- 'required': [getPythonPath(iface)
- for iface in reg.required
- if iface is not None],
- 'name': getattr(reg, 'name', None),
- 'factory': path,
- 'factory_url': url
- })
- return adapters
+ def getGenericRequiredAdapters(self):
+ """Get adapters where this interface is required."""
+ # Must remove security and location proxies, so that we have access to
+ # the API methods and class representation.
+ iface = removeAllProxies(self.context)
+ regs = component.getRequiredAdapters(iface)
+ regs = tuple(component.filterAdapterRegistrations(
+ regs, iface,
+ level=component.GENERIC_INTERFACE_LEVEL))
+ return [component.getAdapterInfoDictionary(reg)
+ for reg in regs]
def getProvidedAdapters(self):
- """Get adapters where this interface is provided.
-
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getInterfaceDetails
- >>> details = getInterfaceDetails()
-
- >>> adapters = details.getProvidedAdapters()
- >>> pprint(adapters)
- [[('factory', '__builtin__.object'),
- ('factory_url', '__builtin__/object'),
- ('name', ''),
- ('required', ['zope.app.apidoc.ifacemodule.tests.IBar'])]]
- """
- sm = zapi.getSiteManager()
+ """Get adapters where this interface is provided."""
# Must remove security and location proxies, so that we have access to
# the API methods and class representation.
- iface = removeAllProxies(self.context)
- adapters = []
- for reg in sm.registrations():
- # Only grab adapters
- if not isinstance(reg, AdapterRegistration):
- continue
- # Only grab adapters for which this interface is provided
- if iface is not reg.provided:
- continue
- # Ignore views
- if IInterface.providedBy(reg.required[-1]) and \
- reg.required[-1].isOrExtends(IRequest):
- continue
- factory = _getRealFactory(reg.value)
- path = getPythonPath(factory)
- if type(factory) in (FunctionType, MethodType):
- url = None
- else:
- url = path.replace('.', '/')
- adapters.append({
- 'required': [getPythonPath(iface) for iface in reg.required],
- 'name': reg.name,
- 'factory': path,
- 'factory_url': url
- })
- return adapters
+ regs = component.getProvidedAdapters(removeAllProxies(self.context))
+ return [component.getAdapterInfoDictionary(reg)
+ for reg in regs]
def getClasses(self):
"""Get the classes that implement this interface.
@@ -539,76 +204,53 @@
# Must remove security and location proxies, so that we have access to
# the API methods and class representation.
iface = removeAllProxies(self.context)
- classes = classRegistry.getClassesThatImplement(iface)
+ classes = classregistry.classRegistry.getClassesThatImplement(iface)
return [{'path': path, 'url': path.replace('.', '/')}
for path, klass in classes]
def getFactories(self):
"""Return the factories, who will provide objects implementing this
- interface.
+ interface."""
+ # Must remove security and location proxies, so that we have access to
+ # the API methods and class representation.
+ regs = component.getFactories(removeAllProxies(self.context))
+ return [component.getFactoryInfoDictionary(reg)
+ for reg in regs]
- Example::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getInterfaceDetails
- >>> details = getInterfaceDetails()
-
- >>> factories = details.getFactories()
- >>> factories = [f.items() for f in factories]
- >>> factories = [f for f in factories if f.sort() is None]
- >>> factories.sort()
- >>> pprint(factories)
- [[('name', u'FooFactory'),
- ('title', 'Foo Factory'),
- ('url', 'zope/component/factory/Factory')]]
- """
+ def getUtilities(self):
+ """Return all utilities that provide this interface."""
# Must remove security and location proxies, so that we have access to
# the API methods and class representation.
- iface = removeAllProxies(self.context)
- factories = [(n, f) for n, f in
- zapi.getFactoriesFor(iface)
- if iface in tuple(f.getInterfaces())]
- info = []
- for name, factory in factories:
- if type(factory) in (ClassType, TypeType):
- klass = factory
- else:
- klass = factory.__class__
- path = getPythonPath(klass)
- info.append({'name': name or '<i>no name</i>',
- 'title': getattr(factory, 'title', ''),
- 'url': path.replace('.', '/')})
- return info
+ regs = component.getUtilities(removeAllProxies(self.context))
+ return [component.getUtilityInfoDictionary(reg)
+ for reg in regs]
- def getUtilitiesFor(self):
- """Return all utilities that provide this interface.
- Example::
+ def _prepareViews(self):
+ self.httpViews = []
+ self.browserViews = []
+ self.ftpViews = []
+ self.xmlrpcViews = []
+ self.otherViews = []
- >>> from zope.app.apidoc.tests import pprint
- >>> from tests import getInterfaceDetails
- >>> details = getInterfaceDetails()
+ for reg in presentation.getViews(removeAllProxies(self.context)):
+ type = presentation.getPresentationType(reg.required[-1])
+ info = presentation.getViewInfoDictionary(reg)
- >>> utils = details.getUtilitiesFor()
- >>> pprint(utils)
- [[('name', u'The Foo'),
- ('path', 'zope.app.apidoc.ifacemodule.tests.Foo'),
- ('url', 'zope/app/apidoc/ifacemodule/tests/Foo'),
- ('url_name', u'The Foo')]]
- """
- sm = zapi.getSiteManager()
- # Must remove security and location proxies, so that we have access to
- # the API methods and class representation.
- utils = sm.getUtilitiesFor(removeAllProxies(self.context))
- info = []
- for name, util in utils:
- if type(util) in (ClassType, TypeType):
- klass = util
+ if type is IBrowserRequest:
+ self.browserViews.append(info)
+ elif type is IXMLRPCRequest:
+ self.xmlrpcViews.append(info)
+ elif type is IHTTPRequest:
+ self.httpViews.append(info)
+ elif type is IFTPRequest:
+ self.ftpViews.append(info)
else:
- klass = util.__class__
- path = getPythonPath(klass)
- info.append({'name': name or '<i>no name</i>',
- 'url_name': name or '__noname__',
- 'path': path,
- 'url': path.replace('.', '/')})
- return info
+ self.otherViews.append(info)
+
+ sort_function = lambda x, y: cmp(x['name'], y['name'])
+ self.httpViews.sort(sort_function)
+ self.browserViews.sort(sort_function)
+ self.ftpViews.sort(sort_function)
+ self.xmlrpcViews.sort(sort_function)
+ self.otherViews.sort(sort_function)
Added: Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,353 @@
+======================================
+Module Menu and ZCML Directive Details
+======================================
+
+This document provides an overview of all browser-presentation related
+objects.
+
+`getAllTextOfInterface(iface)`
+------------------------------
+
+Get all searchable text from an interface
+
+ >>> import zope.interface
+ >>> import zope.schema
+ >>> class IFoo(zope.interface.Interface):
+ ... '''foo'''
+ ...
+ ... def bar(self):
+ ... '''bar'''
+ ...
+ ... blah = zope.interface.Attribute('blah', 'blah')
+ ...
+ ... field = zope.schema.Field(
+ ... title = u'title', description = u'description')
+
+Now get the text. Note that there is no particular order during the text
+collection.
+
+ >>> from zope.app.apidoc.ifacemodule.menu import getAllTextOfInterface
+ >>> text = getAllTextOfInterface(IFoo)
+ >>> u'foo' in text
+ True
+ >>> u'bar' in text
+ True
+ >>> u'blah' in text
+ True
+ >>> u'field' in text
+ True
+ >>> u'title' in text
+ True
+ >>> u'description' in text
+ True
+
+
+`Menu` class
+------------
+
+This is the menu class for the Interface Documentation Module.
+
+The menu allows one to look for interfaces by full-text search or partial
+names. The `findInterfaces()` function provides a simple search mechanism.
+
+Before we can test the method, let's create a `Menu` instance:
+
+ >>> from zope.interface.interfaces import IElement, IAttribute
+
+ >>> from zope.app.apidoc.ifacemodule.menu import Menu
+ >>> menu = Menu()
+ >>> menu.context = {'IElement': IElement, 'IAttribute': IAttribute}
+ >>> menu.request = {'name_only': 'on', 'search_str': ''}
+
+Now let's see how successful our searches are:
+
+ >>> menu.request['search_str'] = 'Elem'
+ >>> pprint(menu.findInterfaces())
+ [{'name': 'IElement',
+ 'url': './IElement/apiindex.html'}]
+
+ >>> menu.request['search_str'] = 'I'
+ >>> pprint(menu.findInterfaces())
+ [{'name': 'IAttribute',
+ 'url': './IAttribute/apiindex.html'},
+ {'name': 'IElement',
+ 'url': './IElement/apiindex.html'}]
+
+Now using the full text search:
+
+ >>> del menu.request['name_only']
+
+ >>> menu.request['search_str'] = 'object'
+ >>> pprint(menu.findInterfaces())
+ [{'name': 'IAttribute',
+ 'url': './IAttribute/apiindex.html'},
+ {'name': 'IElement',
+ 'url': './IElement/apiindex.html'}]
+
+ >>> menu.request['search_str'] = 'Stores'
+ >>> pprint(menu.findInterfaces())
+ [{'name': 'IAttribute',
+ 'url': './IAttribute/apiindex.html'}]
+
+
+`InterfaceDetails` class
+------------------------
+
+This view provides many details about an interface. Most methods of the class
+actually use the public inspection API.
+
+Before we can test the view, we need to create an interesting setup, so that
+the view can provide some useful data. Let's start by defining a complex
+interface:
+
+ >>> class IFoo(zope.interface.Interface):
+ ... """This is the Foo interface
+ ...
+ ... More description here...
+ ... """
+ ... foo = zope.interface.Attribute('This is foo.')
+ ... bar = zope.interface.Attribute('This is bar.')
+ ...
+ ... title = zope.schema.TextLine(
+ ... description=u'Title',
+ ... required=True,
+ ... default=u'Foo')
+ ...
+ ... description = zope.schema.Text(
+ ... description=u'Desc',
+ ... required=False,
+ ... default=u'Foo.')
+ ...
+ ... def blah():
+ ... """This is blah."""
+ ...
+ ... def get(key, default=None):
+ ... """This is get."""
+
+Let's now create another interface `IBar` and make `Foo` an adapter from
+`IBar` to `IFoo`:
+
+ >>> class IBar(zope.interface.Interface):
+ ... pass
+
+ >>> class Foo(object):
+ ... zope.interface.implements(IFoo)
+
+ >>> from zope.app.testing import ztapi
+ >>> ztapi.provideAdapter(IBar, IFoo, Foo)
+
+ >>> from zope.app.apidoc.classregistry import classRegistry
+ >>> classRegistry['__builtin__.Foo'] = Foo
+
+Let's also register a factory for `Foo`
+
+ >>> from zope.component.interfaces import IFactory
+ >>> from zope.component.factory import Factory
+ >>> ztapi.provideUtility(IFactory, Factory(Foo, title='Foo Factory'),
+ ... 'FooFactory')
+
+and a utility providing `IFoo`:
+
+ >>> ztapi.provideUtility(IFoo, Foo(), 'The Foo')
+
+Now that the initial setup is done, we can create an interface that is located
+in the interface documentation module
+
+ >>> from zope.app.apidoc.ifacemodule.ifacemodule import InterfaceModule
+ >>> ifacemodule = InterfaceModule()
+
+ >>> from zope.app.apidoc.tests import Root
+ >>> ifacemodule.__parent__ = Root()
+ >>> ifacemodule.__name__ = 'Interfaces'
+
+ >>> from zope.app.location import LocationProxy
+ >>> iface = LocationProxy(IFoo, ifacemodule, 'IFoo')
+
+and finally the details view:
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> from zope.app.apidoc.ifacemodule.browser import InterfaceDetails
+ >>> details = InterfaceDetails(iface, TestRequest())
+
+
+`getId()`
+---------
+
+Return the id of the field as it is defined for the interface
+utility.
+
+ >>> details.getId()
+ 'IFoo'
+
+`getDoc()`
+----------
+
+Return the main documentation string of the interface.
+
+ >>> details.getDoc()[:55]
+ u'<div class="document">\n<p>This is the Foo interface</p>'
+
+
+`getBases()`
+------------
+
+Get all bases of this class
+
+ >>> details.getBases()
+ ['zope.interface.Interface']
+
+
+`getTypes()`
+------------
+
+Return a list of interface types that are specified for this interface.
+
+Initially we do not have any types
+
+ >>> details.getTypes()
+ []
+
+but when I create and assign a type to the interface
+
+ >>> class IMyType(zope.interface.interfaces.IInterface):
+ ... pass
+
+ >>> zope.interface.directlyProvides(IFoo, IMyType)
+
+we get a result:
+
+ >>> pprint(details.getTypes())
+ [{'name': 'IMyType',
+ 'path': '__builtin__.IMyType'}]
+
+
+`getAttributes()`
+-----------------
+
+Return a list of attributes in the order they were specified.
+
+ >>> pprint(details.getAttributes())
+ [{'doc': u'<div class="document">\nThis is bar.</div>\n',
+ 'name': 'bar'},
+ {'doc': u'<div class="document">\nThis is foo.</div>\n',
+ 'name': 'foo'}]
+
+
+`getMethods()`
+--------------
+
+Return a list of methods in the order they were specified.
+
+ >>> pprint(details.getMethods())
+ [{'doc': u'<div class="document">\nThis is blah.</div>\n',
+ 'name': 'blah',
+ 'signature': '()'},
+ {'doc': u'<div class="document">\nThis is get.</div>\n',
+ 'name': 'get',
+ 'signature': '(key, default=None)'}]
+
+
+`getFields()`
+-------------
+
+Return a list of fields in required + alphabetical order.
+
+The required attributes are listed first, then the optional attributes.
+
+ >>> pprint(details.getFields())
+ [{'class': {'name': 'TextLine',
+ 'path': 'zope/schema/_bootstrapfields/TextLine'},
+ 'default': "u'Foo'",
+ 'description': u'<div class="document">\nTitle</div>\n',
+ 'iface': {'id': 'zope.schema.interfaces.ITextLine',
+ 'name': 'ITextLine'},
+ 'name': 'title',
+ 'required': True,
+ 'required_string': u'required',
+ 'title': u''},
+ {'class': {'name': 'Text',
+ 'path': 'zope/schema/_bootstrapfields/Text'},
+ 'default': "u'Foo.'",
+ 'description': u'<div class="document">\nDesc</div>\n',
+ 'iface': {'id': 'zope.schema.interfaces.IText',
+ 'name': 'IText'},
+ 'name': 'description',
+ 'required': False,
+ 'required_string': u'optional',
+ 'title': u''}]
+
+`getSpecificRequiredAdapters()`
+-------------------------------
+
+Get adapters where this interface is required.
+
+ >>> pprint(details.getSpecificRequiredAdapters())
+ []
+
+
+`getExtendedRequiredAdapters()`
+-------------------------------
+
+Get adapters where this interface is required.
+
+ >>> pprint(details.getExtendedRequiredAdapters())
+ []
+
+
+`getGenericRequiredAdapters()`
+------------------------------
+
+Get adapters where this interface is required.
+
+ >>> pprint(details.getGenericRequiredAdapters())
+ []
+
+
+`getProvidedAdapters()`
+-----------------------
+
+Get adapters where this interface is provided.
+
+ >>> pprint(details.getProvidedAdapters())
+ [{'doc': '',
+ 'factory': '__builtin__.Foo',
+ 'factory_url': '__builtin__/Foo',
+ 'name': '',
+ 'provided': {'module': '__builtin__',
+ 'name': 'IFoo'},
+ 'required': [{'module': '__builtin__',
+ 'name': 'IBar'}],
+ 'zcml': None}]
+
+
+`getClasses()`
+---------------
+
+Get the classes that implement this interface.
+
+ >>> pprint(details.getClasses())
+ [{'path': '__builtin__.Foo',
+ 'url': '__builtin__/Foo'}]
+
+`getFactories()`
+----------------
+
+Return the factories, who will provide objects implementing this
+interface.
+
+ >>> pprint(details.getFactories())
+ [{'description': u'',
+ 'name': 'FooFactory',
+ 'title': 'Foo Factory',
+ 'url': 'zope/component/factory/Factory'}]
+
+`getUtilities()`
+----------------
+
+Return all utilities that provide this interface.
+
+ >>> pprint(details.getUtilities())
+ [{'name': 'The Foo',
+ 'path': '__builtin__.Foo',
+ 'url': '__builtin__/Foo',
+ 'url_name': 'The Foo'}]
\ No newline at end of file
Property changes on: Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,100 @@
+<metal:block define-macro="ifacename"
+ ><span tal:replace="iface/module" />.<u tal:content="iface/name"
+/></metal:block>
+
+<metal:block define-macro="zcml">
+ <a href=""
+ tal:attributes="href
+ string:../../Code/${zcml/url}/index.html"
+ tal:content="zcml/file">
+ zope/app/configure.zcml
+ </a>
+ <span class="small">(line <tal:block replace="zcml/line" />)</span>
+</metal:block>
+
+
+<metal:block define-macro="adapter">
+ <div>
+ <b><code>
+ <a href=""
+ tal:attributes="href
+ string:$rootURL/Code/${adapter/factory_url}/index.html"
+ tal:content="adapter/factory"
+ tal:condition="adapter/factory_url" />
+ <span tal:content="adapter/factory"
+ tal:condition="not: adapter/factory_url" />
+ </code></b>
+ <span tal:condition="adapter/name">
+ (<span i18n:translate="">name:</span>
+ <tal:block content="adapter/name" />)
+ </span>
+ </div>
+
+ <div tal:condition="adapter/zcml"
+ tal:define="zcml adapter/zcml">
+ <i i18n:translate="">registered:</i>
+ <metal:block use-macro="context/@@interface_macros/zcml" />
+ </div>
+
+ <div>
+ <i i18n:translate="">requires:</i>
+ <tal:block repeat="iface adapter/required">
+ <a href=""
+ tal:condition="iface"
+ tal:attributes="href
+ string:../${iface/module}.${iface/name}/apiindex.html">
+ <metal:block use-macro="context/@@interface_macros/ifacename"
+ /></a><tal:block condition="not:repeat/iface/end">, </tal:block>
+ </tal:block>
+ <span tal:condition="not:adapter/required" i18n:translate="">
+ No interface required.
+ </span>
+ </div>
+
+ <div tal:define="iface adapter/provided">
+ <i i18n:translate="">provides:</i>
+ <a href=""
+ tal:condition="iface"
+ tal:attributes="href
+ string:../${iface/module}.${iface/name}/apiindex.html">
+ <metal:block use-macro="context/@@interface_macros/ifacename" />
+ </a>
+ </div>
+
+ <div tal:condition="adapter/doc">
+ <i i18n:translate="">registration info:</i>
+ <span tal:content="adapter/doc">reg info</span>
+ </div>
+
+</metal:block>
+
+
+<metal:block define-macro="factory">
+ <a href=""
+ tal:attributes="href string:../../Code/${factory/url}/"
+ tal:content="factory/name" />
+ <tal:block replace="string:(${factory/title})" condition="factory/title" />
+</metal:block>
+
+
+<metal:block define-macro="utility">
+ <a href=""
+ tal:attributes="href
+ string:$rootURL/Utility/${view/getId}/${utility/url_name}/index.html"
+ tal:content="structure utility/name" />
+ <br />
+ <div><span i18n:translate="">Class:</span> <code>
+ <a href=""
+ tal:attributes="href string:$rootURL/Code/${utility/url}/index.html"
+ tal:content="utility/path" />
+ </code></div>
+</metal:block>
+
+
+<metal:block define-macro="class">
+ <b><code>
+ <a href=""
+ tal:attributes="href string:$rootURL/Code/${klass/url}/index.html"
+ tal:content="klass/path" />
+ </code></b>
+</metal:block>
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/configure.zcml 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/configure.zcml 2005-02-23 22:22:48 UTC (rev 29269)
@@ -2,8 +2,8 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
- <class class=".InterfaceModule">
- <allow interface=".IInterfaceModule" />
+ <class class=".ifacemodule.InterfaceModule">
+ <allow interface=".ifacemodule.IInterfaceModule" />
<allow interface="zope.app.container.interfaces.IReadContainer" />
</class>
@@ -11,13 +11,44 @@
<utility
provides="zope.app.apidoc.interfaces.IDocumentationModule"
- factory=".InterfaceModule"
+ factory=".ifacemodule.InterfaceModule"
name="Interface" />
- <!-- The name for the interface content cannot be 'index.html', since the
- introspector uses this name already. -->
+ <!-- Setup interface-related macros -->
<browser:page
+ for="*"
+ name="interface_macros"
+ permission="zope.View"
+ class=".macros.InterfaceDetailsMacros"
+ allowed_interface="zope.interface.common.mapping.IItemMapping"
+ />
+
+ <browser:page
+ for="*"
+ name="iface_macros"
+ permission="zope.View"
+ template="iface_macros.pt"
+ />
+
+ <browser:page
+ for="*"
+ name="component_macros"
+ permission="zope.View"
+ template="component_macros.pt"
+ />
+
+ <browser:page
+ for="*"
+ name="presentation_macros"
+ permission="zope.View"
+ template="presentation_macros.pt"
+ />
+
+ <!-- The name for the interface content cannot be 'index.html', since -->
+ <!-- the introspector uses this name already. -->
+
+ <browser:page
for="zope.interface.interfaces.IInterface"
permission="zope.app.apidoc.UseAPIDoc"
class=".browser.InterfaceDetails"
@@ -28,7 +59,7 @@
<!-- Interface Documentation Module Menu -->
<browser:page
- for=".InterfaceModule"
+ for=".ifacemodule.InterfaceModule"
permission="zope.app.apidoc.UseAPIDoc"
class=".menu.Menu"
name="menu.html"
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/ftests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/ftests.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/ftests.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -36,7 +36,7 @@
def testInterfaceDetailsView(self):
response = self.publish(
'/++apidoc++/Interface'
- '/zope.app.apidoc.ifacemodule.IInterfaceModule'
+ '/zope.app.apidoc.ifacemodule.ifacemodule.IInterfaceModule'
'/apiindex.html',
basic='mgr:mgrpw')
self.assertEqual(response.getStatus(), 200)
Added: Zope3/trunk/src/zope/app/apidoc/ifacemodule/iface_macros.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/iface_macros.pt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/iface_macros.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,85 @@
+<metal:block define-macro="attribute">
+ <b><code tal:content="attribute/name">attr</code></b>
+ <span i18n:translate="">(Attribute)</span>
+ <br />
+ <div class="inline-documentation" tal:content="structure attribute/doc">
+ attr desc
+ </div>
+</metal:block>
+
+
+<metal:block define-macro="field">
+ <b tal:attributes="class field/required_string">
+ <code tal:content="field/name">field</code>
+ <span tal:condition="field/required">*</span>
+ </b>
+ -
+ <a href=""
+ tal:attributes="href string:$rootURL/Code/${field/class/path}/index.html">
+ <code tal:content="field/class/name">Field</code>
+ </a>
+
+ (<span i18n:translate="">default</span> =
+ <code tal:content="field/default" />)
+ <br />
+ <div tal:content="structure field/title" class="field-title">title</div>
+ <span tal:content="structure field/description">field desc</span>
+</metal:block>
+
+
+<metal:block define-macro="method">
+ <b><code
+ tal:content="string:${method/name}${method/signature}" />
+ </b><br>
+ <div class="inline-documentation" tal:content="structure method/doc">
+ method desc
+ </div>
+</metal:block>
+
+
+<metal:block define-macro="methods">
+ <div metal:define-slot="header">
+ <h2 class="details-section" i18n:translate="">Methods</h2>
+ </div>
+ <div class="indent">
+
+ <ul class="attr-list" tal:condition="methods">
+ <li tal:repeat="method methods">
+ <metal:block use-macro="context/@@interface_macros/method" />
+ </li>
+ </ul>
+
+ <p tal:condition="not: methods">
+ <em i18n:translate="">There are no methods specified.</em>
+ </p>
+
+ </div>
+</metal:block>
+
+<metal:block define-macro="attributes_fields">
+ <div metal:define-slot="header">
+ <h2 class="details-section" i18n:translate="">Attributes/Fields</h2>
+ </div>
+ <div class="indent">
+
+ <ul class="attr-list"
+ tal:condition="python: attributes or fields">
+ <li tal:repeat="attribute attributes">
+ <metal:block use-macro="context/@@interface_macros/attribute" />
+ </li>
+ <li tal:repeat="field fields">
+ <metal:block use-macro="context/@@interface_macros/field" />
+ </li>
+ </ul>
+
+ <p tal:condition="python: not (attributes or fields)">
+ <em i18n:translate="">There are no attributes or fields specified.</em>
+ </p>
+
+ <p tal:condition="python: attributes or fields">
+ <em><b class="required">*</b> =
+ <span i18n:translate="">required</span></em>
+ </p>
+
+ </div>
+</metal:block>
Added: Zope3/trunk/src/zope/app/apidoc/ifacemodule/ifacemodule.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/ifacemodule.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/ifacemodule.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,90 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Interface Documentation Module
+
+The interface documentation module retrieves its information from the
+site manager. Therefore, currently there are no unregsitered interfaces
+listed in the documentation. This might be good, since unregistered interfaces
+are usually private and not of interest to a general developer.
+
+$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.app import zapi
+from zope.interface import implements
+from zope.app.apidoc.interfaces import IDocumentationModule
+from zope.app.apidoc.utilities import ReadContainerBase
+from zope.app.location import LocationProxy
+from zope.app.component.interface \
+ import queryInterface, searchInterfaceUtilities
+from zope.app.i18n import ZopeMessageIDFactory as _
+
+class IInterfaceModule(IDocumentationModule):
+ """Interface API Documentation Module
+
+ This is a marker interface, so that we can write adapters for objects
+ implementing this interface.
+ """
+
+class InterfaceModule(ReadContainerBase):
+ r"""Represent the Documentation of all Interfaces.
+
+ This documentation is implemented using a simple `IReadContainer`. The
+ items of the container are all the interfaces listed in the global
+ site manager."""
+
+ implements(IInterfaceModule)
+
+ # See zope.app.apidoc.interfaces.IDocumentationModule
+ title = _('Interfaces')
+
+ # See zope.app.apidoc.interfaces.IDocumentationModule
+ description = _("""
+ All used and important interfaces are registered through the site
+ manager. While it would be possible to just list all attributes, it is
+ hard on the user to read such an overfull list. Therefore, interfaces that
+ have partial common module paths are bound together.
+
+ The documentation of an interface also provides a wide variety of
+ information, including of course the declared attributes/fields and
+ methods, but also available adapters, and utilities that provide
+ this interface.
+ """)
+
+ def get(self, key, default=None):
+ """See zope.app.interfaces.container.IReadContainer"""
+ iface = queryInterface(key, default)
+ if iface is default:
+ # Yeah, we find more items than we claim to have! This way we can
+ # handle all interfaces using this module. :-)
+ parts = key.split('.')
+ try:
+ mod = __import__('.'.join(parts[:-1]), {}, {}, ('*',))
+ except ImportError:
+ iface = default
+ else:
+ iface = getattr(mod, parts[-1], default)
+
+ if not iface is default:
+ iface = LocationProxy(iface, self, key)
+
+ return iface
+
+ def items(self):
+ """See zope.app.interfaces.container.IReadContainer"""
+ items = list(searchInterfaceUtilities(self))
+ items.sort()
+ items = [(i[0], LocationProxy(i[1], self, i[0])) for i in items]
+ return items
Property changes on: Zope3/trunk/src/zope/app/apidoc/ifacemodule/ifacemodule.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/index.pt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,5 +1,6 @@
-<html metal:use-macro="views/apidoc_macros/details">
-<body metal:fill-slot="contents">
+<html metal:use-macro="context/@@apidoc_macros/details">
+<body metal:fill-slot="contents"
+ tal:define="rootURL view/apidocRoot">
<h1 class="details-header" tal:content="view/getId">
zope.app.interfaces.IInterface
@@ -37,165 +38,157 @@
</ul>
<p tal:condition="not: bases">
- <em i18n:translate="">There are no base classes.</em>
+ <em i18n:translate="">There are no base interfaces.</em>
</p>
</div>
- <h2 class="details-section" i18n:translate="">Attributes/Fields</h2>
+ <tal:block define="attributes view/getAttributes;
+ fields view/getFields">
+ <metal:block use-macro="context/@@interface_macros/attributes_fields" />
+ </tal:block>
- <div class="indent"
- tal:define="attributes view/getAttributes;
- fields view/getFields">
+ <tal:block define="methods view/getMethods">
+ <metal:block use-macro="context/@@interface_macros/methods" />
+ </tal:block>
- <ul class="attr-list"
- tal:condition="python: attributes or fields">
+ <h2 class="details-section" i18n:translate="">Adapters</h2>
- <li tal:repeat="attr attributes">
- <b><code tal:content="attr/name">attr</code></b>
- <span i18n:translate="">(Attribute)</span><br>
- <div class="inline-documentation" tal:content="structure attr/doc">
- attr desc
- </div>
- </li>
+ <div tal:define="specific_adapters view/getSpecificRequiredAdapters;
+ extended_adapters view/getExtendedRequiredAdapters;
+ generic_adapters view/getGenericRequiredAdapters;
+ provided_adapters view/getProvidedAdapters">
- <li tal:repeat="field fields">
- <b tal:attributes="class field/required_css">
- <code tal:content="field/name">field</code>
- <span tal:condition="field/required">*</span>
- </b>
- - <a href=""
- tal:attributes="
- href string:../../Class/${field/class/path}/index.html">
- <code tal:content="field/class/name">Field</code></a>
- (<span i18n:translate="">default</span> =
- <code tal:content="field/default" />)<br />
- <div tal:content="structure field/title" class="field-title">title</div>
- <span tal:content="structure field/description">field desc</span>
- </li>
-
- </ul>
-
- <p tal:condition="python: not (attributes or fields)">
- <em i18n:translate="">There are no attributes or fields specified.</em>
- </p>
-
+ <div class="indent"
+ tal:condition="python: specific_adapters or generic_adapters">
+
+ <h3 i18n:translate="">Adapters where this interface is required:</h3>
+
+ <h4 i18n:translate="">Specific Adapters</h4>
+ <ul class="attr-list"
+ tal:condition="specific_adapters">
+ <li tal:repeat="adapter specific_adapters">
+ <metal:block use-macro="context/@@interface_macros/adapter" />
+ </li>
+ </ul>
+ <p tal:condition="not:specific_adapters">
+ <em i18n:translate="">There are no specific adapters registered for
+ this interface.</em>
+ </p>
+
+ <h4 i18n:translate="">Extended Adapters</h4>
+ <ul class="attr-list"
+ tal:condition="extended_adapters">
+ <li tal:repeat="adapter extended_adapters">
+ <metal:block use-macro="context/@@interface_macros/adapter" />
+ </li>
+ </ul>
+ <p tal:condition="not:extended_adapters">
+ <em i18n:translate="">There are no extended adapters registered for
+ this interface.</em>
+ </p>
+
+ <h4 i18n:translate="">Generic Adapters</h4>
+ <ul class="attr-list"
+ tal:condition="generic_adapters">
+ <li tal:repeat="adapter generic_adapters">
+ <metal:block use-macro="context/@@interface_macros/adapter" />
+ </li>
+ </ul>
+ <p tal:condition="not:generic_adapters">
+ <em i18n:translate="">There are no generic adapters registered.</em>
+ </p>
+
+ </div>
+
+ <div class="indent"
+ tal:condition="provided_adapters">
+
+ <h3 i18n:translate="">Adapters that provide this interface:</h3>
+ <ul>
+ <li tal:repeat="adapter provided_adapters">
+ <metal:block use-macro="context/@@interface_macros/adapter" />
+ </li>
+ </ul>
+
+ </div>
+
+ <p tal:condition="
+ python: not (specific_adapters or extended_adapters or generic_adapters
+ or provided_adapters)">
+ <em i18n:translate="">There are no adapters registered for
+ this interface.</em>
+ </p>
</div>
+ <div tal:define="Views view/browserViews"
+ tal:condition="Views">
+ <h2 class="details-section" i18n:translate="">Views</h2>
- <h2 class="details-section" i18n:translate="">Methods</h2>
+ <div class="indent">
- <div class="indent">
-
- <ul class="attr-list" tal:condition="view/getMethods">
- <li tal:repeat="method view/getMethods">
- <b><code
- tal:content="string:${method/name}${method/signature}" />
- </b><br>
- <div class="inline-documentation" tal:content="structure method/doc">
- method desc
- </div>
- </li>
- </ul>
-
- <p tal:condition="not: view/getMethods">
- <em i18n:translate="">There are no methods specified.</em>
- </p>
-
- </div>
-
-
-
- <h2 class="details-section" i18n:translate="">Adapters</h2>
+ <tal:block condition="view/browserViews">
+ <h3 class="details-section" i18n:translate="">Browser</h3>
+ <div class="indent">
+ <ul class="attr-list">
+ <li tal:repeat="View view/browserViews">
+ <metal:block use-macro="context/@@interface_macros/View" />
+ </li>
+ </ul>
+ </div>
+ </tal:block>
- <div class="indent"
- tal:define="adapters view/getRequiredAdapters"
- tal:condition="adapters">
+ <tal:block condition="view/xmlrpcViews">
+ <h3 class="details-section" i18n:translate="">XML-RPC</h3>
+ <div class="indent">
+ <ul class="attr-list">
+ <li tal:repeat="View view/xmlrpcViews">
+ <metal:block use-macro="context/@@interface_macros/View" />
+ </li>
+ </ul>
+ </div>
+ </tal:block>
+
+ <tal:block condition="view/httpViews">
+ <h3 class="details-section" i18n:translate="">HTTP</h3>
+ <div class="indent">
+ <ul class="attr-list">
+ <li tal:repeat="View view/httpViews">
+ <metal:block use-macro="context/@@interface_macros/View" />
+ </li>
+ </ul>
+ </div>
+ </tal:block>
+
+ <tal:block condition="view/ftpViews">
+ <h3 class="details-section" i18n:translate="">FTP</h3>
+ <div class="indent">
+ <ul class="attr-list">
+ <li tal:repeat="View view/ftpViews">
+ <metal:block use-macro="context/@@interface_macros/View" />
+ </li>
+ </ul>
+ </div>
+ </tal:block>
+
+ <tal:block condition="view/otherViews">
+ <h3 class="details-section" i18n:translate="">Other</h3>
+ <div class="indent">
+ <ul class="attr-list">
+ <li tal:repeat="View view/otherViews">
+ <metal:block use-macro="context/@@interface_macros/View" />
+ </li>
+ </ul>
+ </div>
+ </tal:block>
- <h3 i18n:translate="">Adapters where this interface is required:</h3>
- <ul class="attr-list">
- <li tal:repeat="adapter adapters">
- <b><code>
- <a href=""
- tal:attributes="href
- string:../../Class/${adapter/factory_url}/index.html"
- tal:content="adapter/factory"
- tal:condition="adapter/factory_url" />
- <span tal:content="adapter/factory"
- tal:condition="not: adapter/factory_url" />
- </code></b>
- <span tal:condition="adapter/name">
- (<span i18n:translate="">name:</span>
- <tal:block content="adapter/name" />)
- </span>
- <br />
- <tal:block condition="adapter/provided">
- <i i18n:translate="">provides:</i>
- <a href=""
- tal:attributes="href string:../${adapter/provided}/apiindex.html"
- tal:content="adapter/provided" /><br />
- </tal:block>
- <tal:block condition="adapter/required">
- <i i18n:translate="">also required:</i>
- <tal:block repeat="iface adapter/required">
- <a href=""
- tal:attributes="href string:../$iface/apiindex.html"
- tal:content="iface" /><tal:block
- condition="not:repeat/iface/end">, </tal:block>
- </tal:block>
- </tal:block>
- </li>
- </ul>
-
+ </div>
</div>
- <div class="indent"
- tal:define="adapters view/getProvidedAdapters"
- tal:condition="adapters">
-
- <h3 i18n:translate="">Adapters that provide this interface:</h3>
- <ul>
- <li tal:repeat="adapter adapters">
- <b><code>
- <a href=""
- tal:attributes="href
- string:../../Class/${adapter/factory_url}/index.html"
- tal:content="adapter/factory"
- tal:condition="adapter/factory_url" />
- <span tal:content="adapter/factory"
- tal:condition="not: adapter/factory_url" />
- </code></b>
- <span tal:condition="adapter/name">
- (<span i18n:translate="">name:</span>
- <tal:block content="adapter/name" />)
- </span>
- <br />
- <i i18n:translate="">requires:</i>
- <tal:block repeat="iface adapter/required">
- <a href=""
- tal:condition="iface"
- tal:attributes="href string:../$iface/"
- tal:content="iface" /><tal:block
- condition="not:repeat/iface/end">, </tal:block>
- <span tal:condition="not: iface" i18n:translate="">
- No interface required.
- </span>
- </tal:block>
- </li>
- </ul>
-
- </div>
-
- <p tal:condition="
- python: not (view.getRequiredAdapters() or view.getProvidedAdapters())">
- <em i18n:translate="">There are no adapters registered for
- this interface.</em>
- </p>
-
<div tal:define="factories view/getFactories;
- utilities view/getUtilitiesFor;
+ utilities view/getUtilities;
classes view/getClasses"
tal:condition="python: factories or utilities or classes">
@@ -212,11 +205,7 @@
</div>
<ul>
<li tal:repeat="factory factories">
- <a href=""
- tal:attributes="href string:../../Class/${factory/url}/"
- tal:content="factory/name" />
- <tal:block replace="string:(${factory/title})"
- condition="factory/title" />
+ <metal:block use-macro="context/@@interface_macros/factory" />
</li>
</ul>
</div>
@@ -231,17 +220,7 @@
</div>
<ul>
<li tal:repeat="utility utilities">
- <a href=""
- tal:attributes="href
- string:../../Utility/${view/getId}/${utility/url_name}/index.html"
- tal:content="structure utility/name" />
- <br />
- <div><span i18n:translate="">Class:</span> <code>
- <a href=""
- tal:attributes="href
- string:../../Class/${utility/url}/index.html"
- tal:content="utility/path" />
- </code></div>
+ <metal:block use-macro="context/@@interface_macros/utility" />
</li>
</ul>
</div>
@@ -256,12 +235,7 @@
</div>
<ul>
<li tal:repeat="klass classes">
- <b><code>
- <a href=""
- tal:attributes="href
- string:../../Class/${klass/url}/index.html"
- tal:content="klass/path" />
- </code></b>
+ <metal:block use-macro="context/@@interface_macros/class" />
</li>
</ul>
</div>
@@ -270,10 +244,5 @@
</div>
</div>
- <p>
- <em><b class="required">*</b> =
- <span i18n:translate="">required</span></em>
- </p>
-
</body>
</html>
Added: Zope3/trunk/src/zope/app/apidoc/ifacemodule/macros.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/macros.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/macros.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""API Documentation macros
+
+$Id: macros.py 25177 2004-06-02 13:17:31Z jim $
+"""
+from zope.app.basicskin.standardmacros import StandardMacros
+
+class InterfaceDetailsMacros(StandardMacros):
+ """Page Template METAL macros for Interfaces"""
+ macro_pages = ('iface_macros', 'component_macros', 'presentation_macros')
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -13,50 +13,13 @@
##############################################################################
"""Interface Module Browser Menu (Tree)
-A list of interfaces from the global site manager is pretty much unmanagable and
-is very confusing. Therefore it is nice to split the path of the interface, so
-that we get a deeper tree with nodes having shorter, manageable names.
-
$Id$
"""
__docformat__ = 'restructuredtext'
from zope.security.proxy import removeSecurityProxy
def getAllTextOfInterface(iface):
- """Get all searchable text from an interface
-
- Example:
-
- >>> import zope.interface
- >>> import zope.schema
- >>> class IFoo(zope.interface.Interface):
- ... '''foo'''
- ...
- ... def bar(self):
- ... '''bar'''
- ...
- ... blah = zope.interface.Attribute('blah', 'blah')
- ...
- ... field = zope.schema.Field(
- ... title = u'title', description = u'description')
-
- Now get the text. Note that there is no particular order during the text
- collection.
-
- >>> text = getAllTextOfInterface(IFoo)
- >>> u'foo' in text
- True
- >>> u'bar' in text
- True
- >>> u'blah' in text
- True
- >>> u'field' in text
- True
- >>> u'title' in text
- True
- >>> u'description' in text
- True
- """
+ """Get all searchable text from an interface"""
iface = removeSecurityProxy(iface)
text = iface.__doc__ or ''
for name in iface:
@@ -67,49 +30,11 @@
class Menu(object):
- """Menu for the Interface Documentation Module.
+ """Menu for the Interface Documentation Module."""
- The menu allows for looking for interfaces by full-text search or partial
- names. See `findInterfaces()` for the simple search implementation.
- """
-
def findInterfaces(self):
"""Find the interface that match any text in the documentation strings
- or a partial path.
-
- Before we can test the method, let's create a Menu instance:
-
- >>> from zope.interface.interfaces import IElement, IAttribute
-
- >>> menu = Menu()
- >>> menu.context = {'IElement': IElement, 'IAttribute': IAttribute}
- >>> menu.request = {'name_only': 'on', 'search_str': ''}
-
- Now let's see how successful our searches are:
-
- >>> from zope.app.apidoc.tests import pprint
- >>> menu.request['search_str'] = 'Elem'
- >>> pprint(menu.findInterfaces())
- [[('name', 'IElement'), ('url', './IElement/apiindex.html')]]
-
- >>> menu.request['search_str'] = 'I'
- >>> pprint(menu.findInterfaces())
- [[('name', 'IAttribute'), ('url', './IAttribute/apiindex.html')],
- [('name', 'IElement'), ('url', './IElement/apiindex.html')]]
-
- Now using the full text search:
-
- >>> del menu.request['name_only']
-
- >>> menu.request['search_str'] = 'object'
- >>> pprint(menu.findInterfaces())
- [[('name', 'IAttribute'), ('url', './IAttribute/apiindex.html')],
- [('name', 'IElement'), ('url', './IElement/apiindex.html')]]
-
- >>> menu.request['search_str'] = 'Stores'
- >>> pprint(menu.findInterfaces())
- [[('name', 'IAttribute'), ('url', './IAttribute/apiindex.html')]]
- """
+ or a partial path."""
name_only = ('name_only' in self.request) and True or False
search_str = self.request.get('search_str', None)
results = []
Added: Zope3/trunk/src/zope/app/apidoc/ifacemodule/presentation_macros.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/presentation_macros.pt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/presentation_macros.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,91 @@
+<metal:block define-macro="View">
+ <div>
+ <b tal:content="structure View/name" />
+ </div>
+
+ <span class="small">
+
+ <div tal:define="zcml View/zcml"
+ tal:condition="zcml">
+ <i i18n:translate="">registered:</i>
+ <metal:block use-macro="context/@@interface_macros/zcml" />
+ </div>
+
+ <div tal:define="iface View/type"
+ tal:condition="python: iface == View['required'][-1]">
+ <i i18n:translate="">presentation type:</i>
+ <a href=""
+ tal:attributes="href
+ string:../${iface/module}.${iface/name}/apiindex.html">
+ <metal:block use-macro="context/@@interface_macros/ifacename" />
+ </a>
+ </div>
+
+ <div tal:define="ifaces python:View['required'][:-1]">
+ <i i18n:translate="">requires:</i>
+ <tal:block repeat="iface ifaces">
+ <a href=""
+ tal:condition="iface"
+ tal:attributes="href
+ string:../${iface/module}.${iface/name}/apiindex.html">
+ <metal:block use-macro="context/@@interface_macros/ifacename"
+ /></a><tal:block condition="not:repeat/iface/end">, </tal:block>
+ </tal:block>
+ <span tal:condition="not: ifaces" i18n:translate="">
+ No interface required.
+ </span>
+ </div>
+
+ <div tal:define="iface View/provided"
+ tal:condition="iface">
+ <i i18n:translate="">provides:</i>
+ <a href=""
+ tal:attributes="href
+ string:../${iface/module}.${iface/name}/apiindex.html">
+ <metal:block use-macro="context/@@interface_macros/ifacename" />
+ </a>
+ </div>
+
+ <div tal:define="iface View/layer"
+ tal:condition="iface">
+ <i i18n:translate="">layer:</i>
+ <a href=""
+ tal:attributes="href
+ string:../${iface/module}.${iface/name}/apiindex.html">
+ <metal:block use-macro="context/@@interface_macros/ifacename" />
+ </a>
+ </div>
+
+ <div condition="View/factory/path">
+ <i i18n:translate="">factory path:</i>
+ <a href=""
+ tal:condition="View/factory/referencable"
+ tal:attributes="href
+ string: ../../Code/${View/factory/url}/index.html"
+ tal:content="View/factory/path" />
+ <span
+ tal:condition="not:View/factory/referencable"
+ tal:content="View/factory/path" />
+ </div>
+
+ <div tal:condition="View/factory/template">
+ <i i18n:translate="">template:</i>
+ <span tal:replace="View/factory/template" />
+ </div>
+
+ <div tal:condition="View/factory/resource">
+ <i i18n:translate="">resource:</i>
+ <a href=""
+ tal:attributes="href
+ string: /@@/${View/factory/resource}"
+ tal:content="View/factory/resource" />
+ </div>
+
+ <div tal:condition="View/read_perm">
+ <i i18n:translate="">Permission:</i>
+ <span tal:replace="View/read_perm">zope.View</span>
+ </div>
+
+ </span>
+
+</metal:block>
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/tests.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/tests.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -18,113 +18,42 @@
import unittest
from zope.component.interfaces import IFactory
-from zope.component.factory import Factory
-from zope.interface import implements, Interface, Attribute
from zope.interface.interfaces import IInterface
-from zope.publisher.browser import TestRequest
-from zope.schema import TextLine, Text
-from zope.testing.doctestunit import DocTestSuite
+from zope.testing import doctest, doctestunit
-from zope.app.component.interface import provideInterface
-from zope.app.location import LocationProxy
-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.interfaces import IContainmentRoot
-from zope.app.traversing.interfaces import IPhysicallyLocatable
+from zope.app.testing import placelesssetup, ztapi, setup
from zope.app.tree.interfaces import IUniqueId
from zope.app.tree.adapters import LocationUniqueId
-from zope.app.apidoc.classmodule import classRegistry
-from zope.app.apidoc.ifacemodule import IInterfaceModule, InterfaceModule
-from zope.app.apidoc.ifacemodule.browser import InterfaceDetails
-from zope.app.apidoc.interfaces import IDocumentationModule
-
-
-class Root(object):
- implements(IContainmentRoot)
-
- __parent__ = None
- __name__ = ''
-
-def rootLocation(obj, name):
- return LocationProxy(obj, Root(), name)
-
-class IFoo(Interface):
- """This is the Foo interface
-
- More description here...
- """
- foo = Attribute('This is foo.')
- bar = Attribute('This is bar.')
-
- title = TextLine(description=u'Title', required=True, default=u'Foo')
- description = Text(description=u'Desc', required=False, default=u'Foo.')
-
- def blah():
- """This is blah."""
-
- def get(key, default=None):
- """This is get."""
-
-class IBar(Interface):
- pass
-
-class Foo(object):
- implements(IFoo)
-
-
-def getInterfaceDetails():
- ifacemodule = InterfaceModule()
- ifacemodule.__parent__ = Root()
- ifacemodule.__name__ = 'Interfaces'
- iface = LocationProxy(IFoo, ifacemodule, 'IFoo')
- view = InterfaceDetails()
- view.context = iface
- view.request = TestRequest()
- return view
-
-
def setUp(test):
placelesssetup.setUp()
- provideInterface(None, IDocumentationModule)
- provideInterface('IInterfaceModule', IInterfaceModule)
+ setup.setUpTraversal()
+
ztapi.provideAdapter(IInterface, IUniqueId, LocationUniqueId)
- ztapi.provideAdapter(None, IPhysicallyLocatable,
- LocationPhysicallyLocatable)
# 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)
+ # Cheat and register the ReST factory for STX as well
+ ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory,
+ 'zope.source.stx')
- # Make IFoo adapter interesting.
-
- ztapi.provideAdapter(IBar, IFoo, object)
- classRegistry[Foo.__module__ + '.' + Foo.__name__] = Foo
- ztapi.provideUtility(IFactory, Factory(Foo, title='Foo Factory'),
- 'FooFactory')
- ztapi.provideUtility(IFoo, Foo(), 'The Foo')
-
def test_suite():
return unittest.TestSuite((
- DocTestSuite('zope.app.apidoc.ifacemodule',
- setUp=setUp, tearDown=placelesssetup.tearDown),
- DocTestSuite('zope.app.apidoc.ifacemodule.menu',
- setUp=setUp, tearDown=placelesssetup.tearDown),
- DocTestSuite('zope.app.apidoc.ifacemodule.browser',
- setUp=setUp, tearDown=placelesssetup.tearDown),
+ doctest.DocFileSuite('README.txt',
+ setUp=setUp, tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ doctest.DocFileSuite('browser.txt',
+ setUp=setUp, tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
))
if __name__ == '__main__':
Added: Zope3/trunk/src/zope/app/apidoc/interface.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/interface.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/interface.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,135 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Interface Inspection Utilities
+
+$Id: browser.py 29199 2005-02-17 22:38:55Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.interface import Interface, providedBy
+from zope.interface.interfaces import IInterface, ISpecification
+from zope.interface.interfaces import IElement, IAttribute, IMethod
+from zope.schema.interfaces import IField
+
+from zope.app.apidoc.utilities import getPythonPath, renderText
+
+
+def getElements(iface, type=IElement):
+ """Return a dictionary containing the elements in an interface.
+
+ The type specifies whether we are looking for attributes or methods."""
+ items = {}
+ for name in iface:
+ attr = iface[name]
+ if type.providedBy(attr):
+ items[name] = attr
+ return items
+
+
+def getFieldsInOrder(iface,
+ _itemsorter=lambda x, y: cmp(x[1].order, y[1].order)):
+ """Return a list of (name, field) tuples in native interface order."""
+ items = getElements(iface, IField).items()
+ items.sort(_itemsorter)
+ return items
+
+
+def getAttributes(iface):
+ """Returns a list of attributes specified in the interface."""
+ return [(name, attr)
+ for name, attr in getElements(iface, IAttribute).items()
+ if not (IField.providedBy(attr) or IMethod.providedBy(attr))]
+
+
+def getMethods(iface):
+ """Returns a list of methods specified in the interface."""
+ return getElements(iface, IMethod).items()
+
+
+def getFields(iface):
+ """Returns a list of fields specified in the interface."""
+ return getFieldsInOrder(iface)
+
+
+def getInterfaceTypes(iface):
+ """Return a list of interface types that are specified for this
+ interface.
+
+ Note that you should only expect one type at a time.
+ """
+ types = list(providedBy(iface).flattened())
+ # Remove interfaces provided by every interface instance
+ types.remove(ISpecification)
+ types.remove(IElement)
+ types.remove(Interface)
+ # Remove interface provided by every interface type
+ types.remove(IInterface)
+ return types
+
+
+def getFieldInterface(field):
+ """Return the interface representing the field."""
+ name = field.__class__.__name__
+ field_iface = None
+ ifaces = tuple(providedBy(field).flattened())
+ for iface in ifaces:
+ # All field interfaces implement `IField`. In case the name match
+ # below does not work, use the first `IField`-based interface found
+ if field_iface is None and iface.extends(IField):
+ field_iface = iface
+
+ # Usually fields have interfaces with the same name (with an 'I')
+ if iface.getName() == 'I' + name:
+ return iface
+
+ # If not even a `IField`-based interface was found, return the first
+ # interface of the implemented interfaces list.
+ return field_iface or ifaces[0]
+
+
+def getAttributeInfoDictionary(attr, format='zope.source.rest'):
+ """Return a page-template-friendly information dictionary."""
+ return {'name': attr.getName(),
+ 'doc': renderText(attr.getDoc() or u'', format=format)}
+
+
+def getMethodInfoDictionary(method, format='zope.source.rest'):
+ """Return a page-template-friendly information dictionary."""
+ return {'name': method.getName(),
+ 'signature': method.getSignatureString(),
+ 'doc': renderText(method.getDoc() or u'', format=format)}
+
+
+def getFieldInfoDictionary(field, format='zope.source.rest'):
+ """Return a page-template-friendly information dictionary."""
+
+ info = {'name': field.getName(),
+ 'required': field.required,
+ 'required_string': field.required and u'required' or u'optional',
+ 'default': repr(field.default),
+ 'title': field.title}
+
+ # Determine the interface of the field
+ iface = getFieldInterface(field)
+ info['iface'] = {'name': iface.getName(), 'id': getPythonPath(iface)}
+
+ # Determine the field class
+ class_ = field.__class__
+ info['class'] = {'name': class_.__name__,
+ 'path': getPythonPath(class_).replace('.', '/')}
+
+ # Render the field description
+ info['description'] = renderText(field.description or u'', format=format)
+
+ return info
Added: Zope3/trunk/src/zope/app/apidoc/interface.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/interface.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/interface.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,249 @@
+==============================
+Interface Inspection Utilities
+==============================
+
+This document is a presentation of the utility functions provided by
+
+ >>> from zope.app.apidoc import interface
+
+For the following demonstrations, we need a nice interface that we can inspect:
+
+ >>> from zope.interface import Interface, Attribute
+ >>> from zope.schema import Field, TextLine
+
+ >>> class IFoo(Interface):
+ ... foo = Field(title=u"Foo")
+ ...
+ ... bar = TextLine(title=u"Bar",
+ ... description=u"The Bar",
+ ... required=True,
+ ... default=u"My Bar")
+ ...
+ ... baz = Attribute('baz',
+ ... 'This is the baz attribute')
+ ...
+ ... def blah(one, two, three=None, *args, **kwargs):
+ ... """This is the `blah` method."""
+
+
+`getElements(iface, type=IElement)`
+-----------------------------------
+
+Return a dictionary containing all elements in an interface. The type
+specifies whether we are looking for attributes, fields or methods. So let's
+look at an example.
+
+First, let's get the methods of an interface:
+
+ >>> from zope.interface.interfaces import IMethod
+ >>> interface.getElements(IFoo, type=IMethod).keys()
+ ['blah']
+
+and now the fields:
+
+ >>> from zope.schema.interfaces import IField
+ >>> names = interface.getElements(IFoo, type=IField).keys()
+ >>> names.sort()
+ >>> names
+ ['bar', 'foo']
+
+We can also get all attributes of course.
+
+ >>> from zope.interface.interfaces import IAttribute
+ >>> names = interface.getElements(IFoo, type=IAttribute).keys()
+ >>> names.sort()
+ >>> names
+ ['bar', 'baz', 'blah', 'foo']
+
+You might be surprised by the above result, since the fields and methods are
+again included. However, fields and methods are just attributes and thus
+extend the simple attribute implementation. If you want to get a list of
+attributes that does not include fields and methods, see the
+`getAttributes(iface)` function.
+
+The default type is `IElement` which will simply return all elements of the
+interface:
+
+ >>> names = interface.getElements(IFoo).keys()
+ >>> names.sort()
+ >>> names
+ ['bar', 'baz', 'blah', 'foo']
+
+Note: The interface you pass to this function *cannot* be proxied!
+Presentation code often like to wrap interfaces in security proxies and apidoc
+even uses location proxies for interface.
+
+
+`getFieldsInOrder(iface, _itemsorter=...)`
+-----------------------------------------------------------
+
+For presentation purposes we often want fields to have the a certain order,
+most comonly the order they have in the interface. This function returns a
+list of (name, field) tuples in a specified order.
+
+The `_itemsorter` argument provides the function that is used to order the
+fields. The default function, which sorts by the fields' `order` attribute,
+should be the correct one for 99% of your needs.
+
+Reusing the interface created above, we check the output:
+
+ >>> [n for n, a in interface.getFieldsInOrder(IFoo)]
+ ['foo', 'bar']
+
+By changing the sort method to sort by names, we get:
+
+ >>> [n for n, a in interface.getFieldsInOrder(
+ ... IFoo, _itemsorter=lambda x, y: cmp(x[0], y[0]))]
+ ['bar', 'foo']
+
+
+`getAttributes(iface)`
+----------------------
+
+This function returns a (name, attr) tuple for every attribute in the
+interface. Note that this function will only return pure attributes; it
+ignores methods and fields.
+
+ >>> attrs = interface.getAttributes(IFoo)
+ >>> attrs.sort()
+ >>> attrs #doctest: +ELLIPSIS
+ [('baz', <zope.interface.interface.Attribute object at ...>)]
+
+
+`getMethods(iface)`
+-------------------
+
+This function returns a (name, method) tuple for every declared method in the
+interface.
+
+ >>> methods = interface.getMethods(IFoo)
+ >>> methods.sort()
+ >>> methods #doctest: +ELLIPSIS
+ [('blah', <zope.interface.interface.Method object at ...>)]
+
+
+`getFields(iface)`
+------------------
+
+This function returns a (name, field) tuple for every declared field in the
+interface.
+
+ >>> interface.getFields(IFoo) #doctest: +ELLIPSIS
+ [('foo', <zope.schema._bootstrapfields.Field object at ...>),
+ ('bar', <zope.schema._bootstrapfields.TextLine object at ...>)]
+
+Note that this returns the same result as `getFieldsInOrder()` with the fields
+sorted by their `order` attribute, except that you cannot specify the sort
+function here. This function was mainly provided for symmetry with the other
+functions.
+
+
+`getInterfaceTypes(iface)`
+--------------------------
+
+Interfaces can be categorized/grouped by using interface types. Interface
+types simply extend `zope.interface.interfaces.IInterface`, which are
+basically meta-interfaces. The interface types are then provided by particular
+interfaces.
+
+The `getInterfaceTypes()` function returns a list of interface types that are
+provided for the specified interface. Note that you commonly expect only one
+type per interface, though.
+
+Before we assign any type to our `IFoo` interface, there are no types
+declared.
+
+ >>> interface.getInterfaceTypes(IFoo)
+ []
+
+Now we define a new type called `IContentType`
+
+ >>> from zope.interface.interfaces import IInterface
+ >>> class IContentType(IInterface):
+ ... pass
+
+and have our interface provide it:
+
+ >>> from zope.interface import directlyProvides
+ >>> directlyProvides(IFoo, IContentType)
+
+Note that ZCML has some more convenient methods of doing this. Now let's get
+the interface types again:
+
+ >>> interface.getInterfaceTypes(IFoo)
+ [<InterfaceClass __builtin__.IContentType>]
+
+Again note that the interface passed to this function *cannot* be proxied,
+otherwise this method will pick up the proxy's interfaces as well.
+
+
+`getFieldInterface(field)`
+--------------------------
+
+This function tries pretty hard to determine the best-matching interface that
+represents the field. Commonly the field class has the same name as the field
+interface (minus an "I"). So this is our first choice:
+
+ >>> from zope.schema import Text, Int
+ >>> interface.getFieldInterface(Text())
+ <InterfaceClass zope.schema.interfaces.IText>
+
+ >>> interface.getFieldInterface(Int())
+ <InterfaceClass zope.schema.interfaces.IInt>
+
+If the name matching method fails, it picks the first interface that extends
+`IField`:
+
+ >>> from zope.schema.interfaces import IField
+ >>> class ISpecialField(IField):
+ ... pass
+ >>> class ISomething(Interface):
+ ... pass
+
+ >>> from zope.interface import implements
+ >>> class MyField:
+ ... implements(ISomething, ISpecialField)
+
+ >>> interface.getFieldInterface(MyField())
+ <InterfaceClass __builtin__.ISpecialField>
+
+
+`getAttributeInfoDictionary(attr, format='restructuredtext')`
+-------------------------------------------------------------
+
+This function returns a page-template-friendly dictionary for a simple
+attribute:
+
+ >>> pprint(interface.getAttributeInfoDictionary(IFoo['baz']))
+ {'doc': u'<div class="document">\nThis is the baz attribute</div>\n',
+ 'name': 'baz'}
+
+
+`getMethodInfoDictionary(method, format='restructuredtext')`
+-------------------------------------------------------------
+
+This function returns a page-template-friendly dictionary for a method:
+
+ >>> pprint(interface.getMethodInfoDictionary(IFoo['blah'])) #doc
+ {'doc':
+ u'<div class="document">\nThis is the <cite>blah</cite> method.</div>\n',
+ 'name': 'blah',
+ 'signature': '(one, two, three=None, *args, **kwargs)'}
+
+
+`getFieldInfoDictionary(field, format='restructuredtext')`
+----------------------------------------------------------
+
+This function returns a page-template-friendly dictionary for a field:
+
+ >>> pprint(interface.getFieldInfoDictionary(IFoo['bar']))
+ {'class': {'name': 'TextLine',
+ 'path': 'zope/schema/_bootstrapfields/TextLine'},
+ 'default': "u'My Bar'",
+ 'description': u'<div class="document">\nThe Bar</div>\n',
+ 'iface': {'id': 'zope.schema.interfaces.ITextLine',
+ 'name': 'ITextLine'},
+ 'name': 'bar',
+ 'required': True,
+ 'required_string': u'required',
+ 'title': u'Bar'}
\ No newline at end of file
Added: Zope3/trunk/src/zope/app/apidoc/presentation.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/presentation.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/presentation.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,160 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Views/Presentation Utilities
+
+$Id$
+"""
+from types import ClassType, FunctionType
+from zope.component.site import AdapterRegistration
+from zope.interface import Interface
+
+from zope.app import zapi
+from zope.app.apidoc.utilities import getPythonPath, relativizePath
+from zope.app.apidoc.utilities import getPermissionIds
+from zope.app.apidoc.component import getParserInfoInfoDictionary
+from zope.app.apidoc.component import getInterfaceInfoDictionary
+from zope.app.publisher.browser.icon import IconViewFactory
+
+from zope.publisher.interfaces import IRequest, ILayer
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.publisher.interfaces.xmlrpc import IXMLRPCRequest
+from zope.publisher.interfaces.http import IHTTPRequest
+from zope.publisher.interfaces.ftp import IFTPRequest
+
+SPECIFIC_INTERFACE_LEVEL = 1
+EXTENDED_INTERFACE_LEVEL = 2
+GENERIC_INTERFACE_LEVEL = 4
+
+def getViewFactoryData(factory):
+ """Squeeze some useful information out of the view factory"""
+ info = {'path': None, 'url': None, 'template': None, 'resource': None,
+ 'referencable': True}
+
+ if hasattr(factory, '__name__') and \
+ factory.__name__.startswith('SimpleViewClass'):
+ # In the case of a SimpleView, the base is really what we are
+ # interested in. Usually the first listed class is the interesting one.
+ base = factory.__bases__[0]
+ info['path'] = base.__module__ + '.' + base.__name__
+ info['template'] = relativizePath(factory.index.filename)
+
+ elif isinstance(factory, (str, unicode, float, int, list, tuple)):
+ info['referencable'] = False
+
+ elif factory.__module__.startswith('zope.app.publisher.browser.viewmeta'):
+ info['path'] = getPythonPath(factory.__bases__[0])
+
+ elif hasattr(factory, '__class__') and \
+ factory.__class__.__name__ == 'ProxyView':
+ factory = factory.factory
+ info['path'] = factory.__module__ + '.' + factory.__name__
+
+ elif not hasattr(factory, '__name__'):
+ info['path'] = getPythonPath(factory.__class__)
+
+ elif type(factory) in (type, ClassType):
+ info['path'] = getPythonPath(factory)
+
+ elif isinstance(factory, FunctionType):
+ info['path'] = getPythonPath(factory.factory)
+ else:
+ info['path'] = getPythonPath(factory)
+
+ if info['referencable']:
+ info['url'] = info['path'].replace('.', '/')
+
+ if isinstance(factory, IconViewFactory):
+ info['resource'] = factory.rname
+
+ return info
+
+
+def getPresentationType(iface):
+ """Get the presentation type from a layer interface."""
+ # Note that the order of the requests matters here, since we want to
+ # inspect the most specific one first. For example, IBrowserRequest is also
+ # an IHTTPRequest.
+ for type in [IBrowserRequest, IXMLRPCRequest, IHTTPRequest, IFTPRequest]:
+ if iface.isOrExtends(type):
+ return type
+ return iface
+
+
+def getViews(iface, type=IRequest):
+ """Get all view registrations for a particular interface."""
+ gsm = zapi.getGlobalSiteManager()
+ for reg in gsm.registrations():
+ if (isinstance(reg, AdapterRegistration) and
+ reg.required[-1] is not None and
+ reg.required[-1].isOrExtends(type)):
+
+ for required_iface in reg.required[:-1]:
+ if iface.isOrExtends(required_iface):
+ yield reg
+
+
+def filterViewRegistrations(regs, iface, level=SPECIFIC_INTERFACE_LEVEL):
+ """Return only those registrations that match the specifed level"""
+ for reg in regs:
+ if level & GENERIC_INTERFACE_LEVEL:
+ for required_iface in reg.required[:-1]:
+ if required_iface in (Interface, None):
+ yield reg
+ continue
+
+ if level & EXTENDED_INTERFACE_LEVEL:
+ for required_iface in reg.required[:-1]:
+ if required_iface is not Interface and \
+ iface.extends(required_iface):
+ yield reg
+ continue
+
+ if level & SPECIFIC_INTERFACE_LEVEL:
+ for required_iface in reg.required[:-1]:
+ if required_iface is iface:
+ yield reg
+ continue
+
+
+def getViewInfoDictionary(reg):
+ """Build up an information dictionary for a view registration."""
+ # get configuration info
+ if isinstance(reg.doc, (str, unicode)):
+ doc = reg.doc
+ zcml = None
+ else:
+ doc = None
+ zcml = getParserInfoInfoDictionary(reg.doc)
+
+ # get layer
+ layer = None
+ if ILayer.providedBy(reg.required[-1]):
+ layer = getInterfaceInfoDictionary(reg.required[-1])
+
+
+ info = {'name' : reg.name or '<i>no name</i>',
+ 'type' : getPythonPath(getPresentationType(reg.required[-1])),
+ 'factory' : getViewFactoryData(reg.value),
+ 'required': [getInterfaceInfoDictionary(iface)
+ for iface in reg.required],
+ 'provided' : getInterfaceInfoDictionary(reg.provided),
+ 'layer': layer,
+ 'doc': doc,
+ 'zcml': zcml
+ }
+
+ # Educated guess of the attribute name
+ info.update(getPermissionIds('publishTraverse', klass=reg.value))
+
+ return info
Added: Zope3/trunk/src/zope/app/apidoc/presentation.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/presentation.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/presentation.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,293 @@
+=================================
+Presentation Inspection Utilities
+=================================
+
+The `presentation` module provides some nice utilities to inspect presentation
+registrations.
+
+ >>> from zope.app.apidoc import presentation
+
+
+`getViewFactoryData(factory)`
+-----------------------------
+
+This function tries really hard to determine the correct information about a
+view factories. For example, when you create a page, a new type is dynamically
+generated upon generation. Let's look at a couple examples.
+
+First, let's look at a case where a simple browser page was configured without
+a special view class. In these cases the factory is a `SimpleViewClass`:
+
+ >>> from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
+ >>> view = SimpleViewClass('browser/index.pt')
+ >>> info = presentation.getViewFactoryData(view)
+
+Before we can check the result, we have to make sure that all Windows paths
+are converted to Unix-like paths. We also clip off instance-specific parts of
+the template path:
+
+ >>> info['template'] = info['template'].replace('\\\\', '/')[-32:]
+ >>> pprint(info)
+ {'path': 'zope.app.pagetemplate.simpleviewclass.simple',
+ 'referencable': True,
+ 'resource': None,
+ 'template': 'zope/app/apidoc/browser/index.pt',
+ 'url': 'zope/app/pagetemplate/simpleviewclass/simple'}
+
+So in the result above we see what the function returns. It is a dictionary
+(converted to a list for test purposes) that contains the Python path of the
+view class, a flag that specifies whether the factory can be referenced and
+thus be viewed by the class browser, the (page) template used for the view and
+the URL under which the factory will be found in the class browser. Some
+views, like icons, also use resources to provide their data. In these cases
+the name of the resource will be provided. Of course, not in all cases all
+values will be available. Empty values are marked with `None`.
+
+Believe it or not, in some cases the factory is just a simple type. In these
+cases we cannot retrieve any useful information:
+
+ >>> info = presentation.getViewFactoryData(3)
+ >>> pprint(info)
+ {'path': None,
+ 'referencable': False,
+ 'resource': None,
+ 'template': None,
+ 'url': None}
+
+In some cases factories are callable class instances, where we cannot directly
+have a referencable name, so we lookup the class and use its name:
+
+ >>> class Factory(object):
+ ... pass
+
+ >>> info = presentation.getViewFactoryData(Factory())
+ >>> pprint(info)
+ {'path': '__builtin__.Factory',
+ 'referencable': True,
+ 'resource': None,
+ 'template': None,
+ 'url': '__builtin__/Factory'}
+
+One of the more common cases, however, is that the factory is a class or
+type. In this case we can just retrieve the reference directly:
+
+ >>> info = presentation.getViewFactoryData(Factory)
+ >>> pprint(info)
+ {'path': '__builtin__.Factory',
+ 'referencable': True,
+ 'resource': None,
+ 'template': None,
+ 'url': '__builtin__/Factory'}
+
+
+`getPresentationType(iface)`
+----------------------------
+
+In Zope 3, presentation types (i.e. browser, ftp, ...) are defined through
+their special request interface, such as `IBrowserRequest` or
+`IFTPRequest`. To complicate matters further, layer interfaces are used in
+browser presentations to allow skinning. Layers extend any request type, but
+most commonly `IBrowserRequest`. This function inspects the request interface
+of any presentation multi-adapter and determines its type, which is returned
+in form of an interface.
+
+ >>> from zope.app.apidoc.presentation import getPresentationType
+ >>> from zope.publisher.interfaces.http import IHTTPRequest
+ >>> from zope.publisher.interfaces.browser import IBrowserRequest
+
+ >>> class ILayer1(IBrowserRequest):
+ ... pass
+
+ >>> presentation.getPresentationType(ILayer1)
+ <InterfaceClass zope.publisher.interfaces.browser.IBrowserRequest>
+
+ >>> class ILayer2(IHTTPRequest):
+ ... pass
+
+ >>> presentation.getPresentationType(ILayer2)
+ <InterfaceClass zope.publisher.interfaces.http.IHTTPRequest>
+
+If the function cannot determine the presentation type, the interface itself
+is returned:
+
+ >>> from zope.interface import Interface
+ >>> class ILayer3(Interface):
+ ... pass
+
+ >>> presentation.getPresentationType(ILayer3)
+ <InterfaceClass __builtin__.ILayer3>
+
+Note that more specific presentation types are considered first. For example,
+`IBrowserRequest` extends `IHTTPRequest`, but it will always determine the
+presentation type to be an `IBrowserRequest`.
+
+
+`getViews(iface, type=IRequest)`
+--------------------------------
+
+This function retrieves all available view registrations for a given interface
+and presentation type. The default argument for the presentation type is
+`IRequest`, which will effectively return all views for the specified
+interface.
+
+To see how this works, we first have to register some views:
+
+ >>> class IFoo(Interface):
+ ... pass
+
+ >>> from zope.app.testing import ztapi
+ >>> ztapi.provideAdapter((IFoo, IHTTPRequest), Interface, None, name='foo')
+ >>> ztapi.provideAdapter((Interface, IHTTPRequest), Interface, None,
+ ... name='bar')
+ >>> ztapi.provideAdapter((IFoo, IBrowserRequest), Interface, None,
+ ... name='blah')
+
+Now let's see what we've got. If we do not specify a type, all registrations
+should be returned:
+
+ >>> regs = list(presentation.getViews(IFoo))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('IFoo', 'IBrowserRequest'), 'Interface',
+ 'blah', None, ''),
+ AdapterRegistration(('IFoo', 'IHTTPRequest'), 'Interface',
+ 'foo', None, ''),
+ AdapterRegistration(('Interface', 'IHTTPRequest'), 'Interface',
+ 'bar', None, '')]
+
+ >>> regs = list(presentation.getViews(Interface, IHTTPRequest))
+ >>> regs.sort()
+ >>> regs
+ [AdapterRegistration(('Interface', 'IHTTPRequest'), 'Interface',
+ 'bar', None, '')]
+
+
+`filterViewRegistrations(regs, iface, level=SPECIFC_INTERFACE_LEVEL)`
+---------------------------------------------------------------------
+
+Oftentimes the amount of views that are being returned for a particular
+interface are too much to show at once. It is then good to split the view into
+categories. The `filterViewRegistrations()` function allows you to filter the
+views on how specific they are to the interface. Here are the three levels you
+can select from:
+
+ * SPECIFC_INTERFACE_LEVEL -- Only return registrations that require the
+ specified interface directly.
+
+ * EXTENDED_INTERFACE_LEVEL -- Only return registrations that require an
+ interface that the specified interface extends.
+
+ * GENERIC_INTERFACE_LEVEL -- Only return registrations that explicitely
+ require the `Interface` interface.
+
+So, let's see how this is done. We first need to create a couple of interfaces
+and register some views:
+
+ >>> class IContent(Interface):
+ ... pass
+ >>> class IFile(IContent):
+ ... pass
+
+ Clear out the registries first, so we know what we have.
+ >>> from zope.testing.cleanup import cleanUp
+ >>> cleanUp()
+
+ >>> ztapi.provideAdapter((IContent, IHTTPRequest), Interface,
+ ... None, name='view.html')
+ >>> ztapi.provideAdapter((IContent, IHTTPRequest), Interface,
+ ... None, name='edit.html')
+ >>> ztapi.provideAdapter((IFile, IHTTPRequest), Interface,
+ ... None, name='view.html')
+ >>> ztapi.provideAdapter((Interface, IHTTPRequest), Interface,
+ ... None, name='view.html')
+
+Now we get all the registrations:
+
+ >>> regs = list(presentation.getViews(IFile, IHTTPRequest))
+
+Let's now filter those registrations:
+
+ >>> result = list(presentation.filterViewRegistrations(
+ ... regs, IFile, level=presentation.SPECIFIC_INTERFACE_LEVEL))
+ >>> result.sort()
+ >>> result
+ [AdapterRegistration(('IFile', 'IHTTPRequest'), 'Interface',
+ 'view.html', None, '')]
+
+ >>> result = list(presentation.filterViewRegistrations(
+ ... regs, IFile, level=presentation.EXTENDED_INTERFACE_LEVEL))
+ >>> result.sort()
+ >>> result
+ [AdapterRegistration(('IContent', 'IHTTPRequest'), 'Interface', 'edit.html',
+ None, ''),
+ AdapterRegistration(('IContent', 'IHTTPRequest'), 'Interface', 'view.html',
+ None, '')]
+
+ >>> result = list(presentation.filterViewRegistrations(
+ ... regs, IFile, level=presentation.GENERIC_INTERFACE_LEVEL))
+ >>> result.sort()
+ >>> result
+ [AdapterRegistration(('Interface', 'IHTTPRequest'), 'Interface', 'view.html',
+ None, '')]
+
+You can also specify multiple levels at once using the Boolean OR operator,
+since all three levels are mutually exclusive.
+
+ >>> result = list(presentation.filterViewRegistrations(
+ ... regs, IFile, level=presentation.SPECIFIC_INTERFACE_LEVEL |
+ ... presentation.EXTENDED_INTERFACE_LEVEL))
+ >>> result.sort()
+ >>> result
+ [AdapterRegistration(('IContent', 'IHTTPRequest'), 'Interface',
+ 'edit.html', None, ''),
+ AdapterRegistration(('IContent', 'IHTTPRequest'), 'Interface',
+ 'view.html', None, ''),
+ AdapterRegistration(('IFile', 'IHTTPRequest'), 'Interface',
+ 'view.html', None, '')]
+
+ >>> result = list(presentation.filterViewRegistrations(
+ ... regs, IFile, level=presentation.SPECIFIC_INTERFACE_LEVEL |
+ ... presentation.GENERIC_INTERFACE_LEVEL))
+ >>> result.sort()
+ >>> result
+ [AdapterRegistration(('IFile', 'IHTTPRequest'), 'Interface',
+ 'view.html', None, ''),
+ AdapterRegistration(('Interface', 'IHTTPRequest'), 'Interface',
+ 'view.html', None, '')]
+
+
+`getViewInfoDictionary(reg)`
+----------------------------
+
+Now that we have all these utilities to select the registrations, we need to
+prepare the them for output. For page templates the best data structures are
+dictionaries and tuples/lists. This utility will generate an informational
+dictionary for the specified registration.
+
+Let's first create a registration:
+
+ >>> from zope.component.site import AdapterRegistration
+ >>> reg = AdapterRegistration((IFile, Interface, IHTTPRequest),
+ ... Interface, 'view.html', Factory, 'reg info')
+
+ >>> pprint(presentation.getViewInfoDictionary(reg))
+ {'doc': 'reg info',
+ 'factory': {'path': '__builtin__.Factory',
+ 'referencable': True,
+ 'resource': None,
+ 'template': None,
+ 'url': '__builtin__/Factory'},
+ 'layer': None,
+ 'name': 'view.html',
+ 'provided': {'module': 'zope.interface',
+ 'name': 'Interface'},
+ 'read_perm': None,
+ 'required': [{'module': '__builtin__',
+ 'name': 'IFile'},
+ {'module': 'zope.interface',
+ 'name': 'Interface'},
+ {'module': 'zope.publisher.interfaces.http',
+ 'name': 'IHTTPRequest'}],
+ 'type': 'zope.publisher.interfaces.http.IHTTPRequest',
+ 'write_perm': None,
+ 'zcml': None}
Modified: Zope3/trunk/src/zope/app/apidoc/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/tests.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/tests.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -19,14 +19,12 @@
import unittest
from zope.component.interfaces import IFactory
+from zope.interface import implements
+from zope.testing import doctest, doctestunit
+
from zope.app.traversing.interfaces import IContainmentRoot
from zope.app.location import LocationProxy
from zope.app.testing import placelesssetup, ztapi
-from zope.interface import implements
-from zope.app.apidoc.interfaces import IDocumentationModule
-from zope.app.apidoc.ifacemodule import InterfaceModule
-from zope.app.apidoc.zcmlmodule import ZCMLModule
-from zope.testing.doctestunit import DocTestSuite
from zope.app.renderer.rest import ReStructuredTextSourceFactory
from zope.app.renderer.rest import IReStructuredTextSource
@@ -35,15 +33,16 @@
def setUp(test):
placelesssetup.setUp()
- ztapi.provideUtility(IDocumentationModule, InterfaceModule(),
- 'Interface')
- ztapi.provideUtility(IDocumentationModule, ZCMLModule(), 'ZCML')
-
# Register Renderer Components
ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory,
'zope.source.rest')
ztapi.browserView(IReStructuredTextSource, '',
ReStructuredTextToHTMLRenderer)
+ # Cheat and register the ReST renderer as the STX one as well.
+ ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory,
+ 'zope.source.stx')
+ ztapi.browserView(IReStructuredTextSource, '',
+ ReStructuredTextToHTMLRenderer)
# Generally useful classes and functions
@@ -57,60 +56,40 @@
def rootLocation(obj, name):
return LocationProxy(obj, Root(), name)
-
-def _convertToSortedSequence(obj):
- """Convert data structures containing dictionaries to data structures
- using sequences only.
-
- Examples::
-
- >>> _convertToSortedSequence(())
- ()
- >>> _convertToSortedSequence({})
- []
- >>> _convertToSortedSequence({'foo': 1})
- [('foo', 1)]
- >>> _convertToSortedSequence({'foo': 1, 'bar': 2})
- [('bar', 2), ('foo', 1)]
- >>> _convertToSortedSequence({'foo': {1: 'a'}, 'bar': 2})
- [('bar', 2), ('foo', [(1, 'a')])]
- """
-
- # Handle incoming sequences
- if isinstance(obj, (tuple, list)):
- objtype = type(obj)
- result = []
- for value in obj:
- result.append(_convertToSortedSequence(value))
- return objtype(result)
-
- # Handle Dictionaries
- if isinstance(obj, dict):
- result = []
- for key, value in obj.items():
- result.append((key, _convertToSortedSequence(value)))
- result.sort()
- return result
-
- return obj
-
-
-def pprint(info):
- """Print a datastructure in a nice format."""
- info = _convertToSortedSequence(info)
- return PrettyPrinter(width=69).pprint(info)
-
-
-
+
def test_suite():
return unittest.TestSuite((
- DocTestSuite('zope.app.apidoc',
- setUp=setUp, tearDown=placelesssetup.tearDown),
- DocTestSuite('zope.app.apidoc.browser.apidoc',
- setUp=setUp, tearDown=placelesssetup.tearDown),
- DocTestSuite('zope.app.apidoc.utilities'),
- DocTestSuite('zope.app.apidoc.tests'),
+ doctest.DocTestSuite('zope.app.apidoc.browser.apidoc',
+ setUp=setUp, tearDown=placelesssetup.tearDown),
+ doctest.DocFileSuite('README.txt',
+ setUp=setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ doctest.DocFileSuite('classregistry.txt',
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ doctest.DocFileSuite('interface.txt',
+ setUp=setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ doctest.DocFileSuite('component.txt',
+ setUp=setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ doctest.DocFileSuite('presentation.txt',
+ setUp=placelesssetup.setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ doctest.DocFileSuite('utilities.txt',
+ setUp=setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
))
if __name__ == '__main__':
- unittest.main()
+ unittest.main(default="test_suite")
Modified: Zope3/trunk/src/zope/app/apidoc/utilities.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilities.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilities.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -46,46 +46,7 @@
class ReadContainerBase(object):
- """Base for `IReadContainer` objects.
-
- This is a base class that minimizes the implementation of an
- `IReadContainer` to two methods, `get()` and `items()`, since the other
- methods can be implemented using these two.
-
- Demonstration::
-
- Make a sample implementation first
-
- >>> class Container(ReadContainerBase):
- ... def get(self, key, default=None):
- ... return {'a': 1, 'b': 2}.get(key, default)
- ... def items(self):
- ... return [('a', 1), ('b', 2)]
-
- >>> container = Container()
-
- Now we can use the methods
-
- >>> container.get('a')
- 1
- >>> container.get('c') is None
- True
- >>> container['b']
- 2
-
- >>> container.items()
- [('a', 1), ('b', 2)]
- >>> container.keys()
- ['a', 'b']
- >>> container.values()
- [1, 2]
-
- >>> 1 in container
- True
- >>> len(container)
- 2
- """
-
+ """Base for `IReadContainer` objects."""
implements(IReadContainer)
def get(self, key, default=None):
@@ -102,7 +63,7 @@
return obj
def __contains__(self, key):
- return self.get(key) is None
+ return self.get(key) is not None
def keys(self):
return map(lambda x: x[0], self.items())
@@ -118,40 +79,7 @@
def getPythonPath(obj):
- """Return the path of the object in standard Python notation.
-
- This method makes only sense for classes and interfaces. Instances do not
- have a `__name__` attribute, so we would expect them to fail.
-
- If a method is passed in, its class path is returned, since this is the
- only path we have a page for.
-
- Example::
-
- >>> from zope.interface import Interface
- >>> class ISample(Interface):
- ... pass
- >>> class Sample(object):
- ... def sample(self):
- ... pass
-
- >>> getPythonPath(ISample)
- 'zope.app.apidoc.utilities.ISample'
-
- >>> getPythonPath(Sample)
- 'zope.app.apidoc.utilities.Sample'
-
- For methods getPythonPath returns the class path:
-
- >>> getPythonPath(Sample.sample)
- 'zope.app.apidoc.utilities.Sample'
-
- >>> try:
- ... getPythonPath(Sample())
- ... except AttributeError:
- ... print 'failed'
- failed
- """
+ """Return the path of the object in standard Python notation."""
if obj is None:
return None
@@ -161,8 +89,11 @@
naked = removeSecurityProxy(obj)
if hasattr(naked, "im_class"):
naked = naked.im_class
- module = naked.__module__
- return '%s.%s' %(module, naked.__name__)
+ module = getattr(naked, '__module__', _marker)
+ if module is _marker:
+ return naked.__name__
+ else:
+ return '%s.%s' %(module, naked.__name__)
def _evalId(id):
@@ -174,69 +105,7 @@
def getPermissionIds(name, checker=_marker, klass=_marker):
- """Get the permissions of an attribute.
-
- Either the klass or the checker must be specified. If the class is
- specified, then the checker for it is looked up. Furthermore, this
- function only works with `INameBasedChecker` checkers. If another checker
- is found, ``None`` is returned for the permissions.
-
- Example::
-
- We first define the class and then the checker for it
-
- >>> from zope.security.checker import Checker, defineChecker
- >>> from zope.security.checker import CheckerPublic
-
- >>> class Sample(object):
- ... attr = 'value'
- ... attr3 = 'value3'
-
- >>> class Sample2(object):
- ... pass
-
- >>> checker = Checker({'attr': 'zope.Read', 'attr3': CheckerPublic},
- ... {'attr': 'zope.Write', 'attr3': CheckerPublic})
- >>> defineChecker(Sample, checker)
-
- Now let's see how this function works
-
- >>> entries = getPermissionIds('attr', klass=Sample)
- >>> entries['read_perm']
- 'zope.Read'
- >>> entries['write_perm']
- 'zope.Write'
-
- >>> entries = getPermissionIds('attr', getCheckerForInstancesOf(Sample))
- >>> entries['read_perm']
- 'zope.Read'
- >>> entries['write_perm']
- 'zope.Write'
-
- Sample does not know about attr2.
-
- >>> entries = getPermissionIds('attr2', klass=Sample)
- >>> print entries['read_perm']
- n/a
- >>> print entries['write_perm']
- n/a
-
- Sample2 does not have a checker.
-
- >>> entries = getPermissionIds('attr', klass=Sample2)
- >>> entries['read_perm'] is None
- True
- >>> print entries['write_perm'] is None
- True
-
- Sample declares attr3 public.
-
- >>> entries = getPermissionIds('attr3', klass=Sample)
- >>> print entries['read_perm']
- zope.Public
- >>> print entries['write_perm']
- zope.Public
- """
+ """Get the permissions of an attribute."""
assert (klass is _marker) != (checker is _marker)
entry = {}
@@ -255,57 +124,7 @@
def getFunctionSignature(func):
- """Return the signature of a function or method.
-
- The `func` argument *must* be a generic function or a method of a class.
-
- Examples::
-
- >>> def func(attr, attr2=None):
- ... pass
- >>> print getFunctionSignature(func)
- (attr, attr2=None)
-
- >>> def func(attr, **kw):
- ... pass
- >>> print getFunctionSignature(func)
- (attr, **kw)
-
- >>> def func(attr, attr2=None, **kw):
- ... pass
- >>> print getFunctionSignature(func)
- (attr, attr2=None, **kw)
-
- >>> def func(*args, **kw):
- ... pass
- >>> print getFunctionSignature(func)
- (*args, **kw)
-
- >>> def func(**kw):
- ... pass
- >>> print getFunctionSignature(func)
- (**kw)
-
- >>> class Klass(object):
- ... def func(self, attr):
- ... pass
-
- >>> print getFunctionSignature(Klass.func)
- (attr)
-
- >>> class Klass(object):
- ... def func(self, attr, *args, **kw):
- ... pass
-
- >>> print getFunctionSignature(Klass.func)
- (attr, *args, **kw)
-
- >>> try:
- ... getFunctionSignature('func')
- ... except TypeError:
- ... print 'Argument not a function or method.'
- Argument not a function or method.
- """
+ """Return the signature of a function or method."""
if not isinstance(func, (types.FunctionType, types.MethodType)):
raise TypeError("func must be a function or method")
@@ -341,48 +160,7 @@
def getPublicAttributes(obj):
- """Return a list of public attribute names.
-
- This excludes any attribute starting with '_'. The `obj` argument can be
- either a classic class, type or instance of the previous two. Note that
- the term "attributes" here includes methods and properties.
-
- Examples::
-
- >>> class Sample(object):
- ... attr = None
- ... def __str__(self):
- ... return ''
- ... def func(self):
- ... pass
- ... def _getAttr(self):
- ... return self.attr
- ... attr2 = property(_getAttr)
- >>> class Sample2(object):
- ... attr = None
- >>> class Sample3(Sample):
- ... attr3 = None
-
- >>> attrs = getPublicAttributes(Sample)
- >>> attrs.sort()
- >>> print attrs
- ['attr', 'attr2', 'func']
-
- >>> attrs = getPublicAttributes(Sample())
- >>> attrs.sort()
- >>> print attrs
- ['attr', 'attr2', 'func']
-
- >>> attrs = getPublicAttributes(Sample2)
- >>> attrs.sort()
- >>> print attrs
- ['attr']
-
- >>> attrs = getPublicAttributes(Sample3)
- >>> attrs.sort()
- >>> print attrs
- ['attr', 'attr2', 'attr3', 'func']
- """
+ """Return a list of public attribute names."""
attrs = []
for attr in dir(obj):
if attr.startswith('_'):
@@ -393,57 +171,7 @@
def getInterfaceForAttribute(name, interfaces=_marker, klass=_marker,
asPath=True):
- """Determine the interface in which an attribute is defined.
-
- This function is nice, if you have an attribute name which you retrieved
- from a class and want to know which interface requires it to be there.
-
- Either 'interfaces' or 'klass' must be specified. If 'interfaces' is not
- specified, the 'klass' is used to retrieve a list of
- interfaces. 'interfaces' must be iterable.
-
- `asPath` specifies whether the dotted name of the interface or the
- interface object is returned.
-
- If no match is found, ``None`` is returned.
-
- Example::
-
- >>> from zope.interface import Interface, Attribute
- >>> class I1(Interface):
- ... attr = Attribute('attr')
- >>> class I2(I1):
- ... def getAttr():
- ... '''get attr'''
- >>> class Sample(object):
- ... implements(I2)
-
- >>> getInterfaceForAttribute('attr', (I1, I2), asPath=False).getName()
- 'I1'
- >>> getInterfaceForAttribute('getAttr', (I1, I2), asPath=False).getName()
- 'I2'
- >>> getInterfaceForAttribute('attr', klass=Sample, asPath=False).getName()
- 'I1'
- >>> getInterfaceForAttribute(
- ... 'getAttr', klass=Sample, asPath=False).getName()
- 'I2'
-
- >>> getInterfaceForAttribute('attr', (I1, I2))
- 'zope.app.apidoc.utilities.I1'
-
- >>> getInterfaceForAttribute('attr2', (I1, I2)) is None
- True
- >>> getInterfaceForAttribute('attr2', klass=Sample) is None
- True
-
- >>> getInterfaceForAttribute('getAttr')
- Traceback (most recent call last):
- ValueError: need to specify interfaces or klass
- >>> getInterfaceForAttribute('getAttr', interfaces=(I1,I2), klass=Sample)
- Traceback (most recent call last):
- ValueError: must specify only one of interfaces and klass
-
- """
+ """Determine the interface in which an attribute is defined."""
if (interfaces is _marker) and (klass is _marker):
raise ValueError("need to specify interfaces or klass")
if (interfaces is not _marker) and (klass is not _marker):
@@ -468,34 +196,7 @@
def columnize(entries, columns=3):
- """Place a list of entries into columns.
-
- Examples::
-
- >>> print columnize([1], 3)
- [[1]]
-
- >>> print columnize([1, 2], 3)
- [[1], [2]]
-
- >>> print columnize([1, 2, 3], 3)
- [[1], [2], [3]]
-
- >>> print columnize([1, 2, 3, 4], 3)
- [[1, 2], [3], [4]]
-
- >>> print columnize([1], 2)
- [[1]]
-
- >>> print columnize([1, 2], 2)
- [[1], [2]]
-
- >>> print columnize([1, 2, 3], 2)
- [[1, 2], [3]]
-
- >>> print columnize([1, 2, 3, 4], 2)
- [[1, 2], [3, 4]]
- """
+ """Place a list of entries into columns."""
if len(entries)%columns == 0:
per_col = len(entries)/columns
last_full_col = columns
@@ -517,13 +218,13 @@
columns.append(col)
return columns
+
_format_dict = {
'plaintext': 'zope.source.plaintext',
'structuredtext': 'zope.source.stx',
'restructuredtext': 'zope.source.rest'
}
-
def getDocFormat(module):
"""Convert a module's __docformat__ specification to a renderer source
id"""
@@ -532,6 +233,9 @@
def renderText(text, module=None, format=None):
+ if not text:
+ return u''
+
if module is not None:
if isinstance(module, (str, unicode)):
module = sys.modules.get(module, None)
@@ -542,9 +246,6 @@
assert format in _format_dict.values()
- if text:
- source = zapi.createObject(format, text)
- renderer = zapi.getMultiAdapter((source, TestRequest()))
- return renderer.render()
- else:
- return u''
+ source = zapi.createObject(format, text)
+ renderer = zapi.getMultiAdapter((source, TestRequest()))
+ return renderer.render()
Added: Zope3/trunk/src/zope/app/apidoc/utilities.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilities.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilities.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,522 @@
+=======================
+Miscellaneous Utilities
+=======================
+
+The utilities module provides some useful helper functions and classes that
+make the work of the API doctool and inspection code easier.
+
+ >>> from zope.app.apidoc import utilities
+
+
+`relativizePath(path)`
+----------------------
+
+When dealing with files, such as page templates and text files, and not with
+Python paths, it is necessary to keep track of the the absolute path of the
+file. However, for presentation purposes, the absolute path is inappropriate
+and we are commonly interested in the path starting at the Zope 3 root
+directory. This function attempts to remove the absolute path to the root
+directory and replaces it with "Zope3".
+
+ >>> import os
+ >>> path = os.path.join(utilities.BASEDIR, 'src', 'zope', 'README.txt')
+
+ >>> utilities.BASEDIR in path
+ True
+
+ >>> path = utilities.relativizePath(path)
+
+ >>> utilities.BASEDIR in path
+ False
+
+ # Be kind to Windows users
+ >>> path.replace('\\', '/')
+ 'Zope3/src/zope/README.txt'
+
+If the base path is not found in a particular path, the original path is
+returned:
+
+ >>> otherpath = 'foo/bar/blah.txt'
+ >>> utilities.relativizePath(otherpath)
+ 'foo/bar/blah.txt'
+
+
+`ReadContainerBase` (Class)
+---------------------------
+
+This class serves as a base class for `IReadContainer` objects that minimizes
+the implementation of an `IReadContainer` to two methods, `get()` and
+`items()`, since the other methods can be implemented using these two.
+
+Note that this implementation might be very expensive for certain container,
+especially if collecting the items is of high order. However, there are many
+scenarios when one has a complete mapping already and simply want to persent
+it as an `IReadContainer`.
+
+Let's start by making a simple `IReadContainer` implementation using the
+class:
+
+ >>> class Container(utilities.ReadContainerBase):
+ ... def get(self, key, default=None):
+ ... return {'a': 1, 'b': 2}.get(key, default)
+ ... def items(self):
+ ... return [('a', 1), ('b', 2)]
+
+ >>> container = Container()
+
+Now we can use the methods. First `get()`
+
+ >>> container.get('a')
+ 1
+ >>> container.get('c') is None
+ True
+ >>> container['b']
+ 2
+
+and then `items()`
+
+ >>> container.items()
+ [('a', 1), ('b', 2)]
+ >>> container.keys()
+ ['a', 'b']
+ >>> container.values()
+ [1, 2]
+
+Then naturally, all the other methods work as well:
+
+ * `__getitem__(key)`
+
+ >>> container['a']
+ 1
+ >>> container['c']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'c'
+
+ * `__contains__(key)`
+
+ >>> 'a' in container
+ True
+ >>> 'c' in container
+ False
+
+ * `keys()`
+
+ >>> container.keys()
+ ['a', 'b']
+
+ * `__iter__()`
+
+ >>> iterator = iter(container)
+ >>> iterator.next()
+ 1
+ >>> iterator.next()
+ 2
+ >>> iterator.next()
+ Traceback (most recent call last):
+ ...
+ StopIteration
+
+ * `values()`
+
+ >>> container.values()
+ [1, 2]
+
+ * `__len__()`
+
+ >>> len(container)
+ 2
+
+
+`getPythonPath(obj)`
+--------------------
+
+Return the path of the object in standard Python dot-notation.
+
+This function makes only sense for objects that provide a name, since we
+cannot determine the path otherwise. Instances, for example, do not have a
+`__name__` attribute, so we would expect them to fail.
+
+For interfaces we simply get
+
+ >>> from zope.interface import Interface
+ >>> class ISample(Interface):
+ ... pass
+
+ >>> utilities.getPythonPath(ISample)
+ '__builtin__.ISample'
+
+and for classes
+
+ >>> class Sample(object):
+ ... def sample(self):
+ ... pass
+
+ >>> utilities.getPythonPath(Sample.sample)
+ '__builtin__.Sample'
+
+One can also pass functions
+
+ >>> def sample():
+ ... pass
+
+ >>> # Result is a bit strange due to doctests
+ >>> utilities.getPythonPath(sample)
+ 'None.sample'
+
+and even methods. If a method is passed in, its class path is returned.
+
+ >>> utilities.getPythonPath(Sample.sample)
+ '__builtin__.Sample'
+
+Modules are another kind of objects that can return a python path:
+
+ >>> utilities.getPythonPath(utilities)
+ 'zope.app.apidoc.utilities'
+
+Passing in `None` returns `None`:
+
+ >>> utilities.getPythonPath(None)
+
+Clearly, instance lookups should fail:
+
+ >>> utilities.getPythonPath(Sample())
+ Traceback (most recent call last):
+ ...
+ AttributeError: 'Sample' object has no attribute '__name__'
+
+
+`getPermissionIds(name, checker=_marker, klass=_marker)`
+--------------------------------------------------------
+
+Get the permissions of a class attribute. The attribute is specified by name.
+
+Either the `klass` or the `checker` argument must be specified. If the class
+is specified, then the checker for it is looked up. Furthermore, this function
+only works with `INameBasedChecker` checkers. If another checker is found,
+``None`` is returned for the permissions.
+
+We start out by defining the class and then the checker for it:
+
+ >>> from zope.security.checker import Checker, defineChecker
+ >>> from zope.security.checker import CheckerPublic
+
+ >>> class Sample(object):
+ ... attr = 'value'
+ ... attr3 = 'value3'
+
+ >>> class Sample2(object):
+ ... pass
+
+ >>> checker = Checker({'attr': 'zope.Read', 'attr3': CheckerPublic},
+ ... {'attr': 'zope.Write', 'attr3': CheckerPublic})
+ >>> defineChecker(Sample, checker)
+
+Now let's see how this function works:
+
+ >>> entries = utilities.getPermissionIds('attr', klass=Sample)
+ >>> entries['read_perm']
+ 'zope.Read'
+ >>> entries['write_perm']
+ 'zope.Write'
+
+ >>> from zope.security.checker import getCheckerForInstancesOf
+ >>> entries = utilities.getPermissionIds('attr',
+ ... getCheckerForInstancesOf(Sample))
+ >>> entries['read_perm']
+ 'zope.Read'
+ >>> entries['write_perm']
+ 'zope.Write'
+
+The `Sample` class does not know about the `attr2` attribute:
+
+ >>> entries = utilities.getPermissionIds('attr2', klass=Sample)
+ >>> print entries['read_perm']
+ n/a
+ >>> print entries['write_perm']
+ n/a
+
+The `Sample2` class does not have a checker:
+
+ >>> entries = utilities.getPermissionIds('attr', klass=Sample2)
+ >>> entries['read_perm'] is None
+ True
+ >>> print entries['write_perm'] is None
+ True
+
+Finally, the `Sample` class' `attr3` attribute is public:
+
+ >>> entries = utilities.getPermissionIds('attr3', klass=Sample)
+ >>> print entries['read_perm']
+ zope.Public
+ >>> print entries['write_perm']
+ zope.Public
+
+
+`getFunctionSignature(func)`
+----------------------------
+
+Return the signature of a function or method. The `func` argument *must* be a
+generic function or a method of a class.
+
+First, we get the signature of a function that has a specific positional and
+keyword argument:
+
+ >>> def func(attr, attr2=None):
+ ... pass
+ >>> utilities.getFunctionSignature(func)
+ '(attr, attr2=None)'
+
+Here is a function that has an unspecified amount of keyword arguments:
+
+ >>> def func(attr, **kw):
+ ... pass
+ >>> utilities.getFunctionSignature(func)
+ '(attr, **kw)'
+
+And here we mix specified and unspecified keyword arguments:
+
+ >>> def func(attr, attr2=None, **kw):
+ ... pass
+ >>> utilities.getFunctionSignature(func)
+ '(attr, attr2=None, **kw)'
+
+In the next example we have unspecified positional and keyword arguments:
+
+ >>> def func(*args, **kw):
+ ... pass
+ >>> utilities.getFunctionSignature(func)
+ '(*args, **kw)'
+
+And finally an example, where we have on unspecified keyword arguments without
+any positional arguments:
+
+ >>> def func(**kw):
+ ... pass
+ >>> utilities.getFunctionSignature(func)
+ '(**kw)'
+
+Next we test whether the signature is correctly determined for class
+methods. Note that the `self` argument is removed from the signature, since it
+is not essential for documentation.
+
+We start out with a simple positional argument:
+
+ >>> class Klass(object):
+ ... def func(self, attr):
+ ... pass
+ >>> utilities.getFunctionSignature(Klass.func)
+ '(attr)'
+
+Next we have specific and unspecified positional arguments as well as
+unspecified keyword arguments:
+
+ >>> class Klass(object):
+ ... def func(self, attr, *args, **kw):
+ ... pass
+ >>> utilities.getFunctionSignature(Klass.func)
+ '(attr, *args, **kw)'
+
+If you do not pass a function or method to the function, it will fail:
+
+ >>> utilities.getFunctionSignature('func')
+ Traceback (most recent call last):
+ ...
+ TypeError: func must be a function or method
+
+`getPublicAttributes(obj)`
+--------------------------
+
+Return a list of public attribute names for a given object.
+
+This excludes any attribute starting with '_', which includes attributes of
+the form `__attr__`, which are commonly considered public, but they are so
+special that they are excluded. The `obj` argument can be either a classic
+class, type or instance of the previous two. Note that the term "attributes"
+here includes methods and properties.
+
+First we need to create a class with some attributes, properties and methods:
+
+ >>> class Sample(object):
+ ... attr = None
+ ... def __str__(self):
+ ... return ''
+ ... def func(self):
+ ... pass
+ ... def _getAttr(self):
+ ... return self.attr
+ ... attr2 = property(_getAttr)
+
+We can simply pass in the class and get the public attributes:
+
+ >>> attrs = utilities.getPublicAttributes(Sample)
+ >>> attrs.sort()
+ >>> attrs
+ ['attr', 'attr2', 'func']
+
+But an instance of that class will work as well.
+
+ >>> attrs = utilities.getPublicAttributes(Sample())
+ >>> attrs.sort()
+ >>> attrs
+ ['attr', 'attr2', 'func']
+
+The function will also take inheritance into account and return all inherited
+attributes as well:
+
+ >>> class Sample2(Sample):
+ ... attr3 = None
+
+ >>> attrs = utilities.getPublicAttributes(Sample2)
+ >>> attrs.sort()
+ >>> attrs
+ ['attr', 'attr2', 'attr3', 'func']
+
+
+`getInterfaceForAttribute(name, interfaces=_marker, klass=_marker, asPath=True)`
+--------------------------------------------------------------------------------
+
+Determine the interface in which an attribute is defined. This function is
+nice, if you have an attribute name which you retrieved from a class and want
+to know which interface requires it to be there.
+
+Either the `interfaces` or `klass` argument must be specified. If `interfaces`
+is not specified, the `klass` is used to retrieve a list of
+interfaces. `interfaces` must be iterable.
+
+`asPath` specifies whether the dotted name of the interface or the interface
+object is returned.
+
+First, we need to create some interfaces and a class that implements them:
+
+ >>> from zope.interface import Interface, Attribute, implements
+ >>> class I1(Interface):
+ ... attr = Attribute('attr')
+
+ >>> class I2(I1):
+ ... def getAttr():
+ ... '''get attr'''
+
+ >>> class Sample(object):
+ ... implements(I2)
+
+First we check whether an aatribute can be found in a list of interfaces:
+
+ >>> utilities.getInterfaceForAttribute('attr', (I1, I2), asPath=False)
+ <InterfaceClass __builtin__.I1>
+ >>> utilities.getInterfaceForAttribute('getAttr', (I1, I2), asPath=False)
+ <InterfaceClass __builtin__.I2>
+
+Now we are repeating the same lookup, but using the class, instead of a list
+of interfaces:
+
+ >>> utilities.getInterfaceForAttribute('attr', klass=Sample, asPath=False)
+ <InterfaceClass __builtin__.I1>
+ >>> utilities.getInterfaceForAttribute('getAttr', klass=Sample, asPath=False)
+ <InterfaceClass __builtin__.I2>
+
+By default, `asPath` is `True`, which means the path of the interface is
+returned:
+
+ >>> utilities.getInterfaceForAttribute('attr', (I1, I2))
+ '__builtin__.I1'
+
+If no match is found, ``None`` is returned.
+
+ >>> utilities.getInterfaceForAttribute('attr2', (I1, I2)) is None
+ True
+ >>> utilities.getInterfaceForAttribute('attr2', klass=Sample) is None
+ True
+
+If both, the `interfaces` and `klass` argument are missing, raise an error:
+
+ >>> utilities.getInterfaceForAttribute('getAttr')
+ Traceback (most recent call last):
+ ...
+ ValueError: need to specify interfaces or klass
+
+Similarly, it does not make sense if both are specified:
+
+ >>> utilities.getInterfaceForAttribute('getAttr', interfaces=(I1,I2),
+ ... klass=Sample)
+ Traceback (most recent call last):
+ ...
+ ValueError: must specify only one of interfaces and klass
+
+
+`columnize(entries, columns=3)`
+-------------------------------
+
+This function places a list of entries into columns.
+
+Here are some examples:
+
+ >>> utilities.columnize([1], 3)
+ [[1]]
+
+ >>> utilities.columnize([1, 2], 3)
+ [[1], [2]]
+
+ >>> utilities.columnize([1, 2, 3], 3)
+ [[1], [2], [3]]
+
+ >>> utilities.columnize([1, 2, 3, 4], 3)
+ [[1, 2], [3], [4]]
+
+ >>> utilities.columnize([1], 2)
+ [[1]]
+
+ >>> utilities.columnize([1, 2], 2)
+ [[1], [2]]
+
+ >>> utilities.columnize([1, 2, 3], 2)
+ [[1, 2], [3]]
+
+ >>> utilities.columnize([1, 2, 3, 4], 2)
+ [[1, 2], [3, 4]]
+
+
+`getDocFormat(module)`
+----------------------
+
+This function inspects a module to determine the supported documentation
+format. The function returns a valid renderer source factory id.
+
+If the `__docformat__` module attribute is specified, its value will be used
+to look up the factory id:
+
+ >>> from zope.app.apidoc import apidoc
+ >>> utilities.getDocFormat(apidoc)
+ 'zope.source.rest'
+
+By default structured text is returned:
+
+ >>> from zope.app.apidoc import tests
+ >>> utilities.getDocFormat(tests)
+ 'zope.source.stx'
+
+This is a sensible default, since we only decided later in development to
+endorse restructured text, so that many files are still in the structured text
+format. All converted and new modules will have the `__docformat__` attribute.
+
+
+`renderText(text, module=None, format=None)`
+--------------------------------------------
+
+A function that quickly renders the given text using the specified format.
+
+If the `module` argument is specified, the function will try to determine the
+format using the module. If the `format` argument is given, it is simply
+used. Clearly, you cannot specify both, the `module` and `format` argument.
+
+You specify the format as follows:
+
+ >>> utilities.renderText('Hello!\n', format='zope.source.rest')
+ u'<div class="document">\nHello!</div>\n'
+
+Note that the format string must be a valid source factory id; if the factory
+id is not a match, 'zope.source.stx' is used. Thus, specifying the module is
+often safer (if available):
+
+ >>> utilities.renderText('Hello!\n', module=apidoc)
+ u'<div class="document">\nHello!</div>\n'
\ No newline at end of file
Property changes on: Zope3/trunk/src/zope/app/apidoc/utilities.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/apidoc/utilitymodule/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/README.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/README.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,78 @@
+==================================
+The Utilities Documentation Module
+==================================
+
+This documentation module organizes all registered utilities by their provided
+interface and then by the name of the utility.
+
+`UtilityModule` class
+---------------------
+
+This class represents the documentation of all utility interfaces. The items
+of the container are all `UtilityInterface` instances.
+
+Let's start by creating a utility documentation module:
+
+ >>> from zope.app.apidoc.utilitymodule.utilitymodule import UtilityModule
+ >>> module = UtilityModule()
+
+To make the documentation module useful, we have to register a utility, so why
+not the documentation module itself?
+
+ >>> from zope.app.apidoc.interfaces import IDocumentationModule
+ >>> from zope.app.testing import ztapi
+ >>> ztapi.provideUtility(IDocumentationModule, module, 'Utility')
+
+Now we can get a single utility interface by path:
+
+ >>> module.get('zope.app.apidoc.interfaces.IDocumentationModule')
+ <zope.app.apidoc.utilitymodule.utilitymodule.UtilityInterface ...>
+
+and list all available interfaces:
+
+ >>> module.items()
+ [('zope.app.apidoc.interfaces.IDocumentationModule',
+ <zope.app.apidoc.utilitymodule.utilitymodule.UtilityInterface ...>),
+ ('zope.security.interfaces.IPermission',
+ <zope.app.apidoc.utilitymodule.utilitymodule.UtilityInterface ...>)]
+
+
+`UtilityInterface` class
+------------------------
+
+Representation of an interface a utility provides.
+
+First we create a utility interface documentation instance:
+
+ >>> from zope.app.apidoc.utilitymodule.utilitymodule import UtilityInterface
+ >>> ut_iface = UtilityInterface(
+ ... module,
+ ... 'zope.app.apidoc.interfaces.IDocumentationModule',
+ ... IDocumentationModule)
+
+Now we can get the utility:
+
+ >>> ut_iface.get('Utility').component
+ <zope.app.apidoc.utilitymodule.utilitymodule.UtilityModule object at ...>
+
+Unnamed utilities are special, since they can be looked up in different ways:
+
+ >>> ztapi.provideUtility(IDocumentationModule, module, '')
+
+ >>> ut_iface.get('').component
+ <zope.app.apidoc.utilitymodule.utilitymodule.UtilityModule object at ...>
+
+ >>> from zope.app.apidoc.utilitymodule.utilitymodule import NONAME
+ >>> ut_iface.get(NONAME).component
+ <zope.app.apidoc.utilitymodule.utilitymodule.UtilityModule object at ...>
+
+If you try to get a non-existent utility, `None` is returned:
+
+ >>> ut_iface.get('foo') is None
+ True
+
+You can get a list of available utilities as well, of course:
+
+ >>> ut_iface.items()
+ [('Utility', <zope.app.apidoc.utilitymodule.utilitymodule.Utility ...>),
+ ('__noname__', <zope.app.apidoc.utilitymodule.utilitymodule.Utility ...>)]
Property changes on: Zope3/trunk/src/zope/app/apidoc/utilitymodule/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/__init__.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/__init__.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,166 +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.
-#
-##############################################################################
-"""Utility Documentation Module
-
-$Id$
-"""
-__docformat__ = 'restructuredtext'
-
-from zope.component.site import UtilityRegistration
-from zope.interface import implements
-
-from zope.app import zapi
-from zope.app.i18n import ZopeMessageIDFactory as _
-from zope.app.component import queryNextSiteManager
-from zope.app.location.interfaces import ILocation
-from zope.app.apidoc.interfaces import IDocumentationModule
-from zope.app.apidoc.utilities import ReadContainerBase, getPythonPath
-
-# Constant used when the utility has no name
-NONAME = '__noname__'
-
-class Utility(object):
- """Representation of a utility for the API Documentation"""
-
- implements(ILocation)
-
- def __init__(self, parent, reg):
- """Initialize Utility object."""
- self.__parent__ = parent
- self.__name__ = reg.name or NONAME
- self.registration = reg
- self.interface = reg.provided
- self.component = reg.component
- # Handle local and global utility registrations
- self.doc = hasattr(reg, 'doc') and reg.doc or ''
-
-
-class UtilityInterface(ReadContainerBase):
- r"""Representation of an interface a utility provides.
-
- Demonstration::
-
- >>> from zope.app.apidoc.interfaces import IDocumentationModule
-
- >>> id = 'zope.app.apidoc.interfaces.IDocumentationModule'
- >>> ut_iface = UtilityInterface(UtilityModule(), id,
- ... IDocumentationModule)
-
- >>> ut_iface.get('Classes').component.__class__.__name__
- 'ClassModule'
-
- >>> ut_iface.get('').component.__class__.__name__
- 'InterfaceModule'
-
- >>> ut_iface.get(NONAME).component.__class__.__name__
- 'InterfaceModule'
-
- >>> ut_iface.get('foo') is None
- True
-
- >>> print '\n'.join([id for id, iface in ut_iface.items()])
- Classes
- __noname__
- """
-
- implements(ILocation)
-
- def __init__(self, parent, name, interface):
- self.__parent__ = parent
- self.__name__ = name
- self.interface = interface
-
- def get(self, key, default=None):
- """See zope.app.container.interfaces.IReadContainer"""
- sm = zapi.getGlobalSiteManager()
- if key == NONAME:
- key = ''
- utils = [Utility(self, reg)
- for reg in sm.registrations()
- if zapi.isinstance(reg, UtilityRegistration) and \
- reg.name == key and reg.provided == self.interface]
- return utils and utils[0] or default
-
- def items(self):
- """See zope.app.container.interfaces.IReadContainer"""
- sm = zapi.getGlobalSiteManager()
- items = [(reg.name or NONAME, Utility(self, reg))
- for reg in sm.registrations()
- if zapi.isinstance(reg, UtilityRegistration) and \
- self.interface == reg.provided]
- items.sort()
- return items
-
-
-class UtilityModule(ReadContainerBase):
- r"""Represent the Documentation of all Interfaces.
-
- This documentation is implemented using a simple `IReadContainer`. The
- items of the container are all factories listed in the closest
- site manager and above.
-
- Demonstration::
-
- >>> module = UtilityModule()
- >>> ut_iface = module.get(
- ... 'zope.app.apidoc.interfaces.IDocumentationModule')
-
- >>> ut_iface.interface.getName()
- 'IDocumentationModule'
-
- >>> print '\n'.join([id for id, iface in module.items()])
- zope.app.apidoc.interfaces.IDocumentationModule
- zope.security.interfaces.IPermission
- """
-
- implements(IDocumentationModule)
-
- # See zope.app.apidoc.interfaces.IDocumentationModule
- title = _('Utilities')
-
- # See zope.app.apidoc.interfaces.IDocumentationModule
- description = _("""
- Utilities are also nicely registered in a site manager, so that it is easy
- to create a listing of available utilities. A utility is identified by the
- providing interface and a name, which can be empty. The menu provides you
- with a list of interfaces that utilities provide and as sub-items the
- names of the various implementations.
-
- Again, the documentation of a utility lists all the attributes/fields and
- methods the utility provides and provides a link to the implementation.
- """)
-
- def get(self, key, default=None):
- parts = key.split('.')
- try:
- mod = __import__('.'.join(parts[:-1]), {}, {}, ('*',))
- except ImportError:
- return default
- else:
- return UtilityInterface(self, key, getattr(mod, parts[-1], default))
-
- def items(self):
- sm = zapi.getSiteManager()
- ifaces = {}
- while sm is not None:
- for reg in sm.registrations():
- if isinstance(reg, UtilityRegistration):
- path = getPythonPath(reg.provided)
- ifaces[path] = UtilityInterface(self, path, reg.provided)
- sm = queryNextSiteManager(sm)
-
- items = ifaces.items()
- items.sort(lambda x, y: cmp(x[0].split('.')[-1], y[0].split('.')[-1]))
- return items
-
+# Make a package
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -21,89 +21,29 @@
from zope.app.location import LocationProxy
from zope.app.apidoc.ifacemodule.browser import InterfaceDetails
from zope.app.apidoc.utilities import getPythonPath
-from zope.app.apidoc.utilitymodule import NONAME, Utility, UtilityInterface
+from zope.app.apidoc.utilitymodule.utilitymodule import NONAME, Utility
+from zope.app.apidoc.utilitymodule.utilitymodule import UtilityInterface
class UtilityDetails(object):
"""Utility Details View."""
def getName(self):
- """Get the name of the utility.
-
- Return the string ``no name``, if the utility has no name.
-
- Examples::
-
- >>> def makeRegistration(name):
- ... return type('RegistrationStub', (),
- ... {'name': name, 'provided': None,
- ... 'component': None, 'doc': ''})()
-
- >>> details = UtilityDetails()
- >>> details.context = Utility(None, makeRegistration('myname'))
- >>> details.getName()
- 'myname'
-
- >>> details.context = Utility(None, makeRegistration(NONAME))
- >>> details.getName()
- 'no name'
- """
+ """Get the name of the utility."""
name = zapi.name(self.context)
if name == NONAME:
return 'no name'
return name
def getInterface(self):
- """Return the interface the utility provides.
-
- Example::
-
- >>> from tests import getDetailsView
- >>> details = getDetailsView()
-
- >>> iface = details.getInterface()
- >>> iface.getId()
- 'zope.app.apidoc.interfaces.IDocumentationModule'
- """
+ """Return the interface the utility provides."""
schema = LocationProxy(self.context.interface,
self.context,
getPythonPath(self.context.interface))
- details = InterfaceDetails()
- details.context = schema
- details.request = self.request
-
+ details = InterfaceDetails(schema, self.request)
return details
def getComponent(self):
- """Return the python path of the implementation class.
-
- Examples::
-
- >>> from zope.app.apidoc.utilitymodule import Utility
- >>> from zope.app.apidoc.tests import pprint
-
- >>> def makeRegistration(name, component):
- ... return type(
- ... 'RegistrationStub', (),
- ... {'name': name, 'provided': None,
- ... 'component': component, 'doc': ''})()
-
- >>> class Foo(object):
- ... pass
-
- >>> class Bar(object):
- ... pass
-
- >>> details = UtilityDetails()
- >>> details.context = Utility(None, makeRegistration('', Foo()))
- >>> pprint(details.getComponent())
- [('path', 'zope.app.apidoc.utilitymodule.browser.Foo'),
- ('url', 'zope/app/apidoc/utilitymodule/browser/Foo')]
-
- >>> details.context = Utility(None, makeRegistration('', Bar()))
- >>> pprint(details.getComponent())
- [('path', 'zope.app.apidoc.utilitymodule.browser.Bar'),
- ('url', 'zope/app/apidoc/utilitymodule/browser/Bar')]
- """
+ """Return the python path of the implementation class."""
# We could use `type()` here, but then we would need to remove the
# security proxy from the component. This is easier and also supports
# old-style classes
@@ -112,53 +52,10 @@
return {'path': getPythonPath(klass),
'url': getPythonPath(klass).replace('.', '/')}
+
class Menu(object):
- """Menu View Helper Class
+ """Menu View Helper Class"""
- A class that helps building the menu. The menu_macros expects the menu view
- class to have the `getMenuTitle(node)` and `getMenuLink(node)` methods
- implemented. `node` is a `zope.app.tree.node.Node` instance.
-
- Examples::
-
- >>> from zope.app.tree.node import Node
- >>> from zope.app.apidoc.utilitymodule import Utility, UtilityInterface
- >>> from zope.app.apidoc.tests import Root
- >>> menu = Menu()
-
- >>> def makeRegistration(name):
- ... return type('RegistrationStub', (),
- ... {'name': name, 'provided': None,
- ... 'component': None, 'doc': ''})()
-
- Get menu title and link for a utility interface
-
- >>> uiface = UtilityInterface(Root(), 'foo.bar.iface', None)
- >>> node = Node(uiface)
- >>> menu.getMenuTitle(node)
- 'iface'
- >>> menu.getMenuLink(node)
- '../Interface/foo.bar.iface/apiindex.html'
-
- Get menu title and link for a utility with a name
-
- >>> util = Utility(uiface, makeRegistration('FooBar'))
- >>> node = Node(util)
- >>> menu.getMenuTitle(node)
- 'FooBar'
- >>> menu.getMenuLink(node)
- './foo.bar.iface/FooBar/index.html'
-
- Get menu title and link for a utility without a name
-
- >>> util = Utility(uiface, makeRegistration(None))
- >>> node = Node(util)
- >>> menu.getMenuTitle(node)
- 'no name'
- >>> menu.getMenuLink(node)
- './foo.bar.iface/__noname__/index.html'
- """
-
def getMenuTitle(self, node):
"""Return the title of the node that is displayed in the menu."""
obj = node.context
Added: Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,154 @@
+================================
+Utilities Menu and Details Views
+================================
+
+
+`Menu` class
+------------
+
+This is a class that helps building the menu. The `menu_macros` expect the menu
+view class to have the `getMenuTitle(node)` and `getMenuLink(node)` methods
+implemented. `node` is a `zope.app.tree.node.Node` instance.
+
+Let's start by creating the menu:
+
+ >>> from zope.app.apidoc.utilitymodule.browser import Menu
+ >>> menu = Menu()
+
+Now we want to get the menu title and link for a utility interface. To do that
+we first have to create a utility interface
+
+ >>> from zope.app.apidoc.tests import Root
+ >>> from zope.app.apidoc.utilitymodule.utilitymodule import UtilityInterface
+ >>> uiface = UtilityInterface(Root(), 'foo.bar.iface', None)
+
+and then wrap it in a node:
+
+ >>> from zope.app.tree.node import Node
+ >>> node = Node(uiface)
+
+You can now get the title and link from the menu:
+
+ >>> menu.getMenuTitle(node)
+ 'iface'
+ >>> menu.getMenuLink(node)
+ '../Interface/foo.bar.iface/apiindex.html'
+
+Next, let's get the menu title and link for a utility with a name. We first
+have to create a utility registration
+
+ >>> foobar_reg = type(
+ ... 'RegistrationStub', (),
+ ... {'name': 'FooBar', 'provided': None,
+ ... 'component': None, 'doc': ''})()
+
+which is then wrapped in a `Utility` documentation class and then in a node:
+
+ >>> from zope.app.apidoc.utilitymodule.utilitymodule import Utility
+ >>> util = Utility(uiface, foobar_reg)
+ >>> node = Node(util)
+
+We can now ask the menu to give us the tile and link for the utility:
+
+ >>> menu.getMenuTitle(node)
+ 'FooBar'
+ >>> menu.getMenuLink(node)
+ './foo.bar.iface/FooBar/index.html'
+
+Finally, we get menu title and link for a utility without a name:
+
+ >>> from zope.app.apidoc.utilitymodule.utilitymodule import NONAME
+ >>> noname_reg = type(
+ ... 'RegistrationStub', (),
+ ... {'name': NONAME, 'provided': None,
+ ... 'component': None, 'doc': ''})()
+
+ >>> util = Utility(uiface, noname_reg)
+ >>> node = Node(util)
+ >>> menu.getMenuTitle(node)
+ 'no name'
+ >>> menu.getMenuLink(node)
+ './foo.bar.iface/__noname__/index.html'
+
+
+`UtilityDetails` class
+----------------------
+
+This class provides presentation-ready data about a particular utility.
+
+`getName()`
+-----------
+
+Get the name of the utility.
+
+ >>> from zope.app.apidoc.utilitymodule.browser import UtilityDetails
+ >>> details = UtilityDetails()
+ >>> details.context = Utility(None, foobar_reg)
+ >>> details.getName()
+ 'FooBar'
+
+Return the string ``no name``, if the utility has no name.
+
+ >>> details.context = Utility(None, noname_reg)
+ >>> details.getName()
+ 'no name'
+
+
+`getInterface()`
+----------------
+
+Return the interface details view for the interface the utility provides.
+
+Let's start by creating the utility interface and building a utility
+registration:
+
+ >>> from zope.interface import Interface
+ >>> class IBlah(Interface):
+ ... pass
+
+ >>> blah_reg = type(
+ ... 'RegistrationStub', (),
+ ... {'name': 'Blah', 'provided': IBlah,
+ ... 'component': None, 'doc': ''})()
+
+Then we wrap the registration in the utility documentation class and create
+the details view:
+
+ >>> details = UtilityDetails()
+ >>> details.context = Utility(None, blah_reg)
+ >>> details.request = None
+
+Now that we have the details view, we can look up the interface's detail view
+and get the id (for example):
+
+ >>> iface = details.getInterface()
+ >>> iface.getId()
+ '__builtin__.IBlah'
+
+
+`getComponent()`
+----------------
+
+Return the Python path and a code browser URL path of the implementation
+class.
+
+This time around we create the utility class and put it into a utility
+registration:
+
+ >>> class Foo(object):
+ ... pass
+
+ >>> foo_reg = type(
+ ... 'RegistrationStub', (),
+ ... {'name': '', 'provided': None, 'component': Foo(), 'doc': ''})()
+
+Then we create a utility documentation class and its details view:
+
+ >>> details = UtilityDetails()
+ >>> details.context = Utility(None, foo_reg)
+
+Now we can get the component information:
+
+ >>> pprint(details.getComponent())
+ {'path': '__builtin__.Foo',
+ 'url': '__builtin__/Foo'}
Property changes on: Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/configure.zcml 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/configure.zcml 2005-02-23 22:22:48 UTC (rev 29269)
@@ -2,34 +2,34 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
- <class class=".UtilityModule">
+ <class class=".utilitymodule.UtilityModule">
<allow interface="zope.app.apidoc.interfaces.IDocumentationModule" />
<allow interface="zope.app.container.interfaces.IReadContainer" />
</class>
- <class class=".Utility">
+ <class class=".utilitymodule.Utility">
<allow attributes="registration interface component doc" />
</class>
- <class class=".UtilityInterface">
+ <class class=".utilitymodule.UtilityInterface">
<allow interface="zope.app.container.interfaces.IReadContainer" />
<allow attributes="interface" />
</class>
<utility
provides="zope.app.apidoc.interfaces.IDocumentationModule"
- factory=".UtilityModule"
+ factory=".utilitymodule.UtilityModule"
name="Utility" />
<browser:page
- for=".UtilityModule"
+ for=".utilitymodule.UtilityModule"
permission="zope.app.apidoc.UseAPIDoc"
class=".browser.Menu"
name="menu.html"
template="menu.pt" />
<browser:page
- for=".Utility"
+ for=".utilitymodule.Utility"
permission="zope.app.apidoc.UseAPIDoc"
class=".browser.UtilityDetails"
name="index.html"
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/ftests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/ftests.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/ftests.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -35,16 +35,18 @@
response = self.publish(
'/++apidoc++/Utility/'
'zope.app.apidoc.interfaces.IDocumentationModule/'
- 'Class/index.html',
+ 'Utility/index.html',
basic='mgr:mgrpw')
self.assertEqual(response.getStatus(), 200)
body = response.getBody()
- self.assert_(body.find('zope.app.apidoc.classmodule.ClassModule') > 0)
+ self.assert_(
+ body.find(
+ 'zope.app.apidoc.utilitymodule.utilitymodule.UtilityModule') > 0)
self.checkForBrokenLinks(
body,
'/++apidoc++/Utility/'
'zope.app.apidoc.interfaces.IDocumentationModule/'
- 'Class/index.html',
+ 'Utility/index.html',
basic='mgr:mgrpw')
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/index.pt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,6 +1,7 @@
<html metal:use-macro="views/apidoc_macros/details">
<body metal:fill-slot="contents"
- tal:define="iface view/getInterface">
+ tal:define="iface view/getInterface;
+ rootURL iface/apidocRoot">
<h1 class="details-header">
<a href=""
@@ -17,7 +18,7 @@
<span i18n:translate="">Component:</span>
<a href=""
tal:attributes="href
- string:../../../Class/${component/url}/index.html"
+ string:../../../Code/${component/url}/index.html"
tal:content="component/path" /></h3>
</div>
@@ -27,74 +28,14 @@
</div>
</div>
- <h2 class="details-section" i18n:translate="">Attributes/Fields</h2>
+ <tal:block define="attributes iface/getAttributes;
+ fields iface/getFields">
+ <metal:block use-macro="context/@@interface_macros/attributes_fields" />
+ </tal:block>
- <div class="indent"
- tal:define="attributes iface/getAttributes;
- fields iface/getFields">
+ <tal:block define="methods iface/getMethods">
+ <metal:block use-macro="context/@@interface_macros/methods" />
+ </tal:block>
- <ul class="attr-list"
- tal:condition="python: attributes or fields">
-
- <li tal:repeat="attr attributes">
- <b><code tal:content="attr/name">attr</code></b>
- <span i18n:translate="">(Attribute)</span><br>
- <div class="inline-documentation" tal:content="structure attr/doc">
- attr desc
- </div>
- </li>
-
- <li tal:repeat="field fields">
- <b tal:attributes="class field/required_css">
- <code tal:content="field/name">field</code>
- <span tal:condition="field/required">*</span>
- </b>
- - <a href=""
- tal:attributes="
- href string:../../../Interface/${field/iface/id}/apiindex.html">
- <code tal:content="field/iface/name">IField</code></a>
- (<span i18n:translate="">default</span> =
- <code tal:content="field/default" />)<br />
- <div tal:content="structure field/title" class="field-title">title</div>
- <span tal:content="field/description">field desc</span>
- </li>
-
- </ul>
-
- <p tal:condition="python: not (attributes or fields)">
- <em i18n:translate="">There are no attributes or fields specified.</em>
- </p>
-
- </div>
-
-
-
- <h2 class="details-section" i18n:translate="">Methods</h2>
-
- <div class="indent"
- tal:define="methods iface/getMethods">
-
- <ul class="attr-list" tal:condition="methods">
- <li tal:repeat="method methods">
- <b><code
- tal:content="string:${method/name}${method/signature}" />
- </b><br>
- <div class="inline-documentation" tal:content="structure method/doc">
- method desc
- </div>
- </li>
- </ul>
-
- <p tal:condition="not: methods">
- <em i18n:translate="">There are no methods or fields specified.</em>
- </p>
-
- </div>
-
- <p>
- <em><b class="required">*</b> =
- <span i18n:translate="">required</span></em>
- </p>
-
</body>
</html>
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/tests.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/tests.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -16,62 +16,37 @@
$Id$
"""
import unittest
+from zope.testing import doctest, doctestunit
-from zope.publisher.browser import TestRequest
-from zope.testing.doctestunit import DocTestSuite
-
-from zope.app import zapi
+from zope.app.location.traversing import LocationPhysicallyLocatable
from zope.app.testing import placelesssetup, ztapi
-
-from zope.app.apidoc.interfaces import IDocumentationModule
-from zope.app.apidoc.tests import Root
-from zope.app.apidoc.ifacemodule import InterfaceModule
-from zope.app.apidoc.classmodule import ClassModule
-from zope.app.apidoc.utilitymodule import UtilityModule, Utility
-from browser import UtilityDetails
-
+from zope.app.traversing.interfaces import IPhysicallyLocatable
from zope.app.tree.interfaces import IUniqueId
from zope.app.tree.adapters import LocationUniqueId
-from zope.app.traversing.interfaces import IPhysicallyLocatable
-from zope.app.location.traversing import LocationPhysicallyLocatable
-
def setUp(test):
placelesssetup.setUp()
- gsm = zapi.getGlobalSiteManager()
- gsm.provideUtility(IDocumentationModule, InterfaceModule(), '')
- gsm.provideUtility(IDocumentationModule, ClassModule(), 'Classes')
ztapi.provideAdapter(None, IUniqueId, LocationUniqueId)
ztapi.provideAdapter(None, IPhysicallyLocatable,
LocationPhysicallyLocatable)
-def makeRegistration(name, interface, component):
- return type('RegistrationStub', (),
- {'name': name, 'provided': interface,
- 'component': component, 'doc': ''})()
-
-def getDetailsView():
- utils = UtilityModule()
- utils.__parent__ = Root
- utils.__name__ = 'Utility'
- util = Utility(
- utils,
- makeRegistration('Classes', IDocumentationModule, ClassModule()))
- details = UtilityDetails()
- details.context = util
- details.request = TestRequest()
- return details
-
def test_suite():
return unittest.TestSuite((
- DocTestSuite('zope.app.apidoc.utilitymodule',
- setUp=setUp, tearDown=placelesssetup.tearDown),
- DocTestSuite('zope.app.apidoc.utilitymodule.browser',
- setUp=setUp, tearDown=placelesssetup.tearDown),
+ doctest.DocFileSuite('README.txt',
+ setUp=setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE|
+ doctest.ELLIPSIS),
+ doctest.DocFileSuite('browser.txt',
+ setUp=setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
))
if __name__ == '__main__':
- unittest.main()
+ unittest.main(default="test_suite")
Added: Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,123 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Utility Documentation Module
+
+$Id: __init__.py 29199 2005-02-17 22:38:55Z srichter $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.component.site import UtilityRegistration
+from zope.interface import implements
+
+from zope.app import zapi
+from zope.app.i18n import ZopeMessageIDFactory as _
+from zope.app.component import queryNextSiteManager
+from zope.app.location.interfaces import ILocation
+from zope.app.apidoc.interfaces import IDocumentationModule
+from zope.app.apidoc.utilities import ReadContainerBase, getPythonPath
+
+# Constant used when the utility has no name
+NONAME = '__noname__'
+
+class Utility(object):
+ """Representation of a utility for the API Documentation"""
+ implements(ILocation)
+
+ def __init__(self, parent, reg):
+ """Initialize Utility object."""
+ self.__parent__ = parent
+ self.__name__ = reg.name or NONAME
+ self.registration = reg
+ self.interface = reg.provided
+ self.component = reg.component
+ self.doc = reg.doc
+
+
+class UtilityInterface(ReadContainerBase):
+ """Representation of an interface a utility provides."""
+ implements(ILocation)
+
+ def __init__(self, parent, name, interface):
+ self.__parent__ = parent
+ self.__name__ = name
+ self.interface = interface
+
+ def get(self, key, default=None):
+ """See zope.app.container.interfaces.IReadContainer"""
+ sm = zapi.getGlobalSiteManager()
+ if key == NONAME:
+ key = ''
+ utils = [Utility(self, reg)
+ for reg in sm.registrations()
+ if zapi.isinstance(reg, UtilityRegistration) and \
+ reg.name == key and reg.provided == self.interface]
+ return utils and utils[0] or default
+
+ def items(self):
+ """See zope.app.container.interfaces.IReadContainer"""
+ sm = zapi.getGlobalSiteManager()
+ items = [(reg.name or NONAME, Utility(self, reg))
+ for reg in sm.registrations()
+ if zapi.isinstance(reg, UtilityRegistration) and \
+ self.interface == reg.provided]
+ items.sort()
+ return items
+
+
+class UtilityModule(ReadContainerBase):
+ """Represent the Documentation of all Interfaces.
+
+ This documentation is implemented using a simple `IReadContainer`. The
+ items of the container are all utility interfaces.
+ """
+ implements(IDocumentationModule)
+
+ # See zope.app.apidoc.interfaces.IDocumentationModule
+ title = _('Utilities')
+
+ # See zope.app.apidoc.interfaces.IDocumentationModule
+ description = _("""
+ Utilities are also nicely registered in a site manager, so that it is easy
+ to create a listing of available utilities. A utility is identified by the
+ providing interface and a name, which can be empty. The menu provides you
+ with a list of interfaces that utilities provide and as sub-items the
+ names of the various implementations.
+
+ Again, the documentation of a utility lists all the attributes/fields and
+ methods the utility provides and provides a link to the implementation.
+ """)
+
+ def get(self, key, default=None):
+ parts = key.split('.')
+ try:
+ mod = __import__('.'.join(parts[:-1]), {}, {}, ('*',))
+ except ImportError:
+ return default
+ else:
+ return UtilityInterface(self, key, getattr(mod, parts[-1], default))
+
+ def items(self):
+ sm = zapi.getSiteManager()
+ ifaces = {}
+ while sm is not None:
+ for reg in sm.registrations():
+ if isinstance(reg, UtilityRegistration):
+ path = getPythonPath(reg.provided)
+ ifaces[path] = UtilityInterface(self, path, reg.provided)
+ sm = queryNextSiteManager(sm)
+
+ items = ifaces.items()
+ items.sort(lambda x, y: cmp(x[0].split('.')[-1], y[0].split('.')[-1]))
+ return items
+
Property changes on: Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/version.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/version.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/version.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1 +1 @@
-apidoc 0.1
\ No newline at end of file
+apidoc 0.2
Added: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/README.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/README.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,110 @@
+=============================
+The ZCML Documentation Module
+=============================
+
+This documentation module provides you with a complete reference of all
+directives available on your Zope 3 installation.
+
+
+`ZCMLModule` class
+------------------
+
+The ZCML module class manages all available ZCML namespaces. Once we
+initialize the module
+
+ >>> from zope.app.apidoc.zcmlmodule import ZCMLModule
+ >>> module = ZCMLModule()
+
+it evaluates all meta directives and creates the namspace list:
+
+ >>> module.get('http://namespaces.zope.org/browser').getFullName()
+ 'http://namespaces.zope.org/browser'
+
+You can also access the namespace via its encoded form:
+
+ >>> module.get(
+ ... 'http_co__sl__sl_namespaces.zope.org_sl_browser').getFullName()
+ 'http://namespaces.zope.org/browser'
+
+and via its short form:
+
+ >>> module.get('browser').getFullName()
+ 'http://namespaces.zope.org/browser'
+
+If the module does not exist, the usual `None` is returned:
+
+ >>> module.get('foo') is None
+ True
+
+You can also list all namespaces:
+
+ >>> names = [n for n, ns in module.items()]
+ >>> 'ALL' in names
+ True
+ >>> 'http_co__sl__sl_namespaces.zope.org_sl_browser' in names
+ True
+ >>> 'http_co__sl__sl_namespaces.zope.org_sl_meta' in names
+ True
+
+
+`Namespace` class
+-----------------
+
+Simple namespace object for the ZCML Documentation Module.
+
+The namespace manages a particular ZCML namespace. The object always
+expects the parent to be a `ZCMLModule` instance. So let's create a namespace:
+
+ >>> module = ZCMLModule()
+ >>> module._makeDocStructure()
+ >>> from zope.app.apidoc.zcmlmodule import Namespace
+ >>> ns = Namespace(ZCMLModule(), 'http://namespaces.zope.org/browser')
+
+We can now get its short name, which is the name without the URL prefix:
+
+ >>> ns.getShortName()
+ 'browser'
+
+and its full name in unquoted form:
+
+ >>> ns.getFullName()
+ 'http://namespaces.zope.org/browser'
+
+or even quoted:
+
+ >>> ns.getQuotedName()
+ 'http_co__sl__sl_namespaces.zope.org_sl_browser'
+
+One can get a directive using the common mapping interface:
+
+ >>> ns.get('pages').__name__
+ 'pages'
+
+ >>> ns.get('foo') is None
+ True
+
+ >>> print '\n'.join([name for name, dir in ns.items()][:4])
+ addMenuItem
+ addform
+ addview
+ addwizard
+
+
+`quoteNS(ns)`
+-------------
+
+Quotes a namespace to make it URL-secure.
+
+ >>> from zope.app.apidoc.zcmlmodule import quoteNS
+ >>> quoteNS('http://namespaces.zope.org/browser')
+ 'http_co__sl__sl_namespaces.zope.org_sl_browser'
+
+
+`unquoteNS(ns)`
+---------------
+
+Un-quotes a namespace from a URL-secure version.
+
+ >>> from zope.app.apidoc.zcmlmodule import unquoteNS
+ >>> unquoteNS('http_co__sl__sl_namespaces.zope.org_sl_browser')
+ 'http://namespaces.zope.org/browser'
Property changes on: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/__init__.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/__init__.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -36,64 +36,21 @@
subdirs = None
def quoteNS(ns):
- """Quotes a namespace to make it URL-secure.
-
- Example::
-
- >>> quoteNS('http://namespaces.zope.org/browser')
- 'http_co__sl__sl_namespaces.zope.org_sl_browser'
- """
+ """Quotes a namespace to make it URL-secure."""
ns = ns.replace(':', '_co_')
ns = ns.replace('/', '_sl_')
return ns
def unquoteNS(ns):
- """Un-quotes a namespace from a URL-secure version.
-
- Example::
-
- >>> unquoteNS('http_co__sl__sl_namespaces.zope.org_sl_browser')
- 'http://namespaces.zope.org/browser'
- """
+ """Un-quotes a namespace from a URL-secure version."""
ns = ns.replace('_sl_', '/')
ns = ns.replace('_co_', ':')
return ns
class Namespace(ReadContainerBase):
- r"""Simple namespace object for the ZCML Documentation Module.
+ """Simple namespace object for the ZCML Documentation Module."""
- The namespace manages a particular ZCML namespace. The object always
- expects the parent to be a `ZCMLModule` instance.
-
- Demonstration::
-
- >>> module = ZCMLModule()
- >>> module._makeDocStructure()
- >>> ns = Namespace(ZCMLModule(), 'http://namespaces.zope.org/browser')
-
- >>> ns.getShortName()
- 'browser'
-
- >>> ns.getFullName()
- 'http://namespaces.zope.org/browser'
-
- >>> ns.getQuotedName()
- 'http_co__sl__sl_namespaces.zope.org_sl_browser'
-
- >>> ns.get('pages').__name__
- 'pages'
-
- >>> ns.get('foo') is None
- True
-
- >>> print '\n'.join([name for name, dir in ns.items()][:4])
- addMenuItem
- addform
- addview
- addwizard
- """
-
implements(ILocation)
def __init__(self, parent, name):
@@ -152,38 +109,11 @@
class ZCMLModule(ReadContainerBase):
- r"""Represent the Documentation of all Interfaces.
+ r"""Represent the Documentation of all ZCML namespaces.
This documentation is implemented using a simple `IReadContainer`. The
- items of the container are all the interfaces listed in the closest
- site manager and above.
+ items of the container."""
- Demonstration::
-
- >>> module = ZCMLModule()
-
- >>> module.get('http://namespaces.zope.org/browser').getFullName()
- 'http://namespaces.zope.org/browser'
-
- >>> module.get(
- ... 'http_co__sl__sl_namespaces.zope.org_sl_browser').getFullName()
- 'http://namespaces.zope.org/browser'
-
- >>> module.get('browser').getFullName()
- 'http://namespaces.zope.org/browser'
-
- >>> module.get('foo') is None
- True
-
- >>> names = [ns.getShortName() for n, ns in module.items()]
- >>> 'browser' in names
- True
- >>> 'meta' in names
- True
- >>> 'ALL' in names
- True
- """
-
implements(IDocumentationModule)
# See zope.app.apidoc.interfaces.IDocumentationModule
Modified: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -29,48 +29,8 @@
from zope.app.apidoc.utilities import getPythonPath, relativizePath
class Menu(object):
- """Menu View Helper Class
+ """Menu View Helper Class"""
- Examples::
-
- >>> from zope.app.tree.node import Node
- >>> from zope.app.apidoc.zcmlmodule import Namespace, Directive
- >>> from zope.app.apidoc.zcmlmodule import ZCMLModule
- >>> from zope.app.apidoc.tests import Root
- >>> menu = Menu()
-
- >>> module = ZCMLModule()
- >>> module.__parent__ = Root()
- >>> module.__name__ = 'ZCML'
-
- Namespace representing directives available in all namespaces.
-
- >>> ns = Namespace(module, 'ALL')
- >>> node = Node(ns)
- >>> menu.getMenuTitle(node)
- 'All Namespaces'
- >>> menu.getMenuLink(node) is None
- True
-
- From now on we use the browser namespace.
-
- >>> ns = Namespace(module, 'http://namespaces.zope.org/browser')
- >>> node = Node(ns)
- >>> menu.getMenuTitle(node)
- 'browser'
- >>> menu.getMenuLink(node) is None
- True
-
- The namespace has a page directive.
-
- >>> dir = Directive(ns, 'page', None, None, None, None)
- >>> node = Node(dir)
- >>> menu.getMenuTitle(node)
- 'page'
- >>> menu.getMenuLink(node)
- './http_co__sl__sl_namespaces.zope.org_sl_browser/page/index.html'
- """
-
def getMenuTitle(self, node):
"""Return the title of the node that is displayed in the menu."""
obj = node.context
@@ -104,80 +64,23 @@
schema = LocationProxy(schema,
self.context,
getPythonPath(schema))
- details = InterfaceDetails()
+ details = InterfaceDetails(schema, self.request)
details._getFieldName = _getFieldName
- details.context = schema
- details.request = self.request
return details
def getSchema(self):
- """Return the schema of the directive.
-
- Examples::
-
- >>> from zope.interface import Interface
- >>> from zope.publisher.browser import TestRequest
- >>> from tests import getDirective
- >>> details = DirectiveDetails()
- >>> details.context = getDirective()
- >>> details.request = TestRequest()
-
- >>> class IFoo(Interface):
- ... pass
- >>> details.context.schema = IFoo
- >>> iface = details.getSchema()
- >>> if_class = iface.__class__
- >>> if_class.__module__ + '.' + if_class.__name__
- 'zope.app.apidoc.ifacemodule.browser.InterfaceDetails'
- >>> iface.context
- <InterfaceClass zope.app.apidoc.zcmlmodule.browser.IFoo>
- """
+ """Return the schema of the directive."""
return self._getInterfaceDetails(self.context.schema)
def getNamespaceName(self):
- """Return the name of the namespace.
-
- Examples::
-
- >>> from tests import getDirective
- >>> details = DirectiveDetails()
-
- >>> details.context = getDirective()
- >>> details.getNamespaceName()
- 'http://namespaces.zope.org/browser'
-
- >>> details.context.__parent__.__realname__ = 'ALL'
- >>> details.getNamespaceName()
- '<i>all namespaces</i>'
- """
+ """Return the name of the namespace."""
name = zapi.getParent(self.context).getFullName()
if name == 'ALL':
return '<i>all namespaces</i>'
return name
def getFileInfo(self):
- """Get the file where the directive was declared.
-
- Examples::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from zope.configuration.xmlconfig import ParserInfo
- >>> from tests import getDirective
- >>> details = DirectiveDetails()
- >>> details.context = getDirective()
-
- >>> details.getFileInfo() is None
- True
-
- >>> details.context.info = ParserInfo('foo.zcml', 2, 3)
- >>> info = details.getFileInfo()
- >>> pprint(info)
- [('column', 3),
- ('ecolumn', 3),
- ('eline', 2),
- ('file', 'foo.zcml'),
- ('line', 2)]
- """
+ """Get the file where the directive was declared."""
# ZCML directive `info` objects do not have security declarations, so
# everything is forbidden by default. We need to remove the security
# proxies in order to get to the data.
@@ -191,45 +94,13 @@
return None
def getInfo(self):
- """Get the file where the directive was declared.
-
- Examples::
-
- >>> from zope.configuration.xmlconfig import ParserInfo
- >>> from tests import getDirective
- >>> details = DirectiveDetails()
- >>> details.context = getDirective()
-
- >>> details.getInfo() is None
- True
-
- >>> details.context.info = 'info here'
- >>> details.getInfo()
- 'info here'
-
- >>> details.context.info = ParserInfo('foo.zcml', 2, 3)
- >>> details.getInfo() is None
- True
- """
+ """Get the file where the directive was declared."""
if isinstance(self.context.info, (str, unicode)):
return self.context.info
return None
def getHandler(self):
- """Return information about the handler.
-
- Examples::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from zope.configuration.xmlconfig import ParserInfo
- >>> from tests import getDirective
- >>> details = DirectiveDetails()
- >>> details.context = getDirective()
-
- >>> pprint(details.getHandler())
- [('path', 'zope.app.apidoc.zcmlmodule.tests.foo'),
- ('url', 'zope/app/apidoc/zcmlmodule/tests/foo')]
- """
+ """Return information about the handler."""
if self.context.handler is not None:
path = getPythonPath(self.context.handler)
return {'path': path,
@@ -237,41 +108,7 @@
return None
def getSubdirectives(self):
- """Create a list of subdirectives.
-
- Examples::
-
- >>> from zope.app.apidoc.tests import pprint
- >>> from zope.configuration.xmlconfig import ParserInfo
- >>> from zope.interface import Interface
- >>> from zope.publisher.browser import TestRequest
- >>> from tests import getDirective
- >>> details = DirectiveDetails()
- >>> details.context = getDirective()
- >>> details.request = TestRequest()
-
- >>> class IFoo(Interface):
- ... pass
-
- >>> def handler():
- ... pass
-
- >>> details.getSubdirectives()
- []
-
- >>> details.context.subdirs = (
- ... ('browser', 'foo', IFoo, handler, 'info'),)
- >>> info = details.getSubdirectives()[0]
- >>> info['schema'] = info['schema'].__module__ + '.InterfaceDetails'
- >>> pprint(info)
- [('handler',
- [('path', 'zope.app.apidoc.zcmlmodule.browser.handler'),
- ('url', 'zope/app/apidoc/zcmlmodule/browser/handler')]),
- ('info', 'info'),
- ('name', 'foo'),
- ('namespace', 'browser'),
- ('schema', 'zope.app.apidoc.ifacemodule.browser.InterfaceDetails')]
- """
+ """Create a list of subdirectives."""
dirs = []
for ns, name, schema, handler, info in self.context.subdirs:
details = self._getInterfaceDetails(schema)
Added: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.txt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.txt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -0,0 +1,218 @@
+======================================
+Module Menu and ZCML Directive Details
+======================================
+
+
+`Menu` class
+------------
+
+Let's start out by creating a menu. First we isntantiate the class:
+
+ >>> from zope.app.apidoc.zcmlmodule.browser import Menu
+ >>> menu = Menu()
+
+then we create a ZCML module instance:
+
+ >>> from zope.app.apidoc.zcmlmodule import ZCMLModule
+ >>> from zope.app.apidoc.tests import Root
+ >>> module = ZCMLModule()
+ >>> module.__parent__ = Root()
+ >>> module.__name__ = 'ZCML'
+
+Now we create a namespace representing directives available in all namespaces
+
+ >>> from zope.app.apidoc.zcmlmodule import Namespace
+ >>> ns = Namespace(module, 'ALL')
+
+and generate a tree node :
+
+ >>> from zope.app.tree.node import Node
+ >>> node = Node(ns)
+
+We can now ask the menu for the title of the namespace
+
+ >>> menu.getMenuTitle(node)
+ 'All Namespaces'
+
+and the link to the namespace overview.
+
+ >>> menu.getMenuLink(node) is None
+ True
+
+Since the 'ALL' namespace is not that useful, let's create a namespace
+instance for the browser namespace:
+
+ >>> ns = Namespace(module, 'http://namespaces.zope.org/browser')
+ >>> node = Node(ns)
+
+And again we can get its title and menu link:
+
+ >>> menu.getMenuTitle(node)
+ 'browser'
+ >>> menu.getMenuLink(node) is None
+ True
+
+Now we add the `page` directive to the browser namespace:
+
+ >>> from zope.app.apidoc.zcmlmodule import Directive
+ >>> dir = Directive(ns, 'page', None, None, None, None)
+ >>> node = Node(dir)
+
+And we can get its menu title and link.
+
+ >>> menu.getMenuTitle(node)
+ 'page'
+ >>> menu.getMenuLink(node)
+ './http_co__sl__sl_namespaces.zope.org_sl_browser/page/index.html'
+
+Note that the directive's namespace URL is encoded, so it can be used in a
+URL.
+
+
+`DirectiveDetails` class
+------------------------
+
+A browser view class that provides support for the ZCML directive overview.
+
+Let's create a directive that we can use as context for the details:
+
+ >>> from zope.interface import Interface, Attribute
+ >>> class IFoo(Interface):
+ ... class_ = Attribute('class_')
+
+ >>> def foo():
+ ... pass
+
+ >>> directive = Directive(ns, 'page', IFoo, foo, None, ())
+
+Now we can isntantiate the view:
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> from zope.app.apidoc.zcmlmodule.browser import DirectiveDetails
+
+ >>> details = DirectiveDetails()
+ >>> details.context = directive
+ >>> details.request = TestRequest()
+
+We are now ready to see what the details class has to offer.
+
+
+`getSchema()`
+~~~~~~~~~~~~~
+
+Returns the interface details class for the schema.
+
+ >>> iface_details = details.getSchema()
+
+ >>> iface_details #doctest:+ELLIPSIS
+ <zope.app.apidoc.ifacemodule.browser.InterfaceDetails object at ...>
+
+ >>> iface_details.context
+ <InterfaceClass __builtin__.IFoo>
+
+The `_getFieldName()` method of the interface details has been overridden to
+neglect trailing underscores in the field name. This is necessary, since
+Python keywords cannot be used as field names:
+
+ >>> iface_details._getFieldName(IFoo['class_'])
+ 'class'
+
+
+`getNamespaceName()`
+~~~~~~~~~~~~~~~~~~~~
+
+Return the name of the namespace.
+
+ >>> details.getNamespaceName()
+ 'http://namespaces.zope.org/browser'
+
+If the directive is in the 'ALL' namespace, a special string is returned:
+
+ >>> details2 = DirectiveDetails()
+ >>> ns2 = Namespace(module, 'ALL')
+ >>> details2.context = Directive(ns2, 'include', None, None, None, None)
+
+ >>> details2.getNamespaceName()
+ '<i>all namespaces</i>'
+
+
+`getFileInfo()`
+~~~~~~~~~~~~~~~
+
+Get the file where the directive was declared. If the info attribute is not
+set, return `None`:
+
+ >>> details.getFileInfo() is None
+ True
+
+If the info attribute is a parser info, then return the details:
+
+ >>> from zope.configuration.xmlconfig import ParserInfo
+ >>> details.context.info = ParserInfo('foo.zcml', 2, 3)
+ >>> info = details.getFileInfo()
+ >>> pprint(info)
+ {'column': 3,
+ 'ecolumn': 3,
+ 'eline': 2,
+ 'file': 'foo.zcml',
+ 'line': 2}
+
+If the info is a string, `None` should be returned again:
+
+ >>> details.context.info = 'info here'
+ >>> details.getFileInfo() is None
+ True
+
+
+`getInfo()`
+~~~~~~~~~~~
+
+Get the configuration information string of the directive:
+
+ >>> details.context.info = 'info here'
+ >>> details.getInfo()
+ 'info here'
+
+Return `None`, if the info attribute is a parser info:
+
+ >>> details.context.info = ParserInfo('foo.zcml', 2, 3)
+ >>> details.getInfo() is None
+ True
+
+
+`getHandler()`
+~~~~~~~~~~~~~~
+
+Return information about the directive handler object.
+
+ >>> pprint(details.getHandler())
+ {'path': 'None.foo',
+ 'url': 'None/foo'}
+
+
+`getSubdirectives()`
+~~~~~~~~~~~~~~~~~~~~
+
+Create a list of subdirectives. Currently, we have not specifiedany
+subdirectives
+
+ >>> details.getSubdirectives()
+ []
+
+but if we add one
+
+ >>> def handler():
+ ... pass
+
+ >>> details.context.subdirs = (
+ ... ('browser', 'foo', IFoo, handler, 'info'),)
+
+the result becomes more interesting:
+
+ >>> pprint(details.getSubdirectives()) #doctest:+ELLIPSIS
+ [{'handler': {'path': 'None.handler',
+ 'url': 'None/handler'},
+ 'info': 'info',
+ 'name': 'foo',
+ 'namespace': 'browser',
+ 'schema': <zope.app.apidoc.ifacemodule.browser.InterfaceDetails ...>}]
\ No newline at end of file
Property changes on: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/index.pt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/index.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -1,6 +1,7 @@
<html metal:use-macro="views/apidoc_macros/details">
<body metal:fill-slot="contents"
- tal:define="schema view/getSchema">
+ tal:define="schema view/getSchema;
+ rootURL string:../../..">
<h1 class="details-header">
<span tal:replace="context/zope:name" />
@@ -37,7 +38,7 @@
<i i18n:translate="">Handler:</i>
<a href=""
tal:attributes="href
- string:../../../Class/${handler/url}/index.html"
+ string:../../../Code/${handler/url}/index.html"
tal:content="handler/path">
</a>
</div>
@@ -58,18 +59,7 @@
tal:condition="fields">
<li tal:repeat="field fields">
- <b tal:attributes="class field/required_css">
- <code tal:content="field/name">field</code>
- <span tal:condition="field/required">*</span>
- </b>
- - <a href=""
- tal:attributes="href
- string:../../../Class/${field/class/path}/index.html">
- <code tal:content="field/class/name">Field</code></a>
- (<span i18n:translate="">default</span> =
- <code tal:content="field/default" />)<br />
- <div tal:content="structure field/title" class="field-title">title</div>
- <span tal:content="structure field/description">field desc</span>
+ <metal:block use-macro="context/@@interface_macros/field" />
</li>
</ul>
@@ -80,7 +70,7 @@
</div>
- <tal:omit-tag
+ <tal:block
define="dir view/getSubdirectives"
condition="dir">
@@ -93,10 +83,8 @@
directive
</h3>
- <div>
- <div class="documentation" tal:content="structure dir/schema/getDoc">
- Here is the doc string
- </div>
+ <div class="documentation" tal:content="structure dir/schema/getDoc">
+ Here is the doc string
</div>
<br />
@@ -106,7 +94,7 @@
<i i18n:translate="">Handler:</i>
<a href=""
tal:attributes="href
- string:../../../Class/${dir/handler/url}/index.html"
+ string:../../../Code/${dir/handler/url}/index.html"
tal:content="dir/handler/path">
</a>
</div>
@@ -115,42 +103,31 @@
<a href=""
tal:attributes="href
string:../../../Interface/${dir/schema/getId}/apiindex.html">
- <h4 tal:content="dir/schema/getId">zope.fields.Schema</h4>
+ <h3 tal:content="dir/schema/getId">zope.fields.Schema</h3>
</a>
</div>
<div class="indent"
tal:define="fields dir/schema/getFields">
- <ul class="attr-list"
- tal:condition="fields">
-
- <li tal:repeat="field fields">
- <b tal:attributes="class field/required_css">
- <code tal:content="field/name">field</code>
- <span tal:condition="field/required">*</span>
- </b>
- - <a href=""
- tal:attributes="href
- string:../../../Interface/${field/iface/id}/apiindex.html">
- <code tal:content="field/iface/name">IField</code></a>
- (<span i18n:translate="">default</span> =
- <code tal:content="field/default" />)<br />
- <div tal:content="structure field/title" class="field-title">title</div>
- <span tal:content="structure field/description">field desc</span>
- </li>
+ <ul class="attr-list"
+ tal:condition="fields">
+
+ <li tal:repeat="field fields">
+ <metal:block use-macro="context/@@interface_macros/field" />
+ </li>
+
+ </ul>
+
+ <p tal:condition="not: fields">
+ <em i18n:translate="">There are no fields specified.</em>
+ </p>
- </ul>
-
- <p tal:condition="not: fields">
- <em i18n:translate="">There are no fields specified.</em>
- </p>
-
</div>
</div>
- </tal:omit-tag>
+ </tal:block>
<p>
<em><b class="required">*</b> =
Modified: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/tests.py 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/tests.py 2005-02-23 22:22:48 UTC (rev 29269)
@@ -17,7 +17,7 @@
"""
import os
import unittest
-from zope.testing.doctestunit import DocTestSuite
+from zope.testing import doctest, doctestunit
from zope.app.testing import placelesssetup, ztapi
from zope.app.apidoc.tests import Root
@@ -62,11 +62,15 @@
def test_suite():
return unittest.TestSuite((
- DocTestSuite('zope.app.apidoc.zcmlmodule',
- setUp=setUp, tearDown=tearDown),
- DocTestSuite('zope.app.apidoc.zcmlmodule.browser',
- setUp=setUp, tearDown=tearDown),
+ doctest.DocFileSuite('README.txt',
+ setUp=setUp, tearDown=tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
+ doctest.DocFileSuite('browser.txt',
+ setUp=setUp, tearDown=tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE),
))
if __name__ == '__main__':
- unittest.main()
+ unittest.main(default='test_suite')
Modified: Zope3/trunk/src/zope/app/introspector/introspector.pt
===================================================================
--- Zope3/trunk/src/zope/app/introspector/introspector.pt 2005-02-23 22:17:22 UTC (rev 29268)
+++ Zope3/trunk/src/zope/app/introspector/introspector.pt 2005-02-23 22:22:48 UTC (rev 29269)
@@ -113,7 +113,7 @@
<td><a tal:define="path python: (introspector.getModule()
+ '.' + introspector.getClass()).replace('.', '/')"
tal:attributes="href
- string: /++apidoc++/Class/${path}/index.html"
+ string: /++apidoc++/Code/${path}/index.html"
href="">
<span tal:replace="introspector/getModule">Module</span
>.<span tal:replace="introspector/getClass">Name</span></a></td>
@@ -129,7 +129,7 @@
<a tal:define="path
python: path('repeat/base/item').replace('.', '/')"
tal:attributes="href
- string: /++apidoc++/Class/${path}/index.html"
+ string: /++apidoc++/Code/${path}/index.html"
href=""><span tal:replace="repeat/base/item" /></a>
</div>
</td>
More information about the Zope3-Checkins
mailing list