modular_cli/service/request_processor.py (179 lines of code) (raw):

import os from base64 import b64encode from modular_cli.utils.exceptions import ModularCliBadRequestException ROUTE = 'route' NAME = 'name' TYPE = 'type' PATH = 'path' ALIAS = 'alias' NUMERIC = 'num' BOOLEAN = 'bool' METHOD = 'method' PARAMS = 'parameters' REQUIRED = 'required' BOOL_PARAM_MAP = { 'true': True, 'false': False } def validate_params(appropriate_command, passed_parameters): missed_param = [ param[NAME] for param in appropriate_command[PARAMS] if param[REQUIRED] and param[NAME] not in passed_parameters ] if missed_param: raise ModularCliBadRequestException( f'The following parameters are missing: ' f'{", ".join(missed_param)}.\n' f'Try \'--help\' for help or list subcommands.') passed_parameters_names = passed_parameters.keys() for checked_name in passed_parameters_names: found = False for item in appropriate_command.get(PARAMS): name = item.get(NAME) if checked_name == name: param_type = item.get(TYPE) value = passed_parameters.get(checked_name) check_param_type(p_name=checked_name, p_type=param_type, value=value) found = True break if not found: raise ModularCliBadRequestException(f"Invalid parameter " f"\'{checked_name}\'.") def check_param_type(p_name, p_type, value): if p_type == BOOLEAN and not isinstance(value, bool): raise ModularCliBadRequestException( f'Invalid value of parameter \'{p_name}\'.\nShould be a flag or ' f'boolean type expected.') if p_type == NUMERIC: try: float(value) except ValueError: raise ModularCliBadRequestException( f'Invalid parameter \'{p_name}\'. Numeric value expected.') def alias_to_parameter(command, params): updated_params = {} params_meta = command.get(PARAMS) # validate aliases for param in params: found = False if param.startswith("-"): for item in params_meta: alias = item.get(ALIAS) if alias and param == ("-" + alias): found = True if not found: raise ModularCliBadRequestException(f"Invalid alias " f"\'{param}\'") # replace aliases by full name parameters for param in params: if param.startswith("-"): for item in params_meta: alias = item.get(ALIAS) if alias and "-" + alias == param: full_name = item.get(NAME) value = params.get(param) updated_params[full_name] = value else: updated_params[param] = params.get(param) return updated_params def resolve_secure_parameters(command, params): secure_parameters = {param: value for param, value in params.items() if param in command['secure_parameters']} params_to_log = {} for param, value in params.items(): if param in secure_parameters: value = '*****' params_to_log.update({param: value}) return params_to_log def resolve_passed_files(command, params): parameters = command['parameters'] for parameter in parameters: is_file = parameter.get('convert_content_to_file') parameter_name = parameter.get('name') if not is_file or parameter_name not in params: continue path_to_file = params[parameter_name] *_, filename = os.path.split(path_to_file) filename, file_extension = os.path.splitext(filename) allowed_extensions = parameter.get('temp_file_extension') if allowed_extensions and file_extension not in allowed_extensions: raise ModularCliBadRequestException( f'File must have the following extensions: ' f'{", ".join(allowed_extensions)}') if not os.path.isfile(path_to_file): raise ModularCliBadRequestException( 'Provided file path does not exist' ) encoded_str = str(b64encode(open(path_to_file, 'rb').read()))[2:-1] params.update( {parameter_name: {'file_content': encoded_str, 'filename': filename, 'file_extension': file_extension}}) return params def process_input_parameters(token_meta, passed_parameters): index = 0 processed_parameters = {} for idx, param in enumerate(passed_parameters): if idx < index: continue existed_param = [parameter for parameter in token_meta['parameters'] if f'-{parameter["alias"]}' == param or f'--{parameter["name"]}' == param] if not existed_param: raise ModularCliBadRequestException(f"No such option: " f"\'{param}\'") existed_param = existed_param[0] param_name = existed_param['name'] is_bool_param = existed_param['type'] == 'bool' is_flag_param = existed_param.get('is_flag') # process bool parameter type if is_flag_param: processed_parameters[param_name] = True index += 1 elif is_bool_param: try: processed_parameters[param_name] = BOOL_PARAM_MAP.get( passed_parameters[index + 1].lower() ) index += 2 if not isinstance(processed_parameters[param_name], bool): raise ModularCliBadRequestException( f'Missed value for "{param}" parameter. ' f'Bool type expected' ) except IndexError: raise ModularCliBadRequestException( f'Missed value for "{param}" parameter. ' f'Bool type expected' ) elif param_name in processed_parameters: # process multiple parameter type existed_param_value = processed_parameters[param_name] if existed_param_value and isinstance(existed_param_value, list): processed_parameters[param_name].append( passed_parameters[index + 1] ) else: processed_parameters[param_name] = [ existed_param_value, passed_parameters[index + 1] ] index += 2 else: try: processed_parameters[existed_param['name']] = passed_parameters[idx+1] except IndexError: raise ModularCliBadRequestException( f'Missed value for "{param}" parameter' ) index += 2 return processed_parameters def prepare_request(token_meta, passed_parameters): passed_parameters = process_input_parameters( token_meta=token_meta, passed_parameters=passed_parameters ) passed_parameters = resolve_passed_files(command=token_meta, params=passed_parameters) validate_params(token_meta, passed_parameters) params_to_log = resolve_secure_parameters(command=token_meta, params=passed_parameters) route = token_meta[ROUTE] return route[PATH], route[METHOD], passed_parameters, params_to_log