From 128cc7b1f918b69531a19468d9e8c9e1c81bbed4 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Mon, 8 Jun 2020 22:38:33 -0700 Subject: [PATCH] Add backend infrastructure for item callbacks --- inquisitor/app.py | 3 ++- inquisitor/importer.py | 48 ++++++++++++++++++++++++++++------------- sources/callbackdemo.py | 3 ++- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/inquisitor/app.py b/inquisitor/app.py index 57ab55a..b8385db 100644 --- a/inquisitor/app.py +++ b/inquisitor/app.py @@ -8,7 +8,7 @@ from flask import Flask, render_template, request, jsonify # Application imports from inquisitor.configs import logger, DUNGEON_PATH -from inquisitor import loader, timestamp +from inquisitor import importer, loader, timestamp # Globals app = Flask(__name__) @@ -146,4 +146,5 @@ def callback(): params = request.get_json() if 'source' not in params and 'itemid' not in params: logger.error("Bad request params: {}".format(params)) + importer.item_callback(params['source'], params['itemid']) return jsonify({}) diff --git a/inquisitor/importer.py b/inquisitor/importer.py index 04adfc3..2c7bf13 100644 --- a/inquisitor/importer.py +++ b/inquisitor/importer.py @@ -43,22 +43,23 @@ def load_source(source_name): """ # Push the sources directory cwd = os.getcwd() - os.chdir(SOURCES_PATH) - # Check if the named source is present. - source_file_name = source_name + ".py" - if not os.path.isfile(source_file_name): + try: + os.chdir(SOURCES_PATH) + # Check if the named source is present. + source_file_name = source_name + ".py" + if not os.path.isfile(source_file_name): + raise FileNotFoundError("Missing '{}' in '{}'".format(source_name, SOURCES_PATH)) + # Try to import the source module. + logger.debug("Loading module {}".format(source_file_name)) + spec = importlib.util.spec_from_file_location("itemsource", source_file_name) + itemsource = importlib.util.module_from_spec(spec) + spec.loader.exec_module(itemsource) + if not hasattr(itemsource, 'fetch_new'): + raise ImportError("Missing fetch_new in '{}'".format(source_file_name)) + # Since the source is valid, get or create the source cell. + return itemsource + finally: os.chdir(cwd) - raise FileNotFoundError("Missing '{}' in '{}'".format(source_name, SOURCES_PATH)) - # Try to import the source module. - logger.debug("Loading module {}".format(source_file_name)) - spec = importlib.util.spec_from_file_location("itemsource", source_file_name) - itemsource = importlib.util.module_from_spec(spec) - spec.loader.exec_module(itemsource) - if not hasattr(itemsource, 'fetch_new'): - raise ImportError("Missing fetch_new in '{}'".format(source_file_name)) - # Since the source is valid, get or create the source cell. - os.chdir(cwd) - return itemsource def update_source(source_name, fetch_new): """ @@ -169,3 +170,20 @@ def populate_old(prior, new): if 'ttd' in new: prior['ttd'] = new['ttd'] if 'tts' in new: prior['tts'] = new['tts'] if 'callback' in new: prior['callback'] = new['callback'] + +def item_callback(source_name, itemid): + try: + # Load the module with the callback function + source_module = load_source(source_name) + if not hasattr(source_module, 'callback'): + raise ImportError(f"Missing callback in '{source_name}'") + # Load the source state and the origin item + state = loader.load_state(source_name) + item = loader.WritethroughDict(os.path.join(DUNGEON_PATH, source_name, itemid + ".item")) + # Execute callback + source_module.callback(state, item) + # Save any changes + item.flush() + state.flush() + except Exception: + error.as_item(f"Error executing callback for {source_name}/{itemid}", traceback.format_exc()) diff --git a/sources/callbackdemo.py b/sources/callbackdemo.py index 93e1b2f..4fa6927 100644 --- a/sources/callbackdemo.py +++ b/sources/callbackdemo.py @@ -2,6 +2,7 @@ Demonstrates the behavior of the callback field. """ # Standard library imports +from datetime import datetime import random def fetch_new(state): @@ -16,4 +17,4 @@ def fetch_new(state): return [item] def callback(state, item): - print(item) + item['body'] = f"Last callback at {datetime.now()}"