当前位置:   article > 正文

pywinauto核心代码理解_raise elementnotfounderror(kwargs)

raise elementnotfounderror(kwargs)
  1. def __getattribute__(self, attr_name):
  2. """
  3. Attribute access for this class
  4. If we already have criteria for both dialog and control then
  5. resolve the control and return the requested attribute.
  6. If we have only criteria for the dialog but the attribute
  7. requested is an attribute of DialogWrapper then resolve the
  8. dialog and return the requested attribute.
  9. Otherwise delegate functionality to :func:`__getitem__` - which
  10. sets the appropriate criteria for the control.
  11. """
  12. allow_magic_lookup = object.__getattribute__(self, "allow_magic_lookup") # Beware of recursions here!
  13. if not allow_magic_lookup:
  14. try:
  15. return object.__getattribute__(self, attr_name)
  16. except AttributeError:
  17. wrapper_object = self.wrapper_object() # 这里是重点,需要看对应函数的实现代码
  18. try:
  19. return getattr(wrapper_object, attr_name)
  20. except AttributeError:
  21. message = (
  22. 'Attribute "%s" exists neither on %s object nor on'
  23. 'targeted %s element wrapper (typo? or set allow_magic_lookup to True?)' %
  24. (attr_name, self.__class__, wrapper_object.__class__))
  25. raise AttributeError(message)
  26. if attr_name in ['__dict__', '__members__', '__methods__', '__class__', '__name__']:
  27. return object.__getattribute__(self, attr_name)
  28. if attr_name in dir(self.__class__):
  29. return object.__getattribute__(self, attr_name)
  30. if attr_name in self.__dict__:
  31. return self.__dict__[attr_name]
  32. # if we already have 2 levels of criteria (dlg, control)
  33. # this third must be an attribute so resolve and get the
  34. # attribute and return it
  35. if len(self.criteria) >= 2: # FIXME - this is surprising
  36. ctrls = self.__resolve_control(self.criteria)
  37. try:
  38. return getattr(ctrls[-1], attr_name)
  39. except AttributeError:
  40. return self.child_window(best_match=attr_name)
  41. else:
  42. # FIXME - I don't get this part at all, why is it win32-specific and why not keep the same logic as above?
  43. # if we have been asked for an attribute of the dialog
  44. # then resolve the window and return the attribute
  45. desktop_wrapper = self.backend.generic_wrapper_class(self.backend.element_info_class())
  46. need_to_resolve = (len(self.criteria) == 1 and hasattr(desktop_wrapper, attr_name))
  47. if hasattr(self.backend, 'dialog_class'):
  48. need_to_resolve = need_to_resolve and hasattr(self.backend.dialog_class, attr_name)
  49. # Probably there is no DialogWrapper for another backend
  50. if need_to_resolve:
  51. ctrls = self.__resolve_control(self.criteria)
  52. return getattr(ctrls[-1], attr_name)
  53. # It is a dialog/control criterion so let getitem
  54. # deal with it
  55. return self[attr_name]
  1. def __get_ctrl(self, criteria_):
  2. """Get a control based on the various criteria"""
  3. # make a copy of the criteria
  4. criteria = [crit.copy() for crit in criteria_]
  5. # find the dialog
  6. if 'backend' not in criteria[0]:
  7. criteria[0]['backend'] = self.backend.name
  8. if self.app is not None:
  9. # find_elements(...) accepts only "process" argument
  10. criteria[0]['process'] = self.app.process
  11. del criteria[0]['app']
  12. dialog = self.backend.generic_wrapper_class(findwindows.find_element(**criteria[0]))
  13. ctrls = []
  14. # if there is only criteria for a dialog then return it
  15. if len(criteria) > 1:
  16. # so there was criteria for a control, add the extra criteria
  17. # that are required for child controls
  18. previous_parent = dialog.element_info
  19. for ctrl_criteria in criteria[1:]:
  20. ctrl_criteria["top_level_only"] = False
  21. if "parent" not in ctrl_criteria:
  22. ctrl_criteria["parent"] = previous_parent
  23. if isinstance(ctrl_criteria["parent"], WindowSpecification):
  24. ctrl_criteria["parent"] = ctrl_criteria["parent"].wrapper_object()
  25. # resolve the control and return it
  26. if 'backend' not in ctrl_criteria:
  27. ctrl_criteria['backend'] = self.backend.name
  28. ctrl = self.backend.generic_wrapper_class(findwindows.find_element(**ctrl_criteria))
  29. previous_parent = ctrl.element_info
  30. ctrls.append(ctrl)
  31. if ctrls:
  32. return (dialog, ) + tuple(ctrls)
  33. else:
  34. return (dialog, )
  35. def __resolve_control(self, criteria, timeout=None, retry_interval=None):
  36. """
  37. Find a control using criteria
  38. * **criteria** - a list that contains 1 or 2 dictionaries
  39. 1st element is search criteria for the dialog
  40. 2nd element is search criteria for a control of the dialog
  41. * **timeout** - maximum length of time to try to find the controls (default 5)
  42. * **retry_interval** - how long to wait between each retry (default .2)
  43. """
  44. if timeout is None:
  45. timeout = Timings.window_find_timeout
  46. if retry_interval is None:
  47. retry_interval = Timings.window_find_retry
  48. try:
  49. ctrl = wait_until_passes(
  50. timeout,
  51. retry_interval,
  52. self.__get_ctrl, # 传入了一个函数接口
  53. (findwindows.ElementNotFoundError,
  54. findbestmatch.MatchError,
  55. controls.InvalidWindowHandle,
  56. controls.InvalidElement),
  57. criteria)
  58. except TimeoutError as e:
  59. raise e.original_exception
  60. return ctrl
  61. def wrapper_object(self):
  62. """Allow the calling code to get the HwndWrapper object"""
  63. ctrls = self.__resolve_control(self.criteria)
  64. return ctrls[-1]
  1. #=========================================================================
  2. def wait_until_passes(timeout,
  3. retry_interval,
  4. func,
  5. exceptions=(Exception),
  6. *args, **kwargs):
  7. """
  8. Wait until ``func(*args, **kwargs)`` does not raise one of the exceptions
  9. * **timeout** how long the function will try the function
  10. * **retry_interval** how long to wait between retries
  11. * **func** the function that will be executed
  12. * **exceptions** list of exceptions to test against (default: Exception)
  13. * **args** optional arguments to be passed to func when called
  14. * **kwargs** optional keyword arguments to be passed to func when called
  15. Returns the return value of the function
  16. If the operation times out then the original exception raised is in
  17. the 'original_exception' attribute of the raised exception.
  18. e.g. ::
  19. try:
  20. # wait a maximum of 10.5 seconds for the
  21. # window to be found in increments of .5 of a second.
  22. # P.int a message and re-raise the original exception if never found.
  23. wait_until_passes(10.5, .5, self.Exists, (ElementNotFoundError))
  24. except TimeoutError as e:
  25. print("timed out")
  26. raise e.
  27. """
  28. start = timestamp()
  29. # keep trying until the timeout is passed
  30. while True:
  31. try:
  32. # Call the function with any arguments
  33. func_val = func(*args, **kwargs)
  34. # if no exception is raised then we are finished
  35. break
  36. # An exception was raised - so wait and try again
  37. except exceptions as e:
  38. # find out how much of the time is left
  39. time_left = timeout - (timestamp() - start)
  40. # if we have to wait some more
  41. if time_left > 0:
  42. # wait either the retry_interval or else the amount of
  43. # time until the timeout expires (whichever is less)
  44. time.sleep(min(retry_interval, time_left))
  45. else:
  46. # Raise a TimeoutError - and put the original exception
  47. # inside it
  48. err = TimeoutError()
  49. err.original_exception = e
  50. raise err
  51. # return the function value
  52. return func_val
  1. #=========================================================================
  2. def find_element(**kwargs):
  3. """
  4. Call find_elements and ensure that only one element is returned
  5. Calls find_elements with exactly the same arguments as it is called with
  6. so please see :py:func:`find_elements` for the full parameters description.
  7. """
  8. elements = find_elements(**kwargs)
  9. if not elements:
  10. raise ElementNotFoundError(kwargs)
  11. if len(elements) > 1:
  12. exception = ElementAmbiguousError(
  13. "There are {0} elements that match the criteria {1}".format(
  14. len(elements),
  15. six.text_type(kwargs),
  16. )
  17. )
  18. exception.elements = elements
  19. raise exception
  20. return elements[0]

以下是我的理解:
1. 通过child_window()无条件的返回了一个pywinauto.application.WindowSpecification对象,这个对象只是封装了对应的查找条件,拿着这个返回对象还不能知道是否成功查找到窗口;

2. WindowSpecification对象获取其wapper_object()时才开始真正查找。wrapper_object() -> _resolve_control() -> wait_until_passes() -> _get_ctrl() -> findwindows.find_element()
3. wait_until_passes()中使用了总超时时间和重试间隔,当总时间超时时会抛出Timeout异常。如果__get_ctrl()返回了正常值就立即返回;
4.wait_until_passes会捕获_resolve_control()中指定的(findwindows.ElementNotFoundError,
                 findbestmatch.MatchError,
                 controls.InvalidWindowHandle,
                 controls.InvalidElement)几种类型的异常,当出现这些异常时会继续进行重试。
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/121325
推荐阅读
相关标签
  

闽ICP备14008679号