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

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


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

Added Files:
	__init__.py __init__.pyc browser.pt browser.py browser.pyc 
	configure.zcml index.pt menu.pt 
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/classmodule/__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.
#
##############################################################################
"""Class Documentation Module

This module is able to take a dotted name of any class and display
documentation for it. 

$Id: __init__.py,v 1.1 2004/01/29 17:51:15 srichter Exp $
"""
from zope.app import zapi
from zope.interface import implements
from zope.products.apidoc.interfaces import IDocumentationModule


class ClassModule(object):
    """Represent the Documentation of any possible class."""

    implements(IDocumentationModule)

    # See zope.products.apidoc.interfaces.IDocumentationModule
    title = 'Classes'

    # See zope.products.apidoc.interfaces.IDocumentationModule
    description = """
    Since there is no registry for implemented classes for Zope 3, the user
    experience of this module is somewhat different than the others. Two
    alternative navigation means are provided. In the menu of the module you
    will see an input field in which you can type the dotted name of the
    desired class; for example 'zope.app.location.LocationProxy'. Once you
    press enter or click on "Show" you can see the documentation for the
    class.

    The second method is to click on the "Browse Zope Source" link. In the
    main window, you will see a directory listing with the root Zope 3
    modules. You can click on the module names to discover their content. If a
    class is found, it is represented as a bold entry in the list.

    The documentation contents of a class provides you with an incredible
    amount of information. Not only does it tell you about its base classes,
    implemented interfaces, attributes and methods, but it also lists the
    interface that requires a method or attribute to be implemented and the
    permissions required to access it. 
    """

    rootModules = ['ZConfig', 'persistence', 'transaction', 'zdaemon',
                   'zodb', 'zope']


=== Added File Zope3/src/zope/products/apidoc/classmodule/__init__.pyc ===
  <Binary-ish file>

=== Added File Zope3/src/zope/products/apidoc/classmodule/browser.pt ===
<html metal:use-macro="views/apidoc_macros/details">
<body metal:fill-slot="contents">

  <h1 class="details-header">Zope 3 Class Browser</h1>

  <p class="breadcrumbs">
    <span>
      <a href="./browser.html">[top]</a> /
    </span>
    <span tal:repeat="entry view/getBreadCrumbs">
      <a href="" 
         tal:attributes="href string:./browser.html?module=${entry/path}"
         tal:content="entry/name" />
      <tal:omit-tag condition="not: repeat/entry/end">/</tal:omit-tag>
    </span>
  </p>


  <table width="100%" valign="top"><tr>
   
  <td tal:repeat="column view/getEntriesInColumns"><ul>
    <li tal:repeat="entry column">
      <a href=""
         tal:condition="entry/module"
         tal:attributes="href string:./browser.html?module=${entry/path}"
         tal:content="entry/name" />
      <a href=""
         tal:condition="not:entry/module"
         tal:attributes="href string:./index.html?path=${entry/path}"
         tal:content="structure string:<b>${entry/name}</b>" />
    </li>
  </ul></td>

  </tr></table>

</body>
</html>

=== Added File Zope3/src/zope/products/apidoc/classmodule/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.
#
##############################################################################
"""Class Module Views

$Id: browser.py,v 1.1 2004/01/29 17:51:15 srichter Exp $
"""
import os
import inspect
from zope.app import zapi
from zope.configuration.config import ConfigurationContext
from zope.interface import implementedBy
from zope.products.apidoc.utilities import \
     getPythonPath, stx2html, getPermissionIds, getFunctionSignature, \
     getPublicAttributes, getInterfaceForAttribute
from zope.proxy import removeAllProxies
from zope.security.checker import getCheckerForInstancesOf

def _getTypeLink(type):
    path = getPythonPath(type)
    if path.startswith('__builtin__'):
        return None
    return path
    
class ClassDetails(object):
    """Represents the details of the class"""

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.path = request['path']
        self.klass = ConfigurationContext().resolve(self.path)
        self.checker = getCheckerForInstancesOf(self.klass)
        self.interfaces = list(implementedBy(self.klass))
        all_ifaces = {}
        for iface in self.interfaces:
            all_ifaces[iface] = 1
            for base in iface.getBases():
                all_ifaces[base] = 1
        self._all_ifaces = all_ifaces.keys()

    def getBases(self):
        """Get all bases of this class"""
        return [getPythonPath(base) for base in self.klass.__bases__]

    def getInterfaces(self):
        """Get all interfaces of this class."""
        return [getPythonPath(iface) for iface in self.interfaces]

    def getAttributes(self):
        """Get all attributes of this class."""
        attrs = []
        for name in getPublicAttributes(self.klass):
            attr = getattr(self.klass, name)
            if not inspect.ismethod(attr):
                entry = {'name': name,
                         'value': attr.__repr__(),
                         'type': type(attr).__name__,
                         'type_link': _getTypeLink(type(attr)),
                         'interface': getInterfaceForAttribute(
                                         name, self._all_ifaces)}
                entry.update(getPermissionIds(name, self.checker))
                attrs.append(entry)
        return attrs

    def getMethods(self):
        """Get all methods of this class."""
        methods = []
        for name in getPublicAttributes(self.klass):
            attr = getattr(self.klass, name)
            if inspect.ismethod(attr):
                entry = {'name': name,
                         'signature': getFunctionSignature(attr),
                         'doc': stx2html(attr.__doc__ or ''),
                         'interface': getInterfaceForAttribute(
                                          name, self._all_ifaces)}
                entry.update(getPermissionIds(name, self.checker))
                methods.append(entry)
        return methods

    def getDoc(self):
        """Get the doc string of the class."""
        return stx2html(self.klass.__doc__ or '')


class ModuleDetails(object):
    """ """

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.module_name = request.get('module', '')
        if self.module_name:
            self.module = __import__(self.module_name, {}, {}, ('*',))

    def isRoot(self):
        return self.module_name == ''

    def getEntries(self):
        if self.isRoot():
            return [{'name': name, 'path': name, 'module': True}
                    for name in self.context.rootModules]
        entries = []
        # Detect packages
        if self.module.__file__.endswith('__init__.pyc'):
            dir = os.path.split(self.module.__file__)[0]
            for file in os.listdir(dir):
                path = os.path.join(dir, file)
                if os.path.isdir(path) and '__init__.py' in os.listdir(path):
                    entries.append(
                        {'name': file,
                         'path': self.module.__name__ + '.' + file,
                         'module': True})
                elif os.path.isfile(path) and file.endswith('.py') and \
                         not file.startswith('__init__'):
                    entries.append(
                        {'name': file[:-3],
                         'path': self.module.__name__ + '.' + file[:-3],
                         'module': True})

        for name in self.module.__dict__.keys():
            attr = getattr(self.module, name)
            if `attr`.startswith('<class'):
                entries.append(
                    {'name': name,
                     'path': attr.__module__ + '.' + attr.__name__,
                     'module': False})
                
        entries.sort(lambda x, y: cmp(x['name'], y['name']))
        return entries

    def getEntriesInColumns(self, columns=3):
        entries = self.getEntries()
        per_col = len(entries)/3 + 1
        columns = []
        col = []
        in_col = 0
        for entry in entries:
            if in_col < per_col:
                col.append(entry)
                in_col += 1
            else:
                columns.append(col)
                col = [entry]
                in_col = 1
        if col:
            columns.append(col)
        return columns
            
        
    def getBreadCrumbs(self):
        names = self.module_name.split('.') 
        mods = []
        for i in xrange(len(names)):
            mods.append(
                {'name': names[i],
                 'path': '.'.join(names[:i+1])}
                )
        return mods


=== Added File Zope3/src/zope/products/apidoc/classmodule/browser.pyc ===
  <Binary-ish file>

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

  <class class=".ClassModule">
    <allow interface="zope.products.apidoc.interfaces.IDocumentationModule" />
    <allow attributes="rootModules" />
  </class>

  <utility
    provides="zope.products.apidoc.interfaces.IDocumentationModule"
    factory=".ClassModule"
    name="Class" />

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

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

  <browser:page
    for=".ClassModule"
    permission="zope.View"
    class=".browser.ModuleDetails"
    name="browser.html"
    template="browser.pt" />

</configure>


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

  <h1 class="details-header"
      tal:content="view/path">
    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">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:./index.html?path=$base"
           tal:content="base" />
      </li>
    </ul>
    
    <p tal:condition="not: bases">
      <em>There are no base classes.</em>
    </p>
    
    </div>

  <h2 class="details-section">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:../Interface/$iface/apiindex.html"
           tal:content="iface" />
      </li>
    </ul>
    
    <p tal:condition="not: ifaces">
      <em>There are no implemented interfaces.</em>
    </p>
    
    </div>


  <h2 class="details-section">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">
        (type: 
        <a href="" 
           tal:attributes="href string:./index.html?path=${attr/type_link}">
          <code tal:content="attr/type" /></a>)
      </tal:omit-tag>
      <br/>
      <i>Value:</i>
      <code tal:content="attr/value">u''</code><br />

      <span class="small" tal:condition="attr/interface">
        <i>Interface:</i>
        <a href=""
           tal:attributes="href attr/interface"
           tal:content="attr/interface">Iface</a><br />
      </span>
      <span class="small" 
          tal:condition="python: attr['read_perm'] and attr['write_perm']">
        <i>Permissions:</i>
        <span tal:replace="attr/read_perm">zope.View</span> (read), 
        <span tal:replace="attr/write_perm">zope.View</span> (write)
      </span>
    </li>

  </ul>

  <p tal:condition="not: attributes">
    <em>There are no attributes in this class.</em>
  </p>

  </div>


  <h2 class="details-section">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>Interface:</i>
        <a href=""
           tal:attributes="href 
               string:../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>Permissions:</i>
        <span tal:replace="method/read_perm">zope.View</span> (read), 
        <span tal:replace="method/write_perm">zope.View</span> (write)
      </span>
    </li>

  </ul>

  <p tal:condition="not: methods">
    <em>There are no methods in this class.</em>
  </p>

  </div>


</body>
</html>

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

  <div metal:fill-slot="menu" class="small">

    <div>Enter the dotted name (Python path) of the class:</div>
    <form action="./index.html" target="main">
      <input type="text" name="path" 
             style="font-size: 80%; width=95%" />
      <input type="submit" name="SUBMIT" value="Show" 
             style="font-size: 80%; width=95%"/>
    </form>

    <p style="font-size: 120%">
      <a href="./browser.html" target="main">Browse Zope Source</a>
    </p>
  </div>

</body>
</html>



More information about the Zope3-Checkins mailing list