kitchen/kitchen3/tests/test__all__.py

194 lines
7.8 KiB
Python

# -*- coding: utf-8 -*-
from nose import tools
import os
import types
import warnings
def logit(msg):
log = open('/var/tmp/test.log', 'a')
log.write('%s\n' % msg)
log.close()
class NoAll(RuntimeError):
pass
class FailedImport(RuntimeError):
pass
class Test__all__(object):
'''Test that every function in __all__ exists and that no public methods
are missing from __all__
'''
known_private = set([('kitchen', 'collections', 'version_tuple_to_string'),
('kitchen.collections', 'strictdict', 'defaultdict'),
('kitchen', 'i18n', 'version_tuple_to_string'),
('kitchen', 'i18n', 'to_bytes'),
('kitchen', 'i18n', 'to_unicode'),
('kitchen', 'i18n', 'ENOENT'),
('kitchen', 'i18n', 'byte_string_valid_encoding'),
('kitchen', 'i18n', 'isbasestring'),
('kitchen', 'i18n', 'partial'),
('kitchen', 'iterutils', 'isbasestring'),
('kitchen', 'iterutils', 'version_tuple_to_string'),
('kitchen', 'pycompat24', 'version_tuple_to_string'),
('kitchen', 'pycompat25', 'version_tuple_to_string'),
('kitchen.pycompat25.collections', '_defaultdict', 'b_'),
('kitchen', 'pycompat27', 'version_tuple_to_string'),
('kitchen.pycompat27', 'subprocess', 'MAXFD'),
('kitchen.pycompat27', 'subprocess', 'list2cmdline'),
('kitchen.pycompat27', 'subprocess', 'mswindows'),
('kitchen', 'text', 'version_tuple_to_string'),
('kitchen.text', 'converters', 'b_'),
('kitchen.text', 'converters', 'b64decode'),
('kitchen.text', 'converters', 'b64encode'),
('kitchen.text', 'converters', 'ControlCharError'),
('kitchen.text', 'converters', 'guess_encoding'),
('kitchen.text', 'converters', 'html_entities_unescape'),
('kitchen.text', 'converters', 'isbytestring'),
('kitchen.text', 'converters', 'isunicodestring'),
('kitchen.text', 'converters', 'process_control_chars'),
('kitchen.text', 'converters', 'XmlEncodeError'),
('kitchen.text', 'misc', 'b_'),
('kitchen.text', 'misc', 'chardet'),
('kitchen.text', 'misc', 'ControlCharError'),
('kitchen.text', 'display', 'b_'),
('kitchen.text', 'display', 'ControlCharError'),
('kitchen.text', 'display', 'to_bytes'),
('kitchen.text', 'display', 'to_unicode'),
('kitchen.text', 'utf8', 'b_'),
('kitchen.text', 'utf8', 'byte_string_textual_width_fill'),
('kitchen.text', 'utf8', 'byte_string_valid_encoding'),
('kitchen.text', 'utf8', 'fill'),
('kitchen.text', 'utf8', 'isunicodestring'),
('kitchen.text', 'utf8', 'textual_width'),
('kitchen.text', 'utf8', 'textual_width_chop'),
('kitchen.text', 'utf8', 'to_bytes'),
('kitchen.text', 'utf8', 'to_unicode'),
('kitchen.text', 'utf8', 'wrap'),
])
lib_dir = os.path.join(os.path.dirname(__file__), '..', 'kitchen')
def setUp(self):
# Silence deprecation warnings
warnings.simplefilter('ignore', DeprecationWarning)
def tearDown(self):
warnings.simplefilter('default', DeprecationWarning)
def walk_modules(self, basedir, modpath):
files = os.listdir(basedir)
files.sort()
for fn in files:
path = os.path.join(basedir, fn)
if os.path.isdir(path):
pkg_init = os.path.join(path, '__init__.py')
if os.path.exists(pkg_init):
yield pkg_init, modpath + fn
for p, m in self.walk_modules(path, modpath + fn + '.'):
yield p, m
continue
if not fn.endswith('.py') or fn == '__init__.py':
continue
yield path, modpath + fn[:-3]
def check_has__all__(self, modpath):
# This heuristic speeds up the process by removing, de facto,
# most test modules (and avoiding the auto-executing ones).
f = None
try:
try:
f = open(modpath, 'r', encoding='utf-8')
tools.ok_('__all__' in f.read(), '%s does not contain __all__' % modpath)
except IOError as e:
tools.ok_(False, '%s' % e)
finally:
if f:
f.close()
def test_has__all__(self):
'''
For each module, check that it has an __all__
'''
# Blacklisted modules and packages
blacklist = set([ ])
for path, modname in [m for m in self.walk_modules(self.lib_dir, '')
if m[1] not in blacklist]:
# Check that it has an __all__
yield self.check_has__all__, path
def check_everything_in__all__exists(self, modname, modpath):
names = {}
exec('from %s import %s' % (modpath, modname), names)
if not hasattr(names[modname], '__all__'):
# This should have been reported by test_has__all__
return
interior_names = {}
try:
exec('from %s.%s import *' % (modpath, modname), interior_names)
except Exception as e:
# Include the module name in the exception string
tools.ok_(False, '__all__ failure in %s: %s: %s' % (
modname, e.__class__.__name__, e))
if '__builtins__' in interior_names:
del interior_names['__builtins__']
keys = set(interior_names)
all = set(names[modname].__all__)
tools.ok_(keys == all)
def test_everything_in__all__exists(self):
'''
For each name in module's __all__, check that it exists
'''
# Blacklisted modules and packages
blacklist = set([ ])
for path, modname in [m for m in self.walk_modules(self.lib_dir, '')
if m[1] not in blacklist]:
# From path, deduce the module name
from_name = path[path.find('../kitchen') + 3:]
if from_name.endswith('__init__.py'):
# Remove __init__.py as well as the filename
from_name = os.path.dirname(from_name)
from_name = os.path.dirname(from_name)
from_name = from_name.translate({ord('/'): '.'})
yield self.check_everything_in__all__exists, modname.split('.')[-1], from_name
def check__all__is_complete(self, modname, modpath):
names = {}
exec('from %s import %s' % (modpath, modname), names)
if not hasattr(names[modname], '__all__'):
# This should have been reported by test_has__all__
return
mod = names[modname]
expected_public = [k for k in mod.__dict__ if (modpath, modname, k)
not in self.known_private and not k.startswith("_") and not
isinstance(mod.__dict__[k], types.ModuleType)]
all = set(mod.__all__)
public = set(expected_public)
tools.ok_(all.issuperset(public), 'These public names are not in %s.__all__: %s'
% (modname, ', '.join(public.difference(all))))
def test__all__is_complete(self):
'''
For each module, check that every public name is in __all__
'''
# Blacklisted modules and packages
blacklist = set(['pycompat27.subprocess._subprocess',
'pycompat24.base64._base64'])
for path, modname in [m for m in self.walk_modules(self.lib_dir, '')
if m[1] not in blacklist]:
# From path, deduce the module name
from_name = path[path.find('../kitchen') + 3:]
if from_name.endswith('__init__.py'):
# Remove __init__.py as well as the filename
from_name = os.path.dirname(from_name)
from_name = os.path.dirname(from_name)
from_name = from_name.translate({ord('/'): '.'})
yield self.check__all__is_complete, modname.split('.')[-1], from_name