def get_archive_book_data(bookid): """ Get internet archive book infos :arg book_id: Internet archive book id :returns: A dict with metadata from internet archive :rtype: dict """ query = "http://archive.org/metadata/" + bookid data = json.loads(requests.get(query).content) img = "http://www.archive.org/download/" + bookid + "/page/n7_w100_h100" default_dict = {"title": None, "publisher": None, "volume": None, "contributor": None} known_dict = dict(img=img, bookid=bookid) for key in default_dict: try: default_dict[key] = data["metadata"][key] except: logger.error(Archive_book_data_exception(1, key)) raise Archive_book_data_exception(1, key) if default_dict['volume'] != None: default_dict['title'] = default_dict['title'] + ' (Vol. ' + default_dict['volume'] + ')' return dict(known_dict.items() + default_dict.items())
def generate_metadata_file(self, metadata_dict, bookid): try: tmp_file = tempfile.mkstemp() f = open(tmp_file[1], "aw") f.write("Título: " + metadata_dict["title"] + "\n") f.write("Subtítulo: " + metadata_dict["subtitle"] + "\n") f.write("Assunto: " + subject_table_map.get_subject(metadata_dict["subject"]) + "\n") f.write("Fontes: " + metadata_dict["source"] + "\n") f.write("Título do Livro: " + metadata_dict["book_title"] + "\n") f.write("Página do Livro: " + str(metadata_dict["page_number"]) + "\n") f.write("Número da Tabela: " + str(metadata_dict["table_number"]) + "\n") f.close() f = open(tmp_file[1], "rb") data_mngr2.record_metadata_file(dict( book_id=bookid, page_number=metadata_dict["page_number"], table_number=metadata_dict["table_number"], mt_file=f.read() )) f.close() os.unlink(f.name) msg = "Metadata file generated with success. Content: " + str(metadata_dict) logger.info(msg) except Exception as e: logger.error(e) raise e
def get_task(task_id): """ Returns a specific task based in PyBossa task_id :params task_id: Pybossa's task_id """ try: pb_app = __find_app_by_taskid(task_id) app_short_name = pb_app["short_name"] task_type = app_short_name[-1] task = None if task_type == "1": task = tt_tasks.TTTask1(task_id, app_short_name) elif task_type == "2": task = tt_tasks.TTTask2(task_id, app_short_name) elif task_type == "3": task = tt_tasks.TTTask3(task_id, app_short_name) elif task_type == "4": task = tt_tasks.TTTask4(task_id, app_short_name) return task except Exception: logger.error(Meb_task_factory_exception(1, task_id)) raise Meb_task_factory_exception(1, task_id)
def __create_app(self): """ Create a new app with name, shortname and description passed in constructor and with category_id = 1 and return app.id. Or return the app.id from the app registered in pybossa database. :returns: app.id :rtype: int """ apps = pbclient.find_app(short_name=self.short_name) if not len(apps) == 0: app = apps[0] msg = '{app_name} app is already registered in the DB'.format(app_name=app.name.encode('utf-8', 'replace')) logger.info(unicode(msg, "utf-8")) return app.id else: logger.info("The application is not registered in PyBOSSA. Creating it...") ans = pbclient.create_app(name=self.name, short_name=self.short_name, description=self.description) try: if ans: app = pbclient.find_app(short_name=self.short_name)[0] app.info = dict(newtask="%s/app/%s/newtask" % (flask_app.config['PYBOSSA_URL'], self.short_name)) app.category_id = 1 pbclient.update_app(app) return app.id except Exception as ex: logger.error(Meb_apps_exception(4, -1, self.short_name)) raise ex
def __compare_answers(self, answer1, answer2): THRESHOLD = 2 try: # TODO: RESOLVER ISSO DEPOIS: CASO EM QUE USUARIO NAO FAZ MARCACAO NA PAGINA if answer1 == 0 or answer2 == 0: return False if len(answer1) != len(answer2): return False for i in range(0, min(len(answer2), len(answer1))): table1 = answer1[i] table2 = answer2[i] for answer_key in table1.keys(): a1_value = table1[answer_key] a2_value = table2[answer_key] if answer_key in ["top", "left", "width", "height"]: if a2_value < (a1_value - THRESHOLD) or a2_value > (a1_value + THRESHOLD): return False elif answer_key in ["text"]: if a1_value["assunto"] != a2_value["assunto"]: return False else: # some other key differ if a1_value != a2_value: return False return True except Exception as ex: logger.error(Meb_exception_tt2(1, self.task.id)) logger.error(ex) raise Meb_exception_tt2(1, self.task.id)
def add_next_task(self): try: # Verify the answer of the question to create a new task if (self.task.info.has_key("answer") and self.task.info["answer"] == "Yes"): # record a page on mbdb bookId = self.get_book_id() archurl = self.task.info["url_m"] pg = self.task.info["page"] data_manager.record_page(dict(bookid=bookId, archiveURL=archurl, page_num=pg)) if (self.__checkIfNextTaskWasCreated()): logger.warn(Meb_exception_tt1(3, self.task.id)) raise Meb_exception_tt1(3, self.task.id) info = dict(link=self.task.info["url_m"], page=self.task.info["page"]) tt2_app_short_name = self.app_short_name[:-1] + "2" tt2_app = ttapps.Apptt_meta(short_name=tt2_app_short_name) tt2_task = tt2_app.add_task(info) workflow_transaction_info = dict(task_id_1=self.task.id, task_id_2=tt2_task.id, task_id_3=None, task_id_4=None) data_manager.update_workflow_transaction_t2(workflow_transaction_info) return True else: raise Meb_exception_tt1(1, self.task.id) except Meb_exception_tt1 as e: logger.error(e) return False
def delete_metadata_file(bookid, page_id, page_table_id): try: db.session.query(metadata_file).filter(metadata_file.book_id == bookid) \ .filter(metadata_file.page_id == page_id) \ .filter(metadata_file.page_table_id == page_table_id).delete() db.session.commit() except Exception as e: logger.error(e) db.session.rollback() raise e
def add_next_task(self): if (self.__checkIfNextTaskWasCreated()): logger.warn(Meb_exception_tt3(3, self.task.id)) raise Meb_exception_tt3(3, self.task.id) try: linesAndColumnsMap = self.__loadAnswers() # didnt found a valid task group if self.task.info['hasZoom'] and linesAndColumnsMap == None: return False cells = cells_util.create_cells(linesAndColumnsMap["linhas"], linesAndColumnsMap["colunas"], linesAndColumnsMap["maxX"], linesAndColumnsMap["maxY"]) linkImg = self.task.info['img_url'] book_id = self.get_book_id() page = self.task.info['page'] table_id = self.task.info['table_id'] maxX = linesAndColumnsMap["maxX"] maxY = linesAndColumnsMap["maxY"] self.__runOCR(cells, book_id, page, table_id, maxX, maxY) values = self.__loadValues(book_id, page, table_id) confidences = self.__loadConfidences(book_id, page, table_id) infoDict = {} infoDict['cells'] = cells infoDict['img_url'] = linkImg infoDict['page'] = page infoDict['table_id'] = table_id infoDict['maxX'] = maxX infoDict['maxY'] = maxY infoDict['values'] = values infoDict['confidences'] = confidences tt4_app_short_name = self.app_short_name[:-1] + "4" tt4_app = ttapps.Apptt_transcribe(short_name=tt4_app_short_name) tt4_task = tt4_app.add_task(infoDict, priority=self.task.priority_0) workflow_transaction_info = dict(task_id_1=None, task_id_2=None, task_id_3=self.task.id, task_id_4=tt4_task.id) data_manager.update_workflow_transaction_t4(workflow_transaction_info) return True except Exception as e: logger.error(e) raise e
def __init__(self, task_id, app_short_name): """ Constructor of pb_task :params task_id: Pybossa Task Id """ self.app_short_name = None try: self.__set_app_shortname(task_id, app_short_name) self.task = self.__get_pbtask(task_id) except Meb_pb_task_exception as e: logger.error(e) raise e
def __downloadArchiveImages(self, bookId, imgId, width=550, height=700, max_width=1650, max_height=2100): """ Download internet archive images to tt3_backend project :returns: True if the download was successful :rtype: bool """ try: archiveURL = "http://archive.org/download/%s/page/n%s_w%s_h%s" % ( bookId, imgId, max_width, max_height) logger.info("Downloading archive image: " + archiveURL) url_request = requests.get(archiveURL) fullImgPath = "%s/books/%s/alta_resolucao/image%s" % ( app.config['CV_MODULES'], bookId, imgId) fullImgPathJPG = fullImgPath + ".jpg" fullImgPathPNG = fullImgPath + ".png" fullImgFile = open(fullImgPathJPG, "w") fullImgFile.write(url_request.content) fullImgFile.close() # shell command to convert jpg to png command = 'convert %s -resize %dx%d! %s; rm %s; ' % ( fullImgPathJPG, max_width, max_height, fullImgPathPNG, fullImgPathJPG) # create image with low resolution lowImgPath = "%s/books/%s/baixa_resolucao/image%s" % ( app.config['CV_MODULES'], bookId, imgId) lowImgPathPNG = lowImgPath + ".png" command += 'convert %s -resize %dx%d! %s' % ( fullImgPathPNG, width, height, lowImgPathPNG) msg = "Command to download archive images: " + command logger.info(msg) call([command], shell=True) # calls the shell command return True except Exception as ex: logger.error(Meb_exception_tt2(5, self.task.id)) logger.error(ex) raise Meb_exception_tt2(5, self.task.id) return False
def add_task(self, task_info, priority=0): """ Add task to this app :arg dict task_info: dict with info to task :arg float priority: priority of task (must be between 0 and 1), default = 0 """ if priority < 0 or priority > 1: logger.error(Meb_apps_exception(6, self.app_id, self.short_name)) raise Meb_apps_exception(6, self.app_id, self.short_name) return pbclient.create_task(self.app_id, task_info, priority_0=priority)
def __init__(self, name, short_name, description): """ Pybossa application constructor :arg string name: The application name. :arg string short_name: The slug application name. :arg string description: A short description of the application. """ if name == "": logger.error(Meb_apps_exception(1, -1, "-")) raise Meb_apps_exception(1, -1, "-") elif short_name == "": logger.error(Meb_apps_exception(2, -1, "-")) raise Meb_apps_exception(2, -1, "-") elif description == "": logger.error(Meb_apps_exception(3, -1, "-")) raise Meb_apps_exception(3, -1, "-") self.short_name = short_name self.api_key = pbclient._opts['api_key'] self.pybossa_url = pbclient._opts['endpoint'] self.description = description self.name = name try: self.app_id = self.__create_app() except Exception as e: logger.error(e) raise e
def __init__(self, **keyargs): if "short_name" in keyargs.keys(): if "_tt1" in keyargs['short_name']: short_name = keyargs['short_name'] else: logger.error(Meb_ttapps_exception(5, -1, "-")) raise Meb_ttapps_exception(5, -1, "-") else: logger.error(Meb_ttapps_exception(1, -1, "-")) raise Meb_ttapps_exception(1, -1, "-") if "title" in keyargs.keys(): title = keyargs['title'] + " " else: title = "" if keyargs.has_key("book_info"): data_mngr.record_book(keyargs["book_info"]) app_name = title + unicode("Seleção", "utf-8") super(Apptt_select, self).__init__( app_name, short_name, "Por favor. Selecione as páginas com tabela.") super(Apptt_select, self).set_template(meb_util.set_url( urllib2.urlopen( urllib2.Request( flask_app.config['URL_TEMPLATES'] + "/templates" + "/template-select.html")), short_name)) super(Apptt_select, self).set_long_description(meb_util.set_url( urllib2.urlopen( urllib2.Request( flask_app.config['URL_TEMPLATES'] + "/templates" + "/long_description-select.html")), short_name)) super(Apptt_select, self).add_app_infos( dict(thumbnail=flask_app.config['URL_TEMPLATES'] + "/images" + "/long_description_selection.png")) logger.info("Create task type 1")
def __init__(self, **keyargs): if "short_name" in keyargs.keys(): if "_tt4" in keyargs['short_name']: short_name = keyargs['short_name'] else: logger.error(Meb_ttapps_exception(8, -1, "-")) raise Meb_ttapps_exception(8, -1, "-") else: raise Meb_ttapps_exception(4, -1, "-") if "title" in keyargs.keys(): title = keyargs['title'] + " " else: title = "" app_name = title + unicode("Transcrição", "utf-8") super(Apptt_transcribe, self).__init__( app_name, short_name, "Por favor. Corrija o conteúdo das células da tabela.") super(Apptt_transcribe, self).set_template(meb_util.set_url( urllib2.urlopen( urllib2.Request( flask_app.config['URL_TEMPLATES'] + "/templates/template-transcribe.html")), short_name)) super(Apptt_transcribe, self).set_long_description(meb_util.set_url( urllib2.urlopen( urllib2.Request( flask_app.config['URL_TEMPLATES'] + "/templates" + "/long_description-transcribe.html")), short_name)) super(Apptt_transcribe, self).add_app_infos( dict( sched="incremental", thumbnail=flask_app.config['URL_TEMPLATES'] + "/images" + "/long_description_transcribe.png")) logger.info("Create task type 4")
def get_tt_images(bookId): """ Get public book images from internet archive server :returns: A list with dicts containing images urls and index. :rtype: list """ WIDTH = 550 HEIGHT = 700 logger.info('Contacting archive.org') url = "http://archive.org/metadata/" query = url + bookId urlobj = urllib2.urlopen(query) data = urlobj.read() urlobj.close() output = json.loads(data) imgList = [] if output: n_pages = None try: if output['metadata'].has_key('imagecount'): n_pages = output['metadata']['imagecount'] elif output['metadata'].has_key('numero_de_paginas_do_item'): n_pages = output['metadata']['numero_de_paginas_do_item'] except KeyError: logger.error(Archive_book_data_exception(1, "imagecount or numero_de_paginas_do_item")) raise Archive_book_data_exception(1, "imagecount or numero_de_paginas_do_item") imgUrls = "http://www.archive.org/download/" + bookId + "/page/n" for idx in range(int(n_pages)): logger.info('Retrieved img: %s' % idx) page = idx imgUrl_m = imgUrls + "%d_w%d_h%d" % (idx, WIDTH, HEIGHT) imgUrl_b = imgUrls + str(idx) imgList.append({'url_m': imgUrl_m, 'url_b': imgUrl_b, 'page': page}) return imgList
def add_app_infos(self, info_values): """ Add new info values to info attribute from this app :arg dict info_values: dict with infos and respectives values to add to the app """ app = pbclient.get_app(self.app_id) if(type(info_values) is dict): for info_key in info_values.keys(): app.info[str(info_key)] = info_values[info_key] else: logger.error(Meb_apps_exception(5, self.app_id, self.short_name)) raise Meb_apps_exception(5, self.app_id, self.short_name) pbclient.update_app(app)
def __init__(self, **keyargs): if "short_name" in keyargs.keys(): if "_tt2" in keyargs['short_name']: short_name = keyargs['short_name'] else: logger.error(Meb_ttapps_exception(6, -1, "-")) raise Meb_ttapps_exception(6, -1, "-") else: raise Meb_ttapps_exception(2, -1, "-") if "title" in keyargs.keys(): title = keyargs['title'] + " " else: title = "" app_name = title + unicode("Marcação", "utf-8") super(Apptt_meta, self).__init__( app_name, short_name, "Marque e descreva as tabelas ou corrija as marcações.") super(Apptt_meta, self).set_template(meb_util.set_url( urllib2.urlopen( urllib2.Request( flask_app.config['URL_TEMPLATES'] + "/templates" + "/template-meta.html")), short_name)) super(Apptt_meta, self).set_long_description(meb_util.set_url( urllib2.urlopen( urllib2.Request( flask_app.config['URL_TEMPLATES'] + "/templates" + "/long_description-meta.html")), short_name)) super(Apptt_meta, self).add_app_infos( dict( sched="incremental", thumbnail=flask_app.config['URL_TEMPLATES'] + "/images" + "/long_description_meta.png")) logger.info("Create task type 2")
def __runLinesRecognition(self, bookId, imgId, rotate, model="1"): """ Call cpp software that recognizes lines into the table and writes lines coords into \ <tt3_backend_dir>/books/bookId/metadados/saida/image<imgId>.txt :returns: True if the write was successful :rtype: bool """ try: if rotate: # rotated table rotate = "-r" command = 'cd %s/TableTranscriber2/; sudo ./tabletranscriber2 ' \ '"/books/%s/baixa_resolucao/image%s.png" "model%s" "%s"' % ( app.config['CV_MODULES'], bookId, imgId, model, rotate) msg = "Command to run lines recognition software: " + command logger.info(msg) call([command], shell=True) # calls the shell command else: # not rotated table rotate = "-nr" command = 'cd %s/TableTranscriber2/; sudo ./tabletranscriber2 ' \ '"/books/%s/baixa_resolucao/image%s.png" "model%s" "%s"' % ( app.config['CV_MODULES'], bookId, imgId, model, rotate) msg = "Command to run lines recognition software: " + command logger.info(msg) call([command], shell=True) # calls the shell command return self.__checkFile(bookId, imgId) except Meb_exception_tt2 as e: logger.error(Meb_exception_tt2(3, self.task.id)) raise e except Exception as ex: logger.error(Meb_exception_tt2(2), self.task.id) raise ex
def __loadValues(self, book_id, page, table_id): """ Load values transcripted by tesseract ocr for this table """ try: f = open("%s/books/%s/transcricoes/texts/image%s_%s.txt" % ( app.config['CV_MODULES'], book_id, page, table_id), 'r') tmp = f.readlines() f.close() values = [] for val in tmp[1:]: values.append(val[:-1]) # exclude \n return values #excluding header except IOError as ioe: logger.error(ioe) raise Meb_exception_tt3(5, self.task.id)
def __runOCR(self, cells, book_id, page, table_id, maxX, maxY): """ Run tesseract executor """ self.__saveCells(cells, book_id, page, table_id, maxX, maxY) try: command = 'cd %s/TesseractExecutorApp2/; sudo ./tesseractexecutorapp2 ' \ '"/books/%s/metadados/tabelasAlta/image%s_%d.png"' % ( app.config['CV_MODULES'], book_id, page, table_id) msg = "Command to run tesseract executor: " + command logger.info(msg) call([command], shell=True) except Exception as ex: logger.error(Meb_exception_tt3(4, self.task.id)) raise ex
def __init__(self, **keyargs): if "short_name" in keyargs.keys(): if "_tt3" in keyargs['short_name']: short_name = keyargs['short_name'] else: logger.error(Meb_ttapps_exception(7, -1, "-")) raise Meb_ttapps_exception(7, -1, "-") else: raise Meb_ttapps_exception(3, -1, "-") if "title" in keyargs.keys(): title = keyargs['title'] + " " else: title = "" app_name = title + unicode("Estrutura", "utf-8") super(Apptt_struct, self).__init__( app_name, short_name, "Por favor. Corrija as linhas e colunas da tabela.") super(Apptt_struct, self).set_template(meb_util.set_url( urllib2.urlopen( urllib2.Request( flask_app.config['URL_TEMPLATES'] + "/templates/template-struct.html")), short_name)) super(Apptt_struct, self).set_long_description(meb_util.set_url( urllib2.urlopen( urllib2.Request( flask_app.config['URL_TEMPLATES'] + "/templates" + "/long_description-struct.html")), short_name)) try: self.__create_dirs(flask_app.config['CV_MODULES'], short_name[:-4]) logger.info("TT folders created") except OSError, e: logger.error(e)
def check_answer(self): task_runs = self.get_task_runs() n_taskruns = len(task_runs) # task_runs goes from 0 to n-1 try: if(n_taskruns > 1): answer1 = task_runs[n_taskruns - 1].info answer2 = task_runs[n_taskruns - 2].info answer1_json = json.loads(answer1) answer2_json = json.loads(answer2) if(self.__compare_answers(answer1_json, answer2_json)): return True else: return False else: return False except Meb_exception_tt3 as ex: logger.error(ex) raise ex
def check_answer(self): task_runs = self.get_task_runs() n_taskruns = len(task_runs) # task_runs goes from 0 to n-1 try: if (n_taskruns > 0): last_answer_info = task_runs[-1].info last_answer_info_json = json.loads(last_answer_info) confirmations = last_answer_info_json['num_of_confirmations'] for confirmation in confirmations: if (int(confirmation) < 2): return False return True else: return False except Exception as e: logger.error(Meb_exception_tt4(1, self.task.id)) logger.error(e) raise Meb_exception_tt4(1, self.task.id)
def check_answer(self): task_runs = self.get_task_runs() n_taskruns = len(task_runs) # task_runs goes from 0 to n-1 try: if(n_taskruns > 1): answer1 = task_runs[n_taskruns - 1].info answer2 = task_runs[n_taskruns - 2].info answer1_json = json.loads(answer1) answer2_json = json.loads(answer2) if self.__compare_answers(answer1_json, answer2_json): if answer2 != "0": return self.__fileOutput(answer2_json) return False except Exception as ex: logger.error(Meb_exception_tt2(1, self.task.id)) logger.error(ex) raise Meb_exception_tt2(1, self.task.id)
def __loadConfidences(self, book_id, page, table_id): """ Load confidences identified in transcriptions by tesseract ocr for this table. """ try: f = open("%s/books/%s/transcricoes/confidences/image%s_%s.txt" % ( app.config['CV_MODULES'], book_id, page, table_id), 'r') tmp = f.readlines() f.close() confidences = [] for conf in tmp[1:]: confidences.append( int(conf[:-1])) # exclude \n return confidences # excluding header except IOError as ioe: logger.error(ioe) raise Meb_exception_tt3(6, self.task.id)
def check_answer(self): try: task_runs = self.get_task_runs() N_ANSWERS = 2 answers = {} for taskrun in task_runs: answer = taskrun.info if(answer not in answers.keys()): answers[answer] = 1 else: answers[answer] += 1 if(answers[answer] == N_ANSWERS and answer != "NotKnown"): self.task.info["answer"] = answer # put the answer into task info pbclient.update_task(self.task) return True except Exception: logger.error(Meb_exception_tt1(2, self.task.id)) raise Meb_exception_tt1(2, self.task.id)
def __runAreaSelection(self, bookId, imgId, tableId, rotate): """ Call cpp ZoomingSelector software that splits the tables and write the pieces at <tt3_backend_id>/books/bookId/selections/image<imgId>_tableId.txt :returns: True if the execution was ok :rtype: bool """ try: command = 'cd %s/ZoomingSelector/; sudo ./zoomingselector ' \ '"/books/%s/metadados/tabelasAlta/image%s_%d.png"' % ( app.config['CV_MODULES'], bookId, imgId, tableId) msg = "Command to run zoomingselector (area selection software) " + command logger.info(msg) call([command], shell=True) except Exception as ex: logger.error(Meb_exception_tt2(4, self.task.id)) raise ex
def record_metadata_file(metadata_file_dict): try: mt_file = metadata_file( metadata_file_dict["book_id"], metadata_file_dict["page_number"], metadata_file_dict["table_number"], metadata_file_dict["mt_file"] ) db.session.add(mt_file) db.session.commit() except Exception as e: db.session.rollback() logger.error(e) logger.error(Meb_data_manager_metadata_file_exception(1, metadata_file_dict["book_id"], metadata_file["page_number"], metadata_file["table_number"] )) raise e
def __fileOutput(self, answer): """"" Writes tt2 answers into the file input for the lines recognitions :returns: True if the answer is saved at the file :rtype: bool """ try: pb_app_name = self.app_short_name bookId = pb_app_name[:-4] imgId = self.task.info["page"] msg = "File path:" + "%s/books/%s/metadados/entrada/image%s.txt" % \ (app.config["CV_MODULES"], bookId, imgId), "a" logger.info(msg) arch = open("%s/books/%s/metadados/entrada/image%s.txt" % ( app.config["CV_MODULES"], bookId, imgId), "w") for table in answer: x0 = int(table["left"]) x1 = int(table["width"] + x0) y0 = int(table["top"]) y1 = int(table["height"] + y0) arch.write( str(x0) + "," + str(y0) + "," + str(x1) + "," + str(y1) + "\n") arch.close() return True except IOError as e: print e logger.error(Meb_file_output_exception_tt2(1, self.task.id, bookId, imgId)) raise Meb_file_output_exception_tt2(1, self.task.id, bookId, imgId) return False
def __getAreaSelection(self, bookId, imgId, tableId): selections = [] try: filepath = "%s/books/%s/selections/image%s_%d.txt" % ( app.config['CV_MODULES'], bookId, imgId, tableId) arch = open(filepath) data = arch.read().strip().split('\n') for data_idx in range(1, len(data)): selections.append([ int(coord) for coord in data[data_idx].split(',')]) except IOError as ioe: msg = "Error! Couldn't open image%s_%d.txt selection file" % (imgId, tableId) logger.error(Meb_exception_tt2(4, self.task.id)) logger.error(msg) raise ioe except Exception as ex: logger.error(Meb_exception_tt2(4, self.task.id)) raise ex return selections