44
41
# Files which are listed here will be skipped when testing for Copyright (or
46
COPYRIGHT_EXCEPTIONS = ['bzrlib/lsprof.py']
43
COPYRIGHT_EXCEPTIONS = [
44
'bzrlib/_bencode_py.py',
45
'bzrlib/doc_generate/conf.py',
48
LICENSE_EXCEPTIONS = ['bzrlib/lsprof.py']
49
LICENSE_EXCEPTIONS = [
50
'bzrlib/_bencode_py.py',
51
'bzrlib/doc_generate/conf.py',
49
54
# Technically, 'bzrlib/lsprof.py' should be 'bzrlib/util/lsprof.py',
50
55
# (we do not check bzrlib/util/, since that is code bundled from elsewhere)
51
56
# but for compatibility with previous releases, we don't want to move it.
58
# sphinx_conf is semi-autogenerated.
54
61
class TestSourceHelper(TestCase):
284
291
def test_coding_style(self):
285
292
"""Check if bazaar code conforms to some coding style conventions.
287
Currently we check for:
294
Currently we assert that the following is not present:
288
295
* any tab characters
289
* trailing white space
290
296
* non-unix newlines
291
297
* no newline at end of files
299
Print how many files have
300
* trailing white space
292
301
* lines longer than 79 chars
293
(only print how many files and lines are in violation)
321
329
'Tab characters were found in the following source files.'
322
330
'\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:'
332
print ("There are %i lines with trailing white space in %i files."
333
% (sum([len(lines) for f, lines in trailing_ws.items()]),
327
335
if illegal_newlines:
328
336
problems.append(self._format_message(illegal_newlines,
329
337
'Non-unix newlines were found in the following source files:'))
368
assert_re = re.compile(r'\bassert\b')
361
369
for fname, text in self.get_source_file_contents():
362
370
if not self.is_our_code(fname):
364
ast = parser.ast2tuple(parser.suite(''.join(text)))
372
if not assert_re.search(text):
374
ast = parser.ast2tuple(parser.suite(text))
366
376
badfiles.append(fname)
369
379
"these files contain an assert statement and should not:\n%s"
370
380
% '\n'.join(badfiles))
382
def test_extension_exceptions(self):
383
"""Extension functions should propagate exceptions.
385
Either they should return an object, have an 'except' clause, or have a
386
"# cannot_raise" to indicate that we've audited them and defined them as not
389
both_exc_and_no_exc = []
391
class_re = re.compile(r'^(cdef\s+)?(public\s+)?(api\s+)?class (\w+).*:',
393
except_re = re.compile(r'cdef\s+' # start with cdef
394
r'([\w *]*?)\s*' # this is the return signature
395
r'(\w+)\s*\(' # the function name
396
r'[^)]*\)\s*' # parameters
397
r'(.*)\s*:' # the except clause
398
r'\s*(#\s*cannot[- _]raise)?' # cannot raise comment
400
for fname, text in self.get_source_file_contents(
401
extensions=('.pyx',)):
402
known_classes = set([m[-1] for m in class_re.findall(text)])
403
cdefs = except_re.findall(text)
404
for sig, func, exc_clause, no_exc_comment in cdefs:
405
if sig.startswith('api '):
407
if not sig or sig in known_classes:
409
if 'nogil' in exc_clause:
410
exc_clause = exc_clause.replace('nogil', '').strip()
411
if exc_clause and no_exc_comment:
412
both_exc_and_no_exc.append((fname, func))
413
if sig != 'object' and not (exc_clause or no_exc_comment):
414
missing_except.append((fname, func))
416
if both_exc_and_no_exc:
417
error_msg.append('The following functions had "cannot raise" comments'
418
' but did have an except clause set:')
419
for fname, func in both_exc_and_no_exc:
420
error_msg.append('%s:%s' % (fname, func))
421
error_msg.extend(('', ''))
423
error_msg.append('The following functions have fixed return types,'
424
' but no except clause.')
425
error_msg.append('Either add an except or append "# cannot_raise".')
426
for fname, func in missing_except:
427
error_msg.append('%s:%s' % (fname, func))
428
error_msg.extend(('', ''))
430
self.fail('\n'.join(error_msg))