Commit 5f7d3068059e65ca987be48575dae7ed02db8395
1 parent
84a1054c
Exists in
master
and in
1 other branch
- Initial support for dependency graphs.
Showing
4 changed files
with
46 additions
and
5 deletions
Show diff stats
README.md
... | ... | @@ -27,7 +27,7 @@ In the end you should be able to run `pip3 --version` and `python3 -c "import sq |
27 | 27 | |
28 | 28 | Install additional python packages locally on the user area: |
29 | 29 | |
30 | - pip install --user tornado sqlalchemy pyyaml pygments markdown bcrypt | |
30 | + pip install --user tornado sqlalchemy pyyaml pygments markdown bcrypt networkx | |
31 | 31 | |
32 | 32 | These are usually installed under |
33 | 33 | ... | ... |
app.py
... | ... | @@ -8,6 +8,8 @@ try: |
8 | 8 | import bcrypt |
9 | 9 | from sqlalchemy import create_engine |
10 | 10 | from sqlalchemy.orm import sessionmaker |
11 | + import networkx as nx | |
12 | + import yaml | |
11 | 13 | except ImportError: |
12 | 14 | logger.critical('Python package missing. See README.md for instructions.') |
13 | 15 | sys.exit(1) |
... | ... | @@ -24,10 +26,17 @@ logger = logging.getLogger(__name__) |
24 | 26 | # ============================================================================ |
25 | 27 | class LearnApp(object): |
26 | 28 | def __init__(self): |
29 | + # online students | |
27 | 30 | self.online = {} |
28 | 31 | |
29 | 32 | # connect to database and check registered students |
30 | - db = 'students.db' # FIXME | |
33 | + self.setup_db('students.db') # FIXME | |
34 | + | |
35 | + # build dependency graph | |
36 | + self.build_dependency_graph({'uevora/lei'}) # FIXME | |
37 | + | |
38 | + # ------------------------------------------------------------------------ | |
39 | + def setup_db(self, db): | |
31 | 40 | engine = create_engine(f'sqlite:///{db}', echo=False) |
32 | 41 | self.Session = sessionmaker(bind=engine) |
33 | 42 | try: |
... | ... | @@ -59,7 +68,6 @@ class LearnApp(object): |
59 | 68 | 'number': student.id, |
60 | 69 | 'knowledge': Knowledge(), # FIXME initial state? |
61 | 70 | } |
62 | - # print(self.online) | |
63 | 71 | return True |
64 | 72 | |
65 | 73 | # ------------------------------------------------------------------------ |
... | ... | @@ -103,3 +111,37 @@ class LearnApp(object): |
103 | 111 | raise |
104 | 112 | finally: |
105 | 113 | session.close() |
114 | + | |
115 | + # ------------------------------------------------------------------------ | |
116 | + # Receives a set of topics (strings like "math/algebra"), | |
117 | + # and recursively adds dependencies to the dependency graph | |
118 | + def build_dependency_graph(self, topics=set()): | |
119 | + g = nx.DiGraph() | |
120 | + | |
121 | + # add nodes "recursively" following the config.yaml files | |
122 | + while topics: | |
123 | + t = topics.pop() # take one topic | |
124 | + if t in g.nodes(): # skip it if already in the graph | |
125 | + continue | |
126 | + | |
127 | + # get configuration dictionary for this topic | |
128 | + # dictionary has keys: type, title, depends | |
129 | + try: | |
130 | + with open(f'topics/{t}/config.yaml', 'r') as f: | |
131 | + logger.info(f'Loading {t}') | |
132 | + config = yaml.load(f) | |
133 | + except FileNotFoundError: | |
134 | + logger.error(f'Not found: topics/{t}/config.yaml') | |
135 | + continue | |
136 | + | |
137 | + config.setdefault('depends', set()) # make sure 'depends' key exists | |
138 | + topics.update(config['depends']) | |
139 | + g.add_node(t, config=config) | |
140 | + | |
141 | + # add edges topic -> dependency | |
142 | + for t in g.nodes(): | |
143 | + deps = g.node[t]['config']['depends'] | |
144 | + g.add_edges_from([(t, d) for d in deps]) | |
145 | + | |
146 | + self.depgraph = g | |
147 | + logger.info(f'Graph has {g.number_of_nodes()} nodes and {g.number_of_edges()} edges') | ... | ... |
config/logger.yaml
serve.py
... | ... | @@ -82,7 +82,6 @@ class LoginHandler(BaseHandler): |
82 | 82 | def post(self): |
83 | 83 | uid = self.get_body_argument('uid') |
84 | 84 | pw = self.get_body_argument('pw') |
85 | - # print(f'login.post: user={uid}, pw={pw}') | |
86 | 85 | |
87 | 86 | if self.learn.login(uid, pw): |
88 | 87 | logging.info(f'User "{uid}" login ok.') | ... | ... |