Commit 20c14661 authored by Daniel Holth's avatar Daniel Holth

merge

--HG--
branch : distribute
extra : rebase_source : e10714ab6506fa313a8bfb3f88f0620d3ab1707d
parents fb321a77 cada83b2
...@@ -16,6 +16,11 @@ CHANGES ...@@ -16,6 +16,11 @@ CHANGES
* Issue #313: Support for sdist subcommands (Python 2.7) * Issue #313: Support for sdist subcommands (Python 2.7)
* Issue #314: test_local_index() would fail an OS X. * Issue #314: test_local_index() would fail an OS X.
* Issue #310: Non-ascii characters in a namespace __init__.py causes errors. * Issue #310: Non-ascii characters in a namespace __init__.py causes errors.
* Issue #218: Improved documentation on behavior of `package_data` and
`include_package_data`. Files indicated by `package_data` are now included
in the manifest.
* `distribute_setup.py` now allows a `--download-base` argument for retrieving
distribute from a specified location.
------ ------
0.6.28 0.6.28
......
...@@ -19,6 +19,8 @@ import time ...@@ -19,6 +19,8 @@ import time
import fnmatch import fnmatch
import tempfile import tempfile
import tarfile import tarfile
import optparse
from distutils import log from distutils import log
try: try:
...@@ -495,22 +497,39 @@ def _extractall(self, path=".", members=None): ...@@ -495,22 +497,39 @@ def _extractall(self, path=".", members=None):
self._dbg(1, "tarfile: %s" % e) self._dbg(1, "tarfile: %s" % e)
def _build_install_args(argv): def _build_install_args(options):
"""
Build the arguments to 'python setup.py install' on the distribute package
"""
install_args = [] install_args = []
user_install = '--user' in argv if options.user_install:
if user_install and sys.version_info < (2, 6): if sys.version_info < (2, 6):
log.warn("--user requires Python 2.6 or later") log.warn("--user requires Python 2.6 or later")
raise SystemExit(1) raise SystemExit(1)
if user_install:
install_args.append('--user') install_args.append('--user')
return install_args return install_args
def _parse_args():
def main(argv, version=DEFAULT_VERSION): """
Parse the command line for options
"""
parser = optparse.OptionParser()
parser.add_option(
'--user', dest='user_install', action='store_true', default=False,
help='install in user site package (requires Python 2.6 or later)')
parser.add_option(
'--download-base', dest='download_base', metavar="URL",
default=DEFAULT_URL,
help='alternative URL from where to download the distribute package')
options, args = parser.parse_args()
# positional arguments are ignored
return options
def main(version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall""" """Install or upgrade setuptools and EasyInstall"""
tarball = download_setuptools() options = _parse_args()
_install(tarball, _build_install_args(argv)) tarball = download_setuptools(download_base=options.download_base)
_install(tarball, _build_install_args(options))
if __name__ == '__main__': if __name__ == '__main__':
main(sys.argv[1:]) main()
...@@ -756,17 +756,18 @@ e.g.:: ...@@ -756,17 +756,18 @@ e.g.::
include_package_data = True include_package_data = True
) )
This tells setuptools to install any data files it finds in your packages. The This tells setuptools to install any data files it finds in your packages.
data files must be under CVS or Subversion control, or else they must be The data files must be under CVS or Subversion control, or else they must be
specified via the distutils' ``MANIFEST.in`` file. (They can also be tracked specified via the distutils' ``MANIFEST.in`` file. (They can also be tracked
by another revision control system, using an appropriate plugin. See the by another revision control system, using an appropriate plugin. See the
section below on `Adding Support for Other Revision Control Systems`_ for section below on `Adding Support for Other Revision Control Systems`_ for
information on how to write such plugins.) information on how to write such plugins.)
If you want finer-grained control over what files are included (for example, if If the data files are not under version control, or are not in a supported
you have documentation files in your package directories and want to exclude version control system, or if you want finer-grained control over what files
them from installation), then you can also use the ``package_data`` keyword, are included (for example, if you have documentation files in your package
e.g.:: directories and want to exclude them from installation), then you can also use
the ``package_data`` keyword, e.g.::
from setuptools import setup, find_packages from setuptools import setup, find_packages
setup( setup(
...@@ -822,7 +823,10 @@ converts slashes to appropriate platform-specific separators at build time. ...@@ -822,7 +823,10 @@ converts slashes to appropriate platform-specific separators at build time.
(Note: although the ``package_data`` argument was previously only available in (Note: although the ``package_data`` argument was previously only available in
``setuptools``, it was also added to the Python ``distutils`` package as of ``setuptools``, it was also added to the Python ``distutils`` package as of
Python 2.4; there is `some documentation for the feature`__ available on the Python 2.4; there is `some documentation for the feature`__ available on the
python.org website.) python.org website. If using the setuptools-specific ``include_package_data``
argument, files specified by ``package_data`` will *not* be automatically
added to the manifest unless they are tracked by a supported version control
system, or are listed in the MANIFEST.in file.)
__ http://docs.python.org/dist/node11.html __ http://docs.python.org/dist/node11.html
......
...@@ -198,6 +198,14 @@ class sdist(_sdist): ...@@ -198,6 +198,14 @@ class sdist(_sdist):
if self.distribution.has_pure_modules(): if self.distribution.has_pure_modules():
build_py = self.get_finalized_command('build_py') build_py = self.get_finalized_command('build_py')
self.filelist.extend(build_py.get_source_files()) self.filelist.extend(build_py.get_source_files())
# This functionality is incompatible with include_package_data, and
# will in fact create an infinite recursion if include_package_data
# is True. Use of include_package_data will imply that
# distutils-style automatic handling of package_data is disabled
if not self.distribution.include_package_data:
for _, src_dir, _, filenames in build_py.data_files:
self.filelist.extend([os.path.join(src_dir, filename)
for filename in filenames])
if self.distribution.has_ext_modules(): if self.distribution.has_ext_modules():
build_ext = self.get_finalized_command('build_ext') build_ext = self.get_finalized_command('build_ext')
......
...@@ -264,6 +264,7 @@ class Distribution(_Distribution): ...@@ -264,6 +264,7 @@ class Distribution(_Distribution):
def fetch_build_egg(self, req): def fetch_build_egg(self, req):
"""Fetch an egg needed for building""" """Fetch an egg needed for building"""
try: try:
cmd = self._egg_fetcher cmd = self._egg_fetcher
cmd.package_index.to_scan = [] cmd.package_index.to_scan = []
...@@ -287,7 +288,7 @@ class Distribution(_Distribution): ...@@ -287,7 +288,7 @@ class Distribution(_Distribution):
cmd = easy_install( cmd = easy_install(
dist, args=["x"], install_dir=os.curdir, exclude_scripts=True, dist, args=["x"], install_dir=os.curdir, exclude_scripts=True,
always_copy=False, build_directory=None, editable=False, always_copy=False, build_directory=None, editable=False,
upgrade=False, multi_version=True, no_report = True upgrade=False, multi_version=True, no_report=True, user=False
) )
cmd.ensure_finalized() cmd.ensure_finalized()
self._egg_fetcher = cmd self._egg_fetcher = cmd
......
...@@ -166,12 +166,12 @@ else: ...@@ -166,12 +166,12 @@ else:
_EXCEPTIONS = [] _EXCEPTIONS = []
try: try:
from win32com.client.gencache import GetGeneratePath from win32com.client.gencache import GetGeneratePath
_EXCEPTIONS.append(GetGeneratePath()) _EXCEPTIONS.append(GetGeneratePath())
del GetGeneratePath del GetGeneratePath
except ImportError: except ImportError:
# it appears pywin32 is not installed, so no need to exclude. # it appears pywin32 is not installed, so no need to exclude.
pass pass
class DirectorySandbox(AbstractSandbox): class DirectorySandbox(AbstractSandbox):
"""Restrict operations to a single subdirectory - pseudo-chroot""" """Restrict operations to a single subdirectory - pseudo-chroot"""
......
...@@ -38,7 +38,7 @@ def makeSetup(**args): ...@@ -38,7 +38,7 @@ def makeSetup(**args):
try: try:
return setuptools.setup(**args) return setuptools.setup(**args)
finally: finally:
distutils.core_setup_stop_after = None distutils.core._setup_stop_after = None
class DependsTests(unittest.TestCase): class DependsTests(unittest.TestCase):
......
...@@ -12,6 +12,7 @@ import urlparse ...@@ -12,6 +12,7 @@ import urlparse
import StringIO import StringIO
import distutils.core import distutils.core
from setuptools.sandbox import run_setup, SandboxViolation
from setuptools.command.easy_install import easy_install, get_script_args, main from setuptools.command.easy_install import easy_install, get_script_args, main
from setuptools.command.easy_install import PthDistributions from setuptools.command.easy_install import PthDistributions
from setuptools.command import easy_install as easy_install_pkg from setuptools.command import easy_install as easy_install_pkg
...@@ -110,7 +111,9 @@ class TestEasyInstallTest(unittest.TestCase): ...@@ -110,7 +111,9 @@ class TestEasyInstallTest(unittest.TestCase):
old_wd = os.getcwd() old_wd = os.getcwd()
try: try:
os.chdir(dir) os.chdir(dir)
main([]) reset_setup_stop_context(
lambda: self.assertRaises(SystemExit, main, [])
)
finally: finally:
os.chdir(old_wd) os.chdir(old_wd)
shutil.rmtree(dir) shutil.rmtree(dir)
...@@ -247,7 +250,7 @@ class TestUserInstallTest(unittest.TestCase): ...@@ -247,7 +250,7 @@ class TestUserInstallTest(unittest.TestCase):
cmd.local_index.scan([new_location]) cmd.local_index.scan([new_location])
res = cmd.easy_install('foo') res = cmd.easy_install('foo')
self.assertEqual(os.path.realpath(res.location), self.assertEqual(os.path.realpath(res.location),
os.path.realpath(new_location)) os.path.realpath(new_location))
finally: finally:
sys.path.remove(target) sys.path.remove(target)
for basedir in [new_location, target, ]: for basedir in [new_location, target, ]:
...@@ -262,6 +265,57 @@ class TestUserInstallTest(unittest.TestCase): ...@@ -262,6 +265,57 @@ class TestUserInstallTest(unittest.TestCase):
else: else:
del os.environ['PYTHONPATH'] del os.environ['PYTHONPATH']
def test_setup_requires(self):
"""Regression test for issue #318
Ensures that a package with setup_requires can be installed when
distribute is installed in the user site-packages without causing a
SandboxViolation.
"""
test_setup_attrs = {
'name': 'test_pkg', 'version': '0.0',
'setup_requires': ['foobar'],
'dependency_links': [os.path.abspath(self.dir)]
}
test_pkg = os.path.join(self.dir, 'test_pkg')
test_setup_py = os.path.join(test_pkg, 'setup.py')
test_setup_cfg = os.path.join(test_pkg, 'setup.cfg')
os.mkdir(test_pkg)
f = open(test_setup_py, 'w')
f.write(textwrap.dedent("""\
import setuptools
setuptools.setup(**%r)
""" % test_setup_attrs))
f.close()
foobar_path = os.path.join(self.dir, 'foobar-0.1.tar.gz')
make_trivial_sdist(
foobar_path,
textwrap.dedent("""\
import setuptools
setuptools.setup(
name='foobar',
version='0.1'
)
"""))
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StringIO.StringIO()
sys.stderr = StringIO.StringIO()
try:
reset_setup_stop_context(
lambda: run_setup(test_setup_py, ['install'])
)
except SandboxViolation:
self.fail('Installation caused SandboxViolation')
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
class TestSetupRequires(unittest.TestCase): class TestSetupRequires(unittest.TestCase):
...@@ -319,30 +373,41 @@ class TestSetupRequires(unittest.TestCase): ...@@ -319,30 +373,41 @@ class TestSetupRequires(unittest.TestCase):
doesn't exist) and invoke installer on it. doesn't exist) and invoke installer on it.
""" """
def build_sdist(dir): def build_sdist(dir):
setup_py = tarfile.TarInfo(name="setup.py")
try:
# Python 3 (StringIO gets converted to io module)
MemFile = StringIO.BytesIO
except AttributeError:
MemFile = StringIO.StringIO
setup_py_bytes = MemFile(textwrap.dedent("""
import setuptools
setuptools.setup(
name="distribute-test-fetcher",
version="1.0",
setup_requires = ['does-not-exist'],
)
""").lstrip().encode('utf-8'))
setup_py.size = len(setup_py_bytes.getvalue())
dist_path = os.path.join(dir, 'distribute-test-fetcher-1.0.tar.gz') dist_path = os.path.join(dir, 'distribute-test-fetcher-1.0.tar.gz')
dist = tarfile.open(dist_path, 'w:gz') make_trivial_sdist(
try: dist_path,
dist.addfile(setup_py, fileobj=setup_py_bytes) textwrap.dedent("""
finally: import setuptools
dist.close() setuptools.setup(
name="distribute-test-fetcher",
version="1.0",
setup_requires = ['does-not-exist'],
)
""").lstrip())
installer(dist_path) installer(dist_path)
tempdir_context(build_sdist) tempdir_context(build_sdist)
def make_trivial_sdist(dist_path, setup_py):
"""Create a simple sdist tarball at dist_path, containing just a
setup.py, the contents of which are provided by the setup_py string.
"""
setup_py_file = tarfile.TarInfo(name='setup.py')
try:
# Python 3 (StringIO gets converted to io module)
MemFile = StringIO.BytesIO
except AttributeError:
MemFile = StringIO.StringIO
setup_py_bytes = MemFile(setup_py.encode('utf-8'))
setup_py_file.size = len(setup_py_bytes.getvalue())
dist = tarfile.open(dist_path, 'w:gz')
try:
dist.addfile(setup_py_file, fileobj=setup_py_bytes)
finally:
dist.close()
def tempdir_context(f, cd=lambda dir:None): def tempdir_context(f, cd=lambda dir:None):
""" """
Invoke f in the context Invoke f in the context
......
"""sdist tests"""
import os
import shutil
import sys
import tempfile
import unittest
from StringIO import StringIO
from setuptools.command.sdist import sdist
from setuptools.dist import Distribution
SETUP_ATTRS = {
'name': 'sdist_test',
'version': '0.0',
'packages': ['sdist_test'],
'package_data': {'sdist_test': ['*.txt']}
}
SETUP_PY = """\
from setuptools import setup
setup(**%r)
""" % SETUP_ATTRS
class TestSdistTest(unittest.TestCase):
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
f = open(os.path.join(self.temp_dir, 'setup.py'), 'w')
f.write(SETUP_PY)
f.close()
# Set up the rest of the test package
test_pkg = os.path.join(self.temp_dir, 'sdist_test')
os.mkdir(test_pkg)
# *.rst was not included in package_data, so c.rst should not be
# automatically added to the manifest when not under version control
for fname in ['__init__.py', 'a.txt', 'b.txt', 'c.rst']:
# Just touch the files; their contents are irrelevant
open(os.path.join(test_pkg, fname), 'w').close()
self.old_cwd = os.getcwd()
os.chdir(self.temp_dir)
def tearDown(self):
os.chdir(self.old_cwd)
shutil.rmtree(self.temp_dir)
def test_package_data_in_sdist(self):
"""Regression test for pull request #4: ensures that files listed in
package_data are included in the manifest even if they're not added to
version control.
"""
dist = Distribution(SETUP_ATTRS)
dist.script_name = 'setup.py'
cmd = sdist(dist)
cmd.ensure_finalized()
# squelch output
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StringIO()
sys.stderr = StringIO()
try:
cmd.run()
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
manifest = cmd.filelist.files
self.assert_(os.path.join('sdist_test', 'a.txt') in manifest)
self.assert_(os.path.join('sdist_test', 'b.txt') in manifest)
self.assert_(os.path.join('sdist_test', 'c.rst') not in manifest)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment