[Zope-dev] A limited browser of sorts

Damian Morton morton@dennisinter.com
Sat, 4 Mar 2000 19:24:02 -0500


This is a multi-part message in MIME format.

------=_NextPart_000_0005_01BF860F.32AAA9A0
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

I had been wanting to see exactly what methods and attributes a given object
in a zope path would have access to. After buggering around with the monitor
for a while, I created an external method which does the job for me.

Put the file 'browse.py' into your Extensions directory,
Create a DTML method called 'viewself' (or whatever) in your Zope root
folder
Upload the file 'viewself.dtml' into your 'viewself' DTML method

You will now be able to get a listing of all attributes and methods for your
object by using the url:
http://yourzope/path/to/your/object/viewself


Bugs: I havent been able to get this line to work properly:
self.typestr = str(type(value))

the result of str(type(obj)) always sees to be an empty string, even though
comparing types seems to work. If anyone has any clues as to why this might
be, let me know.

------=_NextPart_000_0005_01BF860F.32AAA9A0
Content-Type: text/plain;
	name="browse.py"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="browse.py"

"""
    browse.py

    utility for use in the Zope monitor
    collects ALL the attributes and methods associated with an object =
through inheritance and acquisition

    usage in the monitor:
        import Zope
        app =3D Zope.app()
        import browse
        browse.ignore =3D ['OFS.ZDOM.*', 'webdav.*']
        browse.collect(app.Stuff)  # Stuff is an object of app
       =20
"""


import string
import pprint
import types

# you can put a list of classes to ignore here
# ignore =3D ['OFS.ZDOM.*', 'webdav.*']     =20
ignore =3D []

def isIgnored(name):
    """
        tests a given classname against a list of ignore cases
        use of the wildcard '*' is supported
        a trailing '*' on an ignore item matches any and all further =
terms
        e.g. 'a.b.*' matches 'a.b.c' and 'a.b.c.d.e.f.g'
    """
    name_parts =3D string.split(name, '.')
    for ig in ignore:
        ig_parts =3D string.split(ig, '.')
        matched =3D 1
        for i in range(0, min(len(name_parts), len(ig_parts))):
            ig_part =3D ig_parts[i]
            if (ig_part !=3D '*') and (ig_part !=3D name_parts[i]):
                matched =3D 0
                break
        if matched and not (len(ig_parts) > len(name_parts) and =
ig_parts[-1] !=3D '*'):
            return 1
    return 0

class Attribute:
    def __init__(self, name, value, path, src):
        self.name =3D name
        if type(value) =3D=3D types.InstanceType:
            self.typestr =3D value.__class__.__name__
        else:
            self.typestr =3D str(type(value))
        self.value =3D pprint.pformat(value)
        self.path =3D path
        self.src =3D src
   =20
def collect_dict(d, path, src, attrs):
    """
        collects into the dictionary 'attrs' all the items from the =
dictionary passed in
    """
    for k,v in d.items():
        if not attrs.has_key(k):
            attrs[k] =3D Attribute(k, v, path, src)

def collect_class(c, path, attrs, classes):
    """
        collects attributes from a class and recursively from its base =
classes
        maintains a list of visted classes; doesnt revisit classes
    """
    if hasattr(c, '__module__'):
        name =3D str(c.__module__) + '.' + str(c.__name__)
    else:
        name =3D str(c.__name__)
    if not (classes.has_key(name) or isIgnored(name)):=20
        classes[name] =3D 1
        collect_dict(c.__dict__, path, name, attrs)
        if hasattr(c, '__bases__'):
             for b in c.__bases__:
                 collect_class(b, path, attrs, classes)   =20

def collect_obj(obj, path, attrs, classes, aqobj):
    """
        collects attributes from an object and recursively from its =
aquisition path
        maintains a list of visted objects; doesnt revisit objects
    """
    if hasattr(obj, 'aq_self'):
        collect_obj(obj.aq_self, '/' + obj.__name__ + path, attrs, =
classes, aqobj)
        collect_obj(obj.aq_parent, '/' + obj.__name__ + path, attrs, =
classes, aqobj)
    elif not (obj in aqobj):
        aqobj.append(obj)
        collect_dict(obj.__dict__, path, 'self', attrs)
        if hasattr(obj, '__class__'):
            collect_class(obj.__class__, path, attrs, classes)
   =20
def collect(obj):
    """
        collects all the attributes and methods for an object in a =
context
        traverses inheritance and acquisition paths
    """
    attrs =3D {}
    collect_obj(obj, '', attrs, {}, [])
    items =3D attrs.items()
    items.sort()
    for k, v in items:
        print k, v

def viewObj(self):
    """
        collects all the attributes and methods for an object in a =
context
        traverses inheritance and acquisition paths
    """
    attrs =3D {}
    collect_obj(self.aq_parent, '', attrs, {}, [])
    return attrs.values()
------=_NextPart_000_0005_01BF860F.32AAA9A0
Content-Type: application/octet-stream;
	name="viewself.dtml"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="viewself.dtml"

<dtml-var standard_html_header>
<h2><dtml-var title_or_id></h2>
<table cols=4 width='100%'>
<dtml-in viewObj sort=name>
 <tr>
    <td><code><b><dtml-var name></b> (<dtml-var typestr>)</code></td>
    <td><code><dtml-var src>  :  <dtml-var path></code></td>
</tr>
 <tr>
    <td></td>
    <td><code><dtml-var value></code></td>
 <tr>
</dtml-in>
</table>
<dtml-var standard_html_footer>
------=_NextPart_000_0005_01BF860F.32AAA9A0--