async def do_exec( db_session, action, form, arguments=None, modal_guid=None, current_user=None): """ Executes python commands form AxAction.code Args: action (AxAction): Current action that is performed form (AxForm): Tobe form. Its same as action.form, but it contains values from vue form arguments(**kargs): Custom dict that can be used in code modal_guid (str): AxForm modal guid for wss console subscribtion Returns: Dict: Its custom Dict containing: info (str): Message that must be displayed to user error (str): Error that must be displayed to user item (DotMap): Javascript style dictionary of field and values. example- item.guid -> guid of current row exception (Dict): Info on exception that accured abort (Bool): If set to True - the action will be aborted and row state will not be changed """ import backend.schema as ax_schema host = await ax_misc.get_ax_host() localz = dict() ax = DotMap() # javascript style dicts item['guid'] == item.guid ax.row.guid = form.row_guid ax.arguments = arguments ax.stripe = stripe ax.user_email = None ax.user_guid = None if current_user: ax.user_email = current_user.get("email", None) ax.user_guid = current_user.get("user_id", None) ax.tom_label = await ax_misc.get_tom_label(form) ax.host = host ax.form_url = f'{host}/form/{form.db_name}/{form.row_guid}' ax.form = form ax.action = action ax.schema = ax_schema.schema ax.sql = ax_dialects.dialect.custom_query ax.print = ConsoleSender(modal_guid=modal_guid) ax.email = ax_emails.email_sender ax.paths.uploads = ax_misc.uploads_root_dir ax.paths.tmp = ax_misc.tmp_root_dir ax.add_action_job = ax_scheduler.add_action_job ax.do_action = ActionExecuter( db_session=db_session, current_user=current_user) ax.modal_guid = modal_guid for field in form.db_fields: ax.row[field.db_name] = field.value localz['ax'] = ax line_number = None try: await ax_exec.aexec(code=str(action.code), localz=localz, ax=ax) ret_ax = localz['ax'] ret_data = { "info": ret_ax.message if 'message' in ret_ax else None, "error": ret_ax.error if 'error' in ret_ax else None, "item": ret_ax.row, "exception": None, "abort": ret_ax.abort if 'abort' in ret_ax else None } return ret_data except SyntaxError as err: logger.error(err) error_class = err.__class__.__name__ detail = err.args[0] line_number = err.lineno ret_data = { "info": None, "item": None, "error": None, "exception": { "error_class": error_class, "line_number": line_number, "action_name": action.name, "detail": detail }, "abort": True } if ax.print.check_was_used(): err = json.dumps(ret_data, indent=4, sort_keys=True) ax.print('\n\n----- SYNTAX ERROR ------\n\n' + err) return ret_data except Exception as err: # pylint: disable=broad-except logger.error(err) error_class = err.__class__.__name__ detail = err.args[0] cl, exc, tb = sys.exc_info() del cl, exc # line_number = traceback.extract_tb(tb)[-1][1] line_number = 0 traces = traceback.extract_tb(tb) for idx, trace in enumerate(traces): if trace.filename == '<string>': line_number = traceback.extract_tb(tb)[idx].lineno del tb ret_data = { "info": None, "item": None, "error": None, "exception": { "error_class": error_class, "line_number": line_number, "action_name": action.name, "detail": detail }, "abort": True } if ax.print.check_was_used(): err = json.dumps(ret_data, indent=4, sort_keys=True) ax.print('\n\n----- EXCEPTION ------\n\n' + err) return ret_data