44
41
# Files which are listed here will be skipped when testing for Copyright (or
46
COPYRIGHT_EXCEPTIONS = ['bzrlib/lsprof.py']
43
COPYRIGHT_EXCEPTIONS = ['bzrlib/lsprof.py', 'bzrlib/_bencode_py.py',
44
'bzrlib/doc_generate/sphinx_conf.py']
48
LICENSE_EXCEPTIONS = ['bzrlib/lsprof.py']
46
LICENSE_EXCEPTIONS = ['bzrlib/lsprof.py', 'bzrlib/_bencode_py.py',
47
'bzrlib/doc_generate/sphinx_conf.py']
49
48
# Technically, 'bzrlib/lsprof.py' should be 'bzrlib/util/lsprof.py',
50
49
# (we do not check bzrlib/util/, since that is code bundled from elsewhere)
51
50
# but for compatibility with previous releases, we don't want to move it.
52
# sphinx_conf is semi-autogenerated.
54
55
class TestSourceHelper(TestCase):
284
285
def test_coding_style(self):
285
286
"""Check if bazaar code conforms to some coding style conventions.
287
Currently we check for:
288
Currently we assert that the following is not present:
288
289
* any tab characters
289
* trailing white space
290
290
* non-unix newlines
291
291
* no newline at end of files
293
Print how many files have
294
* trailing white space
292
295
* lines longer than 79 chars
293
(only print how many files and lines are in violation)
321
323
'Tab characters were found in the following source files.'
322
324
'\nThey should either be replaced by "\\t" or by spaces:'))
324
problems.append(self._format_message(trailing_ws,
325
'Trailing white space was found in the following source files:'
326
print ("There are %i lines with trailing white space in %i files."
327
% (sum([len(lines) for f, lines in trailing_ws.items()]),
327
329
if illegal_newlines:
328
330
problems.append(self._format_message(illegal_newlines,
329
331
'Non-unix newlines were found in the following source files:'))
362
assert_re = re.compile(r'\bassert\b')
361
363
for fname, text in self.get_source_file_contents():
362
364
if not self.is_our_code(fname):
364
ast = parser.ast2tuple(parser.suite(''.join(text)))
366
if not assert_re.search(text):
368
ast = parser.ast2tuple(parser.suite(text))
366
370
badfiles.append(fname)
369
373
"these files contain an assert statement and should not:\n%s"
370
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+)?(public\s+)?(api\s+)?class (\w+).*:',
387
except_re = re.compile(r'cdef\s+' # start with cdef
388
r'([\w *]*?)\s*' # this is the return signature
389
r'(\w+)\s*\(' # the function name
390
r'[^)]*\)\s*' # parameters
391
r'(.*)\s*:' # the except clause
392
r'\s*(#\s*cannot[- _]raise)?' # cannot raise comment
394
for fname, text in self.get_source_file_contents(
395
extensions=('.pyx',)):
396
known_classes = set([m[-1] for m in class_re.findall(text)])
397
cdefs = except_re.findall(text)
398
for sig, func, exc_clause, no_exc_comment in cdefs:
399
if sig.startswith('api '):
401
if not sig or sig in known_classes:
403
if 'nogil' in exc_clause:
404
exc_clause = exc_clause.replace('nogil', '').strip()
405
if exc_clause and no_exc_comment:
406
both_exc_and_no_exc.append((fname, func))
407
if sig != 'object' and not (exc_clause or no_exc_comment):
408
missing_except.append((fname, func))
410
if both_exc_and_no_exc:
411
error_msg.append('The following functions had "cannot raise" comments'
412
' but did have an except clause set:')
413
for fname, func in both_exc_and_no_exc:
414
error_msg.append('%s:%s' % (fname, func))
415
error_msg.extend(('', ''))
417
error_msg.append('The following functions have fixed return types,'
418
' but no except clause.')
419
error_msg.append('Either add an except or append "# cannot_raise".')
420
for fname, func in missing_except:
421
error_msg.append('%s:%s' % (fname, func))
422
error_msg.extend(('', ''))
424
self.fail('\n'.join(error_msg))