1"""Tests for distutils.command.build_py."""
2
3import os
4import sys
5import unittest
6
7from distutils.command.build_py import build_py
8from distutils.core import Distribution
9from distutils.errors import DistutilsFileError
10
11from distutils.tests import support
12from test.support import run_unittest
13
14
15class BuildPyTestCase(support.TempdirManager,
16                      support.LoggingSilencer,
17                      unittest.TestCase):
18
19    def test_package_data(self):
20        sources = self.mkdtemp()
21        f = open(os.path.join(sources, "__init__.py"), "w")
22        try:
23            f.write("# Pretend this is a package.")
24        finally:
25            f.close()
26        f = open(os.path.join(sources, "README.txt"), "w")
27        try:
28            f.write("Info about this package")
29        finally:
30            f.close()
31
32        destination = self.mkdtemp()
33
34        dist = Distribution({"packages": ["pkg"],
35                             "package_dir": {"pkg": sources}})
36        # script_name need not exist, it just need to be initialized
37        dist.script_name = os.path.join(sources, "setup.py")
38        dist.command_obj["build"] = support.DummyCommand(
39            force=0,
40            build_lib=destination)
41        dist.packages = ["pkg"]
42        dist.package_data = {"pkg": ["README.txt"]}
43        dist.package_dir = {"pkg": sources}
44
45        cmd = build_py(dist)
46        cmd.compile = 1
47        cmd.ensure_finalized()
48        self.assertEqual(cmd.package_data, dist.package_data)
49
50        cmd.run()
51
52        # This makes sure the list of outputs includes byte-compiled
53        # files for Python modules but not for package data files
54        # (there shouldn't *be* byte-code files for those!).
55        self.assertEqual(len(cmd.get_outputs()), 3)
56        pkgdest = os.path.join(destination, "pkg")
57        files = os.listdir(pkgdest)
58        pycache_dir = os.path.join(pkgdest, "__pycache__")
59        self.assertIn("__init__.py", files)
60        self.assertIn("README.txt", files)
61        if sys.dont_write_bytecode:
62            self.assertFalse(os.path.exists(pycache_dir))
63        else:
64            pyc_files = os.listdir(pycache_dir)
65            self.assertIn("__init__.%s.pyc" % sys.implementation.cache_tag,
66                          pyc_files)
67
68    def test_empty_package_dir(self):
69        # See bugs #1668596/#1720897
70        sources = self.mkdtemp()
71        open(os.path.join(sources, "__init__.py"), "w").close()
72
73        testdir = os.path.join(sources, "doc")
74        os.mkdir(testdir)
75        open(os.path.join(testdir, "testfile"), "w").close()
76
77        os.chdir(sources)
78        dist = Distribution({"packages": ["pkg"],
79                             "package_dir": {"pkg": ""},
80                             "package_data": {"pkg": ["doc/*"]}})
81        # script_name need not exist, it just need to be initialized
82        dist.script_name = os.path.join(sources, "setup.py")
83        dist.script_args = ["build"]
84        dist.parse_command_line()
85
86        try:
87            dist.run_commands()
88        except DistutilsFileError:
89            self.fail("failed package_data test when package_dir is ''")
90
91    @unittest.skipIf(sys.dont_write_bytecode, 'byte-compile disabled')
92    def test_byte_compile(self):
93        project_dir, dist = self.create_dist(py_modules=['boiledeggs'])
94        os.chdir(project_dir)
95        self.write_file('boiledeggs.py', 'import antigravity')
96        cmd = build_py(dist)
97        cmd.compile = 1
98        cmd.build_lib = 'here'
99        cmd.finalize_options()
100        cmd.run()
101
102        found = os.listdir(cmd.build_lib)
103        self.assertEqual(sorted(found), ['__pycache__', 'boiledeggs.py'])
104        found = os.listdir(os.path.join(cmd.build_lib, '__pycache__'))
105        self.assertEqual(found,
106                         ['boiledeggs.%s.pyc' % sys.implementation.cache_tag])
107
108    @unittest.skipIf(sys.dont_write_bytecode, 'byte-compile disabled')
109    def test_byte_compile_optimized(self):
110        project_dir, dist = self.create_dist(py_modules=['boiledeggs'])
111        os.chdir(project_dir)
112        self.write_file('boiledeggs.py', 'import antigravity')
113        cmd = build_py(dist)
114        cmd.compile = 0
115        cmd.optimize = 1
116        cmd.build_lib = 'here'
117        cmd.finalize_options()
118        cmd.run()
119
120        found = os.listdir(cmd.build_lib)
121        self.assertEqual(sorted(found), ['__pycache__', 'boiledeggs.py'])
122        found = os.listdir(os.path.join(cmd.build_lib, '__pycache__'))
123        expect = 'boiledeggs.{}.opt-1.pyc'.format(sys.implementation.cache_tag)
124        self.assertEqual(sorted(found), [expect])
125
126    def test_dir_in_package_data(self):
127        """
128        A directory in package_data should not be added to the filelist.
129        """
130        # See bug 19286
131        sources = self.mkdtemp()
132        pkg_dir = os.path.join(sources, "pkg")
133
134        os.mkdir(pkg_dir)
135        open(os.path.join(pkg_dir, "__init__.py"), "w").close()
136
137        docdir = os.path.join(pkg_dir, "doc")
138        os.mkdir(docdir)
139        open(os.path.join(docdir, "testfile"), "w").close()
140
141        # create the directory that could be incorrectly detected as a file
142        os.mkdir(os.path.join(docdir, 'otherdir'))
143
144        os.chdir(sources)
145        dist = Distribution({"packages": ["pkg"],
146                             "package_data": {"pkg": ["doc/*"]}})
147        # script_name need not exist, it just need to be initialized
148        dist.script_name = os.path.join(sources, "setup.py")
149        dist.script_args = ["build"]
150        dist.parse_command_line()
151
152        try:
153            dist.run_commands()
154        except DistutilsFileError:
155            self.fail("failed package_data when data dir includes a dir")
156
157    def test_dont_write_bytecode(self):
158        # makes sure byte_compile is not used
159        dist = self.create_dist()[1]
160        cmd = build_py(dist)
161        cmd.compile = 1
162        cmd.optimize = 1
163
164        old_dont_write_bytecode = sys.dont_write_bytecode
165        sys.dont_write_bytecode = True
166        try:
167            cmd.byte_compile([])
168        finally:
169            sys.dont_write_bytecode = old_dont_write_bytecode
170
171        self.assertIn('byte-compiling is disabled',
172                      self.logs[0][1] % self.logs[0][2])
173
174
175def test_suite():
176    return unittest.makeSuite(BuildPyTestCase)
177
178if __name__ == "__main__":
179    run_unittest(test_suite())
180