[Zope3-checkins] CVS: Zope3/src/zope/products/apidoc/zcmlmodule - __init__.py:1.1 browser.py:1.1 configure.zcml:1.1 index.pt:1.1 menu.pt:1.1 tests.py:1.1

Stephan Richter srichter at cosmos.phy.tufts.edu
Thu Jan 29 12:51:21 EST 2004


Update of /cvs-repository/Zope3/src/zope/products/apidoc/zcmlmodule
In directory cvs.zope.org:/tmp/cvs-serv11915/apidoc/zcmlmodule

Added Files:
	__init__.py browser.py configure.zcml index.pt menu.pt 
	tests.py 
Log Message:
Here comes the new Zope 3 API Documentation tool. You can access it via

  http://localhost:8080/++apidoc++/

There is really not much more to say here. Check it out and let me know what
you think.


=== Added File Zope3/src/zope/products/apidoc/zcmlmodule/__init__.py ===
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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 Documentation module

The ZCML documentation module reads all of the meta directives (but does not
execute them) and uses the collected data to generate the tree. The result of
the evaluation is stored in thread-global variables, so that we have to parse
the files only once. 

$Id: __init__.py,v 1.1 2004/01/29 17:51:19 srichter Exp $
"""
import os
from zope.app import zapi
from zope.app.interfaces.location import ILocation
from zope.configuration import docutils, xmlconfig
from zope.interface import implements, Interface, Attribute
from zope.products.apidoc.interfaces import IDocumentationModule
from zope.products.apidoc.utilities import ReadContainerBase

# Caching variables, so that the meta-ZCML files need to be read only once
namespaces = None
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'
    """
    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'
    """
    ns = ns.replace('_sl_', '/')
    ns = ns.replace('_co_', ':')
    return ns    


class Namespace(ReadContainerBase):
    r"""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::

      >>> 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):
        self.__parent__ = parent
        self.__realname__ = name
        self.__name__ = self.getQuotedName()

    def getShortName(self):
        """Get the short name of the namespace."""
        name = self.__realname__
        if name.startswith('http://namespaces.zope.org/'):
            name = name[27:]
        return name

    def getFullName(self):
        """Get the full name of the namespace."""
        name = self.__realname__
        if name != 'ALL' and not name.startswith('http://namespaces.zope.org/'):
            name = 'http://namespaces.zope.org/' + name
        return name

    def getQuotedName(self):
        """Get the full name, but quoted for a URL."""
        name = self.getFullName()
        name = quoteNS(name)
        return name

    def get(self, key, default=None):
        """See zope.app.interfaces.container.IReadContainer"""
        ns = self.getFullName()
        if not namespaces[ns].has_key(key):
            return default
        schema, info = namespaces[ns][key]
        sd = subdirs.get((ns, key), [])
        directive = Directive(self, key, schema, info, sd)
        return directive
    
    def items(self):
        """See zope.app.interfaces.container.IReadContainer"""
        list = []
        for key in namespaces[self.getFullName()].keys():
            list.append((key, self.get(key)))
        list.sort()
        return list
        

class Directive(object):
    """Represents a ZCML Directive."""

    implements(ILocation)

    def __init__(self, ns, name, schema, info, subdirs):
        self.__parent__ = ns
        self.__name__ = name
        self.schema = schema
        self.info = info
        self.subdirs = subdirs
    

class ZCMLModule(ReadContainerBase):
    r"""Represent the Documentation of all Interfaces.

    This documentation is implemented using a simply 'IReadContainer'. The
    items of the container are all the interfaces listed in the closest
    interface service and above.

    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

      >>> print '\n'.join([ns.getShortName() for n, ns in module.items()][1:4])
      browser
      code
      dav
    """

    implements(IDocumentationModule)

    # See zope.products.apidoc.interfaces.IDocumentationModule
    title = 'ZCML Reference'

    # See zope.products.apidoc.interfaces.IDocumentationModule
    description = """
    This module presents you with a complete list of ZCML directives and
    serves therefore well as reference. The menu provides you with a tree that
    organizes the directives by namespaces.

    The documentation contents for each directive tells you all the available
    attributes and their semantics. It also provides a link to the interface
    the directive confirms to. If available, it will even tell you the
    file the directive was declared in. At the end a list of available
    subdirectives is given, also listing the implemented interface and
    available attributes.
    """

    def __init__(self):
        # Some trivial caching
        global namespaces
        global subdirs
        if namespaces is None or subdirs is None:
            from zope import app
            file = os.path.join(os.path.split(app.__file__)[0], 'meta.zcml')
            context = xmlconfig.file(file, execute=False)
            namespaces, subdirs = docutils.makeDocStructures(context)

        # Empty keys are not so good for a container
        if namespaces.has_key(''):
            namespaces['ALL'] = namespaces['']
            del namespaces['']


    def get(self, key, default=None):
        """See zope.app.interfaces.container.IReadContainer

        Get the namespace by name; long and abbreviated names work.
        """
        key = unquoteNS(key)
        if not (key == 'ALL' or key.startswith('http://namespaces.zope.org/')):
            key = 'http://namespaces.zope.org/' + key
        if not namespaces.has_key(key):
            return default
        return Namespace(self, key)


    def items(self):
        """See zope.app.interfaces.container.IReadContainer"""
        list = []
        for key in namespaces.keys():
            namespace = Namespace(self, key)
            # We need to make sure that we use the quoted URL as key
            list.append((namespace.getQuotedName(), namespace))
        list.sort()
        return list


=== Added File Zope3/src/zope/products/apidoc/zcmlmodule/browser.py ===
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Browser Views for ZCML Reference

$Id: browser.py,v 1.1 2004/01/29 17:51:19 srichter Exp $
"""
import urllib
from zope.app import zapi
from zope.app.location import LocationProxy
from zope.configuration.xmlconfig import ParserInfo
from zope.products.apidoc.zcmlmodule import Directive, Namespace
from zope.products.apidoc.ifacemodule.browser import InterfaceDetails
from zope.products.apidoc.utilities import getPythonPath
from zope.proxy import removeAllProxies
from zope.schema import getFieldsInOrder 


class Menu(object):
    """Menu View Helper Class"""

    def getMenuTitle(self, node):
        """Return the title of the node that is displayed in the menu."""
        obj = removeAllProxies(node.context)
        if isinstance(obj, Namespace):
            name = obj.getShortName()
            if name == 'ALL':
                return 'All Namespaces'
            return name
        return zapi.name(obj)

    def getMenuLink(self, node):
        """Return the HTML link of the node that is displayed in the menu."""
        obj = removeAllProxies(node.context)
        if isinstance(obj, Directive):
            ns = zapi.getParent(obj)
            return './'+zapi.name(ns) + '/' + zapi.name(obj) + '/index.html'
        return None


class DirectiveDetails(object):
    """View class for a Directive."""

    def getSchema(self):
        """Return the schema of the directive.""" 
        schema = LocationProxy(self.context.schema,
                               self.context,
                               getPythonPath(self.context.schema))
        return InterfaceDetails(schema, self.request)

    def getNamespaceName(self):
        """Return the name of the namespace."""
        name = zapi.getParent(self.context).getFullName()
        if name == 'ALL':
            return '<i>all namespaces</i>'
        return name

    def getFile(self):
        """Get the file where the directive was declared."""
        info = removeAllProxies(self.context.info)
        if isinstance(info, ParserInfo):
            return info.file
        return None

    def getInfo(self):
        """Get info, if available."""
        info = removeAllProxies(self.context.info)
        if isinstance(info, ParserInfo):
            return None
        return info
    
    def getSubdirectives(self):
        """Create a list of subdirectives."""
        dirs = []
        for ns, name, schema, info in self.context.subdirs:
            schema = LocationProxy(schema, self.context, getPythonPath(schema))
            schema = InterfaceDetails(schema, self.request)
            dirs.append({'namespace': ns,
                         'name': name,
                         'schema': schema,
                         'info': info})
        return dirs


=== Added File Zope3/src/zope/products/apidoc/zcmlmodule/configure.zcml ===
<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:browser="http://namespaces.zope.org/browser">

  <class class=".ZCMLModule">
    <allow interface="zope.products.apidoc.interfaces.IDocumentationModule" />
    <allow interface="zope.app.interfaces.container.IReadContainer" />
  </class>

  <class class=".Namespace">
    <allow attributes="getShortName getFullName getQuotedName" />
    <allow interface="zope.app.interfaces.container.IReadContainer" />
  </class>

  <class class=".Directive">
    <allow attributes="name schema info subdirs" />
  </class>

  <utility
    provides="zope.products.apidoc.interfaces.IDocumentationModule"
    factory=".ZCMLModule"
    name="ZCML" />

  <browser:page
    for=".ZCMLModule"
    class=".browser.Menu"
    permission="zope.View"
    name="menu.html"
    template="menu.pt" />

  <browser:page
    for=".Directive"
    class=".browser.DirectiveDetails"
    permission="zope.View"
    name="index.html"
    template="index.pt" />

</configure>



=== Added File Zope3/src/zope/products/apidoc/zcmlmodule/index.pt ===
<html metal:use-macro="views/apidoc_macros/details">
<body metal:fill-slot="contents"
      tal:define="schema view/getSchema">

  <h1 class="details-header">
    <span tal:replace="context/zope:name" /> 
    (<span tal:replace="structure view/getNamespaceName" />)
  </h1>

  <div class="indent" 
       tal:condition="view/getFile">
    <i>File:</i> <tal:block content="view/getFile"/>
  </div>

  <div class="indent" 
       tal:condition="view/getInfo">
    <i>Info:</i> <tal:block content="view/getInfo"/>
  </div>

  <h2 class="details-section">Schema</h2>

  <div class="indent">
    <a href=""
       tal:attributes="href 
           string:../../../Interface/${schema/getId}/apiindex.html">
      <h3 tal:content="schema/getId">zope.fields.Schema</h3>
    </a>
  </div>

  <div class="indent">
    <div class="documentation" tal:content="structure schema/getDoc">
      Here is the doc string
    </div>
  </div>

  <div class="indent"
      tal:define="fields schema/getFields">

  <ul class="attr-list" 
      tal:condition="fields">
  
    <li tal:repeat="field fields">
      <b><code tal:content="field/name">field</code></b>
      - <a href=""
           tal:attributes="href 
               string:../../../Interface/${field/iface/id}/apiindex.html">
          <code tal:content="field/iface/name">IField</code></a>
      (<span tal:content="string:${field/required}, ">optional, </span>
        default = <code tal:content="field/default" />)<br>
      <span tal:content="field/description">field desc</span>      
    </li>

  </ul>

  <p tal:condition="not: fields">
    <em>There are no fields specified.</em>
  </p>

  </div>

  <tal:omit-tag 
      define="dir view/getSubdirectives"
      condition="dir">

  <h2 class="details-section">Subdirectives</h2>

  <div class="indent"
       tal:repeat="dir view/getSubdirectives">

  <h3 tal:content="dir/name"> 
    directive
  </h3>

  <div class="indent">
    <a href=""
       tal:attributes="href 
           string:../../../Interface/${dir/schema/getId}/apiindex.html">
      <h4 tal:content="dir/schema/getId">zope.fields.Schema</h4>
    </a>
  </div>

  <div class="indent">
    <div class="documentation" tal:content="structure dir/schema/getDoc">
      Here is the doc string
    </div>
  </div>

  <div class="indent"
      tal:define="fields dir/schema/getFields">

  <ul class="attr-list" 
      tal:condition="fields">
  
    <li tal:repeat="field fields">
      <b><code tal:content="field/name">field</code></b>
      - <a href=""
           tal:attributes="href 
               string:../../../Interface/${field/iface/id}/apiindex.html">
          <code tal:content="field/iface/name">IField</code></a>
      (<span tal:content="string:${field/required}, ">optional, </span>
        default = <code tal:content="field/default" />)<br>
      <span tal:content="field/description">field desc</span>      
    </li>

  </ul>

  <p tal:condition="not: fields">
    <em>There are no fields specified.</em>
  </p>

  </div>

  </div>

  </tal:omit-tag>

</body>
</html>

=== Added File Zope3/src/zope/products/apidoc/zcmlmodule/menu.pt ===
<html metal:use-macro="views/apidoc_macros/menu">
<body>

  <p metal:fill-slot="pre_menu" class="small">
    Namespaces that are not full URLs start with "http://namespaces.zope.org".
  </p>

</body>
</html>

=== Added File Zope3/src/zope/products/apidoc/zcmlmodule/tests.py ===
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Tests for the ZCML Documentation Module

$Id: tests.py,v 1.1 2004/01/29 17:51:19 srichter Exp $
"""
import unittest
from zope.testing.doctestunit import DocTestSuite
    
def test_suite():
    return unittest.TestSuite((
        DocTestSuite('zope.products.apidoc.zcmlmodule'),
        ))

if __name__ == '__main__':
    unittest.main()




More information about the Zope3-Checkins mailing list