diff options
-rw-r--r-- | .hgtags | 5 | ||||
-rw-r--r-- | .travis.yml | 3 | ||||
-rw-r--r-- | CHANGES.txt | 34 | ||||
-rwxr-xr-x | README.txt | 14 | ||||
-rw-r--r-- | bootstrap.py | 51 | ||||
-rw-r--r-- | docs/setuptools.txt | 2 | ||||
-rw-r--r-- | docs/using.txt | 3 | ||||
-rw-r--r-- | ez_setup.py | 2 | ||||
-rw-r--r-- | pkg_resources.py | 19 | ||||
-rw-r--r-- | setuptools.egg-info/dependency_links.txt | 2 | ||||
-rw-r--r-- | setuptools.egg-info/entry_points.txt | 64 | ||||
-rw-r--r-- | setuptools.egg-info/requires.txt | 7 | ||||
-rw-r--r-- | setuptools/__init__.py | 6 | ||||
-rwxr-xr-x | setuptools/command/easy_install.py | 4 | ||||
-rwxr-xr-x | setuptools/command/install_egg_info.py | 2 | ||||
-rw-r--r-- | setuptools/dist.py | 19 | ||||
-rw-r--r-- | setuptools/svn_utils.py | 2 | ||||
-rw-r--r-- | setuptools/tests/environment.py | 65 | ||||
-rw-r--r-- | setuptools/version.py | 2 | ||||
-rw-r--r-- | setuptools/windows_support.py | 29 | ||||
-rw-r--r-- | tox.ini | 2 |
21 files changed, 185 insertions, 152 deletions
@@ -156,4 +156,7 @@ a1fc0220bfa3581158688789f6dfdc00672eb99b 5.6 67550a8ed9f4ef49ee5a31f433adbf5a0eaeccf9 5.8 755cbfd3743ffb186cdf7e20be8e61dbdaa22503 6.0 bc6655b4acf205dd9f25c702955645656077398a 6.0.1 -8b8a52665803abf0bc2d2e892fc59ce5416f4bf7 7.0b1 +1ae2a75724bbba56373784f185a7f235ed0f24a4 6.0.2b1 +01271e84e5125fcc4f0f368a6e21116a5722953c 6.0.2 +7ea80190d494a766c6356fce85c844703964b6cc 6.1 +df26609c2f614f5fc9110342e4003ee8bd95cf84 7.0 diff --git a/.travis.yml b/.travis.yml index bc387f46..22541671 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,7 @@ python: - pypy # command to run tests script: - # testing fix for https://bitbucket.org/hpk42/pytest/issue/555 - - pip install --pre -i https://devpi.net/hpk/dev/ --upgrade pytest + - python setup.py egg_info - python setup.py test - python setup.py ptr - python ez_setup.py --version 5.4.1 diff --git a/CHANGES.txt b/CHANGES.txt index 19d8095f..f4d8019a 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -3,7 +3,7 @@ CHANGES ======= --- -7.0 +8.0 --- * Implement `PEP 440 <http://legacy.python.org/dev/peps/pep-0440/>`_ within @@ -15,6 +15,38 @@ CHANGES supported. Setuptools now "vendors" the `packaging <https://github.com/pypa/packaging>`_ library. +--- +7.0 +--- + +* Issue #80, Issue #209: Eggs that are downloaded for ``setup_requires``, + ``test_requires``, etc. are now placed in a ``./.eggs`` directory instead of + directly in the current directory. This choice of location means the files + can be readily managed (removed, ignored). Additionally, + later phases or invocations of setuptools will not detect the package as + already installed and ignore it for permanent install (See #209). + + This change is indicated as backward-incompatible as installations that + depend on the installation in the current directory will need to account for + the new location. Systems that ignore ``*.egg`` will probably need to be + adapted to ignore ``.eggs``. The files will need to be manually moved or + will be retrieved again. Most use cases will require no attention. + +--- +6.1 +--- + +* Issue #268: When resolving package versions, a VersionConflict now reports + which package previously required the conflicting version. + +----- +6.0.2 +----- + +* Issue #262: Fixed regression in pip install due to egg-info directories + being omitted. Re-opens Issue #118. +>>>>>>> master + ----- 6.0.1 ----- @@ -83,6 +83,18 @@ Alternatively, Setuptools may be installed to a user-local path:: > wget https://bootstrap.pypa.io/ez_setup.py -O - | python - --user +Note that on some older systems (noted on Debian 6 and CentOS 5 installations), +`wget` may refuse to download `ez_setup.py`, complaining that the certificate common name `*.c.ssl.fastly.net` +does not match the host name `bootstrap.pypa.io`. In addition, the `ez_setup.py` script may then encounter similar problems using +`wget` internally to download `setuptools-x.y.zip`, complaining that the certificate common name of `www.python.org` does not match the +host name `pypi.python.org`. Those are known issues, related to a bug in the older versions of `wget` +(see `Issue 59 <https://bitbucket.org/pypa/pypi/issue/59#comment-5881915>`_). If you happen to encounter them, +install Setuptools as follows:: + + > wget --no-check-certificate https://bootstrap.pypa.io/ez_setup.py + > python ez_setup.py --insecure + + Unix including Mac OS X (curl) ============================== @@ -153,7 +165,6 @@ learning about Setuptools, Python Eggs, and EasyInstall: * `The EasyInstall user's guide and reference manual`_ * `The setuptools Developer's Guide`_ * `The pkg_resources API reference`_ -* `Package Compatibility Notes`_ (user-maintained) * `The Internal Structure of Python Eggs`_ Questions, comments, and bug reports should be directed to the `distutils-sig @@ -164,7 +175,6 @@ them there, so this reference list can be updated. If you have working, the `setuptools bug tracker`_. .. _setuptools bug tracker: https://bitbucket.org/pypa/setuptools/issues -.. _Package Compatibility Notes: https://pythonhosted.org/setuptools/PackageNotes .. _The Internal Structure of Python Eggs: https://pythonhosted.org/setuptools/formats.html .. _The setuptools Developer's Guide: https://pythonhosted.org/setuptools/setuptools.html .. _The pkg_resources API reference: https://pythonhosted.org/setuptools/pkg_resources.html diff --git a/bootstrap.py b/bootstrap.py new file mode 100644 index 00000000..cbc1ca9d --- /dev/null +++ b/bootstrap.py @@ -0,0 +1,51 @@ +""" +If setuptools is not already installed in the environment, it's not possible +to invoke setuptools' own commands. This routine will bootstrap this local +environment by creating a minimal egg-info directory and then invoking the +egg-info command to flesh out the egg-info directory. +""" + +import os +import sys +import textwrap +import subprocess + + +minimal_egg_info = textwrap.dedent(""" + [distutils.commands] + egg_info = setuptools.command.egg_info:egg_info + + [distutils.setup_keywords] + include_package_data = setuptools.dist:assert_bool + install_requires = setuptools.dist:check_requirements + extras_require = setuptools.dist:check_extras + entry_points = setuptools.dist:check_entry_points + + [egg_info.writers] + dependency_links.txt = setuptools.command.egg_info:overwrite_arg + entry_points.txt = setuptools.command.egg_info:write_entries + requires.txt = setuptools.command.egg_info:write_requirements + """) + +def ensure_egg_info(): + if not os.path.exists('setuptools.egg-info'): + build_egg_info() + + +def build_egg_info(): + """ + Build a minimal egg-info, enough to invoke egg_info + """ + + os.mkdir('setuptools.egg-info') + with open('setuptools.egg-info/entry_points.txt', 'w') as ep: + ep.write(minimal_egg_info) + + +def run_egg_info(): + subprocess.check_call([sys.executable, 'setup.py', 'egg_info']) + + +if __name__ == '__main__': + ensure_egg_info() + run_egg_info() diff --git a/docs/setuptools.txt b/docs/setuptools.txt index c3844cf2..a34ec304 100644 --- a/docs/setuptools.txt +++ b/docs/setuptools.txt @@ -473,7 +473,7 @@ script called ``baz``, you might do something like this:: setup( # other arguments here... - entry_points = { + entry_points={ 'console_scripts': [ 'foo = my_package.some_module:main_func', 'bar = other_module:some_func', diff --git a/docs/using.txt b/docs/using.txt index e44847d6..bd80893d 100644 --- a/docs/using.txt +++ b/docs/using.txt @@ -8,3 +8,6 @@ it at the very beginning of `setup.py` like this:: from ez_setup import use_setuptools use_setuptools() + +More info on `ez_setup.py` can be found at `the project home page +<https://pypy.python.org/pypi/setuptools>`_. diff --git a/ez_setup.py b/ez_setup.py index a523401e..f6361e8e 100644 --- a/ez_setup.py +++ b/ez_setup.py @@ -36,7 +36,7 @@ try: except ImportError: USER_SITE = None -DEFAULT_VERSION = "7.0" +DEFAULT_VERSION = "8.0" DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/" def _python_cmd(*args): diff --git a/pkg_resources.py b/pkg_resources.py index 6f21b0bf..daf7732c 100644 --- a/pkg_resources.py +++ b/pkg_resources.py @@ -602,6 +602,10 @@ class WorkingSet(object): best = {} to_activate = [] + # Mapping of requirement to set of distributions that required it; + # useful for reporting info about conflicts. + required_by = collections.defaultdict(set) + while requirements: # process dependencies breadth-first req = requirements.pop(0) @@ -635,9 +639,18 @@ class WorkingSet(object): to_activate.append(dist) if dist not in req: # Oops, the "best" so far conflicts with a dependency - # XXX put more info here - raise VersionConflict(dist, req) - requirements.extend(dist.requires(req.extras)[::-1]) + tmpl = "%s is installed but %s is required by %s" + args = dist, req, list(required_by.get(req, [])) + raise VersionConflict(tmpl % args) + + # push the new requirements onto the stack + new_requirements = dist.requires(req.extras)[::-1] + requirements.extend(new_requirements) + + # Register the new requirements needed by req + for new_requirement in new_requirements: + required_by[new_requirement].add(req.project_name) + processed[req] = True # return list of distros to activate diff --git a/setuptools.egg-info/dependency_links.txt b/setuptools.egg-info/dependency_links.txt deleted file mode 100644 index b454c168..00000000 --- a/setuptools.egg-info/dependency_links.txt +++ /dev/null @@ -1,2 +0,0 @@ -https://pypi.python.org/packages/source/c/certifi/certifi-1.0.1.tar.gz#md5=45f5cb94b8af9e1df0f9450a8f61b790 -https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2 diff --git a/setuptools.egg-info/entry_points.txt b/setuptools.egg-info/entry_points.txt deleted file mode 100644 index 72a5ffe0..00000000 --- a/setuptools.egg-info/entry_points.txt +++ /dev/null @@ -1,64 +0,0 @@ -[console_scripts] -easy_install = setuptools.command.easy_install:main -easy_install-3.4 = setuptools.command.easy_install:main - -[distutils.commands] -alias = setuptools.command.alias:alias -bdist_egg = setuptools.command.bdist_egg:bdist_egg -bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm -bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst -build_ext = setuptools.command.build_ext:build_ext -build_py = setuptools.command.build_py:build_py -develop = setuptools.command.develop:develop -easy_install = setuptools.command.easy_install:easy_install -egg_info = setuptools.command.egg_info:egg_info -install = setuptools.command.install:install -install_egg_info = setuptools.command.install_egg_info:install_egg_info -install_lib = setuptools.command.install_lib:install_lib -install_scripts = setuptools.command.install_scripts:install_scripts -register = setuptools.command.register:register -rotate = setuptools.command.rotate:rotate -saveopts = setuptools.command.saveopts:saveopts -sdist = setuptools.command.sdist:sdist -setopt = setuptools.command.setopt:setopt -test = setuptools.command.test:test -upload_docs = setuptools.command.upload_docs:upload_docs - -[distutils.setup_keywords] -convert_2to3_doctests = setuptools.dist:assert_string_list -dependency_links = setuptools.dist:assert_string_list -eager_resources = setuptools.dist:assert_string_list -entry_points = setuptools.dist:check_entry_points -exclude_package_data = setuptools.dist:check_package_data -extras_require = setuptools.dist:check_extras -include_package_data = setuptools.dist:assert_bool -install_requires = setuptools.dist:check_requirements -namespace_packages = setuptools.dist:check_nsp -package_data = setuptools.dist:check_package_data -packages = setuptools.dist:check_packages -setup_requires = setuptools.dist:check_requirements -test_loader = setuptools.dist:check_importable -test_runner = setuptools.dist:check_importable -test_suite = setuptools.dist:check_test_suite -tests_require = setuptools.dist:check_requirements -use_2to3 = setuptools.dist:assert_bool -use_2to3_exclude_fixers = setuptools.dist:assert_string_list -use_2to3_fixers = setuptools.dist:assert_string_list -zip_safe = setuptools.dist:assert_bool - -[egg_info.writers] -PKG-INFO = setuptools.command.egg_info:write_pkg_info -dependency_links.txt = setuptools.command.egg_info:overwrite_arg -depends.txt = setuptools.command.egg_info:warn_depends_obsolete -eager_resources.txt = setuptools.command.egg_info:overwrite_arg -entry_points.txt = setuptools.command.egg_info:write_entries -namespace_packages.txt = setuptools.command.egg_info:overwrite_arg -requires.txt = setuptools.command.egg_info:write_requirements -top_level.txt = setuptools.command.egg_info:write_toplevel_names - -[setuptools.file_finders] -svn_cvs = setuptools.command.sdist:_default_revctrl - -[setuptools.installation] -eggsecutable = setuptools.command.easy_install:bootstrap - diff --git a/setuptools.egg-info/requires.txt b/setuptools.egg-info/requires.txt deleted file mode 100644 index f3f4471e..00000000 --- a/setuptools.egg-info/requires.txt +++ /dev/null @@ -1,7 +0,0 @@ -packaging>=14.2,<15.0.dev0 - -[certs] -certifi==1.0.1 - -[ssl:sys_platform=='win32'] -wincertstore==0.2 diff --git a/setuptools/__init__.py b/setuptools/__init__.py index d99ab2a6..ca025c30 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -139,7 +139,7 @@ def findall(dir = os.curdir): (relative to 'dir'). """ all_files = [] - for base, dirs, files in os.walk(dir): + for base, dirs, files in os.walk(dir, followlinks=True): if base==os.curdir or base.startswith(os.curdir+os.sep): base = base[2:] if base: @@ -148,7 +148,3 @@ def findall(dir = os.curdir): return all_files distutils.filelist.findall = findall # fix findall bug in distutils. - -# sys.dont_write_bytecode was introduced in Python 2.6. -_dont_write_bytecode = getattr(sys, 'dont_write_bytecode', - bool(os.environ.get("PYTHONDONTWRITEBYTECODE"))) diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 68548272..2e00b996 100755 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -35,7 +35,7 @@ import warnings import site import struct -from setuptools import Command, _dont_write_bytecode +from setuptools import Command from setuptools.sandbox import run_setup from setuptools.py31compat import get_path, get_config_vars from setuptools.command import setopt @@ -1152,7 +1152,7 @@ See the setuptools documentation for the "develop" command for more info. chmod(f, mode) def byte_compile(self, to_compile): - if _dont_write_bytecode: + if sys.dont_write_bytecode: self.warn('byte-compiling is disabled, skipping.') return diff --git a/setuptools/command/install_egg_info.py b/setuptools/command/install_egg_info.py index 992709f1..fd0f118b 100755 --- a/setuptools/command/install_egg_info.py +++ b/setuptools/command/install_egg_info.py @@ -27,7 +27,7 @@ class install_egg_info(Command): ).egg_name() + '.egg-info' self.source = ei_cmd.egg_info self.target = os.path.join(self.install_dir, basename) - self.outputs = [] + self.outputs = [self.target] def run(self): self.run_command('egg_info') diff --git a/setuptools/dist.py b/setuptools/dist.py index a3a37ee4..e44796fd 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -22,6 +22,7 @@ except ImportError: from setuptools.depends import Require from setuptools.compat import basestring, PY2 +from setuptools import windows_support import pkg_resources @@ -334,6 +335,21 @@ class Distribution(_Distribution): else: self.convert_2to3_doctests = [] + def get_egg_cache_dir(self): + egg_cache_dir = os.path.join(os.curdir, '.eggs') + if not os.path.exists(egg_cache_dir): + os.mkdir(egg_cache_dir) + windows_support.hide_file(egg_cache_dir) + readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt') + with open(readme_txt_filename, 'w') as f: + f.write('This directory contains eggs that were downloaded ' + 'by setuptools to build, test, and run plug-ins.\n\n') + f.write('This directory caches those eggs to prevent ' + 'repeated downloads.\n\n') + f.write('However, it is safe to delete this directory.\n\n') + + return egg_cache_dir + def fetch_build_egg(self, req): """Fetch an egg needed for building""" @@ -357,8 +373,9 @@ class Distribution(_Distribution): if 'find_links' in opts: links = opts['find_links'][1].split() + links opts['find_links'] = ('setup', links) + install_dir = self.get_egg_cache_dir() cmd = easy_install( - dist, args=["x"], install_dir=os.curdir, exclude_scripts=True, + dist, args=["x"], install_dir=install_dir, exclude_scripts=True, always_copy=False, build_directory=None, editable=False, upgrade=False, multi_version=True, no_report=True, user=False ) diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py index dadb682a..6502fc98 100644 --- a/setuptools/svn_utils.py +++ b/setuptools/svn_utils.py @@ -302,7 +302,7 @@ class SvnInfo(object): self._externals = None
def get_revision(self):
- 'Retrieve the directory revision informatino using svnversion'
+ 'Retrieve the directory revision information using svnversion'
code, data = _run_command(['svnversion', '-c', self.path])
if code:
log.warn("svnversion failed")
diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py index 476d280a..c8d0e669 100644 --- a/setuptools/tests/environment.py +++ b/setuptools/tests/environment.py @@ -10,57 +10,6 @@ import unicodedata from subprocess import Popen as _Popen, PIPE as _PIPE -def _extract(self, member, path=None, pwd=None): - """for zipfile py2.5 borrowed from cpython""" - if not isinstance(member, zipfile.ZipInfo): - member = self.getinfo(member) - - if path is None: - path = os.getcwd() - - return _extract_member(self, member, path, pwd) - - -def _extract_from_zip(self, name, dest_path): - dest_file = open(dest_path, 'wb') - try: - dest_file.write(self.read(name)) - finally: - dest_file.close() - - -def _extract_member(self, member, targetpath, pwd): - """for zipfile py2.5 borrowed from cpython""" - # build the destination pathname, replacing - # forward slashes to platform specific separators. - # Strip trailing path separator, unless it represents the root. - if (targetpath[-1:] in (os.path.sep, os.path.altsep) - and len(os.path.splitdrive(targetpath)[1]) > 1): - targetpath = targetpath[:-1] - - # don't include leading "/" from file name if present - if member.filename[0] == '/': - targetpath = os.path.join(targetpath, member.filename[1:]) - else: - targetpath = os.path.join(targetpath, member.filename) - - targetpath = os.path.normpath(targetpath) - - # Create all upper directories if necessary. - upperdirs = os.path.dirname(targetpath) - if upperdirs and not os.path.exists(upperdirs): - os.makedirs(upperdirs) - - if member.filename[-1] == '/': - if not os.path.isdir(targetpath): - os.mkdir(targetpath) - return targetpath - - _extract_from_zip(self, member.filename, targetpath) - - return targetpath - - def _remove_dir(target): #on windows this seems to a problem @@ -92,7 +41,7 @@ class ZippedEnvironment(unittest.TestCase): try: zip_file = zipfile.ZipFile(self.datafile) for files in zip_file.namelist(): - _extract(zip_file, files, self.temp_dir) + zip_file.extract(files, self.temp_dir) finally: if zip_file: zip_file.close() @@ -147,10 +96,13 @@ def run_setup_py(cmd, pypath=None, path=None, cmd = [sys.executable, "setup.py"] + list(cmd) - #regarding the shell argument, see: http://bugs.python.org/issue8557 + # http://bugs.python.org/issue8557 + shell = sys.platform == 'win32' + try: - proc = _Popen(cmd, stdout=_PIPE, stderr=_PIPE, - shell=(sys.platform == 'win32'), env=env) + proc = _Popen( + cmd, stdout=_PIPE, stderr=_PIPE, shell=shell, env=env, + ) data = proc.communicate()[data_stream] except OSError: @@ -158,7 +110,8 @@ def run_setup_py(cmd, pypath=None, path=None, #decode the console string if needed if hasattr(data, "decode"): - data = data.decode() # should use the preffered encoding + # use the default encoding + data = data.decode() data = unicodedata.normalize('NFC', data) #communciate calls wait() diff --git a/setuptools/version.py b/setuptools/version.py index 29524eba..4ca9d5df 100644 --- a/setuptools/version.py +++ b/setuptools/version.py @@ -1 +1 @@ -__version__ = '7.0' +__version__ = '8.0' diff --git a/setuptools/windows_support.py b/setuptools/windows_support.py new file mode 100644 index 00000000..cb977cff --- /dev/null +++ b/setuptools/windows_support.py @@ -0,0 +1,29 @@ +import platform +import ctypes + + +def windows_only(func): + if platform.system() != 'Windows': + return lambda *args, **kwargs: None + return func + + +@windows_only +def hide_file(path): + """ + Set the hidden attribute on a file or directory. + + From http://stackoverflow.com/questions/19622133/ + + `path` must be text. + """ + __import__('ctypes.wintypes') + SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW + SetFileAttributes.argtypes = ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD + SetFileAttributes.restype = ctypes.wintypes.BOOL + + FILE_ATTRIBUTE_HIDDEN = 0x02 + + ret = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN) + if not ret: + raise ctypes.WinError() @@ -2,4 +2,4 @@ envlist = py26,py27,py31,py32,py33,py34 [testenv] deps=pytest -commands=py.test +commands=py.test {posargs} |