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