Skip to content

Commit

Permalink
Rewrite windows driver for new driver interface, draft version
Browse files Browse the repository at this point in the history
Signed-off-by: xcgspring <[email protected]>
  • Loading branch information
xcgspring committed Apr 9, 2015
1 parent c302570 commit 7b1b50b
Show file tree
Hide file tree
Showing 10 changed files with 589 additions and 154 deletions.
18 changes: 13 additions & 5 deletions AXUI/XML/app_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ def _init_UI_element(self, xml_element):
UI_element.identifier = identifier_parser.parse(UI_element.identifier_string, lexer=identifier_lexer)

return UI_element

elif xml_element.tag == "{AXUI}Root_element":
UI_element = element_module.RootElement()

UI_element.name = xml_element.attrib["name"]

return UI_element

elif xml_element.tag == "{AXUI}UI_element_group":
UI_element_group = element_module.ElementGroup()
Expand Down Expand Up @@ -153,14 +160,15 @@ def _build_UI_element(self, xml_element, parent_UI_element):
def _build_top_level_UI_element(self, xml_element):
UI_element = self._init_UI_element(xml_element)

#do nothing for root element
if UI_element.is_root():
return UI_element

#top level element must have parent
#except root element
if UI_element.parent_string == self.root_parent_string:
UI_element.parent = None
elif UI_element.parent_string:
if UI_element.parent_string:
UI_element.parent = self.get_UI_element_by_name(UI_element.parent_string)
else:
raise ValueError("Top level element except root must have parent, miss parent in element: %s" % UI_element.name)
raise ValueError("Top level element must have parent attribute, miss parent in element: %s" % UI_element.name)

return UI_element

Expand Down
115 changes: 94 additions & 21 deletions AXUI/XML/element.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,90 @@ def __repr__(self):
def verify(self):
return self

class RootElement(object):
'''wrapper for root element
provide interface for enter point of UI automation API
like desktop of windows UIA API, or browser for web driver API
Interfaces exposed for use:
verify: function to verify if self still exist
start: function to init and start this element
stop: function to stop this element
screenshot: function to take a screenshot
other driver special interfaces
'''
def __init__(self):
#Need init by app map module
self.name = ""
self.children = {}

#get driver module
driver_module = driver.get_driver()
#represent for root interface of driver module
self.root = driver_module.Root()

def __repr__(self):
docstring = "root element instance"
return docstring

@property
def details(self):
'''return details of this element
'''
docstring = "Root element details for: %s\n" % self.name

docstring += "#"*24
docstring += "\n"
docstring += " Children:\n"
for key in self.children:
docstring += " %s\n" % repr(self.children[key])

docstring += "#"*24
docstring += "\n"
docstring += " details:\n"
docstring += self.root.__repr__()

return docstring

def start(self, **kwargs):
'''
start method will do some initiation for root element
for windows UIA, just bind UIA root element to driver root interface, no arguments required
for webdriver API, could pass in some arguments, like browser type, URL, timeout, and start the browser
'''
self.root.start(kwargs)

def stop(self):
'''
'''
self.root.stop()

def find(self, identifier):
'''find element by identifier
identifier should already be parsed
'''
self.start()
return self.root.find_element(identifier)

def findall(self, identifier):
'''find all elements match identifier
'''
self.start()
return self.root.find_elements(identifier)

def __getattr__(self, name):
if self.children.has_key(name):
return self.children[name]
else:
self.start()
return getattr(self.root, name)

class Element(object):
'''wrapper for UIElement
hold informations from app map, and provide UIElement interface for app map
Attributes:
Attributes used internal:
name: Element's name, from XML
parent_string: Element's parent string, from XML
identifier_string: Identifier string, from XML
Expand All @@ -33,11 +112,16 @@ class Element(object):
identifier: parsed identifier
UIElement: driver interface for UIElement
find: function to find first match child element
findall: function to find all matched children elements
Interfaces exposed for use:
verify: function to verify if self still exist
find: function to find children element
start: function to start this element
stop: function to stop this element
screenshot: function to take a screenshot
other driver special interfaces
'''
#fake UI element is for elements without identifier
Expand Down Expand Up @@ -95,19 +179,16 @@ def verify(self):
'''verify UIElement is valid or not
return None if not valid
'''
#root element
if self.parent is None:
self.UIElement = driver.get_UIElement().get_root()
#no identifier
elif self.identifier is None:
if self.identifier is None:
self.UIElement = self.fake_UI_element
#has identifier and not root
else:
self.UIElement = self.parent.find(self.identifier)

return self.UIElement

def wait_start(self):
def _wait_start(self):
'''wait until UIElement is valid or timeout
'''
#keep finding the element by identifier, until found or timeout
Expand All @@ -132,7 +213,7 @@ def wait_start(self):
element.screenshot()
return False

def wait_stop(self):
def _wait_stop(self):
'''wait until UIElement is not valid or timeout
'''
if not self.identifier is None:
Expand Down Expand Up @@ -160,10 +241,7 @@ def find(self, identifier):
elif self.UIElement is self.fake_UI_element:
return self.parent.find(identifier)
else:
if self.parent is None:
return self.UIElement.root_find(identifier)
else:
return self.UIElement.find(identifier)
return self.UIElement.find_element(identifier)

def _start(self):
if not self.start_func is None:
Expand All @@ -176,7 +254,7 @@ def start(self):
#run start func
if self.start_func:
self._start()
if not self.wait_start():
if not self._wait_start():
raise TimeOutError("time out encounter, during element:%s start" % self.name)

def _stop(self):
Expand All @@ -196,20 +274,15 @@ def stop(self):
#only stop and check element which has stop_func attribute
if self.stop_func:
self._stop()
if not self.wait_stop():
if not self._wait_stop():
raise TimeOutError("time out encounter, during element:%s stop" % self.name)

def findall(self, identifier):
'''find all elements match identifier
'''
self.start()
if self.parent is None:
children_UIElements = self.UIElement._root_find_all_by_UIA(identifier)
else:
children_UIElements = self.UIElement._find_all_by_UIA(identifier)

return children_UIElements

return self.UIElement.find_elements(identifier)

def screenshot(self):
'''take a screen shot for this element
'''
Expand Down
13 changes: 13 additions & 0 deletions AXUI/XML/schemas/AXUI_app_map.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,19 @@

<xs:element name="UI_elements">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="1">
<xs:element ref="AXUI:Root_element" />
</xs:choice>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="AXUI:UI_element" />
<xs:element ref="AXUI:UI_element_group" />
</xs:choice>
</xs:complexType>
</xs:element>

<xs:element name="Root_element">
<xs:complexType>
<xs:attribute name="name" type="xs:string" use="required" />
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="AXUI:UI_element" />
<xs:element ref="AXUI:UI_element_group" />
Expand Down
8 changes: 4 additions & 4 deletions AXUI/driver/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#for config use
from config_driver import *

def get_UIElement():
'''get driver UIElement
Return: return UIElement from driver selected in config
def get_driver():
'''get driver
Return: return driver module selected in config
'''
import config_driver
driver_used = config_driver.DriverUsed
Expand All @@ -15,4 +15,4 @@ def get_UIElement():
except ImportError:
raise NotImplementedError("driver not implement: %s, check your driver folder" % driver_used)

return driver.UIElement
return driver
99 changes: 86 additions & 13 deletions AXUI/driver/fake_driver/UIElement.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,47 @@

class Method(object):
'''
optional interface,
this class is a method wrapper for UIElement methods, if UI API has native python lib, this class might not needed
'''
pass

class UIElement(object):
class Pattern(object):
'''
optional interface,
this class is a method set for different kinds of UIElement
usually different kind of UIElements support different set of methods
we can assign different pattern for these UIElements
'''
this is a template driver module need to implement
pass

class UIElement(object):
'''This class defines interfaces for common UI element
Every driver (Windows, Appium, Selenium) should implement this interfaces,
provides independent interfaces for uplevel modules, so we transplant AXUI cross different platform
Attributes:
find_element: find the first descendant element which matches parsed_identifier
find_elements: find all elements which match parsed_identifier
verify: verify current element is valid
get_keyboard: class for keyboard related methods
get_mouse: class for mouse related methods
get_touch: class for touch related methods
get_property: get property value for current element
get_pattern: get pattern interface for current element
'''
@classmethod
def get_root(cls):
def find_element(self, parsed_identifier):
'''
find the first child UI element via identifier, return one UIAElement if success, return None if not find
'''
raise NotImplementedError("Not implement")
property_keys = []
pattern_keys = []
def find(self, parsed_identifier):

def find_elements(self, parsed_identifier):
'''
find the UI element via identifier, return one UIAElement if success, return None if not find
find the child UI elements via identifier, return a list containing target UI elements
'''
raise NotImplementedError("Not implement")

Expand All @@ -29,25 +59,25 @@ def get_property(self, name):

def get_pattern(self, name):
'''
get pattern supprted by UI element
pattern is a class support one kind of UI actions
'''
raise NotImplementedError("Not implement")

def get_keyboard(self):
'''
get keyboard
get keyboard class to use keyboard related methods
'''
raise NotImplementedError("Not implement")

def get_mouse(self):
'''
get mouse
get mouse class to use mouse related methods
'''
raise NotImplementedError("Not implement")

def get_touch(self):
'''
get touch
get touch class to use touch related methods
'''
raise NotImplementedError("Not implement")

Expand All @@ -67,5 +97,48 @@ def __getattr__(self, name):
return attr
raise AttributeError("Attribute not exist: %s" % name)


class Root(UIElement):
'''
root is the entry point to interact with UI
like desktop of windows UIA, web browser of web driver API
This class defines interfaces for root element
Every driver (Windows, Appium, Selenium) should implement this interfaces,
provides independent interfaces for uplevel modules, so we transplant AXUI cross different platform
Attributes:
start: start root element
stop: stop root element
screenshot: take a screen shot for root element
find_element: find the first descendant element which matches parsed_identifier
find_elements: find all elements which match parsed_identifier
verify: verify current element is valid
get_keyboard: class for keyboard related methods
get_mouse: class for mouse related methods
get_touch: class for touch related methods
get_property: get property value for current element
get_pattern: get pattern interface for current element
'''
def start(self, **kwargs):
'''
get root ready
like get root element in windows UIA, get browser to target website
'''
raise NotImplementedError("Not implement")

def stop(self, **kwargs):
'''
stop root
like close browser for web driver API
'''
raise NotImplementedError("Not implement")

def screenshot(self, absfile_path):
'''
take a screen shot for root
'''
raise NotImplementedError("Not implement")
Loading

0 comments on commit 7b1b50b

Please sign in to comment.