diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/INSTALLER b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/INSTALLER similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/INSTALLER rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/INSTALLER diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/METADATA b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/METADATA new file mode 100644 index 00000000..b41a9476 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/METADATA @@ -0,0 +1,80 @@ +Metadata-Version: 2.1 +Name: pyOpenRPA +Version: 1.0.15 +Summary: First open source RPA platform for business +Home-page: https://gitlab.com/UnicodeLabs/OpenRPA +Author: Ivan Maslov +Author-email: Ivan.Maslov@unicodelabs.ru +License: MIT +Keywords: OpenRPA RPA Robot Automation Robotization +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3.7 +Description-Content-Type: text/markdown +Requires-Dist: pywinauto (>=0.6.6) +Requires-Dist: WMI (>=1.4.9) +Requires-Dist: pillow (>=6.0.0) +Requires-Dist: keyboard (>=0.13.3) +Requires-Dist: pyautogui (>=0.9.44) +Requires-Dist: pywin32 (>=224) + +# OpenRPA +First open source RPA platform for business is released! + +# How to run +Studio +Double click to Studio\StudioRun_32.cmd or Studio\StudioRun_64.cmd + +# Robot how to debug +Robot\PythonDebug_64.cmd +import Robot +Robot.ActivityRun( + { + ModuleName: <"GUI"|..., str>, + ActivityName: , + ArgumentList: [, ...] - optional, + ArgumentDict: {:, ...} - optional + } +) + +# Robot example script: +Robot\Examples\GetFolderList\Python_32_Script_Run.cmd + +# Python 32 bit +Resources\WPy32-3720\python-3.7.2\python.exe + +# Python 64 bit +Resources\WPy64-3720\python-3.7.2.amd64\python.exe + +# Module GUI activity List: +############################ +Новая версия +############################ +Получить СЃРїРёСЃРѕРє элементов, который удовлетворяет условиям через расширенный движок РїРѕРёСЃРєР° +[ + { + "index":<Позиция элемента РІ родительском объекте>, + "depth_start" - глубина, СЃ которой начинается РїРѕРёСЃРє (РїРѕ умолчанию 1) + "depth_end" - глубина, РґРѕ которой ведется РїРѕРёСЃРє (РїРѕ умолчанию 1) + "class_name" - наименование класса, который требуется искать + "title" - наименование заголовка + "rich_text" - наименование rich_text + } +] + + +# Open RPA Wiki +- [Home](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/home) +- [04. Desktop app access (win32 & ui automation)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/04.-Desktop-app-access-(win32-&-ui-automation)) + +#Dependencies +* Python 3 x32 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF] +* Python 3 x64 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF] +* pywinauto (Windows GUI automation) +* Semantic UI CSS framework +* JsRender by https://www.jsviews.com (switch to Handlebars) +* Handlebars + +Created by Unicode Labs (Ivan Maslov) + diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/RECORD b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/RECORD new file mode 100644 index 00000000..07ef7d0a --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/RECORD @@ -0,0 +1,23 @@ +pyOpenRPA-1.0.15.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pyOpenRPA-1.0.15.dist-info/METADATA,sha256=OVAh2YFn_pseeM5KBSk8G19yTsO-jBMZDY8i9S8saJs,3510 +pyOpenRPA-1.0.15.dist-info/RECORD,, +pyOpenRPA-1.0.15.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97 +pyOpenRPA-1.0.15.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10 +pyOpenRPA/Clipboard.py,sha256=q76X8L21zJwcwdoJJNPeCEwAV30xS6ylHP1WwvtxoWI,722 +pyOpenRPA/GUI.py,sha256=SzbCIZMAf53vEM5cwY55itseM5gcMSowF7POo2KwyeM,68726 +pyOpenRPA/IntegrationOrchestrator.py,sha256=T1g1jJM7_JMTSVP50DTM5WHrMh1w8wovvcBXl1nEokU,2656 +pyOpenRPA/JSONNormalize.py,sha256=aIuVzuZDazhxkCOzoOjfhHVz66mp2FWdfPv5E7KWF5Y,3890 +pyOpenRPA/ProcessCommunicator.py,sha256=eT_NgoAQBUxSu9alCGxuauuussrP50HDoiBA9JcUkOc,8114 +pyOpenRPA/Robot.py,sha256=a_xiI4SuSpGFAfnSrvhL8qeuFVHrBUEGOFwelRWIvTA,9407 +pyOpenRPA/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777 +pyOpenRPA/Window.py,sha256=UJl-sg4RvvJ35aG9jZOzqGVwE15XK7qPHqoOBD13xFk,431 +pyOpenRPA/__init__.py,sha256=wJLBEdKdtm0jeWLL-KyBrTN2vfDK75uF0qGpoGQHQgI,372 +pyOpenRPA/__pycache__/Clipboard.cpython-37.pyc,, +pyOpenRPA/__pycache__/GUI.cpython-37.pyc,, +pyOpenRPA/__pycache__/IntegrationOrchestrator.cpython-37.pyc,, +pyOpenRPA/__pycache__/JSONNormalize.cpython-37.pyc,, +pyOpenRPA/__pycache__/ProcessCommunicator.cpython-37.pyc,, +pyOpenRPA/__pycache__/Robot.cpython-37.pyc,, +pyOpenRPA/__pycache__/ValueVerify.cpython-37.pyc,, +pyOpenRPA/__pycache__/Window.cpython-37.pyc,, +pyOpenRPA/__pycache__/__init__.cpython-37.pyc,, diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/WHEEL b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/WHEEL similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/WHEEL rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/WHEEL diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/top_level.txt b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/top_level.txt new file mode 100644 index 00000000..4170df85 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/top_level.txt @@ -0,0 +1 @@ +pyOpenRPA diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/METADATA b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/METADATA deleted file mode 100644 index 377d259f..00000000 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/METADATA +++ /dev/null @@ -1,23 +0,0 @@ -Metadata-Version: 2.1 -Name: pyOpenRPA -Version: 1.0.7 -Summary: First open source RPA platform for business -Home-page: https://gitlab.com/UnicodeLabs/OpenRPA -Author: Ivan Maslov -Author-email: Ivan.Maslov@unicodelabs.ru -License: MIT -Keywords: OpenRPA RPA Robot Automation Robotization -Platform: UNKNOWN -Classifier: Development Status :: 3 - Alpha -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 3.7 -Requires-Dist: pywinauto (>=0.6.6) -Requires-Dist: WMI (>=1.4.9) -Requires-Dist: pillow (>=6.0.0) -Requires-Dist: keyboard (>=0.13.3) -Requires-Dist: pyautogui (>=0.9.44) -Requires-Dist: pywin32 (>=224) - -UNKNOWN - - diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/RECORD b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/RECORD deleted file mode 100644 index 1560492d..00000000 --- a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/RECORD +++ /dev/null @@ -1,5 +0,0 @@ -pyOpenRPA-1.0.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pyOpenRPA-1.0.7.dist-info/METADATA,sha256=_rN4UG95FENZbFjRiTmaCf31KPJa8XKkFoFbDR3vgaI,654 -pyOpenRPA-1.0.7.dist-info/RECORD,, -pyOpenRPA-1.0.7.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97 -pyOpenRPA-1.0.7.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 diff --git a/Robot/Clipboard.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Clipboard.py similarity index 100% rename from Robot/Clipboard.py rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Clipboard.py diff --git a/Robot/GUI.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/GUI.py similarity index 99% rename from Robot/GUI.py rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/GUI.py index a572260d..05b139a5 100644 --- a/Robot/GUI.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/GUI.py @@ -12,8 +12,8 @@ import win32api import win32clipboard import time import traceback -import ProcessCommunicator -import JSONNormalize +from . import ProcessCommunicator +from . import JSONNormalize from threading import Timer import datetime import logging diff --git a/Robot/IntegrationOrchestrator.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/IntegrationOrchestrator.py similarity index 100% rename from Robot/IntegrationOrchestrator.py rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/IntegrationOrchestrator.py diff --git a/Robot/JSONNormalize.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/JSONNormalize.py similarity index 100% rename from Robot/JSONNormalize.py rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/JSONNormalize.py diff --git a/Robot/ProcessCommunicator.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/ProcessCommunicator.py similarity index 99% rename from Robot/ProcessCommunicator.py rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/ProcessCommunicator.py index 582a1f9a..2ab4ceaf 100644 --- a/Robot/ProcessCommunicator.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/ProcessCommunicator.py @@ -3,7 +3,7 @@ import subprocess import zlib import sys import os -import JSONNormalize +from . import JSONNormalize import pdb ############################################ ####Межпроцессное взаимодействие diff --git a/Robot/Robot.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Robot.py similarity index 99% rename from Robot/Robot.py rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Robot.py index c3f6c5d8..da848224 100644 --- a/Robot/Robot.py +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Robot.py @@ -3,7 +3,7 @@ import json import subprocess import zlib import os -import ProcessCommunicator +from . import ProcessCommunicator import importlib import traceback import logging diff --git a/Robot/ValueVerify.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/ValueVerify.py similarity index 100% rename from Robot/ValueVerify.py rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/ValueVerify.py diff --git a/Robot/Window.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Window.py similarity index 100% rename from Robot/Window.py rename to Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/Window.py diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/__init__.py b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/__init__.py new file mode 100644 index 00000000..f69e75bb --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA/__init__.py @@ -0,0 +1,15 @@ +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/Resources/WPy32-3720/python-3.7.2/Reports/ReportRobotGUIRun_2019_11_08.log b/Resources/WPy32-3720/python-3.7.2/Reports/ReportRobotGUIRun_2019_11_08.log new file mode 100644 index 00000000..3b2761e0 --- /dev/null +++ b/Resources/WPy32-3720/python-3.7.2/Reports/ReportRobotGUIRun_2019_11_08.log @@ -0,0 +1 @@ +2019-11-08 19:47:24,560 - RobotLogger - INFO - Robot/GUI: Debug mode, x32 diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/INSTALLER b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/INSTALLER similarity index 100% rename from Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/INSTALLER rename to Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/INSTALLER diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/METADATA b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/METADATA new file mode 100644 index 00000000..b41a9476 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/METADATA @@ -0,0 +1,80 @@ +Metadata-Version: 2.1 +Name: pyOpenRPA +Version: 1.0.15 +Summary: First open source RPA platform for business +Home-page: https://gitlab.com/UnicodeLabs/OpenRPA +Author: Ivan Maslov +Author-email: Ivan.Maslov@unicodelabs.ru +License: MIT +Keywords: OpenRPA RPA Robot Automation Robotization +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3.7 +Description-Content-Type: text/markdown +Requires-Dist: pywinauto (>=0.6.6) +Requires-Dist: WMI (>=1.4.9) +Requires-Dist: pillow (>=6.0.0) +Requires-Dist: keyboard (>=0.13.3) +Requires-Dist: pyautogui (>=0.9.44) +Requires-Dist: pywin32 (>=224) + +# OpenRPA +First open source RPA platform for business is released! + +# How to run +Studio +Double click to Studio\StudioRun_32.cmd or Studio\StudioRun_64.cmd + +# Robot how to debug +Robot\PythonDebug_64.cmd +import Robot +Robot.ActivityRun( + { + ModuleName: <"GUI"|..., str>, + ActivityName: , + ArgumentList: [, ...] - optional, + ArgumentDict: {:, ...} - optional + } +) + +# Robot example script: +Robot\Examples\GetFolderList\Python_32_Script_Run.cmd + +# Python 32 bit +Resources\WPy32-3720\python-3.7.2\python.exe + +# Python 64 bit +Resources\WPy64-3720\python-3.7.2.amd64\python.exe + +# Module GUI activity List: +############################ +Новая версия +############################ +Получить СЃРїРёСЃРѕРє элементов, который удовлетворяет условиям через расширенный движок РїРѕРёСЃРєР° +[ + { + "index":<Позиция элемента РІ родительском объекте>, + "depth_start" - глубина, СЃ которой начинается РїРѕРёСЃРє (РїРѕ умолчанию 1) + "depth_end" - глубина, РґРѕ которой ведется РїРѕРёСЃРє (РїРѕ умолчанию 1) + "class_name" - наименование класса, который требуется искать + "title" - наименование заголовка + "rich_text" - наименование rich_text + } +] + + +# Open RPA Wiki +- [Home](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/home) +- [04. Desktop app access (win32 & ui automation)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/04.-Desktop-app-access-(win32-&-ui-automation)) + +#Dependencies +* Python 3 x32 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF] +* Python 3 x64 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF] +* pywinauto (Windows GUI automation) +* Semantic UI CSS framework +* JsRender by https://www.jsviews.com (switch to Handlebars) +* Handlebars + +Created by Unicode Labs (Ivan Maslov) + diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/RECORD b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/RECORD new file mode 100644 index 00000000..07ef7d0a --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/RECORD @@ -0,0 +1,23 @@ +pyOpenRPA-1.0.15.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pyOpenRPA-1.0.15.dist-info/METADATA,sha256=OVAh2YFn_pseeM5KBSk8G19yTsO-jBMZDY8i9S8saJs,3510 +pyOpenRPA-1.0.15.dist-info/RECORD,, +pyOpenRPA-1.0.15.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97 +pyOpenRPA-1.0.15.dist-info/top_level.txt,sha256=RPzwQXgYBRo_m5L3ZLs6Voh8aEkMeT29Xsul1w1qE0g,10 +pyOpenRPA/Clipboard.py,sha256=q76X8L21zJwcwdoJJNPeCEwAV30xS6ylHP1WwvtxoWI,722 +pyOpenRPA/GUI.py,sha256=SzbCIZMAf53vEM5cwY55itseM5gcMSowF7POo2KwyeM,68726 +pyOpenRPA/IntegrationOrchestrator.py,sha256=T1g1jJM7_JMTSVP50DTM5WHrMh1w8wovvcBXl1nEokU,2656 +pyOpenRPA/JSONNormalize.py,sha256=aIuVzuZDazhxkCOzoOjfhHVz66mp2FWdfPv5E7KWF5Y,3890 +pyOpenRPA/ProcessCommunicator.py,sha256=eT_NgoAQBUxSu9alCGxuauuussrP50HDoiBA9JcUkOc,8114 +pyOpenRPA/Robot.py,sha256=a_xiI4SuSpGFAfnSrvhL8qeuFVHrBUEGOFwelRWIvTA,9407 +pyOpenRPA/ValueVerify.py,sha256=ObskxU4fOMoCGw74_nzYt6-a5jjrAckb3sdBLYyhYxY,777 +pyOpenRPA/Window.py,sha256=UJl-sg4RvvJ35aG9jZOzqGVwE15XK7qPHqoOBD13xFk,431 +pyOpenRPA/__init__.py,sha256=wJLBEdKdtm0jeWLL-KyBrTN2vfDK75uF0qGpoGQHQgI,372 +pyOpenRPA/__pycache__/Clipboard.cpython-37.pyc,, +pyOpenRPA/__pycache__/GUI.cpython-37.pyc,, +pyOpenRPA/__pycache__/IntegrationOrchestrator.cpython-37.pyc,, +pyOpenRPA/__pycache__/JSONNormalize.cpython-37.pyc,, +pyOpenRPA/__pycache__/ProcessCommunicator.cpython-37.pyc,, +pyOpenRPA/__pycache__/Robot.cpython-37.pyc,, +pyOpenRPA/__pycache__/ValueVerify.cpython-37.pyc,, +pyOpenRPA/__pycache__/Window.cpython-37.pyc,, +pyOpenRPA/__pycache__/__init__.cpython-37.pyc,, diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/WHEEL b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/WHEEL similarity index 100% rename from Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/WHEEL rename to Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/WHEEL diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/top_level.txt b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/top_level.txt new file mode 100644 index 00000000..4170df85 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.15.dist-info/top_level.txt @@ -0,0 +1 @@ +pyOpenRPA diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/METADATA b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/METADATA deleted file mode 100644 index 377d259f..00000000 --- a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/METADATA +++ /dev/null @@ -1,23 +0,0 @@ -Metadata-Version: 2.1 -Name: pyOpenRPA -Version: 1.0.7 -Summary: First open source RPA platform for business -Home-page: https://gitlab.com/UnicodeLabs/OpenRPA -Author: Ivan Maslov -Author-email: Ivan.Maslov@unicodelabs.ru -License: MIT -Keywords: OpenRPA RPA Robot Automation Robotization -Platform: UNKNOWN -Classifier: Development Status :: 3 - Alpha -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python :: 3.7 -Requires-Dist: pywinauto (>=0.6.6) -Requires-Dist: WMI (>=1.4.9) -Requires-Dist: pillow (>=6.0.0) -Requires-Dist: keyboard (>=0.13.3) -Requires-Dist: pyautogui (>=0.9.44) -Requires-Dist: pywin32 (>=224) - -UNKNOWN - - diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/RECORD b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/RECORD deleted file mode 100644 index 1560492d..00000000 --- a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/RECORD +++ /dev/null @@ -1,5 +0,0 @@ -pyOpenRPA-1.0.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pyOpenRPA-1.0.7.dist-info/METADATA,sha256=_rN4UG95FENZbFjRiTmaCf31KPJa8XKkFoFbDR3vgaI,654 -pyOpenRPA-1.0.7.dist-info/RECORD,, -pyOpenRPA-1.0.7.dist-info/WHEEL,sha256=qB97nP5e4MrOsXW5bIU5cUn_KSVr10EV0l-GCHG9qNs,97 -pyOpenRPA-1.0.7.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Clipboard.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Clipboard.py new file mode 100644 index 00000000..12b43186 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Clipboard.py @@ -0,0 +1,22 @@ +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/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/GUI.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/GUI.py new file mode 100644 index 00000000..05b139a5 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/GUI.py @@ -0,0 +1,1210 @@ +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/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/IntegrationOrchestrator.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/IntegrationOrchestrator.py new file mode 100644 index 00000000..be03032c --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/IntegrationOrchestrator.py @@ -0,0 +1,46 @@ +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/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/JSONNormalize.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/JSONNormalize.py new file mode 100644 index 00000000..ef540777 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/JSONNormalize.py @@ -0,0 +1,83 @@ +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/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/ProcessCommunicator.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/ProcessCommunicator.py new file mode 100644 index 00000000..2ab4ceaf --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/ProcessCommunicator.py @@ -0,0 +1,143 @@ +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/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Robot.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Robot.py new file mode 100644 index 00000000..da848224 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Robot.py @@ -0,0 +1,158 @@ +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/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/ValueVerify.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/ValueVerify.py new file mode 100644 index 00000000..ee28f066 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/ValueVerify.py @@ -0,0 +1,21 @@ +#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/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Window.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Window.py new file mode 100644 index 00000000..8476bba7 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/Window.py @@ -0,0 +1,13 @@ +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/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/__init__.py b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/__init__.py new file mode 100644 index 00000000..f69e75bb --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA/__init__.py @@ -0,0 +1,15 @@ +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/Resources/WPy64-3720/python-3.7.2.amd64/Reports/ReportRobotGUIRun_2019_11_08.log b/Resources/WPy64-3720/python-3.7.2.amd64/Reports/ReportRobotGUIRun_2019_11_08.log new file mode 100644 index 00000000..e4f59293 --- /dev/null +++ b/Resources/WPy64-3720/python-3.7.2.amd64/Reports/ReportRobotGUIRun_2019_11_08.log @@ -0,0 +1 @@ +2019-11-08 19:49:01,742 - RobotLogger - INFO - Robot/GUI: Debug mode, x64 diff --git a/Robot/CreateUploadInstall_x64_x32.cmd b/Robot/CreateUploadInstall_x64_x32.cmd index e66dc464..42ec89c5 100644 --- a/Robot/CreateUploadInstall_x64_x32.cmd +++ b/Robot/CreateUploadInstall_x64_x32.cmd @@ -1,10 +1,10 @@ cd %~dp0 +RD /S /Q "build" +RD /S /Q "dist" .\..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe setup.py sdist bdist_wheel .\..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe -m twine upload dist/* -.\..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe -m pip install --upgrade pyOpenRPA -.\..\Resources\WPy64-3720\python-3.7.2.amd64\python.exe -m pip install --upgrade pyOpenRPA -.\..\Resources\WPy32-3720\python-3.7.2\python.exe setup.py sdist bdist_wheel -.\..\Resources\WPy32-3720\python-3.7.2\python.exe -m twine upload dist/* -.\..\Resources\WPy32-3720\python-3.7.2\python.exe -m pip install --upgrade pyOpenRPA -.\..\Resources\WPy32-3720\python-3.7.2\python.exe -m pip install --upgrade pyOpenRPA +timeout 5 +cd .. +Resources\WPy64-3720\python-3.7.2.amd64\python.exe -m pip install --upgrade pyOpenRPA +Resources\WPy32-3720\python-3.7.2\python.exe -m pip install --upgrade pyOpenRPA pause >nul \ No newline at end of file diff --git a/Robot/Test/SeleniumRun/Python_64_Debug.cmd b/Robot/Examples/SeleniumRun/Python_64_Debug.cmd similarity index 100% rename from Robot/Test/SeleniumRun/Python_64_Debug.cmd rename to Robot/Examples/SeleniumRun/Python_64_Debug.cmd diff --git a/Robot/Test/SeleniumRun/Python_64_Script_Run.cmd b/Robot/Examples/SeleniumRun/Python_64_Script_Run.cmd similarity index 100% rename from Robot/Test/SeleniumRun/Python_64_Script_Run.cmd rename to Robot/Examples/SeleniumRun/Python_64_Script_Run.cmd diff --git a/Robot/Test/SeleniumRun/Script.py b/Robot/Examples/SeleniumRun/Script.py similarity index 100% rename from Robot/Test/SeleniumRun/Script.py rename to Robot/Examples/SeleniumRun/Script.py diff --git a/Robot/Test/SeleniumRun/ScriptSeleniumInit.py b/Robot/Examples/SeleniumRun/ScriptSeleniumInit.py similarity index 100% rename from Robot/Test/SeleniumRun/ScriptSeleniumInit.py rename to Robot/Examples/SeleniumRun/ScriptSeleniumInit.py diff --git a/Robot/PIPUpgrade.cmd b/Robot/PIPUpgrade.cmd new file mode 100644 index 00000000..0dcebc5d --- /dev/null +++ b/Robot/PIPUpgrade.cmd @@ -0,0 +1,4 @@ +cd .. +Resources\WPy64-3720\python-3.7.2.amd64\python.exe -m pip install --upgrade pyOpenRPA +Resources\WPy32-3720\python-3.7.2\python.exe -m pip install --upgrade pyOpenRPA +pause >nul \ No newline at end of file diff --git a/Robot/Version.py b/Robot/Version.py index e6b9d58d..2bb6ef95 100644 --- a/Robot/Version.py +++ b/Robot/Version.py @@ -9,4 +9,18 @@ def Get(inFolderPath): lResult = None else: lResult = lResultList[0] - return lResult \ No newline at end of file + return lResult +#Update version in pyOpenRPA package +def pyOpenRPAVersionUpdate(inVarsionFolderPath,inInitFile): + #Check version is not None + lVersion = Get(inVarsionFolderPath) + if lVersion: + lInitPyFile = open(inInitFile,"r",encoding="utf8") + lInitPyFyleString = lInitPyFile.read() + lInitPyFile = open(inInitFile,"w",encoding="utf8") + lInitPyFyleVersionIndexStart = lInitPyFyleString.find("__version__") + lInitPyFyleVersionIndexEnd = lInitPyFyleString.find("\n",lInitPyFyleVersionIndexStart) + lInitPyFyleString = lInitPyFyleString[:lInitPyFyleVersionIndexStart] + f"__version__ = '{lVersion}'" + lInitPyFyleString[lInitPyFyleVersionIndexEnd:] + #print(lInitPyFyleString) + lInitPyFile.write(lInitPyFyleString) + lInitPyFile.close() \ No newline at end of file diff --git a/Robot/__init__.py b/Robot/__init__.py deleted file mode 100644 index 43b95459..00000000 --- a/Robot/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -r""" - -The OpenRPA package (from UnicodeLabs) - -""" -import Version -__version__ = Version.Get("..") -__all__ = [ - 'GUI','Clipboard','IntegrationOrchestrator','Window' -] - -__author__ = 'Ivan Maslov ' - -import GUI -import Clipboard -import IntegrationOrchestrator -import Window \ No newline at end of file diff --git a/Robot/build/lib/pyOpenRPA/Clipboard.py b/Robot/build/lib/pyOpenRPA/Clipboard.py new file mode 100644 index 00000000..12b43186 --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/Clipboard.py @@ -0,0 +1,22 @@ +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 new file mode 100644 index 00000000..05b139a5 --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/GUI.py @@ -0,0 +1,1210 @@ +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 new file mode 100644 index 00000000..be03032c --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/IntegrationOrchestrator.py @@ -0,0 +1,46 @@ +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 new file mode 100644 index 00000000..ef540777 --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/JSONNormalize.py @@ -0,0 +1,83 @@ +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 new file mode 100644 index 00000000..2ab4ceaf --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/ProcessCommunicator.py @@ -0,0 +1,143 @@ +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 new file mode 100644 index 00000000..da848224 --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/Robot.py @@ -0,0 +1,158 @@ +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 new file mode 100644 index 00000000..ee28f066 --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/ValueVerify.py @@ -0,0 +1,21 @@ +#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 new file mode 100644 index 00000000..8476bba7 --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/Window.py @@ -0,0 +1,13 @@ +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 new file mode 100644 index 00000000..f69e75bb --- /dev/null +++ b/Robot/build/lib/pyOpenRPA/__init__.py @@ -0,0 +1,15 @@ +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 new file mode 100644 index 00000000..9289b383 Binary files /dev/null and b/Robot/dist/pyOpenRPA-1.0.15-py3-none-any.whl differ diff --git a/Robot/dist/pyOpenRPA-1.0.15.tar.gz b/Robot/dist/pyOpenRPA-1.0.15.tar.gz new file mode 100644 index 00000000..7e62e8f5 Binary files /dev/null and b/Robot/dist/pyOpenRPA-1.0.15.tar.gz differ diff --git a/Robot/pyOpenRPA.egg-info/PKG-INFO b/Robot/pyOpenRPA.egg-info/PKG-INFO new file mode 100644 index 00000000..6d0c75ba --- /dev/null +++ b/Robot/pyOpenRPA.egg-info/PKG-INFO @@ -0,0 +1,72 @@ +Metadata-Version: 2.1 +Name: pyOpenRPA +Version: 1.0.15 +Summary: First open source RPA platform for business +Home-page: https://gitlab.com/UnicodeLabs/OpenRPA +Author: Ivan Maslov +Author-email: Ivan.Maslov@unicodelabs.ru +License: MIT +Description: # OpenRPA + First open source RPA platform for business is released! + + # How to run + Studio + Double click to Studio\StudioRun_32.cmd or Studio\StudioRun_64.cmd + + # Robot how to debug + Robot\PythonDebug_64.cmd + import Robot + Robot.ActivityRun( + { + ModuleName: <"GUI"|..., str>, + ActivityName: , + ArgumentList: [, ...] - optional, + ArgumentDict: {:, ...} - optional + } + ) + + # Robot example script: + Robot\Examples\GetFolderList\Python_32_Script_Run.cmd + + # Python 32 bit + Resources\WPy32-3720\python-3.7.2\python.exe + + # Python 64 bit + Resources\WPy64-3720\python-3.7.2.amd64\python.exe + + # Module GUI activity List: + ############################ + Новая версия + ############################ + Получить СЃРїРёСЃРѕРє элементов, который удовлетворяет условиям через расширенный движок РїРѕРёСЃРєР° + [ + { + "index":<Позиция элемента РІ родительском объекте>, + "depth_start" - глубина, СЃ которой начинается РїРѕРёСЃРє (РїРѕ умолчанию 1) + "depth_end" - глубина, РґРѕ которой ведется РїРѕРёСЃРє (РїРѕ умолчанию 1) + "class_name" - наименование класса, который требуется искать + "title" - наименование заголовка + "rich_text" - наименование rich_text + } + ] + + + # Open RPA Wiki + - [Home](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/home) + - [04. Desktop app access (win32 & ui automation)](https://gitlab.com/UnicodeLabs/OpenRPA/wikis/04.-Desktop-app-access-(win32-&-ui-automation)) + + #Dependencies + * Python 3 x32 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF] + * Python 3 x64 [psutil, pywinauto, wmi, PIL, keyboard, pyautogui, win32api (pywin32), selenium, openCV, tesseract, requests, lxml, PyMuPDF] + * pywinauto (Windows GUI automation) + * Semantic UI CSS framework + * JsRender by https://www.jsviews.com (switch to Handlebars) + * Handlebars + + Created by Unicode Labs (Ivan Maslov) +Keywords: OpenRPA RPA Robot Automation Robotization +Platform: UNKNOWN +Classifier: Development Status :: 3 - Alpha +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3.7 +Description-Content-Type: text/markdown diff --git a/Robot/pyOpenRPA.egg-info/SOURCES.txt b/Robot/pyOpenRPA.egg-info/SOURCES.txt new file mode 100644 index 00000000..5df32d3a --- /dev/null +++ b/Robot/pyOpenRPA.egg-info/SOURCES.txt @@ -0,0 +1,16 @@ +setup.py +pyOpenRPA/Clipboard.py +pyOpenRPA/GUI.py +pyOpenRPA/IntegrationOrchestrator.py +pyOpenRPA/JSONNormalize.py +pyOpenRPA/ProcessCommunicator.py +pyOpenRPA/Robot.py +pyOpenRPA/ValueVerify.py +pyOpenRPA/Window.py +pyOpenRPA/__init__.py +pyOpenRPA.egg-info/PKG-INFO +pyOpenRPA.egg-info/SOURCES.txt +pyOpenRPA.egg-info/dependency_links.txt +pyOpenRPA.egg-info/not-zip-safe +pyOpenRPA.egg-info/requires.txt +pyOpenRPA.egg-info/top_level.txt \ No newline at end of file diff --git a/Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/top_level.txt b/Robot/pyOpenRPA.egg-info/dependency_links.txt similarity index 100% rename from Resources/WPy32-3720/python-3.7.2/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/top_level.txt rename to Robot/pyOpenRPA.egg-info/dependency_links.txt diff --git a/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/top_level.txt b/Robot/pyOpenRPA.egg-info/not-zip-safe similarity index 100% rename from Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/pyOpenRPA-1.0.7.dist-info/top_level.txt rename to Robot/pyOpenRPA.egg-info/not-zip-safe diff --git a/Robot/pyOpenRPA.egg-info/requires.txt b/Robot/pyOpenRPA.egg-info/requires.txt new file mode 100644 index 00000000..92632ea4 --- /dev/null +++ b/Robot/pyOpenRPA.egg-info/requires.txt @@ -0,0 +1,6 @@ +pywinauto>=0.6.6 +WMI>=1.4.9 +pillow>=6.0.0 +keyboard>=0.13.3 +pyautogui>=0.9.44 +pywin32>=224 diff --git a/Robot/pyOpenRPA.egg-info/top_level.txt b/Robot/pyOpenRPA.egg-info/top_level.txt new file mode 100644 index 00000000..4170df85 --- /dev/null +++ b/Robot/pyOpenRPA.egg-info/top_level.txt @@ -0,0 +1 @@ +pyOpenRPA diff --git a/Robot/pyOpenRPA/Clipboard.py b/Robot/pyOpenRPA/Clipboard.py new file mode 100644 index 00000000..12b43186 --- /dev/null +++ b/Robot/pyOpenRPA/Clipboard.py @@ -0,0 +1,22 @@ +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/pyOpenRPA/GUI.py b/Robot/pyOpenRPA/GUI.py new file mode 100644 index 00000000..05b139a5 --- /dev/null +++ b/Robot/pyOpenRPA/GUI.py @@ -0,0 +1,1210 @@ +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/pyOpenRPA/IntegrationOrchestrator.py b/Robot/pyOpenRPA/IntegrationOrchestrator.py new file mode 100644 index 00000000..be03032c --- /dev/null +++ b/Robot/pyOpenRPA/IntegrationOrchestrator.py @@ -0,0 +1,46 @@ +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/pyOpenRPA/JSONNormalize.py b/Robot/pyOpenRPA/JSONNormalize.py new file mode 100644 index 00000000..ef540777 --- /dev/null +++ b/Robot/pyOpenRPA/JSONNormalize.py @@ -0,0 +1,83 @@ +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/pyOpenRPA/ProcessCommunicator.py b/Robot/pyOpenRPA/ProcessCommunicator.py new file mode 100644 index 00000000..2ab4ceaf --- /dev/null +++ b/Robot/pyOpenRPA/ProcessCommunicator.py @@ -0,0 +1,143 @@ +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/README.md b/Robot/pyOpenRPA/README.md similarity index 100% rename from Robot/README.md rename to Robot/pyOpenRPA/README.md diff --git a/Robot/pyOpenRPA/Robot.py b/Robot/pyOpenRPA/Robot.py new file mode 100644 index 00000000..da848224 --- /dev/null +++ b/Robot/pyOpenRPA/Robot.py @@ -0,0 +1,158 @@ +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/pyOpenRPA/ValueVerify.py b/Robot/pyOpenRPA/ValueVerify.py new file mode 100644 index 00000000..ee28f066 --- /dev/null +++ b/Robot/pyOpenRPA/ValueVerify.py @@ -0,0 +1,21 @@ +#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/pyOpenRPA/Window.py b/Robot/pyOpenRPA/Window.py new file mode 100644 index 00000000..8476bba7 --- /dev/null +++ b/Robot/pyOpenRPA/Window.py @@ -0,0 +1,13 @@ +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/pyOpenRPA/__init__.py b/Robot/pyOpenRPA/__init__.py new file mode 100644 index 00000000..f69e75bb --- /dev/null +++ b/Robot/pyOpenRPA/__init__.py @@ -0,0 +1,15 @@ +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/setup.py b/Robot/setup.py index ba55f7be..30266b70 100644 --- a/Robot/setup.py +++ b/Robot/setup.py @@ -1,13 +1,17 @@ from setuptools import setup, find_packages import Version def LongDescriptionRead(): - with open('README.md') as f: + with open('pyOpenRPA/README.md') as f: return f.read() +#Do pyOpenRPA package __init__ __version__ update +Version.pyOpenRPAVersionUpdate("..","pyOpenRPA/__init__.py") + setup(name='pyOpenRPA', version=Version.Get(".."), description='First open source RPA platform for business', long_description=LongDescriptionRead(), + long_description_content_type='text/markdown', classifiers=[ 'Development Status :: 3 - Alpha', 'License :: OSI Approved :: MIT License', diff --git a/Robot/test.json b/Robot/test.json deleted file mode 100644 index 9e26dfee..00000000 --- a/Robot/test.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/v1.0.8 b/v1.0.15 similarity index 100% rename from v1.0.8 rename to v1.0.15