Skip to content

Commit 98c2927

Browse files
Merge pull request #14 from UBC-DSCI/review-fixes
Review fixes
2 parents 3e45b20 + 5ecb715 commit 98c2927

File tree

7 files changed

+47
-47
lines changed

7 files changed

+47
-47
lines changed

Diff for: nbgrader/apps/quickstartapp.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ def start(self):
122122
ignore_html = shutil.ignore_patterns("*.html")
123123
shutil.copytree(example, os.path.join(course_path, "source"), ignore=ignore_html)
124124

125-
# copying the tests.yml file to the course directory
125+
# copying the autotests.yml file to the course directory
126126
tests_file_path = os.path.abspath(os.path.join(
127-
os.path.dirname(__file__), '..', 'docs', 'source', 'user_guide', 'tests.yml'))
128-
shutil.copyfile(tests_file_path, os.path.join(course_path, 'tests.yml'))
127+
os.path.dirname(__file__), '..', 'docs', 'source', 'user_guide', 'autotests.yml'))
128+
shutil.copyfile(tests_file_path, os.path.join(course_path, 'autotests.yml'))
129129

130130
# create the config file
131131
self.log.info("Generating example config file...")

Diff for: nbgrader/preprocessors/instantiatetests.py

+31-31
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class InstantiateTests(NbGraderPreprocessor):
3333
tests = None
3434

3535
autotest_filename = Unicode(
36-
"tests.yml",
36+
"autotests.yml",
3737
help="The filename where automatic testing code is stored"
3838
).tag(config=True)
3939

@@ -115,7 +115,7 @@ def preprocess(self, nb, resources):
115115
raise ValueError(f"Kernel {kernel_name} has not been specified in InstantiateTests.comment_strs")
116116
if kernel_name not in self.sanitizers:
117117
raise ValueError(f"Kernel {kernel_name} has not been specified in InstantiateTests.sanitizers")
118-
self.log.debug(f"Found kernel {kernel_name}")
118+
self.log.debug("Found kernel %s", kernel_name)
119119
resources["kernel_name"] = kernel_name
120120

121121
# load the template tests file
@@ -124,10 +124,10 @@ def preprocess(self, nb, resources):
124124
self.global_tests_loaded = True
125125

126126
# set up the sanitizer
127-
self.log.debug('Setting sanitizer for kernel {kernel_name}')
127+
self.log.debug('Setting sanitizer for kernel %s', kernel_name)
128128
self.sanitizer = self.sanitizers[kernel_name]
129129
#start the kernel
130-
self.log.debug('Starting client for kernel {kernel_name}')
130+
self.log.debug('Starting client for kernel %s', kernel_name)
131131
km, self.kc = start_new_kernel(kernel_name = kernel_name)
132132

133133
# run the preprocessor
@@ -214,7 +214,9 @@ def preprocess_cell(self, cell, resources, index):
214214
# appears in the line before the self.autotest_delimiter token
215215
use_hash = (self.hashed_delimiter in line[:line.find(self.autotest_delimiter)])
216216
if use_hash:
217-
self.log.debug('Hashing delimiter found, using template: ' + self.hash_template)
217+
if self.hash_template is None:
218+
raise ValueError('Found a hashing delimiter, but the hash property has not been set in autotests.yml')
219+
self.log.debug('Hashing delimiter found, using template: %s', self.hash_template)
218220
else:
219221
self.log.debug('Hashing delimiter not found')
220222

@@ -233,18 +235,18 @@ def preprocess_cell(self, cell, resources, index):
233235

234236
# generate the test for each snippet
235237
for snippet in snippets:
236-
self.log.debug('Running autotest generation for snippet ' + snippet)
238+
self.log.debug('Running autotest generation for snippet %s', snippet)
237239

238240
# create a random salt for this test
239241
if use_hash:
240242
salt = secrets.token_hex(8)
241-
self.log.debug('Using salt: ' + salt)
243+
self.log.debug('Using salt: %s', salt)
242244
else:
243245
salt = None
244246

245247
# get the normalized(/hashed) template tests for this code snippet
246248
self.log.debug(
247-
'Instantiating normalized' + ('/hashed ' if use_hash else ' ') + 'test templates based on type')
249+
'Instantiating normalized%s test templates based on type', ' & hashed' if use_hash else '')
248250
instantiated_tests, test_values, fail_messages = self._instantiate_tests(snippet, salt)
249251

250252
# add all the lines to the cell
@@ -253,21 +255,21 @@ def preprocess_cell(self, cell, resources, index):
253255
for i in range(len(instantiated_tests)):
254256
check_code = template.render(snippet=instantiated_tests[i], value=test_values[i],
255257
message=fail_messages[i])
256-
self.log.debug('Test: ' + check_code)
258+
self.log.debug('Test: %s', check_code)
257259
new_lines.append(check_code)
258260

259261
# add an empty line after this block of test code
260262
new_lines.append('')
261263

264+
# add the final success code and execute it
265+
if is_grade_flag and self.global_tests_loaded and (self.autotest_delimiter in cell.source) and (self.success_code is not None):
266+
new_lines.append(self.success_code)
267+
non_autotest_code_lines.append(self.success_code)
268+
262269
# run the trailing non-autotest lines, if any remain
263270
if len(non_autotest_code_lines) > 0:
264271
self._execute_code_snippet("\n".join(non_autotest_code_lines))
265272

266-
# add the final success message
267-
if is_grade_flag and self.global_tests_loaded:
268-
if self.autotest_delimiter in cell.source:
269-
new_lines.append(self.success_code)
270-
271273
# replace the cell source
272274
cell.source = "\n".join(new_lines)
273275

@@ -279,36 +281,34 @@ def preprocess_cell(self, cell, resources, index):
279281
# -------------------------------------------------------------------------------------
280282
def _load_test_template_file(self, resources):
281283
"""
282-
attempts to load the tests.yml file within the assignment directory. In case such file is not found
284+
attempts to load the autotests.yml file within the assignment directory. In case such file is not found
283285
or perhaps cannot be loaded, it will attempt to load the default_tests.yaml file with the course_directory
284286
"""
285-
self.log.debug('loading template tests.yml...')
286-
self.log.debug(f'kernel_name: {resources["kernel_name"]}')
287+
self.log.debug('loading template autotests.yml...')
288+
self.log.debug('kernel_name: %s', resources["kernel_name"])
287289
try:
288290
with open(os.path.join(resources['metadata']['path'], self.autotest_filename), 'r') as tests_file:
289291
tests = yaml.safe_load(tests_file)
290292
self.log.debug(tests)
291293

292294
except FileNotFoundError:
293-
# if there is no tests file, just load a default tests dict
295+
# if there is no tests file, try to load default tests dict
294296
self.log.warning(
295-
'No tests.yml file found in the assignment directory. Loading the default tests.yml file in the course root directory')
296-
# tests = {}
297+
'No autotests.yml file found in the assignment directory. Loading the default autotests.yml file in the course root directory')
297298
try:
298299
with open(os.path.join(self.autotest_filename), 'r') as tests_file:
299300
tests = yaml.safe_load(tests_file)
300301
except FileNotFoundError:
301-
# if there is no tests file, just create a default empty tests dict
302-
self.log.warning(
303-
'No tests.yml file found. If AUTOTESTS appears in testing cells, an error will be thrown.')
304-
tests = {}
302+
# if there is not even a default tests file, re-raise the FileNotFound error
303+
self.log.error('No autotests.yml file found, but there were autotest directives found in the notebook. ')
304+
raise
305305
except yaml.parser.ParserError as e:
306-
self.log.error('tests.yml contains invalid YAML code.')
306+
self.log.error('autotests.yml contains invalid YAML code.')
307307
self.log.error(e.msg)
308308
raise
309309

310310
except yaml.parser.ParserError as e:
311-
self.log.error('tests.yml contains invalid YAML code.')
311+
self.log.error('autotests.yml contains invalid YAML code.')
312312
self.log.error(e.msg)
313313
raise
314314

@@ -322,10 +322,10 @@ def _load_test_template_file(self, resources):
322322
self.dispatch_template = tests['dispatch']
323323

324324
# get the success message template
325-
self.success_code = tests['success']
325+
self.success_code = tests.get('success', None)
326326

327327
# get the hash code template
328-
self.hash_template = tests['hash']
328+
self.hash_template = tests.get('hash', None)
329329

330330
# get the hash code template
331331
self.check_template = tests['check']
@@ -342,19 +342,19 @@ def _instantiate_tests(self, snippet, salt=None):
342342
template = j2.Environment(loader=j2.BaseLoader).from_string(self.dispatch_template)
343343
dispatch_code = template.render(snippet=snippet)
344344
dispatch_result = self._execute_code_snippet(dispatch_code)
345-
self.log.debug('Dispatch result returned by kernel: ', dispatch_result)
345+
self.log.debug('Dispatch result returned by kernel: %s', dispatch_result)
346346
# get the test code; if the type isn't in our dict, just default to 'default'
347347
# if default isn't in the tests code, this will throw an error
348348
try:
349349
tests = self.test_templates_by_type.get(dispatch_result, self.test_templates_by_type['default'])
350350
except KeyError:
351-
self.log.error('tests.yml must contain a top-level "default" key with corresponding test code')
351+
self.log.error('autotests.yml must contain a top-level "default" key with corresponding test code')
352352
raise
353353
try:
354354
test_templs = [t['test'] for t in tests]
355355
fail_msgs = [t['fail'] for t in tests]
356356
except KeyError:
357-
self.log.error('each type in tests.yml must have a list of dictionaries with a "test" and "fail" key')
357+
self.log.error('each type in autotests.yml must have a list of dictionaries with a "test" and "fail" key')
358358
self.log.error('the "test" item should store the test template code, '
359359
'and the "fail" item should store a failure message')
360360
raise
File renamed without changes.

Diff for: nbgrader/tests/apps/test_nbgrader_autograde.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def test_grade_autotest(self, db, course_dir):
102102
run_nbgrader(["db", "student", "add", "bar", "--db", db])
103103

104104
self._copy_file(join("files", "autotest-simple.ipynb"), join(course_dir, "source", "ps1", "p1.ipynb"))
105-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
105+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
106106
run_nbgrader(["generate_assignment", "ps1", "--db", db])
107107

108108
self._copy_file(join("files", "autotest-simple-unchanged.ipynb"), join(course_dir, "submitted", "foo", "ps1", "p1.ipynb"))
@@ -132,7 +132,7 @@ def test_grade_hashed_autotest(self, db, course_dir):
132132
run_nbgrader(["db", "student", "add", "bar", "--db", db])
133133

134134
self._copy_file(join("files", "autotest-hashed.ipynb"), join(course_dir, "source", "ps1", "p1.ipynb"))
135-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
135+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
136136
run_nbgrader(["generate_assignment", "ps1", "--db", db])
137137

138138
self._copy_file(join("files", "autotest-hashed-unchanged.ipynb"), join(course_dir, "submitted", "foo", "ps1", "p1.ipynb"))
@@ -162,7 +162,7 @@ def test_grade_complex_autotest(self, db, course_dir):
162162
run_nbgrader(["db", "student", "add", "bar", "--db", db])
163163

164164
self._copy_file(join("files", "autotest-multi.ipynb"), join(course_dir, "source", "ps1", "p1.ipynb"))
165-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
165+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
166166
run_nbgrader(["generate_assignment", "ps1", "--db", db])
167167

168168
self._copy_file(join("files", "autotest-multi-unchanged.ipynb"), join(course_dir, "submitted", "foo", "ps1", "p1.ipynb"))
@@ -944,7 +944,7 @@ def test_hidden_tests_autotest(self, db, course_dir):
944944
fh.write("""c.ClearSolutions.code_stub=dict(python="# YOUR CODE HERE")""")
945945

946946
self._copy_file(join("files", "autotest-hidden.ipynb"), join(course_dir, "source", "ps1", "p1.ipynb"))
947-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
947+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
948948
run_nbgrader(["generate_assignment", "ps1", "--db", db])
949949

950950
self._copy_file(join("files", "autotest-hidden-unchanged.ipynb"), join(course_dir, "submitted", "foo", "ps1", "p1.ipynb"))

Diff for: nbgrader/tests/apps/test_nbgrader_generate_assignment.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,23 @@ def test_single_file(self, course_dir, temp_cwd):
5050
def test_autotests_simple(self, course_dir, temp_cwd):
5151
"""Can a notebook with simple autotests be generated with a default yaml location, and is autotest code removed?"""
5252
self._copy_file(join("files", "autotest-simple.ipynb"), join(course_dir, "source", "ps1", "foo.ipynb"))
53-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
53+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
5454
run_nbgrader(["db", "assignment", "add", "ps1"])
5555
run_nbgrader(["generate_assignment", "ps1"])
5656
assert os.path.isfile(join(course_dir, "release", "ps1", "foo.ipynb"))
57-
assert not os.path.isfile(join(course_dir, "release", "ps1", "tests.yml"))
57+
assert not os.path.isfile(join(course_dir, "release", "ps1", "autotests.yml"))
5858

5959
foo = self._file_contents(join(course_dir, "release", "ps1", "foo.ipynb"))
6060
assert "AUTOTEST" not in foo
6161

6262
def test_autotests_simple(self, course_dir, temp_cwd):
6363
"""Can a notebook with simple autotests be generated with an assignment-specific yaml, and is autotest code removed?"""
6464
self._copy_file(join("files", "autotest-simple.ipynb"), join(course_dir, "source", "ps1", "foo.ipynb"))
65-
self._copy_file(join("files", "tests.yml"), join(course_dir, "source", "ps1", "tests.yml"))
65+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "source", "ps1", "autotests.yml"))
6666
run_nbgrader(["db", "assignment", "add", "ps1"])
6767
run_nbgrader(["generate_assignment", "ps1"])
6868
assert os.path.isfile(join(course_dir, "release", "ps1", "foo.ipynb"))
69-
assert os.path.isfile(join(course_dir, "release", "ps1", "tests.yml"))
69+
assert os.path.isfile(join(course_dir, "release", "ps1", "autotests.yml"))
7070

7171
foo = self._file_contents(join(course_dir, "release", "ps1", "foo.ipynb"))
7272
assert "AUTOTEST" not in foo
@@ -81,7 +81,7 @@ def test_autotests_needs_yaml(self, course_dir, temp_cwd):
8181
def test_autotests_fancy(self, course_dir, temp_cwd):
8282
"""Can a more complicated autotests notebook be generated, and is autotest code removed?"""
8383
self._copy_file(join("files", "autotest-multi.ipynb"), join(course_dir, "source", "ps1", "foo.ipynb"))
84-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
84+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
8585
run_nbgrader(["db", "assignment", "add", "ps1"])
8686
run_nbgrader(["generate_assignment", "ps1"])
8787
assert os.path.isfile(join(course_dir, "release", "ps1", "foo.ipynb"))
@@ -92,7 +92,7 @@ def test_autotests_fancy(self, course_dir, temp_cwd):
9292
def test_autotests_hidden(self, course_dir, temp_cwd):
9393
"""Can a notebook with hidden autotest be generated, and is autotest/hidden sections removed?"""
9494
self._copy_file(join("files", "autotest-hidden.ipynb"), join(course_dir, "source", "ps1", "foo.ipynb"))
95-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
95+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
9696
run_nbgrader(["db", "assignment", "add", "ps1"])
9797
run_nbgrader(["generate_assignment", "ps1"])
9898
assert os.path.isfile(join(course_dir, "release", "ps1", "foo.ipynb"))
@@ -104,7 +104,7 @@ def test_autotests_hidden(self, course_dir, temp_cwd):
104104
def test_autotests_hashed(self, course_dir, temp_cwd):
105105
"""Can a notebook with hashed autotests be generated, and is hashed autotest code removed?"""
106106
self._copy_file(join("files", "autotest-hashed.ipynb"), join(course_dir, "source", "ps1", "foo.ipynb"))
107-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
107+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
108108
run_nbgrader(["db", "assignment", "add", "ps1"])
109109
run_nbgrader(["generate_assignment", "ps1"])
110110
assert os.path.isfile(join(course_dir, "release", "ps1", "foo.ipynb"))
@@ -117,7 +117,7 @@ def test_generate_source_with_tests_flag(self, course_dir, temp_cwd):
117117
"""Does setting the flag --source_with_tests also create a notebook with solution and tests in the
118118
source_with_tests directory"""
119119
self._copy_file(join("files", "autotest-simple.ipynb"), join(course_dir, "source", "ps1", "foo.ipynb"))
120-
self._copy_file(join("files", "tests.yml"), join(course_dir, "source", "ps1", "tests.yml"))
120+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "source", "ps1", "autotests.yml"))
121121
run_nbgrader(["db", "assignment", "add", "ps1"])
122122
run_nbgrader(["generate_assignment", "ps1", "--source_with_tests"])
123123
assert os.path.isfile(join(course_dir, "release", "ps1", "foo.ipynb"))

Diff for: nbgrader/tests/apps/test_nbgrader_generate_feedback.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ def test_autotests(self, course_dir):
333333

334334
self._copy_file(join("files", "autotest-simple.ipynb"), join(course_dir, "source", "ps1", "p1.ipynb"))
335335
self._copy_file(join("files", "autotest-simple.ipynb"), join(course_dir, "source", "ps1", "p2.ipynb"))
336-
self._copy_file(join("files", "tests.yml"), join(course_dir, "tests.yml"))
336+
self._copy_file(join("files", "autotests.yml"), join(course_dir, "autotests.yml"))
337337
run_nbgrader(["generate_assignment", "ps1"])
338338

339339
self._copy_file(join("files", "autotest-simple.ipynb"), join(course_dir, "submitted", "foo", "ps1", "p1.ipynb"))

0 commit comments

Comments
 (0)