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";
 
+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 base import *
 from other import *
-from accessible import *
+
+from test 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.
 
-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 factory import create_accessible, add_accessible_class
+
+import constants
 
 class AccessibleObjectNoLongerExists(Exception):
        pass
 
 #------------------------------------------------------------------------------
 
-class Enum(int):
+class _Enum(int):
        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 = { 
-                       '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():
@@ -65,61 +61,267 @@ class BaseProxy(Interface):
                                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.
 
-               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):
-               """
-               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
-       def _data(self):
+       def cached_data(self):
                try:
-                       data = self._cache._objects[self._path]
+                       return self._cache[self._app_name][self._acc_path]
                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):
+               """
+               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:
-                               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))
 
+#------------------------------------------------------------------------------
+
+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----------------------------------------------------------------------------
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.
 
-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):
                """
@@ -60,22 +53,28 @@ class BaseCache(object):
                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 = {}
 
-               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
-               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]
@@ -85,30 +84,14 @@ class BaseCache(object):
                        else:
                                self._objects[path] = _CacheData(data)
 
-       def _removeObjects(self, paths):
+       def _remove_objects(self, paths):
                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
@@ -116,6 +99,9 @@ class AccessibleCache(BaseCache):
 
        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'
@@ -124,73 +110,16 @@ class AccessibleCache(BaseCache):
        _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()
 
-       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---------------------------------------------------------------------------
index ccef0fb..f4c41b2 100644 (file)
@@ -139,20 +139,21 @@ EVENT_TREE = {
     ['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.
 
-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----------------------------------------------------------------------------
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.
 
-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)
 
 
-class Application(Accessible):
+class Application(_Accessible):
     
     
     """
@@ -250,7 +250,7 @@ class BoundingBox(list):
     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")
@@ -296,7 +296,7 @@ class Collection(BaseProxy):
         func = self.get_dbus_method("unImplemented4")
         return func(*args, **kwargs)
 
-    class MatchType(Enum):
+    class MatchType(_Enum):
         _enum_lookup = {
             0:'MATCH_INVALID',
             1:'MATCH_ALL',
@@ -318,7 +318,7 @@ class Collection(BaseProxy):
     
     MATCH_NONE = MatchType(3)
 
-    class SortOrder(Enum):
+    class SortOrder(_Enum):
         _enum_lookup = {
             0:'SORT_ORDER_INVALID',
             1:'SORT_ORDER_CANONICAL',
@@ -346,7 +346,7 @@ class Collection(BaseProxy):
     
     SORT_ORDER_TAB = SortOrder(3)
 
-    class TreeTraversalType(Enum):
+    class TreeTraversalType(_Enum):
         _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)
 
-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
@@ -400,7 +400,7 @@ class CommandListener(BaseProxy):
         return func(*args, **kwargs)
 
 
-class Component(BaseProxy):
+class Component(_BaseProxy):
     
     
     """
@@ -537,7 +537,7 @@ class Component(BaseProxy):
         return func(*args, **kwargs)
 
 
-class ComponentLayer(Enum):
+class ComponentLayer(_Enum):
     _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.
@@ -610,7 +610,7 @@ class ContentStream(BaseProxy):
     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
@@ -671,7 +671,7 @@ class DeviceEvent(list):
         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.
@@ -817,7 +817,7 @@ class DeviceEventController(BaseProxy):
         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
@@ -861,7 +861,7 @@ class DeviceEventListener(BaseProxy):
         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
@@ -923,7 +923,7 @@ class Document(BaseProxy):
         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.
@@ -1617,7 +1617,7 @@ class EventDetails(list):
         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
@@ -1676,7 +1676,7 @@ class EventListenerMode(list):
     global_ = property(fget=_get_global_, fset=_set_global_)
 
 
-class EventType(Enum):
+class EventType(_Enum):
     _enum_lookup = {
         0:'KEY_PRESSED_EVENT',
         1:'KEY_RELEASED_EVENT',
@@ -1684,7 +1684,7 @@ class EventType(Enum):
         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,
@@ -1785,7 +1785,7 @@ class Hyperlink(BaseProxy):
     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'
@@ -1844,7 +1844,7 @@ class Hypertext(BaseProxy):
         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
@@ -1966,13 +1966,13 @@ class KeyDefinition(list):
         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',
     }
 
-class KeySynthType(Enum):
+class KeySynthType(_Enum):
     _enum_lookup = {
         0:'KEY_PRESS',
         1:'KEY_RELEASE',
@@ -1981,7 +1981,7 @@ class KeySynthType(Enum):
         4:'KEY_STRING',
     }
 
-class LOCALE_TYPE(Enum):
+class LOCALE_TYPE(_Enum):
     _enum_lookup = {
         0:'LOCALE_TYPE_MESSAGES',
         1:'LOCALE_TYPE_COLLATE',
@@ -1991,7 +1991,7 @@ class LOCALE_TYPE(Enum):
         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'
@@ -2086,7 +2086,7 @@ class LoginHelper(BaseProxy):
         func = self.get_dbus_method("unImplemented4")
         return func(*args, **kwargs)
 
-    class DeviceReq(Enum):
+    class DeviceReq(_Enum):
         _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)
 
-class ModifierType(Enum):
+class ModifierType(_Enum):
     _enum_lookup = {
         0:'MODIFIER_SHIFT',
         1:'MODIFIER_SHIFTLOCK',
@@ -2297,7 +2297,7 @@ class Registry(EventListener):
         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
@@ -2351,7 +2351,7 @@ class Relation(BaseProxy):
         return func(*args, **kwargs)
 
 
-class RelationType(Enum):
+class RelationType(_Enum):
     _enum_lookup = {
         0:'RELATION_NULL',
         1:'RELATION_LABEL_FOR',
@@ -2374,7 +2374,7 @@ class RelationType(Enum):
         18:'RELATION_LAST_DEFINED',
     }
 
-class Role(Enum):
+class Role(_Enum):
     _enum_lookup = {
         0:'ROLE_INVALID',
         1:'ROLE_ACCELERATOR_LABEL',
@@ -2469,7 +2469,7 @@ class Role(Enum):
         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.
@@ -2593,7 +2593,7 @@ class Selection(BaseProxy):
     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
@@ -2689,7 +2689,7 @@ class Selector(BaseProxy):
         """
     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.
@@ -2712,7 +2712,7 @@ class Selector(BaseProxy):
     
     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,
@@ -2792,7 +2792,7 @@ class StateSet(BaseProxy):
         return func(*args, **kwargs)
 
 
-class StateType(Enum):
+class StateType(_Enum):
     _enum_lookup = {
         0:'STATE_INVALID',
         1:'STATE_ACTIVE',
@@ -2838,7 +2838,7 @@ class StateType(Enum):
         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.
@@ -2907,7 +2907,7 @@ class StreamableContent(BaseProxy):
         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',
@@ -2918,7 +2918,7 @@ class TEXT_BOUNDARY_TYPE(Enum):
         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',
@@ -2926,7 +2926,7 @@ class TEXT_CLIP_TYPE(Enum):
         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
@@ -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.
@@ -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)
-
-
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
+
+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_print("Moving to next stage\n");
+  ;
 }
 
 G_MODULE_EXPORT void
 test_finished (int argc, char *argv[])
 {
-  g_print("Test has completed\n");
+  ;
 }
 
 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\"/>"
+"              <method name=\"finish\"/>"
 "               <signal name=\"started\"/>"
 "      </interface>"
 "</node>";
@@ -145,8 +146,6 @@ message_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
 
   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"))
@@ -159,7 +158,7 @@ message_handler (DBusConnection *bus, DBusMessage *message, void *user_data)
          result = DBUS_HANDLER_RESULT_HANDLED;
        }
 
-      if (!strcmp(member, "finished"))
+      if (!strcmp(member, "finish"))
        {
          ((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 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.attributes["role"] = str(int(accessible.role))
+       e.attributes["role"] = str(int(accessible.getRole()))
        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)
 
-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()
-               createNode(root, doc)
+               _createNode(root, doc)
                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()
                
-               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.
 
+import gobject
 from Events import Events
 
+import traceback
+
 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._test = test
 
        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
-               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):
@@ -62,29 +72,33 @@ class PasyTestFunc(PasyTestStep):
                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):
-               PasyTest.__init__(self, name)
+               PasyTestStep.__init__(self, name)
 
                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):
-               functest = PasyTestFunc(self, func.func_name, func)
-               self.add(functest)
+               functest = PasyTestFunc(func.func_name, func)
                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):
@@ -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:
-                                       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
@@ -111,3 +125,18 @@ class PasyTest(PasyTestStep):
        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
index 4a95f70..efd9289 100755 (executable)
@@ -1,11 +1,19 @@
 #!/usr/bin/python
 
+import gobject
 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
 
@@ -46,24 +54,38 @@ def runTestApp(module_name, dbus_name=None):
                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)) 
 
-       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)
+       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")
 
-       # 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))