[Python-checkins] cpython (merge 2.7 -> 2.7): Branch merge

eric.araujo python-checkins at python.org
Fri Aug 26 16:37:41 CEST 2011


http://hg.python.org/cpython/rev/4493ac4c1287
changeset:   72094:4493ac4c1287
branch:      2.7
parent:      72076:498b03a55297
parent:      72093:993bccb490c7
user:        Éric Araujo <merwok at netwok.org>
date:        Fri Aug 26 16:32:36 2011 +0200
summary:
  Branch merge

files:
  Doc/ACKS.txt                          |    1 +
  Doc/distutils/apiref.rst              |   61 ++--
  Lib/distutils/tests/support.py        |   76 +++++
  Lib/distutils/tests/test_build_ext.py |  104 +++----
  Lib/distutils/tests/test_install.py   |  195 +++++++++++++-
  Lib/distutils/tests/test_sdist.py     |    1 +
  Lib/shutil.py                         |    3 +-
  7 files changed, 351 insertions(+), 90 deletions(-)


diff --git a/Doc/ACKS.txt b/Doc/ACKS.txt
--- a/Doc/ACKS.txt
+++ b/Doc/ACKS.txt
@@ -183,6 +183,7 @@
    * Joakim Sernbrant
    * Justin Sheehy
    * Charlie Shepherd
+   * Yue Shuaijie
    * Michael Simcich
    * Ionel Simionescu
    * Michael Sloan
diff --git a/Doc/distutils/apiref.rst b/Doc/distutils/apiref.rst
--- a/Doc/distutils/apiref.rst
+++ b/Doc/distutils/apiref.rst
@@ -31,8 +31,9 @@
    +====================+================================+=============================================================+
    | *name*             | The name of the package        | a string                                                    |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *version*          | The version number of the      | See :mod:`distutils.version`                                |
-   |                    | package                        |                                                             |
+   | *version*          | The version number of the      | a string                                                    |
+   |                    | package; see                   |                                                             |
+   |                    | :mod:`distutils.version`       |                                                             |
    +--------------------+--------------------------------+-------------------------------------------------------------+
    | *description*      | A single line describing the   | a string                                                    |
    |                    | package                        |                                                             |
@@ -49,14 +50,14 @@
    |                    | maintainer, if different from  |                                                             |
    |                    | the author                     |                                                             |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *maintainer_email* | The email address of the       |                                                             |
+   | *maintainer_email* | The email address of the       | a string                                                    |
    |                    | current maintainer, if         |                                                             |
    |                    | different from the author      |                                                             |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *url*              | A URL for the package          | a URL                                                       |
+   | *url*              | A URL for the package          | a string                                                    |
    |                    | (homepage)                     |                                                             |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *download_url*     | A URL to download the package  | a URL                                                       |
+   | *download_url*     | A URL to download the package  | a string                                                    |
    +--------------------+--------------------------------+-------------------------------------------------------------+
    | *packages*         | A list of Python packages that | a list of strings                                           |
    |                    | distutils will manipulate      |                                                             |
@@ -68,14 +69,13 @@
    |                    | files to be built and          |                                                             |
    |                    | installed                      |                                                             |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *ext_modules*      | A list of Python extensions to | A list of  instances of                                     |
+   | *ext_modules*      | A list of Python extensions to | a list of instances of                                      |
    |                    | be built                       | :class:`distutils.core.Extension`                           |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *classifiers*      | A list of categories for the   | The list of available                                       |
-   |                    | package                        | categorizations is available on `PyPI                       |
-   |                    |                                | <http://pypi.python.org/pypi?:action=list_classifiers>`_.   |
+   | *classifiers*      | A list of categories for the   | a list of strings; valid classifiers are listed on `PyPI    |
+   |                    | package                        | <http://pypi.python.org/pypi?:action=list_classifiers>`_.   |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *distclass*        | the :class:`Distribution`      | A subclass of                                               |
+   | *distclass*        | the :class:`Distribution`      | a subclass of                                               |
    |                    | class to use                   | :class:`distutils.core.Distribution`                        |
    +--------------------+--------------------------------+-------------------------------------------------------------+
    | *script_name*      | The name of the setup.py       | a string                                                    |
@@ -85,15 +85,15 @@
    | *script_args*      | Arguments to supply to the     | a list of strings                                           |
    |                    | setup script                   |                                                             |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *options*          | default options for the setup  | a string                                                    |
+   | *options*          | default options for the setup  | a dictionary                                                |
    |                    | script                         |                                                             |
    +--------------------+--------------------------------+-------------------------------------------------------------+
    | *license*          | The license for the package    | a string                                                    |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *keywords*         | Descriptive meta-data, see     |                                                             |
+   | *keywords*         | Descriptive meta-data, see     | a list of strings or a comma-separated string               |
    |                    | :pep:`314`                     |                                                             |
    +--------------------+--------------------------------+-------------------------------------------------------------+
-   | *platforms*        |                                |                                                             |
+   | *platforms*        |                                | a list of strings or a comma-separated string               |
    +--------------------+--------------------------------+-------------------------------------------------------------+
    | *cmdclass*         | A mapping of command names to  | a dictionary                                                |
    |                    | :class:`Command` subclasses    |                                                             |
@@ -165,13 +165,13 @@
    +------------------------+--------------------------------+---------------------------+
    | argument name          | value                          | type                      |
    +========================+================================+===========================+
-   | *name*                 | the full name of the           | string                    |
+   | *name*                 | the full name of the           | a string                  |
    |                        | extension, including any       |                           |
    |                        | packages --- ie. *not* a       |                           |
    |                        | filename or pathname, but      |                           |
    |                        | Python dotted name             |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *sources*              | list of source filenames,      | string                    |
+   | *sources*              | list of source filenames,      | a list of strings         |
    |                        | relative to the distribution   |                           |
    |                        | root (where the setup script   |                           |
    |                        | lives), in Unix form (slash-   |                           |
@@ -184,12 +184,12 @@
    |                        | as source for a Python         |                           |
    |                        | extension.                     |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *include_dirs*         | list of directories to search  | string                    |
+   | *include_dirs*         | list of directories to search  | a list of strings         |
    |                        | for C/C++ header files (in     |                           |
    |                        | Unix form for portability)     |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *define_macros*        | list of macros to define; each | (string, string) tuple or |
-   |                        | macro is defined using a       | (name, ``None``)          |
+   | *define_macros*        | list of macros to define; each | a list of tuples          |
+   |                        | macro is defined using a       |                           |
    |                        | 2-tuple ``(name, value)``,     |                           |
    |                        | where *value* is               |                           |
    |                        | either the string to define it |                           |
@@ -200,31 +200,31 @@
    |                        | on Unix C compiler command     |                           |
    |                        | line)                          |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *undef_macros*         | list of macros to undefine     | string                    |
+   | *undef_macros*         | list of macros to undefine     | a list of strings         |
    |                        | explicitly                     |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *library_dirs*         | list of directories to search  | string                    |
+   | *library_dirs*         | list of directories to search  | a list of strings         |
    |                        | for C/C++ libraries at link    |                           |
    |                        | time                           |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *libraries*            | list of library names (not     | string                    |
+   | *libraries*            | list of library names (not     | a list of strings         |
    |                        | filenames or paths) to link    |                           |
    |                        | against                        |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *runtime_library_dirs* | list of directories to search  | string                    |
+   | *runtime_library_dirs* | list of directories to search  | a list of strings         |
    |                        | for C/C++ libraries at run     |                           |
    |                        | time (for shared extensions,   |                           |
    |                        | this is when the extension is  |                           |
    |                        | loaded)                        |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *extra_objects*        | list of extra files to link    | string                    |
+   | *extra_objects*        | list of extra files to link    | a list of strings         |
    |                        | with (eg. object files not     |                           |
    |                        | implied by 'sources', static   |                           |
    |                        | library that must be           |                           |
    |                        | explicitly specified, binary   |                           |
    |                        | resource files, etc.)          |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *extra_compile_args*   | any extra platform- and        | string                    |
+   | *extra_compile_args*   | any extra platform- and        | a list of strings         |
    |                        | compiler-specific information  |                           |
    |                        | to use when compiling the      |                           |
    |                        | source files in 'sources'. For |                           |
@@ -235,7 +235,7 @@
    |                        | for other platforms it could   |                           |
    |                        | be anything.                   |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *extra_link_args*      | any extra platform- and        | string                    |
+   | *extra_link_args*      | any extra platform- and        | a list of strings         |
    |                        | compiler-specific information  |                           |
    |                        | to use when linking object     |                           |
    |                        | files together to create the   |                           |
@@ -244,7 +244,7 @@
    |                        | Similar interpretation as for  |                           |
    |                        | 'extra_compile_args'.          |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *export_symbols*       | list of symbols to be exported | string                    |
+   | *export_symbols*       | list of symbols to be exported | a list of strings         |
    |                        | from a shared extension. Not   |                           |
    |                        | used on all platforms, and not |                           |
    |                        | generally necessary for Python |                           |
@@ -252,15 +252,20 @@
    |                        | export exactly one symbol:     |                           |
    |                        | ``init`` + extension_name.     |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *depends*              | list of files that the         | string                    |
+   | *depends*              | list of files that the         | a list of strings         |
    |                        | extension depends on           |                           |
    +------------------------+--------------------------------+---------------------------+
-   | *language*             | extension language (i.e.       | string                    |
+   | *language*             | extension language (i.e.       | a string                  |
    |                        | ``'c'``, ``'c++'``,            |                           |
    |                        | ``'objc'``). Will be detected  |                           |
    |                        | from the source extensions if  |                           |
    |                        | not provided.                  |                           |
    +------------------------+--------------------------------+---------------------------+
+   | *optional*             | specifies that a build failure | a boolean                 |
+   |                        | in the extension should not    |                           |
+   |                        | abort the build process, but   |                           |
+   |                        | simply skip the extension.     |                           |
+   +------------------------+--------------------------------+---------------------------+
 
 
 .. class:: Distribution
diff --git a/Lib/distutils/tests/support.py b/Lib/distutils/tests/support.py
--- a/Lib/distutils/tests/support.py
+++ b/Lib/distutils/tests/support.py
@@ -1,7 +1,10 @@
 """Support code for distutils test cases."""
 import os
+import sys
 import shutil
 import tempfile
+import unittest
+import sysconfig
 from copy import deepcopy
 import warnings
 
@@ -9,6 +12,7 @@
 from distutils.log import DEBUG, INFO, WARN, ERROR, FATAL
 from distutils.core import Distribution
 
+
 def capture_warnings(func):
     def _capture_warnings(*args, **kw):
         with warnings.catch_warnings():
@@ -16,6 +20,7 @@
             return func(*args, **kw)
     return _capture_warnings
 
+
 class LoggingSilencer(object):
 
     def setUp(self):
@@ -49,6 +54,7 @@
     def clear_logs(self):
         self.logs = []
 
+
 class TempdirManager(object):
     """Mix-in class that handles temporary directories for test cases.
 
@@ -105,6 +111,7 @@
 
         return pkg_dir, dist
 
+
 class DummyCommand:
     """Class to store options for retrieval via set_undefined_options()."""
 
@@ -115,6 +122,7 @@
     def ensure_finalized(self):
         pass
 
+
 class EnvironGuard(object):
 
     def setUp(self):
@@ -131,3 +139,71 @@
                 del os.environ[key]
 
         super(EnvironGuard, self).tearDown()
+
+
+def copy_xxmodule_c(directory):
+    """Helper for tests that need the xxmodule.c source file.
+
+    Example use:
+
+        def test_compile(self):
+            copy_xxmodule_c(self.tmpdir)
+            self.assertIn('xxmodule.c', os.listdir(self.tmpdir))
+
+    If the source file can be found, it will be copied to *directory*.  If not,
+    the test will be skipped.  Errors during copy are not caught.
+    """
+    filename = _get_xxmodule_path()
+    if filename is None:
+        raise unittest.SkipTest('cannot find xxmodule.c (test must run in '
+                                'the python build dir)')
+    shutil.copy(filename, directory)
+
+
+def _get_xxmodule_path():
+    srcdir = sysconfig.get_config_var('srcdir')
+    candidates = [
+        # use installed copy if available
+        os.path.join(os.path.dirname(__file__), 'xxmodule.c'),
+        # otherwise try using copy from build directory
+        os.path.join(srcdir, 'Modules', 'xxmodule.c'),
+        # srcdir mysteriously can be $srcdir/Lib/distutils/tests when
+        # this file is run from its parent directory, so walk up the
+        # tree to find the real srcdir
+        os.path.join(srcdir, '..', '..', '..', 'Modules', 'xxmodule.c'),
+    ]
+    for path in candidates:
+        if os.path.exists(path):
+            return path
+
+
+def fixup_build_ext(cmd):
+    """Function needed to make build_ext tests pass.
+
+    When Python was build with --enable-shared on Unix, -L. is not good
+    enough to find the libpython<blah>.so.  This is because regrtest runs
+    it under a tempdir, not in the top level where the .so lives.  By the
+    time we've gotten here, Python's already been chdir'd to the tempdir.
+
+    When Python was built with in debug mode on Windows, build_ext commands
+    need their debug attribute set, and it is not done automatically for
+    some reason.
+
+    This function handles both of these things.  Example use:
+
+        cmd = build_ext(dist)
+        support.fixup_build_ext(cmd)
+        cmd.ensure_finalized()
+    """
+    if os.name == 'nt':
+        cmd.debug = sys.executable.endswith('_d.exe')
+    elif sysconfig.get_config_var('Py_ENABLE_SHARED'):
+        # To further add to the shared builds fun on Unix, we can't just add
+        # library_dirs to the Extension() instance because that doesn't get
+        # plumbed through to the final compiler command.
+        runshared = sysconfig.get_config_var('RUNSHARED')
+        if runshared is None:
+            cmd.library_dirs = ['.']
+        else:
+            name, equals, value = runshared.partition('=')
+            cmd.library_dirs = value.split(os.pathsep)
diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py
--- a/Lib/distutils/tests/test_build_ext.py
+++ b/Lib/distutils/tests/test_build_ext.py
@@ -1,7 +1,5 @@
 import sys
 import os
-import tempfile
-import shutil
 from StringIO import StringIO
 import textwrap
 
@@ -19,76 +17,40 @@
 # Don't load the xx module more than once.
 ALREADY_TESTED = False
 
-def _get_source_filename():
-    # use installed copy if available
-    tests_f = os.path.join(os.path.dirname(__file__), 'xxmodule.c')
-    if os.path.exists(tests_f):
-        return tests_f
-    # otherwise try using copy from build directory
-    srcdir = sysconfig.get_config_var('srcdir')
-    if srcdir is None:
-        return os.path.join(sysconfig.project_base, 'Modules', 'xxmodule.c')
-    return os.path.join(srcdir, 'Modules', 'xxmodule.c')
-
-_XX_MODULE_PATH = _get_source_filename()
 
 class BuildExtTestCase(support.TempdirManager,
                        support.LoggingSilencer,
                        unittest.TestCase):
     def setUp(self):
-        # Create a simple test environment
-        # Note that we're making changes to sys.path
         super(BuildExtTestCase, self).setUp()
-        self.tmp_dir = tempfile.mkdtemp(prefix="pythontest_")
-        if os.path.exists(_XX_MODULE_PATH):
-            self.sys_path = sys.path[:]
-            sys.path.append(self.tmp_dir)
-            shutil.copy(_XX_MODULE_PATH, self.tmp_dir)
+        self.tmp_dir = self.mkdtemp()
+        self.xx_created = False
+        sys.path.append(self.tmp_dir)
+        self.addCleanup(sys.path.remove, self.tmp_dir)
+        if sys.version > "2.6":
+            import site
+            self.old_user_base = site.USER_BASE
+            site.USER_BASE = self.mkdtemp()
+            from distutils.command import build_ext
+            build_ext.USER_BASE = site.USER_BASE
 
     def tearDown(self):
-        # Get everything back to normal
-        if os.path.exists(_XX_MODULE_PATH):
+        if self.xx_created:
             test_support.unload('xx')
-            sys.path[:] = self.sys_path
             # XXX on Windows the test leaves a directory
             # with xx module in TEMP
-        shutil.rmtree(self.tmp_dir, os.name == 'nt' or
-                                    sys.platform == 'cygwin')
         super(BuildExtTestCase, self).tearDown()
 
-    def _fixup_command(self, cmd):
-        # When Python was build with --enable-shared, -L. is not good enough
-        # to find the libpython<blah>.so.  This is because regrtest runs it
-        # under a tempdir, not in the top level where the .so lives.  By the
-        # time we've gotten here, Python's already been chdir'd to the
-        # tempdir.
-        #
-        # To further add to the fun, we can't just add library_dirs to the
-        # Extension() instance because that doesn't get plumbed through to the
-        # final compiler command.
-        if (sysconfig.get_config_var('Py_ENABLE_SHARED') and
-            not sys.platform.startswith('win')):
-            runshared = sysconfig.get_config_var('RUNSHARED')
-            if runshared is None:
-                cmd.library_dirs = ['.']
-            else:
-                name, equals, value = runshared.partition('=')
-                cmd.library_dirs = value.split(os.pathsep)
-
-    @unittest.skipIf(not os.path.exists(_XX_MODULE_PATH),
-                     'xxmodule.c not found')
     def test_build_ext(self):
         global ALREADY_TESTED
+        support.copy_xxmodule_c(self.tmp_dir)
+        self.xx_created = True
         xx_c = os.path.join(self.tmp_dir, 'xxmodule.c')
         xx_ext = Extension('xx', [xx_c])
         dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]})
         dist.package_dir = self.tmp_dir
         cmd = build_ext(dist)
-        self._fixup_command(cmd)
-        if os.name == "nt":
-            # On Windows, we must build a debug version iff running
-            # a debug build of Python
-            cmd.debug = sys.executable.endswith("_d.exe")
+        support.fixup_build_ext(cmd)
         cmd.build_lib = self.tmp_dir
         cmd.build_temp = self.tmp_dir
 
@@ -141,6 +103,36 @@
         # make sure we get some library dirs under solaris
         self.assertTrue(len(cmd.library_dirs) > 0)
 
+    def test_user_site(self):
+        # site.USER_SITE was introduced in 2.6
+        if sys.version < '2.6':
+            return
+
+        import site
+        dist = Distribution({'name': 'xx'})
+        cmd = build_ext(dist)
+
+        # making sure the user option is there
+        options = [name for name, short, label in
+                   cmd.user_options]
+        self.assertIn('user', options)
+
+        # setting a value
+        cmd.user = 1
+
+        # setting user based lib and include
+        lib = os.path.join(site.USER_BASE, 'lib')
+        incl = os.path.join(site.USER_BASE, 'include')
+        os.mkdir(lib)
+        os.mkdir(incl)
+
+        cmd.ensure_finalized()
+
+        # see if include_dirs and library_dirs were set
+        self.assertIn(lib, cmd.library_dirs)
+        self.assertIn(lib, cmd.rpath)
+        self.assertIn(incl, cmd.include_dirs)
+
     def test_finalize_options(self):
         # Make sure Python's include directories (for Python.h, pyconfig.h,
         # etc.) are in the include search path.
@@ -149,7 +141,6 @@
         cmd = build_ext(dist)
         cmd.finalize_options()
 
-        from distutils import sysconfig
         py_include = sysconfig.get_python_inc()
         self.assertTrue(py_include in cmd.include_dirs)
 
@@ -277,13 +268,10 @@
         dist = Distribution({'name': 'xx',
                              'ext_modules': [ext]})
         cmd = build_ext(dist)
-        self._fixup_command(cmd)
+        support.fixup_build_ext(cmd)
         cmd.ensure_finalized()
         self.assertEqual(len(cmd.get_outputs()), 1)
 
-        if os.name == "nt":
-            cmd.debug = sys.executable.endswith("_d.exe")
-
         cmd.build_lib = os.path.join(self.tmp_dir, 'build')
         cmd.build_temp = os.path.join(self.tmp_dir, 'tempt')
 
@@ -509,10 +497,8 @@
         cmd.build_temp = self.tmp_dir
 
         try:
-            old_stdout = sys.stdout
             cmd.ensure_finalized()
             cmd.run()
-
         except CompileError:
             self.fail("Wrong deployment target during compilation")
 
diff --git a/Lib/distutils/tests/test_install.py b/Lib/distutils/tests/test_install.py
--- a/Lib/distutils/tests/test_install.py
+++ b/Lib/distutils/tests/test_install.py
@@ -1,17 +1,33 @@
 """Tests for distutils.command.install."""
 
 import os
+import sys
 import unittest
+import site
 
-from test.test_support import run_unittest
+from test.test_support import captured_stdout, run_unittest
 
+from distutils import sysconfig
 from distutils.command.install import install
+from distutils.command import install as install_module
+from distutils.command.build_ext import build_ext
+from distutils.command.install import INSTALL_SCHEMES
 from distutils.core import Distribution
+from distutils.errors import DistutilsOptionError
+from distutils.extension import Extension
 
 from distutils.tests import support
 
 
-class InstallTestCase(support.TempdirManager, unittest.TestCase):
+def _make_ext_name(modname):
+    if os.name == 'nt' and sys.executable.endswith('_d.exe'):
+        modname += '_d'
+    return modname + sysconfig.get_config_var('SO')
+
+
+class InstallTestCase(support.TempdirManager,
+                      support.LoggingSilencer,
+                      unittest.TestCase):
 
     def test_home_installation_scheme(self):
         # This ensure two things:
@@ -49,6 +65,181 @@
         check_path(cmd.install_scripts, os.path.join(destination, "bin"))
         check_path(cmd.install_data, destination)
 
+    def test_user_site(self):
+        # site.USER_SITE was introduced in 2.6
+        if sys.version < '2.6':
+            return
+
+        # preparing the environment for the test
+        self.old_user_base = site.USER_BASE
+        self.old_user_site = site.USER_SITE
+        self.tmpdir = self.mkdtemp()
+        self.user_base = os.path.join(self.tmpdir, 'B')
+        self.user_site = os.path.join(self.tmpdir, 'S')
+        site.USER_BASE = self.user_base
+        site.USER_SITE = self.user_site
+        install_module.USER_BASE = self.user_base
+        install_module.USER_SITE = self.user_site
+
+        def _expanduser(path):
+            return self.tmpdir
+        self.old_expand = os.path.expanduser
+        os.path.expanduser = _expanduser
+
+        try:
+            # this is the actual test
+            self._test_user_site()
+        finally:
+            site.USER_BASE = self.old_user_base
+            site.USER_SITE = self.old_user_site
+            install_module.USER_BASE = self.old_user_base
+            install_module.USER_SITE = self.old_user_site
+            os.path.expanduser = self.old_expand
+
+    def _test_user_site(self):
+        for key in ('nt_user', 'unix_user', 'os2_home'):
+            self.assertTrue(key in INSTALL_SCHEMES)
+
+        dist = Distribution({'name': 'xx'})
+        cmd = install(dist)
+
+        # making sure the user option is there
+        options = [name for name, short, lable in
+                   cmd.user_options]
+        self.assertTrue('user' in options)
+
+        # setting a value
+        cmd.user = 1
+
+        # user base and site shouldn't be created yet
+        self.assertTrue(not os.path.exists(self.user_base))
+        self.assertTrue(not os.path.exists(self.user_site))
+
+        # let's run finalize
+        cmd.ensure_finalized()
+
+        # now they should
+        self.assertTrue(os.path.exists(self.user_base))
+        self.assertTrue(os.path.exists(self.user_site))
+
+        self.assertTrue('userbase' in cmd.config_vars)
+        self.assertTrue('usersite' in cmd.config_vars)
+
+    def test_handle_extra_path(self):
+        dist = Distribution({'name': 'xx', 'extra_path': 'path,dirs'})
+        cmd = install(dist)
+
+        # two elements
+        cmd.handle_extra_path()
+        self.assertEqual(cmd.extra_path, ['path', 'dirs'])
+        self.assertEqual(cmd.extra_dirs, 'dirs')
+        self.assertEqual(cmd.path_file, 'path')
+
+        # one element
+        cmd.extra_path = ['path']
+        cmd.handle_extra_path()
+        self.assertEqual(cmd.extra_path, ['path'])
+        self.assertEqual(cmd.extra_dirs, 'path')
+        self.assertEqual(cmd.path_file, 'path')
+
+        # none
+        dist.extra_path = cmd.extra_path = None
+        cmd.handle_extra_path()
+        self.assertEqual(cmd.extra_path, None)
+        self.assertEqual(cmd.extra_dirs, '')
+        self.assertEqual(cmd.path_file, None)
+
+        # three elements (no way !)
+        cmd.extra_path = 'path,dirs,again'
+        self.assertRaises(DistutilsOptionError, cmd.handle_extra_path)
+
+    def test_finalize_options(self):
+        dist = Distribution({'name': 'xx'})
+        cmd = install(dist)
+
+        # must supply either prefix/exec-prefix/home or
+        # install-base/install-platbase -- not both
+        cmd.prefix = 'prefix'
+        cmd.install_base = 'base'
+        self.assertRaises(DistutilsOptionError, cmd.finalize_options)
+
+        # must supply either home or prefix/exec-prefix -- not both
+        cmd.install_base = None
+        cmd.home = 'home'
+        self.assertRaises(DistutilsOptionError, cmd.finalize_options)
+
+        # can't combine user with with prefix/exec_prefix/home or
+        # install_(plat)base
+        cmd.prefix = None
+        cmd.user = 'user'
+        self.assertRaises(DistutilsOptionError, cmd.finalize_options)
+
+    def test_record(self):
+        install_dir = self.mkdtemp()
+        project_dir, dist = self.create_dist(scripts=['hello'])
+        self.addCleanup(os.chdir, os.getcwd())
+        os.chdir(project_dir)
+        self.write_file('hello', "print('o hai')")
+
+        cmd = install(dist)
+        dist.command_obj['install'] = cmd
+        cmd.root = install_dir
+        cmd.record = os.path.join(project_dir, 'RECORD')
+        cmd.ensure_finalized()
+        cmd.run()
+
+        f = open(cmd.record)
+        try:
+            content = f.read()
+        finally:
+            f.close()
+
+        found = [os.path.basename(line) for line in content.splitlines()]
+        expected = ['hello',
+                    'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]]
+        self.assertEqual(found, expected)
+
+    def test_record_extensions(self):
+        install_dir = self.mkdtemp()
+        project_dir, dist = self.create_dist(ext_modules=[
+            Extension('xx', ['xxmodule.c'])])
+        self.addCleanup(os.chdir, os.getcwd())
+        os.chdir(project_dir)
+        support.copy_xxmodule_c(project_dir)
+
+        buildextcmd = build_ext(dist)
+        support.fixup_build_ext(buildextcmd)
+        buildextcmd.ensure_finalized()
+
+        cmd = install(dist)
+        dist.command_obj['install'] = cmd
+        dist.command_obj['build_ext'] = buildextcmd
+        cmd.root = install_dir
+        cmd.record = os.path.join(project_dir, 'RECORD')
+        cmd.ensure_finalized()
+        cmd.run()
+
+        f = open(cmd.record)
+        try:
+            content = f.read()
+        finally:
+            f.close()
+
+        found = [os.path.basename(line) for line in content.splitlines()]
+        expected = [_make_ext_name('xx'),
+                    'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]]
+        self.assertEqual(found, expected)
+
+    def test_debug_mode(self):
+        # this covers the code called when DEBUG is set
+        old_logs_len = len(self.logs)
+        install_module.DEBUG = True
+        try:
+            with captured_stdout():
+                self.test_record()
+        finally:
+            install_module.DEBUG = False
+        self.assertTrue(len(self.logs) > old_logs_len)
 
 def test_suite():
     return unittest.makeSuite(InstallTestCase)
diff --git a/Lib/distutils/tests/test_sdist.py b/Lib/distutils/tests/test_sdist.py
--- a/Lib/distutils/tests/test_sdist.py
+++ b/Lib/distutils/tests/test_sdist.py
@@ -423,6 +423,7 @@
     def test_manual_manifest(self):
         # check that a MANIFEST without a marker is left alone
         dist, cmd = self.get_cmd()
+        cmd.formats = ['gztar']
         cmd.ensure_finalized()
         self.write_file((self.tmp_dir, cmd.manifest), 'README.manual')
         self.write_file((self.tmp_dir, 'README.manual'),
diff --git a/Lib/shutil.py b/Lib/shutil.py
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -25,7 +25,8 @@
 __all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2",
            "copytree", "move", "rmtree", "Error", "SpecialFileError",
            "ExecError", "make_archive", "get_archive_formats",
-           "register_archive_format", "unregister_archive_format"]
+           "register_archive_format", "unregister_archive_format",
+           "ignore_patterns"]
 
 class Error(EnvironmentError):
     pass

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list