Commit a08b82c950e6fccd4cf46d01f87c9001afde6b54
1 parent
0b1ced64
Exists in
master
and in
1 other branch
- changed how paths are handled so that the ~ is expanded to $HOME only when man…
…ipulating files, and not saving expanded paths (to avoid /User vs /home conflicts between OSX and Linux).
Showing
7 changed files
with
32 additions
and
20 deletions
Show diff stats
BUGS.md
... | ... | @@ -27,6 +27,7 @@ |
27 | 27 | |
28 | 28 | # FIXED |
29 | 29 | |
30 | +- Quando grava JSON do teste deve usar 'path' tal como definido na configuração e não expandido. Isto porque em OSX /home é /Users e quando se muda de um sistema para outro não encontra os testes. Assim, usando ~ na configuração deveria funcionar sempre. | |
30 | 31 | - configuração do teste não joga bem com o do aprendizations. Em particular os scripts não ficam com o mesmo path!!! |
31 | 32 | - configurar pf em freebsd, port forward 80 -> 8080. documentacao |
32 | 33 | - barras com notas em grade estão desalinhadas. | ... | ... |
app.py
... | ... | @@ -34,7 +34,8 @@ class App(object): |
34 | 34 | self.testfactory = test.TestFactory(filename, conf=conf) |
35 | 35 | |
36 | 36 | # connect to database and check registered students |
37 | - engine = create_engine('sqlite:///{}'.format(self.testfactory['database']), echo=False) | |
37 | + dbfile = path.expanduser(self.testfactory['database']) | |
38 | + engine = create_engine('sqlite:///{}'.format(dbfile), echo=False) | |
38 | 39 | self.Session = scoped_session(sessionmaker(bind=engine)) |
39 | 40 | |
40 | 41 | try: |
... | ... | @@ -133,7 +134,7 @@ class App(object): |
133 | 134 | |
134 | 135 | # save test in JSON format |
135 | 136 | fname = ' -- '.join((t['student']['number'], t['ref'], str(t['finish_time']))) + '.json' |
136 | - fpath = path.abspath(path.join(t['answers_dir'], fname)) | |
137 | + fpath = path.join(t['answers_dir'], fname) | |
137 | 138 | t.save_json(fpath) |
138 | 139 | |
139 | 140 | # insert test and questions into database | ... | ... |
questions.py
... | ... | @@ -447,7 +447,7 @@ class QuestionTextArea(Question): |
447 | 447 | 'correct': '' # trying to execute this will fail => grade 0.0 |
448 | 448 | }) |
449 | 449 | |
450 | - self['correct'] = path.abspath(path.normpath(path.join(self['path'], self['correct']))) | |
450 | + self['correct'] = path.join(self['path'], self['correct']) | |
451 | 451 | |
452 | 452 | #------------------------------------------------------------------------ |
453 | 453 | # can return negative values for wrong answers | ... | ... |
serve.py
... | ... | @@ -281,12 +281,19 @@ class Root(object): |
281 | 281 | @require(name_is('0')) |
282 | 282 | def review(self, test_id): |
283 | 283 | fname = self.app.get_json_filename_of_test(test_id) |
284 | - with open(fname) as f: | |
285 | - t = json.load(f) | |
286 | - r = self.template['review'].render(t=t) | |
287 | - # import pdfkit | |
288 | - # pdfkit.from_string(r, 'out.pdf') # FIXME fails getting css, images, etc | |
289 | - return r | |
284 | + try: | |
285 | + f = open(path.expanduser(fname)) | |
286 | + except FileNotFoundError: | |
287 | + logging.error('Cannot find "{}" for review.'.format(fname)) | |
288 | + except Exception as e: | |
289 | + raise e | |
290 | + else: | |
291 | + with f: | |
292 | + t = json.load(f) | |
293 | + return self.template['review'].render(t=t) | |
294 | + # FIXME | |
295 | + # import pdfkit | |
296 | + # pdfkit.from_string(r, 'out.pdf') # FIXME fails getting css, images, etc | |
290 | 297 | |
291 | 298 | @cherrypy.expose |
292 | 299 | @require(name_is('0')) | ... | ... |
templates/review.html
... | ... | @@ -226,7 +226,7 @@ |
226 | 226 | |
227 | 227 | % if t['show_points']: |
228 | 228 | <p class="text-right"> |
229 | - <small>(Cotação: ${round(q['points'] / total_points * 20.0, 1)} pontos)</small> | |
229 | + <small>(Cotação: ${round(q['points'] / total_points * 20.0, 2)} pontos)</small> | |
230 | 230 | <p> |
231 | 231 | % endif |
232 | 232 | ... | ... |
test.py
... | ... | @@ -74,7 +74,7 @@ class TestFactory(dict): |
74 | 74 | if 'ref' not in self: |
75 | 75 | logger.warning('Missing "ref". Will use current date/time.') |
76 | 76 | if 'answers_dir' not in self: |
77 | - logger.warning('Missing "answers_dir". Will use current directory!') | |
77 | + logger.warning('Missing "answers_dir". Will save to current directory {}'.format(path.abspath(path.curdir))) | |
78 | 78 | if 'questions_dir' not in self: |
79 | 79 | logger.warning('Missing "questions_dir". Using {}'.format(path.abspath(path.curdir))) |
80 | 80 | if 'files' not in self: |
... | ... | @@ -89,15 +89,15 @@ class TestFactory(dict): |
89 | 89 | self.setdefault('show_ref', False) |
90 | 90 | self.setdefault('questions_dir', path.curdir) |
91 | 91 | self.setdefault('answers_dir', path.curdir) |
92 | - self['database'] = path.abspath(path.expanduser(self['database'])) | |
93 | - self['questions_dir'] = path.abspath(path.expanduser(self['questions_dir'])) | |
94 | - self['answers_dir'] = path.abspath(path.expanduser(self['answers_dir'])) | |
92 | + # self['database'] = path.abspath(path.expanduser(self['database'])) | |
93 | + # self['questions_dir'] = path.abspath(path.expanduser(self['questions_dir'])) | |
94 | + # self['answers_dir'] = path.abspath(path.expanduser(self['answers_dir'])) | |
95 | 95 | |
96 | - if not path.isfile(self['database']): | |
96 | + if not path.isfile(path.expanduser(self['database'])): | |
97 | 97 | logger.critical('Can\'t find database "{}"'.format(self['database'])) |
98 | 98 | raise TestFactoryException() |
99 | 99 | |
100 | - if not path.isdir(self['questions_dir']): | |
100 | + if not path.isdir(path.expanduser(self['questions_dir'])): | |
101 | 101 | logger.critical('Can\'t find questions directory "{}"'.format(self['questions_dir'])) |
102 | 102 | raise TestFactoryException() |
103 | 103 | |
... | ... | @@ -117,7 +117,7 @@ class TestFactory(dict): |
117 | 117 | |
118 | 118 | |
119 | 119 | try: |
120 | - f = open(path.join(self['answers_dir'],'REMOVE-ME'), 'w') | |
120 | + f = open(path.join(path.expanduser(self['answers_dir']),'REMOVE-ME'), 'w') | |
121 | 121 | except EnvironmentError: |
122 | 122 | logger.critical('Cannot write answers to "{0}".'.format(self['answers_dir'])) |
123 | 123 | raise TestFactoryException() |
... | ... | @@ -175,7 +175,7 @@ class TestFactory(dict): |
175 | 175 | 'show_hints': self['show_hints'], |
176 | 176 | 'show_points': self['show_points'], |
177 | 177 | 'show_ref': self['show_ref'], |
178 | - 'debug': self['debug'], | |
178 | + 'debug': self['debug'], # required by template test.html | |
179 | 179 | 'database': self['database'], |
180 | 180 | 'questions_dir': self['questions_dir'], |
181 | 181 | 'files': self['files'], |
... | ... | @@ -249,7 +249,7 @@ class Test(dict): |
249 | 249 | |
250 | 250 | # ----------------------------------------------------------------------- |
251 | 251 | def save_json(self, filepath): |
252 | - with open(filepath, 'w') as f: | |
252 | + with open(path.expanduser(filepath), 'w') as f: | |
253 | 253 | json.dump(self, f, indent=2, default=str) |
254 | 254 | # HACK default=str is required for datetime objects |
255 | 255 | logger.info('Student {}: saved JSON file.'.format(self['student']['number'])) | ... | ... |
tools.py
1 | 1 | |
2 | +from os import path | |
2 | 3 | import subprocess |
3 | 4 | import logging |
5 | + | |
4 | 6 | import yaml |
5 | 7 | import markdown |
6 | 8 | |
... | ... | @@ -12,7 +14,7 @@ logger = logging.getLogger(__name__) |
12 | 14 | # --------------------------------------------------------------------------- |
13 | 15 | def load_yaml(filename, default=None): |
14 | 16 | try: |
15 | - f = open(filename, 'r', encoding='utf-8') | |
17 | + f = open(path.expanduser(filename), 'r', encoding='utf-8') | |
16 | 18 | except IOError: |
17 | 19 | logger.error('Can\'t open file "{}"'.format(filename)) |
18 | 20 | return default |
... | ... | @@ -30,6 +32,7 @@ def load_yaml(filename, default=None): |
30 | 32 | # Note: requires python 3.5+ |
31 | 33 | # --------------------------------------------------------------------------- |
32 | 34 | def run_script(script, stdin='', timeout=5): |
35 | + script = path.expanduser(script) | |
33 | 36 | try: |
34 | 37 | p = subprocess.run([script], |
35 | 38 | input=stdin, | ... | ... |