Merged changes from MetaClassWrapping branch

This commit is contained in:
markm 2006-05-05 14:05:32 +00:00
parent d9c4e758ec
commit c3bf694038
13 changed files with 141 additions and 275 deletions

@ -24,3 +24,7 @@ Python package for automating GUI manipulation on Windows
"""
__revision__ = "$Revision$"
__version__ = "0.3.4"
import findwindows
WindowAmbiguousError = findwindows.WindowAmbiguousError
WindowNotFoundError = findwindows.WindowNotFoundError

@ -22,20 +22,20 @@
When starting to automate and application you must initialize an instance
of the Application class. Then you must `start_()`_ that application or
`connect_()`_ to a running instance of that application.
`Connect_()`_ to a running instance of that application.
Once you have an Application instance you can access dialogs in that
application either by using one of the methods below. ::
dlg = app.YourDialogTitle
dlg = app.window_(title = "your title", class = "your class", ...)
dlg = app.Window_(title = "your title", classname = "your class", ...)
dlg = app['Your Dialog Title']
Similarly once you have a dialog you can get a control from that dialog
in almost exactly the same ways. ::
ctrl = dlg.YourControlTitle
ctrl = dlg.control_(title = "Your control", class = "Button", ...)
ctrl = dlg.Window_(title = "Your control", classname = "Button", ...)
ctrl = dlg["Your control"]
**Note:** For attribute access of controls and dialogs you do not have to
@ -46,11 +46,11 @@ avialable dialogs or controls.
`findwindows.find_windows()`_ for the keyword arguments that can be
passed to both `Application.window_()`_ and `ActionDialog.control_()`_
.. _start_(): class-pywinauto.application.Application.html#start_
.. _connect_(): class-pywinauto.application.Application.html#connect_
.. _Start_(): class-pywinauto.application.Application.html#start_
.. _Connect_(): class-pywinauto.application.Application.html#connect_
.. _findwindows.find_windows(): module-pywinauto.findwindows.html#find_windows
.. _Application.window_(): class-pywinauto.application.Application.html#window_
.. _ActionDialog.control_(): class-pywinauto.application.ActionDialog.html#control_
.. _Application.Window_(): class-pywinauto.application.Application.html#window_
.. _WindowSpecification.Window_(): class-pywinauto.application.WindowSpecification.html#control_
"""
@ -135,21 +135,24 @@ class WindowSpecification(object):
else:
ctrls = _resolve_control(self.criteria)
self.app.RecordMatch(self.criteria, ctrls)
#self.app.RecordMatch(self.criteria, ctrls)
#write_appdata(self.criteria, ctrls)
return ctrls[-1]
def ctrl_(self):
"Allow the calling code to get the HwndWrapper object"
message = "ctrl_() has been renamed to ControlObject() please use " \
message = "ctrl_() has been renamed to WrapperObject() please use " \
"that method in the future. ctrl_() will be removed at some " \
"future time."
warnings.warn(message, DeprecationWarning)
return self.WrapperObject()
def Window_(self, **criteria):
"Add the criteria that will be matched when we resolve the control"
"""Add criteria for a control
When this window specification is resolved then this will be used
to match against a control."""
new_item = WindowSpecification(self.app, self.criteria[0])
new_item.criteria.append(criteria)
@ -182,7 +185,7 @@ class WindowSpecification(object):
ctrls = _resolve_control(
self.criteria)
self.app.RecordMatch(self.criteria, ctrls)
#self.app.RecordMatch(self.criteria, ctrls)
# try to return a good error message if the control does not
# have a __getitem__() method)
@ -234,7 +237,7 @@ class WindowSpecification(object):
ctrls = _resolve_control(
self.criteria)
self.app.RecordMatch(self.criteria, ctrls)
#self.app.RecordMatch(self.criteria, ctrls)
return getattr(ctrls[-1], attr)
else:
@ -250,7 +253,7 @@ class WindowSpecification(object):
ctrls = _resolve_control(
self.criteria)
self.app.RecordMatch(self.criteria, ctrls)
#self.app.RecordMatch(self.criteria, ctrls)
return getattr(ctrls[-1], attr)
# why was I using wait below and not just
@ -363,7 +366,7 @@ class WindowSpecification(object):
timeout,
retry_interval)
self.app.RecordMatch(self.criteria, ctrls)
#self.app.RecordMatch(self.criteria, ctrls)
return ctrls[-1]
@ -421,7 +424,7 @@ class WindowSpecification(object):
#raise
return
self.app.RecordMatch(self.criteria, ctrls)
#self.app.RecordMatch(self.criteria, ctrls)
while True:
@ -1061,6 +1064,8 @@ class Application(object):
def RecordMatch(self, criteria, ctrls):
"Save that a control request matched."
return
# if we are not working from existing match
# data then don't add the match
if not self.use_history:

@ -24,10 +24,8 @@ __revision__ = "$Revision$"
# pylint: disable-msg=W0611
#from pprint import pprint
import time
import re
import ctypes
# the wrappers may be used in an environment that does not need
@ -38,7 +36,6 @@ try:
except ImportError:
pass
# I leave this optional because PIL is a large dependency
try:
import PIL.ImageGrab
@ -76,39 +73,56 @@ class InvalidWindowHandle(RuntimeError):
"Handle 0x%d is not a vaild window handle"% hwnd)
#====================================================================
# just wrap the importing of WrapHandle - because it imports us
# and we import it - it can't be at the global level
def WrapHandle(hwnd):
"""Wrap a window handle
* **hwnd** the handle of the window to wrap
This is a simple wrapper around wraphandle.WrapHandle
that we need to have due to import cross dependencies."""
import wraphandle
return wraphandle.WrapHandle(hwnd)
# metaclass that will know about
class _MetaWrapper(type):
"Metaclass for Wrapper objects"
re_wrappers = {}
str_wrappers = {}
#
# # Optimization - check if the control name matches exactly
# # before trying a re.match
# if class_name in _HwndWrappers:
# return _HwndWrappers[class_name][1](hwnd)
#
# for wrapper_name, (regex, class_) in _HwndWrappers.items():
# if regex.match(class_name):
# #print wrapper_name
# return class_(hwnd)
#
# # so it is not one of the 'known' classes - just wrap it with
# # hwnd wrapper
# wrapped_hwnd = HwndWrapper(hwnd)
#
# # if it's not a dialog -
# #if not isDialog:
# # wrapped_hwnd._NeedsImageProp = True
#
# return wrapped_hwnd
def __init__(cls, name, bases, attrs):
# register the class names, both the regular expression
# or the classes directly
#print "metaclass __init__", cls
type.__init__(cls, name, bases, attrs)
for win_class in cls.windowclasses:
_MetaWrapper.re_wrappers[re.compile(win_class)] = cls
_MetaWrapper.str_wrappers[win_class] = cls
def FindWrapper(handle):
"""Find the correct wrapper for this handle"""
class_name = handleprops.classname(handle)
try:
return _MetaWrapper.str_wrappers[class_name]
except KeyError:
wrapper_match = None
for regex, wrapper in _MetaWrapper.re_wrappers.items():
if regex.match(class_name):
wrapper_match = wrapper
_MetaWrapper.str_wrappers[class_name] = wrapper
break
# if it is a dialog then override the wrapper we found
# and make it a DialogWrapper
if handleprops.is_toplevel_window(handle):
import win32_controls
wrapper_match = win32_controls.DialogWrapper
if wrapper_match is None:
wrapper_match = HwndWrapper
return wrapper_match
#if handle in meta.wrappers:
# return meta.wrappers[handle]
FindWrapper = staticmethod(FindWrapper)
#====================================================================
@ -130,9 +144,22 @@ class HwndWrapper(object):
C function - and it will get converted to a Long with the value of
it's handle (see ctypes, _as_parameter_)"""
__metaclass__ = _MetaWrapper
friendlyclassname = None
windowclasses = []
handle = None
#-----------------------------------------------------------
def __new__(cls, handle):
new_class = cls.FindWrapper(handle)
#super(currentclass, cls).__new__(cls[, ...])"
obj = object.__new__(new_class)
obj.__init__(handle)
return obj
#-----------------------------------------------------------
def __init__(self, hwnd):
"""Initialize the control
@ -408,7 +435,7 @@ class HwndWrapper(object):
if parent_hwnd:
#return WrapHandle(parent_hwnd)
self._cache["parent"] = WrapHandle(parent_hwnd)
self._cache["parent"] = HwndWrapper(parent_hwnd)
else:
self._cache["parent"] = None
@ -507,7 +534,7 @@ class HwndWrapper(object):
"""
child_windows = handleprops.children(self)
return [WrapHandle(hwnd) for hwnd in child_windows]
return [HwndWrapper(hwnd) for hwnd in child_windows]
#-----------------------------------------------------------
def ControlCount(self):
@ -1023,7 +1050,7 @@ class HwndWrapper(object):
Returns None if there is no owner"""
owner = win32functions.GetWindow(self, win32defines.GW_OWNER)
if owner:
return WrapHandle(owner)
return HwndWrapper(owner)
else:
return None
@ -1275,7 +1302,7 @@ class HwndWrapper(object):
if not ret:
return None
return WrapHandle(gui_info.hwndFocus)
return HwndWrapper(gui_info.hwndFocus)
#-----------------------------------------------------------
def SetFocus(self):
@ -1535,7 +1562,7 @@ def GetDialogPropsFromHandle(hwnd):
controls = [hwnd, ]
controls.extend(hwnd.Children())
except AttributeError:
controls = [WrapHandle(hwnd), ]
controls = [HwndWrapper(hwnd), ]
# add all the children of the dialog
controls.extend(controls[0].Children())

@ -23,7 +23,14 @@
__revision__ = "$Revision$"
from HwndWrapper import GetDialogPropsFromHandle
from wraphandle import WrapHandle
# make an alias for the HwndWrapper object as WrapHandle
from HwndWrapper import HwndWrapper as WrapHandle
# import the control clases - this will register the classes they
# contain
import common_controls
import win32_controls
#
##====================================================================

@ -175,8 +175,9 @@ class ListViewWrapper(HwndWrapper.HwndWrapper):
#-----------------------------------------------------------
def GetHeaderControl(self):
"Returns the Header control associated with the ListView"
import wraphandle
return wraphandle.WrapHandle(
#from wraphandle import WrapHandle
#from HwndWrapper import WrapHandle
return HwndWrapper.HwndWrapper(
self.SendMessage(win32defines.LVM_GETHEADER))
#-----------------------------------------------------------
@ -398,7 +399,12 @@ class ListViewWrapper(HwndWrapper.HwndWrapper):
#-----------------------------------------------------------
def _modify_selection(self, item, to_select):
""
"""Change the selection of the item
item is the item you want to chagne
to_slect shoudl be tru to select the item and false
to deselect the item
"""
self.VerifyActionable()
@ -1809,9 +1815,10 @@ class UpDownWrapper(HwndWrapper.HwndWrapper):
def GetBuddyControl(self):
"Get the buddy control of the updown control"
import wraphandle
#from wraphandle import WrapHandle
#from HwndWrapper import WrapHandle
buddy_handle = self.SendMessage(win32defines.UDM_GETBUDDY)
return wraphandle.WrapHandle(buddy_handle)
return HwndWrapper.HwndWrapper(buddy_handle)
def SetValue(self, new_pos):
"Set the value of the of the UpDown control to some integer value"

@ -1,126 +0,0 @@
# GUI Application automation and testing library
# Copyright (C) 2006 Mark Mc Mahon
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1
# of the License, or (at your option) any later version.
#
# This library 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc.,
# 59 Temple Place,
# Suite 330,
# Boston, MA 02111-1307 USA
"Collect the wrapping classes and respond to request to wrap handles"
import re
import win32_controls
import common_controls
from pywinauto import handleprops
__revision__ = "$Revision $"
#====================================================================
# get all the classes/functions from win32_contols
_all_classes = win32_controls.__dict__.values()
# and add all the classes/functinos from common_controls
_all_classes.extend(common_controls.__dict__.values())
_wrapper_info = {}
# Many thanks to Stefaan Himpe for suggesting the wrapper cache
# it saves a lot of time because there are really not that many
# registered window classes so it doesn't make sense to search
# from scratch for every window!.
_wrapper_cache = {}
for item in _all_classes:
try:
for classname_ in item.windowclasses:
# set the info
_wrapper_info[classname_] = (
re.compile(classname_),
item)
_wrapper_cache[classname_] = item
# needed to add KeyError so that Pudge could
# generate the documentation
except (KeyError, AttributeError), e:
pass
def _find_wrapper(class_name):
"""return the wrapper that handles this classname
If there is no match found then return None.
"""
try:
# Optimization - return the item from the cache if it exists
# in the cache
return _wrapper_cache[class_name]
# Optimization - then check if the control name matches
# exactly before trying a re.match (and add it to the cache)
#if classname in _wrapper_info:
# _wrapper_cache[classname] = _wrapper_info[classname][1]
# return _wrapper_info[classname][1]
except KeyError:
wrapper_match = None
for regex, wrapper in _wrapper_info.values():
if regex.match(class_name):
wrapper_match = wrapper
# save this classname - wrapper match for later
# There are not so many classnames registerd usually so this saves
# time
_wrapper_cache[class_name] = wrapper_match
# return the wrapper that matched
return wrapper_match
#====================================================================
def WrapHandle(hwnd):
"""Return the hwnd wrapped with the correct wraper
Wrapper is chosen on the Class of the control
"""
from HwndWrapper import HwndWrapper
class_name = handleprops.classname(hwnd)
_needs_image = False
wrapper = _find_wrapper(class_name)
if wrapper is None:
# yet another optimization to not call this function too often
is_top_level_win = handleprops.is_toplevel_window(hwnd)
if is_top_level_win:
wrapper = win32_controls.DialogWrapper
else:
wrapper = HwndWrapper
if not is_top_level_win:
_needs_image = True
wrapped_hwnd = wrapper(hwnd)
if _needs_image:
wrapped_hwnd._NeedsImageProp = True
return wrapped_hwnd

@ -68,13 +68,16 @@ def find_window(**kwargs):
#for w in windows:
# print "ambig", handleprops.classname(w), \
# handleprops.text(w), handleprops.processid(w)
raise WindowAmbiguousError(
exception = WindowAmbiguousError(
"There are %d windows that match the criteria %s"% (
len(windows),
unicode(kwargs),
)
)
exception.windows = windows
raise exception
return windows[0]
#=========================================================================
@ -173,6 +176,7 @@ def find_windows(class_name = None,
windows = [WrapHandle(win) for win in windows]
windows = findbestmatch.find_best_control_matches(
best_match, windows)
# convert window back to handle
windows = [win.handle for win in windows]
if predicate_func is not None and windows:

@ -229,7 +229,7 @@ class HwndWrapperTests(unittest.TestCase):
def testIsChild(self):
self.assertEqual(self.ctrl.IsChild(self.dlg.ctrl_()), True)
self.assertEqual(self.ctrl.IsChild(self.dlg.WrapperObject()), True)
self.assertEqual(self.dlg.IsChild(self.ctrl), False)

@ -430,14 +430,14 @@ class WindowSpecificationTestCases(unittest.TestCase):
def testCtrl(self):
def testWrapperObject(self):
"Test that we can get a control "
from pywinauto.controls import HwndWrapper
self.assertEquals(True, isinstance(self.dlgspec, WindowSpecification))
self.assertEquals(
True,
isinstance(self.dlgspec.ctrl_(), HwndWrapper.HwndWrapper)
isinstance(self.dlgspec.WrapperObject(), HwndWrapper.HwndWrapper)
)
def testWindow(self):
@ -517,33 +517,33 @@ class WindowSpecificationTestCases(unittest.TestCase):
allowable_error = .02
start = time.time()
self.assertEqual(self.dlgspec.ctrl_(), self.dlgspec.Wait("enaBleD "))
self.assertEqual(self.dlgspec.WrapperObject(), self.dlgspec.Wait("enaBleD "))
time_taken = (time.time() - start)
if not 0 <= time_taken < (0 + allowable_error):
self.assertEqual(.02, time_taken)
start = time.time()
self.assertEqual(self.dlgspec.ctrl_(), self.dlgspec.Wait(" ready"))
self.assertEqual(self.dlgspec.WrapperObject(), self.dlgspec.Wait(" ready"))
self.assertEqual(True, 0 <= (time.time() - start) < 0 + allowable_error)
start = time.time()
self.assertEqual(self.dlgspec.ctrl_(), self.dlgspec.Wait(" exiSTS"))
self.assertEqual(self.dlgspec.WrapperObject(), self.dlgspec.Wait(" exiSTS"))
self.assertEqual(True, 0 <= (time.time() - start) < 0 + allowable_error)
start = time.time()
self.assertEqual(self.dlgspec.ctrl_(), self.dlgspec.Wait(" VISIBLE "))
self.assertEqual(self.dlgspec.WrapperObject(), self.dlgspec.Wait(" VISIBLE "))
self.assertEqual(True, 0 <= (time.time() - start) < 0 + allowable_error)
start = time.time()
self.assertEqual(self.dlgspec.ctrl_(), self.dlgspec.Wait(" ready enabled"))
self.assertEqual(self.dlgspec.WrapperObject(), self.dlgspec.Wait(" ready enabled"))
self.assertEqual(True, 0 <= (time.time() - start) < 0 + allowable_error)
start = time.time()
self.assertEqual(self.dlgspec.ctrl_(), self.dlgspec.Wait("visible exists "))
self.assertEqual(self.dlgspec.WrapperObject(), self.dlgspec.Wait("visible exists "))
self.assertEqual(True, 0 <= (time.time() - start) < 0 + allowable_error)
start = time.time()
self.assertEqual(self.dlgspec.ctrl_(), self.dlgspec.Wait("exists "))
self.assertEqual(self.dlgspec.WrapperObject(), self.dlgspec.Wait("exists "))
self.assertEqual(True, 0 <= (time.time() - start) < 0 + allowable_error)

@ -75,7 +75,7 @@ class ListViewTestCases(unittest.TestCase):
self.app = app
self.dlg = app.MicrosoftControlSpy #top_window_()
self.ctrl = app.MicrosoftControlSpy.ListView.ctrl_()
self.ctrl = app.MicrosoftControlSpy.ListView.WrapperObject()
#self.dlg.MenuSelect("Styles")
@ -290,7 +290,7 @@ class TreeViewTestCases(unittest.TestCase):
self.app = app
self.dlg = app.MicrosoftControlSpy #top_window_()
self.ctrl = app.MicrosoftControlSpy.TreeView.ctrl_()
self.ctrl = app.MicrosoftControlSpy.TreeView.WrapperObject()
#self.dlg.MenuSelect("Styles")
@ -375,7 +375,7 @@ class HeaderTestCases(unittest.TestCase):
RECT(180, 0, 260, 21)]
self.app = app
self.dlg = app.MicrosoftControlSpy
self.ctrl = app.MicrosoftControlSpy.Header.ctrl_()
self.ctrl = app.MicrosoftControlSpy.Header.WrapperObject()
def tearDown(self):
@ -449,7 +449,7 @@ class StatusBarTestCases(unittest.TestCase):
RECT(92, 2, 264, 20)]
self.app = app
self.dlg = app.MicrosoftControlSpy
self.ctrl = app.MicrosoftControlSpy.StatusBar.ctrl_()
self.ctrl = app.MicrosoftControlSpy.StatusBar.WrapperObject()
#self.dlg.MenuSelect("Styles")
@ -566,7 +566,7 @@ class TabControlTestCases(unittest.TestCase):
self.app = app
self.dlg = app.MicrosoftControlSpy
self.ctrl = app.MicrosoftControlSpy.TabControl.ctrl_()
self.ctrl = app.MicrosoftControlSpy.TabControl.WrapperObject()
#self.dlg.MenuSelect("Styles")
@ -681,7 +681,7 @@ class ToolbarTestCases(unittest.TestCase):
self.app = app
self.dlg = app.MicrosoftControlSpy
self.ctrl = app.MicrosoftControlSpy.Toolbar.ctrl_()
self.ctrl = app.MicrosoftControlSpy.Toolbar.WrapperObject()
#self.dlg.MenuSelect("Styles")
@ -757,7 +757,7 @@ class RebarTestCases(unittest.TestCase):
self.app = app
self.dlg = app.MicrosoftControlSpy
self.ctrl = app.MicrosoftControlSpy.Rebar.ctrl_()
self.ctrl = app.MicrosoftControlSpy.Rebar.WrapperObject()
#self.dlg.MenuSelect("Styles")
@ -892,7 +892,7 @@ class UpDownTestCases(unittest.TestCase):
self.app = app
self.dlg = app.MicrosoftControlSpy
self.ctrl = app.MicrosoftControlSpy.UpDown2.ctrl_()
self.ctrl = app.MicrosoftControlSpy.UpDown2.WrapperObject()
#self.dlg.MenuSelect("Styles")

@ -150,7 +150,7 @@ class ComboBoxTestCases(unittest.TestCase):
self.app.UntitledNotepad.MenuSelect("Format->Font")
self.ctrl = self.app.Font.ComboBox2.ctrl_()
self.ctrl = self.app.Font.ComboBox2.WrapperObject()
def tearDown(self):
@ -257,7 +257,7 @@ class ListBoxTestCases(unittest.TestCase):
#pdb.set_trace()
self.dlg = self.app.DateAndTime
self.ctrl = self.dlg.ListBox.ctrl_()
self.ctrl = self.dlg.ListBox.WrapperObject()
def tearDown(self):
"Close the application after tests"
@ -339,7 +339,7 @@ class EditTestCases(unittest.TestCase):
self.app = app
self.dlg = app.UntitledNotepad
self.ctrl = self.dlg.Edit.ctrl_()
self.ctrl = self.dlg.Edit.WrapperObject()
self.old_pos = self.dlg.Rectangle
@ -514,7 +514,7 @@ class PopupMenuTestCases(unittest.TestCase):
self.app.start_("notepad.exe")
self.app.Notepad.Edit.RightClick()
self.popup = self.app.PopupMenu.ctrl_()
self.popup = self.app.PopupMenu.WrapperObject()
def tearDown(self):
"Close the application after tests"

@ -1,65 +0,0 @@
# GUI Application automation and testing library
# Copyright (C) 2006 Mark Mc Mahon
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1
# of the License, or (at your option) any later version.
#
# This library 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc.,
# 59 Temple Place,
# Suite 330,
# Boston, MA 02111-1307 USA
"Tests for application.py"
__revision__ = "$Revision: 234 $"
import unittest
from pywinauto.controls.wraphandle import *
#class ApplicationTestCases(unittest.TestCase):
# "Unit tests for the ListViewWrapper class"
#
# def setUp(self):
# """Start the application set some data and ensure the application
# is in the state we want it."""
# pass
#
# def tearDown(self):
# "Close the application after tests"
# # close the application
# #self.dlg.SendMessage(win32defines.WM_CLOSE)
# pass
#
# def testNotConnected(self):
# "Make sure the friendly class is set correctly"
# self.assertRaises (AppNotConnected, Application().__getattr__, 'Hiya')
# self.assertRaises (AppNotConnected, Application().__getitem__, 'Hiya')
# self.assertRaises (AppNotConnected, Application().window_, title = 'Hiya')
# self.assertRaises (AppNotConnected, Application().top_window_,)
#
# def testStartProplem(self):
# "Make sure the friendly class is set correctly"
# self.assertRaises (AppStartError, Application().start_, 'Hiya')
#
# #def testStartProplem(self):
# # "Make sure the friendly class is set correctly"
# # self.assertRaises (AppStartError, Application().start_, 'Hiya')
#
if __name__ == "__main__":
#_unittests()
unittest.main()

@ -7,6 +7,7 @@ import sys
from pywinauto.timings import Timings
Timings.Fast()
excludes = ['test_sendkeys']
def run_tests():
testfolder = os.path.abspath(os.path.split(__file__)[0])
@ -21,7 +22,9 @@ def run_tests():
file.startswith('test_') and
file.endswith('.py')]
test_modules = [mod for mod in test_modules if mod.lower() not in excludes]
for mod in test_modules:
#globals().update(__import__(mod, globals(), locals()).__dict__)
# import it
imported_mod = __import__(mod, globals(), locals())