diff --git a/Lib/test/package_helper.py b/Lib/test/package_helper.py new file mode 100644 --- /dev/null +++ b/Lib/test/package_helper.py @@ -0,0 +1,186 @@ +""" +Support for creating files, directories and packages for testing purposes. + +The classes in this module provide convenience methods for the creation +of arbitrarily nested packages and directories. + +To illustrate, here is an involved example that creates following +directory structure: + +package/ + __init__.py + # code + mod.py + # code + subpackage/ + __init__.py + submod.py + data/ + file1.txt + file2.txt + foo + +test_pkg = TestPackage('package', init_src='# code', subs=[ + TestModule('mod', src='# code'), + TestPackage('subpackage', subs=['submod']), + TestDir('data', subs=['file1.txt', + TestFile('file2.txt', text='foo')])]) +test_pkg.write(parent_dir='temp') + +""" + +import os + + +def create_file(path, text='', encoding=None): + """Create a file at the given path.""" + if encoding is None: + encoding = 'utf-8' + with open(path, 'w', encoding=encoding) as f: + f.write(text) + + +def _create_test_file(test_file, parent_dir=None): + """Create a file inside the given parent directory. + + Returns the path to the file created. + + Arguments: + + test_file: a TestFile instance. + + parent_dir: defaults to the current working directory. + + """ + if parent_dir is None: + parent_dir = os.getcwd() + file_path = os.path.join(parent_dir, test_file.filename) + create_file(file_path, text=test_file.text) + return file_path + + +def _create_test_dir(test_dir, parent_dir=None): + """Create a directory hierarchy inside the given parent directory. + + Returns the path to the directory created. + + Arguments: + + test_dir: a TestDir instance. + + parent_dir: defaults to the current working directory. + + """ + if parent_dir is None: + parent_dir = os.getcwd() + dir_path = os.path.join(parent_dir, test_dir.name) + os.mkdir(dir_path) + for sub in test_dir.subs: + sub.write(parent_dir=dir_path) + return dir_path + + +class _Namespace(object): + + """A container for storing attributes.""" + + def __init__(self, **kwargs): + for name in kwargs: + setattr(self, name, kwargs[name]) + + # The equality operators are primarily to support unit testing + # the current module. + def __eq__(self, other): + if type(self) != type(other): + return False + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + # A quick and dirty implementation so that attribute information + # will display in the error messages for unit-test assertion + # failures. + return "<%s: %s>" % (type(self), repr(self.__dict__)) + + +class TestFile(_Namespace): + + """Encapsulates information about a file.""" + + def __init__(self, filename, text=''): + super().__init__(filename=filename, text=text) + + def write(self, parent_dir=None): + """Create the file, and return its path.""" + return _create_test_file(self, parent_dir=parent_dir) + + +class TestModule(TestFile): + + """Encapsulates information about a module.""" + + def __init__(self, modname, src=''): + filename = modname + os.extsep + "py" + super().__init__(filename=filename, text=src) + # Set remaining non-TestFile attributes. + _Namespace.__init__(self, modname=modname) + + +class TestDir(_Namespace): + + """Encapsulates information about a directory.""" + + def __init__(self, name, subs=None): + """ + Arguments: + + name: the name of the directory. + + subs: an iterable of TestDir instances, TestFile instances, and + string file names. Defaults to an empty list. + + """ + if subs is None: + subs = [] + # Create a new list, and convert string subs to object instances. + new_subs = [] + for sub in subs: + if isinstance(sub, str): + sub = TestFile(sub) + new_subs.append(sub) + super().__init__(name=name, subs=new_subs) + + def write(self, parent_dir=None): + """Create the directory, and return its path.""" + return _create_test_dir(self, parent_dir=parent_dir) + + +class TestPackage(TestDir): + + """Encapsulates information about a package.""" + + def __init__(self, name, init_src='', subs=None): + """ + Arguments: + + name: the name of the package. + + init_src: the text of the __init__.py file. + + subs: an iterable of TestDir instances, TestFile instances, and + string module names. Do not include __init__.py as that + is added automatically. Defaults to an empty list. + + """ + if subs is None: + subs = [] + # Create a new list, and convert all subs to objects. + init_mod = TestModule('__init__', src=init_src) + new_subs = [init_mod] + for sub in subs: + if isinstance(sub, str): + sub = TestModule(sub) + new_subs.append(sub) + super().__init__(name=name, subs=new_subs) diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -13,7 +13,7 @@ import zipfile from imp import source_from_cache -from test.support import make_legacy_pyc, strip_python_stderr +from test.support import make_legacy_pyc, strip_python_stderr, TestModule # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): @@ -88,14 +88,10 @@ shutil.rmtree(dirname) def make_script(script_dir, script_basename, source): - script_filename = script_basename+os.extsep+'py' - script_name = os.path.join(script_dir, script_filename) - # The script should be encoded to UTF-8, the default string encoding - script_file = open(script_name, 'w', encoding='utf-8') - script_file.write(source) - script_file.close() + test_mod = TestModule(script_basename, src=source) + script_path = test_mod.write(parent_dir=script_dir) importlib.invalidate_caches() - return script_name + return script_path def make_zip_script(zip_dir, zip_basename, script_name, name_in_zip=None): zip_filename = zip_basename+os.extsep+'zip' @@ -118,10 +114,6 @@ # zip_file.close() return zip_name, os.path.join(zip_name, name_in_zip) -def make_pkg(pkg_dir, init_source=''): - os.mkdir(pkg_dir) - make_script(pkg_dir, '__init__', init_source) - def make_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, source, depth=1, compiled=False): unlink = [] diff --git a/Lib/test/support.py b/Lib/test/support.py --- a/Lib/test/support.py +++ b/Lib/test/support.py @@ -26,6 +26,9 @@ import struct import tempfile import _testcapi +from test.package_helper import ( + create_file, TestFile, TestModule, TestDir, TestPackage +) try: import _thread, threading diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -12,7 +12,7 @@ import textwrap from test import support from test.script_helper import ( - make_pkg, make_script, make_zip_pkg, make_zip_script, + make_script, make_zip_pkg, make_zip_script, assert_python_ok, assert_python_failure, temp_dir, spawn_python, kill_python) @@ -56,6 +56,13 @@ print('cwd==%a' % os.getcwd()) """ +def _make_pkg(name, parent_dir, init_source=''): + pkg = support.TestPackage(name, init_src=init_source) + pkg_dir = pkg.write(parent_dir=parent_dir) + # XXX TODO: can we remove this? + importlib.invalidate_caches() + return pkg_dir + def _make_test_script(script_dir, script_basename, source=test_source): to_return = make_script(script_dir, script_basename, source) importlib.invalidate_caches() @@ -219,8 +226,7 @@ def test_module_in_package(self): with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) + pkg_dir = _make_pkg('test_pkg', parent_dir=script_dir) script_name = _make_test_script(pkg_dir, 'script') launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.script') self._check_script(launch_name, script_name, script_name, @@ -244,8 +250,7 @@ def test_package(self): with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) + pkg_dir = _make_pkg('test_pkg', parent_dir=script_dir) script_name = _make_test_script(pkg_dir, '__main__') launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') self._check_script(launch_name, script_name, @@ -254,8 +259,7 @@ def test_package_compiled(self): with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) + pkg_dir = _make_pkg('test_pkg', parent_dir=script_dir) script_name = _make_test_script(pkg_dir, '__main__') compiled_name = py_compile.compile(script_name, doraise=True) os.remove(script_name) @@ -267,8 +271,7 @@ def test_package_error(self): with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) + pkg_dir = _make_pkg('test_pkg', parent_dir=script_dir) msg = ("'test_pkg' is a package and cannot " "be directly executed") launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') @@ -276,10 +279,8 @@ def test_package_recursion(self): with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) - main_dir = os.path.join(pkg_dir, '__main__') - make_pkg(main_dir) + pkg_dir = _make_pkg('test_pkg', parent_dir=script_dir) + main_dir = _make_pkg('__main__', parent_dir=pkg_dir) msg = ("Cannot use package as __main__ module; " "'test_pkg' is a package and cannot " "be directly executed") @@ -291,8 +292,8 @@ # searching for the module to execute with temp_dir() as script_dir: with support.temp_cwd(path=script_dir): - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir, "import sys; print('init_argv0==%r' % sys.argv[0])") + pkg_dir = _make_pkg('test_pkg', parent_dir=script_dir, + init_source="import sys; print('init_argv0==%r' % sys.argv[0])") script_name = _make_test_script(pkg_dir, 'script') rc, out, err = assert_python_ok('-m', 'test_pkg.script', *example_args) if verbose > 1: @@ -336,8 +337,7 @@ # shell is '1' with temp_dir() as script_dir: with support.temp_cwd(path=script_dir): - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) + pkg_dir = _make_pkg('test_pkg', parent_dir=script_dir) script_name = _make_test_script(pkg_dir, 'other', "if __name__ == '__main__': raise ValueError") rc, out, err = assert_python_failure('-m', 'test_pkg.other', *example_args) diff --git a/Lib/test/test_filecmp.py b/Lib/test/test_filecmp.py --- a/Lib/test/test_filecmp.py +++ b/Lib/test/test_filecmp.py @@ -2,6 +2,7 @@ import os, filecmp, shutil, tempfile import unittest from test import support +from test.support import create_file, TestFile, TestDir class FileCompareTestCase(unittest.TestCase): def setUp(self): @@ -10,9 +11,7 @@ self.name_diff = support.TESTFN + '-diff' data = 'Contents of file go here.\n' for name in [self.name, self.name_same, self.name_diff]: - output = open(name, 'w') - output.write(data) - output.close() + create_file(name, text=data) output = open(self.name_diff, 'a+') output.write('An extra line.\n') @@ -43,25 +42,21 @@ class DirCompareTestCase(unittest.TestCase): def setUp(self): tmpdir = tempfile.gettempdir() - self.dir = os.path.join(tmpdir, 'dir') - self.dir_same = os.path.join(tmpdir, 'dir-same') - self.dir_diff = os.path.join(tmpdir, 'dir-diff') self.caseinsensitive = os.path.normcase('A') == os.path.normcase('a') data = 'Contents of file go here.\n' - for dir in [self.dir, self.dir_same, self.dir_diff]: - shutil.rmtree(dir, True) - os.mkdir(dir) - if self.caseinsensitive and dir is self.dir_same: - fn = 'FiLe' # Verify case-insensitive comparison - else: - fn = 'file' - output = open(os.path.join(dir, fn), 'w') - output.write(data) - output.close() - output = open(os.path.join(self.dir_diff, 'file2'), 'w') - output.write('An extra file.\n') - output.close() + # For verifying case-insensitive comparison + case_name = 'FiLe' if self.caseinsensitive else 'file' + test_dirs = [ + TestDir('dir', subs=[TestFile('file', text=data)]), + TestDir('dir-same', subs=[TestFile(case_name, text=data)]), + TestDir('dir-diff', subs=[TestFile('file', text=data), + TestFile('file2', + text='An extra file.\n')]) + ] + + paths = [test_dir.write(parent_dir=tmpdir) for test_dir in test_dirs] + self.dir, self.dir_same, self.dir_diff = paths def tearDown(self): shutil.rmtree(self.dir) @@ -86,9 +81,8 @@ "Comparing directory to same fails") # Add different file2 - output = open(os.path.join(self.dir, 'file2'), 'w') - output.write('Different contents.\n') - output.close() + path = os.path.join(self.dir, 'file2') + create_file(path, text='Different contents.\n') self.assertFalse(filecmp.cmpfiles(self.dir, self.dir_same, ['file', 'file2']) == @@ -119,9 +113,8 @@ self.assertEqual(d.diff_files, []) # Add different file2 - output = open(os.path.join(self.dir, 'file2'), 'w') - output.write('Different contents.\n') - output.close() + path = os.path.join(self.dir, 'file2') + create_file(path, text='Different contents.\n') d = filecmp.dircmp(self.dir, self.dir_diff) self.assertEqual(d.same_files, ['file']) self.assertEqual(d.diff_files, ['file2']) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -19,7 +19,7 @@ from test.support import ( EnvironmentVarGuard, TESTFN, check_warnings, forget, is_jython, make_legacy_pyc, rmtree, run_unittest, swap_attr, swap_item, temp_umask, - unlink, unload, create_empty_file, cpython_only) + unlink, unload, create_empty_file, cpython_only, TestModule, TestPackage) from test import script_helper @@ -648,13 +648,9 @@ rmtree('pep3147') unload('pep3147.foo') unload('pep3147') - os.mkdir('pep3147') + test_pkg = TestPackage('pep3147', subs=['foo']) + test_pkg.write() self.addCleanup(cleanup) - # Touch the __init__.py - with open(os.path.join('pep3147', '__init__.py'), 'w'): - pass - with open(os.path.join('pep3147', 'foo.py'), 'w'): - pass importlib.invalidate_caches() m = __import__('pep3147.foo') init_pyc = imp.cache_from_source( @@ -671,13 +667,9 @@ rmtree('pep3147') unload('pep3147.foo') unload('pep3147') - os.mkdir('pep3147') + test_pkg = TestPackage('pep3147', subs=['foo']) + test_pkg.write() self.addCleanup(cleanup) - # Touch the __init__.py - with open(os.path.join('pep3147', '__init__.py'), 'w'): - pass - with open(os.path.join('pep3147', 'foo.py'), 'w'): - pass importlib.invalidate_caches() m = __import__('pep3147.foo') unload('pep3147.foo') @@ -785,13 +777,11 @@ sys.path[:] = self.old_path rmtree(TESTFN) - def create_module(self, mod, contents, ext=".py"): - fname = os.path.join(TESTFN, mod + ext) - with open(fname, "w") as f: - f.write(contents) + def create_module(self, mod, contents): + test_mod = TestModule(mod, src=contents) + test_mod.write(parent_dir=TESTFN) self.addCleanup(unload, mod) importlib.invalidate_caches() - return fname def assert_traceback(self, tb, files): deduped_files = [] @@ -860,15 +850,11 @@ def _setup_broken_package(self, parent, child): pkg_name = "_parent_foo" self.addCleanup(unload, pkg_name) - pkg_path = os.path.join(TESTFN, pkg_name) - os.mkdir(pkg_path) - # Touch the __init__.py + test_pkg = TestPackage(pkg_name, init_src=parent, + subs=[TestModule('bar', src=child)]) + pkg_path = test_pkg.write(parent_dir=TESTFN) init_path = os.path.join(pkg_path, '__init__.py') - with open(init_path, 'w') as f: - f.write(parent) bar_path = os.path.join(pkg_path, 'bar.py') - with open(bar_path, 'w') as f: - f.write(child) importlib.invalidate_caches() return init_path, bar_path diff --git a/Lib/test/test_package_helper.py b/Lib/test/test_package_helper.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_package_helper.py @@ -0,0 +1,187 @@ +import os +import unittest +from test import support +from test.package_helper import _Namespace +from test.script_helper import temp_dir +# The functions and classes under test. +from test.support import ( + create_file, TestFile, TestModule, TestDir, TestPackage +) + + +def read_file(path): + """Return the contents of a file as a unicode string.""" + with open(path, encoding='utf-8') as f: + return f.read() + + +class TestCaseMixin(object): + + """Contains helper assert methods.""" + + def assert_paths(self, path1, path2): + """Check that two paths are equivalent.""" + path1, path2 = (os.path.abspath(path) for path in (path1, path2)) + self.assertEquals(path1, path2) + + def assert_file_text(self, path, expected_text): + """Check the text contents of the file at a given path.""" + actual_text = read_file(path) + self.assertEquals(actual_text, expected_text) + + def assert_isdir(self, path): + """Check that a path is a directory.""" + msg = "does not exist: %s" % repr(path) + self.assertTrue(os.path.exists(path), msg=msg) + msg = "not a directory: %s" % repr(path) + self.assertTrue(os.path.isdir(path), msg=msg) + + +class CreateFileTestCase(unittest.TestCase): + + """Test the create_file() function.""" + + def test_create_file(self): + with temp_dir() as parent_dir: + path = os.path.join(parent_dir, 'test.txt') + create_file(path, text='foo') + actual = read_file(path) + self.assertEqual(actual, 'foo') + + +# We test the private _Namespace class to make sure that our equality +# and inequality operators behave as expected, which is important because +# we use them in our tests. +class NamespaceTestCase(unittest.TestCase): + + def test_eq_and_ne(self): + class MyNamespace(_Namespace): + pass + + ns1 = _Namespace(a=1, b=2) + ns2 = _Namespace(a=1, b=2) + ns3 = _Namespace(a=1, b=3) + ns4 = MyNamespace(a=1, b=2) + # ns2 + self.assertTrue(ns1 == ns2) + self.assertFalse(ns1 != ns2) + # ns3 + self.assertFalse(ns1 == ns3) + self.assertTrue(ns1 != ns3) + # ns4: check that the type matters. + self.assertFalse(ns1 == ns4) + self.assertTrue(ns1 != ns4) + + +class TestFileTestCase(unittest.TestCase, TestCaseMixin): + + def test_init__default_args(self): + test_file = TestFile('temp.txt') + self.assertEquals(test_file.filename, 'temp.txt') + self.assertEquals(test_file.text, '') + + def test_init(self): + test_file = TestFile('temp.txt', text='foo') + self.assertEquals(test_file.filename, 'temp.txt') + self.assertEquals(test_file.text, 'foo') + + def test_write(self): + test_file = TestFile('temp.txt', text='foo') + with temp_dir() as parent_dir: + path = test_file.write(parent_dir) + self.assert_paths(path, os.path.join(parent_dir, 'temp.txt')) + self.assert_file_text(path, 'foo') + + +class TestModuleTestCase(unittest.TestCase, TestCaseMixin): + + def test_init__default_args(self): + test_mod = TestModule('temp') + self.assertEquals(test_mod.modname, 'temp') + self.assertEquals(test_mod.filename, 'temp.py') + self.assertEquals(test_mod.text, '') + + def test_init(self): + test_mod = TestModule('temp', src='# foo') + self.assertEquals(test_mod.modname, 'temp') + self.assertEquals(test_mod.filename, 'temp.py') + self.assertEquals(test_mod.text, '# foo') + + def test_write(self): + test_mod = TestModule('temp', src='# foo') + with temp_dir() as parent_dir: + path = test_mod.write(parent_dir) + self.assert_paths(path, os.path.join(parent_dir, 'temp.py')) + self.assert_file_text(path, '# foo') + + +class TestDirTestCase(unittest.TestCase, TestCaseMixin): + + def test_init__default_args(self): + test_dir = TestDir('temp') + self.assertEquals(test_dir.name, 'temp') + self.assertEquals(test_dir.subs, []) + + def test_init__subs(self): + """Check the subs attribute.""" + subs = ['foo.txt'] + test_dir = TestDir('temp', subs=subs) + self.assertEquals(len(test_dir.subs), 1) + actual_sub = test_dir.subs[0] + expected_sub = TestFile('foo.txt') + self.assertEquals(actual_sub, expected_sub) + + def test_write(self): + test_dir = TestDir('temp', + subs=['file1.txt', + TestFile('file2.txt', text='file2 text'), + TestModule('mod', src='# code'), + TestDir('subdir', subs=['subfile.txt'])]) + with temp_dir() as parent_dir: + dir_path = test_dir.write(parent_dir) + self.assert_paths(dir_path, os.path.join(parent_dir, 'temp')) + self.assert_isdir(dir_path) + self.assert_file_text(os.path.join(dir_path, 'file1.txt'), '') + self.assert_file_text(os.path.join(dir_path, 'file2.txt'), + 'file2 text') + self.assert_file_text(os.path.join(dir_path, 'mod.py'), '# code') + subdir_path = os.path.join(dir_path, 'subdir') + self.assert_isdir(subdir_path) + self.assert_file_text(os.path.join(subdir_path, 'subfile.txt'), '') + + +class TestPackageTestCase(unittest.TestCase, TestCaseMixin): + + def test_init__default_args(self): + test_pkg = TestPackage('temp') + self.assertEquals(test_pkg.name, 'temp') + subs = test_pkg.subs + self.assertEquals(len(subs), 1) + actual_sub = subs[0] + expected_sub = TestModule('__init__') + self.assertEquals(actual_sub, expected_sub) + + def test_init(self): + test_pkg = TestPackage('temp', init_src='# code', + subs=['mod1', TestModule('mod2')]) + self.assertEquals(test_pkg.name, 'temp') + subs = test_pkg.subs + self.assertEquals(len(subs), 3) + sub1, sub2, sub3 = subs + self.assertEquals(sub1, TestModule('__init__', src='# code')) + self.assertEquals(sub2, TestModule('mod1')) + self.assertEquals(sub3, TestModule('mod2')) + + +def test_main(): + tests = [CreateFileTestCase, + NamespaceTestCase, + TestFileTestCase, + TestModuleTestCase, + TestDirTestCase, + TestPackageTestCase] + support.run_unittest(*tests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -9,9 +9,9 @@ import py_compile from test.support import ( forget, make_legacy_pyc, run_unittest, unload, verbose, no_tracing, - create_empty_file) + TestModule, TestPackage) from test.script_helper import ( - make_pkg, make_script, make_zip_pkg, make_zip_script, temp_dir) + make_script, make_zip_pkg, make_zip_script, temp_dir) import runpy @@ -176,31 +176,26 @@ def test_library_module(self): self.assertEqual(run_module("runpy")["__name__"], "runpy") - def _add_pkg_dir(self, pkg_dir): - os.mkdir(pkg_dir) - pkg_fname = os.path.join(pkg_dir, "__init__.py") - create_empty_file(pkg_fname) - return pkg_fname - def _make_pkg(self, source, depth, mod_base="runpy_test"): pkg_name = "__runpy_pkg__" - test_fname = mod_base+os.extsep+"py" - pkg_dir = sub_dir = os.path.realpath(tempfile.mkdtemp()) - if verbose > 1: print(" Package tree in:", sub_dir) - sys.path.insert(0, pkg_dir) + parent_dir = os.path.realpath(tempfile.mkdtemp()) + if verbose > 1: print(" Package tree in:", parent_dir) + sys.path.insert(0, parent_dir) if verbose > 1: print(" Updated sys.path:", sys.path[0]) + + sub_dir = parent_dir for i in range(depth): - sub_dir = os.path.join(sub_dir, pkg_name) - pkg_fname = self._add_pkg_dir(sub_dir) - if verbose > 1: print(" Next level in:", sub_dir) - if verbose > 1: print(" Created:", pkg_fname) - mod_fname = os.path.join(sub_dir, test_fname) - mod_file = open(mod_fname, "w") - mod_file.write(source) - mod_file.close() + pkg = TestPackage(pkg_name) + sub_dir = pkg.write(parent_dir=sub_dir) + if verbose > 1: print(" Created next level in:", sub_dir) + + mod = TestModule(mod_base, src=source) + mod_fname = mod.write(parent_dir=sub_dir) if verbose > 1: print(" Created:", mod_fname) - mod_name = (pkg_name+".")*depth + mod_base - return pkg_dir, mod_fname, mod_name + + mod_name = ".".join(depth * [pkg_name] + [mod_base]) + + return parent_dir, mod_fname, mod_name def _del_pkg(self, top, depth, mod_name): for entry in list(sys.modules): @@ -303,7 +298,7 @@ self._del_pkg(pkg_dir, depth, pkg_name) if verbose > 1: print("Package executed successfully") - def _add_relative_modules(self, base_dir, source, depth): + def _add_relative_modules(self, base_dir, depth): if depth <= 1: raise ValueError("Relative module test needs depth > 1") pkg_name = "__runpy_pkg__" @@ -311,20 +306,13 @@ for i in range(depth): parent_dir = module_dir module_dir = os.path.join(module_dir, pkg_name) - # Add sibling module - sibling_fname = os.path.join(module_dir, "sibling.py") - create_empty_file(sibling_fname) + mod = TestModule("sibling") + sibling_fname = mod.write(parent_dir=module_dir) if verbose > 1: print(" Added sibling module:", sibling_fname) - # Add nephew module - uncle_dir = os.path.join(parent_dir, "uncle") - self._add_pkg_dir(uncle_dir) + cousin_pkg = TestPackage("cousin", subs=['nephew']) + uncle_pkg = TestPackage("uncle", subs=[cousin_pkg]) + uncle_dir = uncle_pkg.write(parent_dir=parent_dir) if verbose > 1: print(" Added uncle package:", uncle_dir) - cousin_dir = os.path.join(uncle_dir, "cousin") - self._add_pkg_dir(cousin_dir) - if verbose > 1: print(" Added cousin package:", cousin_dir) - nephew_fname = os.path.join(cousin_dir, "nephew.py") - create_empty_file(nephew_fname) - if verbose > 1: print(" Added nephew module:", nephew_fname) def _check_relative_imports(self, depth, run_name=None): contents = r"""\ @@ -339,7 +327,7 @@ else: expected_name = run_name try: - self._add_relative_modules(pkg_dir, contents, depth) + self._add_relative_modules(pkg_dir, depth) pkg_name = mod_name.rpartition('.')[0] if verbose > 1: print("Running from source:", mod_name) d1 = run_module(mod_name, run_name=run_name) # Read from source @@ -438,7 +426,7 @@ self._make_pkg("", max_depth)) self.addCleanup(self._del_pkg, pkg_dir, max_depth, mod_name) for depth in range(2, max_depth+1): - self._add_relative_modules(pkg_dir, "", depth) + self._add_relative_modules(pkg_dir, depth) for finder, mod_name, ispkg in pkgutil.walk_packages([pkg_dir]): self.assertIsInstance(finder, importlib.machinery.FileFinder)