def send_crash(self, # all optional. # option 1: the success message. message=None, # (1) args={}, # (2) # option 2: the error message. error=None, # option 3: the response object. response=None, # save the message/error/response. save=False, # the active log level (int) (leave None to use self.log_level). log_level=None, # the required log level for when to print to console (leave None to use Response.log_level ; default: 0). required_log_level=Response.log_level, ): if log_level == None: log_level = self.log_level if isinstance(message, (str,String)): self.__response__ = Response.success(message, args, log_level=-1, save=False) msg = message elif isinstance(error, (str,String)): self.__response__ = Response.error(error, log_level=-1, save=False) msg = error elif isinstance(response, ResponseObject): self.__response__ = response if response["success"]: msg = response["message"] else: msg = response["error"] else: raise Exceptions.InvalidUsage("Define one of the following parameters: [message:str, error:str, response:ResponseObject].") self.__status__ = "crashed" if log_level >= required_log_level or save: Response.log(response=self.__response__, save=save, log_level=log_level, required_log_level=required_log_level) return self.__response__
def assign(self, dictionary): if isinstance(dictionary, (dict, Dictionary)): for key, value in dictionary.items(): self[key] = value elif isinstance(dictionary, (tuple, list, Array)): for key, value in dictionary: self[key] = value else: raise Exceptions.InvalidUsage( "The dictionary parameter must be a dict or tuple.") return self
def run(self): self.log(f"Starting thread {self.id}.") self.__status__ = "running" response = None try: response = self.__run__() except AttributeError: raise Exceptions.InvalidUsage(f"Thread [{self.id}] is missing the main [__run__] function.") if isinstance(response, ResponseObject): if response.success: self.send_crash(response=response) else: self.send_stop(response=response) else: self.send_stop(response=response) return self.send_stop(f"Thread [{self.id}] has finished running.")
def check( self, # the parameters (dict) (#1). parameters={"parameter": None}, # the recognizer value for when the parameters are supposed to be empty. default=None, # the traceback id. traceback=None, ): # single. if isinstance(parameters, tuple): name, parameter = parameters if parameter == default: if traceback != None: return Response.error( f"{traceback}: Define parameter [{name}].") else: return Response.error(f"Define parameter [{name}].") if ":" in name: name, formats = name.split(":") while True: if " " in formats: formats = formats.replace(" ", "") else: break formats = formats.split(",") param_format = Formats.get(parameter, serialize=True) if param_format not in formats: return Response.error( f"Incorrect parameter [{name}:{param_format}] format, correct format(s): {Array(path=False, array=formats).string(joiner=', ')}." ) return Response.success(f"Succesfully checked parameter [{name}].") # recursive. elif isinstance(parameters, (dict, Dictionary, ResponseObject)): for id, value in parameters.items(): response = self.check(parameters=(id, value), default=default, traceback=traceback) if response["error"] != None: return response return Response.success( f"Succesfully checked {len(parameters)} parameter(s).") # invalid. else: raise Exceptions.InstanceError( f"Parameter [parameters] requires to be a [dict, Dictionary, tuple] not [{parameters.__class__.__name__}]." )
def unpack(self, # the key / keys / defaults parameter (#1). # str instance: # unpack the str key # list instance: # unpack all keys in the list. # dict instance: # unpack all keys from the dict & when not present return the key's value as default. keys, ): defaults = {} if isinstance(keys, (dict, Files.Dictionary)): if isinstance(keys, dict): defaults = dict(keys) keys = list(keys.keys()) else: defaults = keys.dict() keys = keys.keys() elif isinstance(keys, str): keys = [keys] unpacked = [] for key in keys: value, set = None, True try: value = self[key] except KeyError: try: value = defaults[key] except KeyError: set = False if not set: raise Exceptions.UnpackError(f"Dictionary does not contain attribute [{key}].") unpacked.append(value) if len(unpacked) == 1: return unpacked[0] else: return unpacked
def expect( self, # the expected data parameter (#1). # str instantce: expect a single identifier. # list instance: expect one of the provided identifiers & return the found one if success. expect=["Password*"], # the optional data to send (#2). # none instance: do not send anything. # str instance: the data to send. # list/tuple instance: send value of index from expected expect (required expect to be a list, Array & the indexes of [expect, send] be match). send=None, # the timeout (float). timeout=1.0, ): # check none timeout. if timeout == None: timeout = 1.0 # single expect. if isinstance(expect, str): if isinstance(send, (list, Array)): raise Exceptions.InvalidUsage( f"{self.__traceback__(function='expect', parameter='send')}: parameter [send] requires to be be a [str, String] when parameter [expect] is a [{expect.__class__.__name__}], not [{send.__class__.__name__}]." ) """ add to lines to output (before) (adds nothing when empty) (do not use self.expecting before adding the output). """ response = self.read(wait=False) if not response.success: return response """ check expect & send if provided. """ c = 1 try: #if self.async_: # g = yield from self.child.expect(expect, timeout=timeout, async_=True) # r = next(g) #else: r = self.child.expect(expect, timeout=timeout) if not isinstance(r, (int, Integer, float)): return Response.error( f"Expected [{expect}] is not the child's expected input (#873465)." ) c = 2 if self.log_level >= 8: print(f"Found expected: {expect}") if send != None: if self.log_level >= 8: print(f"Attempting to send: {send}") #if self.async_: # g = yield from self.child.sendline(str(send), async_=True) # r = next(g) #else: r = self.child.sendline(str(send)) self.__secrets__.append(str(send)) if self.log_level >= 8: print(f"Succesfully sended: {send}") except pexpect.exceptions.TIMEOUT: if c == 1: return Response.error( f"Expected [{expect}] is not the child's expected input, error: Timeout (during epxecting)." ) else: return Response.error( f"Failed to send expected [{expect}], error: Timeout (during sending input)." ) except pexpect.exceptions.EOF: if c == 1: return Response.error( f"Expected [{expect}] is not the child's expected input, error: End of file (during epxecting)." ) else: return Response.error( f"Failed to send expected [{expect}], error: End of file (during sending input)." ) except Exception as e: if c == 1: return Response.error( f"Expected [{expect}] is not the child's expected input, error: {e}." ) else: return Response.error( f"Failed to send expected [{expect}], error: {e}.") """ add to lines to output (after) (adds nothing when empty) (do not use self.expecting before adding the output). """ response = self.read(wait=False) if not response.success: return response # handler. if send != None: return Response.success( f"Successfully send expected input ({expect}).") else: return Response.success( f"Successfully retrieved expected input ({expect}).") # list expect. elif isinstance(expect, (list, Array)): index = 0 for _expect_ in expect: if isinstance(send, (list, Array)): try: _send_ = str(send[index]) except: raise Exceptions.InvalidUsage( f"{self.__traceback__(function='expect', parameter='send')}: parameter [send] and parameter [expect] do not have the same indexes." ) else: _send_ = str(send) if self.log_level >= 8: print(f"Checking optional expect: {_expect_}") response = self.expect(expect=_expect_, timeout=timeout, send=_send_) if not response.success and "is not the child's expected input" not in response.error: return response elif response.success: return Response.success( f"Successfully {Boolean(send).string(true='send', false='retrieved')} the expected input(s).", { "expected": _expect_, "index": index, }) index += 1 return Response.error(f"None of the specified input was expected.") # invalid usage. else: raise Exceptions.InvalidUsage( f"{self.__traceback__(function='expect', parameter='expect')}: parameter [expect] requires to be be a [Dictionary], not [{config.__class__.__name__}]." )
def execute( # Notes: # returns a syst3m.console.OutputObject object (very similair to ResponseObject). # # Mode: # option 1: # the command in str format, the command is saved to a script & then executed). command="ls .", # joiner for when command is in list format. joiner=" ", # option 2: the path to script. path=None, # # Executement: # the executable. executable="sh", # the arguments passed to the (saved) script. arguments=[], # # Options: # asynchronous process. async_=False, # await asynchronous child (sync process always awaits). wait=False, # kill process when finished (async that is not awaited is never killed). kill=True, # the subprocess shell parameter. shell=False, # serialize output to dict (expect literal dictionary / json output). serialize=False, # # Input (sync only): # send input to the command. # undefined: send no input & automatically await the process since input is always sync. # dict instance: selects "and" mode ; send expected inputs and their value & return error when one of them is missing. # list[dict] instance: send all dictionaries in the list (default dict behaviour so one of the keys in each dict is expected). input=None, # the input timeout (float) (list with floats by index from input) timeout=1.0, # do not throw an error when the input is missing or not expected when optional is disabled (bool). optional=False, # # Logging. # the log level. log_level=Defaults.options.log_level, # # System functions. # add additional attributes to the spawn object. __spawn_attributes__={}, # ): # checks, if input != None and not isinstance(input, (dict, Dictionary, list, Array)): raise Exceptions.InvalidUsage( f"<Code.execute>: Parameter [input] requires to be be a [dict, Dictionary, list, Array], not [{iput.__class__.__name__}]." ) # vars. delete = False if path == None: delete = True path = f"/tmp/tmp_script_{String('').generate()}" if isinstance(command, list): command = Array(array=command).string(joiner=joiner) Files.save(path, command) response_str = f"command ({command})" else: response_str = f"script ({path})" # execute with input. #if isinstance(input, (dict, Dictionary, list, Array)): # checks. #if async_: # raise Exceptions.InvalidUsage(f"<Code.execute>: Parameters [input] & [async] are not compatible, select either one.") # spawn. l = [] for i in arguments: l.append(f'"{i}"') arguments = Array(l).string(joiner=' ') if log_level >= 8: print(f"Spawn: [ $ {executable} {path} {arguments}]", ) spawn = Spawn( command=f"{executable} {path} {arguments}", #async_=async_, # does not work. response_str=response_str, log_level=log_level, attributes=__spawn_attributes__, ) spawn.echo = False if isinstance(timeout, (int, float, Integer)): spawn.timeout = int(timeout) # start. response = spawn.start() if not response.success: return OutputObject( error=f"Failed to start {response_str}, error: {response.error}", log_level=log_level) # check crashed response = spawn.crashed() if not response.success: return OutputObject(error=response.error, log_level=log_level) # has already exited. elif spawn.exit_status in [0]: # get output. response = spawn.wait(timeout=1.0) if not response.success: return OutputObject(error=response.error, log_level=log_level) # exit status. output = response.output # # proceed if already finished. elif spawn.exit_status not in [0]: # await. for i in range(10): if spawn.running: break time.sleep(1) if not spawn.running: return OutputObject(error=f"Unable to start {response_str}.", log_level=log_level) # str input. if isinstance(input, (list, Array)): if len(input) > 0: str_input = Array(list(input[0].keys())).string(joiner=", ") else: str_input = Array(input).string(joiner=", ") elif isinstance(input, (dict, Dictionary)): str_input = Array(list(input.keys())).string(joiner=", ") else: str_input = f"[{input}]" # send optional input. error_end_of_file = None if not async_ and isinstance( input, (list, Array, dict, Dictionary)) and len(input) > 0: # expect one of the keys in the dictionary. def process_dict_input(dictionary): # vars. expect = list(dictionary.keys()) send = list(dictionary.values()) # expect . if log_level >= 8: print(f"Expecting one of the following inputs: {expect}.") response = spawn.expect(expect=expect, send=send, timeout=timeout) if not response.success: if "None of the specified inputs were expected." in response.error: if optional: return Response.error( f"Unable to find the expected input but still success since it is optional." ) else: return Response.error( f"Specified input [{Array(expect).string(joiner=', ')}] was not expected." ) else: return response if log_level >= 8: print("Send response message:", response.message) # success. return Response.success("Success.") """ check expecting. """ expecting = True if not spawn.expecting: expecting = False if not optional: if log_level >= 1: return OutputObject( error= f"Failed to send expected input {str_input} to {response_str}, child is not expecting any input [{spawn.child}].", log_level=log_level) else: return OutputObject( error= f"Failed to send expected input {str_input} to {response_str}, child is not expecting any input.", log_level=log_level) # limit not expecting by optional. if expecting: # send all dicts in the list (list instance). error_end_of_file = False if isinstance(input, (list, Array)): for _input_ in input: response = process_dict_input(_input_) if not response.success: if "End of file" in response.error: error_end_of_file = True else: # str input. if isinstance(_input_, (list, Array)): str_input = Array(_input_).string( joiner=", ") elif isinstance(_input_, (dict, Dictionary)): str_input = Array(list( _input_.keys())).string(joiner=", ") else: str_input = f"[{_input_}]" if optional: break else: return OutputObject( error= f"Failed to send one of the expected input(s) {str_input}, error: {response.error}", log_level=log_level) # send one of the keys (dict instance). elif isinstance(input, (dict, Dictionary)): response = process_dict_input(input) if not response.success: if "End of file" in response.error: error_end_of_file = True elif not optional: return OutputObject( error= f"Failed to send one of the expected input(s) {str_input}, error: {response.error}", log_level=log_level) """ check no input left (does not work properly). if not error_end_of_file and spawn.expecting: try: after = spawn.child.after.decode() except : after = spawn.child.after return OutputObject(error=f"Failed to execute {response_str}, still expecting: [{after}].", log_level=log_level) """ # do not get or kill when async. output = None if not async_: # check crashed. response = spawn.crashed() if not response.success: return OutputObject(error=response.error, log_level=log_level) # always await sync. response = spawn.wait() if not response.success: return OutputObject(error=response.error, log_level=log_level) output = response.output if error_end_of_file != None and error_end_of_file: if log_level >= 1: return OutputObject( error= f"Failed to send expected input {str_input} to {response_str} (#234343) (output: {output}) (child: {spawn.child}).", log_level=log_level) else: return OutputObject( error= f"Failed to send expected input {str_input} to {response_str} (#234343) (output: {output}).", log_level=log_level) # check kill. if kill and spawn.running: if log_level >= 8: print(f"Killing process {response_str}.") response = spawn.kill() if not response.success: return OutputObject( error= f"Failed to kill {response_str}, error: {response.error}", log_level=log_level) # async. elif async_: # check exit status. response = spawn.read(wait=False) if not response.success: if not response.success: return OutputObject( error= f"Failed to retrieve output from spawn {response_str}, error: {response.error}", log_level=log_level) if spawn.child.exitstatus not in [0, None]: return OutputObject( error= f"{response_str} returned exit status: [{spawn.child.exitstatus}] (output: {self.read(wait=False, __safe__=True).output}).", log_level=log_level) # await async. if wait: # await. response = spawn.wait() if not response.success: return OutputObject(error=response.error, log_level=log_level) # exit status. output = response.output if spawn.child.exitstatus not in [0, None]: return OutputObject( error= f"{response_str} returned exit status: [{spawn.child.exitstatus}] (output: {self.read(wait=False, __safe__=True).output}).", log_level=log_level) # check kill. if kill and spawn.running: if log_level >= 8: print(f"Killing process {response_str}.") response = spawn.kill() if not response.success: return OutputObject( error= f"Failed to kill {response_str}, error: {response.error}", log_level=log_level) # handler. if delete: Files.delete(path) if serialize: try: response = Response.ResponseObject(json=output) except Exception as e: if loader != None: loader.stop(success=False) return OutputObject( error=f"Failed to serialize (output: {output}).", log_level=log_level) if not response.success: return OutputObject( error= f"Encoutered an error in the serialized response, error: {response.error}", log_level=log_level) return OutputObject(message=f"Succesfully executed {response_str}.", log_level=log_level, attributes={ "output": output, "process": spawn, "pid": spawn.child.pid, "running": spawn.running, "exit_status": spawn.exit_status, }) """
def __le__(self, response): if not isinstance(response, self.__class__): raise Exceptions.InstanceError( f"Can not compare object {self.__class__} & {response.__class__}." ) return len(self) <= len(response)
def __init__( self, # the response attributes. attributes={ "success": False, "message": None, "error": None, }, # import a dumped json response (str) (ignores attributes). json=None, ): # check self instance. if isinstance(attributes, ResponseObject): #attributes = attributes.dict() #self = attributes attributes = attributes.dict() elif isinstance(json, ResponseObject): json = json.dict() # assign attributes. if json != None: if isinstance(json, str): try: self.assign(pypi_json.loads(json)) except: try: self.assign(ast.literal_eval(json)) except: self.assign(pypi_json.loads(String(json).slice_dict())) elif isinstance(json, dict): self.assign(json) elif json != None: raise Exceptions.InvalidUsage( "The ResponseObject.json parameter must be str / dict format." ) else: self.assign(attributes) # clean message & error. try: if self.message in ["None", "null", "", "nan"]: self.message = None if self.message != None: self.message = String(self.message).capitalized_word() if self.error in ["None", "null", "", "nan"]: self.error = None if self.error != None: self.error = String(self.error).capitalized_word() while True: if self.message != None and len( self.message) >= 1 and self.message[len(self.message) - 1] in [ " ", ".", "," ]: self.message = self.message[:-1] elif self.error != None and len( self.error) >= 1 and self.error[len(self.error) - 1] in [" ", ".", ","]: self.error = self.error[:-1] elif self.error != None and len(self.error) >= len( "Error: ") and self.error[:len("Error: ")] in [ "Error: " ]: self.error = String( self.error[len("Error: "):]).capitalized_word() else: break # add dot. if self.message != None and len( self.message) > 0 and self.message[len(self.message) - 1] not in ["!", "?"]: self.message += "." if self.error != None and len( self.error) > 0 and self.error[len(self.error) - 1] not in ["!", "?"]: self.error += "." # check error passed as success response. & reversed if self.message != None and len(self.message) >= len( "Failed") and self.message[:len("Failed")] == "Failed": #_traceback_.print_exc() raise ValueError( "A success response may not start with (failed ...). You most likely called an Response.success return while you meant Response.error." ) if self.error != None and len(self.error) >= len( "Success") and self.error[:len("Success")] == "Success": #_traceback_.print_exc() raise ValueError( "An error response may not start with (success ...). You most likely called an Response.error return while you meant Response.success." ) # except if not present. except AttributeError: a = 1
def get( self, # the django request (1). request=None, # the identifiers (#2). # str instance: return the parameters value. # list instance: return a parameters object & return an error response when a parameter is undefined. # dict instance: return a parameters object & return the parameter's value from the dict as a default when undefined. parameters=[], # default return value (dict instance of parameters overwrites the default parameter). default=None, # traceback id. traceback=None, ): if request == None: raise Exceptions.InvalidUsage( "<Response.paramters.get>: Define parameter: [request].") # single parameter. if isinstance(parameters, (str, String)): parameters = str(parameters) response = Response.response() format = None if ":" in parameters: parameters, format = parameters.split(":") while True: if " " in format: format = format.replace(" ", "") else: break if request.method in ["post", "POST"]: variable = request.POST.get(parameters) else: variable = request.GET.get(parameters) if variable in ["", None]: if traceback != None: return variable, Response.error( f"{traceback}: Define parameter: [{parameters}].") else: return variable, Response.error( f"Define parameter: [{parameters}].") elif format != None: if format in ["str", "string"]: variable = str(variable) elif format in ["int", "integer"]: variable = int(variable) elif format in ["bool", "boolean"]: if variable in ["true", "True", "TRUE", True]: variable = True else: variable = False elif format in ["float", "double"]: variable = float(variable) elif format in ["array", "list"]: variable = variable.split(",") else: raise ValueError( f"Unrecognized <Response.parameters.get> format: {format}." ) # handler. return variable, Response.success( f"Succesfully retrieved request parameter [{parameters}].", { "key": parameters, "value": variable, }) # list recursive. elif isinstance(parameters, (list, Array)): optional = False params = ResponseObject() for param in parameters: param_value, response = self.get(request, param, traceback=traceback) param = param.split(":")[0] if response["error"] != None: if optional: params[param] = default else: return params, response else: params[param] = param_value if optional: for key in parameters: try: params[key] except: params[key] = default return params, Response.success( f"Succesfully retrieved {len(params)} request parameter(s).") # dict recursive. elif isinstance(parameters, (dict, Dictionary, ResponseObject)): if isinstance(parameters, (ResponseObject)): parameters = parameters.clean() optional = True params = ResponseObject() for param, default in parameters.items(): param_value, response = self.get(request, param, traceback=traceback) param = param.split(":")[0] if response["error"] != None: if optional: params[param] = default else: return params, response else: params[param] = param_value if optional: for key, default in parameters.items(): try: params[key] except: params[key] = default return params, Response.success( f"Succesfully retrieved {len(params)} request parameter(s).") # invalid. else: raise Exceptions.InvalidUsage( f"The parameters parameter must be [str, String, list, Array, dict, Dictionary] not [{dictionary.__class__.__name__}]." )
def serialize( self, # the response (#1) (dict) (str repr of dict) (ResponseObject) (generator) . response={}, # init to response object. init=True, ): # check async generator. if response.__class__.__name__ in ["generator"]: raise ValueError("Not supported yet.") return self.serialize(response=response.value, init=init) #print("Converting generator.") #print(f"Generator value ({response.value.__class__.__name__}) [{response.value}].") #try: # value = next(response) #except StopIteration as e: # return self.serialize(response=str(e), init=True) # #print(f"Generator output: [{e}].") # #response = self.serialize(response=str(e), init=True) # #print(f"Serialized generator output instance: [{response.__class__.__name__}].") # #return response #except Eception as e: # return Response.error(f"An error occured during the execution of generator [{response}], error: {e}") # check ResponseObject. elif response.__class__.__name__ in ["ResponseObject"]: return response # check syst3m.console.Output. elif response.__class__.__name__ in ["Output"]: try: return response.response() except AttributeError: return response # dict / str. elif response.__class__.__name__ in [ "str", "String", "dict", "Dictionary" ]: if response.__class__.__name__ in ["str", "String"]: try: try: response = ast.literal_eval(response) except: response = json.loads(response) except Exception as e: raise Exceptions.JsonDecodeError( f"Unable to parse a dictionary from [{response}], {e}." ) for key in list(response.keys()): value = response[key] no_dict = False if isinstance(value, dict): value = self.serialize(value) elif value in [None, "None", "none", "null"]: value = None elif value in [True, "True", "true", "TRUE"]: value = True elif value in [False, "False", "false", "FALSE"]: value = False elif isinstance(value, str): if "." in value: try: value = float(value) except: a = 1 else: try: value = int(value) except: a = 1 response[key] = value # invalid. else: raise Exceptions.InvalidUsage( f"The parameter [response] must be [str, String, dict, Dictionary, generator] not [{response.__class__.__name__}]." ) # return dict. if init: return ResponseObject(response) else: return response
def log( self, # option 1: # the message (#1 param). message=None, # option 2: # the error. error=None, # option 3: # the response dict (leave message None to use). response={}, # print the response as json. json=False, # optionals: # the active log level. log_level=0, # the required log level for when printed to console (leave None to use self.log_level). required_log_level=None, # save to log file. save=False, # save errors always (for options 2 & 3 only). save_errors=None, # the log mode (leave None for default). mode=None, ): if mode != None: mode = str(mode).lower().replace("-", "").replace("_", "") if mode not in [None, "warning", "alert"]: raise Exceptions.InvalidUsage( f"{self.__traceback__(function='log', parameter='mode')}: Selected an invalid mode [{mode}], options: [None, warning, alert]." ) def fill_message(msg, error=False): if mode == None: if error: msg = f"Error: {msg}" else: msg = msg elif mode == "warning": msg = f"&RED&:Warning&END&: {msg}" elif mode == "alert": msg = f"&ORANGE&:Alert&END&: {msg}" return msg # msg, _error_ = None, False if [message, error, response] == [None, None, {}]: raise Exceptions.InvalidUsage( f"{self.__traceback__(function='log')}: Define either parameter [message:str], [error:str] or [response:dict]." ) if response != {}: if response["error"] != None: _error_ = True msg = f"Error: {response['error']}" else: if response.__class__.__name__ in ["Output"]: msg = response.output else: msg = response["message"] elif isinstance(error, (str, String)): msg = fill_message(error, error=True) else: msg = fill_message(message, error=False) if required_log_level == None: required_log_level = self.log_level try: required_log_level = int(required_log_level) except: required_log_level = 0 try: comparison = log_level != None and log_level >= required_log_level except TypeError as e: if "not supported between instances of 'dict' and 'int'" in f"{e}": raise TypeError( f"You most likely returned a Response.error when you meant a Response.success, error: {e}" ) else: raise TypeError(e) if comparison: #print(f"{Date().seconds_timestamp} - {color.fill(msg)}") if json: if response != {}: print(response.json()) elif error != None: print(self.error(error)) else: print(self.success(message)) else: print(f"{color.fill(msg)}") if save: self.__log_to_file__(msg) elif save_errors and _error_: self.__log_to_file__(msg)