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,6 +27,7 @@ | ||
27 | 27 | ||
28 | # FIXED | 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 | - configuração do teste não joga bem com o do aprendizations. Em particular os scripts não ficam com o mesmo path!!! | 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 | - configurar pf em freebsd, port forward 80 -> 8080. documentacao | 32 | - configurar pf em freebsd, port forward 80 -> 8080. documentacao |
32 | - barras com notas em grade estão desalinhadas. | 33 | - barras com notas em grade estão desalinhadas. |
app.py
@@ -34,7 +34,8 @@ class App(object): | @@ -34,7 +34,8 @@ class App(object): | ||
34 | self.testfactory = test.TestFactory(filename, conf=conf) | 34 | self.testfactory = test.TestFactory(filename, conf=conf) |
35 | 35 | ||
36 | # connect to database and check registered students | 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 | self.Session = scoped_session(sessionmaker(bind=engine)) | 39 | self.Session = scoped_session(sessionmaker(bind=engine)) |
39 | 40 | ||
40 | try: | 41 | try: |
@@ -133,7 +134,7 @@ class App(object): | @@ -133,7 +134,7 @@ class App(object): | ||
133 | 134 | ||
134 | # save test in JSON format | 135 | # save test in JSON format |
135 | fname = ' -- '.join((t['student']['number'], t['ref'], str(t['finish_time']))) + '.json' | 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 | t.save_json(fpath) | 138 | t.save_json(fpath) |
138 | 139 | ||
139 | # insert test and questions into database | 140 | # insert test and questions into database |
questions.py
@@ -447,7 +447,7 @@ class QuestionTextArea(Question): | @@ -447,7 +447,7 @@ class QuestionTextArea(Question): | ||
447 | 'correct': '' # trying to execute this will fail => grade 0.0 | 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 | # can return negative values for wrong answers | 453 | # can return negative values for wrong answers |
serve.py
@@ -281,12 +281,19 @@ class Root(object): | @@ -281,12 +281,19 @@ class Root(object): | ||
281 | @require(name_is('0')) | 281 | @require(name_is('0')) |
282 | def review(self, test_id): | 282 | def review(self, test_id): |
283 | fname = self.app.get_json_filename_of_test(test_id) | 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 | @cherrypy.expose | 298 | @cherrypy.expose |
292 | @require(name_is('0')) | 299 | @require(name_is('0')) |
templates/review.html
@@ -226,7 +226,7 @@ | @@ -226,7 +226,7 @@ | ||
226 | 226 | ||
227 | % if t['show_points']: | 227 | % if t['show_points']: |
228 | <p class="text-right"> | 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 | <p> | 230 | <p> |
231 | % endif | 231 | % endif |
232 | 232 |
test.py
@@ -74,7 +74,7 @@ class TestFactory(dict): | @@ -74,7 +74,7 @@ class TestFactory(dict): | ||
74 | if 'ref' not in self: | 74 | if 'ref' not in self: |
75 | logger.warning('Missing "ref". Will use current date/time.') | 75 | logger.warning('Missing "ref". Will use current date/time.') |
76 | if 'answers_dir' not in self: | 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 | if 'questions_dir' not in self: | 78 | if 'questions_dir' not in self: |
79 | logger.warning('Missing "questions_dir". Using {}'.format(path.abspath(path.curdir))) | 79 | logger.warning('Missing "questions_dir". Using {}'.format(path.abspath(path.curdir))) |
80 | if 'files' not in self: | 80 | if 'files' not in self: |
@@ -89,15 +89,15 @@ class TestFactory(dict): | @@ -89,15 +89,15 @@ class TestFactory(dict): | ||
89 | self.setdefault('show_ref', False) | 89 | self.setdefault('show_ref', False) |
90 | self.setdefault('questions_dir', path.curdir) | 90 | self.setdefault('questions_dir', path.curdir) |
91 | self.setdefault('answers_dir', path.curdir) | 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 | logger.critical('Can\'t find database "{}"'.format(self['database'])) | 97 | logger.critical('Can\'t find database "{}"'.format(self['database'])) |
98 | raise TestFactoryException() | 98 | raise TestFactoryException() |
99 | 99 | ||
100 | - if not path.isdir(self['questions_dir']): | 100 | + if not path.isdir(path.expanduser(self['questions_dir'])): |
101 | logger.critical('Can\'t find questions directory "{}"'.format(self['questions_dir'])) | 101 | logger.critical('Can\'t find questions directory "{}"'.format(self['questions_dir'])) |
102 | raise TestFactoryException() | 102 | raise TestFactoryException() |
103 | 103 | ||
@@ -117,7 +117,7 @@ class TestFactory(dict): | @@ -117,7 +117,7 @@ class TestFactory(dict): | ||
117 | 117 | ||
118 | 118 | ||
119 | try: | 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 | except EnvironmentError: | 121 | except EnvironmentError: |
122 | logger.critical('Cannot write answers to "{0}".'.format(self['answers_dir'])) | 122 | logger.critical('Cannot write answers to "{0}".'.format(self['answers_dir'])) |
123 | raise TestFactoryException() | 123 | raise TestFactoryException() |
@@ -175,7 +175,7 @@ class TestFactory(dict): | @@ -175,7 +175,7 @@ class TestFactory(dict): | ||
175 | 'show_hints': self['show_hints'], | 175 | 'show_hints': self['show_hints'], |
176 | 'show_points': self['show_points'], | 176 | 'show_points': self['show_points'], |
177 | 'show_ref': self['show_ref'], | 177 | 'show_ref': self['show_ref'], |
178 | - 'debug': self['debug'], | 178 | + 'debug': self['debug'], # required by template test.html |
179 | 'database': self['database'], | 179 | 'database': self['database'], |
180 | 'questions_dir': self['questions_dir'], | 180 | 'questions_dir': self['questions_dir'], |
181 | 'files': self['files'], | 181 | 'files': self['files'], |
@@ -249,7 +249,7 @@ class Test(dict): | @@ -249,7 +249,7 @@ class Test(dict): | ||
249 | 249 | ||
250 | # ----------------------------------------------------------------------- | 250 | # ----------------------------------------------------------------------- |
251 | def save_json(self, filepath): | 251 | def save_json(self, filepath): |
252 | - with open(filepath, 'w') as f: | 252 | + with open(path.expanduser(filepath), 'w') as f: |
253 | json.dump(self, f, indent=2, default=str) | 253 | json.dump(self, f, indent=2, default=str) |
254 | # HACK default=str is required for datetime objects | 254 | # HACK default=str is required for datetime objects |
255 | logger.info('Student {}: saved JSON file.'.format(self['student']['number'])) | 255 | logger.info('Student {}: saved JSON file.'.format(self['student']['number'])) |
tools.py
1 | 1 | ||
2 | +from os import path | ||
2 | import subprocess | 3 | import subprocess |
3 | import logging | 4 | import logging |
5 | + | ||
4 | import yaml | 6 | import yaml |
5 | import markdown | 7 | import markdown |
6 | 8 | ||
@@ -12,7 +14,7 @@ logger = logging.getLogger(__name__) | @@ -12,7 +14,7 @@ logger = logging.getLogger(__name__) | ||
12 | # --------------------------------------------------------------------------- | 14 | # --------------------------------------------------------------------------- |
13 | def load_yaml(filename, default=None): | 15 | def load_yaml(filename, default=None): |
14 | try: | 16 | try: |
15 | - f = open(filename, 'r', encoding='utf-8') | 17 | + f = open(path.expanduser(filename), 'r', encoding='utf-8') |
16 | except IOError: | 18 | except IOError: |
17 | logger.error('Can\'t open file "{}"'.format(filename)) | 19 | logger.error('Can\'t open file "{}"'.format(filename)) |
18 | return default | 20 | return default |
@@ -30,6 +32,7 @@ def load_yaml(filename, default=None): | @@ -30,6 +32,7 @@ def load_yaml(filename, default=None): | ||
30 | # Note: requires python 3.5+ | 32 | # Note: requires python 3.5+ |
31 | # --------------------------------------------------------------------------- | 33 | # --------------------------------------------------------------------------- |
32 | def run_script(script, stdin='', timeout=5): | 34 | def run_script(script, stdin='', timeout=5): |
35 | + script = path.expanduser(script) | ||
33 | try: | 36 | try: |
34 | p = subprocess.run([script], | 37 | p = subprocess.run([script], |
35 | input=stdin, | 38 | input=stdin, |