2008-08-15 Mark Doffman <mark.doffman@codethink.co.uk>
authorMark Doffman <mdoff@silver-wind.(none)>
Fri, 15 Aug 2008 12:30:17 +0000 (13:30 +0100)
committerMark Doffman <mdoff@silver-wind.(none)>
Fri, 15 Aug 2008 12:30:17 +0000 (13:30 +0100)
* pyatspi/ tests/pyatspi
Changes to enable the most basic unit test of pyatspi
to work.

16 files changed:
pyatspi/__init__.py
pyatspi/accessible.py [deleted file]
pyatspi/base.py
pyatspi/cache.py
pyatspi/constants.py
pyatspi/desktop.py [deleted file]
pyatspi/factory.py
pyatspi/other.py
pyatspi/test.py [new file with mode: 0644]
pyatspi/utils.py
tests/apps/object-app.c
tests/apps/test-application.c
tests/pyatspi/accessibletest.py
tests/pyatspi/pasytest/Pasy.py
tests/pyatspi/setvars.sh
tests/pyatspi/testrunner.py

index 2b916c9..be6f0d5 100644 (file)
@@ -30,7 +30,29 @@ def clearCache():
 def printCache():
        print "Print cache function is deprecated";
 
 def printCache():
        print "Print cache function is deprecated";
 
+import other
+
+# Build a dictionary mapping state values to names based on the prefix of the
+# enum constants.
+STATE_VALUE_TO_NAME = dict(((value, name[6:].lower().replace('_', ' ')) 
+                            for name, value 
+                            in vars(other).items()
+                            if name.startswith('STATE_')))
+
+# Build a dictionary mapping relation values to names based on the prefix of 
+# the enum constants.
+RELATION_VALUE_TO_NAME = dict(((value, name[9:].lower().replace('_', ' ')) 
+                               for name, value 
+                               in vars(other).items()
+                               if name.startswith('RELATION_')))
+
+del other
+
 from constants import *
 from constants import *
+
+from base import *
 from other import *
 from other import *
-from accessible import *
+
+from test import *
+
 #from utils import *
 #from utils import *
diff --git a/pyatspi/accessible.py b/pyatspi/accessible.py
deleted file mode 100644 (file)
index 54be0cd..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-#Copyright (C) 2008 Codethink Ltd
-
-#This library is free software; you can redistribute it and/or
-#modify it under the terms of the GNU Lesser General Public
-#License version 2 as published by the Free Software Foundation.
-
-#This program is distributed in the hope that it will be useful,
-#but WITHOUT ANY WARRANTY; without even the implied warranty of
-#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#GNU General Public License for more details.
-#You should have received a copy of the GNU Lesser General Public License
-#along with this program; if not, write to the Free Software
-#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-from base import BaseProxy
-
-class Accessible(BaseProxy):
-    """
-    The base interface which is implemented by all accessible objects.
-    All objects support interfaces for querying their contained
-    'children' and position in the accessible-object hierarchy,
-    whether or not they actually have children.
-    """
-    
-    def getApplication(self, *args, **kwargs):
-        """
-        Get the containing Application for this object.
-        @return the Application instance to which this object belongs.
-        """
-        func = self.get_dbus_method("getApplication")
-        return func(*args, **kwargs)
-    
-    def getAttributes(self, *args, **kwargs):
-        """
-        Get a list of properties applied to this object as a whole, as
-        an AttributeSet consisting of name-value pairs. As such these
-        attributes may be considered weakly-typed properties or annotations,
-        as distinct from the strongly-typed interface instance data declared
-        using the IDL "attribute" keyword.
-        Not all objects have explicit "name-value pair" AttributeSet
-        properties.
-        Attribute names and values may have any UTF-8 string value, however
-        where possible, in order to facilitate consistent use and exposure
-        of "attribute" properties by applications and AT clients, attribute
-        names and values should chosen from a publicly-specified namespace
-        where appropriate.
-        Where possible, the names and values in the name-value pairs
-        should be chosen from well-established attribute namespaces using
-        standard semantics. For example, attributes of Accessible objects
-        corresponding to XHTML content elements should correspond to
-        attribute names and values specified in the w3c XHTML specification,
-        at http://www.w3.org/TR/xhtml2, where such values are not already
-        exposed via a more strongly-typed aspect of the AT-SPI API. Metadata
-        names and values should be chosen from the 'Dublin Core' Metadata
-        namespace using Dublin Core semantics: http://dublincore.org/dcregistry/
-        Similarly, relevant structural metadata should be exposed using
-        attribute names and values chosen from the CSS2 and WICD specification:
-        http://www.w3.org/TR/1998/REC-CSS2-19980512 WICD (http://www.w3.org/TR/2005/WD-WICD-20051121/).
-        @return : an AttributeSet encapsulating any "attribute values"
-        currently defined for the object.
-        """
-        func = self.get_dbus_method("getAttributes")
-        return func(*args, **kwargs)
-    
-    def getChildAtIndex(self, *args, **kwargs):
-        """
-        Get the accessible child of this object at index. 
-        @param : index
-        an in parameter indicating which child is requested (zero-indexed).
-        @return : the 'nth' Accessible child of this object.
-        """
-        func = self.get_dbus_method("getChildAtIndex")
-        return func(*args, **kwargs)
-    
-    def getIndexInParent(self, *args, **kwargs):
-        """
-        Get the index of this object in its parent's child list. 
-        @return : a long integer indicating this object's index in the
-        parent's list.
-        """
-        func = self.get_dbus_method("getIndexInParent")
-        return func(*args, **kwargs)
-    
-    def getLocalizedRoleName(self, *args, **kwargs):
-        """
-        Get a string indicating the type of UI role played by this object,
-        translated to the current locale.
-        @return : a UTF-8 string indicating the type of UI role played
-        by this object.
-        """
-        func = self.get_dbus_method("getLocalizedRoleName")
-        return func(*args, **kwargs)
-    
-    def getRelationSet(self, *args, **kwargs):
-        """
-        Get a set defining this object's relationship to other accessible
-        objects. 
-        @return : a RelationSet defining this object's relationships.
-        """
-        func = self.get_dbus_method("getRelationSet")
-        return func(*args, **kwargs)
-    
-    def getRole(self, *args, **kwargs):
-        """
-        Get the Role indicating the type of UI role played by this object.
-        @return : a Role indicating the type of UI role played by this
-        object.
-        """
-        func = self.get_dbus_method("getRole")
-        return func(*args, **kwargs)
-    
-    def getRoleName(self, *args, **kwargs):
-        """
-        Get a string indicating the type of UI role played by this object.
-        @return : a UTF-8 string indicating the type of UI role played
-        by this object.
-        """
-        func = self.get_dbus_method("getRoleName")
-        return func(*args, **kwargs)
-    
-    def getState(self, *args, **kwargs):
-        """
-        Get the current state of the object as a StateSet. 
-        @return : a StateSet encapsulating the currently true states
-        of the object.
-        """
-        func = self.get_dbus_method("getState")
-        return func(*args, **kwargs)
-    
-    def isEqual(self, *args, **kwargs):
-        """
-        Determine whether an Accessible refers to the same object as
-        another. This method should be used rather than brute-force comparison
-        of object references (i.e. "by-value" comparison), as two object
-        references may have different apparent values yet refer to the
-        same object.
-        @param : obj
-        an Accessible object reference to compare to 
-        @return : a boolean indicating whether the two object references
-        point to the same object.
-        """
-        func = self.get_dbus_method("isEqual")
-        return func(*args, **kwargs)
-    
-    def unimplemented(self, *args, **kwargs):
-        """
-        /cond future expansion
-        """
-        func = self.get_dbus_method("unimplemented")
-        return func(*args, **kwargs)
-    
-    def get_childCount(self):
-        self._pgetter(self._dbus_interface, "childCount")
-    def set_childCount(self, value):
-        self._psetter(self._dbus_interface, "childCount", value)
-    _childCountDoc = \
-        """
-        childCount: the number of children contained by this object.
-        """
-    childCount = property(fget=get_childCount, fset=set_childCount, doc=_childCountDoc)
-    
-    def get_description(self):
-        self._pgetter(self._dbus_interface, "description")
-    def set_description(self, value):
-        self._psetter(self._dbus_interface, "description", value)
-    _descriptionDoc = \
-        """
-        a string describing the object in more detail than name.
-        """
-    description = property(fget=get_description, fset=set_description, doc=_descriptionDoc)
-    
-    def get_name(self):
-        self._pgetter(self._dbus_interface, "name")
-    def set_name(self, value):
-        self._psetter(self._dbus_interface, "name", value)
-    _nameDoc = \
-        """
-        a (short) string representing the object's name.
-        """
-    name = property(fget=get_name, fset=set_name, doc=_nameDoc)
-    
-    def get_parent(self):
-        self._pgetter(self._dbus_interface, "parent")
-    def set_parent(self, value):
-        self._psetter(self._dbus_interface, "parent", value)
-    _parentDoc = \
-        """
-        an Accessible object which is this object's containing object.
-        """
-    parent = property(fget=get_parent, fset=set_parent, doc=_parentDoc)
index 0060ea0..8ff71d3 100644 (file)
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-from weakref import proxy
+import dbus as _dbus
+from dbus.proxies import Interface as _Interface
 
 
-from dbus.proxies import Interface, ProxyObject
 from dbus.exceptions import *
 from dbus.exceptions import *
+from factory import create_accessible, add_accessible_class
+
+import constants
 
 class AccessibleObjectNoLongerExists(Exception):
        pass
 
 #------------------------------------------------------------------------------
 
 
 class AccessibleObjectNoLongerExists(Exception):
        pass
 
 #------------------------------------------------------------------------------
 
-class Enum(int):
+class _Enum(int):
        def __str__(self):
                return self._enum_lookup(int(self))
 
 #------------------------------------------------------------------------------
 
        def __str__(self):
                return self._enum_lookup(int(self))
 
 #------------------------------------------------------------------------------
 
-class BaseProxy(Interface):
-       """
-       The base D-Bus proxy for a remote object that implements one or more
-       of the AT-SPI interfaces.
 
 
-       This class must be further specialised as the cache stores are different
-       for Desktop objects and other Accessible objects.
-       """
-       
-       def __new__(cls, *args, **kwargs):
-               Interface.__new__(cls, *args, **kwargs)
+class _BaseProxyMeta(type):
+       def __init__(cls, *args, **kwargs):
+               type.__init__(cls, *args, **kwargs)
 
                queryable_interfaces = { 
 
                queryable_interfaces = { 
-                       'Accessible':ATSPI_ACCESSIBLE,
-                       'Action':ATSPI_ACTION,
-                       'Application':ATSPI_APPLICATION,
-                       'Collection':ATSPI_COLLECTION,
-                       'Component':ATSPI_COMPONENT,
-                       'Desktop':ATSPI_DESKTOP,
-                       'Document':ATSPI_DOCUMENT,
-                       'EditableText':ATSPI_EDITABLE_TEXT,
-                       'Hypertext':ATSPI_HYPERTEXT,
-                       'Hyperlink':ATSPI_HYPERLINK,
-                       'Image':ATSPI_IMAGE,
-                       'Selection':ATSPI_SELECTION,
-                       'StreamableContent':ATSPI_STREAMABLE_CONTENT,
-                       'Table':ATSPI_TABLE,
-                       'Text':ATSPI_TEXT,
-                       'Value':ATSPI_VALUE,
+                       'Accessible':constants.ATSPI_ACCESSIBLE,
+                       'Action':constants.ATSPI_ACTION,
+                       'Application':constants.ATSPI_APPLICATION,
+                       'Collection':constants.ATSPI_COLLECTION,
+                       'Component':constants.ATSPI_COMPONENT,
+                       'Desktop':constants.ATSPI_DESKTOP,
+                       'Document':constants.ATSPI_DOCUMENT,
+                       'EditableText':constants.ATSPI_EDITABLE_TEXT,
+                       'Hypertext':constants.ATSPI_HYPERTEXT,
+                       'Hyperlink':constants.ATSPI_HYPERLINK,
+                       'Image':constants.ATSPI_IMAGE,
+                       'Selection':constants.ATSPI_SELECTION,
+                       'StreamableContent':constants.ATSPI_STREAMABLE_CONTENT,
+                       'Table':constants.ATSPI_TABLE,
+                       'Text':constants.ATSPI_TEXT,
+                       'Value':constants.ATSPI_VALUE,
                }
 
                for interface in queryable_interfaces.keys():
                }
 
                for interface in queryable_interfaces.keys():
@@ -65,61 +61,267 @@ class BaseProxy(Interface):
                                return self.queryInterface(object, queryable_interfaces[interface])
                        setattr(cls, name, new_query) 
 
                                return self.queryInterface(object, queryable_interfaces[interface])
                        setattr(cls, name, new_query) 
 
-       def __init__(self, obj, cache, path, interface):
+#------------------------------------------------------------------------------
+
+class _BaseProxy(_Interface):
+       """
+       The base D-Bus proxy for a remote object that implements one or more
+       of the AT-SPI interfaces.
+       """
+
+       __metaclass__ = _BaseProxyMeta
+
+       def __init__(self, cache, app_name, acc_path, parent, interface, dbus_object=None, connection=None):
                """
                Create a D-Bus Proxy for an ATSPI interface.
 
                """
                Create a D-Bus Proxy for an ATSPI interface.
 
-               obj - The D-Bus proxy object this interface uses for D-Bus calls.
-               cache - Cache storing data for this object.
-               path - The object path of the remote object.
-               interface - The name of the ATSPI interface that this proxy implements.
+               cache - ApplicationCache, where the cached data for the accessible can be obtained.
+               app_name - D-Bus bus name of the application this accessible belongs to.
+               acc_path - D-Bus object path of the server side accessible object.
+               parent - Parent accessible.
+               interface - D-Bus interface of the object. Used to decide which accessible class to instanciate.
+               dbus_object(kwarg) - The D-Bus proxy object used by the accessible for D-Bus method calls.
                """
                """
-               Interface.__init__(self, obj, interface)
+               self._cache = cache
+               self._app_name = app_name
+               self._acc_path = acc_path
+               self._parent = parent
 
 
-               self._cobj = ref(cache)
-               self._path = path
+               if not dbus_object:
+                       dbus_object = connection.get_object(self._app_name, self._acc_path, introspect=False)
+               self._dbus_object = dbus_object
+
+               _Interface.__init__(self, self._dbus_object, interface)
 
                self._pgetter = self.get_dbus_method("Get", dbus_interface="org.freedesktop.DBus.Properties")
                self._psetter = self.get_dbus_method("Set", dbus_interface="org.freedesktop.DBus.Properties")
 
        def __getattr__(self, *args, **kwargs):
 
                self._pgetter = self.get_dbus_method("Get", dbus_interface="org.freedesktop.DBus.Properties")
                self._psetter = self.get_dbus_method("Set", dbus_interface="org.freedesktop.DBus.Properties")
 
        def __getattr__(self, *args, **kwargs):
-               """
-               The __getattr__ function must return the D-Bus method wrapped in a
-               method to translate exceptions.
-               """
-               # Need to throw an AccessibleObjectNoLongerExists exception
-               # on D-Bus error of the same type.
-               try:
-                       return Interface.__getattr__(self, *args, **kwargs)
-               except UnknownMethodException, e:
-                       raise NotImplementedError(e)
-               except DBusException, e:
-                       raise LookupError(e)
+               method =  _Interface.__getattr__(self, *args, **kwargs)
 
 
-       @property
-       def _cache(self):
-               c = self._cobj()
-               if not c:
-                       raise AccessibleObjectNoLongerExits("Application has been removed")
+               def dbus_method_func(*args, **kwargs):
+                       # TODO Need to throw an AccessibleObjectNoLongerExists exception
+                       # on D-Bus error of the same type.
+                       try:
+                               method(*args, **kwargs)
+                       except UnknownMethodException, e:
+                               raise NotImplementedError(e)
+                       except DBusException, e:
+                               raise LookupError(e)
+
+               return dbus_method_func
 
        @property
 
        @property
-       def _data(self):
+       def cached_data(self):
                try:
                try:
-                       data = self._cache._objects[self._path]
+                       return self._cache[self._app_name][self._acc_path]
                except KeyError:
                except KeyError:
-                       raise AccessibleObjectNoLongerExists, 'Cache data cannot be found for path %s' % (self._path,)
-               return data
+                       raise AccessibleObjectNoLongerExists, \
+                               'Cache data cannot be found for path %s in app %s' % (self._acc_path, self._app_name)
 
        @property
        def interfaces(self):
                return self._data.interfaces
 
        def queryInterface(self, interface):
 
        @property
        def interfaces(self):
                return self._data.interfaces
 
        def queryInterface(self, interface):
+               """
+               Gets a different accessible interface for this object
+               or raises a NotImplemented error if the given interface
+               is not supported.
+               """
                if interface in self._data.interfaces:
                if interface in self._data.interfaces:
-                               return self._cache.proxyFactory(self._path, interface, dbus_obj=self._obj)
+                       return create_accessible(self._cache,
+                                                self._app_name,
+                                                self._acc_path,
+                                                self._parent,
+                                                interface,
+                                                dbus_object=self._dbus_object)
                else:
                        raise NotImplementedError(
                                "%s not supported by accessible object at path %s"
                                % (interface, self.path))
 
                else:
                        raise NotImplementedError(
                                "%s not supported by accessible object at path %s"
                                % (interface, self.path))
 
+#------------------------------------------------------------------------------
+
+class Accessible(_BaseProxy):
+    """
+    The base interface which is implemented by all accessible objects.
+    All objects support interfaces for querying their contained
+    'children' and position in the accessible-object hierarchy,
+    whether or not they actually have children.
+    """
+    
+    def getApplication(self):
+        """
+        Get the containing Application for this object.
+        @return the Application instance to which this object belongs.
+        """
+       application_root = self._cache.get_application_root(self._app_name)
+       return create_accessible(self._cache,
+                                self._app_name,
+                                application_root,
+                                constants.NULL_BUS_NAME,
+                                constants.NULL_OBJECT_PATH,
+                                constants.ATSPI_ACCESSIBLE,
+                                dbus_object=self._dbus_object)
+    
+    def getAttributes(self, *args, **kwargs):
+        """
+        Get a list of properties applied to this object as a whole, as
+        an AttributeSet consisting of name-value pairs. As such these
+        attributes may be considered weakly-typed properties or annotations,
+        as distinct from the strongly-typed interface instance data declared
+        using the IDL "attribute" keyword.
+        Not all objects have explicit "name-value pair" AttributeSet
+        properties.
+        Attribute names and values may have any UTF-8 string value, however
+        where possible, in order to facilitate consistent use and exposure
+        of "attribute" properties by applications and AT clients, attribute
+        names and values should chosen from a publicly-specified namespace
+        where appropriate.
+        Where possible, the names and values in the name-value pairs
+        should be chosen from well-established attribute namespaces using
+        standard semantics. For example, attributes of Accessible objects
+        corresponding to XHTML content elements should correspond to
+        attribute names and values specified in the w3c XHTML specification,
+        at http://www.w3.org/TR/xhtml2, where such values are not already
+        exposed via a more strongly-typed aspect of the AT-SPI API. Metadata
+        names and values should be chosen from the 'Dublin Core' Metadata
+        namespace using Dublin Core semantics: http://dublincore.org/dcregistry/
+        Similarly, relevant structural metadata should be exposed using
+        attribute names and values chosen from the CSS2 and WICD specification:
+        http://www.w3.org/TR/1998/REC-CSS2-19980512 WICD (http://www.w3.org/TR/2005/WD-WICD-20051121/).
+        @return : an AttributeSet encapsulating any "attribute values"
+        currently defined for the object.
+        """
+        func = self.get_dbus_method("getAttributes")
+        return func(*args, **kwargs)
+    
+    def getChildAtIndex(self, index):
+        """
+        Get the accessible child of this object at index. 
+        @param : index
+        an in parameter indicating which child is requested (zero-indexed).
+        @return : the 'nth' Accessible child of this object.
+        """
+       path = self.cached_data.children[index]
+       return create_accessible(self._cache,
+                                self._app_name,
+                                path,
+                                self,
+                                constants.ATSPI_ACCESSIBLE,
+                                dbus_object=self._dbus_object)
+    
+    def getIndexInParent(self, *args, **kwargs):
+        """
+        Get the index of this object in its parent's child list. 
+        @return : a long integer indicating this object's index in the
+        parent's list.
+        """
+        func = self.get_dbus_method("getIndexInParent")
+        return func(*args, **kwargs)
+    
+    def getLocalizedRoleName(self, *args, **kwargs):
+        """
+        Get a string indicating the type of UI role played by this object,
+        translated to the current locale.
+        @return : a UTF-8 string indicating the type of UI role played
+        by this object.
+        """
+        func = self.get_dbus_method("getLocalizedRoleName")
+        return func(*args, **kwargs)
+    
+    def getRelationSet(self, *args, **kwargs):
+        """
+        Get a set defining this object's relationship to other accessible
+        objects. 
+        @return : a RelationSet defining this object's relationships.
+        """
+        func = self.get_dbus_method("getRelationSet")
+        return func(*args, **kwargs)
+    
+    def getRole(self):
+        """
+        Get the Role indicating the type of UI role played by this object.
+        @return : a Role indicating the type of UI role played by this
+        object.
+        """
+        return self.cached_data.role
+    
+    def getRoleName(self, *args, **kwargs):
+        """
+        Get a string indicating the type of UI role played by this object.
+        @return : a UTF-8 string indicating the type of UI role played
+        by this object.
+        """
+        func = self.get_dbus_method("getRoleName")
+        return func(*args, **kwargs)
+    
+    def getState(self, *args, **kwargs):
+        """
+        Get the current state of the object as a StateSet. 
+        @return : a StateSet encapsulating the currently true states
+        of the object.
+        """
+        func = self.get_dbus_method("getState")
+        return func(*args, **kwargs)
+    
+    def isEqual(self, accessible):
+        """
+        Determine whether an Accessible refers to the same object as
+        another. This method should be used rather than brute-force comparison
+        of object references (i.e. "by-value" comparison), as two object
+        references may have different apparent values yet refer to the
+        same object.
+        @param : obj
+        an Accessible object reference to compare to 
+        @return : a boolean indicating whether the two object references
+        point to the same object.
+        """
+        return  (self._app_name == accessible._app_name) and \
+               (self._acc_path == accessible._acc_path)        
+    
+    def unimplemented(self, *args, **kwargs):
+        """
+        /cond future expansion
+        """
+        func = self.get_dbus_method("unimplemented")
+        return func(*args, **kwargs)
+    
+    def get_childCount(self):
+        return len(self.cached_data.children)
+    _childCountDoc = \
+        """
+        childCount: the number of children contained by this object.
+        """
+    childCount = property(fget=get_childCount, doc=_childCountDoc)
+    
+    def get_description(self):
+        return self.cached_data.description
+    _descriptionDoc = \
+        """
+        a string describing the object in more detail than name.
+        """
+    description = property(fget=get_description, doc=_descriptionDoc)
+    
+    def get_name(self):
+        return self.cached_data.name
+    _nameDoc = \
+        """
+        a (short) string representing the object's name.
+        """
+    name = property(fget=get_name, doc=_nameDoc)
+    
+    def get_parent(self):
+       # The parent attribute is part of the base proxy
+       return self._parent
+    _parentDoc = \
+        """
+        an Accessible object which is this object's containing object.
+        """
+    parent = property(fget=get_parent, doc=_parentDoc)
+
+# ATTENTION - Register the Accessible class with the accessible factory.
+add_accessible_class(constants.ATSPI_ACCESSIBLE, Accessible)
+
 #END----------------------------------------------------------------------------
 #END----------------------------------------------------------------------------
index 14c959a..8b11645 100644 (file)
@@ -12,8 +12,7 @@
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-from base import AccessibleObjectNoLongerExists
-from factory import interfaceFactory
+import dbus as _dbus
 
 #------------------------------------------------------------------------------
 
 
 #------------------------------------------------------------------------------
 
@@ -42,13 +41,7 @@ class _CacheData(object):
 
 #------------------------------------------------------------------------------
 
 
 #------------------------------------------------------------------------------
 
-class BaseCache(object):
-       """
-       Base object for the Desktop, Accessible and Application caches.
-
-       Abstracts common initialization.
-       """
-
+class _BaseCache(object):
 
        def __init__(self, connection, bus_name):
                """
 
        def __init__(self, connection, bus_name):
                """
@@ -60,22 +53,28 @@ class BaseCache(object):
                self._connection = connection
                self._bus_name = bus_name
 
                self._connection = connection
                self._bus_name = bus_name
 
-               obj = connection.get_object(bus_name, self._PATH)
-               itf = dbus.Interface(obj, self._INTERFACE)
+               obj = connection.get_object(bus_name, self._PATH, introspect=False)
+               itf = _dbus.Interface(obj, self._INTERFACE)
 
                self._objects = {}
 
 
                self._objects = {}
 
-               getMethod = itf.get_dbus_method(self._GET_METHOD)
-               self._updateObjects(getMethod)
+               get_method = itf.get_dbus_method(self._GET_METHOD)
+               self._update_objects(get_method())
 
 
-               self._signalMatch = itf.connect_to_signal(self._UPDATE_SIGNAL, self._updateHandler)
+               self._signalMatch = itf.connect_to_signal(self._UPDATE_SIGNAL, self._update_handler)
 
 
-       def _updateHandler(self, updates):
+       def __getitem__(self, key):
+               return self._objects[key]
+
+       def __contains__(self, key):
+               return key in self._objects
+
+       def _update_handler(self, updates):
                update, remove = updates
                update, remove = updates
-               self._removeObjects(update)
-               self._updateObjects(remove)
+               self._remove_objects(update)
+               self._update_objects(remove)
 
 
-       def _updateObjects(self, objects):
+       def _update_objects(self, objects):
                for data in objects:
                        #First element is the object path.
                        path = data[0]
                for data in objects:
                        #First element is the object path.
                        path = data[0]
@@ -85,30 +84,14 @@ class BaseCache(object):
                        else:
                                self._objects[path] = _CacheData(data)
 
                        else:
                                self._objects[path] = _CacheData(data)
 
-       def _removeObjects(self, paths):
+       def _remove_objects(self, paths):
                for path in paths:
                        del(self._objects[path])
 
 
                for path in paths:
                        del(self._objects[path])
 
 
-       def getAccessible(self, path, interface, dbus_object=None):
-               """
-               Gets a client side proxy for the accessible object found
-               at the path.
-
-               path - The D-Bus path of the remote object.
-               interface - The interface that the accessible object should support.
-               dbus_object=None - The D-Bus proxy object backing this interface.
-               """
-               if path in self._objects:
-                       if not dbus_object:
-                               dbus_object = self._connection.get_object(self._bus_name, path, introspect=False)
-                       return interfaceFactory(proxy, self, path, interface)
-               else:
-                       raise AccessibleObjectNoLongerExists, "D-Bus reference not found in cache"
-
 #------------------------------------------------------------------------------
 
 #------------------------------------------------------------------------------
 
-class AccessibleCache(BaseCache):
+class AccessibleCache(_BaseCache):
        """
        There is one accessible cache per application.
        For each application the accessible cache stores
        """
        There is one accessible cache per application.
        For each application the accessible cache stores
@@ -116,6 +99,9 @@ class AccessibleCache(BaseCache):
 
        It also acts as the factory for creating client
        side proxies for these accessible objects.
 
        It also acts as the factory for creating client
        side proxies for these accessible objects.
+               
+       connection - DBus connection.
+       busName    - Name of DBus connection where cache interface resides.
        """
 
        _PATH = '/org/freedesktop/atspi/tree'
        """
 
        _PATH = '/org/freedesktop/atspi/tree'
@@ -124,73 +110,16 @@ class AccessibleCache(BaseCache):
        _UPDATE_SIGNAL = 'updateTree'
 
        def __init__(self, connection, bus_name):
        _UPDATE_SIGNAL = 'updateTree'
 
        def __init__(self, connection, bus_name):
-               BaseCache.__init__(self, connection, bus_name)
+               _BaseCache.__init__(self, connection, bus_name)
 
 
-               obj = connection.get_object(_self.bus_name, self._PATH)
-               itf = dbus.Interface(obj, self._INTERFACE)
+               obj = connection.get_object(self._bus_name, self._PATH, introspect=False)
+               itf = _dbus.Interface(obj, self._INTERFACE)
 
                self._root = itf.getRoot()
 
 
                self._root = itf.getRoot()
 
-       def getRootAccessible(self):
-               """
-               Gets the accessible object at the root of the tree.
-               """
-               return self.getAccessible(self._root)
-
-#------------------------------------------------------------------------------
-
-class DesktopCache(BaseCache):
-       """
-       Cache of desktop objects obtained from the registry.
-
-       The desktop interface on the registry object is the
-       same as that of the general tree interface on the
-       applications.
-
-       The difference is that the children data refers to
-       bus names of the applications rather than the object
-       paths of particular accessible objects within an application.
-       """
-
-       _PATH = '/org/freedesktop/atspi/registry'
-       _INTERFACE = 'org.freedesktop.atspi.Registry'
-       _GET_METHOD = 'getDesktops'
-       _UPDATE_SIGNAL = 'updateDesktops'
-       
-       def __init__(self, connection, bus_name):
-               self._app_cache = ApplicationCache(connection, bus_name)
-
-       def getApplication(self, name):
-               try:
-                       self._app_cache[name].getRootAccessible()
-               except KeyError:
-                       raise AccessibleObjectNoLongerExists("Application no longer exists")
-
-#------------------------------------------------------------------------------
-
-class ApplicationCache(object):
-       """
-       Holds a mapping of bus names of each accessible application
-       to the applications accessible cache.
-
-       Makes calls and recieves updates from the registry
-       daemon to keep the cache up to date.
-       """
+       def _get_root(self):
+               return self._root
 
 
-       _PATH = '/org/freedesktop/atspi/registry'
-       _INTERFACE = 'org.freedesktop.atspi.Registry'
-       _GET_METHOD = 'getApplications'
-       _UPDATE_SIGNAL = 'updateApplications'
-
-       def _updateApplications(self, names):
-               for name in names:
-                       if name not in self._applications:
-                               self._applications[name] = AccessibleCache(self._connection,
-                                                                       self._busName,
-                                                                       self._treePath)
-
-       def _removeApplications(self, names):
-               for name in names:
-                       del(self._applications[name])
+       root = property(fget=_get_root)
 
 #END---------------------------------------------------------------------------
 
 #END---------------------------------------------------------------------------
index ccef0fb..f4c41b2 100644 (file)
@@ -139,20 +139,21 @@ EVENT_TREE = {
     ['focus:']
 }
 
     ['focus:']
 }
 
-import other
-
-# Build a dictionary mapping state values to names based on the prefix of the
-# enum constants.
-STATE_VALUE_TO_NAME = dict(((value, name[6:].lower().replace('_', ' ')) 
-                            for name, value 
-                            in vars(other).items()
-                            if name.startswith('STATE_')))
-
-# Build a dictionary mapping relation values to names based on the prefix of 
-# the enum constants.
-RELATION_VALUE_TO_NAME = dict(((value, name[9:].lower().replace('_', ' ')) 
-                               for name, value 
-                               in vars(other).items()
-                               if name.startswith('RELATION_')))
-
-del other
+ATSPI_ACCESSIBLE = 'org.freedesktop.atspi.Accessible'
+ATSPI_ACTION = 'org.freedesktop.atspi.Action'
+ATSPI_APPLICATION = 'org.freedesktop.atspi.Application'
+ATSPI_COMPONENT = 'org.freedesktop.atspi.Component'
+ATSPI_COLLECTION = 'org.freedesktop.atspi.Collection'
+ATSPI_DESKTOP = 'org.freedesktop.atspi.Desktop'
+ATSPI_DOCUMENT = 'org.freedesktop.atspi.Document'
+ATSPI_EDITABLE_TEXT = 'org.freedesktop.atspi.EditableText'
+ATSPI_HYPERLINK = 'org.freedesktop.atspi.Hyperlink'
+ATSPI_HYPERTEXT = 'org.freedesktop.atspi.Hypertext'
+ATSPI_IMAGE = 'org.freedesktop.atspi.Image'
+ATSPI_LOGIN_HELPER = 'org.freedesktop.atspi.LoginHelper'
+ATSPI_SELECTION = 'org.freedesktop.atspi.Selection'
+ATSPI_SELECTOR = 'org.freedesktop.atspi.Selector'
+ATSPI_STREAMABLE_CONTENT = 'org.freedesktop.atspi.Content'
+ATSPI_TABLE = 'org.freedesktop.atspi.Table'
+ATSPI_TEXT = 'org.freedesktop.atspi.Text'
+ATSPI_VALUE = 'org.freedesktop.atspi.Value'
diff --git a/pyatspi/desktop.py b/pyatspi/desktop.py
deleted file mode 100644 (file)
index df26d7f..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-#Copyright (C) 2008 Codethink Ltd
-
-#This library is free software; you can redistribute it and/or
-#modify it under the terms of the GNU Lesser General Public
-#License version 2 as published by the Free Software Foundation.
-
-#This program is distributed in the hope that it will be useful,
-#but WITHOUT ANY WARRANTY; without even the implied warranty of
-#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#GNU General Public License for more details.
-#You should have received a copy of the GNU Lesser General Public License
-#along with this program; if not, write to the Free Software
-#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-from base import BaseProxy
-
-from accessible import Accessible
-
-class Desktop(Accessible):
-    """
-    The desktop class implements the 
-    accessible interface, but uses a different
-    method to access its chilren and to obtain cached
-    data. 
-
-    This is because application caches are separate
-    and the children of the desktop are applications.
-    The child access must get the root accessible
-    of the application cache that is accessed.
-
-    The data is accessed from the desktop cache.
-    """
-
-       @property
-       def _data(self):
-               try:
-                       data = self._cache._objects[self._path]
-               except KeyError, ReferenceError:
-                       raise AccessibleObjectNoLongerExists, 'Cache data cannot be found for path %s' % (self._path,)
-               return data
-    
-    def getApplication(self, *args, **kwargs):
-        """
-        Get the containing Application for this object.
-        @return the Application instance to which this object belongs.
-        """
-        func = self.get_dbus_method("getApplication")
-        return func(*args, **kwargs)
-    
-    def getAttributes(self, *args, **kwargs):
-        """
-        Get a list of properties applied to this object as a whole, as
-        an AttributeSet consisting of name-value pairs. As such these
-        attributes may be considered weakly-typed properties or annotations,
-        as distinct from the strongly-typed interface instance data declared
-        using the IDL "attribute" keyword.
-        Not all objects have explicit "name-value pair" AttributeSet
-        properties.
-        Attribute names and values may have any UTF-8 string value, however
-        where possible, in order to facilitate consistent use and exposure
-        of "attribute" properties by applications and AT clients, attribute
-        names and values should chosen from a publicly-specified namespace
-        where appropriate.
-        Where possible, the names and values in the name-value pairs
-        should be chosen from well-established attribute namespaces using
-        standard semantics. For example, attributes of Accessible objects
-        corresponding to XHTML content elements should correspond to
-        attribute names and values specified in the w3c XHTML specification,
-        at http://www.w3.org/TR/xhtml2, where such values are not already
-        exposed via a more strongly-typed aspect of the AT-SPI API. Metadata
-        names and values should be chosen from the 'Dublin Core' Metadata
-        namespace using Dublin Core semantics: http://dublincore.org/dcregistry/
-        Similarly, relevant structural metadata should be exposed using
-        attribute names and values chosen from the CSS2 and WICD specification:
-        http://www.w3.org/TR/1998/REC-CSS2-19980512 WICD (http://www.w3.org/TR/2005/WD-WICD-20051121/).
-        @return : an AttributeSet encapsulating any "attribute values"
-        currently defined for the object.
-        """
-        func = self.get_dbus_method("getAttributes")
-        return func(*args, **kwargs)
-    
-    def getChildAtIndex(self, *args, **kwargs):
-        """
-        Get the accessible child of this object at index. 
-        @param : index
-        an in parameter indicating which child is requested (zero-indexed).
-        @return : the 'nth' Accessible child of this object.
-        """
-        func = self.get_dbus_method("getChildAtIndex")
-        return func(*args, **kwargs)
-    
-    def getIndexInParent(self, *args, **kwargs):
-        """
-        Get the index of this object in its parent's child list. 
-        @return : a long integer indicating this object's index in the
-        parent's list.
-        """
-        func = self.get_dbus_method("getIndexInParent")
-        return func(*args, **kwargs)
-    
-    def getLocalizedRoleName(self, *args, **kwargs):
-        """
-        Get a string indicating the type of UI role played by this object,
-        translated to the current locale.
-        @return : a UTF-8 string indicating the type of UI role played
-        by this object.
-        """
-        func = self.get_dbus_method("getLocalizedRoleName")
-        return func(*args, **kwargs)
-    
-    def getRelationSet(self, *args, **kwargs):
-        """
-        Get a set defining this object's relationship to other accessible
-        objects. 
-        @return : a RelationSet defining this object's relationships.
-        """
-        func = self.get_dbus_method("getRelationSet")
-        return func(*args, **kwargs)
-    
-    def getRole(self, *args, **kwargs):
-        """
-        Get the Role indicating the type of UI role played by this object.
-        @return : a Role indicating the type of UI role played by this
-        object.
-        """
-        func = self.get_dbus_method("getRole")
-        return func(*args, **kwargs)
-    
-    def getRoleName(self, *args, **kwargs):
-        """
-        Get a string indicating the type of UI role played by this object.
-        @return : a UTF-8 string indicating the type of UI role played
-        by this object.
-        """
-        func = self.get_dbus_method("getRoleName")
-        return func(*args, **kwargs)
-    
-    def getState(self, *args, **kwargs):
-        """
-        Get the current state of the object as a StateSet. 
-        @return : a StateSet encapsulating the currently true states
-        of the object.
-        """
-        func = self.get_dbus_method("getState")
-        return func(*args, **kwargs)
-    
-    def isEqual(self, *args, **kwargs):
-        """
-        Determine whether an Accessible refers to the same object as
-        another. This method should be used rather than brute-force comparison
-        of object references (i.e. "by-value" comparison), as two object
-        references may have different apparent values yet refer to the
-        same object.
-        @param : obj
-        an Accessible object reference to compare to 
-        @return : a boolean indicating whether the two object references
-        point to the same object.
-        """
-        func = self.get_dbus_method("isEqual")
-        return func(*args, **kwargs)
-    
-    def unimplemented(self, *args, **kwargs):
-        """
-        /cond future expansion
-        """
-        func = self.get_dbus_method("unimplemented")
-        return func(*args, **kwargs)
-    
-    def get_childCount(self):
-        self._pgetter(self._dbus_interface, "childCount")
-    def set_childCount(self, value):
-        self._psetter(self._dbus_interface, "childCount", value)
-    _childCountDoc = \
-        """
-        childCount: the number of children contained by this object.
-        """
-    childCount = property(fget=get_childCount, fset=set_childCount, doc=_childCountDoc)
-    
-    def get_description(self):
-        self._pgetter(self._dbus_interface, "description")
-    def set_description(self, value):
-        self._psetter(self._dbus_interface, "description", value)
-    _descriptionDoc = \
-        """
-        a string describing the object in more detail than name.
-        """
-    description = property(fget=get_description, fset=set_description, doc=_descriptionDoc)
-    
-    def get_name(self):
-        self._pgetter(self._dbus_interface, "name")
-    def set_name(self, value):
-        self._psetter(self._dbus_interface, "name", value)
-    _nameDoc = \
-        """
-        a (short) string representing the object's name.
-        """
-    name = property(fget=get_name, fset=set_name, doc=_nameDoc)
-    
-    def get_parent(self):
-        self._pgetter(self._dbus_interface, "parent")
-    def set_parent(self, value):
-        self._psetter(self._dbus_interface, "parent", value)
-    _parentDoc = \
-        """
-        an Accessible object which is this object's containing object.
-        """
-    parent = property(fget=get_parent, fset=set_parent, doc=_parentDoc)
index dfb33bd..4227a24 100644 (file)
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-from base import *
-from accessible import *
+#------------------------------------------------------------------------------
 
 
-ATSPI_ACCESSIBLE = 'org.freedesktop.atspi.Accessible'
-ATSPI_ACTION = 'org.freedesktop.atspi.Action'
-ATSPI_APPLICATION = 'org.freedesktop.atspi.Application'
-ATSPI_COMPONENT = 'org.freedesktop.atspi.Component'
-ATSPI_DOCUMENT = 'org.freedesktop.atspi.Document'
-ATSPI_EDITABLE_TEXT = 'org.freedesktop.atspi.EditableText'
-ATSPI_HYPERLINK = 'org.freedesktop.atspi.Hyperlink'
-ATSPI_HYPERTEXT = 'org.freedesktop.atspi.Hypertext'
-ATSPI_IMAGE = 'org.freedesktop.atspi.Image'
-ATSPI_LOGIN_HELPER = 'org.freedesktop.atspi.LoginHelper'
-ATSPI_SELECTION = 'org.freedesktop.atspi.Selection'
-ATSPI_SELECTOR = 'org.freedesktop.atspi.Selector'
-ATSPI_STREAMABLE_CONTENT = 'org.freedesktop.atspi.Content'
-ATSPI_TABLE = 'org.freedesktop.atspi.Table'
-ATSPI_TEXT = 'org.freedesktop.atspi.Text'
-ATSPI_VALUE = 'org.freedesktop.atspi.Value'
+class AccessibleFactory(object):
+       __accessible_interfaces = {}
 
 
-#------------------------------------------------------------------------------
+       def create_accessible(self, cache, app_name, acc_path, parent, interface, dbus_object=None, connection=None):
+               class_ = self.__accessible_interfaces[interface]
+               return class_(cache,
+                             app_name,
+                             acc_path,
+                             parent,
+                             interface,
+                             dbus_object=dbus_object,
+                             connection=connection)
+
+       def add_accessible_class(self, name, cls):
+               self.__accessible_interfaces[name] = cls
 
 
-_interfaces = {
-               ATSPI_ACCESSIBLE:Accessible,
-               #ATSPI_ACTION:
-               #ATSPI_APPLICATION:
-               #ATSPI_COMPONENT:
-               #ATSPI_DOCUMENT:
-               #ATSPI_EDITABLE_TEXT:
-               #ATSPI_HYPERLINK:
-               #ATSPI_HYPERTEXT:
-               #ATSPI_IMAGE:
-               #ATSPI_LOGIN_HELPER:
-               #ATSPI_SELECTION:
-               #ATSPI_SELECTOR:
-               #ATSPI_STREAMABLE_CONTENT:
-               #ATSPI_TABLE:
-               #ATSPI_TEXT:
-               #ATSPI_TREE:
-               #ATSPI_VALUE:
-}
+_factory = AccessibleFactory()
 
 
-def interfaceFactory(self, busobject, cache, app, path, interface):
+def create_accessible(cache, app_name, acc_path, parent, interface, dbus_object=None, connection=None):
        """
        """
-       The queryInterfaces method needs to return
-       different atspi interfaces depending on the interface name.
-       This class registers names and ATSPI interface
-       classes to perform this task.
+       Used to create different python classes for each of the accessible interfaces.
+
+       The decision on which class to create is based on the name of the
+       accessible interface.
+
+       cache - ApplicationCache, where the cached data for the accessible can be obtained.
+       app_name - D-Bus bus name of the application this accessible belongs to.
+       acc_path - D-Bus object path of the server side accessible object.
+       app_parent - D-Bus bus name of the parent objects application.
+       acc_parent - D-Bus object path of the parent accessible.
+       interface - D-Bus interface of the object. Used to decide which accessible class to instanciate.
+       dbus_object(kwarg) - The D-Bus proxy object used by the accessible for D-Bus method calls.
+       connection(kwarg) - Client side D-Bus connection, provided if no D-Bus proxy is available.
        """
        """
-       return _interfaces[interface](object, cache, app, path, interface)
+       return _factory.create_accessible(cache,
+                                         app_name,
+                                         acc_path,
+                                         parent,
+                                         interface,
+                                         dbus_object=dbus_object,
+                                         connection=connection)
+
+def add_accessible_class(name, cls):
+       _factory.add_accessible_class(name, cls)
 
 #END----------------------------------------------------------------------------
 
 #END----------------------------------------------------------------------------
index 61a82e6..46dbcac 100644 (file)
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-from base import *
-from accessible import *
+from base import _BaseProxy, _Enum
+from base import Accessible as _Accessible
 
 
-class Action(BaseProxy):
+class Action(_BaseProxy):
     
     
     """
     
     
     """
@@ -108,7 +108,7 @@ class Action(BaseProxy):
     nActions = property(fget=get_nActions, fset=set_nActions, doc=_nActionsDoc)
 
 
     nActions = property(fget=get_nActions, fset=set_nActions, doc=_nActionsDoc)
 
 
-class Application(Accessible):
+class Application(_Accessible):
     
     
     """
     
     
     """
@@ -250,7 +250,7 @@ class BoundingBox(list):
     height = property(fget=_get_height, fset=_set_height)
 
 
     height = property(fget=_get_height, fset=_set_height)
 
 
-class Collection(BaseProxy):
+class Collection(_BaseProxy):
     
     def createMatchRule(self, *args, **kwargs):
         func = self.get_dbus_method("createMatchRule")
     
     def createMatchRule(self, *args, **kwargs):
         func = self.get_dbus_method("createMatchRule")
@@ -296,7 +296,7 @@ class Collection(BaseProxy):
         func = self.get_dbus_method("unImplemented4")
         return func(*args, **kwargs)
 
         func = self.get_dbus_method("unImplemented4")
         return func(*args, **kwargs)
 
-    class MatchType(Enum):
+    class MatchType(_Enum):
         _enum_lookup = {
             0:'MATCH_INVALID',
             1:'MATCH_ALL',
         _enum_lookup = {
             0:'MATCH_INVALID',
             1:'MATCH_ALL',
@@ -318,7 +318,7 @@ class Collection(BaseProxy):
     
     MATCH_NONE = MatchType(3)
 
     
     MATCH_NONE = MatchType(3)
 
-    class SortOrder(Enum):
+    class SortOrder(_Enum):
         _enum_lookup = {
             0:'SORT_ORDER_INVALID',
             1:'SORT_ORDER_CANONICAL',
         _enum_lookup = {
             0:'SORT_ORDER_INVALID',
             1:'SORT_ORDER_CANONICAL',
@@ -346,7 +346,7 @@ class Collection(BaseProxy):
     
     SORT_ORDER_TAB = SortOrder(3)
 
     
     SORT_ORDER_TAB = SortOrder(3)
 
-    class TreeTraversalType(Enum):
+    class TreeTraversalType(_Enum):
         _enum_lookup = {
             0:'TREE_RESTRICT_CHILDREN',
             1:'TREE_RESTRICT_SIBLING',
         _enum_lookup = {
             0:'TREE_RESTRICT_CHILDREN',
             1:'TREE_RESTRICT_SIBLING',
@@ -379,7 +379,7 @@ class Command(list):
         self[1] = val
     id = property(fget=_get_id, fset=_set_id)
 
         self[1] = val
     id = property(fget=_get_id, fset=_set_id)
 
-class CommandListener(BaseProxy):
+class CommandListener(_BaseProxy):
     """
     An interface which should be implemented by assistive technologies
     or other clients of the Selector interface, over which notifications
     """
     An interface which should be implemented by assistive technologies
     or other clients of the Selector interface, over which notifications
@@ -400,7 +400,7 @@ class CommandListener(BaseProxy):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class Component(BaseProxy):
+class Component(_BaseProxy):
     
     
     """
     
     
     """
@@ -537,7 +537,7 @@ class Component(BaseProxy):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class ComponentLayer(Enum):
+class ComponentLayer(_Enum):
     _enum_lookup = {
         0:'LAYER_INVALID',
         1:'LAYER_BACKGROUND',
     _enum_lookup = {
         0:'LAYER_INVALID',
         1:'LAYER_BACKGROUND',
@@ -551,7 +551,7 @@ class ComponentLayer(Enum):
     }
 
 
     }
 
 
-class ContentStream(BaseProxy):
+class ContentStream(_BaseProxy):
     """
     An interface by which the requested data from a StreamableContent
     object may be read by the client.
     """
     An interface by which the requested data from a StreamableContent
     object may be read by the client.
@@ -610,7 +610,7 @@ class ContentStream(BaseProxy):
     class NotSupported(Exception):
         pass
 
     class NotSupported(Exception):
         pass
 
-    class SeekType(Enum):
+    class SeekType(_Enum):
         """
         Specifies the meaning of a seek 'offset'. Not all SeekTypes are
         supported by all StreamableContent data sources, for instance
         """
         Specifies the meaning of a seek 'offset'. Not all SeekTypes are
         supported by all StreamableContent data sources, for instance
@@ -671,7 +671,7 @@ class DeviceEvent(list):
         self[6] = val
     is_text = property(fget=_get_is_text, fset=_set_is_text)
 
         self[6] = val
     is_text = property(fget=_get_is_text, fset=_set_is_text)
 
-class DeviceEventController(BaseProxy):
+class DeviceEventController(_BaseProxy):
     """
     The interface via which clients request notification of device
     events, and through which device events may be simulated.
     """
     The interface via which clients request notification of device
     events, and through which device events may be simulated.
@@ -817,7 +817,7 @@ class DeviceEventController(BaseProxy):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class DeviceEventListener(BaseProxy):
+class DeviceEventListener(_BaseProxy):
     """
     This interface should be implemented by AT-SPI clients who wish
     to make use of the DeviceEventController to receive device event
     """
     This interface should be implemented by AT-SPI clients who wish
     to make use of the DeviceEventController to receive device event
@@ -861,7 +861,7 @@ class DeviceEventListener(BaseProxy):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class Document(BaseProxy):
+class Document(_BaseProxy):
     """
     Primarily a 'tagging' interface which indicates the start of
     document content in the Accessibility hierarchy. Accessible objects
     """
     Primarily a 'tagging' interface which indicates the start of
     document content in the Accessibility hierarchy. Accessible objects
@@ -923,7 +923,7 @@ class Document(BaseProxy):
         func = self.get_dbus_method("unImplemented_")
         return func(*args, **kwargs)
 
         func = self.get_dbus_method("unImplemented_")
         return func(*args, **kwargs)
 
-class Text(BaseProxy):
+class Text(_BaseProxy):
     """
     The text interface should be implemented by objects which place
     textual information onscreen as character strings or glyphs.
     """
     The text interface should be implemented by objects which place
     textual information onscreen as character strings or glyphs.
@@ -1617,7 +1617,7 @@ class EventDetails(list):
         self[3] = val
     any_data = property(fget=_get_any_data, fset=_set_any_data)
 
         self[3] = val
     any_data = property(fget=_get_any_data, fset=_set_any_data)
 
-class EventListener(BaseProxy):
+class EventListener(_BaseProxy):
     """
     A generic interface implemented by objects for the receipt of
     event notifications. EventListener is the interface from which
     """
     A generic interface implemented by objects for the receipt of
     event notifications. EventListener is the interface from which
@@ -1676,7 +1676,7 @@ class EventListenerMode(list):
     global_ = property(fget=_get_global_, fset=_set_global_)
 
 
     global_ = property(fget=_get_global_, fset=_set_global_)
 
 
-class EventType(Enum):
+class EventType(_Enum):
     _enum_lookup = {
         0:'KEY_PRESSED_EVENT',
         1:'KEY_RELEASED_EVENT',
     _enum_lookup = {
         0:'KEY_PRESSED_EVENT',
         1:'KEY_RELEASED_EVENT',
@@ -1684,7 +1684,7 @@ class EventType(Enum):
         3:'BUTTON_RELEASED_EVENT',
     }
 
         3:'BUTTON_RELEASED_EVENT',
     }
 
-class Hyperlink(BaseProxy):
+class Hyperlink(_BaseProxy):
     """
     Instances of Hyperlink are returned by Hypertext objects, and
     are the means by which end users and clients interact with linked,
     """
     Instances of Hyperlink are returned by Hypertext objects, and
     are the means by which end users and clients interact with linked,
@@ -1785,7 +1785,7 @@ class Hyperlink(BaseProxy):
     startIndex = property(fget=get_startIndex, fset=set_startIndex, doc=_startIndexDoc)
 
 
     startIndex = property(fget=get_startIndex, fset=set_startIndex, doc=_startIndexDoc)
 
 
-class Hypertext(BaseProxy):
+class Hypertext(_BaseProxy):
     """
     An interface used for objects which implement linking between
     multiple resource or content locations, or multiple 'markers'
     """
     An interface used for objects which implement linking between
     multiple resource or content locations, or multiple 'markers'
@@ -1844,7 +1844,7 @@ class Hypertext(BaseProxy):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class Image(BaseProxy):
+class Image(_BaseProxy):
     """
     An interface implemented by objects which render image data or
     pictorial information to the screen. When onscreen components
     """
     An interface implemented by objects which render image data or
     pictorial information to the screen. When onscreen components
@@ -1966,13 +1966,13 @@ class KeyDefinition(list):
         self[3] = val
     unused = property(fget=_get_unused, fset=_set_unused)
 
         self[3] = val
     unused = property(fget=_get_unused, fset=_set_unused)
 
-class KeyEventType(Enum):
+class KeyEventType(_Enum):
     _enum_lookup = {
         0:'KEY_PRESSED',
         1:'KEY_RELEASED',
     }
 
     _enum_lookup = {
         0:'KEY_PRESSED',
         1:'KEY_RELEASED',
     }
 
-class KeySynthType(Enum):
+class KeySynthType(_Enum):
     _enum_lookup = {
         0:'KEY_PRESS',
         1:'KEY_RELEASE',
     _enum_lookup = {
         0:'KEY_PRESS',
         1:'KEY_RELEASE',
@@ -1981,7 +1981,7 @@ class KeySynthType(Enum):
         4:'KEY_STRING',
     }
 
         4:'KEY_STRING',
     }
 
-class LOCALE_TYPE(Enum):
+class LOCALE_TYPE(_Enum):
     _enum_lookup = {
         0:'LOCALE_TYPE_MESSAGES',
         1:'LOCALE_TYPE_COLLATE',
     _enum_lookup = {
         0:'LOCALE_TYPE_MESSAGES',
         1:'LOCALE_TYPE_COLLATE',
@@ -1991,7 +1991,7 @@ class LOCALE_TYPE(Enum):
         5:'LOCALE_TYPE_TIME',
     }
 
         5:'LOCALE_TYPE_TIME',
     }
 
-class LoginHelper(BaseProxy):
+class LoginHelper(_BaseProxy):
     """
     An interface for use by assistive technologies by which they
     can access system information and services on a 'need to know'
     """
     An interface for use by assistive technologies by which they
     can access system information and services on a 'need to know'
@@ -2086,7 +2086,7 @@ class LoginHelper(BaseProxy):
         func = self.get_dbus_method("unImplemented4")
         return func(*args, **kwargs)
 
         func = self.get_dbus_method("unImplemented4")
         return func(*args, **kwargs)
 
-    class DeviceReq(Enum):
+    class DeviceReq(_Enum):
         _enum_lookup = {
             0:'GUI_EVENTS',
             1:'CORE_KEYBOARD',
         _enum_lookup = {
             0:'GUI_EVENTS',
             1:'CORE_KEYBOARD',
@@ -2135,7 +2135,7 @@ class LoginHelper(BaseProxy):
             self[0] = val
         winID = property(fget=_get_winID, fset=_set_winID)
 
             self[0] = val
         winID = property(fget=_get_winID, fset=_set_winID)
 
-class ModifierType(Enum):
+class ModifierType(_Enum):
     _enum_lookup = {
         0:'MODIFIER_SHIFT',
         1:'MODIFIER_SHIFTLOCK',
     _enum_lookup = {
         0:'MODIFIER_SHIFT',
         1:'MODIFIER_SHIFTLOCK',
@@ -2297,7 +2297,7 @@ class Registry(EventListener):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class Relation(BaseProxy):
+class Relation(_BaseProxy):
     """
     An interface via which objects' non-hierarchical relationships
     to one another are indicated. An instance of Relations represents
     """
     An interface via which objects' non-hierarchical relationships
     to one another are indicated. An instance of Relations represents
@@ -2351,7 +2351,7 @@ class Relation(BaseProxy):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class RelationType(Enum):
+class RelationType(_Enum):
     _enum_lookup = {
         0:'RELATION_NULL',
         1:'RELATION_LABEL_FOR',
     _enum_lookup = {
         0:'RELATION_NULL',
         1:'RELATION_LABEL_FOR',
@@ -2374,7 +2374,7 @@ class RelationType(Enum):
         18:'RELATION_LAST_DEFINED',
     }
 
         18:'RELATION_LAST_DEFINED',
     }
 
-class Role(Enum):
+class Role(_Enum):
     _enum_lookup = {
         0:'ROLE_INVALID',
         1:'ROLE_ACCELERATOR_LABEL',
     _enum_lookup = {
         0:'ROLE_INVALID',
         1:'ROLE_ACCELERATOR_LABEL',
@@ -2469,7 +2469,7 @@ class Role(Enum):
         90:'ROLE_LAST_DEFINED',
     }
 
         90:'ROLE_LAST_DEFINED',
     }
 
-class Selection(BaseProxy):
+class Selection(_BaseProxy):
     """
     An interface which indicates that an object exposes a 'selection'
     model, allowing the selection of one or more of its children.
     """
     An interface which indicates that an object exposes a 'selection'
     model, allowing the selection of one or more of its children.
@@ -2593,7 +2593,7 @@ class Selection(BaseProxy):
     nSelectedChildren = property(fget=get_nSelectedChildren, fset=set_nSelectedChildren, doc=_nSelectedChildrenDoc)
 
 
     nSelectedChildren = property(fget=get_nSelectedChildren, fset=set_nSelectedChildren, doc=_nSelectedChildrenDoc)
 
 
-class Selector(BaseProxy):
+class Selector(_BaseProxy):
     """
     This interface is intended for use by assistive technologies
     and related user-agents. Via this interface, an assistive technology
     """
     This interface is intended for use by assistive technologies
     and related user-agents. Via this interface, an assistive technology
@@ -2689,7 +2689,7 @@ class Selector(BaseProxy):
         """
     supportsReplace = property(fget=get_supportsReplace, fset=set_supportsReplace, doc=_supportsReplaceDoc)
 
         """
     supportsReplace = property(fget=get_supportsReplace, fset=set_supportsReplace, doc=_supportsReplaceDoc)
 
-    class CommandResult(Enum):
+    class CommandResult(_Enum):
         """
         A code returned by a call to activateCommand, indicating the
         result of the activation request.
         """
         A code returned by a call to activateCommand, indicating the
         result of the activation request.
@@ -2712,7 +2712,7 @@ class Selector(BaseProxy):
     
     COMMAND_RESULT_SUCCESS = CommandResult(1)
 
     
     COMMAND_RESULT_SUCCESS = CommandResult(1)
 
-class StateSet(BaseProxy):
+class StateSet(_BaseProxy):
     """
     The StateSet interface encapsulates a collection of state information.
     It allows comparison of state information between object instances,
     """
     The StateSet interface encapsulates a collection of state information.
     It allows comparison of state information between object instances,
@@ -2792,7 +2792,7 @@ class StateSet(BaseProxy):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class StateType(Enum):
+class StateType(_Enum):
     _enum_lookup = {
         0:'STATE_INVALID',
         1:'STATE_ACTIVE',
     _enum_lookup = {
         0:'STATE_INVALID',
         1:'STATE_ACTIVE',
@@ -2838,7 +2838,7 @@ class StateType(Enum):
         41:'STATE_LAST_DEFINED',
     }
 
         41:'STATE_LAST_DEFINED',
     }
 
-class StreamableContent(BaseProxy):
+class StreamableContent(_BaseProxy):
     """
     An interface whereby an object allows its backing content to
     be streamed to clients. Negotiation of content type is allowed.
     """
     An interface whereby an object allows its backing content to
     be streamed to clients. Negotiation of content type is allowed.
@@ -2907,7 +2907,7 @@ class StreamableContent(BaseProxy):
         return func(*args, **kwargs)
 
 
         return func(*args, **kwargs)
 
 
-class TEXT_BOUNDARY_TYPE(Enum):
+class TEXT_BOUNDARY_TYPE(_Enum):
     _enum_lookup = {
         0:'TEXT_BOUNDARY_CHAR',
         1:'TEXT_BOUNDARY_WORD_START',
     _enum_lookup = {
         0:'TEXT_BOUNDARY_CHAR',
         1:'TEXT_BOUNDARY_WORD_START',
@@ -2918,7 +2918,7 @@ class TEXT_BOUNDARY_TYPE(Enum):
         6:'TEXT_BOUNDARY_LINE_END',
     }
 
         6:'TEXT_BOUNDARY_LINE_END',
     }
 
-class TEXT_CLIP_TYPE(Enum):
+class TEXT_CLIP_TYPE(_Enum):
     _enum_lookup = {
         0:'TEXT_CLIP_NONE',
         1:'TEXT_CLIP_MIN',
     _enum_lookup = {
         0:'TEXT_CLIP_NONE',
         1:'TEXT_CLIP_MIN',
@@ -2926,7 +2926,7 @@ class TEXT_CLIP_TYPE(Enum):
         3:'TEXT_CLIP_BOTH',
     }
 
         3:'TEXT_CLIP_BOTH',
     }
 
-class Table(BaseProxy):
+class Table(_BaseProxy):
     """
     An interface used by containers whose contained data is arranged
     in a "tabular" (i.e. row-column) fashion. Tables may resemble
     """
     An interface used by containers whose contained data is arranged
     in a "tabular" (i.e. row-column) fashion. Tables may resemble
@@ -3307,7 +3307,7 @@ class Table(BaseProxy):
 
 
 
 
 
 
-class Value(BaseProxy):
+class Value(_BaseProxy):
     """
     An interface supporting controls which allow a one-dimensional,
     scalar quantity to be modified or which reflect a scalar quantity.
     """
     An interface supporting controls which allow a one-dimensional,
     scalar quantity to be modified or which reflect a scalar quantity.
@@ -3766,5 +3766,3 @@ TEXT_CLIP_MAX = TEXT_CLIP_TYPE(2)
 TEXT_CLIP_MIN = TEXT_CLIP_TYPE(1)
 
 TEXT_CLIP_NONE = TEXT_CLIP_TYPE(0)
 TEXT_CLIP_MIN = TEXT_CLIP_TYPE(1)
 
 TEXT_CLIP_NONE = TEXT_CLIP_TYPE(0)
-
-
diff --git a/pyatspi/test.py b/pyatspi/test.py
new file mode 100644 (file)
index 0000000..3696e5e
--- /dev/null
@@ -0,0 +1,49 @@
+#Copyright (C) 2008 Codethink Ltd
+
+#This library is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public
+#License version 2 as published by the Free Software Foundation.
+
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#You should have received a copy of the GNU Lesser General Public License
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+from cache import AccessibleCache
+from factory import create_accessible
+
+import constants
+
+#------------------------------------------------------------------------------
+
+class TestApplicationCache(object):
+       """
+       Test application cache. Accesses single AccessibleCache.
+       """
+
+       def __init__(self, connection, bus_name):
+               self._connection = connection
+               self._bus_name = bus_name
+               self._accessible_cache = AccessibleCache(connection, bus_name)
+
+       def __getitem__(self, key):
+               return self._accessible_cache
+
+       def __contains__(self, key):
+               if key == self._bus_name:
+                       return True
+               else:
+                       return False
+
+       def get_root(self):
+               return create_accessible(self,
+                                        self._bus_name, 
+                                        self._accessible_cache.root, 
+                                        None,
+                                        constants.ATSPI_ACCESSIBLE,
+                                        connection=self._connection)
+
+       root = property(fget=get_root)
index 5853b46..60c8238 100644 (file)
@@ -301,3 +301,5 @@ def getPath(acc):
                except Exception:
                        raise LookupError
                acc = acc.parent
                except Exception:
                        raise LookupError
                acc = acc.parent
+
+del constants
index 07b79e6..35f1cab 100644 (file)
@@ -27,13 +27,13 @@ test_init (gchar *path)
 G_MODULE_EXPORT void
 test_next (int argc, char *argv[])
 {
 G_MODULE_EXPORT void
 test_next (int argc, char *argv[])
 {
-  g_print("Moving to next stage\n");
+  ;
 }
 
 G_MODULE_EXPORT void
 test_finished (int argc, char *argv[])
 {
 }
 
 G_MODULE_EXPORT void
 test_finished (int argc, char *argv[])
 {
-  g_print("Test has completed\n");
+  ;
 }
 
 G_MODULE_EXPORT AtkObject *
 }
 
 G_MODULE_EXPORT AtkObject *
index 0c62402..550f810 100644 (file)
@@ -131,6 +131,7 @@ static const char* introspection_string =
 "<node name=\"/org/codethink/atspi/test\">"
 "      <interface name=\"org.codethink.atspi.test\">"
 "              <method name=\"next\"/>"
 "<node name=\"/org/codethink/atspi/test\">"
 "      <interface name=\"org.codethink.atspi.test\">"
 "              <method name=\"next\"/>"
+"              <method name=\"finish\"/>"
 "               <signal name=\"started\"/>"
 "      </interface>"
 "</node>";
 "               <signal name=\"started\"/>"
 "      </interface>"
 "</node>";
@@ -145,8 +146,6 @@ message_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
 
   DBusMessage *reply = NULL;
 
 
   DBusMessage *reply = NULL;
 
-  g_print("\nRecieved test interface message\n");
-
   g_return_val_if_fail(iface != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
   
   if (!strcmp(iface, "org.codethink.atspi.test"))
   g_return_val_if_fail(iface != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
   
   if (!strcmp(iface, "org.codethink.atspi.test"))
@@ -159,7 +158,7 @@ message_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
          result = DBUS_HANDLER_RESULT_HANDLED;
        }
 
          result = DBUS_HANDLER_RESULT_HANDLED;
        }
 
-      if (!strcmp(member, "finished"))
+      if (!strcmp(member, "finish"))
        {
          ((VoidVoid) test_module_finished)();
           reply = dbus_message_new_method_return (message);
        {
          ((VoidVoid) test_module_finished)();
           reply = dbus_message_new_method_return (message);
index 8e10ef4..b7b2c8c 100644 (file)
@@ -5,33 +5,53 @@ import os.path
 from xml.dom import minidom
 import os
 
 from xml.dom import minidom
 import os
 
-from pasytest import PasyTestSuite
+from pasytest import PasyTest as _PasyTest
 
 
-def createNode(accessible, parentElement):
+import pyatspi
+
+def _createNode(accessible, parentElement):
        e = minidom.Element("accessible")
 
        e.attributes["name"] = accessible.name
        e = minidom.Element("accessible")
 
        e.attributes["name"] = accessible.name
-       e.attributes["role"] = str(int(accessible.role))
+       e.attributes["role"] = str(int(accessible.getRole()))
        e.attributes["description"] = accessible.description
 
        e.attributes["description"] = accessible.description
 
-       for i in range(0, accessible.numChildren):
-               createNode(accessible.getChild(i), e)
+       for i in range(0, accessible.childCount):
+               _createNode(accessible.getChildAtIndex(i), e)
 
        parentElement.appendChild(e)
 
 
        parentElement.appendChild(e)
 
-class TreeTestSuite(PasyTestSuite):
+class AccessibleTest(_PasyTest):
+
+       __tests__ = ["setup", "tree"]
 
 
-       __tests__ = ["accessibleTree"]
+       def __init__(self, bus, path):
+               _PasyTest.__init__(self, "Accessible", False)
+               self._bus = bus
+               self._path = path
 
 
-       def __init__(self, bus, name):
-               PasyTestSuite.__init__(self, "Tree")
-               self._cache = getAccessibleCache(bus, name)
+       def setup(self):
+               self._cache = pyatspi.TestApplicationCache(self._bus, self._path)
 
 
-       def accessibleTree(test):
-               root = self._cache.getRootAccessible()
+       def tree(self):
+               """
+               This is a mild stress test for the 
+               methods:
+
+               getChildAtIndex
+               
+               And the attributes:
+
+               name
+               description
+
+               It checks a tree of these values is correctly
+               passed from Application to AT.
+               """
+               root = self._cache.root
 
                doc = minidom.Document()
 
                doc = minidom.Document()
-               createNode(root, doc)
+               _createNode(root, doc)
                answer = doc.toprettyxml()
 
                correct = os.path.join(os.environ["TEST_DATA_DIRECTORY"],
                answer = doc.toprettyxml()
 
                correct = os.path.join(os.environ["TEST_DATA_DIRECTORY"],
@@ -39,6 +59,4 @@ class TreeTestSuite(PasyTestSuite):
                file = open(correct)
                cstring = file.read()
                
                file = open(correct)
                cstring = file.read()
                
-               test.assertEqual(answer, cstring, "Object tree not passed correctly")
-
-               test.win()
+               self.assertEqual(answer, cstring, "Object tree not passed correctly")
index bb2651f..166c3e1 100644 (file)
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
 #along with this program; if not, write to the Free Software
 #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
+import gobject
 from Events import Events
 
 from Events import Events
 
+import traceback
+
 PASY_TEST_NOT_STARTED = 0
 PASY_TEST_IN_PROGRESS = 1
 PASY_TEST_FAIL = 2
 PASY_TEST_NOT_STARTED = 0
 PASY_TEST_IN_PROGRESS = 1
 PASY_TEST_FAIL = 2
@@ -30,7 +33,6 @@ class PasyTestStep(object):
                self._state = PASY_TEST_NOT_STARTED
 
                self._name = name
                self._state = PASY_TEST_NOT_STARTED
 
                self._name = name
-               self._test = test
 
        def win(self):
                if self._state == PASY_TEST_IN_PROGRESS:
 
        def win(self):
                if self._state == PASY_TEST_IN_PROGRESS:
@@ -49,7 +51,15 @@ class PasyTestStep(object):
 
        def run(self):
                self._state = PASY_TEST_IN_PROGRESS
 
        def run(self):
                self._state = PASY_TEST_IN_PROGRESS
-               self.entry(self)
+               self.entry()
+
+       def report(self):
+               if self._state == PASY_TEST_WIN:
+                       return "%s - PASSED" % (self._name,)
+               elif self._state == PASY_TEST_FAIL:
+                       return "%s - FAILED - %s" % (self._name, self.failMsg)
+               else:
+                       return "%s - INCOMPLETE" %s (self._name,)
 
        @property
        def state(self):
 
        @property
        def state(self):
@@ -62,29 +72,33 @@ class PasyTestFunc(PasyTestStep):
                self._func = func
 
        def entry(self):
                self._func = func
 
        def entry(self):
-               self._func(self)
+               try:
+                       self._func()
+               except Exception, e:
+                       self.fail(e.message)
+                       traceback.print_exc()
+               self.win()
 
 class PasyTest(PasyTestStep):
 
        __tests__ = []
 
        def __init__(self, name, cont):
 
 class PasyTest(PasyTestStep):
 
        __tests__ = []
 
        def __init__(self, name, cont):
-               PasyTest.__init__(self, name)
+               PasyTestStep.__init__(self, name)
 
                self._cont = cont
                self._tests = []
 
 
                self._cont = cont
                self._tests = []
 
-               for name in __tests__:
-                       func = self.__getattr__(name)
+               for name in self.__tests__:
+                       func = getattr(self, name)
                        self._addfunc(func.func_name, func)
 
        def _addfunc(self, name, func):
                        self._addfunc(func.func_name, func)
 
        def _addfunc(self, name, func):
-               functest = PasyTestFunc(self, func.func_name, func)
-               self.add(functest)
+               functest = PasyTestFunc(func.func_name, func)
                self._tests.append(functest)
 
        def entry(self):
                self._tests.append(functest)
 
        def entry(self):
-               self._iter = self._test_iterator
+               self._iter = self._test_iterator()
                gobject.idle_add(self.idle_handler)
 
        def idle_handler(self):
                gobject.idle_add(self.idle_handler)
 
        def idle_handler(self):
@@ -94,8 +108,8 @@ class PasyTest(PasyTestStep):
                                if step.state == PASY_TEST_WIN or self._cont == True:
                                        gobject.idle_add(self.idle_handler)
                                elif step.state == PASY_TEST_FAIL and self._cont == False:
                                if step.state == PASY_TEST_WIN or self._cont == True:
                                        gobject.idle_add(self.idle_handler)
                                elif step.state == PASY_TEST_FAIL and self._cont == False:
-                                       self.fail()
-                       step.events.failed += finished_handler
+                                       self.fail("Sub test %s Failed" % step._name)
+                       step.events.finished += finished_handler
                        step.run()
                except StopIteration:
                        # No More tests, check for success or fail
                        step.run()
                except StopIteration:
                        # No More tests, check for success or fail
@@ -111,3 +125,18 @@ class PasyTest(PasyTestStep):
        def _test_iterator(self):
                for test in self._tests:
                        yield test
        def _test_iterator(self):
                for test in self._tests:
                        yield test
+
+       def report(self):
+               if self._state == PASY_TEST_WIN:
+                       header =  "%s - PASSED" % (self._name,)
+               elif self._state == PASY_TEST_FAIL:
+                       header =  "%s - FAILED - %s" % (self._name, self.failMsg)
+               else:
+                       header =  "%s - INCOMPLETE" %s (self._name,)
+
+               step_messages = []
+               for test in self._tests:
+                       step_messages.append(test.report())
+
+               step_report =  "\n\t".join(step_messages)
+               return header + "\n\t" + step_report
index 17d1c48..d9638a2 100755 (executable)
@@ -1,4 +1,4 @@
-export PYTHONPATH=../../../
+export PYTHONPATH=../../
 
 export TEST_DATA_DIRECTORY=../data
 export TEST_ATSPI_LIBRARY=../../atk-adaptor/.libs/libspiatk.so
 
 export TEST_DATA_DIRECTORY=../data
 export TEST_ATSPI_LIBRARY=../../atk-adaptor/.libs/libspiatk.so
index 4a95f70..efd9289 100755 (executable)
@@ -1,11 +1,19 @@
 #!/usr/bin/python
 
 #!/usr/bin/python
 
+import gobject
 import dbus
 import sys
 import time
 from random import randint
 
 import dbus
 import sys
 import time
 from random import randint
 
-def runTestApp(module_name, dbus_name=None):
+from optparse import OptionParser
+from pasytest import PasyTest
+
+from dbus.mainloop.glib import DBusGMainLoop
+
+DBusGMainLoop(set_as_default=True)
+
+def run_test_app(module_name, dbus_name=None):
        import os
        from subprocess import Popen
 
        import os
        from subprocess import Popen
 
@@ -46,24 +54,38 @@ def runTestApp(module_name, dbus_name=None):
                raw_input(wait_message % (module_name, pop.pid))
 
 def main(argv):
                raw_input(wait_message % (module_name, pop.pid))
 
 def main(argv):
-       testModule = argv[1]
+       parser = OptionParser()
+       parser.add_option("-l", "--library", dest="test_library")
+       parser.add_option("-m", "--module", dest="test_module")
+       parser.add_option("-n", "--name", dest="test_name")
+       (options, args) = parser.parse_args()
 
 
-       # TODO Modify this function to add registryd as an option
        bus = dbus.SessionBus()
        name = "test.atspi.R" + str(randint(1, 1000)) 
 
        bus = dbus.SessionBus()
        name = "test.atspi.R" + str(randint(1, 1000)) 
 
-       app = runTestApp(testModule, name)
-       # Wait a little time for the app to start up
-       # TODO connect this up to the apps start signal
+       app = run_test_app(options.test_library, name)
        time.sleep(1)
        time.sleep(1)
+       print "Started test app on bus name %s" % (name,)
 
        to = bus.get_object(name, "/org/codethink/atspi/test")
        test = dbus.Interface(to, "org.codethink.atspi.test")
 
 
        to = bus.get_object(name, "/org/codethink/atspi/test")
        test = dbus.Interface(to, "org.codethink.atspi.test")
 
-       # Run the test script here FIXME
+       # Run the test script here
+       module = __import__(options.test_module)
+       test_class = getattr(module, options.test_name)
+       test_object = test_class(bus, name)
+       test_object.run()
+
+       loop = gobject.MainLoop()
+
+       def finished_handler():
+               loop.quit()
+               print "\n" + test_object.report() + "\n"
+               test.finish()
+
+       test_object.events.finished += finished_handler
 
 
-       # Inform the test app it can shut down.
-       test.finish()
+       loop.run()
 
 if __name__=="__main__":
        sys.exit(main(sys.argv))
 
 if __name__=="__main__":
        sys.exit(main(sys.argv))