mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-01-18 02:40:07 +00:00
Add a script 'misc/coding_tools/check-interfaces.py' that checks whether zope interfaces are enforced. Also add 'check-interfaces', 'version-and-path', and 'code-checks' targets to the Makefile. fixes #1474
This commit is contained in:
parent
1fa5c729b7
commit
417054aaba
19
Makefile
19
Makefile
@ -121,12 +121,26 @@ upload-coverage:
|
||||
false
|
||||
endif
|
||||
|
||||
code-checks: build version-and-path check-interfaces -find-trailing-spaces -check-umids pyflakes
|
||||
|
||||
version-and-path:
|
||||
$(TAHOE) --version-and-path
|
||||
|
||||
check-interfaces:
|
||||
$(TAHOE) @misc/coding_tools/check-interfaces.py 2>&1 |tee violations.txt
|
||||
@echo
|
||||
|
||||
pyflakes:
|
||||
$(PYTHON) -OOu `which pyflakes` $(SOURCES) |sort |uniq
|
||||
@echo
|
||||
|
||||
check-umids:
|
||||
$(PYTHON) misc/coding_tools/check-umids.py `find $(SOURCES) -name '*.py'`
|
||||
@echo
|
||||
|
||||
-check-umids:
|
||||
-$(PYTHON) misc/coding_tools/check-umids.py `find $(SOURCES) -name '*.py'`
|
||||
@echo
|
||||
|
||||
count-lines:
|
||||
@echo -n "files: "
|
||||
@ -213,6 +227,11 @@ clean:
|
||||
|
||||
find-trailing-spaces:
|
||||
$(PYTHON) misc/coding_tools/find-trailing-spaces.py -r $(SOURCES)
|
||||
@echo
|
||||
|
||||
-find-trailing-spaces:
|
||||
-$(PYTHON) misc/coding_tools/find-trailing-spaces.py -r $(SOURCES)
|
||||
@echo
|
||||
|
||||
# The test-desert-island target grabs the tahoe-deps tarball, unpacks it,
|
||||
# does a build, then asserts that the build did not try to download anything
|
||||
|
81
misc/coding_tools/check-interfaces.py
Normal file
81
misc/coding_tools/check-interfaces.py
Normal file
@ -0,0 +1,81 @@
|
||||
|
||||
# To check a particular Tahoe source distribution, this should be invoked from
|
||||
# the root directory of that distribution as
|
||||
#
|
||||
# bin/tahoe @misc/coding_tools/check-interfaces.py
|
||||
|
||||
import os, sys, re
|
||||
|
||||
import zope.interface as zi
|
||||
from zope.interface.verify import verifyClass
|
||||
from zope.interface.advice import addClassAdvisor
|
||||
|
||||
|
||||
interesting_modules = re.compile(r'(allmydata)|(foolscap)\..*')
|
||||
excluded_classnames = re.compile(r'(_)|(Mock)|(Fake).*')
|
||||
excluded_file_basenames = re.compile(r'check_.*')
|
||||
|
||||
|
||||
other_modules_with_violations = set()
|
||||
|
||||
# deep magic
|
||||
def strictly_implements(*interfaces):
|
||||
frame = sys._getframe(1)
|
||||
f_locals = frame.f_locals
|
||||
|
||||
# Try to make sure we were called from a class def. Assumes Python > 2.2.
|
||||
if f_locals is frame.f_globals or '__module__' not in f_locals:
|
||||
raise TypeError("implements can be used only from a class definition.")
|
||||
|
||||
if '__implements_advice_data__' in f_locals:
|
||||
raise TypeError("implements can be used only once in a class definition.")
|
||||
|
||||
def _implements_advice(cls):
|
||||
interfaces, classImplements = cls.__dict__['__implements_advice_data__']
|
||||
del cls.__implements_advice_data__
|
||||
classImplements(cls, *interfaces)
|
||||
|
||||
if interesting_modules.match(cls.__module__):
|
||||
if not excluded_classnames.match(cls.__name__):
|
||||
for interface in interfaces:
|
||||
try:
|
||||
verifyClass(interface, cls)
|
||||
except Exception, e:
|
||||
print >>sys.stderr, ("%s.%s does not implement %s.%s:\n%s"
|
||||
% (cls.__module__, cls.__name__,
|
||||
interface.__module__, interface.__name__, e))
|
||||
else:
|
||||
other_modules_with_violations.add(cls.__module__)
|
||||
return cls
|
||||
|
||||
f_locals['__implements_advice_data__'] = interfaces, zi.classImplements
|
||||
addClassAdvisor(_implements_advice, depth=2)
|
||||
|
||||
|
||||
# patchee-monkey
|
||||
zi.implements = strictly_implements
|
||||
|
||||
|
||||
# attempt to avoid side-effects from importing command scripts
|
||||
sys.argv = ['', '--help']
|
||||
|
||||
|
||||
from twisted.python.filepath import FilePath
|
||||
|
||||
# import modules under src/
|
||||
src = FilePath('src')
|
||||
for fp in src.walk():
|
||||
(basepath, ext) = fp.splitext()
|
||||
if ext == '.py' and not excluded_file_basenames.match(fp.basename()):
|
||||
relpath = os.path.relpath(basepath, src.path)
|
||||
module = relpath.replace(os.path.sep, '/').replace('/', '.')
|
||||
try:
|
||||
__import__(module)
|
||||
except ImportError:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
print >>sys.stderr
|
||||
|
||||
others = list(other_modules_with_violations)
|
||||
others.sort()
|
||||
print >>sys.stderr, "There were also interface violations in:\n", ", ".join(others), "\n"
|
Loading…
Reference in New Issue
Block a user