def call_task(options): ''' Command line method for running sniffer service''' try: logger = Utilities.GetLogger(LOG_NAME, useFile=False) logger.debug('Calling task from command line') logger.debug('Parsing sample data') title_data = {} print options.top_items[0] message = json.load(open(options.top_items[0] )) top_items = message["content"]["status"]["top_items"] title_data.update({'top_items': top_items}) message = json.load(open(options.found_items[0])) found_items = message["content"]["status"]["found_items"] title_data.update({'found_items': found_items}) search_title= message["content"]["status"]["search_title"] title_data.update({'search_title': search_title}) logger.debug('Selecting best fit for torrent') taskAction = TorrentSelector() top_item = taskAction.findTitle(title_data) pprint.pprint(top_item.to_dict()) except Exception as inst: Utilities.ParseException(inst, logger=logger)
def run(self): '''Threaded action ''' try: ## Setting process as started self.running = True ## Setting thread for joining service list if self.service is not None and self.service.task is not None: self.logger.debug(' + Adding thread for joining context') self.service.task.AddContext(self, self.component) # Getting thread GetPID self.tid = Utilities.GetPID() self.logger.debug('Starting task [%s] with PID [%d]'% (self.component, self.tid)) ## Starting voice recognition self.logger.debug('Setting up voice recognition...') args = {} args.update({'butler_words': self.butler_words}) args.update({'service': self.service}) voice_recognition = Recorder(**args) self.logger.debug('Looping for task [%d]'%self.tid) voice_recognition.Run() #while not self.tStop.isSet(): ## Do something here! ## ... #self.tStop.wait(5) # Ending thread routine self.running = False self.logger.debug('Ending thread [%d]'%self.tid) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def run(self): '''Threaded action ''' try: ## Setting process as started self.running = True ## Setting thread for joining service list if self.service is not None and self.service.task is not None: self.logger.debug(' + Adding thread for joining context') self.service.task.AddContext(self, self.component) # Getting thread GetPID self.tid = Utilities.GetPID() self.logger.debug('Starting task [%s] with PID [%d]'% (self.component, self.tid)) self.logger.debug('Looping for task [%d]'%self.tid) while not self.tStop.isSet(): if self.not_searching: if len(self.title_data.keys())<1: raise Exception('Search data not defined but process started') self.logger.debug(' +++ Confirming title data') top_item_df = self.selector.findTitle(self.title_data) result_state = 'failed' itemsCall = { } top_item = { } if top_item_df.shape[0] > 0: result_state = 'success' print "-_"*60 top_items_dict= top_item_df.to_dict() print "-_"*60 pprint.pprint(top_items_dict) top_item = self.selector.reduce_item(top_items_dict) print "-_"*60 pprint.pprint(top_item) itemsCall.update({'confirmed_title': top_item }) itemsCall.update({'search_title': self.title_data['search_title'] }) pprint.pprint(itemsCall) print"#"*100 print"#"*100 print"#"*100 self.service.notify("updated", result_state, items=itemsCall) self.logger.debug(' +++ Resetting search query...') self.not_searching = False self.tStop.wait(1) # Ending thread routine self.running = False self.logger.debug('Ending thread [%d]'%self.tid) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def __init__(self): try: # Initialising class variables self.component = self.__class__.__name__ self.logger = Utilities.GetLogger(self.component) self.output = None except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def __init__(self, **kwargs): '''Service task constructor''' # Initialising thread parent class threading.Thread.__init__(self) try: # Initialising class variables self.component = self.__class__.__name__ self.logger = Utilities.GetLogger(self.component) # Thread action variables self.tStop = threading.Event() self.threads = [] self.tid = None self.running = False ## Adding local variables self.service = None self.onStart = True self.title = None self.page_limit = None self.search_engines = None self.action_words = None self.not_searching = False self.finder = None # Generating instance of strategy for key, value in kwargs.iteritems(): if "service" == key: self.service = value elif "onStart" == key: self.onStart = bool(value) elif "page_limit" == key: self.page_limit = int(value) elif "search_engines" == key: self.search_engines = value pprint.pprint(self.search_engines) elif "action_words" == key: self.action_words = value ## Setting item started for reporting to device action self.running = True ## Creating torrent finder instance self.finder = TorrentFinder(self.search_engines) # Starting action thread if self.onStart: self.logger.debug(" + Process is starting immediately") self.start() ## Adding monitor thread to the list of references self.threads.append(self) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def run(self): '''Threaded action ''' try: ## Setting process as started self.running = True ## Setting thread for joining service list if self.service is not None and self.service.task is not None: self.logger.debug(' + Adding thread for joining context') self.service.task.AddContext(self, self.component) # Getting thread GetPID self.tid = Utilities.GetPID() self.logger.debug('Starting task [%s] with PID [%d]' % (self.component, self.tid)) self.logger.debug('Looping for task [%d]' % self.tid) while not self.tStop.isSet(): if self.not_searching: if self.title is None: raise Exception( 'Torrent search started with invalid title') self.logger.debug(' ~~~ Searching for torrent') top_items = self.locate_torrent(self.title, self.page_limit) itemsCall = {'search_title': self.title} if top_items is None or 'top_items' not in top_items.keys( ): result_state = 'failed' itemsCall.update({'top_items': {}}) else: self.logger.debug(' ~~~ Found [%d] items' % len(top_items["top_items"])) result_state = 'success' ## pprint.pprint(top_items) ## print "+"*120 itemsCall.update({'top_items': top_items['top_items']}) self.logger.debug(' ~~~ Posting results') self.service.notify("updated", result_state, items=itemsCall) self.logger.debug(' ~~~ Resetting search query...') self.not_searching = False self.title = None self.tStop.wait(1) # Ending thread routine self.running = False self.logger.debug('Ending thread [%d]' % self.tid) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def __init__(self, **kwargs): try: # Initialising class variables self.component = self.__class__.__name__ self.logger = Utilities.GetLogger(self.component) self.logger.debug(" + Creating torrent selector") ## Adding local variables self.title_data = None except Exception as inst: Utilities.ParseException(inst, logger=logger)
def __init__(self, **kwargs): '''Service task constructor''' try: # Initialising class variables self.component = self.__class__.__name__ self.logger = Utilities.GetLogger(self.component) ## Adding local variables self.database = None self.collection = None self.action_words = None self.not_searching = False self.database = None self.torrent_terms = None self.forecast_item = None self.db_handler = None self.slack_channel = None self.last_days = 3 # Generating instance of strategy for key, value in kwargs.iteritems(): if "database" == key: self.database = value elif "last_days" == key: self.last_days = value elif "collection" == key: self.collection = value elif "slack_channel" == key: self.slack_channel = value self.logger.debug(" + Setting up channel [%s]"%self.slack_channel) elif "forecast_item" == key: self.forecast_item = value elif "with_changes" == key: if value is not None: self.with_changes = self.LoadTerms('list_termx.txt') elif "list_term" == key: if value is not None: self.with_changes = self.LoadTerms(value) if self.forecast_item is None: ## Setting item started for reporting to device action self.logger.debug(" + Generating database [%s] in [%s] collections"% (self.database, self.collection)) self.db_handler = MongoAccess(debug=False) self.db_handler.connect(self.database, self.collection) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def __init__(self, **kwargs): '''Service task constructor''' # Initialising thread parent class threading.Thread.__init__(self) try: # Initialising class variables self.component = self.__class__.__name__ self.logger = Utilities.GetLogger(self.component) # Thread action variables self.tStop = threading.Event() self.threads = [] self.tid = None self.running = False ## Adding local variables self.service = None self.onStart = True self.not_searching= False self.search_title = None self.logger.debug(" + Creating IMDB client") self.imdb = Imdb() self.logger.debug(" + Creating similarity calculator") self.similarity = Similarity() # Generating instance of strategy for key, value in kwargs.iteritems(): if "service" == key: self.service = value elif "onStart" == key: self.onStart = bool(value) elif "search_title" == key: self.search_title = value ## Setting item started for reporting to device action self.running = True # Starting action thread if self.onStart: self.logger.debug(" + Process is starting immediately") self.start() ## Adding monitor thread to the list of references self.threads.append(self) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def call_task(options): ''' Command line method for running sniffer service''' try: logger = Utilities.GetLogger(LOG_NAME, useFile=False) logger.debug('Calling task from command line') args = {} args.update({'database': options.database}) args.update({'collection': options.collection}) args.update({'list_term': options.list_term}) if options.slack_file is not None: logger.debug(' Options set for using modelled data') newest_items = options.slack_file args.update({'list_term': options.list_term}) ## Calling methods taskAction = FindChanges(**args) taskAction.PostNew(newest_items) elif options.plot: logger.debug(' Options set for plotting') taskAction = FindChanges(**args) changes, newest_items = taskAction.GetMovies(['seeds']) elif options.forecast_file is None: logger.debug(' Options set for normal use') if options.slack_channel is not None: args.update({'slack_channel': options.slack_channel}) ## Checking if slack token was provided if "SLACK_API_TOKEN" not in os.environ.keys(): logger.debug("Slack token not found!") return taskAction = FindChanges(**args) changes, newest_items = taskAction.GetMovies(['seeds']) taskAction.PostNew(newest_items) else: logger.debug(' Options set for using sample model file [%s]'%options.forecast_file) with open(options.forecast_file, 'r') as file: forecast_item = json.load(file) args.update({'forecast_item': forecast_item}) taskAction = ForecastModel(**args) for data_unit in forecast_item: #taskAction.Run(data_unit, ['leeches', 'seeds']) taskAction.Run(data_unit, ['seeds']) except Exception as inst: Utilities.ParseException(inst, logger=logger)
def call_task(options): ''' Command line method for running sniffer service''' try: logger = Utilities.GetLogger(LOG_NAME, useFile=False) logger.debug('Calling task from command line') args = {} args.update({'option1': options.opt1}) args.update({'option2': options.opt2}) taskAction = GetVoiceOrder(**args) except Exception as inst: Utilities.ParseException(inst, logger=logger)
def GenerateSampleServices(self): ''' Generating files only once''' try: if not self.HasStarted: ## Preparing autogenerator constructor variables filename = 'sample_services.xml' services = ParseXml2Dict(filename, 'MetaServiceConf') ## Making single service a list if type(services['Service']) is not type([]): services['Service'] = [services['Service']] self.logger.info("Checking if previous files exists") ## Remove existing files fileName = 'Context-%s.xml' % services['context_name'] confPath = services['service_path'] + '/Conf/' + fileName if os.path.isfile(confPath): self.logger.debug(" + Removing configuration file:" + confPath) os.remove(confPath) for service in services['Service']: ## Removing services serviceFilesPath = service['location'] + "/" + service[ 'task_service'] if os.path.exists(serviceFilesPath): self.logger.debug(" + Removing configuration file:" + serviceFilesPath) shutil.rmtree(serviceFilesPath) if len(service['location']) > 0: self.logger.info( "Creating service [%s] with ID [%s]" % (service['task_service'], service['task_id'])) service.update( {'context_name': services['context_name']}) service.update({'server_ip': services['server_ip']}) service.update({'sub_port': services['sub_port']}) service.update({'pub_port': services['pub_port']}) service.update( {'service_path': services['service_path']}) service.update({'home_path': services['home_path']}) service.update({'location': service['location']}) service.update({'context_id': services['context_id']}) service.update( {'log_on': bool(int(services['log_on']))}) ## Checking if there is a type of task if 'task_type' in service.keys(): service.update({'taskType': service['task_type']}) ## Calling code autogenerator autogenerator = AutoCode(service) autogenerator.CreateFiles() ## Do not run this procedure every test serviceFileHasStarted = True except Exception as inst: Utilities.ParseException(inst)
def SetSearch(self, status): try: ## Getting correct action self.search_title = status['search_title'] self.not_searching = True except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def LoadTerms(self, fileName): try: with open(fileName, 'r') as file: return file.read().strip().split() except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def http_request(self, url): """ http_request method. This method does not calculate time. Only fetches URL and prepares self.soup """ returned_code = None try: try: self.raw = requests.get(url, timeout=30) returned_code = self.raw.status_code self.logger.debug(" + Returned status code: %d for url %s" % (returned_code, url)) except (requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout) as e: self.logger.error(e) self.logger.exception("Stacktrace...") return None, returned_code self.raw = self.raw.content self.soup = BeautifulSoup(self.raw, 'lxml') return self.soup except KeyboardInterrupt as e: print("Aborted!") self.logger.exception(e) ##sys.exit(2) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def AddMissingKeys(self, db_post, web_element): ''' Adds missing keys in existing DB records. ''' result = True try: if isinstance(db_post, type(None)): self.logger.debug("Invalid input DB post for printing") elementKeys = web_element.keys() postKeys = db_post.keys() postKeysCounter = Counter(postKeys) elementKeysCounter = Counter(elementKeys) extra_in_db = (postKeysCounter - elementKeysCounter).keys() missed_in_db = (elementKeysCounter - postKeysCounter).keys() for key in extra_in_db: if key != '_id': self.logger.debug(' - TODO: Remove item [%s] from DB', key) if len(missed_in_db) > 0: for key in missed_in_db: self.logger.debug(' - Updated item [%s] from DB', key) result = self.Update(condition={"_id": db_post["_id"]}, substitute={key: web_element[key]}, upsertValue=False) self.logger.debug( " - Added key [%s] in item [%s] of collection [%s]" % (key, item[item_index], self.db_handler.coll_name)) except Exception as inst: Utilities.ParseException(inst, logger=self.logger) finally: return result
def DeserializeAction(self, msg): ''' Validates incoming message when called in service section''' try: isForDevice = msg['header']['service_name'] == 'search_imdb' or msg[ 'header']['service_name'] == 'all' isRightTransaction = False if 'transaction' in msg['header'].keys(): isRightTransaction = msg['header'][ 'transaction'] == self.transaction elif 'service_transaction' in msg['header'].keys(): isRightTransaction = msg['header'][ 'service_transaction'] == self.transaction else: self.logger.debug("Message without transaction ID") return isRightTransaction if not isRightTransaction: self.logger.debug("Service with different transaction") return False result = (isForDevice and isRightTransaction) if result: self.logger.debug(" Validation [PASSED]") return result except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def Run(self): ''' Looks for all browse movies and parses HTML in two threads. Then, updates any non feature torrent in DB ''' try: self.logger.debug("Obtaining proxies...") proxy_ok = self.check_proxy() if proxy_ok: self.logger.debug("Preparing threads") condition = threading.Condition() html_crawler = threading.Thread(name='html_crawler', target=self.get_html, args=(condition, )) html_parser = threading.Thread(name='html_parser', target=self.parse_html, args=(condition, )) html_crawler.start() html_parser.start() html_crawler.join() html_parser.join() crawler_db = threading.Thread(name='crawler_db', target=self.complete_db, args=(condition, )) crawler_db.start() crawler_db.join() ## pprint.pprint(lmt.supermasterlist) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def close(self): ''' Ending task service''' try: # Do additional stopping routines here # ... if not self.tStop.isSet(): # Stop thread and give some time to do whatever it has to do self.logger.debug(" Stopping task thread, setting event...") self.tStop.set() time.sleep(0.75) else: self.logger.debug(" Event loop is already interrupted") # Force to stop before leaving if self.is_alive() and self.service is not None: self.logger.debug( " Stopping the thread and wait for it to end") threading.Thread.join(self, 1) else: self.logger.debug(" Thread is not alive") self.logger.debug( " Thread stopped") except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def Run(self, forecast_item): ''' ''' result = {} optimal_model = {} error_optimisation = None result_models = [] try: for input_data in forecast_item: #['leeches', 'seeds'] self.logger.debug("Processing input data for [%s]"%input_data['name']) ## Optimising errors of initial error estimates for initial_error_estim in self.optimisation_steps: ## Executing Kalman filter model result = self.ExecuteModel(input_data, ['seeds'], initial_error_estim, error_optimisation) if result is None: print "Error: Invalid result set" break result_models.append(result) break break except Exception as inst: Utilities.ParseException(inst, logger=self.logger) finally: return result
def sort_top_items(self, top_items): ''' Looks for best magnet based in the averages size. Then in number of seeders.''' best_items = None try: ## pprint.pprint(top_items) ## print "-"*120 top_items_df = pd.DataFrame.from_dict(top_items) ## pprint.pprint(top_items_df) mean = top_items_df["size"].mean() ## quantile_upper = top_items_df["size"].quantile(0.75) ## print "=== mean:", mean ## print "=== quantile_upper:", quantile_upper top_items_size = top_items_df.sort_values(by=['size'], ascending=[False]) ## pprint.pprint(top_items_size) ## print "="*120 top_items_filter = top_items_size.loc[top_items_size['size'] > mean] ## pprint.pprint(top_items_filter) ## print "-"*120 top_items_seeders = top_items_filter.sort_values(by=['seeders'], ascending=[False]) #TODO: If top seeders are zero, use leechers ## pprint.pprint(top_items_seeders) best_items = top_items_seeders except Exception as inst: Utilities.ParseException(inst, logger=self.logger) finally: return best_items
def ControlAction(self, msg): ''' Actions taken if another process reports with control topic''' try: ## Validating transaction isRightTransaction = self.ValidateTransaction(msg) if not isRightTransaction: self.logger.debug("Service with different transaction") return isRightTransaction header = msg['header'] status = msg['content']['status'] if 'service_name' not in header.keys(): self.logger.debug("[service_name] Not found in [header]") return if 'content' not in msg.keys(): self.logger.debug("[content] Not found in [content]") return content = msg['content'] if 'status' not in content.keys(): self.logger.debug("[status] Not found in [content]") return status = content['status'] if 'result' not in status.keys(): self.logger.debug("[result] Not found in [status]") return # Filtering reporting process if header['service_name'] == 'movie_finder' and status[ "result"] == "success": self.logger.debug("Received message from [movie_finder]") statusKeys = status.keys() if 'search_title' not in statusKeys: self.logger.debug("[search_title] Not found in [status]") return if 'top_items' not in statusKeys: self.logger.debug("[top_items] Not found in [status]") return self.logger.debug("Received message for action handler") self.actionHandler.SetSearch(status) elif header['service_name'] == 'search_imdb' and status[ "result"] == "success": self.logger.debug("Received message from [search_imdb]") statusKeys = status.keys() if 'search_title' not in statusKeys: self.logger.debug("[search_title] Not found in [status]") return if 'found_items' not in statusKeys: self.logger.debug("[found_items] Not found in [status]") return self.logger.debug("Received message for action handler") self.actionHandler.SetSearch(status) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def SetSearch(self, status): try: ## Getting correct action VARIABLE1 = status['VARIABLE1'] VARIABLE2 = status['VARIABLE2'] self.not_searching = True except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def run(self): '''Threaded action ''' try: ## Setting process as started self.running = True ## Setting thread for joining service list if self.service is not None and self.service.task is not None: self.logger.debug(' + Adding thread for joining context') self.service.task.AddContext(self, self.component) # Getting thread GetPID self.tid = Utilities.GetPID() self.logger.debug('Starting task [%s] with PID [%d]'% (self.component, self.tid)) self.logger.debug('Looping for task [%d]'%self.tid) while not self.tStop.isSet(): if self.not_searching: self.logger.debug(' ~~~ Starting action handler action') found_items = self.imdb.search_for_title(self.search_title) result_state = 'failed' itemsCall = {} if len(found_items)>0: for item in found_items: if 'title' in item.keys(): score = self.similarity.score(self.search_title, item['title']) item.update({'score':score}) result_state = 'success' #pprint.pprint(found_items) self.logger.debug(' ~~~ Posting results') itemsCall.update({'search_title': self.search_title, 'found_items':found_items}) self.service.notify("updated", result_state, items=itemsCall) self.logger.debug(' ~~~ Resetting search query...') self.not_searching = False self.search_title = None self.tStop.wait(1) # Ending thread routine self.running = False self.logger.debug('Ending thread [%d]'%self.tid) except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def call_method(options): try: args = {} args.update({'butler_words': options.butler_words}) recorder = Recorder(**args) recorder.Run() except Exception as inst: Utilities.ParseException(inst)
def step5_optimise(self, output, **input): ''' Adds columns for current estimate and its 1st derivative ''' result = True try: data_model = None ## Collecting input data for key, value in input.iteritems(): if "data_model" == key: data_model = value ## Collecting step data initial_error_estim = data_model['initial_error_estim'] error_optimisation = data_model['error_optimisation'] optimisation_steps = data_model['optimisation_steps'] ## Iterating item IDs ### for item_id in items_id: self.logger.debug(" 5.1) Getting derivative statistical values") deriv_curr_estim_values = [] #source = input[item_id] source = data_model['model'] deriv_sq_error = pd.Series(source['SqErrorDeriv'].values) stddev_deriv_sq_error = deriv_sq_error.std() ## Updating error optimisation table if error_optimisation is None: ## There is no table, creating one error_optimisation = pd.DataFrame([], index=optimisation_steps, columns = ['SumDerivStdev', '1stDerivSum']) self.logger.debug(" 5.2) Calculating 1st derivative of std of sum of squared error") list_indexes = list(error_optimisation.index.get_values()) index_value = list_indexes.index(initial_error_estim) error_optimisation.iloc[index_value]['SumDerivStdev'] = stddev_deriv_sq_error ## Calculating 1st derivative for sum of squared errors if index_value == 0: ## First derivative is a NaN der_sum_der_std = float('nan') else: previous_value = error_optimisation.iloc[index_value-1]['SumDerivStdev'] der_sum_der_std = stddev_deriv_sq_error - previous_value error_optimisation.iloc[index_value]['1stDerivSum'] = der_sum_der_std data_model['error_optimisation'] = error_optimisation self.logger.debug("-"*65) except Exception as inst: result = False Utilities.ParseException(inst, logger=self.logger) finally: data_model['step_result'] = result output.update({'data_model' : data_model})
def look_for_magnet(link): try: self.logger.debug("+ Getting link magnet") args = {} crawler = LimeTorrentsCrawler(**args) magnet, download_link = crawler.get_magnet_download(link) return magnet, download_link except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def GetActionHandler(self, msg): ''' ''' self.logger.debug( "Creating a Looks into known torrent most popular choices") result = "failure" deviceAction = None try: message = msg['Task']['message'] conf = message['content']['configuration'] state = msg['Task']['state'] confKeys = conf.keys() args = {'onStart': True, 'service': self} ## Parsing parameters self.logger.debug(" Parsing message parameters") for key in confKeys: if key in confKeys: value = message['content']['configuration'][key] args.update({key: value}) # Creating service object and notify start_state = 'started' taskType = state['type'] if not (taskType == 'on_start' or taskType == 'start_now'): self.logger.debug(" - Process is set and start is on demand") args['onStart'] = False start_state = 'created' print "----------------------------------" # Creating service object and notify deviceAction = InspectTorrents(**args) if deviceAction.hasStarted(): result = "success" else: self.logger.debug(" Failed to instance action handler") except Exception as inst: Utilities.ParseException(inst, logger=self.logger) finally: # Notifying if task was created tid = Utilities.GetPID() self.notify("started", result, items={'pid': tid}) return deviceAction
def Run(self): try: isTimerOff = True while isTimerOff: try: self.WaitOrder() except grpc._channel._Rendezvous: continue except Exception as inst: Utilities.ParseException(inst, logger=self.logger)
def call_task(options): ''' Command line method for running sniffer service''' try: logger = Utilities.GetLogger(LOG_NAME, useFile=False) logger.debug('Calling task from command line') args = {} args.update({'database': options.database}) args.update({'collection': options.collection}) logger.debug('Openning sample model file [%s]'%options.forecast_file) with open(options.forecast_file, 'r') as file: forecast_item = json.load(file) args.update({'forecast_item': forecast_item}) taskAction = ForecastModel(**args) taskAction.Run(forecast_item) except Exception as inst: Utilities.ParseException(inst, logger=logger)