[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/ Using the static
apidoc generator I have fixed many problems with
Stephan Richter
srichter at cosmos.phy.tufts.edu
Sat Oct 29 19:25:40 EDT 2005
Log message for revision 39722:
Using the static apidoc generator I have fixed many problems with
unreachable URLs. Changes include:
- Always use absolute URLs to reference to other modules in the interface
details.
- Be much more careful in deciding which objects are referencable, and
this have links. Also, now the calculation of the object to be
referenced is much more careful.
- The details page for interfaces is now called "index.html" like for all
other objects. That allowed some code simplification.
- Allow the exclusion of certain modules from the safe_import.
- The ZCML file view has now many more links thanks to a bug fix.
- Docstrings are now dedented as required for good ReST formatting. Doing
this was suggested by the docutils mailing list.
- The generator now tells you how many URL handling errors occurred during
the generation phase.
Changed:
U Zope3/trunk/src/zope/app/apidoc/classregistry.py
U Zope3/trunk/src/zope/app/apidoc/classregistry.txt
U Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_index.pt
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.pt
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.txt
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module_index.pt
U Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/module.py
U Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py
U Zope3/trunk/src/zope/app/apidoc/component.py
U Zope3/trunk/src/zope/app/apidoc/component.txt
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt
U 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
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/index.pt
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py
U Zope3/trunk/src/zope/app/apidoc/ifacemodule/presentation_macros.pt
U Zope3/trunk/src/zope/app/apidoc/interface.py
U Zope3/trunk/src/zope/app/apidoc/interface.txt
U Zope3/trunk/src/zope/app/apidoc/static.py
U Zope3/trunk/src/zope/app/apidoc/tests.py
U Zope3/trunk/src/zope/app/apidoc/typemodule/browser.py
U Zope3/trunk/src/zope/app/apidoc/utilities.py
U Zope3/trunk/src/zope/app/apidoc/utilities.txt
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.py
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/index.pt
U Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py
U Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py
U 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/interpreter/python.py
U Zope3/trunk/src/zope/app/onlinehelp/browser/tree.py
-=-
Modified: Zope3/trunk/src/zope/app/apidoc/classregistry.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classregistry.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/classregistry.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -19,6 +19,9 @@
__import_unknown_modules__ = False
+# List of modules that should never be imported.
+IGNORE_MODULES = []
+
import sys
from zope.app import zapi
@@ -55,9 +58,16 @@
def safe_import(path, default=None):
"""Import a given path as efficiently as possible and without failure."""
module = sys.modules.get(path, default)
+ for exclude_name in IGNORE_MODULES:
+ if path.startswith(exclude_name):
+ return default
if module is default and __import_unknown_modules__:
try:
module = __import__(path, {}, {}, ('*',))
except ImportError:
return default
+ # Some software, we cannot control, might raise all sorts of errors;
+ # thus catch all exceptions and return the default.
+ except Exception, error:
+ return default
return module
Modified: Zope3/trunk/src/zope/app/apidoc/classregistry.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/classregistry.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/classregistry.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -161,7 +161,42 @@
>>> del sys.modules['zope.app.apidoc.testmodule']
+Importing some code we cannot control, such as twisted, might raise errors
+when imported without having a certain environment. In those cases, the safe
+import should prevent the error from penetrating:
+
+ >>> import os, tempfile
+ >>> dir = tempfile.mkdtemp()
+ >>> open(os.path.join(dir, 'alwaysfail.py'), 'w').write('raise ValueError\n')
+ >>> sys.path.insert(0, dir)
+
+ >>> safe_import('alwaysfail') is None
+ True
+
+ >>> del sys.path[0]
+
+ >>> import shutil
+ >>> shutil.rmtree(dir)
+
+Another method to explicitely turning off the import of certain modules is to
+declare that they should be ignored. For example, if we tell the class
+registry to ignore ``zope.app``,
+
+ >>> classregistry.IGNORE_MODULES.append('zope.app')
+
+then we cannot import it anymore, even though we know it is available:
+
+ >>> safe_import('zope.app') is None
+ True
+
+Note that all sub-packages are also unavailable:
+
+ >>> safe_import('zope.app.apidoc') is None
+ True
+
We also need to play nice concerning variables and have to reset the module
globals:
- >>> classregistry.__import_unknown_modules__ = False
\ No newline at end of file
+ >>> classregistry.IGNORE_MODULES.pop()
+ 'zope.app'
+ >>> classregistry.__import_unknown_modules__ = False
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/README.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -62,6 +62,7 @@
>>> 'meta.zcml' in keys
True
+ >>> import zope.app.apidoc.browser
>>> print module['browser'].getPath()
zope.app.apidoc.browser
@@ -74,13 +75,14 @@
classes hierarchy (since they do not provide or implement any API), we can
still get to them:
+ >>> import zope.app.apidoc.tests
>>> print module['tests'].getPath()
zope.app.apidoc.tests
>>> names = module['tests'].keys()
>>> names.sort()
>>> names
- ['Root', 'rootLocation', 'setUp', 'test_suite']
+ ['Root', 'rootLocation', 'setUp', 'tearDown', 'test_suite']
Classes
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/README.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -311,18 +311,6 @@
The result is a bit strange, since the ZCML Documentation module is the
containment root.
-`ifaceURL(value, field, rootURL)`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This method converts the string value of the field to an interface and then
-crafts a documentation URL for it:
-
- >>> from zope.configuration.fields import GlobalInterface
- >>> field = GlobalInterface()
-
- >>> details.ifaceURL('.interfaces.IZCMLFile', field, '')
- '/../Interface/zope.app.apidoc.codemodule.interfaces.IZCMLFile/apiindex.html'
-
`objectURL(value, field, rootURL)`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -333,7 +321,7 @@
>>> field = GlobalObject()
>>> details.objectURL('.interfaces.IZCMLFile', field, '')
- '/../Interface/zope.app.apidoc.codemodule.interfaces.IZCMLFile/apiindex.html'
+ '/../Interface/zope.app.apidoc.codemodule.interfaces.IZCMLFile/index.html'
>>> details.objectURL('.zcml.ZCMLFile', field, '')
'/zope/app/apidoc/codemodule/zcml/ZCMLFile/index.html'
@@ -534,7 +522,7 @@
'signature': '()',
'write_perm': None},
...
- {'doc': u'<dl class="docutils">\n<dt>Return a sequence-like...',
+ {'doc': u'<p>Return a sequence-like...',
'interface': 'zope.interface.common.mapping.IEnumerableMapping',
'name': 'keys',
'read_perm': None,
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -24,6 +24,7 @@
from zope.app.apidoc.interfaces import IDocumentationModule
from zope.app.apidoc.utilities import getPythonPath, getPermissionIds
from zope.app.apidoc.utilities import renderText, getFunctionSignature
+from zope.app.apidoc.utilities import isReferencable
from zope.app.traversing.interfaces import TraversalError
@@ -31,7 +32,7 @@
if type is types.NoneType:
return None
path = getPythonPath(type)
- return path.replace('.', '/')
+ return isReferencable(path) and path.replace('.', '/') or None
class ClassDetails(object):
"""Represents the details of the class."""
@@ -65,7 +66,7 @@
# 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})
+ info.append({'path': path or None, 'url': url})
return info
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_index.pt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/class_index.pt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -48,7 +48,7 @@
<li tal:repeat="iface ifaces">
<a href=""
tal:attributes="href
- string:${view/getBaseURL}/Interface/$iface/apiindex.html"
+ string:${view/getBaseURL}/Interface/$iface/index.html"
tal:content="iface" />
</li>
</ul>
@@ -75,7 +75,7 @@
<tal:omit-tag condition="attr/type_link">
(<span i18n:translate="">type:</span>
<a href=""
- tal:attributes="href
+ tal:attributes="href
string:${view/getBaseURL}/Code/${attr/type_link}/index.html">
<code tal:content="attr/type" /></a>)
</tal:omit-tag>
@@ -87,7 +87,7 @@
<i i18n:translate="">Interface:</i>
<a href=""
tal:attributes="href
- string:${view/getBaseURL}/Interface/${attr/interface}/apiindex.html"
+ string:${view/getBaseURL}/Interface/${attr/interface}/index.html"
tal:content="attr/interface">Iface</a><br />
</span>
<span class="small"
@@ -128,7 +128,7 @@
<i i18n:translate="">Interface:</i>
<a href=""
tal:attributes="href
- string:${view/getBaseURL}/Interface/${method/interface}/apiindex.html"
+ string:${view/getBaseURL}/Interface/${method/interface}/index.html"
tal:content="method/interface">Iface</a><br/>
</span>
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/function.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -18,8 +18,10 @@
__docformat__ = 'restructuredtext'
from zope.app import zapi
from zope.app.apidoc.interfaces import IDocumentationModule
-from zope.app.apidoc.utilities import getPythonPath, renderText
+from zope.app.apidoc.utilities import renderText
+from class_ import getTypeLink
+
class FunctionDetails(object):
"""Represents the details of the function."""
@@ -34,7 +36,7 @@
return [{'name': name,
'value': `attr`,
'type': type(attr).__name__,
- 'type_link': getPythonPath(type(attr)).replace('.', '/')}
+ 'type_link': getTypeLink(type(attr))}
for name, attr in self.context.getAttributes()]
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.pt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.pt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -43,7 +43,7 @@
<li tal:repeat="iface ifaces">
<a href=""
tal:attributes="href
- string:${view/getBaseURL}/Interface/$iface/apiindex.html"
+ string:${view/getBaseURL}/Interface/$iface/index.html"
tal:content="iface" />
</li>
</ul>
@@ -63,7 +63,7 @@
<li tal:repeat="iface ifaces">
<a href=""
tal:attributes="href
- string:${view/getBaseURL}/Interface/$iface/apiindex.html"
+ string:${view/getBaseURL}/Interface/$iface/index.html"
tal:content="iface" />
</li>
</ul>
@@ -129,7 +129,7 @@
<i i18n:translate="">Interface:</i>
<a href=""
tal:attributes="href
- string:${view/getBaseURL}/Interface/${attr/interface}/apiindex.html"
+ string:${view/getBaseURL}/Interface/${attr/interface}/index.html"
tal:content="attr/interface">Iface</a><br />
</span>
<span class="small"
@@ -169,7 +169,7 @@
<i i18n:translate="">Interface:</i>
<a href=""
tal:attributes="href
- string:${view/getBaseURL}/Interface/${method/interface}/apiindex.html"
+ string:${view/getBaseURL}/Interface/${method/interface}/index.html"
tal:content="method/interface">Iface</a><br/>
</span>
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -34,7 +34,8 @@
if type is types.NoneType:
return None
path = apidoc.utilities.getPythonPath(type)
- return path.replace('.', '/')
+ importable = apidoc.utilities.isReferencable(path)
+ return importable and path.replace('.', '/') or None
class annotationsNamespace(object):
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/introspector.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -32,10 +32,10 @@
see those:
>>> browser.getLink('zope.app.component.interfaces.ISite').url
- '.../++apidoc++/Interface/zope.app.component.interfaces.ISite/apiindex.html'
+ '.../++apidoc++/Interface/zope.app.component.interfaces.ISite/index.html'
>>> browser.getLink('zope.app.folder.interfaces.IRootFolder').url
- '...apidoc++/Interface/zope.app.folder.interfaces.IRootFolder/apiindex.html'
+ '...apidoc++/Interface/zope.app.folder.interfaces.IRootFolder/index.html'
The next two section, the implemented interfaces and the base classes, are not
instance specific pieces of information, but they are still nice to see at
@@ -43,16 +43,16 @@
interfaces:
>>> browser.getLink('zope.app.folder.interfaces.IFolder').url
- '.../++apidoc++/Interface/zope.app.folder.interfaces.IFolder/apiindex.html'
+ '.../++apidoc++/Interface/zope.app.folder.interfaces.IFolder/index.html'
>>> browser.getLink('persistent.interfaces.IPersistent').url
- '.../++apidoc++/Interface/persistent.interfaces.IPersistent/apiindex.html'
+ '.../++apidoc++/Interface/persistent.interfaces.IPersistent/index.html'
>>> browser.getLink('zope.app.component.interfaces.IPossibleSite').url
- '.../Interface/zope.app.component.interfaces.IPossibleSite/apiindex.html'
+ '.../Interface/zope.app.component.interfaces.IPossibleSite/index.html'
>>> browser.getLink('zope.app.container.interfaces.IContained').url
- '...doc++/Interface/zope.app.container.interfaces.IContained/apiindex.html'
+ '...doc++/Interface/zope.app.container.interfaces.IContained/index.html'
The base classes of the ``Folder`` are as follows:
@@ -110,10 +110,7 @@
<li>
<b><code>get(name, default=None)</code>
</b><br>
- <div class="inline documentation"><dl class="docutils">
- <dt>Return ...
- </dl>
- </div>
+ <div class="inline documentation"><p>Return ... </div>
<span class="small">
<i>Interface:</i>
<a href="...">zope.interface.common.mapping.IReadMapping</a><br />
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module_index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module_index.pt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/module_index.pt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -32,7 +32,7 @@
tal:content="entry/name" />
<a href=""
tal:condition="entry/isinterface"
- tal:attributes="href string:./${entry/name}/apiindex.html"
+ tal:attributes="href string:./${entry/name}/index.html"
tal:content="structure string:<b><i>${entry/name}</i></b>" />
<a href=""
tal:condition="entry/isclass"
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/browser/zcml.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -26,7 +26,7 @@
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
+from zope.app.apidoc.utilities import getPythonPath, isReferencable
from zope.app.apidoc.zcmlmodule import quoteNS
from zope.app.apidoc.codemodule.interfaces import IRootDirective
@@ -88,13 +88,6 @@
link += '#' + subDirective.name[1]
return link
- def ifaceURL(self, value, field, rootURL):
- bound = field.bind(self.context.context)
- iface = bound.fromUnicode(value)
- if iface is None:
- return
- return rootURL+'/../Interface/%s/apiindex.html' %(getPythonPath(iface))
-
def objectURL(self, value, field, rootURL):
bound = field.bind(self.context.context)
obj = bound.fromUnicode(value)
@@ -105,15 +98,15 @@
except AttributeError:
# probably an object that does not like to play nice with the CA
isInterface = False
+
+ # The object mught be an instance; in this case get a link to the class
+ if not hasattr(obj, '__name__'):
+ obj = getattr(obj, '__class__')
+ path = getPythonPath(obj)
if isInterface:
- return rootURL+'/../Interface/%s/apiindex.html' %(
- getPythonPath(obj))
- try:
- return rootURL + '/%s/index.html' %(
- getPythonPath(obj).replace('.', '/'))
- except AttributeError:
- # probably an instance
- pass
+ return rootURL+'/../Interface/%s/index.html' % path
+ if isReferencable(path):
+ return rootURL + '/%s/index.html' %(path.replace('.', '/'))
def attributes(self):
context = removeSecurityProxy(self.context)
@@ -126,10 +119,8 @@
for attr in attrs:
name = (attr['name'] in names) and attr['name'] or attr['name']+'_'
field = context.schema.get(name)
- if zapi.isinstance(field, GlobalInterface):
- attr['url'] = self.ifaceURL(attr['value'], field, rootURL)
- elif zapi.isinstance(field, GlobalObject):
+ if zapi.isinstance(field, (GlobalObject, GlobalInterface)):
attr['url'] = self.objectURL(attr['value'], field, rootURL)
elif zapi.isinstance(field, Tokens):
@@ -137,15 +128,11 @@
values = attr['value'].strip().split()
if len(values) == 1:
attr['value'] = values[0]
- if zapi.isinstance(field, GlobalInterface):
- attr['url'] = self.ifaceURL(values[0], field, rootURL)
- elif zapi.isinstance(field, GlobalObject):
- attr['url'] = self.objectURL(values[0], field, rootURL)
+ attr['url'] = self.objectURL(values[0], field, rootURL)
else:
for value in values:
- if zapi.isinstance(field, GlobalInterface):
- url = self.ifaceURL(value, field, rootURL)
- elif zapi.isinstance(field, GlobalObject):
+ if zapi.isinstance(field,
+ (GlobalObject, GlobalInterface)):
url = self.objectURL(value, field, rootURL)
else:
break
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/class_.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Class representation for code browser
+"""Class representation for code browser
$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
"""
@@ -27,7 +27,6 @@
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
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/codemodule.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -69,7 +69,9 @@
if self.__isSetup:
return
for name, mod in zapi.getUtilitiesFor(IAPIDocRootModule):
- self._children[name] = Module(self, name, safe_import(mod))
+ module = safe_import(mod)
+ if module is not None:
+ self._children[name] = Module(self, name, module)
self.__isSetup = True
def getDocString(self):
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/module.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/module.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/module.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Module representation for code browser
+"""Module representation for code browser
$Id: __init__.py 29143 2005-02-14 22:43:16Z srichter $
"""
@@ -64,14 +64,14 @@
if file in IGNORE_FILES or file in self._children:
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]
@@ -79,11 +79,11 @@
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(path, self._module,
self, file)
-
+
elif os.path.isfile(path) and file.endswith('.txt'):
self._children[file] = TextFile(path, file, self)
@@ -136,11 +136,18 @@
else:
path = key
obj = safe_import(path)
+
if obj is not None:
return Module(self, key, obj)
- return default
+ # Maybe it is a simple attribute of the module
+ if obj is None:
+ obj = getattr(self._module, key, default)
+ if obj is not default:
+ obj = LocationProxy(obj, self, key)
+ return obj
+
def items(self):
"""See zope.app.container.interfaces.IReadContainer."""
return self._children.items()
Modified: Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/codemodule/zcml.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -109,6 +109,9 @@
context = zope.app.appsetup.appsetup.getConfigContext()
context.package = self.package
+ # Shut up i18n domain complaints
+ context.i18n_domain = 'zope'
+
# Since we want to use a custom configuration handler, we need to
# instantiate the parser object ourselves
parser = make_parser()
Modified: Zope3/trunk/src/zope/app/apidoc/component.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/component.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/component.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -22,13 +22,14 @@
from zope.component.site import AdapterRegistration, SubscriptionRegistration
from zope.component.site import UtilityRegistration
from zope.interface import Interface
+from zope.interface.interface import InterfaceClass
from zope.publisher.interfaces import IRequest
from zope.app import zapi
from zope.app.i18n import ZopeMessageFactory as _
from zope.app.apidoc.classregistry import classRegistry
from zope.app.apidoc.utilities import relativizePath, truncateSysPath
-from zope.app.apidoc.utilities import getPythonPath, renderText
+from zope.app.apidoc.utilities import getPythonPath, isReferencable, renderText
from zope.app.apidoc.utilitymodule import utilitymodule
SPECIFIC_INTERFACE_LEVEL = 1
@@ -169,10 +170,10 @@
factory = getRealFactory(reg.value)
path = getPythonPath(factory)
- if isinstance(factory, types.MethodType):
- url = None
- else:
+ url = None
+ if isReferencable(path):
url = path.replace('.', '/')
+
if isinstance(reg.doc, (str, unicode)):
doc = reg.doc
zcml = None
@@ -195,7 +196,6 @@
def getFactoryInfoDictionary(reg):
"""Return a PT-friendly info dictionary for a factory."""
factory = reg.component
-
callable = factory
# Usually only zope.component.factory.Factory instances have this attribute
@@ -210,22 +210,29 @@
'title': getattr(factory, 'title', u''),
'description': renderText(getattr(factory, 'description', u''),
module=callable.__module__),
- 'url': path.replace('.', '/')}
+ 'url': isReferencable(path) and path.replace('.', '/') or None}
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__
+ component = reg.component
+ # Check whether we have an instance of some custom type or not
+ # Unfortunately, a lot of utilities have a `__name__` attribute, so we
+ # cannot simply check for its absence
+ # TODO: Once we support passive display of instances, this insanity can go
+ # away.
+ if not isinstance(component, (types.MethodType, types.FunctionType,
+ types.ClassType, types.TypeType,
+ InterfaceClass)):
+ component = getattr(component, '__class__', component)
+ path = getPythonPath(component)
+
# provided interface id
iface_id = '%s.%s' % (reg.provided.__module__, reg.provided.getName())
- path = getPythonPath(klass)
return {'name': reg.name or _('<i>no name</i>'),
'url_name': utilitymodule.encodeName(reg.name or '__noname__'),
'iface_id': iface_id,
'path': path,
- 'url': path.replace('.', '/')}
+ 'url': isReferencable(path) and path.replace('.', '/') or None}
Modified: Zope3/trunk/src/zope/app/apidoc/component.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/component.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/component.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -138,12 +138,13 @@
>>> classes = component.getClasses(IFooBar)
>>> classes.sort()
>>> classes
- [('MyFooBar', <class 'MyFooBar'>)]
+ [('MyFooBar', <class 'zope.app.apidoc.doctest.MyFooBar'>)]
>>> classes = component.getClasses(IFoo)
>>> classes.sort()
>>> classes
- [('MyFoo', <class 'MyFoo'>), ('MyFooBar', <class 'MyFooBar'>)]
+ [('MyFoo', <class 'zope.app.apidoc.doctest.MyFoo'>),
+ ('MyFooBar', <class 'zope.app.apidoc.doctest.MyFooBar'>)]
`getFactories(ifaces)`
@@ -167,15 +168,15 @@
>>> regs.sort()
>>> regs
[UtilityRegistration('IFactory', 'MyFooBar',
- <Factory for <class 'MyFooBar'>>, '')]
+ <Factory for <class 'zope.app.apidoc.doctest.MyFooBar'>>, '')]
>>> regs = list(component.getFactories(IFoo))
>>> regs.sort()
>>> regs
[UtilityRegistration('IFactory', 'MyFoo',
- <Factory for <class 'MyFoo'>>, ''),
+ <Factory for <class 'zope.app.apidoc.doctest.MyFoo'>>, ''),
UtilityRegistration('IFactory', 'MyFooBar',
- <Factory for <class 'MyFooBar'>>, '')]
+ <Factory for <class 'zope.app.apidoc.doctest.MyFooBar'>>, '')]
`getUtilities(iface)`
@@ -195,13 +196,16 @@
>>> regs = list(component.getUtilities(IFooBar))
>>> regs.sort()
>>> regs #doctest:+ELLIPSIS
- [UtilityRegistration('IFooBar', '', <MyFooBar object at ...>, '')]
+ [UtilityRegistration('IFooBar', '',
+ <zope.app.apidoc.doctest.MyFooBar object at ...>, '')]
>>> regs = list(component.getUtilities(IFoo))
>>> regs.sort()
>>> regs #doctest:+ELLIPSIS
- [UtilityRegistration('IFoo', '', <MyFoo object at ...>, ''),
- UtilityRegistration('IFooBar', '', <MyFooBar object at ...>, '')]
+ [UtilityRegistration('IFoo', '',
+ <zope.app.apidoc.doctest.MyFoo object at ...>, ''),
+ UtilityRegistration('IFooBar', '',
+ <zope.app.apidoc.doctest.MyFooBar object at ...>, '')]
`getInterfaceInfoDictionary(iface)`
@@ -213,7 +217,7 @@
utilities.
>>> pprint(component.getInterfaceInfoDictionary(IFoo))
- {'module': '__builtin__', 'name': 'IFoo'}
+ {'module': 'zope.app.apidoc.doctest', 'name': 'IFoo'}
The functions using this function use it with little care and can also
sometimes pass in `None`. In these cases we want to return `None`:
@@ -241,16 +245,36 @@
>>> pprint(component.getAdapterInfoDictionary(reg))
{'doc': 'doc info',
- 'factory': '__builtin__.MyResult',
- 'factory_url': '__builtin__/MyResult',
+ 'factory': 'zope.app.apidoc.doctest.MyResult',
+ 'factory_url': 'zope/app/apidoc/doctest/MyResult',
'name': 'FooToResult',
- 'provided': {'module': '__builtin__', 'name': 'IResult'},
- 'required': [{'module': '__builtin__', 'name': 'IFoo'},
- {'module': '__builtin__', 'name': 'IBar'}],
+ 'provided': {'module': 'zope.app.apidoc.doctest', 'name': 'IResult'},
+ 'required': [{'module': 'zope.app.apidoc.doctest', 'name': 'IFoo'},
+ {'module': 'zope.app.apidoc.doctest', 'name': 'IBar'}],
'zcml': None}
+If the factory's path cannot be referenced, for example if a type has been
+created using the ``type()`` builtin function, then the URL of the factory
+will be ``None``:
+
+ >>> MyResultType = type('MyResult2', (object,), {})
+ >>> from zope.interface import classImplements
+ >>> classImplements(MyResultType, IResult)
+
+ >>> reg = AdapterRegistration((IFoo, IBar), IResult, 'FooToResult',
+ ... MyResultType, 'doc info')
+ >>> pprint(component.getAdapterInfoDictionary(reg))
+ {'doc': 'doc info',
+ 'factory': 'zope.app.apidoc.doctest.MyResult2',
+ 'factory_url': None,
+ 'name': 'FooToResult',
+ 'provided': {'module': 'zope.app.apidoc.doctest', 'name': 'IResult'},
+ 'required': [{'module': 'zope.app.apidoc.doctest', 'name': 'IFoo'},
+ {'module': 'zope.app.apidoc.doctest', 'name': 'IBar'}],
+ 'zcml': None}
+
This function can also handle subscription registrations, which are pretty
-much like adapter registrations, except that they do not have name. So let's
+much like adapter registrations, except that they do not have a name. So let's
see how the function handles subscriptions:
>>> from zope.component.site import SubscriptionRegistration
@@ -258,12 +282,12 @@
>>> pprint(component.getAdapterInfoDictionary(reg))
{'doc': 'doc info',
- 'factory': '__builtin__.MyResult',
- 'factory_url': '__builtin__/MyResult',
+ 'factory': 'zope.app.apidoc.doctest.MyResult',
+ 'factory_url': 'zope/app/apidoc/doctest/MyResult',
'name': u'<subscription>',
'provided': None,
- 'required': [{'module': '__builtin__', 'name': 'IFoo'},
- {'module': '__builtin__', 'name': 'IBar'}],
+ 'required': [{'module': 'zope.app.apidoc.doctest', 'name': 'IFoo'},
+ {'module': 'zope.app.apidoc.doctest', 'name': 'IBar'}],
'zcml': None}
@@ -281,9 +305,31 @@
{'description': u'<p>My Foo Bar</p>\n',
'name': 'MyFooBar',
'title': 'MyFooBar',
- 'url': '__builtin__/MyFooBar'}
+ 'url': 'zope/app/apidoc/doctest/MyFooBar'}
+If the factory's path cannot be referenced, for example if a type has been
+created using the ``type()`` builtin function, then the URL of the factory
+will be ``None``:
+ >>> class IMine(Interface):
+ ... pass
+
+ >>> class FactoryBase(object):
+ ... def getInterfaces(self): return [IMine]
+
+ >>> MyFactoryType = type('MyFactory', (FactoryBase,), {})
+ >>> from zope.interface import classImplements
+ >>> classImplements(MyFactoryType, IFactory)
+ >>> ztapi.provideUtility(IFactory, MyFactoryType(), 'MyFactory')
+
+ >>> pprint(component.getFactoryInfoDictionary(
+ ... component.getFactories(IMine).next()))
+ {'description': u'',
+ 'name': 'MyFactory',
+ 'title': u'',
+ 'url': None}
+
+
`getUtilityInfoDictionary(name, factory)`
-----------------------------------------
@@ -295,8 +341,8 @@
>>> pprint(component.getUtilityInfoDictionary(
... component.getUtilities(IFooBar).next()))
- {'iface_id': '__builtin__.IFooBar',
+ {'iface_id': 'zope.app.apidoc.doctest.IFooBar',
'name': u'<i>no name</i>',
- 'path': '__builtin__.MyFooBar',
- 'url': '__builtin__/MyFooBar',
+ 'path': 'zope.app.apidoc.doctest.MyFooBar',
+ 'url': 'zope/app/apidoc/doctest/MyFooBar',
'url_name': 'X19ub25hbWVfXw=='}
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/browser.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -64,14 +64,14 @@
>>> menu.request['search_str'] = 'Elem'
>>> pprint(menu.findInterfaces())
[{'name': 'IElement',
- 'url': './IElement/apiindex.html'}]
+ 'url': './IElement/index.html'}]
>>> menu.request['search_str'] = 'I'
>>> pprint(menu.findInterfaces())
[{'name': 'IAttribute',
- 'url': './IAttribute/apiindex.html'},
+ 'url': './IAttribute/index.html'},
{'name': 'IElement',
- 'url': './IElement/apiindex.html'}]
+ 'url': './IElement/index.html'}]
Now using the full text search:
@@ -80,14 +80,14 @@
>>> menu.request['search_str'] = 'object'
>>> pprint(menu.findInterfaces())
[{'name': 'IAttribute',
- 'url': './IAttribute/apiindex.html'},
+ 'url': './IAttribute/index.html'},
{'name': 'IElement',
- 'url': './IElement/apiindex.html'}]
+ 'url': './IElement/index.html'}]
>>> menu.request['search_str'] = 'Stores'
>>> pprint(menu.findInterfaces())
[{'name': 'IAttribute',
- 'url': './IAttribute/apiindex.html'}]
+ 'url': './IAttribute/index.html'}]
`InterfaceDetails` class
@@ -311,12 +311,10 @@
>>> pprint(details.getProvidedAdapters())
[{'doc': '',
'factory': '__builtin__.Foo',
- 'factory_url': '__builtin__/Foo',
+ 'factory_url': None,
'name': '',
- 'provided': {'module': '__builtin__',
- 'name': 'IFoo'},
- 'required': [{'module': '__builtin__',
- 'name': 'IBar'}],
+ 'provided': {'module': '__builtin__', 'name': 'IFoo'},
+ 'required': [{'module': '__builtin__', 'name': 'IBar'}],
'zcml': None}]
@@ -339,7 +337,7 @@
[{'description': u'',
'name': 'FooFactory',
'title': 'Foo Factory',
- 'url': '__builtin__/Foo'}]
+ 'url': None}]
`getUtilities()`
----------------
@@ -350,5 +348,5 @@
[{'iface_id': '__builtin__.IFoo',
'name': 'The Foo',
'path': '__builtin__.Foo',
- 'url': '__builtin__/Foo',
+ 'url': None,
'url_name': 'VGhlIEZvbw=='}]
\ No newline at end of file
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/component_macros.pt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -5,7 +5,7 @@
<metal:block define-macro="zcml" i18n:domain="zope">
<a href=""
tal:attributes="href
- string:../../Code/${zcml/url}/index.html?line=${zcml/line}#${zcml/line}"
+ string:$rootURL/Code/${zcml/url}/index.html?line=${zcml/line}#${zcml/line}"
tal:content="zcml/file">
zope/app/configure.zcml
</a>
@@ -42,7 +42,7 @@
<a href=""
tal:condition="iface"
tal:attributes="href
- string:../${iface/module}.${iface/name}/apiindex.html">
+ string:$rootURL/Interface/${iface/module}.${iface/name}/index.html">
<metal:block use-macro="context/@@interface_macros/ifacename"
/></a><tal:block condition="not:repeat/iface/end">, </tal:block>
</tal:block>
@@ -56,7 +56,7 @@
<a href=""
tal:condition="iface"
tal:attributes="href
- string:../${iface/module}.${iface/name}/apiindex.html">
+ string:$rootURL/Interface/${iface/module}.${iface/name}/index.html">
<metal:block use-macro="context/@@interface_macros/ifacename" />
</a>
<span tal:condition="not:iface" i18n:translate="">
@@ -74,7 +74,7 @@
<metal:block define-macro="factory">
<a href=""
- tal:attributes="href string:../../Code/${factory/url}/"
+ tal:attributes="href string:$rootURL/Code/${factory/url}/"
tal:content="factory/name" />
<tal:block replace="string:(${factory/title})" condition="factory/title" />
</metal:block>
@@ -87,10 +87,13 @@
tal:content="structure utility/name" />
<br />
<div style="padding-bottom: 3pt;"><span class="small">
- <span i18n:translate="">Class:</span> <code style="font-size: 100%">
- <a href=""
- tal:attributes="href string:$rootURL/Code/${utility/url}/index.html"
- tal:content="utility/path" />
+ <span i18n:translate="">Component:</span>
+ <code style="font-size: 100%">
+ <a href=""
+ tal:attributes="href string:$rootURL/Code/${utility/url}/index.html"
+ tal:content="utility/path"
+ tal:condition="utility/url" />
+ <span tal:condition="not: utility/url" tal:replace="utility/path" />
</code></span></div>
</metal:block>
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/configure.zcml 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/configure.zcml 2005-10-29 23:25:40 UTC (rev 39722)
@@ -52,7 +52,7 @@
for="zope.interface.interfaces.IInterface"
permission="zope.app.apidoc.UseAPIDoc"
class=".browser.InterfaceDetails"
- name="apiindex.html"
+ name="index.html"
template="index.pt"
/>
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/ftests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/ftests.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/ftests.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -37,7 +37,7 @@
response = self.publish(
'/++apidoc++/Interface'
'/zope.app.apidoc.ifacemodule.ifacemodule.IInterfaceModule'
- '/apiindex.html',
+ '/index.html',
basic='mgr:mgrpw')
self.assertEqual(response.getStatus(), 200)
body = response.getBody()
@@ -46,7 +46,7 @@
body,
'/++apidoc++/Interface'
'/zope.app.apidoc.ifacemodule.IInterfaceModule'
- '/apiindex.html',
+ '/index.html',
basic='mgr:mgrpw')
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/index.pt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/index.pt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -12,7 +12,7 @@
<tal:omit-tag tal:repeat="type view/getTypes" >
<a href=""
tal:attributes="href
- string:${rootURL}/Interface/${type/path}/apiindex.html"
+ string:${rootURL}/Interface/${type/path}/index.html"
tal:content="type/name"/><tal:block
condition="not:repeat/type/end">, </tal:block>
</tal:omit-tag>
@@ -35,7 +35,7 @@
<li tal:repeat="base bases">
<a href=""
tal:attributes="href
- string:${rootURL}/Interface/$base/apiindex.html"
+ string:${rootURL}/Interface/$base/index.html"
tal:content="base" />
</li>
</ul>
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/menu.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -48,7 +48,7 @@
(not name_only and search_str in getAllTextOfInterface(iface))):
results.append(
{'name': name,
- 'url': './%s/apiindex.html' %name
+ 'url': './%s/index.html' %name
})
results.sort(lambda x, y: cmp(x['name'], y['name']))
return results
@@ -63,7 +63,7 @@
rtext = getAllTextOfInterface(iface)
results.append(
{'name': name,
- 'url': './%s/apiindex.html' %name,
+ 'url': './%s/index.html' %name,
'counter': counter,
'doc': whitepattern.sub(' ',getAllTextOfInterface(iface))
})
Modified: Zope3/trunk/src/zope/app/apidoc/ifacemodule/presentation_macros.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/ifacemodule/presentation_macros.pt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/ifacemodule/presentation_macros.pt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -16,7 +16,7 @@
<i i18n:translate="">presentation type:</i>
<a href=""
tal:attributes="
- href string:../${iface/module}.${iface/name}/apiindex.html">
+ href string:$rootURL/Interface/${iface/module}.${iface/name}/index.html">
<metal:block use-macro="context/@@interface_macros/ifacename" />
</a>
</div>
@@ -27,7 +27,7 @@
<a href=""
tal:condition="iface"
tal:attributes="
- href string:../${iface/module}.${iface/name}/apiindex.html">
+ href string:$rootURL/Interface/${iface/module}.${iface/name}/index.html">
<metal:block use-macro="context/@@interface_macros/ifacename"
/></a><tal:block condition="not:repeat/iface/end">, </tal:block>
</tal:block>
@@ -41,7 +41,7 @@
<i i18n:translate="">provides:</i>
<a href=""
tal:attributes="
- href string:../${iface/module}.${iface/name}/apiindex.html">
+ href string:$rootURL/Interface/${iface/module}.${iface/name}/index.html">
<metal:block use-macro="context/@@interface_macros/ifacename" />
</a>
</div>
@@ -51,7 +51,7 @@
<i i18n:translate="">layer:</i>
<a href=""
tal:attributes="
- href string:../${iface/module}.${iface/name}/apiindex.html">
+ href string:$rootURL/Interface/${iface/module}.${iface/name}/index.html">
<metal:block use-macro="context/@@interface_macros/ifacename" />
</a>
</div>
@@ -60,7 +60,8 @@
<i i18n:translate="">factory path:</i>
<a href=""
tal:condition="View/factory/referencable"
- tal:attributes="href string:../../Code/${View/factory/url}/index.html"
+ tal:attributes="
+ href string:$rootURL/Code/${View/factory/url}/index.html"
tal:content="View/factory/path" />
<span
tal:condition="not:View/factory/referencable"
Modified: Zope3/trunk/src/zope/app/apidoc/interface.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/interface.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/interface.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -131,5 +131,5 @@
# Render the field description
info['description'] = renderText(field.description or u'', format=format)
-
+
return info
Modified: Zope3/trunk/src/zope/app/apidoc/interface.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/interface.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/interface.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -19,7 +19,7 @@
... required=True,
... default=u"My Bar")
...
- ... baz = Attribute('baz',
+ ... baz = Attribute('baz',
... 'This is the baz attribute')
...
... def blah(one, two, three=None, *args, **kwargs):
@@ -171,7 +171,7 @@
the interface types again:
>>> interface.getInterfaceTypes(IFoo)
- [<InterfaceClass __builtin__.IContentType>]
+ [<InterfaceClass zope.app.apidoc.doctest.IContentType>]
Again note that the interface passed to this function *cannot* be proxied,
otherwise this method will pick up the proxy's interfaces as well.
@@ -196,7 +196,7 @@
>>> from zope.schema.interfaces import IField
>>> class ISpecialField(IField):
- ... pass
+ ... pass
>>> class ISomething(Interface):
... pass
@@ -205,7 +205,7 @@
... implements(ISomething, ISpecialField)
>>> interface.getFieldInterface(MyField())
- <InterfaceClass __builtin__.ISpecialField>
+ <InterfaceClass zope.app.apidoc.doctest.ISpecialField>
`getAttributeInfoDictionary(attr, format='restructuredtext')`
Modified: Zope3/trunk/src/zope/app/apidoc/static.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/static.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/static.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -28,9 +28,12 @@
import mechanize
from zope.app.testing import functional
+from zope.deprecation import __show__
+from zope.app.apidoc import classregistry
+
# Setup the user feedback detail level.
-VERBOSITY = 2
+VERBOSITY = 4
VERBOSITY_MAP = {1: 'ERROR', 2: 'WARNING', 3: 'INFO'}
@@ -38,10 +41,13 @@
URL = 'http://localhost:8080/'
-START_PAGE = '++apidoc++/Type/@@staticmenu.html'
+START_PAGE = '++apidoc++/static.html'
BASE_DIR = 'apidoc'
+USERNAME = 'mgr'
+PASSWORD = 'mgrpw'
+
# A mapping of HTML elements that can contain links to the attribute that
# actually contains the link
urltags = {
@@ -103,7 +109,7 @@
class Link(object):
"""A link in the page."""
- def __init__(self, mechLink, referenceURL=None):
+ def __init__(self, mechLink, referenceURL='None'):
self.referenceURL = referenceURL
self.originalURL = mechLink.url
self.callableURL = mechLink.absolute_url
@@ -190,9 +196,11 @@
def start(self):
"""Start the retrieval of the apidoc."""
t0 = time.time()
+ __show__.off()
self.visited = []
self.counter = 0
+ self.errors = 0
if not os.path.exists(self.rootDir):
os.mkdir(self.rootDir)
@@ -202,9 +210,12 @@
else:
self.browser = OnlineBrowser()
- self.browser.setUserAndPassword('mgr', 'mgrpw')
+ self.browser.setUserAndPassword(USERNAME, PASSWORD)
self.browser.urltags = urltags
+ #self.browser.addheaders.append(('X-zope-handle-errors', False))
+ classregistry.IGNORE_MODULES = ['twisted']
+
# Work through all links until there are no more to work on.
self.sendMessage('Starting retrieval.')
while self.linkQueue:
@@ -216,9 +227,12 @@
self.showStatistics(link)
self.processLink(link)
+ __show__.on()
t1 = time.time()
self.sendMessage("Run time: %.3f sec real" % (t1-t0))
+ self.sendMessage("Links: %i" %self.counter)
+ self.sendMessage("Errors: %i" %self.errors)
def showStatistics(self, link):
self.counter += 1
@@ -251,15 +265,20 @@
self.browser.open(link.callableURL)
except urllib2.HTTPError, error:
# Something went wrong with retrieving the page.
+ self.errors += 1
self.sendMessage(
'%s (%i): %s' % (error.msg, error.code, link.callableURL), 2)
self.sendMessage('+-> Reference: ' + link.referenceURL, 2)
return
except (urllib2.URLError, ValueError):
# We had a bad URL running the publisher browser
+ self.errors += 1
self.sendMessage('Bad URL: ' + link.callableURL, 2)
self.sendMessage('+-> Reference: ' + link.referenceURL, 2)
return
+ #except Exception, error:
+ # import pdb; pdb.set_trace()
+ # return
# Make sure the directory exists and get a file path.
relativeURL = url.replace(URL, '')
Modified: Zope3/trunk/src/zope/app/apidoc/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/tests.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/tests.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -24,7 +24,7 @@
from zope.app.traversing.interfaces import IContainmentRoot
from zope.app.location import LocationProxy
-from zope.app.testing import placelesssetup, ztapi
+from zope.app.testing import placelesssetup, ztapi, setup
from zope.app.renderer.rest import ReStructuredTextSourceFactory
from zope.app.renderer.rest import IReStructuredTextSource
@@ -35,16 +35,21 @@
placelesssetup.setUp()
# Register Renderer Components
ztapi.provideUtility(IFactory, ReStructuredTextSourceFactory,
- 'zope.source.rest')
- ztapi.browserView(IReStructuredTextSource, '',
+ '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, '',
+ 'zope.source.stx')
+ ztapi.browserView(IReStructuredTextSource, '',
ReStructuredTextToHTMLRenderer)
+ setup.setUpTestAsModule(test, 'zope.app.apidoc.doctest')
+def tearDown(test):
+ placelesssetup.tearDown()
+ setup.tearDownTestAsModule(test)
+
# Generally useful classes and functions
class Root:
@@ -56,7 +61,7 @@
def rootLocation(obj, name):
return LocationProxy(obj, Root(), name)
-
+
def test_suite():
return unittest.TestSuite((
doctest.DocTestSuite('zope.app.apidoc.browser.apidoc',
Modified: Zope3/trunk/src/zope/app/apidoc/typemodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/typemodule/browser.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/typemodule/browser.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -34,4 +34,4 @@
def getMenuLink(self, node):
"""Return the HTML link of the node that is displayed in the menu."""
- return '../Interface/%s/apiindex.html' %zapi.name(node.context)
+ return '../Interface/%s/index.html' %zapi.name(node.context)
Modified: Zope3/trunk/src/zope/app/apidoc/utilities.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilities.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/utilities.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -34,6 +34,8 @@
from zope.app.i18n import ZopeMessageFactory as _
from zope.app.container.interfaces import IReadContainer
+from zope.app.apidoc.classregistry import safe_import
+
_remove_html_overhead = re.compile(
r'(?sm)^<html.*<body.*?>\n(.*)</body>\n</html>\n')
@@ -87,7 +89,11 @@
def getPythonPath(obj):
- """Return the path of the object in standard Python notation."""
+ """Return the path of the object in standard Python notation.
+
+ This method should try very hard to return a string, even if it is not a
+ valid Python path.
+ """
if obj is None:
return None
@@ -100,10 +106,31 @@
module = getattr(naked, '__module__', _marker)
if module is _marker:
return naked.__name__
- else:
- return '%s.%s' %(module, naked.__name__)
+ return '%s.%s' %(module, naked.__name__)
+def isReferencable(path):
+ """Return whether the Python path is referencable."""
+ # Sometimes no path exists, so make a simple check first; example: None
+ if path is None:
+ return False
+ module_name, obj_name = path.rsplit('.', 1)
+ # Do not allow private attributes to be accessible
+ if (obj_name.startswith('_') and
+ not (obj_name.startswith('__') and obj_name.endswith('__'))):
+ return False
+ module = safe_import(module_name)
+ if module is None:
+ return False
+ obj = getattr(module, obj_name, _marker)
+ if obj is _marker:
+ return False
+ # Detect singeltons; those are not referencable in apidoc (yet)
+ if hasattr(obj, '__class__') and getPythonPath(obj.__class__) == path:
+ return False
+ return True
+
+
def _evalId(id):
if zapi.isinstance(id, Global):
id = id.__name__
@@ -247,7 +274,25 @@
return _format_dict.get(format, 'zope.source.stx')
-def renderText(text, module=None, format=None):
+def dedentString(text):
+ """Dedent the docstring, so that docutils can correctly render it."""
+ dedent = 0
+ lines = text.split('\n')
+ for line in lines[1:]:
+ if line != '':
+ for char in line:
+ if char == ' ':
+ dedent += 1
+ else:
+ break
+ break
+
+ for index in range(1, len(lines)):
+ lines[index] = lines[index][dedent:]
+ return '\n'.join(lines)
+
+
+def renderText(text, module=None, format=None, dedent=True):
if not text:
return u''
@@ -261,6 +306,8 @@
assert format in _format_dict.values()
+ text = dedentString(text)
+
source = zapi.createObject(format, text)
renderer = zapi.getMultiAdapter((source, TestRequest()))
return renderer.render()
Modified: Zope3/trunk/src/zope/app/apidoc/utilities.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilities.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/utilities.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -164,7 +164,7 @@
... pass
>>> utilities.getPythonPath(ISample)
- '__builtin__.ISample'
+ 'zope.app.apidoc.doctest.ISample'
and for classes
@@ -173,21 +173,20 @@
... pass
>>> utilities.getPythonPath(Sample.sample)
- '__builtin__.Sample'
+ 'zope.app.apidoc.doctest.Sample'
One can also pass functions
>>> def sample():
... pass
- >>> # Result is a bit strange due to doctests
>>> utilities.getPythonPath(sample)
- 'None.sample'
+ 'zope.app.apidoc.doctest.sample'
and even methods. If a method is passed in, its class path is returned.
>>> utilities.getPythonPath(Sample.sample)
- '__builtin__.Sample'
+ 'zope.app.apidoc.doctest.Sample'
Modules are another kind of objects that can return a python path:
@@ -206,6 +205,65 @@
AttributeError: 'Sample' object has no attribute '__name__'
+`isReferencable(path)`
+----------------------
+
+Determine whether a path can be referenced in the API doc, usually by the code
+browser module. Initially you might think that all objects that have paths can
+be referenced somehow. But that's not true, partially by design of apidoc, but
+also due to limitations of the Python language itself.
+
+The first case is ``None``. When you ask for the python path of ``None``, you
+get ``None``, so that result should not be referencable:
+
+ >>> utilities.isReferencable(None)
+ False
+
+By design we also do not document any private classes and functions:
+
+ >>> utilities.isReferencable('some.path.to._Private')
+ False
+ >>> utilities.isReferencable('some.path.to.__Protected')
+ False
+ >>> utilities.isReferencable('zope.app.apidoc.__doc__')
+ True
+
+Some objects might fake their module name, so that it does not exist:
+
+ >>> utilities.isReferencable('foo.bar')
+ False
+
+On the other hand, you might have a valid module, but non-existent attribute:
+
+ >>> utilities.isReferencable('zope.app.apidoc.MyClass')
+ False
+
+Note that this case is also used for types that are generated using the
+``type()`` function:
+
+ >>> mytype = type('MyType', (object,), {})
+ >>> path = utilities.getPythonPath(mytype)
+ >>> path
+ 'zope.app.apidoc.doctest.MyType'
+
+ >>> utilities.isReferencable(path)
+ False
+
+Finally, since API doc does not allow the documentation of instances yet, it
+is not possible to document singletons, so they are not referencable:
+
+ >>> class Singelton(object):
+ ... pass
+
+ >>> utilities.isReferencable('zope.app.apidoc.doctest.Singelton')
+ True
+
+ >>> Singelton = Singelton()
+
+ >>> utilities.isReferencable('zope.app.apidoc.doctest.Singelton')
+ False
+
+
`getPermissionIds(name, checker=_marker, klass=_marker)`
--------------------------------------------------------
@@ -455,23 +513,23 @@
First we check whether an aatribute can be found in a list of interfaces:
>>> utilities.getInterfaceForAttribute('attr', (I1, I2), asPath=False)
- <InterfaceClass __builtin__.I1>
+ <InterfaceClass zope.app.apidoc.doctest.I1>
>>> utilities.getInterfaceForAttribute('getAttr', (I1, I2), asPath=False)
- <InterfaceClass __builtin__.I2>
+ <InterfaceClass zope.app.apidoc.doctest.I2>
Now we are repeating the same lookup, but using the class, instead of a list
of interfaces:
>>> utilities.getInterfaceForAttribute('attr', klass=Sample, asPath=False)
- <InterfaceClass __builtin__.I1>
+ <InterfaceClass zope.app.apidoc.doctest.I1>
>>> utilities.getInterfaceForAttribute('getAttr', klass=Sample, asPath=False)
- <InterfaceClass __builtin__.I2>
+ <InterfaceClass zope.app.apidoc.doctest.I2>
By default, `asPath` is `True`, which means the path of the interface is
returned:
>>> utilities.getInterfaceForAttribute('attr', (I1, I2))
- '__builtin__.I1'
+ 'zope.app.apidoc.doctest.I1'
If no match is found, ``None`` is returned.
@@ -552,6 +610,70 @@
format. All converted and new modules will have the `__docformat__` attribute.
+`dendentString(text)`
+---------------------
+
+Before doc strings can be processed using STX or ReST they must be dendented,
+since otherwise the output will be incorrect. Let's have a look at some
+docstrings and see how they are correctly dedented.
+
+Let's start with a simple one liner. Nothing should happen:
+
+ >>> def func():
+ ... '''One line documentation string'''
+
+ >>> utilities.dedentString(func.__doc__)
+ 'One line documentation string'
+
+Now what about one line docstrings that start on the second line? While this
+format is discouraged, it is frequently used:
+
+ >>> def func():
+ ... '''
+ ... One line documentation string
+ ... '''
+
+ >>> utilities.dedentString(func.__doc__)
+ '\nOne line documentation string\n'
+
+We can see that the leading whitespace on the string is removed, but not the
+newline character. Let's now try a simple multi-line docstring:
+
+ >>> def func():
+ ... '''Short description
+ ...
+ ... Lengthy description, giving some more background information and
+ ... discuss some edge cases.
+ ... '''
+
+ >>> print utilities.dedentString(func.__doc__)
+ Short description
+ <BLANKLINE>
+ Lengthy description, giving some more background information and
+ discuss some edge cases.
+ <BLANKLINE>
+
+Again, the whitespace was removed only after the first line. Also note that
+the function determines the indentation level correctly. So what happens if
+there are multiple indentation levels? Well, the first occurrence wins:
+
+ >>> def func():
+ ... '''Short description
+ ...
+ ... Root Level
+ ...
+ ... Second Level
+ ... '''
+
+ >>> print utilities.dedentString(func.__doc__)
+ Short description
+ <BLANKLINE>
+ Root Level
+ <BLANKLINE>
+ Second Level
+ <BLANKLINE>
+
+
`renderText(text, module=None, format=None)`
--------------------------------------------
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -17,9 +17,12 @@
"""
__docformat__ = 'restructuredtext'
+from zope.security.proxy import removeSecurityProxy
+
from zope.app import zapi
from zope.app.location import LocationProxy
from zope.app.apidoc.ifacemodule.browser import InterfaceDetails
+from zope.app.apidoc.component import getUtilityInfoDictionary
from zope.app.apidoc.utilities import getPythonPath
from zope.app.apidoc.utilitymodule.utilitymodule import NONAME, Utility
from zope.app.apidoc.utilitymodule.utilitymodule import UtilityInterface
@@ -44,15 +47,12 @@
def getComponent(self):
"""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
- klass = self.context.component.__class__
+ # Remove proxy here, so that we can determine the type correctly
+ naked = removeSecurityProxy(self.context.registration)
+ result = getUtilityInfoDictionary(naked)
+ return {'path': result['path'], 'url': result['url']}
- return {'path': getPythonPath(klass),
- 'url': getPythonPath(klass).replace('.', '/')}
-
class Menu(object):
"""Menu View Helper Class"""
@@ -72,5 +72,5 @@
iface = zapi.getParent(obj)
return './'+zapi.name(iface) + '/' + zapi.name(obj) + '/index.html'
if zapi.isinstance(obj, UtilityInterface):
- return '../Interface/'+zapi.name(obj) + '/apiindex.html'
+ return '../Interface/'+zapi.name(obj) + '/index.html'
return None
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/browser.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -32,7 +32,7 @@
>>> menu.getMenuTitle(node)
'iface'
>>> menu.getMenuLink(node)
- '../Interface/foo.bar.iface/apiindex.html'
+ '../Interface/foo.bar.iface/index.html'
Next, let's get the menu title and link for a utility with a name. We first
have to create a utility registration
@@ -140,15 +140,14 @@
>>> foo_reg = type(
... 'RegistrationStub', (),
- ... {'name': '', 'provided': None, 'component': Foo(), 'doc': ''})()
+ ... {'name': '', 'provided': Interface, 'component': Foo(), 'doc': ''})()
Then we create a utility documentation class and its details view:
>>> details = UtilityDetails()
- >>> details.context = Utility(None, foo_reg)
+ >>> details.context = Utility(Interface, foo_reg)
Now we can get the component information:
>>> pprint(details.getComponent())
- {'path': '__builtin__.Foo',
- 'url': '__builtin__/Foo'}
+ {'path': '__builtin__.Foo', 'url': None}
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/index.pt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/index.pt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -7,7 +7,7 @@
<h1 class="details-header">
<a href=""
tal:attributes="
- href string:../../../Interface/${iface/getId}/apiindex.html"
+ href string:../../../Interface/${iface/getId}/index.html"
tal:content="iface/getId" /> <br />
<tal:block i18n:translate="">(Name: "<span
tal:replace="view/getName" i18n:name="name" />")</tal:block>
Modified: Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/utilitymodule/utilitymodule.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -33,14 +33,13 @@
NONAME = '__noname__'
def encodeName(name):
- # base64 strings can have lines at most 76 chars long; so make sure we get
- # rid of all newline chars. See RFC-3548.
- return base64.encodestring(name.encode('utf-8')).replace('\n', '')
+ return base64.urlsafe_b64encode(name.encode('utf-8'))
def decodeName(name):
try:
- return base64.decodestring(name).decode('utf-8')
- except binascii.Error:
+ return base64.urlsafe_b64decode(str(name)).decode('utf-8')
+ except (binascii.Error, TypeError):
+ # Someone probably passed a non-encoded name, so let's accept that.
return name
class Utility(object):
Modified: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -26,7 +26,8 @@
from zope.app.location import LocationProxy
from zope.app.apidoc.zcmlmodule import Directive, Namespace
from zope.app.apidoc.ifacemodule.browser import InterfaceDetails
-from zope.app.apidoc.utilities import getPythonPath, relativizePath
+from zope.app.apidoc.utilities import getPythonPath, isReferencable
+from zope.app.apidoc.utilities import relativizePath
class Menu(object):
"""Menu View Helper Class"""
@@ -83,7 +84,7 @@
"""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.
+ # proxies in order to get to the data.
info = removeSecurityProxy(self.context.info)
if zapi.isinstance(info, ParserInfo):
return {'file': relativizePath(info.file),
@@ -103,8 +104,9 @@
"""Return information about the handler."""
if self.context.handler is not None:
path = getPythonPath(self.context.handler)
- return {'path': path,
- 'url': path.replace('.', '/')}
+ return {
+ 'path': path,
+ 'url': isReferencable(path) and path.replace('.', '/') or None}
return None
def getSubdirectives(self):
@@ -113,12 +115,12 @@
for ns, name, schema, handler, info in self.context.subdirs:
details = self._getInterfaceDetails(schema)
path = getPythonPath(handler)
+ url = isReferencable(path) and path.replace('.', '/') or None
dirs.append({
'namespace': ns,
'name': name,
'schema': details,
- 'handler': {'path': path,
- 'url': path.replace('.', '/')},
+ 'handler': {'path': path, 'url': url},
'info': info,
})
return dirs
Modified: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.txt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.txt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/browser.txt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -26,7 +26,7 @@
and generate a tree node :
- >>> from zope.app.tree.node import Node
+ >>> from zope.app.tree.node import Node
>>> node = Node(ns)
We can now ask the menu for the title of the namespace
@@ -41,7 +41,7 @@
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)
@@ -52,7 +52,7 @@
>>> menu.getMenuLink(node) is None
True
-Now we add the `page` directive to the browser namespace:
+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)
@@ -80,7 +80,7 @@
>>> class IFoo(Interface):
... class_ = Attribute('class_')
- >>> def foo():
+ >>> def foo():
... pass
>>> directive = Directive(ns, 'page', IFoo, foo, None, ())
@@ -187,7 +187,7 @@
>>> pprint(details.getHandler())
{'path': 'None.foo',
- 'url': 'None/foo'}
+ 'url': None}
`getSubdirectives()`
@@ -210,8 +210,7 @@
the result becomes more interesting:
>>> pprint(details.getSubdirectives()) #doctest:+ELLIPSIS
- [{'handler': {'path': 'None.handler',
- 'url': 'None/handler'},
+ [{'handler': {'path': 'None.handler', 'url': None},
'info': 'info',
'name': 'foo',
'namespace': 'browser',
Modified: Zope3/trunk/src/zope/app/apidoc/zcmlmodule/index.pt
===================================================================
--- Zope3/trunk/src/zope/app/apidoc/zcmlmodule/index.pt 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/apidoc/zcmlmodule/index.pt 2005-10-29 23:25:40 UTC (rev 39722)
@@ -48,7 +48,7 @@
<div class="indent">
<a href="" tal:attributes="href
- string:../../../Interface/${schema/getId}/apiindex.html">
+ string:../../../Interface/${schema/getId}/index.html">
<h3 tal:content="schema/getId">zope.fields.Schema</h3>
</a>
</div>
@@ -105,7 +105,7 @@
<div class="indent">
<a href=""
tal:attributes="href
- string:../../../Interface/${dir/schema/getId}/apiindex.html">
+ string:../../../Interface/${dir/schema/getId}/index.html">
<h3 tal:content="dir/schema/getId">zope.fields.Schema</h3>
</a>
</div>
Modified: Zope3/trunk/src/zope/app/interpreter/python.py
===================================================================
--- Zope3/trunk/src/zope/app/interpreter/python.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/interpreter/python.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -41,10 +41,10 @@
code.exec_(globals,
{}, # we don't want to get local assignments saved.
)
-
+
return tmp.getvalue()
-
+
def evaluateRawCode(self, code, globals):
"""See `zope.app.interfaces.IInterpreter`"""
# Removing probable comments
@@ -59,7 +59,7 @@
if code.startswith(' ') or code.startswith('\t'):
code = 'if 1 == 1:\n' + code
return self.evaluate(code, globals)
-
+
# It's a singelton for now.
PythonInterpreter = PythonInterpreter()
Modified: Zope3/trunk/src/zope/app/onlinehelp/browser/tree.py
===================================================================
--- Zope3/trunk/src/zope/app/onlinehelp/browser/tree.py 2005-10-29 23:19:30 UTC (rev 39721)
+++ Zope3/trunk/src/zope/app/onlinehelp/browser/tree.py 2005-10-29 23:25:40 UTC (rev 39722)
@@ -39,35 +39,35 @@
Iterate this dict oan build from the level info
a navigation tree in the page tmeplate.
Each time you get a level 0 means this is a subitem of the
- Onlinehelp itself.
+ Onlinehelp itself::
- info = [('id',{infoDict}),(),()]
+ >>> info = [('id',{infoDict}),(),()]
- <ul class="tree" id="tree">
- <li><a href="#">items</a>
- <ul>
- <li><a href="#">item</a></li>
- </ul>
- </li>
- <li><a href="#">items</a>
- <ul>
- <li><a href="#">items</a>
- <ul>
- <li><a href="#">item</a></li>
- <li><a href="#">item</a></li>
- <li><a href="#">item</a></li>
- </ul>
- </li>
- <li><a href="#">items</a>
- <ul>
- <li><a href="#">item</a></li>
- <li id="activeTreeNode"><a href="#">active item</a></li>
- <li><a href="#">item</a></li>
- </ul>
- </li>
- </ul>
- </li>
- <ul>
+ <ul class="tree" id="tree">
+ <li><a href="#">items</a>
+ <ul>
+ <li><a href="#">item</a></li>
+ </ul>
+ </li>
+ <li><a href="#">items</a>
+ <ul>
+ <li><a href="#">items</a>
+ <ul>
+ <li><a href="#">item</a></li>
+ <li><a href="#">item</a></li>
+ <li><a href="#">item</a></li>
+ </ul>
+ </li>
+ <li><a href="#">items</a>
+ <ul>
+ <li><a href="#">item</a></li>
+ <li id="activeTreeNode"><a href="#">active item</a></li>
+ <li><a href="#">item</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <ul>
"""
return self.renderTree(self.onlinehelp)
More information about the Zope3-Checkins
mailing list