Branch merge
This commit is contained in:
commit
0db7f72cc7
|
@ -111,12 +111,22 @@ per line, regular files (or symlinks to them) only. If you do supply your own
|
||||||
:file:`MANIFEST`, you must specify everything: the default set of files
|
:file:`MANIFEST`, you must specify everything: the default set of files
|
||||||
described above does not apply in this case.
|
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.
|
:file:`MANIFEST` files start with a comment indicating they are generated.
|
||||||
Files without this comment are not overwritten or removed.
|
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.
|
See :ref:`manifest_template` section for a syntax reference.
|
||||||
|
|
||||||
|
|
||||||
.. _manifest-options:
|
.. _manifest-options:
|
||||||
|
|
||||||
Manifest-related options
|
Manifest-related options
|
||||||
|
@ -124,16 +134,16 @@ Manifest-related options
|
||||||
|
|
||||||
The normal course of operations for the :command:`sdist` command is as follows:
|
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`
|
* if the manifest file (:file:`MANIFEST` by default) exists and the first line
|
||||||
and create the manifest
|
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
|
* if neither :file:`MANIFEST` nor :file:`MANIFEST.in` exist, create a manifest
|
||||||
with just the default file set
|
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
|
* use the list of files now in :file:`MANIFEST` (either just generated or read
|
||||||
in) to create the source distribution archive(s)
|
in) to create the source distribution archive(s)
|
||||||
|
|
||||||
|
@ -271,8 +281,3 @@ character, and ``[range]`` matches any of the characters in *range* (e.g.,
|
||||||
``a-z``, ``a-zA-Z``, ``a-f0-9_.``). The definition of "regular filename
|
``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
|
character" is platform-specific: on Unix it is anything except slash; on Windows
|
||||||
anything except backslash or colon.
|
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`.
|
|
||||||
|
|
|
@ -182,14 +182,20 @@ class sdist(Command):
|
||||||
reading the manifest, or just using the default file set -- it all
|
reading the manifest, or just using the default file set -- it all
|
||||||
depends on the user's options.
|
depends on the user's options.
|
||||||
"""
|
"""
|
||||||
# new behavior:
|
# new behavior when using a template:
|
||||||
# the file list is recalculated everytime because
|
# the file list is recalculated everytime because
|
||||||
# even if MANIFEST.in or setup.py are not changed
|
# even if MANIFEST.in or setup.py are not changed
|
||||||
# the user might have added some files in the tree that
|
# the user might have added some files in the tree that
|
||||||
# need to be included.
|
# 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)
|
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:
|
if not template_exists:
|
||||||
self.warn(("manifest template '%s' does not exist " +
|
self.warn(("manifest template '%s' does not exist " +
|
||||||
"(using default file list)") %
|
"(using default file list)") %
|
||||||
|
@ -352,23 +358,28 @@ class sdist(Command):
|
||||||
by 'add_defaults()' and 'read_template()') to the manifest file
|
by 'add_defaults()' and 'read_template()') to the manifest file
|
||||||
named by 'self.manifest'.
|
named by 'self.manifest'.
|
||||||
"""
|
"""
|
||||||
if os.path.isfile(self.manifest):
|
if self._manifest_is_not_generated():
|
||||||
fp = open(self.manifest)
|
log.info("not writing to manually maintained "
|
||||||
try:
|
"manifest file '%s'" % self.manifest)
|
||||||
first_line = fp.readline()
|
return
|
||||||
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
|
|
||||||
|
|
||||||
content = self.filelist.files[:]
|
content = self.filelist.files[:]
|
||||||
content.insert(0, '# file GENERATED by distutils, do NOT edit')
|
content.insert(0, '# file GENERATED by distutils, do NOT edit')
|
||||||
self.execute(file_util.write_file, (self.manifest, content),
|
self.execute(file_util.write_file, (self.manifest, content),
|
||||||
"writing manifest file '%s'" % self.manifest)
|
"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):
|
def read_manifest(self):
|
||||||
"""Read the manifest file (named by 'self.manifest') and use it to
|
"""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
|
fill in 'self.filelist', the list of files to include in the source
|
||||||
|
@ -376,12 +387,11 @@ class sdist(Command):
|
||||||
"""
|
"""
|
||||||
log.info("reading manifest file '%s'", self.manifest)
|
log.info("reading manifest file '%s'", self.manifest)
|
||||||
manifest = open(self.manifest)
|
manifest = open(self.manifest)
|
||||||
while 1:
|
for line in manifest:
|
||||||
line = manifest.readline()
|
# ignore comments and blank lines
|
||||||
if line == '': # end of file
|
line = line.strip()
|
||||||
break
|
if line.startswith('#') or not line:
|
||||||
if line[-1] == '\n':
|
continue
|
||||||
line = line[0:-1]
|
|
||||||
self.filelist.append(line)
|
self.filelist.append(line)
|
||||||
manifest.close()
|
manifest.close()
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
"""Tests for distutils.command.sdist."""
|
"""Tests for distutils.command.sdist."""
|
||||||
import os
|
import os
|
||||||
import unittest
|
|
||||||
import shutil
|
|
||||||
import zipfile
|
|
||||||
import tarfile
|
import tarfile
|
||||||
|
import unittest
|
||||||
|
import warnings
|
||||||
|
import zipfile
|
||||||
|
from os.path import join
|
||||||
|
from textwrap import dedent
|
||||||
|
|
||||||
# zlib is not used here, but if it's not available
|
# zlib is not used here, but if it's not available
|
||||||
# the tests that use zipfile may fail
|
# the tests that use zipfile may fail
|
||||||
|
@ -19,19 +21,13 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
UID_GID_SUPPORT = False
|
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 test.test_support import captured_stdout, check_warnings, run_unittest
|
||||||
|
|
||||||
from distutils.command.sdist import sdist, show_formats
|
from distutils.command.sdist import sdist, show_formats
|
||||||
from distutils.core import Distribution
|
from distutils.core import Distribution
|
||||||
from distutils.tests.test_config import PyPIRCCommandTestCase
|
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.spawn import find_executable
|
||||||
from distutils.tests import support
|
|
||||||
from distutils.log import WARN
|
from distutils.log import WARN
|
||||||
from distutils.archive_util import ARCHIVE_FORMATS
|
from distutils.archive_util import ARCHIVE_FORMATS
|
||||||
|
|
||||||
|
@ -405,13 +401,33 @@ class SDistTestCase(PyPIRCCommandTestCase):
|
||||||
self.assertEqual(manifest[0],
|
self.assertEqual(manifest[0],
|
||||||
'# file GENERATED by distutils, do NOT edit')
|
'# 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")
|
@unittest.skipUnless(zlib, "requires zlib")
|
||||||
def test_manual_manifest(self):
|
def test_manual_manifest(self):
|
||||||
# check that a MANIFEST without a marker is left alone
|
# check that a MANIFEST without a marker is left alone
|
||||||
dist, cmd = self.get_cmd()
|
dist, cmd = self.get_cmd()
|
||||||
cmd.ensure_finalized()
|
cmd.ensure_finalized()
|
||||||
self.write_file((self.tmp_dir, cmd.manifest), 'README.manual')
|
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.')
|
||||||
cmd.run()
|
cmd.run()
|
||||||
|
self.assertEqual(cmd.filelist.files, ['README.manual'])
|
||||||
|
|
||||||
f = open(cmd.manifest)
|
f = open(cmd.manifest)
|
||||||
try:
|
try:
|
||||||
|
@ -422,6 +438,15 @@ class SDistTestCase(PyPIRCCommandTestCase):
|
||||||
|
|
||||||
self.assertEqual(manifest, ['README.manual'])
|
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():
|
def test_suite():
|
||||||
return unittest.makeSuite(SDistTestCase)
|
return unittest.makeSuite(SDistTestCase)
|
||||||
|
|
||||||
|
|
|
@ -177,22 +177,26 @@ from __future__ import print_function"""
|
||||||
self.assertEqual(results, expected)
|
self.assertEqual(results, expected)
|
||||||
|
|
||||||
def check_file_refactoring(self, test_file, fixers=_2TO3_FIXERS):
|
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():
|
def read_file():
|
||||||
with open(test_file, "rb") as fp:
|
with open(test_file, "rb") as fp:
|
||||||
return fp.read()
|
return fp.read()
|
||||||
|
|
||||||
old_contents = read_file()
|
old_contents = read_file()
|
||||||
rt = self.rt(fixers=fixers)
|
rt = self.rt(fixers=fixers)
|
||||||
|
|
||||||
rt.refactor_file(test_file)
|
rt.refactor_file(test_file)
|
||||||
self.assertEqual(old_contents, read_file())
|
self.assertEqual(old_contents, read_file())
|
||||||
|
|
||||||
try:
|
rt.refactor_file(test_file, True)
|
||||||
rt.refactor_file(test_file, True)
|
new_contents = read_file()
|
||||||
new_contents = read_file()
|
self.assertNotEqual(old_contents, new_contents)
|
||||||
self.assertNotEqual(old_contents, new_contents)
|
|
||||||
finally:
|
|
||||||
with open(test_file, "wb") as fp:
|
|
||||||
fp.write(old_contents)
|
|
||||||
return new_contents
|
return new_contents
|
||||||
|
|
||||||
def test_refactor_file(self):
|
def test_refactor_file(self):
|
||||||
|
|
|
@ -194,6 +194,7 @@ Ned Deily
|
||||||
Vincent Delft
|
Vincent Delft
|
||||||
Arnaud Delobelle
|
Arnaud Delobelle
|
||||||
Erik Demaine
|
Erik Demaine
|
||||||
|
John Dennis
|
||||||
Roger Dev
|
Roger Dev
|
||||||
Raghuram Devarakonda
|
Raghuram Devarakonda
|
||||||
Catherine Devlin
|
Catherine Devlin
|
||||||
|
@ -813,6 +814,7 @@ Mikhail Terekhov
|
||||||
Tobias Thelen
|
Tobias Thelen
|
||||||
James Thomas
|
James Thomas
|
||||||
Robin Thomas
|
Robin Thomas
|
||||||
|
Stephen Thorne
|
||||||
Eric Tiedemann
|
Eric Tiedemann
|
||||||
Tracy Tims
|
Tracy Tims
|
||||||
Oren Tirosh
|
Oren Tirosh
|
||||||
|
|
|
@ -37,6 +37,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issues #11104, #8688: Fix the behavior of distutils' sdist command with
|
||||||
|
manually-maintained MANIFEST files.
|
||||||
|
|
||||||
- Issue #8887: "pydoc somebuiltin.somemethod" (or help('somebuiltin.somemethod')
|
- Issue #8887: "pydoc somebuiltin.somemethod" (or help('somebuiltin.somemethod')
|
||||||
in Python code) now finds the doc of the method.
|
in Python code) now finds the doc of the method.
|
||||||
|
|
||||||
|
@ -158,6 +161,9 @@ Tools/Demos
|
||||||
Tests
|
Tests
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
- 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'
|
- Issue #12549: Correct test_platform to not fail when OS X returns 'x86_64'
|
||||||
as the processor type on some Mac systems.
|
as the processor type on some Mac systems.
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,15 @@ import sys
|
||||||
import shutil
|
import shutil
|
||||||
import os.path
|
import os.path
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sysconfig
|
||||||
|
|
||||||
import reindent
|
import reindent
|
||||||
import untabify
|
import untabify
|
||||||
|
|
||||||
|
|
||||||
|
SRCDIR = sysconfig.get_config_var('srcdir')
|
||||||
|
|
||||||
|
|
||||||
def n_files_str(count):
|
def n_files_str(count):
|
||||||
"""Return 'N file(s)' with the proper plurality on 'file'."""
|
"""Return 'N file(s)' with the proper plurality on 'file'."""
|
||||||
return "{} file{}".format(count, "s" if count != 1 else "")
|
return "{} file{}".format(count, "s" if count != 1 else "")
|
||||||
|
@ -36,7 +40,7 @@ def status(message, modal=False, info=None):
|
||||||
info=lambda x: n_files_str(len(x)))
|
info=lambda x: n_files_str(len(x)))
|
||||||
def changed_files():
|
def changed_files():
|
||||||
"""Get the list of changed or added files from the VCS."""
|
"""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'
|
vcs = 'hg'
|
||||||
cmd = 'hg status --added --modified --no-status'
|
cmd = 'hg status --added --modified --no-status'
|
||||||
elif os.path.isdir('.svn'):
|
elif os.path.isdir('.svn'):
|
||||||
|
@ -75,7 +79,7 @@ def normalize_whitespace(file_paths):
|
||||||
reindent.makebackup = False # No need to create backups.
|
reindent.makebackup = False # No need to create backups.
|
||||||
fixed = []
|
fixed = []
|
||||||
for path in (x for x in file_paths if x.endswith('.py')):
|
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)):
|
||||||
fixed.append(path)
|
fixed.append(path)
|
||||||
return fixed
|
return fixed
|
||||||
|
|
||||||
|
@ -85,10 +89,11 @@ def normalize_c_whitespace(file_paths):
|
||||||
"""Report if any C files """
|
"""Report if any C files """
|
||||||
fixed = []
|
fixed = []
|
||||||
for path in file_paths:
|
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():
|
if '\t' not in f.read():
|
||||||
continue
|
continue
|
||||||
untabify.process(path, 8, verbose=False)
|
untabify.process(abspath, 8, verbose=False)
|
||||||
fixed.append(path)
|
fixed.append(path)
|
||||||
return fixed
|
return fixed
|
||||||
|
|
||||||
|
@ -99,13 +104,14 @@ ws_re = re.compile(br'\s+(\r?\n)$')
|
||||||
def normalize_docs_whitespace(file_paths):
|
def normalize_docs_whitespace(file_paths):
|
||||||
fixed = []
|
fixed = []
|
||||||
for path in file_paths:
|
for path in file_paths:
|
||||||
|
abspath = os.path.join(SRCDIR, path)
|
||||||
try:
|
try:
|
||||||
with open(path, 'rb') as f:
|
with open(abspath, 'rb') as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
new_lines = [ws_re.sub(br'\1', line) for line in lines]
|
new_lines = [ws_re.sub(br'\1', line) for line in lines]
|
||||||
if new_lines != lines:
|
if new_lines != lines:
|
||||||
shutil.copyfile(path, path + '.bak')
|
shutil.copyfile(abspath, abspath + '.bak')
|
||||||
with open(path, 'wb') as f:
|
with open(abspath, 'wb') as f:
|
||||||
f.writelines(new_lines)
|
f.writelines(new_lines)
|
||||||
fixed.append(path)
|
fixed.append(path)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
|
Loading…
Reference in New Issue