diff --git a/CHANGELOG.md b/CHANGELOG.md index fe74600..8fc198d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ## [Unreleased][] +### Added + +- Python.Net 3.0 Support + +### Fixxed + +- Converter bugfix for wrong value convert +- Tree module refactoring + ## [Release][1.6.6] [1.6.6][1.6.5-1.6.6] - 2021-09-01 ### Added diff --git a/src/FlaUILibrary/flaui/module/tree.py b/src/FlaUILibrary/flaui/module/tree.py index a76c12e..db1433b 100644 --- a/src/FlaUILibrary/flaui/module/tree.py +++ b/src/FlaUILibrary/flaui/module/tree.py @@ -4,6 +4,7 @@ from FlaUILibrary.flaui.interface import (ModuleInterface, ValueContainer) from FlaUILibrary.flaui.util.treeitems import TreeItems from FlaUILibrary.flaui.util.converter import Converter +from FlaUILibrary.flaui.util.treeitemaction import TreeItemAction class Tree(ModuleInterface): @@ -107,23 +108,23 @@ def execute_action(self, action: Action, values: Container): self.Action.GET_ROOT_ITEMS_COUNT: lambda: values["element"].Items.Length, self.Action.EXPAND_ALL: - lambda: self._expand_all_treetems(values["element"]), + lambda: TreeItems.expand_all_tree_nodes(values["element"].Items), self.Action.COLLAPSE_ALL: - lambda: self._collapse_all_treetems(values["element"]), + lambda: TreeItems.collapse(values["element"].Items), self.Action.GET_VISIBLE_ITEMS_NAMES: - lambda: self._get_every_visible_treeitems_name(values["element"]), + lambda: TreeItems.get_all_names_from_tree_nodes(values["element"].Items), self.Action.GET_VISIBLE_ITEMS_COUNT: - lambda: self._get_every_visible_treeitems_count(values["element"]), + lambda: TreeItems.get_visible_leaf_count(values["element"].Items), self.Action.ITEM_SHOULD_BE_VISIBLE: lambda: self._should_be_visible(values["element"], values["item"]), self.Action.SELECT_ITEM_BY_NAME: - lambda: self._select_by_name(values["element"], values["item"]), + lambda: TreeItems.select_visible_node_by_name(values["element"].Items, values["item"]), self.Action.SELECT_ITEM: - lambda: self._select(values["element"], values["item"]), + lambda: TreeItems.execute_by_location(values["element"].Items, values["item"], TreeItemAction.SELECT), self.Action.EXPAND_ITEM: - lambda: self._expand(values["element"], values["item"]), + lambda: TreeItems.execute_by_location(values["element"].Items, values["item"], TreeItemAction.EXPAND), self.Action.COLLAPSE_ITEM: - lambda: self._collapse(values["element"], values["item"]), + lambda: TreeItems.execute_by_location(values["element"].Items, values["item"], TreeItemAction.COLLAPSE), self.Action.SELECTED_ITEM_SHOULD_BE: lambda: self._selected_item_should_be(values["element"], values["item"]), self.Action.GET_SELECTED_ITEMS_NAME: @@ -132,57 +133,10 @@ def execute_action(self, action: Action, values: Container): return switcher.get(action, lambda: FlaUiError.raise_fla_ui_error(FlaUiError.ActionNotSupported))() - @staticmethod - def _get_every_visible_treeitems_name(control: Any): - """ - Counts every visible tree item. - - Args: - control (Object): Tree control element from FlaUI. - - Returns: - None. - """ - obj = TreeItems(control) - return obj.get_every_visible_treeitems_name() - - @staticmethod - def _get_every_visible_treeitems_count(control: Any): - """ - Counts every visible tree item. - - Args: - control (Object): Tree control element from FlaUI. - - Returns: - None. - """ - - obj = TreeItems(control) - obj.get_every_visible_treeitems_name() - return obj.treeitems_count - - @staticmethod - def _get_selected_item(control: Any): - """ - Try to get all selected items as a list. - - Args: - control (Object): Treeview control to select item from. - - Returns: - The selected Tree Item object. - """ - obj = TreeItems(control) - selected = obj.selected_treeitem - if not selected: - raise FlaUiError(FlaUiError.NoItemSelected) - return selected - @staticmethod def _should_be_visible(control: Any, name: str): """ - Checks if Tree contains an given item by name. + Checks if Tree contains a given item by name. Args: control (Object): Tree control element from FlaUI. @@ -191,99 +145,9 @@ def _should_be_visible(control: Any, name: str): Returns: True if name from combobox item exists otherwise False. """ - names = Tree._get_every_visible_treeitems_name(control) - if name not in names: + if name not in TreeItems.get_all_names_from_tree_nodes(control.Items): raise FlaUiError(FlaUiError.ElementNotVisible.format(name)) - @staticmethod - def _expand_all_treetems(control: Any): - """ - Expand all tree items. - - Args: - control (Object): Tree control element from FlaUI. - - Returns: - None. - """ - obj = TreeItems(control) - obj.expand_all_treeitems() - - @staticmethod - def _collapse_all_treetems(control: Any): - """ - Collapse all tree items. - - Args: - control (Object): Tree control element from FlaUI. - - Returns: - None. - """ - TreeItems(control).collapse() - - @staticmethod - def _select_by_name(control: Any, name: str): - """ - Try to select element from given name. - - Args: - control (Object): Tree control UI object. - name (String): Name from item to select - - Raises: - FlaUiError: If value can not be found by element. - """ - obj = TreeItems(control) - obj.select_visible_treeitem_by_name(name) - - @staticmethod - def _select(control: Any, location: str): - """ - Try to select element from given parameter. - - Args: - control (Object): Tree control UI object. - location (String): series of pointers, which shows the item's location. - Example: - Location = "N:nameofitem1->N:nameofitem2->I:indexofitem2 - - Raises: - FlaUiError: If value can not be found by control. - """ - obj = TreeItems(control) - obj.execute_by_location(location, "Select") - - @staticmethod - def _expand(control: Any, location: str): - """ - Try to expand element from given parameter. - - Args: - control (Object): Tree control UI object. - location (String): series of pointers, which shows the item's location. - - Raises: - FlaUiError: If value can not be found by control. - """ - obj = TreeItems(control) - obj.execute_by_location(location, "Expand") - - @staticmethod - def _collapse(control: Any, location: str): - """ - Try to collapse element from given parameter. - - Args: - control (Object): Tree control UI object. - location (String): series of pointers, which shows the item's location. - - Raises: - FlaUiError: If value can not be found by control. - """ - obj = TreeItems(control) - obj.execute_by_location(location, "Collapse") - @staticmethod def _get_selected_items_name(control: Any): """ @@ -292,8 +156,11 @@ def _get_selected_items_name(control: Any): Args: control (Object): Tree control UI object. """ - name = Tree._get_selected_item(control).Name - return name + selected = control.SelectedTreeItem + if not selected: + raise FlaUiError(FlaUiError.NoItemSelected) + + return selected.Name @staticmethod def _selected_item_should_be(control: Any, item: str): diff --git a/src/FlaUILibrary/flaui/util/__init__.py b/src/FlaUILibrary/flaui/util/__init__.py index cf8f49a..c2de7c6 100644 --- a/src/FlaUILibrary/flaui/util/__init__.py +++ b/src/FlaUILibrary/flaui/util/__init__.py @@ -1,3 +1,4 @@ from .keyboardinputconverter import KeyboardInputConverter from .treeitems import TreeItems +from .treeitemaction import TreeItemAction from .treeitemsparser import TreeItemsParser diff --git a/src/FlaUILibrary/flaui/util/converter.py b/src/FlaUILibrary/flaui/util/converter.py index 29fa992..67fcc40 100644 --- a/src/FlaUILibrary/flaui/util/converter.py +++ b/src/FlaUILibrary/flaui/util/converter.py @@ -20,7 +20,10 @@ def cast_to_int(value: Any, error_msg=None): error_msg (String) : Custom error message """ try: - return None if not value else int(value) + if value is None: + return None + + return int(value) except ValueError: if error_msg is None: error_msg = FlaUiError.ValueShouldBeANumber.format(value) @@ -31,18 +34,26 @@ def cast_to_int(value: Any, error_msg=None): def cast_to_string(value: Any): """ Helper to cast value as string. + If value is None empty string will be returned. Args: value (Object): Value to convert """ - return "" if not value else str(value) + if value is None: + return "" + + return str(value) @staticmethod def cast_to_bool(value: Any): """ Helper to cast value as bool. + If value is None False will be returned. Args: value (Object): Value to convert """ - return "" if not value else bool(value) + if value is None: + return False + + return bool(value) diff --git a/src/FlaUILibrary/flaui/util/treeitemaction.py b/src/FlaUILibrary/flaui/util/treeitemaction.py new file mode 100644 index 0000000..7480113 --- /dev/null +++ b/src/FlaUILibrary/flaui/util/treeitemaction.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class TreeItemAction(Enum): + """ + Enumeration class for supported tree item actions by syntax usage from tree selection. + """ + EXPAND = "Expand" + COLLAPSE = "Collapse" + SELECT = "Select" diff --git a/src/FlaUILibrary/flaui/util/treeitems.py b/src/FlaUILibrary/flaui/util/treeitems.py index 7c99445..28a7909 100644 --- a/src/FlaUILibrary/flaui/util/treeitems.py +++ b/src/FlaUILibrary/flaui/util/treeitems.py @@ -1,139 +1,155 @@ from typing import Any +from System import InvalidOperationException # pylint: disable=import-error +from FlaUI.Core.Definitions import ExpandCollapseState # pylint: disable=import-error from FlaUILibrary.flaui.exception import FlaUiError +from FlaUILibrary.flaui.util.treeitemaction import TreeItemAction from FlaUILibrary.flaui.util.treeitemsparser import TreeItemsParser class TreeItems: """ - A helper class for Tree control. - Every tree consist of tree items or nodes this class represesents those sub items of tree control. + A helper class for tree control. """ - def __init__(self,control): - self.control = control - self.treeitems = control.Items - self.current_treeitem = None - self.selected_treeitem = self.control.SelectedTreeItem - self.treeitems_name = [] - self.treeitems_count = 0 - self.location = [] - - def get_every_visible_treeitems_name(self): + + @staticmethod + def get_visible_leaf_count(nodes: Any): """ - This function reterns a list of every visible node in tree. - It iterates the given tree and adds the names of the tree items to self.treeitems_name - and the total count of them to self.treeitems_count + Get count from all visible nodes which are visible. + + Args: + nodes (Object): TreeItems[] from current node + + Returns: + Count from all visible nodes """ - for item in self.treeitems: - state = item.ExpandCollapseState - self.current_treeitem = item - self.treeitems_name.append(self.current_treeitem.Name) - self.treeitems_count +=1 - - #The element is Expanded All children are visible. - if state == 1: - self.treeitems = item.Items - self.get_every_visible_treeitems_name() - #The element is PartiallyExpanded Some, but not all, children are visible.. - elif state == 2: - self.treeitems = item.Items - self.get_every_visible_treeitems_name() - #The element is LeafNode does not expand or collapse. - elif state == 3: - continue - #The element is Collapsed No children are visible. - elif state == 0: - continue - return self.treeitems_name - - def select_visible_treeitem_by_name(self, name: Any): + node_count = nodes.Length + for node in nodes: + if node.ExpandCollapseState in (ExpandCollapseState.Expanded, ExpandCollapseState.PartiallyExpanded): + node_count += TreeItems.get_visible_leaf_count(node.Items) + + return node_count + + @staticmethod + def expand_all_tree_nodes(nodes: Any): """ - This function selects a tree item with the given name in tree - if item not found a flauierror will be thrown. + Expand all tree nodes. + + Args: + nodes (Object): TreeItems[] from current node """ - for item in self.treeitems: - state = item.ExpandCollapseState - self.current_treeitem = item - if self.current_treeitem.Name == name: - self.current_treeitem.Select() - self.treeitems_name.append(self.current_treeitem.Name) - #The element is Expanded All children are visible. - if state == 1: - self.treeitems = item.Items - self.select_visible_treeitem_by_name(name) - #The element is PartiallyExpanded Some, but not all, children are visible.. - elif state == 2: - self.treeitems = item.Items - self.select_visible_treeitem_by_name(name) - #The element is Collapsed No children are visible. - elif state == 0: - continue - #The element is LeafNode does not expand or collapse. - elif state == 3: - continue - if not self.treeitems_name: - raise FlaUiError(FlaUiError.ElementNameNotFound.format(name)) - return True + for node in nodes: + if node.ExpandCollapseState in (ExpandCollapseState.Expanded, ExpandCollapseState.Collapsed): + node.Expand() + TreeItems.expand_all_tree_nodes(node.Items) - def expand_all_treeitems(self): + @staticmethod + def collapse(nodes: Any): """ - This function expands every expandable tree item in tree + Collapses every collapsable tree item in root level. + + Args: + nodes (Object): TreeItems[] from current node """ - for item in self.treeitems: - state = item.ExpandCollapseState - self.current_treeitem = item - #The element is PartiallyExpanded Some, but not all, children are visible.. - if state == 2: - self.current_treeitem.Expand() - self.treeitems = item.Items - self.expand_all_treeitems() - #The element is Collapsed No children are visible. - elif state == 0: - self.current_treeitem.Expand() - self.treeitems = item.Items - self.expand_all_treeitems() - #The element is LeafNode does not expand or collapse. - elif state == 3: - continue - #The element is Expanded All children are visible. - elif state == 1: - continue - return True - - def execute_by_location(self, location: Any, exec_func: Any): + for node in nodes: + if node.ExpandCollapseState in (ExpandCollapseState.Expanded, ExpandCollapseState.PartiallyExpanded): + node.Collapse() + + @staticmethod + def get_all_names_from_tree_nodes(nodes: Any): + """ + Get all names from all visible nodes. + + Args: + nodes (Object): TreeItems[] from current node + + Returns: + List from all node names. """ - This function executes the given exec_func function to the last element in location - after iterating the whole location through. - The given location will be parsed with the help of TreeItemsParser + names = [] + + for node in nodes: + names.append(node.Name) + if node.ExpandCollapseState in (ExpandCollapseState.Expanded, ExpandCollapseState.PartiallyExpanded): + names.extend(TreeItems.get_all_names_from_tree_nodes(node.Items)) + + return names + + @staticmethod + def select_visible_node_by_name(nodes: Any, name: str): + """ + Selects a tree item with the given name in tree + + Args: + nodes (Object): TreeItems[] from current node + name (String): Name to search on node. + + Raises: + FlaUiError: If node by a given name could not be found. + """ + if not TreeItems._find_visible_node_by_name(nodes, name): + raise FlaUiError(FlaUiError.ElementNameNotFound.format(name)) + + @staticmethod + def execute_by_location(nodes: Any, location: str, action: TreeItemAction): + """ + Executes the given TreeItemAction to the last element from a tree location. + + Args: + nodes (Object): TreeItems[] from current node + location (String): Location string to execute operations on nodes. + action (TreeItemAction) : Action to operate on node. + + Raises: + FlaUiError: If action is not supported. + FlaUiError: If location syntax is wrong. + FlaUiError: If node is not expandable. """ parser = TreeItemsParser(location) + current_nodes = nodes + for index in range(len(parser.location)): - self.current_treeitem = parser.get_treeitem(self.treeitems, index) + node = parser.get_treeitem(current_nodes, index) if parser.is_last_element(index): - function = "self.current_treeitem." + exec_func + "()" try: - # proved if the exec_func string is valid - if exec_func == "Expand": - self.current_treeitem.Expand() - elif exec_func == "Collapse": - self.current_treeitem.Collapse() - elif exec_func == "Select": - self.current_treeitem.Select() + if action == TreeItemAction.EXPAND: + node.Expand() + elif action == TreeItemAction.COLLAPSE: + node.Collapse() + elif action == TreeItemAction.SELECT: + node.Select() except ValueError: - raise FlaUiError(FlaUiError.FalseSyntax.format(function)) from None - except Exception as ex: - if ex.__class__.__name__=="InvalidOperationException": - raise FlaUiError(FlaUiError.ElementNotExpandable.format(self.current_treeitem.Name)) from None - raise FlaUiError(FlaUiError.FalseSyntax.format(function)) from None + raise FlaUiError(FlaUiError.FalseSyntax.format( + "self.current_treeitem." + action.value + "()")) from None + except InvalidOperationException: + raise FlaUiError(FlaUiError.ElementNotExpandable.format(node.Name)) from None + except Exception: + raise FlaUiError(FlaUiError.FalseSyntax.format( + "self.current_treeitem." + action.value + "()")) from None else: - if self.current_treeitem.ExpandCollapseState == 3: - raise FlaUiError(FlaUiError.ElementNotExpandable.format(self.current_treeitem.Name)) - self.current_treeitem.Expand() - self.treeitems = self.current_treeitem.Items + if node.ExpandCollapseState == ExpandCollapseState.LeafNode: + raise FlaUiError(FlaUiError.ElementNotExpandable.format(node.Name)) + node.Expand() + current_nodes = node.Items - def collapse(self): + @staticmethod + def _find_visible_node_by_name(nodes: Any, name: str): """ - This function collapses every collapsable tree item in root level. + Finds if a node is visible by a given name. + + Args: + nodes (Object): TreeItems[] from current node + name (String): Name from node to search. + + Returns: + True if name was found on any visible node level otherwise False. """ - for item in self.treeitems: - if item.ExpandCollapseState in (1, 2): - item.Collapse() + for node in nodes: + if node.Name == name: + node.Select() + return True + + if node.ExpandCollapseState in (ExpandCollapseState.Expanded, ExpandCollapseState.PartiallyExpanded): + if TreeItems._find_visible_node_by_name(node.Items, name): + return True + + return False diff --git a/src/FlaUILibrary/pythonnetwrapper.py b/src/FlaUILibrary/pythonnetwrapper.py index 25507a4..0102e1f 100644 --- a/src/FlaUILibrary/pythonnetwrapper.py +++ b/src/FlaUILibrary/pythonnetwrapper.py @@ -1,4 +1,6 @@ # pylint: disable=c-extension-no-member +# pylint: disable=no-member + import os import clr