test_runpy.py 8.78 KB
Newer Older
1 2 3 4 5 6
# Test the runpy module
import unittest
import os
import os.path
import sys
import tempfile
7
from test.test_support import verbose, run_unittest, forget
8
from runpy import _run_code, _run_module_code, _run_module_as_main, run_module
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

# Set up the test code and expected results

class RunModuleCodeTest(unittest.TestCase):

    expected_result = ["Top level assignment", "Lower level reference"]
    test_source = (
        "# Check basic code execution\n"
        "result = ['Top level assignment']\n"
        "def f():\n"
        "    result.append('Lower level reference')\n"
        "f()\n"
        "# Check the sys module\n"
        "import sys\n"
        "run_argv0 = sys.argv[0]\n"
24 25 26
        "run_name_in_sys_modules = __name__ in sys.modules\n"
        "if run_name_in_sys_modules:\n"
        "   module_in_sys_modules = globals() is sys.modules[__name__].__dict__\n"
27 28
        "# Check nested operation\n"
        "import runpy\n"
29
        "nested = runpy._run_module_code('x=1\\n', mod_name='<run>')\n"
30 31
    )

32 33 34 35 36 37 38 39 40 41
    def test_run_code(self):
        saved_argv0 = sys.argv[0]
        d = _run_code(self.test_source, {})
        self.failUnless(d["result"] == self.expected_result)
        self.failUnless(d["__name__"] is None)
        self.failUnless(d["__file__"] is None)
        self.failUnless(d["__loader__"] is None)
        self.failUnless(d["run_argv0"] is saved_argv0)
        self.failUnless("run_name" not in d)
        self.failUnless(sys.argv[0] is saved_argv0)
42 43 44

    def test_run_module_code(self):
        initial = object()
45
        name = "<Nonsense>"
46 47 48 49
        file = "Some other nonsense"
        loader = "Now you're just being silly"
        d1 = dict(initial=initial)
        saved_argv0 = sys.argv[0]
50 51 52 53
        d2 = _run_module_code(self.test_source,
                              d1,
                              name,
                              file,
54
                              loader)
55 56 57 58 59 60 61 62 63 64 65 66
        self.failUnless("result" not in d1)
        self.failUnless(d2["initial"] is initial)
        self.failUnless(d2["result"] == self.expected_result)
        self.failUnless(d2["nested"]["x"] == 1)
        self.failUnless(d2["__name__"] is name)
        self.failUnless(d2["run_name_in_sys_modules"])
        self.failUnless(d2["module_in_sys_modules"])
        self.failUnless(d2["__file__"] is file)
        self.failUnless(d2["run_argv0"] is file)
        self.failUnless(d2["__loader__"] is loader)
        self.failUnless(sys.argv[0] is saved_argv0)
        self.failUnless(name not in sys.modules)
67 68 69 70 71 72 73 74 75 76 77 78 79


class RunModuleTest(unittest.TestCase):

    def expect_import_error(self, mod_name):
        try:
            run_module(mod_name)
        except ImportError:
            pass
        else:
            self.fail("Expected import error for " + mod_name)

    def test_invalid_names(self):
80
        # Builtin module
81
        self.expect_import_error("sys")
82
        # Non-existent modules
83 84 85 86 87
        self.expect_import_error("sys.imp.eric")
        self.expect_import_error("os.path.half")
        self.expect_import_error("a.bee")
        self.expect_import_error(".howard")
        self.expect_import_error("..eaten")
88 89
        # Package
        self.expect_import_error("logging")
90 91 92 93

    def test_library_module(self):
        run_module("runpy")

94 95 96 97 98 99 100
    def _add_pkg_dir(self, pkg_dir):
        os.mkdir(pkg_dir)
        pkg_fname = os.path.join(pkg_dir, "__init__"+os.extsep+"py")
        pkg_file = open(pkg_fname, "w")
        pkg_file.close()
        return pkg_fname

101 102 103 104 105 106 107 108 109
    def _make_pkg(self, source, depth):
        pkg_name = "__runpy_pkg__"
        test_fname = "runpy_test"+os.extsep+"py"
        pkg_dir = sub_dir = tempfile.mkdtemp()
        if verbose: print "  Package tree in:", sub_dir
        sys.path.insert(0, pkg_dir)
        if verbose: print "  Updated sys.path:", sys.path[0]
        for i in range(depth):
            sub_dir = os.path.join(sub_dir, pkg_name)
110
            pkg_fname = self._add_pkg_dir(sub_dir)
111 112 113 114 115 116 117 118 119 120 121
            if verbose: print "  Next level in:", sub_dir
            if verbose: 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()
        if verbose: print "  Created:", mod_fname
        mod_name = (pkg_name+".")*depth + "runpy_test"
        return pkg_dir, mod_fname, mod_name

    def _del_pkg(self, top, depth, mod_name):
122 123
        for entry in list(sys.modules):
            if entry.startswith("__runpy_pkg__"):
124
                del sys.modules[entry]
125 126 127
        if verbose: print "  Removed sys.modules entries"
        del sys.path[0]
        if verbose: print "  Removed sys.path entry"
128 129
        for root, dirs, files in os.walk(top, topdown=False):
            for name in files:
130 131 132 133
                try:
                    os.remove(os.path.join(root, name))
                except OSError, ex:
                    if verbose: print ex # Persist with cleaning up
134
            for name in dirs:
135 136 137 138 139 140 141 142 143 144
                fullname = os.path.join(root, name)
                try:
                    os.rmdir(fullname)
                except OSError, ex:
                    if verbose: print ex # Persist with cleaning up
        try:
            os.rmdir(top)
            if verbose: print "  Removed package tree"
        except OSError, ex:
            if verbose: print ex # Persist with cleaning up
145 146 147 148

    def _check_module(self, depth):
        pkg_dir, mod_fname, mod_name = (
               self._make_pkg("x=1\n", depth))
149
        forget(mod_name)
150 151 152
        try:
            if verbose: print "Running from source:", mod_name
            d1 = run_module(mod_name) # Read from source
153
            self.failUnless("x" in d1)
154 155
            self.failUnless(d1["x"] == 1)
            del d1 # Ensure __loader__ entry doesn't keep file open
156 157 158 159
            __import__(mod_name)
            os.remove(mod_fname)
            if verbose: print "Running from compiled:", mod_name
            d2 = run_module(mod_name) # Read from bytecode
160
            self.failUnless("x" in d2)
161 162
            self.failUnless(d2["x"] == 1)
            del d2 # Ensure __loader__ entry doesn't keep file open
163 164 165 166
        finally:
            self._del_pkg(pkg_dir, depth, mod_name)
        if verbose: print "Module executed successfully"

167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
    def _add_relative_modules(self, base_dir, depth):
        if depth <= 1:
            raise ValueError("Relative module test needs depth > 1")
        pkg_name = "__runpy_pkg__"
        module_dir = base_dir
        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"+os.extsep+"py")
        sibling_file = open(sibling_fname, "w")
        sibling_file.close()
        if verbose: print "  Added sibling module:", sibling_fname
        # Add nephew module
        uncle_dir = os.path.join(parent_dir, "uncle")
        self._add_pkg_dir(uncle_dir)
        if verbose: print "  Added uncle package:", uncle_dir
        cousin_dir = os.path.join(uncle_dir, "cousin")
        self._add_pkg_dir(cousin_dir)
        if verbose: print "  Added cousin package:", cousin_dir
        nephew_fname = os.path.join(cousin_dir, "nephew"+os.extsep+"py")
        nephew_file = open(nephew_fname, "w")
        nephew_file.close()
        if verbose: print "  Added nephew module:", nephew_fname

    def _check_relative_imports(self, depth, run_name=None):
        contents = """\
from __future__ import absolute_import
from . import sibling
from ..uncle.cousin import nephew
"""
        pkg_dir, mod_fname, mod_name = (
               self._make_pkg(contents, depth))
        try:
            self._add_relative_modules(pkg_dir, depth)
            if verbose: print "Running from source:", mod_name
            d1 = run_module(mod_name) # Read from source
            self.failUnless("sibling" in d1)
            self.failUnless("nephew" in d1)
            del d1 # Ensure __loader__ entry doesn't keep file open
            __import__(mod_name)
            os.remove(mod_fname)
            if verbose: print "Running from compiled:", mod_name
            d2 = run_module(mod_name) # Read from bytecode
            self.failUnless("sibling" in d2)
            self.failUnless("nephew" in d2)
            del d2 # Ensure __loader__ entry doesn't keep file open
        finally:
            self._del_pkg(pkg_dir, depth, mod_name)
        if verbose: print "Module executed successfully"

218 219 220 221 222
    def test_run_module(self):
        for depth in range(4):
            if verbose: print "Testing package depth:", depth
            self._check_module(depth)

223 224 225 226 227
    def test_explicit_relative_import(self):
        for depth in range(2, 5):
            if verbose: print "Testing relative imports at depth:", depth
            self._check_relative_imports(depth)

228 229

def test_main():
Tim Peters's avatar
Tim Peters committed
230 231
    run_unittest(RunModuleCodeTest)
    run_unittest(RunModuleTest)
232 233

if __name__ == "__main__":
Tim Peters's avatar
Tim Peters committed
234
    test_main()