diff --git a/README.md b/README.md index a733b3b..4dad047 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ In the end you should be able to run `pip3 --version` and `python3 -c "import sq Install additional python packages locally on the user area: - pip install --user tornado sqlalchemy pyyaml pygments markdown bcrypt + pip install --user tornado sqlalchemy pyyaml pygments markdown bcrypt networkx These are usually installed under diff --git a/app.py b/app.py index 698875a..bfaff8d 100644 --- a/app.py +++ b/app.py @@ -8,6 +8,8 @@ try: import bcrypt from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker + import networkx as nx + import yaml except ImportError: logger.critical('Python package missing. See README.md for instructions.') sys.exit(1) @@ -24,10 +26,17 @@ logger = logging.getLogger(__name__) # ============================================================================ class LearnApp(object): def __init__(self): + # online students self.online = {} # connect to database and check registered students - db = 'students.db' # FIXME + self.setup_db('students.db') # FIXME + + # build dependency graph + self.build_dependency_graph({'uevora/lei'}) # FIXME + + # ------------------------------------------------------------------------ + def setup_db(self, db): engine = create_engine(f'sqlite:///{db}', echo=False) self.Session = sessionmaker(bind=engine) try: @@ -59,7 +68,6 @@ class LearnApp(object): 'number': student.id, 'knowledge': Knowledge(), # FIXME initial state? } - # print(self.online) return True # ------------------------------------------------------------------------ @@ -103,3 +111,37 @@ class LearnApp(object): raise finally: session.close() + + # ------------------------------------------------------------------------ + # Receives a set of topics (strings like "math/algebra"), + # and recursively adds dependencies to the dependency graph + def build_dependency_graph(self, topics=set()): + g = nx.DiGraph() + + # add nodes "recursively" following the config.yaml files + while topics: + t = topics.pop() # take one topic + if t in g.nodes(): # skip it if already in the graph + continue + + # get configuration dictionary for this topic + # dictionary has keys: type, title, depends + try: + with open(f'topics/{t}/config.yaml', 'r') as f: + logger.info(f'Loading {t}') + config = yaml.load(f) + except FileNotFoundError: + logger.error(f'Not found: topics/{t}/config.yaml') + continue + + config.setdefault('depends', set()) # make sure 'depends' key exists + topics.update(config['depends']) + g.add_node(t, config=config) + + # add edges topic -> dependency + for t in g.nodes(): + deps = g.node[t]['config']['depends'] + g.add_edges_from([(t, d) for d in deps]) + + self.depgraph = g + logger.info(f'Graph has {g.number_of_nodes()} nodes and {g.number_of_edges()} edges') diff --git a/config/logger.yaml b/config/logger.yaml index cb24382..445082a 100644 --- a/config/logger.yaml +++ b/config/logger.yaml @@ -5,7 +5,7 @@ formatters: void: format: '' standard: - format: '%(asctime)s | %(levelname)-8s | %(name)-14s | %(message)s' + format: '%(asctime)s | %(levelname)-8s | %(name)-8s | %(message)s' handlers: default: diff --git a/serve.py b/serve.py index f8d691b..caf1bcd 100755 --- a/serve.py +++ b/serve.py @@ -82,7 +82,6 @@ class LoginHandler(BaseHandler): def post(self): uid = self.get_body_argument('uid') pw = self.get_body_argument('pw') - # print(f'login.post: user={uid}, pw={pw}') if self.learn.login(uid, pw): logging.info(f'User "{uid}" login ok.') -- libgit2 0.21.2