diff -r c5d3382f14e9 -r bf6106b91633 cubicweb/test/unittest_cwconfig.py --- a/cubicweb/test/unittest_cwconfig.py Wed Jan 18 17:16:00 2017 +0100 +++ b/cubicweb/test/unittest_cwconfig.py Thu Jan 19 15:27:39 2017 +0100 @@ -17,8 +17,12 @@ # with CubicWeb. If not, see . """cubicweb.cwconfig unit tests""" +import contextlib +import compileall +import functools import sys import os +import pkgutil from os.path import dirname, join, abspath from pkg_resources import EntryPoint, Distribution import unittest @@ -31,7 +35,8 @@ from cubicweb.devtools import ApptestConfiguration from cubicweb.devtools.testlib import BaseTestCase, TemporaryDirectory -from cubicweb.cwconfig import _find_prefix +from cubicweb.cwconfig import ( + CubicWebConfiguration, _find_prefix, _expand_modname) def unabsolutize(path): @@ -44,6 +49,50 @@ raise Exception('duh? %s' % path) +def templibdir(func): + """create a temporary directory and insert it in sys.path""" + @functools.wraps(func) + def wrapper(*args, **kwargs): + with TemporaryDirectory() as libdir: + sys.path.insert(0, libdir) + try: + args = args + (libdir,) + return func(*args, **kwargs) + finally: + sys.path.remove(libdir) + return wrapper + + +def create_filepath(filepath): + filedir = dirname(filepath) + if not os.path.exists(filedir): + os.makedirs(filedir) + with open(filepath, 'a'): + pass + + +@contextlib.contextmanager +def temp_config(appid, instance_dir, cubes_dir, cubes): + """context manager that create a config object with specified appid, + instance_dir, cubes_dir and cubes""" + cls = CubicWebConfiguration + old = (cls._INSTANCES_DIR, cls.CUBES_DIR, cls.CUBES_PATH, + sys.path[:], sys.meta_path[:]) + old_modules = set(sys.modules) + try: + cls._INSTANCES_DIR, cls.CUBES_DIR, cls.CUBES_PATH = ( + instance_dir, cubes_dir, []) + config = cls(appid) + config._cubes = cubes + config.adjust_sys_path() + yield config + finally: + (cls._INSTANCES_DIR, cls.CUBES_DIR, cls.CUBES_PATH, + sys.path[:], sys.meta_path[:]) = old + for module in set(sys.modules) - old_modules: + del sys.modules[module] + + class CubicWebConfigurationTC(BaseTestCase): @classmethod @@ -313,5 +362,109 @@ os.environ['VIRTUAL_ENV'] = venv +class ModnamesTC(unittest.TestCase): + + @templibdir + def test_expand_modnames(self, libdir): + tempdir = join(libdir, 'lib') + filepaths = [ + join(tempdir, '__init__.py'), + join(tempdir, 'a.py'), + join(tempdir, 'b.py'), + join(tempdir, 'c.py'), + join(tempdir, 'b', '__init__.py'), + join(tempdir, 'b', 'a.py'), + join(tempdir, 'b', 'c.py'), + join(tempdir, 'b', 'd', '__init__.py'), + join(tempdir, 'e', 'e.py'), + ] + for filepath in filepaths: + create_filepath(filepath) + # not importable + self.assertEqual(list(_expand_modname('isnotimportable')), []) + # not a python package + self.assertEqual(list(_expand_modname('lib.e')), []) + self.assertEqual(list(_expand_modname('lib.a')), [ + ('lib.a', join(tempdir, 'a.py')), + ]) + # lib.b.d (subpackage) not to be imported + self.assertEqual(list(_expand_modname('lib.b')), [ + ('lib.b', join(tempdir, 'b', '__init__.py')), + ('lib.b.a', join(tempdir, 'b', 'a.py')), + ('lib.b.c', join(tempdir, 'b', 'c.py')), + ]) + self.assertEqual(list(_expand_modname('lib')), [ + ('lib', join(tempdir, '__init__.py')), + ('lib.a', join(tempdir, 'a.py')), + ('lib.c', join(tempdir, 'c.py')), + ]) + for source in ( + join(tempdir, 'c.py'), + join(tempdir, 'b', 'c.py'), + ): + if not PY3: + # ensure pyc file exists. + # Doesn't required for PY3 since it create __pycache__ + # directory and will not import if source file doesn't + # exists. + compileall.compile_file(source, force=True) + self.assertTrue(os.path.exists(source + 'c')) + # remove source file + os.remove(source) + self.assertEqual(list(_expand_modname('lib.c')), []) + self.assertEqual(list(_expand_modname('lib.b')), [ + ('lib.b', join(tempdir, 'b', '__init__.py')), + ('lib.b.a', join(tempdir, 'b', 'a.py')), + ]) + self.assertEqual(list(_expand_modname('lib')), [ + ('lib', join(tempdir, '__init__.py')), + ('lib.a', join(tempdir, 'a.py')), + ]) + + @templibdir + def test_schema_modnames(self, libdir): + for filepath in ( + join(libdir, 'schema.py'), + join(libdir, 'cubicweb_foo', '__init__.py'), + join(libdir, 'cubicweb_foo', 'schema', '__init__.py'), + join(libdir, 'cubicweb_foo', 'schema', 'a.py'), + join(libdir, 'cubicweb_foo', 'schema', 'b.py'), + join(libdir, 'cubes', '__init__.py'), + join(libdir, 'cubes', 'bar', '__init__.py'), + join(libdir, 'cubes', 'bar', 'schema.py'), + join(libdir, '_instance_dir', 'data1', 'schema.py'), + join(libdir, '_instance_dir', 'data2', 'noschema.py'), + ): + create_filepath(filepath) + expected = [ + ('cubicweb', 'cubicweb.schemas.bootstrap'), + ('cubicweb', 'cubicweb.schemas.base'), + ('cubicweb', 'cubicweb.schemas.workflow'), + ('cubicweb', 'cubicweb.schemas.Bookmark'), + ('bar', 'cubes.bar.schema'), + ('foo', 'cubes.foo.schema'), + ('foo', 'cubes.foo.schema.a'), + ('foo', 'cubes.foo.schema.b'), + ] + # app has schema file + instance_dir, cubes_dir = ( + join(libdir, '_instance_dir'), join(libdir, 'cubes')) + with temp_config('data1', instance_dir, cubes_dir, + ('foo', 'bar')) as config: + self.assertEqual(pkgutil.find_loader('schema').get_filename(), + join(libdir, '_instance_dir', + 'data1', 'schema.py')) + self.assertEqual(config.schema_modnames(), + expected + [('data', 'schema')]) + # app doesn't have schema file + with temp_config('data2', instance_dir, cubes_dir, + ('foo', 'bar')) as config: + self.assertEqual(pkgutil.find_loader('schema').get_filename(), + join(libdir, 'schema.py')) + self.assertEqual(config.schema_modnames(), expected) + + + + if __name__ == '__main__': unittest.main()