r528 - / zope-docfindertab zope-docfindertab/branches zope-docfindertab/branches/upstream zope-docfindertab/branches/upstream/current zope-docfindertab/branches/upstream/current/DocFinder zope-docfindertab/branches/upstream/current/DocFinder/Extensions zope-docfindertab/branches/upstream/current/dtml zope-docfindertab/branches/upstream/current/help zope-docfindertab/branches/upstream/current/tests

Fabio Tranchitella kobold at alioth.debian.org
Tue Nov 28 12:30:35 CET 2006


Author: kobold
Date: 2006-11-28 12:30:34 +0100 (Tue, 28 Nov 2006)
New Revision: 528

Added:
   zope-docfindertab/
   zope-docfindertab/branches/
   zope-docfindertab/branches/upstream/
   zope-docfindertab/branches/upstream/current/
   zope-docfindertab/branches/upstream/current/CHANGES.txt
   zope-docfindertab/branches/upstream/current/DocFinder/
   zope-docfindertab/branches/upstream/current/DocFinder/Extensions/
   zope-docfindertab/branches/upstream/current/DocFinder/Extensions/analyse.py
   zope-docfindertab/branches/upstream/current/DocFinder/LICENSE.txt
   zope-docfindertab/branches/upstream/current/DocFinder/README.txt
   zope-docfindertab/branches/upstream/current/DocFinder/TODO.txt
   zope-docfindertab/branches/upstream/current/DocFinder/VERSION.txt
   zope-docfindertab/branches/upstream/current/DocFinder/__init__.py
   zope-docfindertab/branches/upstream/current/DocFinder/addDocFinderForm.dtml
   zope-docfindertab/branches/upstream/current/DocFinder/analyse.py
   zope-docfindertab/branches/upstream/current/DocFinder/construct.py
   zope-docfindertab/branches/upstream/current/DocFinder/funcs.py
   zope-docfindertab/branches/upstream/current/DocFinder/showDocumentation.dtml
   zope-docfindertab/branches/upstream/current/Patch.py
   zope-docfindertab/branches/upstream/current/Permissions.py
   zope-docfindertab/branches/upstream/current/README.txt
   zope-docfindertab/branches/upstream/current/__init__.py
   zope-docfindertab/branches/upstream/current/analyse.py
   zope-docfindertab/branches/upstream/current/dtml/
   zope-docfindertab/branches/upstream/current/dtml/showDocumentation.dtml
   zope-docfindertab/branches/upstream/current/funcs.py
   zope-docfindertab/branches/upstream/current/help/
   zope-docfindertab/branches/upstream/current/help/README.stx
   zope-docfindertab/branches/upstream/current/tests/
   zope-docfindertab/branches/upstream/current/tests/README.txt
   zope-docfindertab/branches/upstream/current/tests/__init__.py
   zope-docfindertab/branches/upstream/current/tests/framework.py
   zope-docfindertab/branches/upstream/current/tests/testDocFinderTab.py
   zope-docfindertab/branches/upstream/current/version.txt
   zope-docfindertab/tags/
Log:
[svn-inject] Installing original source of zope-docfindertab

Added: zope-docfindertab/branches/upstream/current/CHANGES.txt
===================================================================
--- zope-docfindertab/branches/upstream/current/CHANGES.txt	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/CHANGES.txt	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,30 @@
+0.5.0
+Renamed product to DocFinderTab. 
+Do not display docstrings but names of simple types in Python 2.3
+
+0.4.1
+Cookies did not work for everybody, they do now.
+
+0.4.0
+Make full use of DocFinder 0.4's filtering capabilities. Results may 
+now be filtered by regular expression and level of detail.
+Even nicer stylesheets for structured text.
+Again change the monkey patch and apply it to Item only.
+
+0.3.4
+Patch ObjectManager instead of Application. Thanks to Gilles Lenfant
+
+0.3.3
+Go even further and patch Bindings directly
+Fix file permissions issue
+
+0.3.2
+Boldly patch the Script base class
+
+0.3.0
+Added 'View documentation' permission
+
+0.2.0
+Monkey patch wrapper around Dieter Maurer's DocFinder product
+http://www.dieter.handshake.de/pyprojects/zope/DocFinder.html
+Adds a Documentation tab to all Zope objects

Added: zope-docfindertab/branches/upstream/current/DocFinder/Extensions/analyse.py
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/Extensions/analyse.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/Extensions/analyse.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,5 @@
+from Products.DocFinder.analyse import DocFinder
+
+def analyse(self,type='scripter',methodRe=''):
+  '''analyse *self* for documentation.'''
+  return DocFinder(self,type,methodRe)

Added: zope-docfindertab/branches/upstream/current/DocFinder/LICENSE.txt
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/LICENSE.txt	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/LICENSE.txt	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,3 @@
+BSD-like,
+
+see the head of 'analyse.py' for details.

Added: zope-docfindertab/branches/upstream/current/DocFinder/README.txt
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/README.txt	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/README.txt	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,63 @@
+DocFinder
+
+  'DocFinder' is a small product that allows to ask Zope for
+  documentation about its objects.
+
+  Unlike the API documentation which describes how thing should
+  be, the DocFinder documentation describes (at least partially)
+  how they really are: complete and precise.
+  The information contains documentation strings. This
+  information is, of cause, also unreliable.
+  What is reliable are the available methods, their parameters
+  and their security information.
+
+  When 'DocFinder' is instantiated, two objects
+  are created:
+
+    1. the external method 'analyseDocumentation'
+
+    2. the DTML method 'showDocumentation'
+
+  To show documentation for an object, you will call 'showDocumentation'
+  for this object. It will present the documentation
+  as a two level explorable tree structure.
+  The first level describes the classes from which the object
+  is build. The second level provides information
+  about each non-private attribute.
+
+  For each class level attribute, its name, the roles allowed to access
+  the attribute, its arguments (if it is callable) and
+  the documentation (if any) are shown.
+
+  Calling 'showDocumentation' for an object can take three forms:
+
+   1. calling is via an URL::
+
+        URL_to_OBJECT/showDocumentation
+
+      will present the documentation for *OBJECT*.
+
+   2. calling it from DTML with implicit argument passing::
+
+        <dtml-var showDocumentation>
+
+      will present the documentation for 'this()'.
+
+   3. calling it from DTML with explicit argument passing::
+
+        <dtml-var "showDocumentation(_.None,_,ObjToDoc__=object)">
+
+      will present the documentation for *object*.
+
+  'showDocumentation' uses 'analyseDocumentation' as an
+  auxiliary do analyse the object for documentation.
+  The result is a 'DocFinder' instance.
+  It behaves like a sequence of 'ClassDoc' instances
+  and the method 'tpValues' returns such a sequence.
+  
+  Each 'ClassDoc' provides methods 'Name' and 'Doc'.
+  Furthermore, it behaves like a sequence of 'AttributeDoc'
+  instances and 'tpValues' returns such a sequence.
+
+  Each 'AttributeDoc' provides methods 'Name', 'Permission',
+  'Roles', 'Args' and 'Doc'.

Added: zope-docfindertab/branches/upstream/current/DocFinder/TODO.txt
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/TODO.txt	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/TODO.txt	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1 @@
+* Provide a bit more comfort for installation

Added: zope-docfindertab/branches/upstream/current/DocFinder/VERSION.txt
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/VERSION.txt	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/VERSION.txt	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,4 @@
+DocFinder 0.4
+
+developed for Zope 2.3
+will not work for older Zope versions

Added: zope-docfindertab/branches/upstream/current/DocFinder/__init__.py
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/__init__.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/__init__.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,9 @@
+import construct
+
+def initialize(context):
+  context.registerClass(
+    construct.DocFinderDummy,
+    constructors=(construct.manage_addDocFinderForm,
+                  construct.manage_addDocFinder),
+    )
+  

Added: zope-docfindertab/branches/upstream/current/DocFinder/addDocFinderForm.dtml
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/addDocFinderForm.dtml	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/addDocFinderForm.dtml	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<html>
+  <head>
+    <title>Add Documentation Finder</title>
+  </head>
+
+  <body>
+    <h1>Add Documentation Finder</h1>
+
+<form action="manage_addDocFinder" method="post">
+<dtml-var Doc fmt="structured-text">
+
+<div align="center"><input type=submit value="Install"></div>
+</form>
+
+  </body>
+</html>

Added: zope-docfindertab/branches/upstream/current/DocFinder/analyse.py
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/analyse.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/analyse.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,405 @@
+# Copyright (C) 2001 by Dr. Dieter Maurer <dieter at handshake.de>
+# D-66386 St. Ingbert, Eichendorffstr. 23, Germany
+#
+#			All Rights Reserved
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice and this permission
+# notice appear in all copies, modified copies and in
+# supporting documentation.
+# 
+# Dieter Maurer DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL Dieter Maurer
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+"""analyse object for methods (names, arguments, documentation) and
+permissions."""
+
+# Detail types
+DETAIL_PROGRAMMER= 'programmer'
+DETAIL_SCRIPTER= 'scripter'
+DETAIL_WEB= 'web'
+
+import sys
+
+
+from funcs import func_prop_tuple
+from string import join, replace
+import re
+from types import IntType, DictType
+from AccessControl.SecurityInfo import ClassSecurityInfo, \
+     ACCESS_PUBLIC, ACCESS_PRIVATE, ACCESS_NONE
+from ExtensionClass import Base
+
+
+class DocFinder(Base):
+  '''determine the documentation of an object.
+
+  Doc is maintained in a two level structure:
+
+   1 classes, the object is build from, in inheritance order
+
+     each class is described by a 'ClassDoc' instance
+
+   2 for each class, the attributes defined by the class
+     
+     each attribute is described by a 'AttributeDoc' instance.
+
+  The documentation does not include instance level attributes
+  (they are too many). However, it does provide
+  summary information about access to unprotected attributes
+  in the doc for the pseudo class '-- Instance --'.
+  This information is not accurate, as the
+  '__allow_access_to_unprotected__subobjects__'
+  evaluation is not precise.
+  '''
+
+  _classDict= None
+
+  _secInfo= ClassSecurityInfo()
+  _secInfo.declarePublic('__getitem__','__len__','tpValues', 'tpId')
+
+  def __init__(self, obj, detail_type=DETAIL_SCRIPTER, method_filter= None):
+    # encode type
+    t= detail_type
+    if type(t) == type(''):
+      if t == DETAIL_PROGRAMMER: t= 10
+      elif t == DETAIL_WEB: t= -10
+      else: t= 0
+
+    # print 'DocFinder: ', detail_type, t; sys.stdout.flush()
+
+    # try to get a name
+    name= None
+    i= getattr(obj,'getId',None) or getattr(obj,'id',None) or getattr(obj,'__name__',None)
+    if i is not None:
+      if callable(i): i= i()
+      name= i
+    if name is None: name= '-- Doc --'
+
+    # permanent members
+    self._classes= []
+    self._type= t
+    self._name= name
+    self._method_filter=  method_filter and re.compile(method_filter).match
+
+    # temporary members
+    self._obj= obj
+    self._seenclasses= {}
+    self._attributes= {}
+    self._check= self._makeUnprotectedChecker()
+
+    c= _getClass(obj)
+
+    ic= ClassDoc('-- Instance --')
+    ic._append(AttributeDoc('-- unprotected attributes --',self._attrRoles(),obj= obj))
+    self._classes.append(ic)
+
+    self._analyseClassStructure(c)
+
+    # delete temporaries
+    del self._obj
+    del self._seenclasses
+    del self._attributes
+    del self._check
+
+
+  def __getitem__(self,k):
+    '''allow access by both integer as well as class names.'''
+    if type(k) is IntType: return self._classes[k]
+    if self._classDict is None:
+      cd= self._classDict= {}
+      for c in self._classes: cd[c._name]= c
+    return self._classDict[k]
+
+  
+  def __len__(self):
+    '''the length of the classes.'''
+    return len(self._classes)
+
+
+  def tpValues(self):
+    '''tuple of classes for tree display.'''
+    return tuple(self._classes)
+
+  def tpId(self):
+    return self._name
+
+
+  def _analyseClassStructure(self, c):
+    '''analyse class *c* including base classes.'''
+
+    if self._seenclasses.has_key(c): return
+    self._seenclasses[c]= None
+
+    self._analyseClass(c)
+
+    for b in c.__bases__:
+      self._analyseClassStructure(b)
+
+
+  def _analyseClass(self, c,
+                    _omit= {'__doc__': None, '__module__': None,
+                            '__allow_access_to_unprotected_subobjects__': None,
+                            }.has_key,
+                    _allow= {'__len__': None,
+                            '__str__': None,
+                            '__getitem__': None,
+                            '__call__': None,
+                            }.has_key,
+                    ):
+    '''analyse *c*.'''
+    cd= ClassDoc(c.__name__, getattr(c,'__doc__',None),_getLoc(c))
+    attributes= self._attributes; seen= attributes.has_key
+    check= self._check; o= self._obj; filter= self._method_filter
+
+    for (k,v) in c.__dict__.items():
+      if k[-9:] == '__roles__' or _omit(k): continue
+      if seen(k): continue
+      attributes[k]= None
+      if self._type <= 5:
+        if k[0] == '_' and not _allow(k): continue
+      if filter and not filter(k): continue
+      r= getattr(o,k+'__roles__', check(k))
+      if self._type <= 0 and _isPrivat(r): continue
+      # something interesting
+      a= AttributeDoc(k,r,v,o)
+      if self._type <= -5 and not a.Doc(): continue
+      cd._append(a)
+
+    if self._type <= 5 and not cd: return
+    cd._finish()
+    self._classes.append(cd)
+
+
+  def _makeUnprotectedChecker(self):
+    roles= getattr(self._obj,'__roles__', ACCESS_PUBLIC)
+    allow= getattr(self._obj,'__allow_access_to_unprotected_subobjects__', 0)
+    if type(allow) is IntType:
+      if not allow: roles= ACCESS_PRIVATE
+      def check(name,roles=roles): return roles
+    elif type(allow) is DictType:
+      def check(name, check=allow.get, roles=roles, priv= ACCESS_PRIVATE):
+        if check(name): return roles
+        return priv
+    else:
+      def check(name, obj= self._obj, allow= allow, roles=roles, priv= ACCESS_PRIVATE):
+        v= getattr(obj,name)
+        if allow(name,v): return roles
+        return priv
+    return check
+
+
+  def _attrRoles(self):
+    roles= getattr(self._obj,'__roles__', ACCESS_PUBLIC)
+    allow= getattr(self._obj,'__allow_access_to_unprotected_subobjects__', 0)
+    if type(allow) is IntType:
+      if not allow: roles= ACCESS_PRIVATE
+    elif type(allow) is DictType: roles= 'Restricted (Dict)'
+    else: roles= 'Restricted (Func)'
+    return roles
+
+
+DocFinder._secInfo.apply(DocFinder)
+
+
+class ClassDoc(Base):
+  """the documentation of a class.
+
+  It consists of a 'Name', 'Doc', 'Module' and a list of attributes,
+  that can also be accessed via the attribute name.
+  """
+
+  _secInfo= ClassSecurityInfo()
+  _secInfo.declarePublic('__getitem__','__len__','tpValues', 'tpId', 'Name', 'Doc', 'Module')
+
+  _AttrDict= None
+
+  def __init__(self,name,doc=None,mod=None):
+    self._name= name
+    self._doc= doc
+    self._mod= mod
+    self._attrs= []
+
+  def __getitem__(self,k):
+    '''allow access by both integer as well as attr names.'''
+    if type(k) is IntType: return self._attrs[k]
+    if self._AttrDict is None:
+      cd= self._AttrDict= {}
+      for c in self._attrs: cd[c._name]= c
+    return self._AttrDict[k]
+
+  
+  def __len__(self):
+    '''the length of the classes.'''
+    return len(self._attrs)
+
+
+  def tpValues(self):
+    '''tuple of attributes for tree display.'''
+    return tuple(self._attrs)
+
+  def tpId(self):
+    '''use name as id.'''
+    return self._name
+
+
+  def Name(self):
+    '''the class name.'''
+    return self._name
+
+  def Doc(self):
+    '''the class doc.'''
+    return self._doc
+
+  def Module(self):
+    '''the module the class is defined in.'''
+    return self._mod
+
+
+  def _append(self,attr):
+    '''append *attr*.'''
+    self._attrs.append(attr)
+
+
+  def _finish(self):
+    '''finish class definition.'''
+    self._attrs.sort(lambda a1,a2, cmp=cmp: cmp(a1._name,a2._name))
+
+
+ClassDoc._secInfo.apply(ClassDoc)
+
+
+
+class AttributeDoc(Base):
+  """the documentation of an attribute.
+
+  It consists of a 'Name', 'Roles', 'Args', 'Doc' and 'Type'.
+  """
+
+  _secInfo= ClassSecurityInfo()
+  _secInfo.declarePublic('tpValues', 'tpId',
+                         'Name', 'Roles', 'Args', 'Doc', 'Type', 'DocOrType',
+                         'Permission',
+                         )
+
+  _knownPermission= 0
+
+  def __init__(self,name,roles,value= None, obj= None):
+    if value is not None:
+      # determine arguments and documentation, if possible
+      arguments= doc= ''
+      try:
+        (n,a,doc)= func_prop_tuple(value)
+        arguments= join(a,', ')
+      except: pass
+      try: doc= value.__doc__
+      except: pass
+      type= _getType(value)
+    else: doc= arguments= type= ''
+
+    self._name= name
+    if roles is ACCESS_PUBLIC: roles= 'public'
+    elif roles == ACCESS_PRIVATE: roles= 'private'
+    elif roles is ACCESS_NONE: roles= 'none'
+    self._roles= roles
+    self._arguments= arguments
+    self._doc= doc
+    self._type= type
+    self._obj= obj
+
+  def Name(self):
+    '''the attribute name'''
+    return self._name
+
+  def Roles(self):
+    '''the attribute roles'''
+    return self._roles
+
+  def Args(self):
+    '''the attribute arguments'''
+    return self._arguments
+
+  def Doc(self):
+    '''the attribute documentation'''
+    return self._doc
+
+  def Type(self):
+    '''the attribute type'''
+    return self._type
+
+  def tpValues(self):
+    return ()
+
+  def tpId(self):
+    '''use name as id.'''
+    return self._name
+
+  def DocOrType(self):
+    '''either the Doc (prefered) or the Type.'''
+    return self.Doc() or self.Type()
+
+  def Permission(self):
+    '''return the permission protecting the attribute, 'None' if not directly protected.'''
+    if self._knownPermission: return self._permission
+    p= None
+    if self._obj:
+      name= self._name
+      if name[:3] == '-- ': name= ''
+      p= _lookup(self._obj, name+'__roles__')
+      if p is not None:
+        try:
+          p= replace(p[1]._p[1:-11],'_',' ')
+        except: p= '-- explicit --'
+    self._permission= p; self._knownPermission= 1
+    return p
+
+
+
+AttributeDoc._secInfo.apply(AttributeDoc)
+
+
+def _isPrivat(role):
+  return role == ACCESS_PRIVATE or role is ACCESS_NONE
+
+
+def _getLoc(c):
+  '''return location (module) of class *c*.'''
+  return getattr(c,'__module__',None)
+
+
+def _getType(v):
+  '''return a nice representation of the *v* type.'''
+  tn= type(v).__name__
+  if tn == 'instance': tn= '%s %s' % (v.__class__.__name__,tn)
+  elif tn == 'instance method': tn= '%s %s' % (v.im_class.__name__,tn)
+  return tn
+
+
+def _getClass(obj):
+  '''return the class of *obj*.'''
+  return hasattr(obj,'_klass') and obj._klass or obj.__class__
+
+
+def _lookup(obj,key):
+  '''emulate Pythons name lookup; return pair (class,attr) or 'None'.'''
+  m= {}
+  od= getattr(obj,'__dict__',m)
+  v= od.get(key,m)
+  if v is not m: return (obj,v)
+  v= _lookupClassHierarchy(_getClass(obj),key,m)
+  return v
+
+
+def _lookupClassHierarchy(c,k,m):
+  v= c.__dict__.get(k,m)
+  if v is not m: return (c,v)
+  for c in c.__bases__:
+    v= _lookupClassHierarchy(c,k,m)
+    if v is not None: return v
+  return None

Added: zope-docfindertab/branches/upstream/current/DocFinder/construct.py
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/construct.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/construct.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,42 @@
+'''DocFinder Constructor.'''
+
+from Globals import HTMLFile
+from Products.ExternalMethod.ExternalMethod import manage_addExternalMethod
+from OFS.DTMLMethod import addDTMLMethod
+
+def manage_addDocFinder(self,REQUEST=None):
+  '''add a 'DocFinder' pair to the current object manager.
+
+  A 'DocFinder' pair consists of the External Method 'analyseDocumentation'
+  and the DTML method 'showDocumentation'.
+
+  'analyseDocumentation' will only be installed, if not yet
+  available through acquisition, as a single instance is enough
+  for a complete subtree.
+  Note: The test is not safe (as the acquisition context
+  during creation may be different from that during use),
+  but there should be no problems in practice.
+
+  'showDocumentation' will be installed unless there
+  is already an object of this name in the current
+  object manager. This error is fatal.
+  '''
+  if not hasattr(self,'analyseDocumentation'):
+    manage_addExternalMethod(self,
+                             'analyseDocumentation',
+                             'analyse a Zope object for documentation',
+                             'DocFinder.analyse',
+                             'analyse',
+                             REQUEST)
+  addDTMLMethod(self,
+                'showDocumentation',
+                'show a Zope object\'s documentation',
+                HTMLFile('showDocumentation',globals()).read(),
+                REQUEST)
+  
+Doc= manage_addDocFinder.__doc__
+
+manage_addDocFinderForm= HTMLFile('addDocFinderForm',globals(), Doc=Doc)
+
+class DocFinderDummy:
+  meta_type= 'Documentation Finder'

Added: zope-docfindertab/branches/upstream/current/DocFinder/funcs.py
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/funcs.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/funcs.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,77 @@
+# Copyright (C) 1997-2001 by Dr. Dieter Maurer <dieter at hit.handshake.de>
+# D-66386 St. Ingbert, Eichendorffstr. 23, Germany
+#
+#			All Rights Reserved
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice appear in all copies and
+# modified copies and that
+# both that copyright notice and this permission notice appear in
+# supporting documentation.
+# 
+# Dieter Maurer DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL Dieter Maurer
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+"""Function auxiliaries"""
+
+import types, string
+
+# copied from Python header file
+CO_OPTIMIZED = 0x0001
+CO_NEWLOCALS = 0x0002
+CO_VARARGS = 0x0004
+CO_VARKEYWORDS = 0x0008
+
+def func_props(f,detail='a',name=None):
+  """returns a string describing the function, method or class *f*
+
+  *detail* controls how much properties are included:
+    ''		only the functions name
+    'a'		includes the functions arguments
+    'd'	        the functions first line of documentation
+    'D'		includes the functions complete documentation
+    several options can be concatenated"""
+  (n,a,d)= func_prop_tuple(f)
+  if name is None: name= n
+  args= 'a' in detail and '(' + string.join(a,',') + ')' or ''
+  doc= ''
+  if d:
+    if 'D' in detail: doc= '\n  ' + d
+    elif 'd' in detail: doc= ': ' + d
+  return name + args + doc
+
+
+def func_prop_tuple(f):
+  name=f.__name__
+  doc=f.__doc__
+  t=type(f)
+  if t is types.MethodType: f= f.im_func
+  elif t is types.ClassType:
+    try:
+      f= f.__init__.im_func
+      if f.__doc__: doc=f.__doc__
+    except: f= _emptyfunc
+  c=f.func_code
+  n=c.co_argcount
+  a=list(c.co_varnames[:n])
+  if f.func_defaults:
+    i=n-len(f.func_defaults)
+    for d in f.func_defaults:
+      a[i]= a[i] + '=' + repr(d)
+      i= i+1
+  if c.co_flags & CO_VARARGS:
+    a.append('*' + c.co_varnames[n])
+    n= n+1
+  if c.co_flags & CO_VARKEYWORDS:
+    a.append('**' + c.co_varnames[n])
+    n= n+1
+  if t is types.ClassType: del(a[0])
+  return (name, a, doc)
+    
+def _emptyfunc(self): pass    

Added: zope-docfindertab/branches/upstream/current/DocFinder/showDocumentation.dtml
===================================================================
--- zope-docfindertab/branches/upstream/current/DocFinder/showDocumentation.dtml	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/DocFinder/showDocumentation.dtml	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,141 @@
+<dtml-comment>
+show the documentation for the applied to object.
+
+The method is called in one of three ways:
+
+  * by the ZPublisher during URL traversal
+
+    In this case, the request URL has the form
+       <object URL>/showDocumentation
+
+    with <object URL> the URL of the object the documentation
+    should be given for,
+
+  * form DTML in the form:
+
+  	<dtml-var showDocumentation>
+
+    shows the documentation for "this()"
+
+  * from DTML in the form:
+
+  	<dtml-var "showDocumentation(_.None,_,ObjToDoc__=object)">
+
+    In this case, the documentation for "object" is shown.
+
+The method interprets the parameter "DocType__" (documentation type).
+It can be one of the strings
+'programmer' 'scripter' or 'web'.
+It controls the amount of documentation generated.
+'programmer' lists all available
+information, 'scripter' does not list any private attribute,
+'web' lists only attributes accessible through the Web.
+
+The parameter "DocMethodRe__" defines a regular expression
+used to filter methods. If not empty, only methods whose
+name are matched by the regular expression are shown.
+</dtml-comment>
+<html>
+<dtml-let obj__="_.has_key('ObjToDoc__') and ObjToDoc__ or this()"
+          DocType__="_.has_key('DocType__') and DocType__ or 'scripter'"
+          title="'%s documentation for %s' % (DocType__, obj__.title_and_id())"
+	  DocMethodRe__="_.has_key('DocMethodRe__') and DocMethodRe__ or ''"
+>
+<head>
+  <title><dtml-var title capitalize></title>
+  <style type="text/css">
+  body {
+    background-color: #ffffff;
+  }
+
+  .list-header {
+    background-color: #cccccc;
+    border: 3pt;
+  }
+
+  .row-hilite {
+    background-color: #ffffcc;
+    border: none;
+  }
+
+  .row-normal {
+    background-color: #ffccff;
+    border: none;
+  }
+  </style>
+</head>
+<body>
+<h2><dtml-var title capitalize></h2>
+
+<dtml-comment>
+We would like to avoid the cookie hackery below, but
+"tree", especially its "urlparam", is too stupid to
+allow us to pass the "DocType__" info.
+
+The hack became even more nasty with the introduction
+of "DocMethodRe__". We would break the cookie spec
+if the regular expression would contain ':', ';' or
+whitespace. Fortunately, they are not common in regular
+expressions for method names.
+</dtml-comment>
+<dtml-if "DocType__ != REQUEST.cookies.get('DocType__')">
+  <dtml-call "RESPONSE.setCookie('DocType__',DocType__)">
+</dtml-if>
+<dtml-if "DocMethodRe__ != REQUEST.cookies.get('DocMethodRe__')">
+  <dtml-call "RESPONSE.setCookie('DocMethodRe__',DocMethodRe__)">
+</dtml-if>
+
+<table align=center cellpadding=20>
+<tr>
+  <dtml-if "DocType__ != 'programmer'">
+    <th><a href="&dtml-URL;?DocType__=programmer">programmer documentation</a> (for product programmers)</th>
+  </dtml-if>
+  <dtml-if "DocType__ != 'scripter'">
+    <th><a href="&dtml-URL;?DocType__=scripter">scripter documentation</a> (for script/DTML programmers)</th>
+  </dtml-if>
+  <dtml-if "DocType__ != 'web'">
+    <th><a href="&dtml-URL;?DocType__=web">web documentation</a> (for Web users)</th>
+  </dtml-if>
+</tr>
+<tr>
+<th>Show methods matching</th>
+<th>
+  <form action="&dtml-URL;">
+    <input type="text" name="DocMethodRe__" value="&dtml-DocMethodRe__;" size=30>
+    <input type="submit" value="show">
+  </form>
+</th>
+</tr>
+</table>
+
+
+<dtml-tree "analyseDocumentation(obj__,DocType__,DocMethodRe__)">
+  <dtml-let level__=tree-level>
+    </td>
+    <dtml-if "level__==0">
+      <td class="list-header" align="center" colspan="4">
+      <table>
+        <tr><td align="center"><h2><dtml-var Name></h2></td></tr>
+	<dtml-if Module>
+	  <tr><td align="center"><dtml-var Module></td></tr>
+	</dtml-if>
+	<dtml-if Doc>
+	  <tr><td><dtml-var Doc fmt="structured-text"></td></tr>
+	</dtml-if>
+	</table>
+      <dtml-call "REQUEST.set('row__',0)">
+    <dtml-else>
+      <dtml-let td_args__="'class=\x22%s\x22' % (row__ % 2 and 'row-hilite' or 'row-normal')">
+        <td &dtml.-td_args__; width="15%"><dtml-var Name>&nbsp;</td>
+        <td &dtml.-td_args__; width="15%"><dtml-if Permission>&dtml-Permission;<br /></dtml-if><dtml-var Roles>&nbsp;</td>
+        <td &dtml.-td_args__; width="20%"><dtml-var Args>&nbsp;</td>
+        <td &dtml.-td_args__; width="40%"><dtml-var DocOrType fmt="structured-text">&nbsp;
+	<dtml-call "REQUEST.set('row__', row__+1)">
+      </dtml-let>
+    </dtml-if>
+  </dtml-let>
+</dtml-tree>
+
+</dtml-let>
+
+<dtml-var standard_html_footer>

Added: zope-docfindertab/branches/upstream/current/Patch.py
===================================================================
--- zope-docfindertab/branches/upstream/current/Patch.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/Patch.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,62 @@
+# DocFinderTab 0.5.0
+# (c) 2001-2004, Stefan H. Holek, stefan at epy.co.at
+# http://zope.org/Members/shh/DocFinderTab
+# License: ZPL
+# Zope: 2.3-2.7
+
+# Monkey patch wrapper around Dieter Maurer's DocFinder product
+# http://www.dieter.handshake.de/pyprojects/zope/DocFinder.html
+# Adds a Doc tab to all Zope objects
+
+# Thanks to Dieter for his input on how to make this work with 
+# PythonScripts and ExternalMethods, and for writing DocFinder 
+# in the first place.
+
+__doc__ = 'Add a Doc tab to all Zope objects'
+__version__ = '0.5.0'
+
+__refresh_module__ = 0
+
+try:
+
+    from Globals import HTMLFile
+    from App.Management import Tabs
+    from OFS.SimpleItem import Item
+    from analyse import DocFinder
+    from AccessControl import getSecurityManager
+    from AccessControl.PermissionRole import PermissionRole
+    from Permissions import ViewDocPermission, ViewDocDefaultRoles
+
+    def filtered_manage_options(self, REQUEST=None):
+        # Append a Doc tab to an object's management tabs
+        tabs = self._old_filtered_manage_options(REQUEST)
+        secman = getSecurityManager()
+        if len(tabs) and secman.checkPermission(ViewDocPermission, self.this()):
+            tabs.append( {'label': 'Doc', 
+                          'action': 'showDocumentation', 
+                          'help': ('DocFinderTab', 'README.stx')} )
+        return tabs
+
+    Tabs._old_filtered_manage_options = Tabs.filtered_manage_options
+    Tabs.filtered_manage_options = filtered_manage_options
+
+    showDocumentation = HTMLFile('dtml/showDocumentation', globals())
+
+    def analyseDocumentation(self, object, type='scripter', filter=''):
+        return DocFinder(object, type, filter)
+        
+    ViewDocRoles = PermissionRole(ViewDocPermission, ViewDocDefaultRoles)
+
+    Item.showDocumentation = showDocumentation
+    Item.showDocumentation__roles__ = ViewDocRoles
+    Item.analyseDocumentation = analyseDocumentation
+    Item.analyseDocumentation__roles__ = ViewDocRoles
+
+    from zLOG import LOG, INFO
+    LOG('DocFinderTab', INFO, 'Applied patch version %s.' % __version__)
+
+except:
+
+    import traceback
+    traceback.print_exc()
+

Added: zope-docfindertab/branches/upstream/current/Permissions.py
===================================================================
--- zope-docfindertab/branches/upstream/current/Permissions.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/Permissions.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,12 @@
+# DocFinderTab 0.5.0
+# (c) 2001-2004, Stefan H. Holek, stefan at epy.co.at
+# http://zope.org/Members/shh/DocFinderTab
+# License: ZPL
+# Zope: 2.3-2.7
+
+__doc__ = 'Add a Doc tab to all Zope objects'
+__version__ = '0.5.0'
+
+ViewDocPermission = 'View documentation'
+ViewDocDefaultRoles = ('Manager',)
+ 

Added: zope-docfindertab/branches/upstream/current/README.txt
===================================================================
--- zope-docfindertab/branches/upstream/current/README.txt	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/README.txt	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,18 @@
+
+DocFinderTab 0.5.0
+
+This product ows nearly everything to Dieter Maurer's DocFinder
+product (version 0.4).
+
+http://www.dieter.handshake.de/pyprojects/zope/DocFinder.html
+   
+I just put some sugar on it ;-)
+
+To install extract the tarball into your Products directory and
+restart Zope. This will add a "Doc" tab to every object's managment
+screens. Now go to an object's management screen, click the "Doc" 
+tab and start exploring.
+
+See the online help for a detailed explanation of what you can
+do with DocFinderTab.
+

Added: zope-docfindertab/branches/upstream/current/__init__.py
===================================================================
--- zope-docfindertab/branches/upstream/current/__init__.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/__init__.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,34 @@
+# DocFinderTab 0.5.0
+# (c) 2001-2004, Stefan H. Holek, stefan at epy.co.at
+# http://zope.org/Members/shh/DocFinderTab
+# License: ZPL
+# Zope: 2.3-2.7
+
+# Monkey patch wrapper around Dieter Maurer's DocFinder product
+# http://www.dieter.handshake.de/pyprojects/zope/DocFinder.html
+# Adds a Doc tab to all Zope objects
+
+# Thanks to Dieter for his input on how to make this work with 
+# PythonScripts and ExternalMethods, and for writing DocFinder 
+# in the first place.
+
+__doc__ = 'Add a Doc tab to all Zope objects'
+__version__ = '0.5.0'
+
+__refresh_module__ = 0
+
+from AccessControl.Permission import registerPermissions
+from Permissions import ViewDocPermission, ViewDocDefaultRoles
+
+def initialize(context):
+    # Register the helpfile
+    if hasattr(context, 'registerHelp'):
+        context.registerHelp()
+        context.registerHelpTitle('DocFinderTab')
+
+    # Register our permission
+    registerPermissions(((ViewDocPermission, (), ViewDocDefaultRoles),))
+
+# Apply the DocFinderTab patch
+import Patch
+

Added: zope-docfindertab/branches/upstream/current/analyse.py
===================================================================
--- zope-docfindertab/branches/upstream/current/analyse.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/analyse.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,422 @@
+# Copyright (C) 2001 by Dr. Dieter Maurer <dieter at handshake.de>
+# D-66386 St. Ingbert, Eichendorffstr. 23, Germany
+#
+#			All Rights Reserved
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice and this permission
+# notice appear in all copies, modified copies and in
+# supporting documentation.
+# 
+# Dieter Maurer DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL Dieter Maurer
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+"""analyse object for methods (names, arguments, documentation) and
+permissions."""
+
+# Detail types
+DETAIL_PROGRAMMER= 'programmer'
+DETAIL_SCRIPTER= 'scripter'
+DETAIL_WEB= 'web'
+
+import sys
+
+
+from funcs import func_prop_tuple
+from string import join, replace
+import re
+from types import IntType, DictType
+from AccessControl.SecurityInfo import ClassSecurityInfo, \
+     ACCESS_PUBLIC, ACCESS_PRIVATE, ACCESS_NONE
+from ExtensionClass import Base
+
+# DFT
+try:
+    simple_types = {str: 1, unicode: 1, int: 1, float: 1, long: 1,
+                    tuple: 1, list: 1, dict: 1}
+except:
+    simple_types = None
+
+
+class DocFinder(Base):
+  '''determine the documentation of an object.
+
+  Doc is maintained in a two level structure:
+
+   1 classes, the object is build from, in inheritance order
+
+     each class is described by a 'ClassDoc' instance
+
+   2 for each class, the attributes defined by the class
+     
+     each attribute is described by a 'AttributeDoc' instance.
+
+  The documentation does not include instance level attributes
+  (they are too many). However, it does provide
+  summary information about access to unprotected attributes
+  in the doc for the pseudo class '-- Instance --'.
+  This information is not accurate, as the
+  '__allow_access_to_unprotected__subobjects__'
+  evaluation is not precise.
+  '''
+
+  _classDict= None
+
+  _secInfo= ClassSecurityInfo()
+  _secInfo.declarePublic('__getitem__','__len__','tpValues', 'tpId')
+
+  def __init__(self, obj, detail_type=DETAIL_SCRIPTER, method_filter= None):
+    # encode type
+    t= detail_type
+    if type(t) == type(''):
+      if t == DETAIL_PROGRAMMER: t= 10
+      elif t == DETAIL_WEB: t= -10
+      else: t= 0
+
+    # print 'DocFinder: ', detail_type, t; sys.stdout.flush()
+
+    # try to get a name
+    name= None
+    i= getattr(obj,'getId',None) or getattr(obj,'id',None) or getattr(obj,'__name__',None)
+    if i is not None:
+      if callable(i): i= i()
+      name= i
+    if name is None: name= '-- Doc --'
+
+    # permanent members
+    self._classes= []
+    self._type= t
+    self._name= name
+    self._method_filter=  method_filter and re.compile(method_filter).match
+
+    # temporary members
+    self._obj= obj
+    self._seenclasses= {}
+    self._attributes= {}
+    self._check= self._makeUnprotectedChecker()
+
+    c= _getClass(obj)
+
+    ic= ClassDoc('-- Instance --')
+    ic._append(AttributeDoc('-- unprotected attributes --',self._attrRoles(),obj= obj))
+    self._classes.append(ic)
+
+    self._analyseClassStructure(c)
+
+    # delete temporaries
+    del self._obj
+    del self._seenclasses
+    del self._attributes
+    del self._check
+
+
+  def __getitem__(self,k):
+    '''allow access by both integer as well as class names.'''
+    if type(k) is IntType: return self._classes[k]
+    if self._classDict is None:
+      cd= self._classDict= {}
+      for c in self._classes: cd[c._name]= c
+    return self._classDict[k]
+
+  
+  def __len__(self):
+    '''the length of the classes.'''
+    return len(self._classes)
+
+
+  def tpValues(self):
+    '''tuple of classes for tree display.'''
+    return tuple(self._classes)
+
+  def tpId(self):
+    return self._name
+
+
+  def _analyseClassStructure(self, c):
+    '''analyse class *c* including base classes.'''
+
+    if self._seenclasses.has_key(c): return
+    self._seenclasses[c]= None
+
+    self._analyseClass(c)
+
+    for b in c.__bases__:
+      self._analyseClassStructure(b)
+
+
+  def _analyseClass(self, c,
+                    _omit= {'__doc__': None, '__module__': None,
+                            '__allow_access_to_unprotected_subobjects__': None,
+                            'showDocumentation': None,      # DFT
+                            'analyseDocumentation': None,   # DFT
+                            }.has_key,
+                    _allow= {'__len__': None,
+                            '__str__': None,
+                            '__getitem__': None,
+                            '__call__': None,
+                            }.has_key,
+                    ):
+    '''analyse *c*.'''
+    cd= ClassDoc(c.__name__, getattr(c,'__doc__',None),_getLoc(c))
+    attributes= self._attributes; seen= attributes.has_key
+    check= self._check; o= self._obj; filter= self._method_filter
+
+    for (k,v) in c.__dict__.items():
+      if k[-9:] == '__roles__' or _omit(k): continue
+      if seen(k): continue
+      attributes[k]= None
+      if self._type <= 5:
+        if k[0] == '_' and not _allow(k): continue
+      if filter and not filter(k): continue
+      r= getattr(o,k+'__roles__', check(k))
+      if self._type <= 0 and _isPrivat(r): continue
+      # something interesting
+      a= AttributeDoc(k,r,v,o)
+      if self._type <= -5 and not a.Doc(): continue
+      cd._append(a)
+
+    if filter and not cd: return  # DFT
+    cd._finish()
+    self._classes.append(cd)
+
+
+  def _makeUnprotectedChecker(self):
+    roles= getattr(self._obj,'__roles__', ACCESS_PUBLIC)
+    allow= getattr(self._obj,'__allow_access_to_unprotected_subobjects__', 0)
+    if type(allow) is IntType:
+      if not allow: roles= ACCESS_PRIVATE
+      def check(name,roles=roles): return roles
+    elif type(allow) is DictType:
+      def check(name, check=allow.get, roles=roles, priv= ACCESS_PRIVATE):
+        if check(name): return roles
+        return priv
+    else:
+      def check(name, obj= self._obj, allow= allow, roles=roles, priv= ACCESS_PRIVATE):
+        v= getattr(obj,name)
+        if allow(name,v): return roles
+        return priv
+    return check
+
+
+  def _attrRoles(self):
+    roles= getattr(self._obj,'__roles__', ACCESS_PUBLIC)
+    allow= getattr(self._obj,'__allow_access_to_unprotected_subobjects__', 0)
+    if type(allow) is IntType:
+      if not allow: roles= ACCESS_PRIVATE
+    elif type(allow) is DictType: roles= 'Restricted (Dict)'
+    else: roles= 'Restricted (Func)'
+    return roles
+
+
+DocFinder._secInfo.apply(DocFinder)
+
+
+class ClassDoc(Base):
+  """the documentation of a class.
+
+  It consists of a 'Name', 'Doc', 'Module' and a list of attributes,
+  that can also be accessed via the attribute name.
+  """
+
+  _secInfo= ClassSecurityInfo()
+  _secInfo.declarePublic('__getitem__','__len__','tpValues', 'tpId', 'Name', 'Doc', 'Module')
+
+  _AttrDict= None
+
+  def __init__(self,name,doc=None,mod=None):
+    self._name= name
+    self._doc= doc
+    self._mod= mod
+    self._attrs= []
+
+  def __getitem__(self,k):
+    '''allow access by both integer as well as attr names.'''
+    if type(k) is IntType: return self._attrs[k]
+    if self._AttrDict is None:
+      cd= self._AttrDict= {}
+      for c in self._attrs: cd[c._name]= c
+    return self._AttrDict[k]
+
+  
+  def __len__(self):
+    '''the length of the classes.'''
+    return len(self._attrs)
+
+
+  def tpValues(self):
+    '''tuple of attributes for tree display.'''
+    return tuple(self._attrs)
+
+  def tpId(self):
+    '''use name as id.'''
+    return self._name
+
+
+  def Name(self):
+    '''the class name.'''
+    return self._name
+
+  def Doc(self):
+    '''the class doc.'''
+    return self._doc
+
+  def Module(self):
+    '''the module the class is defined in.'''
+    return self._mod
+
+
+  def _append(self,attr):
+    '''append *attr*.'''
+    self._attrs.append(attr)
+
+
+  def _finish(self):
+    '''finish class definition.'''
+    self._attrs.sort(lambda a1,a2, cmp=cmp: cmp(a1._name,a2._name))
+
+
+ClassDoc._secInfo.apply(ClassDoc)
+
+
+
+class AttributeDoc(Base):
+  """the documentation of an attribute.
+
+  It consists of a 'Name', 'Roles', 'Args', 'Doc' and 'Type'.
+  """
+
+  _secInfo= ClassSecurityInfo()
+  _secInfo.declarePublic('tpValues', 'tpId',
+                         'Name', 'Roles', 'Args', 'Doc', 'Type', 'DocOrType',
+                         'Permission',
+                         )
+
+  _knownPermission= 0
+
+  def __init__(self,name,roles,value= None, obj= None):
+    if value is not None:
+      # determine arguments and documentation, if possible
+      arguments= doc= ''
+      try:
+        (n,a,doc)= func_prop_tuple(value)
+        arguments= join(a,', ')
+      except: pass
+      try: doc= _getDoc(value)  # DFT
+      except: pass
+      type= _getType(value)
+    else: doc= arguments= type= ''
+
+    self._name= name
+    if roles is ACCESS_PUBLIC: roles= 'public'
+    elif roles == ACCESS_PRIVATE: roles= 'private'
+    elif roles is ACCESS_NONE: roles= 'none'
+    self._roles= roles
+    self._arguments= arguments
+    self._doc= doc
+    self._type= type
+    self._obj= obj
+
+  def Name(self):
+    '''the attribute name'''
+    return self._name
+
+  def Roles(self):
+    '''the attribute roles'''
+    return self._roles
+
+  def Args(self):
+    '''the attribute arguments'''
+    return self._arguments
+
+  def Doc(self):
+    '''the attribute documentation'''
+    return self._doc
+
+  def Type(self):
+    '''the attribute type'''
+    return self._type
+
+  def tpValues(self):
+    return ()
+
+  def tpId(self):
+    '''use name as id.'''
+    return self._name
+
+  def DocOrType(self):
+    '''either the Doc (prefered) or the Type.'''
+    return self.Doc() or self.Type()
+
+  def Permission(self):
+    '''return the permission protecting the attribute, 'None' if not directly protected.'''
+    if self._knownPermission: return self._permission
+    p= None
+    if self._obj:
+      name= self._name
+      if name[:3] == '-- ': name= ''
+      p= _lookup(self._obj, name+'__roles__')
+      if p is not None:
+        try:
+          p= replace(p[1]._p[1:-11],'_',' ')
+        except: p= '-- explicit --'
+    self._permission= p; self._knownPermission= 1
+    return p
+
+
+
+AttributeDoc._secInfo.apply(AttributeDoc)
+
+
+def _isPrivat(role):
+  return role == ACCESS_PRIVATE or role is ACCESS_NONE
+
+
+def _getLoc(c):
+  '''return location (module) of class *c*.'''
+  return getattr(c,'__module__',None)
+
+
+def _getType(v):
+  '''return a nice representation of the *v* type.'''
+  tn= type(v).__name__
+  if tn == 'instance': tn= '%s %s' % (v.__class__.__name__,tn)
+  elif tn == 'instance method': tn= '%s %s' % (v.im_class.__name__,tn)
+  return tn
+
+
+def _getClass(obj):
+  '''return the class of *obj*.'''
+  return hasattr(obj,'_klass') and obj._klass or obj.__class__
+
+
+# DFT
+def _getDoc(obj, simple_types=simple_types):
+    '''return the docstring of *obj*.'''
+    if simple_types is not None and type(obj) in simple_types:
+        return _getType(obj)
+    return obj.__doc__
+
+
+def _lookup(obj,key):
+  '''emulate Pythons name lookup; return pair (class,attr) or 'None'.'''
+  m= {}
+  od= getattr(obj,'__dict__',m)
+  v= od.get(key,m)
+  if v is not m: return (obj,v)
+  v= _lookupClassHierarchy(_getClass(obj),key,m)
+  return v
+
+
+def _lookupClassHierarchy(c,k,m):
+  v= c.__dict__.get(k,m)
+  if v is not m: return (c,v)
+  for c in c.__bases__:
+    v= _lookupClassHierarchy(c,k,m)
+    if v is not None: return v
+  return None

Added: zope-docfindertab/branches/upstream/current/dtml/showDocumentation.dtml
===================================================================
--- zope-docfindertab/branches/upstream/current/dtml/showDocumentation.dtml	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/dtml/showDocumentation.dtml	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,192 @@
+<dtml-let target__="_.has_key('ObjToDoc__') and ObjToDoc__ or this()">
+
+<dtml-if "REQUEST.has_key('expert__')">
+  <dtml-call "REQUEST.set('expert__', _.int(REQUEST['expert__']))">
+<dtml-elif "REQUEST.has_key('submitted__')">
+  <dtml-call "REQUEST.set('expert__', 0)">
+<dtml-elif "REQUEST.cookies.has_key('DF_expert')">
+  <dtml-call "REQUEST.set('expert__', _.int(REQUEST.cookies['DF_expert']))">
+<dtml-else>
+  <dtml-call "REQUEST.set('expert__', 0)">
+</dtml-if>
+<dtml-if "expert__ != REQUEST.cookies.get('DF_expert')">
+  <dtml-call "RESPONSE.setCookie('DF_expert', '%s' %expert__, path='/')">
+</dtml-if>
+<dtml-if "REQUEST.has_key('filter__')">
+<dtml-elif "REQUEST.cookies.has_key('DF_filter')">
+  <dtml-call "REQUEST.set('filter__', REQUEST.cookies['DF_filter'])">
+<dtml-else>
+  <dtml-call "REQUEST.set('filter__', '')">
+</dtml-if>
+<dtml-if "filter__ != REQUEST.cookies.get('DF_filter')">
+  <dtml-call "RESPONSE.setCookie('DF_filter', filter__, path='/')">
+</dtml-if>
+
+<html><head><title>Documentation for object <dtml-var "target__.getId()" html_quote></title>
+<dtml-comment> The following is partially ripped from manage_page_header </dtml-comment>
+<dtml-let ag="_.string.lower(REQUEST.get('HTTP_USER_AGENT', ''))"
+          find="_.string.find"
+          is_nav4="ag[:9]=='mozilla/4' and find(ag,'msie')<0"
+          is_win="find(ag,'win')>=0 and find(ag,'openwin')<0 and find(ag,'mac')<0 and find(ag,'x11')<0"
+          is_msiewin="is_win and find(ag,'msie')>=0"
+          is_camino="find(ag,'camino')>=0"
+          is_mozilla="ag[:8]=='mozilla/' and find(ag,'gecko/')>=0 and not is_camino"
+          use_css="REQUEST.get('zmi_use_css', '1')"
+          zmi_embedded_css="1">
+<dtml-if use_css>
+<dtml-if is_nav4>
+<style type="text/css">
+<!--
+<dtml-var manage_page_style.css missing>
+-->
+</style>
+<dtml-else>
+<link rel="stylesheet" type="text/css" href="<dtml-var BASEPATH1>/manage_page_style.css">
+</dtml-if is_nav4>
+</dtml-if use_css>
+
+<style type="text/css">
+<!--
+body                  { background-color: white; }
+form                  { padding: 0; margin: 0; }
+.list-header          { background-color: #6699cc; border: none; }
+.row-hilite           { background-color: #cfcfcf; border: none; }
+.row-normal           { background-color: #efefef; border: none; } 
+                              /* t r  b l */
+.list-header h3       { padding: 0 0  3 0; margin: 0; }
+.list-header p        { padding: 0 0 15 0; margin: 0; }
+.list-header .nodoc   { padding: 0 0 13 0; margin: 0; }
+.list-header .module  { padding: 0 0  6 0; margin: 0; color: black; }
+.row-hilite  p        { padding: 4 2  4 2; margin: 0; }
+.row-normal  p        { padding: 4 2  4 2; margin: 0; }
+.black                { color: black; }
+.structured-text      { color: #333333; }
+.structured-text h1   { padding: 2 0  2 0; margin: 0; font-size: 12pt; color: #333333; }  
+.structured-text h2   { padding: 2 0  2 0; margin: 0; font-size: 11pt; color: #333333; }  
+.structured-text h3   { padding: 2 0  2 0; margin: 0; font-size: 10pt; color: #333333; }  
+.structured-text h4   { padding: 2 0  2 0: margin: 0; font-size: 10pt; color: #333333; font-style: italic; }  
+.structured-text ul   { margin-top: 5; margin-bottom: 5; font-size: 10pt; color: #333333; }  
+.structured-text ol   { margin-top: 5; margin-bottom: 5; font-size: 10pt; color: #333333; }  
+<dtml-if is_msiewin>
+  .filter-box         { padding: 0; margin: 0; line-height: 10pt; font-size: 8pt; font-family: Arial,Helvetica,sans-serif; height: 13pt; }
+  .expert-box         { margin-left: 0; height: 13pt; }
+  .shortp             { padding-top: 0.8em; margin-top: 0; }
+<dtml-elif is_win>
+  .filter-box         { padding: 0; margin: 0; line-height: 10pt; font-size: 8pt; font-family: Arial,Helvetica,sans-serif; }
+</dtml-if>
+<dtml-if is_camino>
+  .filter-box         { padding: 0; margin: 0; line-height: 10pt; font-size: 8pt; font-family: Arial,Helvetica,sans-serif; }
+  .expert-box         { margin-top: 1; margin-left: 0; height: 10pt; }
+<dtml-elif is_mozilla> 
+  .expert-box         { margin-top: 1; margin-left: 2; }
+</dtml-if>
+-->
+</style>
+
+<script type="text/javascript">
+<!--
+function clear() {
+  form = document.forms[0]
+  filter = form.elements[0]
+  filter.value = ''
+  form.submit()
+}
+// -->
+</script>
+</head><body bgcolor=white>
+<dtml-var manage_tabs missing>
+
+<p>
+<table border=0 cellspacing=0 cellpadding=0 width=100%>
+<form action="&dtml-URL0;">
+<tr valign="top">
+  <td class="std-text" width=100%>
+    Documentation for <b><dtml-with "target__"><dtml-var meta_type html_quote></dtml-with></b> object 
+    <dtml-if "_.hasattr(target__, 'title_and_id')">
+      <b><dtml-var "target__.title_and_id()" html_quote></b>
+    <dtml-else>
+      <b><dtml-var "target__.getId()" html_quote></b>
+    </dtml-if>
+  </td>
+  <td>&nbsp;</td>
+  <td align=right class="std-text" width=1>
+    Filter&nbsp;<br>
+  </td>
+  <td align=right class="std-text" width=1>
+    <input class="filter-box" type="text" name="filter__" value="<dtml-var filter__ html_quote>"size=12><br>
+  </td>
+  <dtml-if filter__>
+    <td align=left class="std-text" width=1>
+      <a href="javascript:clear()">X</a><br>
+    </td>
+  </dtml-if>
+  <td>&nbsp;</td>
+  <td align=right class="std-text" width=1>
+    Expert&nbsp;<br>
+  </td>
+  <td align=right class="std-text" width=1>
+    <input class="expert-box" type=checkbox name=expert__ value="1"<dtml-if expert__> checked</dtml-if> onclick="javascript:submit()"><br>
+  </td>
+</tr>
+<input type=hidden name=submitted__ value=1>
+</form>
+</table>
+
+<p class=shortp>
+<dtml-tree "analyseDocumentation(target__, expert__ and 'programmer' or 'scripter', filter__)">
+  <dtml-let level__=tree-level>
+    </td>
+    <dtml-if "level__==0">
+      <td class="list-header" align="center" colspan="4" width="100%">
+        <h3><dtml-var Name></h3>
+        <dtml-if expert__>
+          <dtml-if Module>
+            <p class=module><dtml-var Module></p>
+          </dtml-if>
+        </dtml-if>
+        <dtml-if Doc>
+	  <span class=structured-text><dtml-var Doc fmt="structured-text"></span>
+        <dtml-else>
+          <p class=nodoc></p>
+        </dtml-if>
+      <dtml-call "REQUEST.set('row__',0)">
+    <dtml-else>
+      <dtml-let td_args__="'class=\x22%s\x22' % (row__ % 2 and 'row-hilite' or 'row-normal')">
+        <td nowrap &dtml.-td_args__; width="20%">
+          <span class="form-element">
+            <p class=black><dtml-var Name></p>
+          </span>
+        </td>
+        <td &dtml.-td_args__; width="20%">
+          <span class="form-element">
+            <dtml-if Permission>
+              <dtml-if "expert__ or Permission != '-- explicit --'"><p class=black><dtml-var Permission><br></p></dtml-if>
+            </dtml-if>
+            <dtml-if Roles><p class=black><dtml-var Roles></p><dtml-else>&nbsp;</dtml-if>
+          </span>
+        </td>
+        <td &dtml.-td_args__; width="20%">
+          <span class="form-element">
+            <dtml-if Args><p class=black><dtml-var Args></p><dtml-else>&nbsp;</dtml-if>
+          </span>
+        </td>
+        <td &dtml.-td_args__; width="40%">
+          <span class="form-element">
+            <dtml-let doc="Doc()">
+              <dtml-if "doc and _.string.strip(doc)">
+                <span class=structured-text><dtml-var doc fmt="structured-text"></span>
+              <dtml-else>
+                <dtml-if Type><p><dtml-var Type></p><dtml-else>&nbsp;</dtml-if>
+              </dtml-if>
+            </dtml-let>
+          </span>
+	<dtml-call "REQUEST.set('row__', row__+1)">
+      </dtml-let td_args__>
+    </dtml-if>
+  </dtml-let level__>
+</dtml-tree>
+
+</dtml-let ag>
+</dtml-let target__>
+
+<dtml-var manage_page_footer missing>

Added: zope-docfindertab/branches/upstream/current/funcs.py
===================================================================
--- zope-docfindertab/branches/upstream/current/funcs.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/funcs.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,77 @@
+# Copyright (C) 1997-2001 by Dr. Dieter Maurer <dieter at hit.handshake.de>
+# D-66386 St. Ingbert, Eichendorffstr. 23, Germany
+#
+#			All Rights Reserved
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose and without fee is hereby granted,
+# provided that the above copyright notice appear in all copies and
+# modified copies and that
+# both that copyright notice and this permission notice appear in
+# supporting documentation.
+# 
+# Dieter Maurer DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL Dieter Maurer
+# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+"""Function auxiliaries"""
+
+import types, string
+
+# copied from Python header file
+CO_OPTIMIZED = 0x0001
+CO_NEWLOCALS = 0x0002
+CO_VARARGS = 0x0004
+CO_VARKEYWORDS = 0x0008
+
+def func_props(f,detail='a',name=None):
+  """returns a string describing the function, method or class *f*
+
+  *detail* controls how much properties are included:
+    ''		only the functions name
+    'a'		includes the functions arguments
+    'd'	        the functions first line of documentation
+    'D'		includes the functions complete documentation
+    several options can be concatenated"""
+  (n,a,d)= func_prop_tuple(f)
+  if name is None: name= n
+  args= 'a' in detail and '(' + string.join(a,',') + ')' or ''
+  doc= ''
+  if d:
+    if 'D' in detail: doc= '\n  ' + d
+    elif 'd' in detail: doc= ': ' + d
+  return name + args + doc
+
+
+def func_prop_tuple(f):
+  name=f.__name__
+  doc=f.__doc__
+  t=type(f)
+  if t is types.MethodType: f= f.im_func
+  elif t is types.ClassType:
+    try:
+      f= f.__init__.im_func
+      if f.__doc__: doc=f.__doc__
+    except: f= _emptyfunc
+  c=f.func_code
+  n=c.co_argcount
+  a=list(c.co_varnames[:n])
+  if f.func_defaults:
+    i=n-len(f.func_defaults)
+    for d in f.func_defaults:
+      a[i]= a[i] + '=' + repr(d)
+      i= i+1
+  if c.co_flags & CO_VARARGS:
+    a.append('*' + c.co_varnames[n])
+    n= n+1
+  if c.co_flags & CO_VARKEYWORDS:
+    a.append('**' + c.co_varnames[n])
+    n= n+1
+  if t is types.ClassType: del(a[0])
+  return (name, a, doc)
+    
+def _emptyfunc(self): pass    

Added: zope-docfindertab/branches/upstream/current/help/README.stx
===================================================================
--- zope-docfindertab/branches/upstream/current/help/README.stx	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/help/README.stx	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,66 @@
+Release Notes
+
+    DocFinderTab 0.5.0
+
+Description
+
+    You can use the "Doc" view to ask Zope for documentation about its objects.
+
+    This product makes Dieter Maurer's 
+    <a href="http://www.dieter.handshake.de/pyprojects/zope/DocFinder.html" target=_blank>DocFinder</a>
+    available from a ZMI management tab.  
+    DocFinder's introspection capabilities make it an important part of the Zopista's 
+    toolbox:
+
+    - Find out how a certain product works.<br> *Tip: Try DocFinder on the CMF!*
+
+    - View an object's public and private interfaces.<br> *Instant reference documentation!*
+
+    - Debug permission related problems.
+
+    - ...
+
+    By default, DocFinder will extract the following information from a Zope object:
+
+    - **Class** (and base class) names, and docstrings.
+
+    - **Attribute** names, roles, arguments, and docstrings.
+
+    DocFinder treats docstrings as structured text which allows you to put nicely formatted 
+    documentation right into the source files, while having it available at the click of a mouse.
+
+Controls
+
+    The information is presented in a tree. You can expand/collapse individual nodes by clicking the plus/minus icons.
+
+    To enjoy the full functionality of the controls you should have cookies and JavaScript enabled.
+
+    Filter
+
+        You can specify a regular expression that will be used to filter attribute names. 
+        Hit the return key to submit the form.
+
+        When a filter is set, clicking the blue X control will clear the filter string.
+
+    Expert
+
+        In expert mode DocFinder returns additional information of interest to the 
+        Python programmer. This includes:
+
+        - The **module** a class has been loaded from.
+
+        - The **private attributes** of a class, i.e. attributes not accessible from restricted (TTW) code.
+
+Permission Names
+
+    If you start Zope with 'ZOPE_SECURITY_POLICY' set to 'PYTHON', DocFinder will furthermore
+    return the names of **permissions** protecting the individual attributes.
+
+    If no permission name is available, DocFinder will indicate the presence of an
+    explicit security declaration for the respective attribute (expert mode only).
+
+Security
+
+    You can control access to the "Doc" tab via the "View documentation" permission.
+
+

Added: zope-docfindertab/branches/upstream/current/tests/README.txt
===================================================================
--- zope-docfindertab/branches/upstream/current/tests/README.txt	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/tests/README.txt	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,14 @@
+
+Tests for DocFinderTab
+
+The tests can be run either directly, e.g.
+
+  python testDocFinderTab.py
+
+or with the testrunner utility, e.g.
+
+  python /Zope/utilities/testrunner.py -qa
+
+Note that you must have the ZopeTestCase 
+package installed.
+

Added: zope-docfindertab/branches/upstream/current/tests/__init__.py
===================================================================
--- zope-docfindertab/branches/upstream/current/tests/__init__.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/tests/__init__.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1 @@
+"""DocFinderTab test package"""

Added: zope-docfindertab/branches/upstream/current/tests/framework.py
===================================================================
--- zope-docfindertab/branches/upstream/current/tests/framework.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/tests/framework.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,107 @@
+##############################################################################
+#
+# ZopeTestCase 
+#
+# COPY THIS FILE TO YOUR 'tests' DIRECTORY.
+#
+# This version of framework.py will use the SOFTWARE_HOME
+# environment variable to locate Zope and the Testing package.
+#
+# If the tests are run in an INSTANCE_HOME installation of Zope,
+# Products.__path__ and sys.path with be adjusted to include the
+# instance's Products and lib/python directories respectively.
+#
+# If you explicitly set INSTANCE_HOME prior to running the tests,
+# auto-detection is disabled and the specified path will be used 
+# instead.
+#
+# If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
+# will be adjusted to use it.
+#
+# If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup 
+# is assumed, and you can attach to a running ZEO server (via the 
+# instance's custom_zodb.py).
+#
+##############################################################################
+#
+# The following code should be at the top of every test module:
+#
+# import os, sys
+# if __name__ == '__main__':
+#     execfile(os.path.join(sys.path[0], 'framework.py'))
+#
+# ...and the following at the bottom:
+#
+# if __name__ == '__main__':
+#     framework()
+#
+##############################################################################
+
+__version__ = '0.2.3'
+
+# Save start state
+#
+__SOFTWARE_HOME = os.environ.get('SOFTWARE_HOME', '')
+__INSTANCE_HOME = os.environ.get('INSTANCE_HOME', '')
+
+if __SOFTWARE_HOME.endswith(os.sep):
+    __SOFTWARE_HOME = os.path.dirname(__SOFTWARE_HOME)
+
+if __INSTANCE_HOME.endswith(os.sep):
+    __INSTANCE_HOME = os.path.dirname(__INSTANCE_HOME)
+
+# Find and import the Testing package
+#
+if not sys.modules.has_key('Testing'):
+    p0 = sys.path[0]
+    if p0 and __name__ == '__main__':
+        os.chdir(p0)
+        p0 = ''
+    s = __SOFTWARE_HOME
+    p = d = s and s or os.getcwd()
+    while d:
+        if os.path.isdir(os.path.join(p, 'Testing')):
+            zope_home = os.path.dirname(os.path.dirname(p))
+            sys.path[:1] = [p0, p, zope_home]
+            break
+        p, d = s and ('','') or os.path.split(p)
+    else:
+        print 'Unable to locate Testing package.',
+        print 'You might need to set SOFTWARE_HOME.'
+        sys.exit(1)
+
+import Testing, unittest
+execfile(os.path.join(os.path.dirname(Testing.__file__), 'common.py'))
+
+# Include ZopeTestCase support
+#
+if 1:   # Create a new scope
+
+    p = os.path.join(os.path.dirname(Testing.__file__), 'ZopeTestCase')
+
+    if not os.path.isdir(p):
+        print 'Unable to locate ZopeTestCase package.',
+        print 'You might need to install ZopeTestCase.'
+        sys.exit(1)
+
+    ztc_common = 'ztc_common.py'
+    ztc_common_global = os.path.join(p, ztc_common)
+
+    f = 0
+    if os.path.exists(ztc_common_global):
+        execfile(ztc_common_global)
+        f = 1
+    if os.path.exists(ztc_common):
+        execfile(ztc_common)
+        f = 1
+
+    if not f:
+        print 'Unable to locate %s.' % ztc_common
+        sys.exit(1)
+
+# Debug
+#
+print 'SOFTWARE_HOME: %s' % os.environ.get('SOFTWARE_HOME', 'Not set')
+print 'INSTANCE_HOME: %s' % os.environ.get('INSTANCE_HOME', 'Not set')
+sys.stdout.flush()
+

Added: zope-docfindertab/branches/upstream/current/tests/testDocFinderTab.py
===================================================================
--- zope-docfindertab/branches/upstream/current/tests/testDocFinderTab.py	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/tests/testDocFinderTab.py	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1,116 @@
+#
+# Test DocFinderTab
+#
+
+import os, sys
+if __name__ == '__main__':
+    execfile(os.path.join(sys.path[0], 'framework.py'))
+
+from Testing import ZopeTestCase
+
+from AccessControl import Unauthorized
+from Products.DocFinderTab.Permissions import ViewDocPermission
+
+standard_permissions = ZopeTestCase.standard_permissions
+access_permissions   = [ViewDocPermission] 
+all_permissions      = standard_permissions+access_permissions
+
+ZopeTestCase.installProduct('DocFinderTab')
+
+
+class TestDocFinderTab(ZopeTestCase.ZopeTestCase):
+
+    def test_00_ItemPatched(self):
+        '''Item should have been patched'''
+        ob = getattr(self.app, 'aq_base', self.app)
+        self.failUnless(hasattr(ob, 'showDocumentation'))
+        self.failUnless(hasattr(ob, 'analyseDocumentation'))
+
+    def test_01_AccessAllowed(self):
+        'showDocumentation should be accessible'
+        self.setPermissions(standard_permissions+access_permissions)
+        try:
+            dummy = self.folder.restrictedTraverse('showDocumentation')
+        except Unauthorized:
+            self.fail('Access to showDocumentation was denied')
+            
+    def test_02_AccessDenied(self):
+        'showDocumentation should be protected'
+        self.setPermissions(standard_permissions)
+        try:
+            dummy = self.folder.restrictedTraverse('showDocumentation')
+        except Unauthorized:
+            pass
+        else:
+            self.fail('Access to showDocumentation was allowed')
+            
+    def test_03_ManagerAccessAllowed(self):
+        'showDocumentation should be accessible to Managers'
+        self.setRoles(['Manager'])
+        try:
+            dummy = self.folder.restrictedTraverse('showDocumentation')
+        except Unauthorized:
+            self.fail('Access to showDocumentation was denied to Manager')
+            
+    def test_04_ManagerAccessDenied(self):
+        'showDocumentation should be protected from Managers'
+        self.folder.manage_permission(ViewDocPermission, ['Owner'], acquire=0)
+        self.setRoles(['Manager'])
+        try:
+            dummy = self.folder.restrictedTraverse('showDocumentation')
+        except Unauthorized:
+            pass
+        else:
+            self.fail('Access to showDocumentation was allowed to Manager')
+            
+    def test_05_AccessAllowed(self):
+        'analyseDocumentation should be accessible'
+        self.setPermissions(standard_permissions+access_permissions)
+        try:
+            dummy = self.folder.restrictedTraverse('analyseDocumentation')
+        except Unauthorized:
+            self.fail('Access to analyseDocumentation was denied')
+            
+    def test_06_AccessDenied(self):
+        'analyseDocumentation should be protected'
+        self.setPermissions(standard_permissions)
+        try:
+            dummy = self.folder.restrictedTraverse('analyseDocumentation')
+        except Unauthorized:
+            pass
+        else:
+            self.fail('Access to analyseDocumentation was allowed')
+            
+    def test_07_ManagerAccessAllowed(self):
+        'analyseDocumentation should be accessible to Managers'
+        self.setRoles(['Manager'])
+        try:
+            dummy = self.folder.restrictedTraverse('analyseDocumentation')
+        except Unauthorized:
+            self.fail('Access to analyseDocumentation was denied to Manager')
+            
+    def test_08_ManagerAccessDenied(self):
+        'analyseDocumentation should be protected from Managers'
+        self.folder.manage_permission(ViewDocPermission, ['Owner'], acquire=0)
+        self.setRoles(['Manager'])
+        try:
+            dummy = self.folder.restrictedTraverse('analyseDocumentation')
+        except Unauthorized:
+            pass
+        else:
+            self.fail('Access to analyseDocumentation was allowed to Manager')
+            
+    # b/w compatibility clutch
+    if not hasattr(ZopeTestCase.ZopeTestCase, 'setPermissions'):
+        setPermissions = ZopeTestCase.ZopeTestCase._setPermissions
+        setRoles = ZopeTestCase.ZopeTestCase._setRoles
+
+            
+def test_suite():
+    from unittest import TestSuite, makeSuite
+    suite = TestSuite()
+    suite.addTest(makeSuite(TestDocFinderTab))
+    return suite
+
+if __name__ == '__main__':
+    framework()

Added: zope-docfindertab/branches/upstream/current/version.txt
===================================================================
--- zope-docfindertab/branches/upstream/current/version.txt	2006-11-28 09:16:26 UTC (rev 527)
+++ zope-docfindertab/branches/upstream/current/version.txt	2006-11-28 11:30:34 UTC (rev 528)
@@ -0,0 +1 @@
+0.5.0




More information about the pkg-zope-commits mailing list