From 0c78cee85abade86c96e28971148f5eab4a88787 Mon Sep 17 00:00:00 2001 From: Ivan Maslov Date: Thu, 23 Dec 2021 12:30:45 +0300 Subject: [PATCH] draft 1.2.7 (need test) # Orchestrator.OrchestratorPySearchInit - auto init .py modules in orchestrator # No more double logger handlers initialization # No more double pyOpenRPA.Orchestrator and pyOpenRPA.Orchestrator.__Orchestrator__ initialization - realy singleton # When init gSettings - default logger level is INFO --- Orchestrator/OrchestratorSettings.py | 40 +----------- .../Orchestrator/SettingsTemplate.py | 50 ++++++++------- .../Orchestrator/__Orchestrator__.py | 61 +++++++++++++++++++ 3 files changed, 91 insertions(+), 60 deletions(-) diff --git a/Orchestrator/OrchestratorSettings.py b/Orchestrator/OrchestratorSettings.py index 41c98b75..304f500c 100644 --- a/Orchestrator/OrchestratorSettings.py +++ b/Orchestrator/OrchestratorSettings.py @@ -14,6 +14,7 @@ if not Orchestrator.OrchestratorIsAdmin(): Orchestrator.OrchestratorRerunAsAdmin() print(f"Orchestrator will be run as administrator!") elif __name__ == "__main__": # New init way - allow run as module -m PyOpenRPA.Orchestrator + #gSettings = Orchestrator.GSettingsGet() gSettings = SettingsTemplate.Create(inModeStr="BASIC") # Create GSettings with basic configuration - no more config is available from the box - you can create own # TEST Add User ND - Add Login ND to superuser of the Orchestrator @@ -23,47 +24,12 @@ elif __name__ == "__main__": # New init way - allow run as module -m PyOpenRPA.O Orchestrator.UACUpdate(inGSettings=gSettings, inADLoginStr="IMaslov", inADStr="", inADIsDefaultBool=True, inURLList=[]) # TEST Add Supertoken for the all access between robots Orchestrator.UACSuperTokenUpdate(inGSettings=gSettings, inSuperTokenStr="1992-04-03-0643-ru-b4ff-openrpa52zzz") - # Add first interface! Orchestrator.WebListenCreate(inGSettings=gSettings) - # Restore DUMP Orchestrator.OrchestratorSessionRestore(inGSettings=gSettings) - - # INFO Relative/Absolute import see below - after settings init - # Template for import CP - Control Panels - # ATTENTION - Pay attention to CP names! Orchestrator is one for the all control panels per one machine - ## !!! For Absolute import control panels !!! - # try: - # sys.path.insert(0,os.path.abspath(os.path.join(r"..\ROBOT\Builds"))) - # import pyRobot_CP - # pyRobot_CP.SettingsUpdate(inGSettings=gSettings) - # except Exception as e: - # gSettings["Logger"].exception(f"Exception when init CP. See below.") - - ## !!! For Relative import control panels !!! - # try: - # sys.path.insert(0,os.path.abspath(os.path.join(r"..\ROBOT\Builds"))) - # from pyRobot_CP import ControlPanel - # ControlPanel.SettingsUpdate(inGSettings=gSettings) - # except Exception as e: - # gSettings["Logger"].exception(f"Exception when init CP. See below.") - - - ## !!! For Relative import !!! CP Version Check - try: - sys.path.insert(0,os.path.abspath(os.path.join(r""))) - from ControlPanel import CP_VersionCheck - CP_VersionCheck.SettingsUpdate(inGSettings=gSettings) - except Exception as e: - gSettings["Logger"].exception(f"Exception when init CP. See below.") - - try: - from ControlPanel import CP_Test - CP_Test.SettingsUpdate(inGSettings=gSettings) - except Exception as e: - gSettings["Logger"].exception(f"Exception when init CP. See below.") - + # Autoinit control panels starts with CP_ + lPyModules = Orchestrator.OrchestratorPySearchInit(inGlobPatternStr="ControlPanel\\CP_*.py", inDefStr="SettingsUpdate", inDefArgNameGSettingsStr="inGSettings") # Call the orchestrator def Orchestrator.Orchestrator(inGSettings=gSettings, inDumpRestoreBool=False) else: diff --git a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py index 242ddf55..b92371b7 100644 --- a/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py +++ b/Sources/pyOpenRPA/Orchestrator/SettingsTemplate.py @@ -324,7 +324,7 @@ def LoggerDumpLogHandlerAdd(inLogger, inGSettingsClientDict): # inModeStr: # "BASIC" - create standart configuration from pyOpenRPA.Orchestrator.Utils import LoggerHandlerDumpLogList -def Create(inModeStr="BASIC"): +def Create(inModeStr="BASIC", inLoggerLevel = None): if inModeStr=="BASIC": lResult = __Create__() # Create settings # Создать файл логирования @@ -334,26 +334,30 @@ def Create(inModeStr="BASIC"): ########################## # Подготовка логгера Robot ######################### - mRobotLogger = lResult["Logger"] - mRobotLogger.setLevel(logging.INFO) - # create the logging file handler - mRobotLoggerFH = logging.FileHandler( - "Reports\\" + datetime.datetime.now().strftime("%Y_%m_%d") + ".log") - mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') - mRobotLoggerFH.setFormatter(mRobotLoggerFormatter) - # add handler to logger object - mRobotLogger.addHandler(mRobotLoggerFH) - ####################Add console output - handler = logging.StreamHandler(sys.stdout) - handler.setFormatter(mRobotLoggerFormatter) - mRobotLogger.addHandler(handler) - ############################################ - LoggerDumpLogHandlerAdd(inLogger=mRobotLogger, inGSettingsClientDict=lResult["Client"]) - #mHandlerDumpLogList = LoggerHandlerDumpLogList.LoggerHandlerDumpLogList(inDict=lResult["Client"], - # inKeyStr="DumpLogList", - # inHashKeyStr="DumpLogListHashStr", - # inRowCountInt=lResult["Client"][ - # "DumpLogListCountInt"]) - #mHandlerDumpLogList.setFormatter(mRobotLoggerFormatter) - #mRobotLogger.addHandler(mHandlerDumpLogList) + if inLoggerLevel is None: inLoggerLevel=logging.INFO + lL = lResult["Logger"] + if len(lL.handlers) == 0: + lL.setLevel(logging.INFO) + # create the logging file handler + mRobotLoggerFH = logging.FileHandler( + "Reports\\" + datetime.datetime.now().strftime("%Y_%m_%d") + ".log") + mRobotLoggerFormatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') + mRobotLoggerFH.setFormatter(mRobotLoggerFormatter) + # add handler to logger object + lL.addHandler(mRobotLoggerFH) + ####################Add console output + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter(mRobotLoggerFormatter) + lL.addHandler(handler) + ############################################ + LoggerDumpLogHandlerAdd(inLogger=lL, inGSettingsClientDict=lResult["Client"]) + #mHandlerDumpLogList = LoggerHandlerDumpLogList.LoggerHandlerDumpLogList(inDict=lResult["Client"], + # inKeyStr="DumpLogList", + # inHashKeyStr="DumpLogListHashStr", + # inRowCountInt=lResult["Client"][ + # "DumpLogListCountInt"]) + #mHandlerDumpLogList.setFormatter(mRobotLoggerFormatter) + #mRobotLogger.addHandler(mHandlerDumpLogList) + else: + if lL: lL.warning("Pay attention! Your code has been call SettingsTemplate.Create - since pyOpenRPA v1.2.7 GSettings is creating automatically") return lResult # return the result dict \ No newline at end of file diff --git a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py index f6907f8e..f3a7a551 100644 --- a/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py +++ b/Sources/pyOpenRPA/Orchestrator/__Orchestrator__.py @@ -27,6 +27,7 @@ from . import SettingsTemplate # Settings template import uuid # Generate uuid import datetime # datetime import math +import glob # search the files #Единый глобальный словарь (За основу взять из Settings.py) gSettingsDict = None @@ -491,6 +492,60 @@ def OrchestratorRerunAsAdmin(): else: print(f"!SKIPPED! Already run as administrator!") +def OrchestratorPySearchInit(inGlobPatternStr, inDefStr = None, inDefArgNameGSettingsStr = None): + """ + Search the py files by the glob and do the safe init (in try except). Also add inited module in sys.modules as imported (module name = file name without extension). + + .. code-block:: python + + # USAGE VAR 1 (without the def auto call) + # Autoinit control panels starts with CP_ + Orchestrator.OrchestratorPySearchInit(inGlobPatternStr="ControlPanel\\CP_*.py") + + # USAGE VAR 2 (with the def auto call) - for the backward compatibility CP for the Orchestrator ver. < 1.2.7 + # Autoinit control panels starts with CP_ + Orchestrator.OrchestratorPySearchInit(inGlobPatternStr="ControlPanel\\CP_*.py", inDefStr="SettingsUpdate", inDefArgNameGSettingsStr="inGSettings") + + # INFO: The code above will replace the code below + ## !!! For Relative import !!! CP Version Check + try: + sys.path.insert(0,os.path.abspath(os.path.join(r""))) + from ControlPanel import CP_VersionCheck + CP_VersionCheck.SettingsUpdate(inGSettings=gSettings) + except Exception as e: + gSettings["Logger"].exception(f"Exception when init CP. See below.") + + + :param inGlobPatternStr: example"..\\*\\*\\*X64*.cmd" + :param inDefStr: OPTIONAL The string name of the def. For backward compatibility if you need to auto call some def from initialized module + :param inDefArgNameGSettingsStr: OPTIONAL The name of the GSettings argument in def (if exists) + :return: { "ModuleNameStr":{"PyPathStr": "", "Module": ...}, ...} + """ + lResultDict = {} + + lPyPathStrList = glob.glob(inGlobPatternStr) # get the file list + lL = OrchestratorLoggerGet() # get the logger + for lPyPathItemStr in lPyPathStrList: + try: + lModuleNameStr = os.path.basename(lPyPathItemStr)[0:-3] + lTechSpecification = importlib.util.spec_from_file_location(lModuleNameStr, lPyPathItemStr) + lTechModuleFromSpec = importlib.util.module_from_spec(lTechSpecification) + sys.modules[lModuleNameStr] = lTechModuleFromSpec # Add initialized module in sys - python will not init this module enought + lTechSpecificationModuleLoader = lTechSpecification.loader.exec_module(lTechModuleFromSpec) + lItemDict = {"ModuleNameStr": lModuleNameStr, "PyPathStr": lPyPathItemStr, "Module": lTechModuleFromSpec} + if lL: lL.info(f"Py module {lModuleNameStr} has been successfully initialized.") + lResultDict[lModuleNameStr]=lItemDict + # Backward compatibility to call def with gsettings when init + if inDefStr is not None and inDefStr is not "": + lDef = getattr(lTechModuleFromSpec, inDefStr) + lArgDict = {} + if inDefArgNameGSettingsStr is not None and inDefArgNameGSettingsStr is not "": + lArgDict = {inDefArgNameGSettingsStr:GSettingsGet()} + lDef(**lArgDict) + except Exception as e: + if lL: lL.exception(f"Exception when init the .py file {os.path.abspath(lPyPathItemStr)}") + return lResultDict + def OrchestratorSessionSave(inGSettings=None): """ Orchestrator session save in file @@ -890,6 +945,12 @@ def WebUserUACHierarchyGet(inRequest): from . import SettingsTemplate GSettings = SettingsTemplate.Create(inModeStr = "BASIC") +# Modules alias for pyOpenRPA.Orchestrator and pyOpenRPA.Orchestrator.__Orchestrator__ +lCurrentModule = sys.modules[__name__] +if __name__ == "pyOpenRPA.Orchestrator" and "pyOpenRPA.Orchestrator.__Orchestrator__" not in sys.modules: + sys.modules["pyOpenRPA.Orchestrator.__Orchestrator__"] = lCurrentModule +if __name__ == "pyOpenRPA.Orchestrator.__Orchestrator__" and "pyOpenRPA.Orchestrator" not in sys.modules: + sys.modules["pyOpenRPA.Orchestrator"] = lCurrentModule def GSettingsGet(inGSettings=None): """