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> </td>
+ <td &dtml.-td_args__; width="15%"><dtml-if Permission>&dtml-Permission;<br /></dtml-if><dtml-var Roles> </td>
+ <td &dtml.-td_args__; width="20%"><dtml-var Args> </td>
+ <td &dtml.-td_args__; width="40%"><dtml-var DocOrType fmt="structured-text">
+ <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> </td>
+ <td align=right class="std-text" width=1>
+ Filter <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> </td>
+ <td align=right class="std-text" width=1>
+ Expert <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> </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> </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> </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