Skip to content

Commit

Permalink
Update coding standards test to reflect SciTools/scitools.org.uk#209.
Browse files Browse the repository at this point in the history
  • Loading branch information
pelson committed Jan 16, 2019
1 parent 427de4f commit 853a344
Showing 1 changed file with 57 additions and 24 deletions.
81 changes: 57 additions & 24 deletions lib/cartopy/tests/test_coding_standards.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,19 @@

LICENSE_RE_PATTERN = re.escape(LICENSE_TEMPLATE).replace(r'\{YEARS\}', '(.*?)')
# Add shebang possibility or C comment starter to the LICENSE_RE_PATTERN
LICENSE_RE_PATTERN = r'((\#\!.*|\/\*)\n)?' + LICENSE_RE_PATTERN
LICENSE_RE = re.compile(LICENSE_RE_PATTERN, re.MULTILINE)
SHEBANG_PATTERN = r'((\#\!.*|\/\*)\n)?'
LICENSE_RE = re.compile(SHEBANG_PATTERN + LICENSE_RE_PATTERN, re.MULTILINE)


LICENSE_TEMPLATE_v2 = """
# (C) Copyright Cartopy Contributors
#
# This file is part of Cartopy and is released under the LGPL license.
# See LICENSE in the root of the repository for full licensing details.
""".strip()
LICENSE_RE_PATTERN_v2 = re.escape(LICENSE_TEMPLATE_v2)
LICENSE_RE_v2 = re.compile(SHEBANG_PATTERN + LICENSE_RE_PATTERN_v2,
re.MULTILINE)


# Guess cartopy repo directory of cartopy - realpath is used to mitigate
Expand All @@ -64,16 +75,16 @@

class TestLicenseHeaders(object):
@staticmethod
def years_of_license_in_file(fh):
def years_of_license_in_file(content, fname):
"""
Using :data:`LICENSE_RE` look for the years defined in the license
header of the given file handle.
If the license cannot be found in the given fh, None will be returned,
else a tuple of (start_year, end_year) will be returned.
If the license cannot be found in the given content, None will be
returned, else a tuple of (start_year, end_year) will be returned.
"""
license_matches = LICENSE_RE.match(fh.read())
license_matches = LICENSE_RE.match(content)
if not license_matches:
# no license found in file.
return None
Expand All @@ -84,7 +95,6 @@ def years_of_license_in_file(fh):
elif len(years) == 11:
start_year, end_year = int(years[:4]), int(years[7:])
else:
fname = getattr(fh, 'name', 'unknown filename')
raise ValueError("Unexpected year(s) string in {}'s copyright "
"notice: {!r}".format(fname, years))
return (start_year, end_year)
Expand Down Expand Up @@ -147,19 +157,35 @@ def test_license_headers(self):
if ext in ('.py', '.pyx', '.c', '.cpp', '.h') and \
os.path.isfile(full_fname) and \
not any(fnmatch(fname, pat) for pat in exclude_patterns):

is_empty = os.path.getsize(full_fname) == 0

with io.open(full_fname, encoding='utf-8') as fh:
years = TestLicenseHeaders.years_of_license_in_file(fh)
if years is None:
print('The file {} has no valid header license and '
'has not been excluded from the license header '
'test.'.format(fname))
failed = True
elif last_change.year > years[1]:
print('The file header at {} is out of date. The last'
' commit was in {}, but the copyright states it'
' was {}.'.format(fname, last_change.year,
years[1]))
failed = True
content = fh.read()

is_yearless_license = bool(LICENSE_RE_v2.match(content))
years = TestLicenseHeaders.years_of_license_in_file(
content, full_fname)

if is_empty:
# Allow completely empty files (e.g. ``__init__.py``)
pass
elif is_yearless_license:
# Allow new style license (v2).
pass

# What is left is the old-style (pre 2019) header.
elif years is None:
print('The file {} has no valid header license and '
'has not been excluded from the license header '
'test.'.format(fname))
failed = True
elif last_change.year > years[1]:
print('The file header at {} is out of date. The last'
' commit was in {}, but the copyright states it'
' was {}.'.format(fname, last_change.year,
years[1]))
failed = True

if failed:
raise ValueError('There were license header failures. See stdout.')
Expand Down Expand Up @@ -197,14 +223,21 @@ def test_future_imports(self):
if any(fnmatch(full_fname, pat) for pat in self.excluded):
continue

is_empty = os.path.getsize(full_fname) == 0

with io.open(full_fname, "r", encoding='utf-8') as fh:
content = fh.read()

if re.search(self.future_imports_pattern, content) is None:
print('The file {} has no valid __future__ imports '
'and has not been excluded from the imports '
'test.'.format(full_fname))
failed = True
has_future_import = re.search(
self.future_imports_pattern, content) is not None

if is_empty:
pass
elif not has_future_import:
print('The file {} has no valid __future__ imports '
'and has not been excluded from the imports '
'test.'.format(full_fname))
failed = True

if failed:
raise ValueError('There were __future__ import check failures. '
Expand Down

0 comments on commit 853a344

Please sign in to comment.