370
370
"these files contain an assert statement and should not:\n%s"
371
371
% '\n'.join(badfiles))
373
def test_extension_exceptions(self):
374
"""Extension functions should propagate exceptions.
376
Either they should return an object, have an 'except' clause, or have a
377
"# cannot_raise" to indicate that we've audited them and defined them as not
380
both_exc_and_no_exc = []
382
class_re = re.compile(r'^(cdef\s+)?class (\w+).*:', re.MULTILINE)
383
except_re = re.compile(r'cdef\s*' # start with cdef
384
r'([\w *]*?)\s*' # this is the return signature
385
r'(\w+)\s*\(' # the function name
386
r'[^)]*\)\s*' # parameters
387
r'(.*)\s*:' # the except clause
388
r'\s*(#\s*cannot[- _]raise)?' # cannot raise comment
390
for fname, text in self.get_source_file_contents(
391
extensions=('.pyx',)):
392
known_classes = set([m[1] for m in class_re.findall(text)])
393
cdefs = except_re.findall(text)
394
for sig, func, exc_clause, no_exc_comment in cdefs:
395
if not sig or sig in known_classes:
397
if exc_clause and no_exc_comment:
398
both_exc_and_no_exc.append((fname, func))
399
if sig != 'object' and not (exc_clause or no_exc_comment):
400
missing_except.append((fname, func))
402
if both_exc_and_no_exc:
403
error_msg.append('The following functions had "cannot raise" comments'
404
' but did have an except clause set:')
405
for fname, func in both_exc_and_no_exc:
406
error_msg.append('%s:%s' % (fname, func))
407
error_msg.extend(('', ''))
409
error_msg.append('The following functions have fixed return types,'
410
' but no except clause.')
411
error_msg.append('Either add an except or append "# cannot_raise".')
412
for fname, func in missing_except:
413
error_msg.append('%s:%s' % (fname, func))
414
error_msg.extend(('', ''))
416
self.fail('\n'.join(error_msg))