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, |