1. Jason R. Coombs
  2. cpython-issue12666


Éric Araujo  committed 8065f92 Merge

Branch merge

  • Participants
  • Parent commits 42f40f5, a425408
  • Branches 2.7

Comments (0)

Files changed (7)

File Doc/distutils/sourcedist.rst

View file
 :file:`MANIFEST`, you must specify everything: the default set of files
 described above does not apply in this case.
-.. versionadded:: 2.7
+.. versionchanged:: 2.7
+   An existing generated :file:`MANIFEST` will be regenerated without
+   :command:`sdist` comparing its modification time to the one of
+   :file:`MANIFEST.in` or :file:`setup.py`.
+.. versionchanged:: 2.7.1
    :file:`MANIFEST` files start with a comment indicating they are generated.
    Files without this comment are not overwritten or removed.
+.. versionchanged:: 2.7.3
+   :command:`sdist` will read a :file:`MANIFEST` file if no :file:`MANIFEST.in`
+   exists, like it did before 2.7.
 See :ref:`manifest_template` section for a syntax reference.
 .. _manifest-options:
 Manifest-related options
 The normal course of operations for the :command:`sdist` command is as follows:
-* if the manifest file, :file:`MANIFEST` doesn't exist, read :file:`MANIFEST.in`
-  and create the manifest
+* if the manifest file (:file:`MANIFEST` by default) exists and the first line
+  does not have a comment indicating it is generated from :file:`MANIFEST.in`,
+  then it is used as is, unaltered
+* if the manifest file doesn't exist or has been previously automatically
+  generated, read :file:`MANIFEST.in` and create the manifest
 * if neither :file:`MANIFEST` nor :file:`MANIFEST.in` exist, create a manifest
   with just the default file set
-* if either :file:`MANIFEST.in` or the setup script (:file:`setup.py`) are more
-  recent than :file:`MANIFEST`, recreate :file:`MANIFEST` by reading
-  :file:`MANIFEST.in`
 * use the list of files now in :file:`MANIFEST` (either just generated or read
   in) to create the source distribution archive(s)
 ``a-z``, ``a-zA-Z``, ``a-f0-9_.``).  The definition of "regular filename
 character" is platform-specific: on Unix it is anything except slash; on Windows
 anything except backslash or colon.
-.. versionchanged:: 2.7
-    An existing generated :file:`MANIFEST` will be regenerated without
-    :command:`sdist` comparing its modification time to the one of
-    :file:`MANIFEST.in` or :file:`setup.py`.

File Lib/distutils/command/sdist.py

View file
         reading the manifest, or just using the default file set -- it all
         depends on the user's options.
-        # new behavior:
+        # new behavior when using a template:
         # the file list is recalculated everytime because
         # even if MANIFEST.in or setup.py are not changed
         # the user might have added some files in the tree that
         # need to be included.
-        #  This makes --force the default and only behavior.
+        #  This makes --force the default and only behavior with templates.
         template_exists = os.path.isfile(self.template)
+        if not template_exists and self._manifest_is_not_generated():
+            self.read_manifest()
+            self.filelist.sort()
+            self.filelist.remove_duplicates()
+            return
         if not template_exists:
             self.warn(("manifest template '%s' does not exist " +
                         "(using default file list)") %
         by 'add_defaults()' and 'read_template()') to the manifest file
         named by 'self.manifest'.
-        if os.path.isfile(self.manifest):
-            fp = open(self.manifest)
-            try:
-                first_line = fp.readline()
-            finally:
-                fp.close()
-            if first_line != '# file GENERATED by distutils, do NOT edit\n':
-                log.info("not writing to manually maintained "
-                         "manifest file '%s'" % self.manifest)
-                return
+        if self._manifest_is_not_generated():
+            log.info("not writing to manually maintained "
+                     "manifest file '%s'" % self.manifest)
+            return
         content = self.filelist.files[:]
         content.insert(0, '# file GENERATED by distutils, do NOT edit')
         self.execute(file_util.write_file, (self.manifest, content),
                      "writing manifest file '%s'" % self.manifest)
+    def _manifest_is_not_generated(self):
+        # check for special comment used in 2.7.1 and higher
+        if not os.path.isfile(self.manifest):
+            return False
+        fp = open(self.manifest, 'rU')
+        try:
+            first_line = fp.readline()
+        finally:
+            fp.close()
+        return first_line != '# file GENERATED by distutils, do NOT edit\n'
     def read_manifest(self):
         """Read the manifest file (named by 'self.manifest') and use it to
         fill in 'self.filelist', the list of files to include in the source
         log.info("reading manifest file '%s'", self.manifest)
         manifest = open(self.manifest)
-        while 1:
-            line = manifest.readline()
-            if line == '':              # end of file
-                break
-            if line[-1] == '\n':
-                line = line[0:-1]
+        for line in manifest:
+            # ignore comments and blank lines
+            line = line.strip()
+            if line.startswith('#') or not line:
+                continue

File Lib/distutils/tests/test_sdist.py

View file
 """Tests for distutils.command.sdist."""
 import os
+import tarfile
 import unittest
-import shutil
+import warnings
 import zipfile
-import tarfile
+from os.path import join
+from textwrap import dedent
 # zlib is not used here, but if it's not available
 # the tests that use zipfile may fail
 except ImportError:
     UID_GID_SUPPORT = False
-from os.path import join
-import sys
-import tempfile
-import warnings
 from test.test_support import captured_stdout, check_warnings, run_unittest
 from distutils.command.sdist import sdist, show_formats
 from distutils.core import Distribution
 from distutils.tests.test_config import PyPIRCCommandTestCase
-from distutils.errors import DistutilsExecError, DistutilsOptionError
+from distutils.errors import DistutilsOptionError
 from distutils.spawn import find_executable
-from distutils.tests import support
 from distutils.log import WARN
 from distutils.archive_util import ARCHIVE_FORMATS
                          '# file GENERATED by distutils, do NOT edit')
+    @unittest.skipUnless(zlib, 'requires zlib')
+    def test_manifest_comments(self):
+        # make sure comments don't cause exceptions or wrong includes
+        contents = dedent("""\
+            # bad.py
+            #bad.py
+            good.py
+            """)
+        dist, cmd = self.get_cmd()
+        cmd.ensure_finalized()
+        self.write_file((self.tmp_dir, cmd.manifest), contents)
+        self.write_file((self.tmp_dir, 'good.py'), '# pick me!')
+        self.write_file((self.tmp_dir, 'bad.py'), "# don't pick me!")
+        self.write_file((self.tmp_dir, '#bad.py'), "# don't pick me!")
+        cmd.run()
+        self.assertEqual(cmd.filelist.files, ['good.py'])
     @unittest.skipUnless(zlib, "requires zlib")
     def test_manual_manifest(self):
         # check that a MANIFEST without a marker is left alone
         dist, cmd = self.get_cmd()
         self.write_file((self.tmp_dir, cmd.manifest), 'README.manual')
+        self.write_file((self.tmp_dir, 'README.manual'),
+                         'This project maintains its MANIFEST file itself.')
+        self.assertEqual(cmd.filelist.files, ['README.manual'])
         f = open(cmd.manifest)
         self.assertEqual(manifest, ['README.manual'])
+        archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz')
+        archive = tarfile.open(archive_name)
+        try:
+            filenames = [tarinfo.name for tarinfo in archive]
+        finally:
+            archive.close()
+        self.assertEqual(sorted(filenames), ['fake-1.0', 'fake-1.0/PKG-INFO',
+                                             'fake-1.0/README.manual'])
 def test_suite():
     return unittest.makeSuite(SDistTestCase)

File Lib/lib2to3/tests/test_refactor.py

View file
         self.assertEqual(results, expected)
     def check_file_refactoring(self, test_file, fixers=_2TO3_FIXERS):
+        tmpdir = tempfile.mkdtemp(prefix="2to3-test_refactor")
+        self.addCleanup(shutil.rmtree, tmpdir)
+        # make a copy of the tested file that we can write to
+        shutil.copy(test_file, tmpdir)
+        test_file = os.path.join(tmpdir, os.path.basename(test_file))
+        os.chmod(test_file, 0o644)
         def read_file():
             with open(test_file, "rb") as fp:
                 return fp.read()
         old_contents = read_file()
         rt = self.rt(fixers=fixers)
         self.assertEqual(old_contents, read_file())
-        try:
-            rt.refactor_file(test_file, True)
-            new_contents = read_file()
-            self.assertNotEqual(old_contents, new_contents)
-        finally:
-            with open(test_file, "wb") as fp:
-                fp.write(old_contents)
+        rt.refactor_file(test_file, True)
+        new_contents = read_file()
+        self.assertNotEqual(old_contents, new_contents)
         return new_contents
     def test_refactor_file(self):

File Misc/ACKS

View file
 Vincent Delft
 Arnaud Delobelle
 Erik Demaine
+John Dennis
 Roger Dev
 Raghuram Devarakonda
 Catherine Devlin
 Tobias Thelen
 James Thomas
 Robin Thomas
+Stephen Thorne
 Eric Tiedemann
 Tracy Tims
 Oren Tirosh

File Misc/NEWS

View file
+- Issues #11104, #8688: Fix the behavior of distutils' sdist command with
+  manually-maintained MANIFEST files.
 - Issue #8887: "pydoc somebuiltin.somemethod" (or help('somebuiltin.somemethod')
   in Python code) now finds the doc of the method.
+- Issue #12331: The test suite for lib2to3 can now run from an installed
+  Python.
 - Issue #12549: Correct test_platform to not fail when OS X returns 'x86_64'
   as the processor type on some Mac systems.

File Tools/scripts/patchcheck.py

View file
 import shutil
 import os.path
 import subprocess
+import sysconfig
 import reindent
 import untabify
+SRCDIR = sysconfig.get_config_var('srcdir')
 def n_files_str(count):
     """Return 'N file(s)' with the proper plurality on 'file'."""
     return "{} file{}".format(count, "s" if count != 1 else "")
         info=lambda x: n_files_str(len(x)))
 def changed_files():
     """Get the list of changed or added files from the VCS."""
-    if os.path.isdir('.hg'):
+    if os.path.isdir(os.path.join(SRCDIR, '.hg')):
         vcs = 'hg'
         cmd = 'hg status --added --modified --no-status'
     elif os.path.isdir('.svn'):
     reindent.makebackup = False  # No need to create backups.
     fixed = []
     for path in (x for x in file_paths if x.endswith('.py')):
-        if reindent.check(path):
+        if reindent.check(os.path.join(SRCDIR, path)):
     return fixed
     """Report if any C files """
     fixed = []
     for path in file_paths:
-        with open(path, 'r') as f:
+        abspath = os.path.join(SRCDIR, path)
+        with open(abspath, 'r') as f:
             if '\t' not in f.read():
-        untabify.process(path, 8, verbose=False)
+        untabify.process(abspath, 8, verbose=False)
     return fixed
 def normalize_docs_whitespace(file_paths):
     fixed = []
     for path in file_paths:
+        abspath = os.path.join(SRCDIR, path)
-            with open(path, 'rb') as f:
+            with open(abspath, 'rb') as f:
                 lines = f.readlines()
             new_lines = [ws_re.sub(br'\1', line) for line in lines]
             if new_lines != lines:
-                shutil.copyfile(path, path + '.bak')
-                with open(path, 'wb') as f:
+                shutil.copyfile(abspath, abspath + '.bak')
+                with open(abspath, 'wb') as f:
         except Exception as err: