From 7e9e461623e4acc5d275539d22c3d770f2b27a75 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Fri, 8 Nov 2019 19:57:37 +0300 Subject: [PATCH] remove carbage --- Robot/build/lib/pyOpenRPA/Clipboard.py | 22 - Robot/build/lib/pyOpenRPA/GUI.py | 1210 ----------------- .../lib/pyOpenRPA/IntegrationOrchestrator.py | 46 - Robot/build/lib/pyOpenRPA/JSONNormalize.py | 83 -- .../lib/pyOpenRPA/ProcessCommunicator.py | 143 -- Robot/build/lib/pyOpenRPA/Robot.py | 158 --- Robot/build/lib/pyOpenRPA/ValueVerify.py | 21 - Robot/build/lib/pyOpenRPA/Window.py | 13 - Robot/build/lib/pyOpenRPA/__init__.py | 15 - Robot/dist/pyOpenRPA-1.0.15-py3-none-any.whl | Bin 24825 -> 0 bytes Robot/dist/pyOpenRPA-1.0.15.tar.gz | Bin 22828 -> 0 bytes 11 files changed, 1711 deletions(-) delete mode 100644 Robot/build/lib/pyOpenRPA/Clipboard.py delete mode 100644 Robot/build/lib/pyOpenRPA/GUI.py delete mode 100644 Robot/build/lib/pyOpenRPA/IntegrationOrchestrator.py delete mode 100644 Robot/build/lib/pyOpenRPA/JSONNormalize.py delete mode 100644 Robot/build/lib/pyOpenRPA/ProcessCommunicator.py delete mode 100644 Robot/build/lib/pyOpenRPA/Robot.py delete mode 100644 Robot/build/lib/pyOpenRPA/ValueVerify.py delete mode 100644 Robot/build/lib/pyOpenRPA/Window.py delete mode 100644 Robot/build/lib/pyOpenRPA/__init__.py delete mode 100644 Robot/dist/pyOpenRPA-1.0.15-py3-none-any.whl delete mode 100644 Robot/dist/pyOpenRPA-1.0.15.tar.gz diff --git a/Robot/build/lib/pyOpenRPA/Clipboard.py b/Robot/build/lib/pyOpenRPA/Clipboard.py deleted file mode 100644 index 12b43186..00000000 --- a/Robot/build/lib/pyOpenRPA/Clipboard.py +++ /dev/null @@ -1,22 +0,0 @@ -import win32clipboard -#################################### -#Info: Clipboard module of the Robot app (OpenRPA - Robot) -#################################### -# GUI Module - interaction with Windows clipboard - -################ -###ClipboardGet -################ -def ClipboardGet(): - win32clipboard.OpenClipboard() - lResult = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT) - win32clipboard.CloseClipboard() - return lResult -################ -###ClipboardSet -################ -def ClipboardSet(inText): - win32clipboard.OpenClipboard() - win32clipboard.EmptyClipboard() - win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT,inText) - win32clipboard.CloseClipboard() diff --git a/Robot/build/lib/pyOpenRPA/GUI.py b/Robot/build/lib/pyOpenRPA/GUI.py deleted file mode 100644 index 05b139a5..00000000 --- a/Robot/build/lib/pyOpenRPA/GUI.py +++ /dev/null @@ -1,1210 +0,0 @@ -from pywinauto import win32defines, win32structures, win32functions -import pdb -import pywinauto -import json -import sys -import ctypes -import struct -import os -import select -import zlib -import win32api -import win32clipboard -import time -import traceback -from . import ProcessCommunicator -from . import JSONNormalize -from threading import Timer -import datetime -import logging -import re -import copy -#Создать файл логирования -# add filemode="w" to overwrite -if not os.path.exists("Reports"): - os.makedirs("Reports") -########################## -#Подготовка логгера Robot -######################### -mRobotLogger=logging.getLogger("RobotLogger") -mRobotLogger.setLevel(logging.INFO) -# create the logging file handler -mRobotLoggerFH = logging.FileHandler("Reports\ReportRobotGUIRun_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log") -mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') -mRobotLoggerFH.setFormatter(mRobotLoggerFormatter) -# add handler to logger object -mRobotLogger.addHandler(mRobotLoggerFH) - - -#logging.basicConfig(filename="Reports\ReportRobotGUIRun_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log", level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") - -#####Внимание####### -#TODO В перспективе нужно реализовать алгоритм определения разрядности не в Robot.py, а в GUI.py, тк начинают появляться функции, на входе в которые еще неизвестна разрядность элемента + селектор может охватить сразу два элемента из 2-х разных разрядностей - обрабатываться это должно непосредственно при выполнении - -#################################### -#Info: GUI module of the Robot app (OpenRPA - Robot) -#################################### -# GUI Module - interaction with Desktop application - -#GUI Naming convention -#__ - -#UIO - UI Object (class of pywinauto UI object) -#UIOSelector - List of dict (key attributes) -#PWA - PyWinAuto -#PWASpecification - List of dict (key attributes in pywinauto.find_window notation) -#UIOTree - Recursive Dict of Dict ... (UI Parent -> Child hierarchy) -#UIOInfo - Dict of UIO attributes -#UIOActivity - Activity of the UIO (UI object) from the Pywinauto module -#UIOEI - UI Object info object - -#inActivitySpecificationDict: -#{ -# ModuleName: <"GUI", str>, - optional -# ActivityName: , -# ArgumentList: [, ...] - optional, -# ArgumentDict: {:, ...} - optional -#} - -#outActivityResultDict: -#{ -# ActivitySpecificationDict: { -# ModuleName: <"GUI", str>, -optional -# ActivityName: , -# ArgumentList: [, ...] - optional, -# ArgumentDict: {: , ...} - optional -# }, -# ErrorFlag: , -# ErrorMessage: - required if ErrorFlag is true, -# ErrorTraceback: - required if ErrorFlag is true, -# Result: - required if ErrorFlag is false -#} - -#inUIOSelector: -#[ -# { -# "index":<Позиция элемента в родительском объекте>, -# "depth_start" - глубина, с которой начинается поиск (по умолчанию 1), -# "depth_end" - глубина, до которой ведется поиск (по умолчанию 1), -# "class_name" - наименование класса, который требуется искать, -# "title" - наименование заголовка, -# "rich_text" - наименование rich_text, -# "backend": <"win32"||"uia", only for the 1-st list element> - if not specified, use mDefaultPywinautoBackend -# }, -# { ... } -# -#] - -#Default parameters -mDefaultPywinautoBackend="win32" - -############################ -#Новая версия -############################ -#Получить список элементов, который удовлетворяет условиям через расширенный движок поиска -#[ -# { -# "index":<Позиция элемента в родительском объекте>, -# "depth_start" - глубина, с которой начинается поиск (по умолчанию 1) -# "depth_end" - глубина, до которой ведется поиск (по умолчанию 1) -# "class_name" - наименование класса, который требуется искать -# "title" - наименование заголовка -# "rich_text" - наименование rich_text -# } -#] -################ -#return: List of UI Object -#inElement - Входной элемент - показатель, что не требуется выполнять коннект к процессу -#inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка -#old name - PywinautoExtElementsGet -def UIOSelector_Get_UIOList (inSpecificationList,inElement=None,inFlagRaiseException=True): - #Создать копию входного листа, чтобы не менять массив в других верхнеуровневых функциях - inSpecificationList=copy.deepcopy(inSpecificationList) - lResultList=[] - lChildrenList=[] - #Получить родительский объект если на вход ничего не поступило - if inElement is None: - #сформировать спецификацию на получение элемента - lRootElementSpecification=[inSpecificationList[0]] - lRootElementList=PWASpecification_Get_UIO(lRootElementSpecification) - for lRootItem in lRootElementList: - if lRootItem is not None: - lChildrenList.append(lRootItem.wrapper_object()) - #Елемент на вход поступил - выполнить его анализ - else: - #Получить список элементов - lElementChildrenList=inElement.children() - #Поступил index - точное добавление - if 'index' in inSpecificationList[0]: - if inSpecificationList[0]['index']1: - lFlagGoCheck=False - #Циклический обход по детям, на предмет соответствия всем условиям - for lChildrenItem in lElementChildrenList: - #Обработка глубины depth (рекурсивный вызов для всех детей с занижением индекса глубины) - #По умолчанию значение глубины 1 - if 'depth_end' in inSpecificationList[0]: - if inSpecificationList[0]['depth_end']>1: - #Подготовка новой версии спецификации - lChildrenItemNewSpecificationList=inSpecificationList.copy() - lChildrenItemNewSpecificationList[0]=lChildrenItemNewSpecificationList[0].copy() - lChildrenItemNewSpecificationList[0]["depth_end"]=lChildrenItemNewSpecificationList[0]["depth_end"]-1 - if 'depth_start' in lChildrenItemNewSpecificationList[0]: - lChildrenItemNewSpecificationList[0]["depth_start"]=lChildrenItemNewSpecificationList[0]["depth_start"]-1 - #Циклический вызов для всех детей со скорректированной спецификацией - lResultList.extend(UIOSelector_Get_UIOList(lChildrenItemNewSpecificationList,lChildrenItem,inFlagRaiseException)) - #Фильтрация - #TODO Сделать поддержку этих атрибутов для первого уровня селектора - if lFlagGoCheck: - lFlagAddChild=True - #Фильтрация по title - if 'title' in inSpecificationList[0]: - if lChildrenItem.element_info.name != inSpecificationList[0]["title"]: - lFlagAddChild=False - #Фильтрация по title_re (regexp) - if 'title_re' in inSpecificationList[0]: - if re.fullmatch(inSpecificationList[0]["title_re"],lChildrenItem.element_info.name) is None: - lFlagAddChild=False - #Фильтрация по rich_text - if 'rich_text' in inSpecificationList[0]: - if lChildrenItem.element_info.rich_text != inSpecificationList[0]["rich_text"]: - lFlagAddChild=False - #Фильтрация по rich_text_re (regexp) - if 'rich_text_re' in inSpecificationList[0]: - if re.fullmatch(inSpecificationList[0]["rich_text_re"],lChildrenItem.element_info.rich_text) is None: - lFlagAddChild=False - #Фильтрация по class_name - if 'class_name' in inSpecificationList[0]: - if lChildrenItem.element_info.class_name != inSpecificationList[0]["class_name"]: - lFlagAddChild=False - #Фильтрация по class_name_re (regexp) - if 'class_name_re' in inSpecificationList[0]: - if re.fullmatch(inSpecificationList[0]["class_name_re"],lChildrenItem.element_info.class_name) is None: - lFlagAddChild=False - #Фильтрация по friendly_class_name - if 'friendly_class_name' in inSpecificationList[0]: - if lChildrenItem.friendly_class_name() != inSpecificationList[0]["friendly_class_name"]: - lFlagAddChild=False - #Фильтрация по friendly_class_name_re (regexp) - if 'friendly_class_name_re' in inSpecificationList[0]: - if re.fullmatch(inSpecificationList[0]["friendly_class_name_re"],lChildrenItem.friendly_class_name) is None: - lFlagAddChild=False - #Фильтрация по control_type - if 'control_type' in inSpecificationList[0]: - if lChildrenItem.element_info.control_type != inSpecificationList[0]["control_type"]: - lFlagAddChild=False - #Фильтрация по control_type_re (regexp) - if 'control_type_re' in inSpecificationList[0]: - if re.fullmatch(inSpecificationList[0]["control_type_re"],lChildrenItem.element_info.control_type) is None: - lFlagAddChild=False - #Фильтрация по is_enabled (bool) - if 'is_enabled' in inSpecificationList[0]: - if lChildrenItem.is_enabled()!=inSpecificationList[0]["is_enabled"]: - lFlagAddChild=False - #Фильтрация по is_visible (bool) - if 'is_visible' in inSpecificationList[0]: - if lChildrenItem.is_visible()!=inSpecificationList[0]["is_visible"]: - lFlagAddChild=False - ##### - #Все проверки пройдены - флаг добавления - if lFlagAddChild: - lChildrenList.append(lChildrenItem) - #Выполнить рекурсивный вызов (уменьшение количества спецификаций), если спецификация больше одного элемента - #????????Зачем в условии ниже is not None ??????????? - if len(inSpecificationList)>1 and len(lChildrenList)>0 is not None: - #Вызвать рекурсивно функцию получения следующего объекта, если в спецификации есть следующий объект - for lChildElement in lChildrenList: - lResultList.extend(UIOSelector_Get_UIOList(inSpecificationList[1:],lChildElement,inFlagRaiseException)) - else: - lResultList.extend(lChildrenList) - #Условие, если результирующий список пустой и установлен флаг создания ошибки (и inElement is None - не следствие рекурсивного вызова) - if inElement is None and len(lResultList)==0 and inFlagRaiseException: - raise pywinauto.findwindows.ElementNotFoundError("Robot can't find element by the UIOSelector") - return lResultList - -################################################################################################# -#Get first (in more than one) UIO (UI Object) -#inSpecificationList - UIOSelector -#inElement - Входной элемент - показатель, что не требуется выполнять коннект к процессу -#inFlagRaiseException - Флаг True - выкинуть ошибку в случае обнаружении пустого списка -#old name - PywinautoExtElementGet -def UIOSelector_Get_UIO (inSpecificationList,inElement=None,inFlagRaiseException=True): - lResult=None - #Получить родительский объект если на вход ничего не поступило - lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement,False) - if len(lResultList)>0: - lResult=lResultList[0] - #Условие, если результирующий список пустой и установлен флаг создания ошибки (и inElement is None - не следствие рекурсивного вызова) - if lResult is None and inFlagRaiseException: - raise pywinauto.findwindows.ElementNotFoundError("Robot can't find element by the UIOSelector") - return lResult -################################################################################################# -#Check if UIO exist (Identified by the UIOSelector) -#inSpecificationList - UIOSelector -#old name - - -def UIOSelector_Exist_Bool (inSpecificationList): - lResult=False - #Получить родительский объект если на вход ничего не поступило - lResultList=UIOSelector_Get_UIOList(inSpecificationList,None,False) - if len(lResultList)>0: - lResult=True - return lResult -################################################################################################# -#Wait for UIO is appear (at least one of them or all at the same time) -#inSpecificationListList - List of the UIOSelector -#inWaitSecs - Время ожидания объекта в секундах -#inFlagWaitAllInMoment - доп. условие - ожидать появление всех UIOSelector одновременно -#return: [0,1,2] - index of UIOSpecification, which is appear -#old name - - -#####Внимание##### -##Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться) -def UIOSelectorsSecs_WaitAppear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False): - lResultFlag=False - lSecsSleep = 1 #Настроечный параметр - lSecsDone = 0 - lResultList = None - #Цикл проверки - while lResultFlag == False and lSecsDone0: - #Условие выполнено - lResultFlag=True - #Если флаг не изменился - увеличить время и уснуть - if lResultFlag == False: - lSecsDone=lSecsDone+lSecsSleep - time.sleep(lSecsSleep) - return lResultList -################################################################################################# -#Wait for UIO is Disappear (at least one of them or all at the same time) -#inSpecificationListList - List of the UIOSelector -#inWaitSecs - Время ожидания пропажи объекта в секундах -#inFlagWaitAllInMoment - доп. условие - ожидать пропажу всех UIOSelector одновременно -#return: [0,1,2] - index of UIOSpecification, which is Disappear -#old name - - -#####Внимание##### -##Функция ожидания пропажи элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться) -def UIOSelectorsSecs_WaitDisappear_List (inSpecificationListList,inWaitSecs,inFlagWaitAllInMoment=False): - lResultFlag=False - lSecsSleep = 1 #Настроечный параметр - lSecsDone = 0 - lResultList = None - #Цикл проверки - while lResultFlag == False and lSecsDone0: - #Условие выполнено - lResultFlag=True - #Если флаг не изменился - увеличить время и уснуть - if lResultFlag == False: - lSecsDone=lSecsDone+lSecsSleep - time.sleep(lSecsSleep) - return lResultList -################################################################################################# -#Wait for UIO is appear (at least one of them or all at the same time) -#inSpecificationList - UIOSelector -#inWaitSecs - Время ожидания объекта в секундах -#return: Bool - True - UIO is appear -#old name - - -def UIOSelectorSecs_WaitAppear_Bool (inSpecificationList,inWaitSecs): - lWaitAppearList=UIOSelectorsSecs_WaitAppear_List([inSpecificationList],inWaitSecs) - lResult=False - if len(lWaitAppearList)>0: - lResult=True - return lResult -################################################################################################# -#Wait for UIO is disappear (at least one of them or all at the same time) -#inSpecificationList - UIOSelector -#inWaitSecs - Время ожидания пропажи объекта в секундах -#return: Bool - True - UIO is Disappear -#old name - - -def UIOSelectorSecs_WaitDisappear_Bool (inSpecificationList,inWaitSecs): - lWaitDisappearList=UIOSelectorsSecs_WaitDisappear_List([inSpecificationList],inWaitSecs) - lResult=False - if len(lWaitDisappearList)>0: - lResult=True - return lResult -################################################################################################# -#Get process bitness (32 or 64) -#inSpecificationList - UIOSelector -#old name - None -#return None (if Process not found), int 32, or int 64 -def UIOSelector_Get_BitnessInt (inSpecificationList): - lResult=None - #Получить объект Application (Для проверки разрядности) - lRootElement=PWASpecification_Get_PWAApplication(inSpecificationList) - if lRootElement is not None: - if lRootElement.is64bit(): - lResult=64 - else: - lResult=32 - return lResult -################################################################################################# -#Get OS bitness (32 or 64) -#old name - None -#return int 32, or int 64 -def Get_OSBitnessInt (): - lResult=32; - if pywinauto.sysinfo.is_x64_OS(): - lResult=64; - return lResult; -################################################################################################## -#inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation -#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element -#return list of UIO object -#old name - GetControl -def PWASpecification_Get_UIO(inControlSpecificationArray): - #Определение backend - lBackend=mDefaultPywinautoBackend - if "backend" in inControlSpecificationArray[0]: - lBackend=inControlSpecificationArray[0]["backend"] - inControlSpecificationArray[0].pop("backend") - #Подготовка входного массива - inControlSpecificationOriginArray=copy.deepcopy(inControlSpecificationArray) - inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray) - #Выполнить идентификацию объектов, если передан массив - lResultList=[]; - lTempObject=None - if len(inControlSpecificationArray) > 0: - #Сформировать выборку элементов, которые подходят под первый уровень спецификации - lSpecificationLvL1List = pywinauto.findwindows.find_elements(**inControlSpecificationArray[0]) - for lItem in lSpecificationLvL1List: - #Сделать независимую копию и установить информацию о process_id и handle - lItemControlSpecificationArray=copy.deepcopy(inControlSpecificationArray) - lItemControlSpecificationArray[0]["process_id"]=lItem.process_id - lItemControlSpecificationArray[0]["handle"]=lItem.handle - lItemControlSpecificationOriginArray=copy.deepcopy(inControlSpecificationOriginArray) - lItemControlSpecificationOriginArray[0]["process_id"]=lItem.process_id - lItemControlSpecificationOriginArray[0]["handle"]=lItem.handle - #Выполнить подключение к объекту - lRPAApplication = pywinauto.Application(backend=lBackend) - #Проверка разрядности - try: - lRPAApplication.connect(**lItemControlSpecificationArray[0]) - except Exception as e: - UIOSelector_TryRestore_Dict(lItemControlSpecificationArray) - try: - lRPAApplication.connect(**lItemControlSpecificationArray[0]) - except Exception as e: - lRPAApplication = None - if lRPAApplication is not None: - #lTempObject=lRPAApplication.window(**lItemControlSpecificationArray[0]) - #Скорректировано из-за недопонимания структуры - lTempObject=lRPAApplication - #Нормализация массива для целей выборки объекта (удаление конфликтующих ключей) - lItemControlSpecificationArray=UIOSelector_SearchUIONormalize_UIOSelector(lItemControlSpecificationOriginArray) - #Циклическое прохождение к недрам объекта - for lWindowSpecification in lItemControlSpecificationArray[0:]: - lTempObject=lTempObject.window(**lWindowSpecification) - #Добавить объект в результирующий массив - lResultList.append(lTempObject) - return lResultList -################################################################################################## -#inControlSpecificationArray - List of dict, dict in pywinauto.find_windows notation -#Backend selection - attribute "backend" ("win32" || "uia") in 1-st list element -#return process application object -#old name - None -def PWASpecification_Get_PWAApplication(inControlSpecificationArray): - #Определение backend - lBackend=mDefaultPywinautoBackend - if "backend" in inControlSpecificationArray[0]: - lBackend=inControlSpecificationArray[0]["backend"] - inControlSpecificationArray[0].pop("backend") - #Подготовка входного массива - inControlSpecificationOriginArray=inControlSpecificationArray - inControlSpecificationArray=UIOSelector_SearchProcessNormalize_UIOSelector(inControlSpecificationArray) - #Выполнить идентификацию объектов, если передан массив - lResultList=[]; - lTempObject=None - if len(inControlSpecificationArray) > 0: - #Выполнить подключение к объекту - lRPAApplication = pywinauto.Application(backend=lBackend) - #Проверка разрядности - try: - lRPAApplication.connect(**inControlSpecificationArray[0]) - except Exception as e: - UIOSelector_TryRestore_Dict(inControlSpecificationArray) - try: - lRPAApplication.connect(**inControlSpecificationArray[0]) - except Exception as e: - lRPAApplication = None - if lRPAApplication is not None: - #lTempObject=lRPAApplication.window(**inControlSpecificationArray[0]) - #Скорректировано из-за недопонимания структуры - lTempObject=lRPAApplication - return lTempObject - -########################################################################################################### -#inElementSpecificationList = UIOSelector (see description on the top of the document) -#result = pywinauto element wrapper instance or None -#old name - AutomationSearchMouseElement -def UIOSelector_SearchChildByMouse_UIO(inElementSpecification): - lGUISearchElementSelected=None - #Настройка - частота обновления подсвечивания - lTimeSleepSeconds=0.4 - lElementFoundedList=[] - #Ветка поиска в режиме реального времени - #Сбросить нажатие Ctrl, если оно было - bool(win32api.GetAsyncKeyState(17)) - #Оптимизация - получить объект для опроса единажды - lUIORoot=UIOSelector_Get_UIO(inElementSpecification) - lFlagLoop = True - while lFlagLoop: - #Проверить, нажата ли клавиша Ctrl (код 17) - lFlagKeyPressedCtrl=bool(win32api.GetAsyncKeyState(17)) - #Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз - if not lFlagKeyPressedCtrl: - #Получить координаты мыши - (lX,lY) = win32api.GetCursorPos() - lElementFounded={} - #Создать карту пикселей и элементов - #####Внимание! Функция UIOXY_SearchChild_ListDict не написана - lElementFoundedList=UIOXY_SearchChild_ListDict(lUIORoot,lX,lY) - #print(lElementFoundedList) - lElementFounded=lElementFoundedList[-1]["element"] - #Подсветить объект, если он мышь раньше стояла на другом объекте - if lGUISearchElementSelected != lElementFounded: - lGUISearchElementSelected = lElementFounded - #Доработанная функция отрисовки - if lElementFounded is not None: - UIO_Highlight(lElementFounded) - else: - #Была нажата клавиша Ctrl - выйти из цикла - lFlagLoop=False; - #Заснуть до следующего цикла - time.sleep(lTimeSleepSeconds) - #Вернуть результат поиска - return lElementFoundedList - -#################################################################################################### -#inElementSpecification - UIOSelector -#old name - AutomationSearchMouseElementHierarchy -def UIOSelector_SearchChildByMouse_UIOTree(inElementSpecification): - lItemInfo = [] - #Запустить функцию поиска элемента по мыши - lElementList = UIOSelector_SearchChildByMouse_UIO(inElementSpecification) - lElement = lElementList[-1]['element'] - #Detect backend of the elements - lFlagIsBackendWin32 = True - #Если объект имеется (не None), то выполнить построение иерархии - if lElement is not None: - if lElement.backend.name == 'uia': - lFlagIsBackendWin32 = False - #Циклическое создание дерева - #while lElement is not None: - lListIterator=0 - lItemInfo2=lItemInfo - for lListItem in lElementList: - lElement = lListItem["element"] - #Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None - #if not lFlagIsBackendWin32 and lElement.parent() is None: - # lElement = None - #else: - #Получить информацию про объект - lItemInfo2.append(UIOEI_Convert_UIOInfo(lElement.element_info)) - #Дообогатить информацией об индексе ребенка в родительском объекте - if "index" in lListItem: - if lListItem["index"] is not None: - lItemInfo2[-1]['ctrl_index']=lListItem["index"] - else: - if "ctrl_index" in lListItem: - lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"] - else: - if "ctrl_index" in lListItem: - lItemInfo2[-1]['ctrl_index']=lListItem["ctrl_index"] - #Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников - lItemInfo2[-1]['SpecificationChild']=[] - lItemInfo2=lItemInfo2[-1]['SpecificationChild'] - #Переход на родительский объект - #lElement = lElement.parent() - lListIterator=lListIterator+1 - #Добавить информацию о Backend в первый объект - lItemInfo[0]["backend"]=lElement.backend.name - #Вернуть результат - return lItemInfo -#################################################################################################### -#inElement- UIO (UI Object) -#old name - PywinautoExtElementCtrlIndexGet -def UIO_GetCtrlIndex_Int(inElement): - lResult = None - #Выполнить алгоритм, если есть Element - if inElement is not None: - lElementParent = inElement.parent() - if lElementParent is not None: - lResult = 0 - lFlagFind = True - #Получить список потомков - lElementParentChildrenList = lElementParent.children() - #Циклический поиск до того момента, пока не упремся в текущий элемент - while lFlagFind: - if lResult=len(lElementParentChildrenList): - lResult = None - lFlagFind = False - else: - lResult = lResult + 1 - else: - lResult=-1 - lFlagFind=False - #Вернуть результат - return lResult - -#################################################################################################### -#Получить список информационных объектов, который удовлетворяет условиям -#inSpecificationList - UIOSelector -#old name - PywinautoExtElementsGetInfo -def UIOSelector_Get_UIOInfoList (inSpecificationList,inElement=None): - #Получить родительский объект если на вход ничего не поступило - lResultList=UIOSelector_Get_UIOList(inSpecificationList,inElement) - lIterator = 0 - for lItem in lResultList: - lResultList[lIterator]=UIOEI_Convert_UIOInfo(lResultList[lIterator].element_info) - lIterator = lIterator + 1 - return lResultList - -#################################################################################################### -#Check is the UIO/UIO's by the UIOSelector exist -#inSpecificationList - UIOSelector -#old name - PywinautoExtElementExist -def UIOSelector_IsExist_Bool (inSpecificationList): - return len(UIOSelector_Get_UIOList(inSpecificationList))>0 - -#################################################################################################### -#Wait for the UIO by the UIOSelector appear -#inSpecificationList - UIOSelector -#result - { } -#old name - PywinautoExtElementWaitAppear -############# -#Внимание! Старая функция (на замену ей пришла UIOSelectorSecs_WaitAppear_Bool) -############# -def UIOSelector_WaitAppear_Dict(inSpecificationList,inTimeout=60): - lTimeoutSeconds = 0 - while (not UIOSelector_IsExist_Bool(inSpecificationList) and inTimeout>lTimeoutSeconds): - lTimeoutSeconds = lTimeoutSeconds + 0.5 - #Заснуть на полсекунды - time.sleep(0.5) - return UIOSelector_IsExist_Bool(inSpecificationList) - -#################################################################################################### -#Try to restore (maximize) window, if it's was minimized -#(особенность uia backend - он не может прицепиться к окну, если оно свернуто) -#inSpecificationList - UIOSelector -#old name - PywinautoExtTryToRestore -def UIOSelector_TryRestore_Dict(inSpecificationList): - lResult={} - try: - #Подготовка взодного массива - inControlSpecificationArray=UIOSelector_SearchUIONormalize_UIOSelector(inSpecificationList) - #Выполнить подключение к объекту. Восстановление необходимо только в бэке win32, - #так как в uia свернутое окно не распознается - lRPAApplication = pywinauto.Application(backend="win32") - lRPAApplication.connect(**inSpecificationList[0]) - lRPAApplication.top_window().restore() - except Exception: - True==False - return lResult -#################################################################################################### -#Get the list of the UI object activities -#inControlSpecificationArray - UIOSelector -#old name - ElementActionGetList -def UIOSelector_Get_UIOActivityList (inControlSpecificationArray): - #Получить объект - lObject=UIOSelector_Get_UIO(inControlSpecificationArray) - lActionList=dir(lObject) - lResult=dir(lObject) - #Выполнить чистку списка от неактуальных методов - for lActionItem in lActionList: - #Удалить те, которые начинаются на _ - if lActionItem[0]=='_': - lResult.remove(lActionItem) - #Удалить те, которые начинаются с символа верхнего регистра - if lActionItem[0].isupper(): - lResult.remove(lActionItem) - return lResult - -#################################################################################################### -#Run the activity in UIO (UI Object) -#inControlSpecificationArray - UIOSelector -#inActionName - UIOActivity (name) from Pywinauto -#old name - ElementRunAction -def UIOSelectorUIOActivity_Run_Dict(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}): - lResult={} - #Определить объект - lObject=UIOSelector_Get_UIO(inControlSpecificationArray) - #Получить метод для вызова - lFunction = getattr(lObject, inActionName) - #Выполнить действие - #Обернуто в безопасную обработку, тк для некоторых объектов метод не работает и может выдавать ошибку типа: NotImplementedError: This method not work properly for WinForms DataGrid, use cells() - try: - return lFunction(*inArgumentList,**inkwArgumentObject) - except Exception as e: - #Если ошибка возникла на action get_properties - if inActionName=="get_properties": - lResult={} - #Ручное формирование - lResult["class_name"]=lObject.class_name() - lResult["friendly_class_name"]=lObject.friendly_class_name() - lResult["texts"]=lObject.texts() - lResult["control_id"]=lObject.control_id() - lResult["control_count"]=lObject.control_count() - lResult["automation_id"]=lObject.automation_id() - return lResult - else: - raise e - return lResult - -#################################################################################################### -#Get the UIO dict of the attributes -#old name - ElementGetInfo -def UIOSelector_Get_UIOInfo(inControlSpecificationArray): - #Подготовка входного массива - inControlSpecificationArray=UIOSelector_SearchUIONormalize_UIOSelector(inControlSpecificationArray) - #Выполнить идентификацию объектов, если передан массив - lResultList=[]; - if len(inControlSpecificationArray) > 0: - #Получить объект - lTempObject=UIOSelector_Get_UIO(inControlSpecificationArray) - #Получить инфо объект - lTempObjectInfo = lTempObject.element_info - #Добавить информацию об обнаруженом объекте - lResultList.append(UIOEI_Convert_UIOInfo(lTempObjectInfo)); - return lResultList - - -#################################################################################################### -#Search child UIO by the: Parent UIO, X, Y -#inHierarchyList: [{"index":<>,"element":<>}] - technical argument for internal purpose -#result -List of dict [{"index":<>,"element":<>}] -- list of element hierarchy specifications -#old name - GUISearchElementByRootXY -def UIOXY_SearchChild_ListDict(inRootElement,inX,inY,inHierarchyList=[]): - #Инициализация результирующего значения - lResultElement = None - lResultElementX1 = None - lResultElementX2 = None - lResultElementY1 = None - lResultElementY2 = None - lResultHierarchyList=[{'index':None,'element':None}] - #Получить координаты текущего объекта - try: - lRootElementRectX1=inRootElement.element_info.rectangle.left - lRootElementRectX2=inRootElement.element_info.rectangle.right - lRootElementRectY1=inRootElement.element_info.rectangle.top - lRootElementRectY2=inRootElement.element_info.rectangle.bottom - #Добавить объект в результирующий, если координаты попадают в него - if inX>=lRootElementRectX1 and inX<=lRootElementRectX2 and inY>=lRootElementRectY1 and inY<=lRootElementRectY2: - lResultElement = inRootElement - lResultElementX1 = lRootElementRectX1 - lResultElementX2 = lRootElementRectX2 - lResultElementY1 = lRootElementRectY1 - lResultElementY2 = lRootElementRectY2 - #Сформировать результирующий обьъект - lParentHierarchy = inHierarchyList - if len(lParentHierarchy)==0: - lParentHierarchy.append({"index":None,"element":lResultElement}) - else: - lParentHierarchy[-1]["element"] = lResultElement - lResultHierarchyList=lParentHierarchy - #Получить список детей и добавить в карту - lChildIterator=0 - for lChildElement in inRootElement.children(): - #Сформировать результирующий массив - lChildFoundedHierarchyList = lParentHierarchy.copy() - lChildFoundedHierarchyList.append({'index': lChildIterator}) - lChildFoundedHierarchyList = UIOXY_SearchChild_ListDict(lChildElement,inX,inY, lChildFoundedHierarchyList) - lChildFoundedElement = lChildFoundedHierarchyList[-1]["element"] - #Установить обнаруженный элемент, если текущий результат пустой - if lResultElement is None and lChildFoundedElement is not None: - lResultElement = lChildFoundedElement - lResultElementX1 = lResultElement.element_info.rectangle.left - lResultElementX2 = lResultElement.element_info.rectangle.right - lResultElementY1 = lResultElement.element_info.rectangle.top - lResultElementY2 = lResultElement.element_info.rectangle.bottom - lResultHierarchyList = lChildFoundedHierarchyList - #Выполнить сверку lChildFoundedElement и lResultElement если оба имеются - elif lResultElement is not None and lChildFoundedElement is not None: - #Правила перезатирания карты, если имеется старый объект - #[Накладываемый объект] - НО - ElementNew - #[Имеющийся объект] - ИО - ElementOld - #3 типа вхождения объектов - #тип 1 - [имеющийся объект] полностью входит в [накладываемый объект] (ИО X1 Y1 >= НО X1 Y1; ИО X2 Y2 <= НО X2 Y2) - не вносить НО в bitmap в эти диапазоны - #тип 2 - [имеющийся объект] полностью выходит за пределы [накладываемого объекта] (ИО X1 Y1 < НО X1 Y1; ИО X2 Y2 > НО X2 Y2) - вносить НО в bitmap - #тип 3 - [имеющийся объект] частично входит в [накладываемый объект] (все остальные случаи)- вносить НО в bitmap - #Получить координаты ИО - lChildFoundedElementInfo = lChildFoundedElement.element_info - #lElementNew = inElement - lChildFoundedElementX1 = lChildFoundedElementInfo.rectangle.left - lChildFoundedElementX2 = lChildFoundedElementInfo.rectangle.right - lChildFoundedElementY1 = lChildFoundedElementInfo.rectangle.top - lChildFoundedElementY2 = lChildFoundedElementInfo.rectangle.bottom - #Проверка вхождения по типу 1 - if (lResultElementX1>=lChildFoundedElementX1) and (lResultElementY1>=lChildFoundedElementY1) and (lResultElementX2<=lChildFoundedElementX2) and (lResultElementY2<=lChildFoundedElementY2): - False == True - #Проверка вхождения по типу 3 - elif (lResultElementX1lChildFoundedElementX2) and (lResultElementY2>lChildFoundedElementY2): - lResultElement = lChildFoundedElement - lResultElementX1 = lChildFoundedElementX1 - lResultElementX2 = lChildFoundedElementX2 - lResultElementY1 = lChildFoundedElementY1 - lResultElementY2 = lChildFoundedElementY2 - lResultHierarchyList = lChildFoundedHierarchyList - #Проверка вхождения по типу 2 - else: - lResultElement = lChildFoundedElement - lResultElementX1 = lChildFoundedElementX1 - lResultElementX2 = lChildFoundedElementX2 - lResultElementY1 = lChildFoundedElementY1 - lResultElementY2 = lChildFoundedElementY2 - lResultHierarchyList = lChildFoundedHierarchyList - lChildIterator=lChildIterator+1 - except Exception as e: - False == False - return lResultHierarchyList - -################################################################################################### -#Get list of child UIO's by Parent UIOSelector -#inControlSpecificationArray- UIOSelector -#old name - ElementGetChildElementList -def UIOSelector_GetChildList_UIOList(inControlSpecificationArray=[],inBackend=mDefaultPywinautoBackend): - #Подготовка входного массива - inControlSpecificationArray=UIOSelector_SearchUIONormalize_UIOSelector(inControlSpecificationArray) - #Выполнить идентификацию объектов, если передан массив - lResultList=[]; - #ctypes.windll.user32.MessageBoxW(0, str(inControlSpecificationArray), "Your title", 1) - if len(inControlSpecificationArray) > 0: - #Получить объект - lTempObject = UIOSelector_Get_UIO(inControlSpecificationArray) - #Получить список дочерних объектов - lTempChildList = lTempObject.children() - lIterator=0 - #Подготовить результирующий объект - for lChild in lTempChildList: - lTempObjectInfo=lChild.element_info - #Добавить информацию об обнаруженом объекте - lObjectInfoItem=UIOEI_Convert_UIOInfo(lTempObjectInfo) - #Итератор внутри объекта (для точной идентификации) - lObjectInfoItem['ctrl_index']=lIterator; - lResultList.append(lObjectInfoItem); - #Инкремент счетчика - lIterator=lIterator+1 - else: - lResultList=BackendStr_GetTopLevelList_UIOInfo(inBackend) - #Установка бэк-енда на первый элемент - for lItem in lResultList: - lItem["backend"]=inBackend - return lResultList - -#################################################################################################### -#Подготовить массив для обращшения к поиску элемементов -#inControlSpecificationArray - UIOSelector (can be dirty) -#old name 1 - ElementSpecificationArraySearchPrepare -#old name 2 - ElementSpecificationListNormalize -def UIOSelector_SearchUIONormalize_UIOSelector (inControlSpecificationArray): - lResult=[] - #Циклический обход - for lSpecificationItem in inControlSpecificationArray: - lSpecificationItemNew=lSpecificationItem.copy() - #Перебор всех элементов - for lItemKey,lItemValue in lSpecificationItem.items(): - #Флаг удаления атрибута - lFlagRemoveAttribute=False - ############################# - #Если является вложенным словарем - удалить - if type(lItemValue) is dict: - lFlagRemoveAttribute=True - #Является типом None - if lItemValue is None: - lFlagRemoveAttribute=True - #Проверка допустимого ключевого слова - if ( - lItemKey == "class_name" or - lItemKey == "class_name_re" or - lItemKey == "parent" or - lItemKey == "process" or - lItemKey == "title" or - lItemKey == "title_re" or - lItemKey == "top_level_only" or - lItemKey == "visible_only" or - lItemKey == "enabled_only" or - lItemKey == "best_match" or - lItemKey == "handle" or - lItemKey == "ctrl_index" or - lItemKey == "found_index" or - lItemKey == "predicate_func" or - lItemKey == "active_only" or - lItemKey == "control_id" or - lItemKey == "control_type" or - lItemKey == "auto_id" or - lItemKey == "framework_id" or - lItemKey == "backend"): - True == True - else: - lFlagRemoveAttribute=True - - - ############################# - #Конструкция по удалению ключа из словаря - if lFlagRemoveAttribute: - lSpecificationItemNew.pop(lItemKey) - #Проверит наличие ctrl_index - если он есть, то удалить control_id и control_type из-за того, что они мешают друг другу - if 'ctrl_index' in lSpecificationItemNew: - if "control_id" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_id") - if "control_type" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_type") - #Проверить наличие handle - если он есть, то удалить process, control_id и control_type из-за того, что они мешают друг другу - if 'handle' in lSpecificationItemNew: - if "control_id" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_id") - if "control_type" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_type") - if "process" in lSpecificationItemNew: - lSpecificationItemNew.pop("process") - #Иначе Проверить наличие process - если он есть, то удалить тк он нужен только при подключении к процессу - if 'process' in lSpecificationItemNew: - lSpecificationItemNew.pop("process") - #Добавить строку в результирующий массив - lResult.append(lSpecificationItemNew) - #Вернуть результат - return lResult -#################################################################################################### -#Подготовить массив для обращшения к поиску процесса (отличается от поиска элемента, тк данная функция нужна для нормализации спецификации для подключения к процессу с окнами) -#inControlSpecificationArray - UIOSelector (can be dirty) -#old name 1 - ElementSpecificationArraySearchPrepare -#old name 2 - ElementSpecificationListNormalize -def UIOSelector_SearchProcessNormalize_UIOSelector (inControlSpecificationArray): - lResult=[] - #Циклический обход - for lSpecificationItem in inControlSpecificationArray: - lSpecificationItemNew=lSpecificationItem.copy() - #Перебор всех элементов - for lItemKey,lItemValue in lSpecificationItem.items(): - #Флаг удаления атрибута - lFlagRemoveAttribute=False - ############################# - #Если является вложенным словарем - удалить - if type(lItemValue) is dict: - lFlagRemoveAttribute=True - #Является типом None - if lItemValue is None: - lFlagRemoveAttribute=True - #Проверка допустимого ключевого слова - if ( - lItemKey == "class_name" or - lItemKey == "class_name_re" or - lItemKey == "parent" or - lItemKey == "process" or - lItemKey == "title" or - lItemKey == "title_re" or - lItemKey == "top_level_only" or - lItemKey == "visible_only" or - lItemKey == "enabled_only" or - lItemKey == "best_match" or - lItemKey == "handle" or - lItemKey == "ctrl_index" or - lItemKey == "found_index" or - lItemKey == "predicate_func" or - lItemKey == "active_only" or - lItemKey == "control_id" or - lItemKey == "control_type" or - lItemKey == "auto_id" or - lItemKey == "framework_id" or - lItemKey == "backend"): - True == True - else: - lFlagRemoveAttribute=True - - - ############################# - #Конструкция по удалению ключа из словаря - if lFlagRemoveAttribute: - lSpecificationItemNew.pop(lItemKey) - #Проверит наличие ctrl_index - если он есть, то удалить control_id и control_type из-за того, что они мешают друг другу - if 'ctrl_index' in lSpecificationItemNew: - if "control_id" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_id") - if "control_type" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_type") - #Проверить наличие handle - если он есть, то удалить process, control_id и control_type из-за того, что они мешают друг другу - if 'handle' in lSpecificationItemNew: - if "control_id" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_id") - if "control_type" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_type") - if "process" in lSpecificationItemNew: - lSpecificationItemNew.pop("process") - #Иначе Проверить наличие process - если он есть, то удалить title, control_id и control_type из-за того, что они мешают друг другу - elif 'process' in lSpecificationItemNew: - if "control_id" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_id") - if "control_type" in lSpecificationItemNew: - lSpecificationItemNew.pop("control_type") - if "title" in lSpecificationItemNew: - lSpecificationItemNew.pop("title") - #Добавить строку в результирующий массив - lResult.append(lSpecificationItemNew) - #Вернуть результат - return lResult -#################################################################################################### -#Transfer UI object element info (pywinauto) to UIOInfo (dict of attributes) -#inElementInfo - UIOEI -#old name - ElementInfoExportObject -def UIOEI_Convert_UIOInfo(inElementInfo): - #Подготовить выходную структуру данных - lResult = {"title":None,"rich_text":None,"process_id":None,"process":None,"handle":None,"class_name":None,"control_type":None,"control_id":None,"rectangle":{"left":None,"top":None,"right":None,"bottom":None}, 'runtime_id':None} - #Проверка name - try: - lResult['title']=inElementInfo.name - except Exception as e: - True == False - #Проверка rich_text - try: - lResult['rich_text']=inElementInfo.rich_text - except Exception as e: - True == False - #Проверка process_id - try: - lResult['process_id']=inElementInfo.process_id - lResult['process']=inElementInfo.process_id - except Exception as e: - True == False - #Проверка handle - try: - lResult['handle']=inElementInfo.handle - except Exception as e: - True == False - #Проверка class_name - try: - lResult['class_name']=inElementInfo.class_name - except Exception as e: - True == False - #Проверка control_type - try: - lResult['control_type']=inElementInfo.control_type - except Exception as e: - True == False - #Проверка control_id - try: - if inElementInfo.control_id!=0: - lResult['control_id']=inElementInfo.control_id - except Exception as e: - True == False - #Проверка rectangle left - try: - lResult['rectangle']['left']=inElementInfo.rectangle.left - except Exception as e: - True == False - #Проверка rectangle right - try: - lResult['rectangle']['right']=inElementInfo.rectangle.right - except Exception as e: - True == False - #Проверка rectangle top - try: - lResult['rectangle']['top']=inElementInfo.rectangle.top - except Exception as e: - True == False - #Проверка rectangle bottom - try: - lResult['rectangle']['bottom']=inElementInfo.rectangle.bottom - except Exception as e: - True == False - #Проверка runtime_id - try: - lResult['runtime_id']=inElementInfo.runtime_id - except Exception as e: - True == False - #Вернуть результат - return lResult - -################################################################################################### -#Get list of top level -#old name - GetRootElementList -def BackendStr_GetTopLevelList_UIOInfo(inBackend=mDefaultPywinautoBackend): - #Получить список объектов - lResultList=pywinauto.findwindows.find_elements(top_level_only=True,backend=inBackend) - lResultList2=[] - for lI in lResultList: - lTempObjectInfo=lI - lResultList2.append(UIOEI_Convert_UIOInfo(lI)); - return lResultList2 - -################################################################################################### -#Highlight the UI object -#old name - ElementDrawOutlineNew -def UIOSelector_Highlight(inSpecificationArray): - UIO_Highlight(UIOSelector_Get_UIO(inSpecificationArray)) - return - -################################################################################################### -#inSpecificationArray - UIOSelector -#old name - ElementDrawOutlineNewFocus -def UIOSelector_FocusHighlight(inSpecificationArray): - UIO_FocusHighlight(UIOSelector_Get_UIO(inSpecificationArray)) - return - -################################################################################################### -#old name - draw_outline_new -def UIO_Highlight(lWrapperObject,colour='green',thickness=2,fill=win32defines.BS_NULL,rect=None,inFlagSetFocus=False): - if lWrapperObject is not None: - """ - Draw an outline around the window. - * **colour** can be either an integer or one of 'red', 'green', 'blue' - (default 'green') - * **thickness** thickness of rectangle (default 2) - * **fill** how to fill in the rectangle (default BS_NULL) - * **rect** the coordinates of the rectangle to draw (defaults to - the rectangle of the control) - """ - if inFlagSetFocus: - #Установить фокус на объект, чтобы было видно выделение - lWrapperObject.set_focus() - time.sleep(0.5) - # don't draw if dialog is not visible - #if not lWrapperObject.is_visible(): - # return - colours = { - "green": 0x00ff00, - "blue": 0xff0000, - "red": 0x0000ff, - } - # if it's a known colour - if colour in colours: - colour = colours[colour] - if rect is None: - rect = lWrapperObject.rectangle() - # create the pen(outline) - pen_handle = win32functions.CreatePen( - win32defines.PS_SOLID, thickness, colour) - # create the brush (inside) - brush = win32structures.LOGBRUSH() - brush.lbStyle = fill - brush.lbHatch = win32defines.HS_DIAGCROSS - brush_handle = win32functions.CreateBrushIndirect(ctypes.byref(brush)) - # get the Device Context - dc = win32functions.CreateDC("DISPLAY", None, None, None ) - # push our objects into it - win32functions.SelectObject(dc, brush_handle) - win32functions.SelectObject(dc, pen_handle) - # draw the rectangle to the DC - win32functions.Rectangle( - dc, rect.left, rect.top, rect.right, rect.bottom) - # Delete the brush and pen we created - win32functions.DeleteObject(brush_handle) - win32functions.DeleteObject(pen_handle) - # delete the Display context that we created - win32functions.DeleteDC(dc) - -################################################################################################### -#Аналог подсвечивания + установка фокуса -#old name - draw_outline_new_focus -def UIO_FocusHighlight(lWrapperObject,colour='green',thickness=2,fill=win32defines.BS_NULL,rect=None): - UIO_Highlight(lWrapperObject,'green',2,win32defines.BS_NULL,None,True) - - - - -#Определить разрядность процесса -lProcessBitnessStr = str(struct.calcsize("P") * 8) -############################ -#Старая версия -# Определять флаг Debug, если как второй входной параметр не поступил ключ RELEASE -############################ -mFlagIsDebug=True -if (len(sys.argv)>=2): - if (sys.argv[1].upper()=="RELEASE"): - mFlagIsDebug=False -#Оповещение о выбранном режиме -if mFlagIsDebug: - mRobotLogger.info("Robot/GUI: Debug mode, x"+lProcessBitnessStr) - print ("Robot/GUI: Debug mode, x"+lProcessBitnessStr) -else: - mRobotLogger.info("Robot/GUI: Release mode, x"+lProcessBitnessStr) - #Нельзя делать print в release mode тк print делает вывод в PIPE поток, что нарушает последовательность взаимодействия с родительским процессом - #print ("Robot/GUI: Release mode, x"+lProcessBitnessStr) -#for line in sys.stdin: -# lText=lText+line; -#ctypes.windll.user32.MessageBoxW(0, lText, "Your title", 1) - -buffer = "" -lJSONInputString="" - -#Выполнить чтение буфера, если не отладка библиотеки -if not mFlagIsDebug: - while True: - lProcessResponse={"ErrorFlag":False} - try: - #Ожидаем синхронно поступление объекта - lJSONInput = ProcessCommunicator.ProcessParentReadWaitObject() - lProcessResponse["ActivitySpecificationDict"]=lJSONInput - #Выполнить вызов функции - lProcessResponse["Result"]=JSONNormalize.JSONNormalizeDictListStrIntBool(locals()[lJSONInput['ActivityName']](*lJSONInput['ArgumentList'],**lJSONInput['ArgumentDict'])) - except Exception as e: - #Установить флаг ошибки - lProcessResponse["ErrorFlag"]=True - #Зафиксировать traceback - lProcessResponse["ErrorTraceback"]=traceback.format_exc() - #Зафиксировать Error message - lProcessResponse["ErrorMessage"]=str(e) - #lProcessResponse["ErrorArgs"]=str(e.args) - #Отправить ответ в родительский процесс - ProcessCommunicator.ProcessParentWriteObject(lProcessResponse) - -else: - print('Debug mode is turned on!') - -#if __name__ == '__main__': -# if len(sys.argv) > 1: -# lFunctionArgs = sys.argv[2:] -# print(locals()[sys.argv[1]](*lFunctionArgs)) - - diff --git a/Robot/build/lib/pyOpenRPA/IntegrationOrchestrator.py b/Robot/build/lib/pyOpenRPA/IntegrationOrchestrator.py deleted file mode 100644 index be03032c..00000000 --- a/Robot/build/lib/pyOpenRPA/IntegrationOrchestrator.py +++ /dev/null @@ -1,46 +0,0 @@ -import requests -import grequests -#from requests import async -import json -################################### -##Orchestrator integration module (safe use when orchestrator is turned off) -################################### - -################################################################################ -#Send data to orchestrator (asynchronyous) -#Example: t=IntegrationOrchestrator.DataSend(["Storage","Robot_R01"],{"RunDateTimeString":"Test1","StepCurrentName":"Test2","StepCurrentDuration":"Test333","SafeStopSignal":True},"localhost",8081) -def DataSend(inKeyList,inValue,inOrchestratorHost="localhost",inOrchestratorPort=80): - lURL = f'http://{inOrchestratorHost}:{inOrchestratorPort}/ProcessingRun' - lDataJSON = {"actionList":[{"type":"AdministrationGlobalDictSetKeyListValue","key_list":inKeyList,"value":inValue}]} - #lAsyncList = [] - lResultItem = [grequests.post(lURL, json=lDataJSON)] - return grequests.map(lResultItem) - #lAsyncList.append(lResultItem) - #return async.map(lAsyncList) -################################################################################ -#recieve Data from orchestrator -#t=IntegrationOrchestrator.DataRecieve(["Storage","Robot_R01"],"localhost",8081) -def DataRecieve(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80): - lURL = f'http://{inOrchestratorHost}:{inOrchestratorPort}/ProcessingRun' - lDataJSON = {"actionList":[{"type":"AdministrationGlobalDictGetKeyListValue","key_list":inKeyList}]} - try: - lResult = requests.post(lURL, json=lDataJSON) - lResultJSON = json.loads(lResult.text) - return lResultJSON["actionListResult"][0]["value"] - except Exception: - return None -################################################################################ -#Check if orchestrator has safe stop signal -#Example: IntegrationOrchestrator.SafeStopSignalIs(["Storage","Robot_R01","SafeStopSignal"],"localhost",8081) -def SafeStopSignalIs(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80): - lResult=False - lResponse=DataRecieve(inKeyList,inOrchestratorHost,inOrchestratorPort) - if lResponse is not None: - lResult = lResponse - return lResult -################################################################################ -#Reset SafeStop signal in orchestrator -#Example: t=IntegrationOrchestrator.SafeStopSignalReset(["Storage","Robot_R01","SafeStopSignal"],"localhost",8081) -def SafeStopSignalReset(inKeyList,inOrchestratorHost="localhost",inOrchestratorPort=80): - lResponse=DataSend(inKeyList,False,inOrchestratorHost,inOrchestratorPort) - return lResponse \ No newline at end of file diff --git a/Robot/build/lib/pyOpenRPA/JSONNormalize.py b/Robot/build/lib/pyOpenRPA/JSONNormalize.py deleted file mode 100644 index ef540777..00000000 --- a/Robot/build/lib/pyOpenRPA/JSONNormalize.py +++ /dev/null @@ -1,83 +0,0 @@ -import json - -#################################### -#Info: Internal JSONNormalize module of the Robot app (OpenRPA - Robot) -#################################### -# JSONNormalize Module - Prepare dict or list for JSON (delete object from the structure) - -############################### -####Нормализация под JSON (в JSON нельзя передавать классы - только null, числа, строки, словари и массивы) -############################### -#Нормализация словаря под JSON -def JSONNormalizeDict(inDictionary): - #Сделать копию объекта - lResult=inDictionary.copy() - #Перебор всех элементов - for lItemKey,lItemValue in inDictionary.items(): - #Флаг удаления атрибута - lFlagRemoveAttribute=False - #Если строка или число или массив или объект или None - оставить - if ( - type(lItemValue) is dict or - type(lItemValue) is int or - type(lItemValue) is str or - type(lItemValue) is list or - type(lItemValue) is bool or - lItemValue is None): - True==True - else: - lFlagRemoveAttribute=True - #Рекурсивный вызов, если объект является словарем - if type(lItemValue) is dict: - lResult[lItemKey]=JSONNormalizeDict(lItemValue) - #Рекурсивный вызов, если объект является списком - if type(lItemValue) is list: - lResult[lItemKey]=JSONNormalizeList(lItemValue) - ############################# - #Конструкция по удалению ключа из словаря - if lFlagRemoveAttribute: - lResult.pop(lItemKey) - #Вернуть результат - return lResult -#Нормализация массива под JSON -def JSONNormalizeList(inList): - lResult=[] - #Циклический обход - for lItemValue in inList: - #Если строка или число или массив или объект или None - оставить - if ( - type(lItemValue) is int or - type(lItemValue) is str or - type(lItemValue) is bool or - lItemValue is None): - lResult.append(lItemValue) - #Если является словарем - вызвать функцию нормализации словаря - if type(lItemValue) is dict: - lResult.append(JSONNormalizeDict(lItemValue)) - #Если является массиваом - вызвать функцию нормализации массива - if type(lItemValue) is list: - lResult.append(JSONNormalizeList(lItemValue)) - #Вернуть результат - return lResult -#Определить объект - dict or list - и нормализовать его для JSON -def JSONNormalizeDictList(inDictList): - lResult={} - if type(inDictList) is dict: - lResult=JSONNormalizeDict(inDictList) - if type(inDictList) is list: - lResult=JSONNormalizeList(inDictList) - return lResult; -def JSONNormalizeDictListStrIntBool(inDictListStrIntBool): - lResult=None - if type(inDictListStrIntBool) is dict: - lResult=JSONNormalizeDict(inDictListStrIntBool) - if type(inDictListStrIntBool) is list: - lResult=JSONNormalizeList(inDictListStrIntBool) - if type(inDictListStrIntBool) is str: - lResult=inDictListStrIntBool - if type(inDictListStrIntBool) is int: - lResult=inDictListStrIntBool - if type(inDictListStrIntBool) is bool: - lResult=inDictListStrIntBool - return lResult; - diff --git a/Robot/build/lib/pyOpenRPA/ProcessCommunicator.py b/Robot/build/lib/pyOpenRPA/ProcessCommunicator.py deleted file mode 100644 index 2ab4ceaf..00000000 --- a/Robot/build/lib/pyOpenRPA/ProcessCommunicator.py +++ /dev/null @@ -1,143 +0,0 @@ -import json -import subprocess -import zlib -import sys -import os -from . import JSONNormalize -import pdb -############################################ -####Межпроцессное взаимодействие -############################################ -#ProcessParentReadWaitString -def ProcessParentReadWaitString(): - #Выполнить чтение строки - #ctypes.windll.user32.MessageBoxW(0, "Hello", "Your title", 1) - lResult = sys.stdin.buffer.readline() - #Вернуть потенциальные \n - lResult = lResult.replace(b'{{n}}',b'\n') - lResult = zlib.decompress(lResult[0:-1]) - lResult = lResult.decode("utf-8") - #Вернуть результат - return lResult - -#ParentProcessWriteString -def ProcessParentWriteString(lString): - lByteString = zlib.compress(lString.encode("utf-8")) - #Выполнить отправку строки в родительский процесс - #Вернуть потенциальные \n - lByteString = lByteString.replace(b'\n',b'{{{n}}}') - #Вернуть \r - lByteString = lByteString.replace(b'\r',b'{{{r}}}') - #Вернуть \0 - lByteString = lByteString.replace(b'\0',b'{{{0}}}') - #Вернуть \a - lByteString = lByteString.replace(b'\a',b'{{{a}}}') - #Вернуть \b - lByteString = lByteString.replace(b'\b',b'{{{b}}}') - #Вернуть \t - lByteString = lByteString.replace(b'\t',b'{{{t}}}') - #Вернуть \v - lByteString = lByteString.replace(b'\v',b'{{{v}}}') - #Вернуть \f - lByteString = lByteString.replace(b'\f',b'{{{f}}}') - ############################ - #print(b"Result: "+lByteString) - #lByteString= b'x\x9c\xdd\x95]O\xc20\x14\x86\xffJ\xb3[5\xa1Cqz\x07\xc4\xe8\x8d\x1fQ\x13.\x0cYJw\xb6U\xbav\xe9\xce"\x84\xf0\xdfm\'"\xb8\xa0L%Q\xb3\x9b\xf6=\xdfO\x9a\xb3\x99\x17\x97\x8a\xa3\xd0\xea\x8ae\xe0\x9d\x12\xaf[\xa2\xce\x98S\xee\x80\x19\x9e^\xea\xb2\x803\t\x19(\xbc\x10`\x9c6\xf5\xf6\x89\xc7LRt\x8daS\x1b\xf5\xf00\xf3\xd4"\xc1u\x0e\xea\xf6\xa6K\x0e\xc8\xb9\xd6\x89\x04\xd2O\x8d\xb6&\x1bb\x04OC\x84\t~\xe2\x97\x1b\xcd\xa1(B\x11YG\xdaj\xfb\xc1\x9b\xb8\xa2\xa4LE\xd2\xd5\xa4\xf6\xdenY\x85Kf\xc3^;yI\x18\x0eD\x94\x00\x0e\x84{{n}}\xa9K\xce\xb5B\xa3e\x88\xd3\xbc\xf2Z\xd5\xaa\x82\xaa\x94\xd25\x0b\x1c\x99J\xaa\x023OB\xec\xbavEP\xe7\x8b\x93\x11I\xeaTz\xe2\xbb\xebH\xa3eW5\xe8\xb7\xe6\xce^*\x14\xb6\x83e\xda\xf9phe]b^\xe2\xf5\xe8\xd1Vp\xf0\xfe.\xbb\x1b\xa6`\x87\xfc8\x1a\x9bSE0q\xa2\x15\xeer\xe0"\x16\xbcz\x9f\xfdT\xc8h\x9d\xdf\xc7\xd4\xbe\xcdj1\xd9:\xa9\x1f\xe1B7\x81\xa1\xef\xc0\xd0:\x98\xc3-\xc0\xd4X\xfc\xda\xf1i\xbb\xe9\xfc\xdb<\x8c\xff2\x7f\'\xa8\x8d\xdf\xdab\xfc\x9e\xd6\xe3\x8c\x99qQ\xe3\xb0f\xd9\x19\x90{\xade\x8f\x99/3\xa1AC(\xfe\x16P\x06F \x90\xb3\t\x07Iba\x17\x83P\xa4\xbf\xb7G\x9e\x04\xa6vE\x13\xb6\xfc\x13\xd6\xa85\x0b\xdd\x19\xd6^i\x11\xa8FT;G\xfe\x06\xac\xc1q\xb0N\x956\xd84\xae\xe4p\xbe\xfa=\x03\x01\xce\x95\x9a' - #lByteString = b"x\x9c\xb5\x91\xcfO\xc3 \x14\xc7\xff\x95\xa6\xd7uI\xf9Q\x8a\xde\xd4\x93\x07\xbdx\xf00\x97\x05)[I(\x90\x8ef3\xcb\xfew\x81M\xbb\xd9M]\x8c!y\xd0\xf7}\xbc\xef\xe3\xd3\xc9&\xd5\xac\x11\xe9u\x92j\xb1J@2N\x1e\x8d\x13\x96U\xa3Q\x9a%i+y=sb\xed\xceV\xd8\xd6p\xb1\\\xced\xe5K{{n}}\x80`\x9f\xeb\x135\xd3\x95{{n}}.\x08RR\xe4>\xc3\x15\xf3\x97>\xbc\x8f:r\xa3]k\xd4\xcc\xbd\xd9(>K]\x99\xd5\xa1\x12\xbd\x00\xc6\xb0\xcc\xcb0\xa4\xe0\x8e\xe9E4\xd8\xa4J\xcc\xc3\xb44\x07^r\xc6\xfa3\x04(\xbeeQ\x07\x05P\x1a\xa4W\xe3\x9ci\xfc\xf7\x15(\xb6A\xee\xb4\x93\x8d\xd85\x9f`?\xf6n\xd8i0v\xadw\xd5\x95X\x87n>\xf1d\x05\x97s\xc9\x99\x93F\xdf\xd5R\xc5K=\xcc\x1bk\xd5^\x1d`\xfc\xa2]\x06PwJ\r\xf0\x9d\xa2\xf6 tw\xcb\xda\x01\xb6}\x83\xd3\xcc\x00\xec\x99\x15\xf4\x88Y\x99\x1f2\x83\xb4\xfc\x8e\x99\xdf\xb3d\x0c\x01.1E\x04\x93l\xff\x8e\xcf\x7f6\xa4Z\xfc\x82\xeaK\x97c BD\xf3\x101\x89g\xba\x8b\x03\xd0?\x97\xff#\xfb{'\x9a\x8b\xe0\x03H\xc89\xfa\x08\x15\x7f\xa2\x0f >\x80_\x0e\xe0\x93\xb3\xf0\xc3\xc4\xd3m\\\xef\xf8\x958\xa0" - #lt=open("logSendByteStringWithoutN.log","wb") - #lt.write(lByteString) - #lt.close() - ############################ - sys.stdout.buffer.write(lByteString+bytes("\n","utf-8")) - sys.stdout.flush(); - return -#ProcessParentWriteObject -def ProcessParentWriteObject(inObject): - #Выполнить нормализацию объекта перед форматированием в JSON - JSONNormalize.JSONNormalizeDictList(inObject) - #Выполнить отправку сконвертированного объекта в JSON - ProcessParentWriteString(json.dumps(inObject)) - return -#ProcessParentReadWaitObject -def ProcessParentReadWaitObject(): - #Выполнить получение и разбор объекта - lResult=json.loads(ProcessParentReadWaitString()); - return lResult; - -#ProcessChildSendString -def ProcessChildSendString(lProcess,lString): - lByteString = zlib.compress(lString.encode("utf-8")) - #Вернуть потенциальные \n - lByteString = lByteString.replace(b'\n',b'{{n}}') - #Отправить сообщение в дочерний процесс - lProcess.stdin.write(lByteString+bytes('\n',"utf-8")) - #print(str(lByteString+bytes('\n',"utf-8"))) - lProcess.stdin.flush() - #Вернуть результат - return - -#ProcessChildReadWaitString -def ProcessChildReadWaitString(lProcess): - #Ожидаем ответ от процесса - #pdb.set_trace() - lResult = lProcess.stdout.readline() - #Обработка спец символов - #print(b'NewLine: '+lResult) - #Вернуть потенциальные \n - lResult = lResult.replace(b'{{{n}}}',b'\n') - #Вернуть \r - lResult = lResult.replace(b'{{{r}}}',b'\r') - #Вернуть \0 - lResult = lResult.replace(b'{{{0}}}',b'\0') - #Вернуть \a - lResult = lResult.replace(b'{{{a}}}',b'\a') - #Вернуть \b - lResult = lResult.replace(b'{{{b}}}',b'\b') - #Вернуть \t - lResult = lResult.replace(b'{{{t}}}',b'\t') - #Вернуть \v - lResult = lResult.replace(b'{{{v}}}',b'\v') - #Вернуть \f - lResult = lResult.replace(b'{{{f}}}',b'\f') - #print("check") - #print(str(lResult)) - lResult = zlib.decompress(lResult[0:-1]) - lResult = lResult.decode("utf-8") - #Вернуть результат - return lResult - -#ProcessChildSendObject -def ProcessChildSendObject(inProcess,inObject): - #Выполнить отправку сконвертированного объекта в JSON - ProcessChildSendString(inProcess,json.dumps(inObject)) - return -#ProcessChildReadWaitObject -def ProcessChildReadWaitObject(inProcess): - #Выполнить получение и разбор объекта - lResult=json.loads(ProcessChildReadWaitString(inProcess)); - return lResult; - -#ProcessChildSendReadWaitString -def ProcessChildSendReadWaitString(lProcess,lString): - ProcessChildSendString(lProcess,lString) - #Вернуть результат - return ProcessChildReadWaitString(lProcess) -#ProcessChildSendReadWaitObject -def ProcessChildSendReadWaitObject(inProcess,inObject): - ProcessChildSendObject(inProcess,inObject) - #Вернуть результат - return ProcessChildReadWaitString(inProcess) -#ProcessChildSendReadWaitQueue -#QueueObject - [Object,Object,...] -def ProcessChildSendReadWaitQueueObject(inProcess,inQueueObject): - lOutputObject=[] - #Циклическая отправка запросов в дочерний объект - for lItem in inQueueObject: - #Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами - ProcessChildSendObject(inProcess,lItem) - #Получить ответ от дочернего процесса - lResponseObject=ProcessChildReadWaitObject(inProcess) - #Добавить в выходной массив - lOutputObject.append(lResponseObject) - #Сформировать ответ - return lOutputObject diff --git a/Robot/build/lib/pyOpenRPA/Robot.py b/Robot/build/lib/pyOpenRPA/Robot.py deleted file mode 100644 index da848224..00000000 --- a/Robot/build/lib/pyOpenRPA/Robot.py +++ /dev/null @@ -1,158 +0,0 @@ -import pdb -import json -import subprocess -import zlib -import os -from . import ProcessCommunicator -import importlib -import traceback -import logging -import sys -import datetime -import struct -import shutil -#Создать файл логирования -# add filemode="w" to overwrite -if not os.path.exists("Reports"): - os.makedirs("Reports") -logging.basicConfig(filename="Reports\ReportRobotRun_"+datetime.datetime.now().strftime("%Y_%m_%d")+".log", level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") - -#################################### -#Info: Main module of the Robot app (OpenRPA - Robot) -#################################### - -#Usage: -#Here you can run some activity or list of activities - -#After import this module you can use the folowing functions: -#ActivityRun(inActivitySpecificationDict): outActivityResultDict - function - run activity (function or procedure) -#ActivityRunJSON(inActivitySpecificationDictJSON): outActivityResultDictJSON -#ActivityListRun(inActivitySpecificationDictList): outActivityResultDictList - function - run list of activities (function or procedure) -#ActivityListRunJSON(inActivitySpecificationDictListJSON): outActivityResultDictListJSON - -#Naming: -#Activity - some action/list of actions -#Module - Any *.py file, which consist of area specific functions -#Argument - -#inActivitySpecificationDict: -#{ -# ModuleName: <"GUI"|..., str>, -# ActivityName: , -# ArgumentList: [, ...] - optional, -# ArgumentDict: {:, ...} - optional -#} - -#outActivityResultDict: -#{ -# ActivitySpecificationDict: { -# ModuleName: <"GUI"|..., str>, -# ActivityName: , -# ArgumentList: [, ...] - optional, -# ArgumentDict: {: , ...} - optional -# }, -# ErrorFlag: , -# ErrorMessage: - required if ErrorFlag is true, -# ErrorTraceback: - required if ErrorFlag is true, -# Result: - required if ErrorFlag is false -#} - -#################### -#Section: Module initialization -#################### -#Start childprocess - GUI Module 32 bit -if not os.path.isfile("..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe"): - shutil.copyfile('..\\Resources\\WPy32-3720\\python-3.7.2\\python.exe',"..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe") -mProcessGUI_x32 = subprocess.Popen(['..\\Resources\\WPy32-3720\\python-3.7.2\\OpenRPARobotGUIx32.exe','..\\Robot\\GUI.py','release'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) -#Start childprocess - GUI Module 64 bit - uncomment after WPy64 installation -ProcessCommunicator.ProcessChildSendObject(mProcessGUI_x32,{"ModuleName":"GUI","ActivityName":"Get_OSBitnessInt","ArgumentList":[],"ArgumentDict":{}}) -lOSBitness = ProcessCommunicator.ProcessChildReadWaitObject(mProcessGUI_x32)["Result"] - -lProcessBitnessStr = str(struct.calcsize("P") * 8) -#start 64 if system support 64 -mProcessGUI_x64= None -if lOSBitness == 64: - if not os.path.isfile("..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\OpenRPARobotGUIx64.exe"): - shutil.copyfile('..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\python.exe',"..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\OpenRPARobotGUIx64.exe") - mProcessGUI_x64 = subprocess.Popen(['..\\Resources\\WPy64-3720\\python-3.7.2.amd64\\OpenRPARobotGUIx64.exe','..\\Robot\\GUI.py','release'],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - -#################### -#Section: Activity -#################### -def ActivityRun(inActivitySpecificationDict): - #Выполнить отправку в модуль GUI, если ModuleName == "GUI" - #pdb.set_trace() - if inActivitySpecificationDict["ModuleName"] == "GUI": - if "ArgumentList" not in inActivitySpecificationDict: - inActivitySpecificationDict["ArgumentList"]=[] - if "ArgumentDict" not in inActivitySpecificationDict: - inActivitySpecificationDict["ArgumentDict"]={} - - #Если mProcessGUI_x64 не инициализирован - lFlagRun64=True - if mProcessGUI_x64 is None: - lFlagRun64=False - else: - if inActivitySpecificationDict["ActivityName"]=="UIOSelectorsSecs_WaitAppear_List": - #Функция ожидания появления элементов (тк элементы могут быть недоступны, неизвестно в каком фреймворке каждый из них может появиться) - lFlagRun64=True - elif inActivitySpecificationDict["ActivityName"].startswith("UIOSelector") or inActivitySpecificationDict["ActivityName"].startswith("PWASpecification"): - if len(inActivitySpecificationDict["ArgumentList"])>0: - if len(inActivitySpecificationDict["ArgumentList"][0])>0: - #Определение разрядности (32 и 64) для тех функций, где это необходимо - ###################################################### - #Выполнить проверку разрядности через UIOSelector_Get_BitnessInt - #Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами - #pdb.set_trace() - #Внимание! Проверка разрядности специально делается на процессе 64 бита, тк процесс 32 бита зависает на 35 итерации проверки - ProcessCommunicator.ProcessChildSendObject(mProcessGUI_x64,{"ModuleName":"GUI","ActivityName":"UIOSelector_Get_BitnessInt","ArgumentList":[inActivitySpecificationDict["ArgumentList"][0]],"ArgumentDict":inActivitySpecificationDict["ArgumentDict"]}) - #Получить ответ от дочернего процесса - lResponseObject=ProcessCommunicator.ProcessChildReadWaitObject(mProcessGUI_x64) - #pdb.set_trace() - if lResponseObject["Result"]==32: - lFlagRun64=False - #Запуск 64 - #pdb.set_trace() - if lFlagRun64: - #Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами - ProcessCommunicator.ProcessChildSendObject(mProcessGUI_x64,inActivitySpecificationDict) - #Получить ответ от дочернего процесса - lResponseObject=ProcessCommunicator.ProcessChildReadWaitObject(mProcessGUI_x64) - else: - #Запуск 32 - #Отправить запрос в дочерний процесс, который отвечает за работу с Windows окнами - ProcessCommunicator.ProcessChildSendObject(mProcessGUI_x32,inActivitySpecificationDict) - #Получить ответ от дочернего процесса - lResponseObject=ProcessCommunicator.ProcessChildReadWaitObject(mProcessGUI_x32) - - #Остальные модули подключать и выполнять здесь - else: - lArgumentList=[] - if "ArgumentList" in inActivitySpecificationDict: - lArgumentList=inActivitySpecificationDict["ArgumentList"] - lArgumentDict={} - if "ArgumentDict" in inActivitySpecificationDict: - lArgumentDict=inActivitySpecificationDict["ArgumentDict"] - #Подготовить результирующую структуру - lResponseObject={"ActivitySpecificationDict":inActivitySpecificationDict,"ErrorFlag":False} - try: - #Подключить модуль для вызова - lModule=importlib.import_module(inActivitySpecificationDict["ModuleName"]) - #Найти функцию - lFunction=getattr(lModule,inActivitySpecificationDict["ActivityName"]) - #Выполнить вызов и записать результат - lResponseObject["Result"]=lFunction(*lArgumentList,**lArgumentDict) - except Exception as e: - #Установить флаг ошибки и передать тело ошибки - lResponseObject["ErrorFlag"]=True - lResponseObject["ErrorMessage"]=str(e) - lResponseObject["ErrorTraceback"]=traceback.format_exc() - return lResponseObject -######################################################### -#Run list of activities -######################################################### -def ActivityListRun(inActivitySpecificationDictList): - lResult=[] - for lItem in inActivitySpecificationDictList: - lResult.append(ActivityRun(lItem)) - return lResult \ No newline at end of file diff --git a/Robot/build/lib/pyOpenRPA/ValueVerify.py b/Robot/build/lib/pyOpenRPA/ValueVerify.py deleted file mode 100644 index ee28f066..00000000 --- a/Robot/build/lib/pyOpenRPA/ValueVerify.py +++ /dev/null @@ -1,21 +0,0 @@ -#valueVerify -#inTypeClass int, str, dict, list, NoneType -def valueVerify(inValue,inTypeClass,inNotValidValue): - lResult = inNotValidValue - if inValue is not None: - if type(inValue) == inTypeClass: - lResult = inValue - #Вернуть результат - return lResult -#valueVerifyDict -def valueVerifyDict(inDict,inKey,inTypeClass,inNotValidValue): - lResult = inNotValidValue - if inKey in inDict: - lResult = valueVerify(inDict[inKey],inTypeClass,inNotValidValue) - return lResult -#valueVerifyList -def valueVerifyList(inList,inIndex,inTypeClass,inNotValidValue): - lResult = inNotValidValue - if inIndex in inList: - lResult = valueVerify(inList[inIndex],inTypeClass,inNotValidValue) - return lResult diff --git a/Robot/build/lib/pyOpenRPA/Window.py b/Robot/build/lib/pyOpenRPA/Window.py deleted file mode 100644 index 8476bba7..00000000 --- a/Robot/build/lib/pyOpenRPA/Window.py +++ /dev/null @@ -1,13 +0,0 @@ -import ctypes -#################################### -#Info: Window module of the Robot app (OpenRPA - Robot) -#################################### -# WIndow Module - Show information dialog messages to user by the modal windows - -################ -###DialogYesNo -################ -#return 1 - Yes; 2 - No -def DialogYesNo(inTitle,inBody): - lResult = ctypes.windll.user32.MessageBoxW(0, inBody, inTitle, 1) - return lResult \ No newline at end of file diff --git a/Robot/build/lib/pyOpenRPA/__init__.py b/Robot/build/lib/pyOpenRPA/__init__.py deleted file mode 100644 index f69e75bb..00000000 --- a/Robot/build/lib/pyOpenRPA/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -r""" - -The OpenRPA package (from UnicodeLabs) - -""" -__version__ = 'v1.0.15' -__all__ = [ - 'GUI','Clipboard','IntegrationOrchestrator','Window', 'ProcessCommunicator' -] -__author__ = 'Ivan Maslov ' -from . import GUI -from . import Clipboard -from . import IntegrationOrchestrator -from . import Window -from . import ProcessCommunicator \ No newline at end of file diff --git a/Robot/dist/pyOpenRPA-1.0.15-py3-none-any.whl b/Robot/dist/pyOpenRPA-1.0.15-py3-none-any.whl deleted file mode 100644 index 9289b383d79949b682f4e03cb860471b4bc1c9dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24825 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≫UFk2d2x=fh| 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