summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore16
-rw-r--r--.hgignore20
-rw-r--r--.hgtags9
-rw-r--r--CHANGES.txt71
-rw-r--r--DEVGUIDE.txt23
-rw-r--r--docs/developer-guide.txt111
-rw-r--r--docs/development.txt1
-rw-r--r--docs/releases.txt10
-rw-r--r--ez_setup.py2
-rwxr-xr-xsetup.cfg1
-rwxr-xr-xsetup.py17
-rw-r--r--setuptools.egg-info/entry_points.txt2
-rw-r--r--setuptools/command/__init__.py5
-rwxr-xr-xsetuptools/command/alias.py14
-rw-r--r--setuptools/command/bdist_egg.py157
-rwxr-xr-xsetuptools/command/bdist_rpm.py3
-rwxr-xr-xsetuptools/command/bdist_wininst.py1
-rw-r--r--setuptools/command/build_ext.py122
-rw-r--r--setuptools/command/build_py.py65
-rwxr-xr-xsetuptools/command/develop.py60
-rwxr-xr-xsetuptools/command/easy_install.py753
-rwxr-xr-xsetuptools/command/egg_info.py101
-rw-r--r--setuptools/command/install.py18
-rwxr-xr-xsetuptools/command/install_egg_info.py131
-rw-r--r--setuptools/command/install_lib.py12
-rwxr-xr-xsetuptools/command/install_scripts.py13
-rw-r--r--setuptools/command/launcher manifest.xml18
-rwxr-xr-xsetuptools/command/register.py1
-rwxr-xr-xsetuptools/command/rotate.py23
-rwxr-xr-xsetuptools/command/saveopts.py14
-rwxr-xr-xsetuptools/command/sdist.py39
-rwxr-xr-xsetuptools/command/setopt.py45
-rw-r--r--setuptools/command/test.py32
-rw-r--r--setuptools/command/upload_docs.py18
-rw-r--r--setuptools/dist.py22
-rw-r--r--setuptools/script (dev).tmpl (renamed from setuptools/script template (dev).py)6
-rw-r--r--setuptools/script template.py4
-rw-r--r--setuptools/script.tmpl4
-rw-r--r--setuptools/tests/test_develop.py6
-rw-r--r--setuptools/tests/test_find_packages.py16
-rw-r--r--setuptools/tests/test_integration.py80
-rw-r--r--setuptools/version.py2
-rw-r--r--test.sh67
-rw-r--r--tests/api_tests.txt4
-rw-r--r--tox.ini5
45 files changed, 1315 insertions, 829 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..05c0808d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,16 @@
+# syntax: glob
+bin
+build
+dist
+include
+lib
+distribute.egg-info
+setuptools.egg-info
+.coverage
+.tox
+CHANGES (links).txt
+*.egg
+*.py[cod]
+*.swp
+*~
+.hg*
diff --git a/.hgignore b/.hgignore
index 6eb702bc..d70c9a7c 100644
--- a/.hgignore
+++ b/.hgignore
@@ -1,16 +1,16 @@
syntax: glob
-*.pyc
-*~
-*.swp
-.coverage
-distribute.egg-info
-setuptools.egg-info
+bin
build
dist
-lib
-bin
include
-\.Python
-*.swp
+lib
+distribute.egg-info
+setuptools.egg-info
+.coverage
+.tox
CHANGES (links).txt
+*.egg
+*.py[cod]
+*.swp
+*~
.git*
diff --git a/.hgtags b/.hgtags
index 81217163..33e3b636 100644
--- a/.hgtags
+++ b/.hgtags
@@ -136,3 +136,12 @@ e39de2d3eb774b70c023a1151758213cc9ed2178 3.4.1
572201d08eadc59210f6f0f28f9dc79f906672d3 3.5.2
e94e768594a1405efde0b79cc60549dd8a4cda9a 3.6
292dfca15d33e72a862d044183a6ad7c06862a19 3.7b1
+49bd27eebf212c067392796bb2d0fa6d8e583586 3.7
+2fa97c06cc013a9c82f4c1219711e72238d5b6e6 3.8
+9b422fc0b8b97cdb62f02d754283f747adef7f83 3.7.1
+40744de29b848f0e88139ba91d645c08a56855e9 3.8.1
+84d936fd18a93d16c46e68ee2e39f5733f3cd863 5.0
+871bd7b4326f48860ebe0baccdaea8fe4f8f8583 5.0.1
+95996b713722376679c3168b15ab12ea8360dd5f 5.0.2
+3a948b6d01e3449b478fcdc532c44eb3cea5ee10 5.1
+f493e6c4ffd88951871110858c141385305e0077 5.2
diff --git a/CHANGES.txt b/CHANGES.txt
index ebc13373..8bcc529d 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -2,16 +2,79 @@
CHANGES
=======
------
-3.7.?
------
+---
+5.3
+---
-* Issue #185: Make svn tagging work on the new style SVN metadata.
+* Issue #185: Make svn tagging work on the new style SVN metadata.
Thanks cazabon!
* Prune revision control directories (e.g .svn) from base path
as well as sub-directories.
---
+5.2
+---
+
+* Added a `Developer Guide
+ <https://pythonhosted.org/setuptools/developer-guide.html>`_ to the official
+ documentation.
+* Some code refactoring and cleanup was done with no intended behavioral
+ changes.
+* During install_egg_info, the generated lines for namespace package .pth
+ files are now processed even during a dry run.
+
+---
+5.1
+---
+
+* Issue #202: Implemented more robust cache invalidation for the ZipImporter,
+ building on the work in Issue #168. Special thanks to Jurko Gospodnetić and
+ PJE.
+
+-----
+5.0.2
+-----
+
+* Issue #220: Restored script templates.
+
+-----
+5.0.1
+-----
+
+* Renamed script templates to end with .tmpl now that they no longer need
+ to be processed by 2to3. Fixes spurious syntax errors during build/install.
+
+---
+5.0
+---
+
+* Issue #218: Re-release of 3.8.1 to signal that it supersedes 4.x.
+* Incidentally, script templates were updated not to include the triple-quote
+ escaping.
+
+-------------------------
+3.7.1 and 3.8.1 and 4.0.1
+-------------------------
+
+* Issue #213: Use legacy StringIO behavior for compatibility under pbr.
+* Issue #218: Setuptools 3.8.1 superseded 4.0.1, and 4.x was removed
+ from the available versions to install.
+
+---
+4.0
+---
+
+* Issue #210: ``setup.py develop`` now copies scripts in binary mode rather
+ than text mode, matching the behavior of the ``install`` command.
+
+---
+3.8
+---
+
+* Extend Issue #197 workaround to include all Python 3 versions prior to
+ 3.2.2.
+
+---
3.7
---
diff --git a/DEVGUIDE.txt b/DEVGUIDE.txt
index f96d8115..066a3a6b 100644
--- a/DEVGUIDE.txt
+++ b/DEVGUIDE.txt
@@ -1,22 +1 @@
-============================
-Quick notes for contributors
-============================
-
-Setuptools is developed using the DVCS Mercurial.
-
-Grab the code at bitbucket::
-
- $ hg clone https://bitbucket.org/pypa/setuptools
-
-If you want to contribute changes, we recommend you fork the repository on
-bitbucket, commit the changes to your repository, and then make a pull request
-on bitbucket. If you make some changes, don't forget to:
-
-- add a note in CHANGES.txt
-
-Please commit bug-fixes against the current maintenance branch and new
-features to the default branch.
-
-You can run the tests via::
-
- $ python setup.py test
+The canonical development guide can be found in docs/developer-guide.txt.
diff --git a/docs/developer-guide.txt b/docs/developer-guide.txt
new file mode 100644
index 00000000..651e6be8
--- /dev/null
+++ b/docs/developer-guide.txt
@@ -0,0 +1,111 @@
+================================
+Developer's Guide for Setuptools
+================================
+
+If you want to know more about contributing on Setuptools, this is the place.
+
+
+.. contents:: **Table of Contents**
+
+
+-------------------
+Recommended Reading
+-------------------
+
+Please read `How to write the perfect pull request
+<http://blog.jaraco.com/2014/04/how-to-write-perfect-pull-request.html>`_
+for some tips on contributing to open source projects. Although the article
+is not authoritative, it was authored by the maintainer of Setuptools, so
+reflects his opinions and will improve the likelihood of acceptance and
+quality of contribution.
+
+------------------
+Project Management
+------------------
+
+Setuptools is maintained primarily in Bitbucket at `this home
+<https://bitbucket.org/pypa/setuptools>`_. Setuptools is maintained under the
+Python Packaging Authority (PyPA) with several core contributors. All bugs
+for Setuptools are filed and the canonical source is maintained in Bitbucket.
+
+User support and discussions are done through the issue tracker (for specific)
+issues, through the distutils-sig mailing list, or on IRC (Freenode) at
+#pypa.
+
+Discussions about development happen on the pypa-dev mailing list or on IRC
+(Freenode) at #pypa-dev.
+
+-----------------
+Authoring Tickets
+-----------------
+
+Before authoring any source code, it's often prudent to file a ticket
+describing the motivation behind making changes. First search to see if a
+ticket already exists for your issue. If not, create one. Try to think from
+the perspective of the reader. Explain what behavior you expected, what you
+got instead, and what factors might have contributed to the unexpected
+behavior. In Bitbucket, surround a block of code or traceback with the triple
+backtick "```" so that it is formatted nicely.
+
+Filing a ticket provides a forum for justification, discussion, and
+clarification. The ticket provides a record of the purpose for the change and
+any hard decisions that were made. It provides a single place for others to
+reference when trying to understand why the software operates the way it does
+or why certain changes were made.
+
+Setuptools makes extensive use of hyperlinks to tickets in the changelog so
+that system integrators and other users can get a quick summary, but then
+jump to the in-depth discussion about any subject referenced.
+
+-----------
+Source Code
+-----------
+
+Grab the code at Bitbucket::
+
+ $ hg clone https://bitbucket.org/pypa/setuptools
+
+If you want to contribute changes, we recommend you fork the repository on
+Bitbucket, commit the changes to your repository, and then make a pull request
+on Bitbucket. If you make some changes, don't forget to:
+
+- add a note in CHANGES.txt
+
+Please commit all changes in the 'default' branch against the latest available
+commit or for bug-fixes, against an earlier commit or release in which the
+bug occurred.
+
+If you find yourself working on more than one issue at a time, Setuptools
+generally prefers Git-style branches, so use Mercurial bookmarks or Git
+branches or multiple forks to maintain separate efforts.
+
+Setuptools also maintains an unofficial `Git mirror in Github
+<https://github.com/jaraco/setuptools>`_. Contributors are welcome to submit
+pull requests here, but because they are not integrated with the Bitbucket
+Issue tracker, linking pull requests to tickets is more difficult. The
+Continuous Integration tests that validate every release are run from this
+mirror.
+
+-------
+Testing
+-------
+
+The primary tests are run using py.test. To run the tests::
+
+ $ python setup.py ptr
+
+Or install py.test into your environment and run ``py.test``.
+
+Under continuous integration, additional tests may be run. See the
+``.travis.yml`` file for full details on the tests run under Travis-CI.
+
+-------------------
+Semantic Versioning
+-------------------
+
+Setuptools follows ``semver`` with some exceptions:
+
+- Uses two-segment version when three segment version ends in zero
+- Omits 'v' prefix for tags.
+
+.. explain value of reflecting meaning in versions.
diff --git a/docs/development.txt b/docs/development.txt
index ba927c73..6fe30f6e 100644
--- a/docs/development.txt
+++ b/docs/development.txt
@@ -30,6 +30,7 @@ setuptools changes. You have been warned.
.. toctree::
:maxdepth: 1
+ developer-guide
formats
releases
diff --git a/docs/releases.txt b/docs/releases.txt
index 5d1419be..41a814bc 100644
--- a/docs/releases.txt
+++ b/docs/releases.txt
@@ -12,7 +12,15 @@ the release process.
A Setuptools release manager must have maintainer access on PyPI to the
project and administrative access to the BitBucket project.
+To make a release, run the following from a Mercurial checkout at the
+revision slated for release::
+
+ python -m jaraco.packaging.release
+
Release Managers
----------------
-Currently, the project has one release manager, Jason R. Coombs.
+Jason R. Coombs is the primary release manager. Additionally, the following
+people have access to create releases:
+
+- Matthew Iversen (Ivoz)
diff --git a/ez_setup.py b/ez_setup.py
index 1f2468f9..2dc324f3 100644
--- a/ez_setup.py
+++ b/ez_setup.py
@@ -36,7 +36,7 @@ try:
except ImportError:
USER_SITE = None
-DEFAULT_VERSION = "3.7"
+DEFAULT_VERSION = "5.3"
DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
def _python_cmd(*args):
diff --git a/setup.cfg b/setup.cfg
index eb63264c..7f5fc796 100755
--- a/setup.cfg
+++ b/setup.cfg
@@ -22,3 +22,4 @@ universal=1
[pytest]
addopts=--ignore tests/manual_test.py --ignore tests/shlib_test
+norecursedirs=dist build *.egg
diff --git a/setup.py b/setup.py
index caad6496..f7be0567 100755
--- a/setup.py
+++ b/setup.py
@@ -90,17 +90,18 @@ class test(_test):
readme_file = io.open('README.txt', encoding='utf-8')
-# the release script adds hyperlinks to issues
-if os.path.exists('CHANGES (links).txt'):
- changes_file = open('CHANGES (links).txt')
-else:
- # but if the release script has not run, fall back to the source file
- changes_file = open('CHANGES.txt')
+# The release script adds hyperlinks to issues,
+# but if the release script has not run, fall back to the source file
+changes_names = 'CHANGES (links).txt', 'CHANGES.txt'
+changes_fn = next(iter(filter(os.path.exists, changes_names)))
+changes_file = io.open(changes_fn, encoding='utf-8')
+
with readme_file:
with changes_file:
long_description = readme_file.read() + '\n' + changes_file.read()
-package_data = {'setuptools': ['site-patch.py']}
+package_data = {
+ 'setuptools': ['script (dev).tmpl', 'script.tmpl', 'site-patch.py']}
force_windows_specific_files = (
os.environ.get("SETUPTOOLS_INSTALL_WINDOWS_SPECIFIC_FILES")
not in (None, "", "0")
@@ -121,7 +122,7 @@ setup_params = dict(
license="PSF or ZPL",
long_description=long_description,
keywords="CPAN PyPI distutils eggs package management",
- url="https://pypi.python.org/pypi/setuptools",
+ url="https://bitbucket.org/pypa/setuptools",
test_suite='setuptools.tests',
src_root=src_root,
packages=setuptools.find_packages(),
diff --git a/setuptools.egg-info/entry_points.txt b/setuptools.egg-info/entry_points.txt
index c345395d..de842da8 100644
--- a/setuptools.egg-info/entry_points.txt
+++ b/setuptools.egg-info/entry_points.txt
@@ -1,6 +1,6 @@
[console_scripts]
easy_install = setuptools.command.easy_install:main
-easy_install-3.3 = setuptools.command.easy_install:main
+easy_install-3.4 = setuptools.command.easy_install:main
[distutils.commands]
alias = setuptools.command.alias:alias
diff --git a/setuptools/command/__init__.py b/setuptools/command/__init__.py
index 29c9d75a..f6dbc39c 100644
--- a/setuptools/command/__init__.py
+++ b/setuptools/command/__init__.py
@@ -5,10 +5,11 @@ __all__ = [
'register', 'bdist_wininst', 'upload_docs',
]
-from setuptools.command import install_scripts
+from distutils.command.bdist import bdist
import sys
-from distutils.command.bdist import bdist
+from setuptools.command import install_scripts
+
if 'egg' not in bdist.format_commands:
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
diff --git a/setuptools/command/alias.py b/setuptools/command/alias.py
index 05c0766b..452a9244 100755
--- a/setuptools/command/alias.py
+++ b/setuptools/command/alias.py
@@ -2,10 +2,12 @@ from distutils.errors import DistutilsOptionError
from setuptools.command.setopt import edit_config, option_base, config_file
+
def shquote(arg):
"""Quote an argument for later parsing by shlex.split()"""
for c in '"', "'", "\\", "#":
- if c in arg: return repr(arg)
+ if c in arg:
+ return repr(arg)
if arg.split() != [arg]:
return repr(arg)
return arg
@@ -18,7 +20,7 @@ class alias(option_base):
command_consumes_arguments = True
user_options = [
- ('remove', 'r', 'remove (unset) the alias'),
+ ('remove', 'r', 'remove (unset) the alias'),
] + option_base.user_options
boolean_options = option_base.boolean_options + ['remove']
@@ -46,7 +48,7 @@ class alias(option_base):
print("setup.py alias", format_alias(alias, aliases))
return
- elif len(self.args)==1:
+ elif len(self.args) == 1:
alias, = self.args
if self.remove:
command = None
@@ -58,9 +60,9 @@ class alias(option_base):
return
else:
alias = self.args[0]
- command = ' '.join(map(shquote,self.args[1:]))
+ command = ' '.join(map(shquote, self.args[1:]))
- edit_config(self.filename, {'aliases': {alias:command}}, self.dry_run)
+ edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run)
def format_alias(name, aliases):
@@ -73,4 +75,4 @@ def format_alias(name, aliases):
source = ''
else:
source = '--filename=%r' % source
- return source+name+' '+command
+ return source + name + ' ' + command
diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py
index c19a0ba7..831d6042 100644
--- a/setuptools/command/bdist_egg.py
+++ b/setuptools/command/bdist_egg.py
@@ -3,29 +3,33 @@
Build .egg distributions"""
# This module should be kept compatible with Python 2.3
+from distutils.errors import DistutilsSetupError
+from distutils.dir_util import remove_tree, mkpath
+from distutils import log
+from types import CodeType
import sys
import os
import marshal
import textwrap
+
+from pkg_resources import get_build_platform, Distribution, ensure_directory
+from pkg_resources import EntryPoint
+from setuptools.compat import basestring, next
+from setuptools.extension import Library
from setuptools import Command
-from distutils.dir_util import remove_tree, mkpath
+
try:
# Python 2.7 or >=3.2
from sysconfig import get_path, get_python_version
+
def _get_purelib():
return get_path("purelib")
except ImportError:
from distutils.sysconfig import get_python_lib, get_python_version
+
def _get_purelib():
return get_python_lib(False)
-from distutils import log
-from distutils.errors import DistutilsSetupError
-from pkg_resources import get_build_platform, Distribution, ensure_directory
-from pkg_resources import EntryPoint
-from types import CodeType
-from setuptools.compat import basestring, next
-from setuptools.extension import Library
def strip_module(filename):
if '.' in filename:
@@ -34,6 +38,7 @@ def strip_module(filename):
filename = filename[:-6]
return filename
+
def write_stub(resource, pyfile):
_stub_template = textwrap.dedent("""
def __bootstrap__():
@@ -49,23 +54,22 @@ def write_stub(resource, pyfile):
class bdist_egg(Command):
-
description = "create an \"egg\" distribution"
user_options = [
('bdist-dir=', 'b',
- "temporary directory for creating the distribution"),
+ "temporary directory for creating the distribution"),
('plat-name=', 'p', "platform name to embed in generated filenames "
- "(default: %s)" % get_build_platform()),
+ "(default: %s)" % get_build_platform()),
('exclude-source-files', None,
- "remove all .py files from the generated egg"),
+ "remove all .py files from the generated egg"),
('keep-temp', 'k',
- "keep the pseudo-installation tree around after " +
- "creating the distribution archive"),
+ "keep the pseudo-installation tree around after " +
+ "creating the distribution archive"),
('dist-dir=', 'd',
- "directory to put final built distributions in"),
+ "directory to put final built distributions in"),
('skip-build', None,
- "skip rebuilding everything (for testing/debugging)"),
+ "skip rebuilding everything (for testing/debugging)"),
]
boolean_options = [
@@ -92,7 +96,7 @@ class bdist_egg(Command):
if self.plat_name is None:
self.plat_name = get_build_platform()
- self.set_undefined_options('bdist',('dist_dir', 'dist_dir'))
+ self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
if self.egg_output is None:
@@ -103,25 +107,25 @@ class bdist_egg(Command):
self.distribution.has_ext_modules() and self.plat_name
).egg_name()
- self.egg_output = os.path.join(self.dist_dir, basename+'.egg')
+ self.egg_output = os.path.join(self.dist_dir, basename + '.egg')
def do_install_data(self):
# Hack for packages that install data to install's --install-lib
self.get_finalized_command('install').install_lib = self.bdist_dir
site_packages = os.path.normcase(os.path.realpath(_get_purelib()))
- old, self.distribution.data_files = self.distribution.data_files,[]
+ old, self.distribution.data_files = self.distribution.data_files, []
for item in old:
- if isinstance(item,tuple) and len(item)==2:
+ if isinstance(item, tuple) and len(item) == 2:
if os.path.isabs(item[0]):
realpath = os.path.realpath(item[0])
normalized = os.path.normcase(realpath)
- if normalized==site_packages or normalized.startswith(
- site_packages+os.sep
+ if normalized == site_packages or normalized.startswith(
+ site_packages + os.sep
):
- item = realpath[len(site_packages)+1:], item[1]
- # XXX else: raise ???
+ item = realpath[len(site_packages) + 1:], item[1]
+ # XXX else: raise ???
self.distribution.data_files.append(item)
try:
@@ -133,11 +137,11 @@ class bdist_egg(Command):
def get_outputs(self):
return [self.egg_output]
- def call_command(self,cmdname,**kw):
+ def call_command(self, cmdname, **kw):
"""Invoke reinitialized command `cmdname` with keyword args"""
for dirname in INSTALL_DIRECTORY_ATTRS:
- kw.setdefault(dirname,self.bdist_dir)
- kw.setdefault('skip_build',self.skip_build)
+ kw.setdefault(dirname, self.bdist_dir)
+ kw.setdefault('skip_build', self.skip_build)
kw.setdefault('dry_run', self.dry_run)
cmd = self.reinitialize_command(cmdname, **kw)
self.run_command(cmdname)
@@ -160,15 +164,16 @@ class bdist_egg(Command):
all_outputs, ext_outputs = self.get_ext_outputs()
self.stubs = []
to_compile = []
- for (p,ext_name) in enumerate(ext_outputs):
- filename,ext = os.path.splitext(ext_name)
- pyfile = os.path.join(self.bdist_dir, strip_module(filename)+'.py')
+ for (p, ext_name) in enumerate(ext_outputs):
+ filename, ext = os.path.splitext(ext_name)
+ pyfile = os.path.join(self.bdist_dir, strip_module(filename) +
+ '.py')
self.stubs.append(pyfile)
log.info("creating stub loader for %s" % ext_name)
if not self.dry_run:
write_stub(os.path.basename(ext_name), pyfile)
to_compile.append(pyfile)
- ext_outputs[p] = ext_name.replace(os.sep,'/')
+ ext_outputs[p] = ext_name.replace(os.sep, '/')
if to_compile:
cmd.byte_compile(to_compile)
@@ -177,12 +182,13 @@ class bdist_egg(Command):
# Make the EGG-INFO directory
archive_root = self.bdist_dir
- egg_info = os.path.join(archive_root,'EGG-INFO')
+ egg_info = os.path.join(archive_root, 'EGG-INFO')
self.mkpath(egg_info)
if self.distribution.scripts:
script_dir = os.path.join(egg_info, 'scripts')
log.info("installing scripts to %s" % script_dir)
- self.call_command('install_scripts',install_dir=script_dir,no_ep=1)
+ self.call_command('install_scripts', install_dir=script_dir,
+ no_ep=1)
self.copy_metadata_to(egg_info)
native_libs = os.path.join(egg_info, "native_libs.txt")
@@ -200,10 +206,10 @@ class bdist_egg(Command):
os.unlink(native_libs)
write_safety_flag(
- os.path.join(archive_root,'EGG-INFO'), self.zip_safe()
+ os.path.join(archive_root, 'EGG-INFO'), self.zip_safe()
)
- if os.path.exists(os.path.join(self.egg_info,'depends.txt')):
+ if os.path.exists(os.path.join(self.egg_info, 'depends.txt')):
log.warn(
"WARNING: 'depends.txt' will not be used by setuptools 0.6!\n"
"Use the install_requires/extras_require setup() args instead."
@@ -214,25 +220,25 @@ class bdist_egg(Command):
# Make the archive
make_zipfile(self.egg_output, archive_root, verbose=self.verbose,
- dry_run=self.dry_run, mode=self.gen_header())
+ dry_run=self.dry_run, mode=self.gen_header())
if not self.keep_temp:
remove_tree(self.bdist_dir, dry_run=self.dry_run)
# Add to 'Distribution.dist_files' so that the "upload" command works
- getattr(self.distribution,'dist_files',[]).append(
- ('bdist_egg',get_python_version(),self.egg_output))
+ getattr(self.distribution, 'dist_files', []).append(
+ ('bdist_egg', get_python_version(), self.egg_output))
def zap_pyfiles(self):
log.info("Removing .py files from temporary directory")
- for base,dirs,files in walk_egg(self.bdist_dir):
+ for base, dirs, files in walk_egg(self.bdist_dir):
for name in files:
if name.endswith('.py'):
- path = os.path.join(base,name)
+ path = os.path.join(base, name)
log.debug("Deleting %s", path)
os.unlink(path)
def zip_safe(self):
- safe = getattr(self.distribution,'zip_safe',None)
+ safe = getattr(self.distribution, 'zip_safe', None)
if safe is not None:
return safe
log.warn("zip_safe flag not set; analyzing archive contents...")
@@ -240,7 +246,7 @@ class bdist_egg(Command):
def gen_header(self):
epm = EntryPoint.parse_map(self.distribution.entry_points or '')
- ep = epm.get('setuptools.installation',{}).get('eggsecutable')
+ ep = epm.get('setuptools.installation', {}).get('eggsecutable')
if ep is None:
return 'w' # not an eggsecutable, do it the usual way.
@@ -268,7 +274,6 @@ class bdist_egg(Command):
' echo Please rename it back to %(basename)s and try again.\n'
' exec false\n'
'fi\n'
-
) % locals()
if not self.dry_run:
@@ -283,7 +288,7 @@ class bdist_egg(Command):
# normalize the path (so that a forward-slash in egg_info will
# match using startswith below)
norm_egg_info = os.path.normpath(self.egg_info)
- prefix = os.path.join(norm_egg_info,'')
+ prefix = os.path.join(norm_egg_info, '')
for path in self.ei_cmd.filelist.files:
if path.startswith(prefix):
target = os.path.join(target_dir, path[len(prefix):])
@@ -296,23 +301,24 @@ class bdist_egg(Command):
all_outputs = []
ext_outputs = []
- paths = {self.bdist_dir:''}
+ paths = {self.bdist_dir: ''}
for base, dirs, files in os.walk(self.bdist_dir):
for filename in files:
if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS:
- all_outputs.append(paths[base]+filename)
+ all_outputs.append(paths[base] + filename)
for filename in dirs:
- paths[os.path.join(base,filename)] = paths[base]+filename+'/'
+ paths[os.path.join(base, filename)] = (paths[base] +
+ filename + '/')
if self.distribution.has_ext_modules():
build_cmd = self.get_finalized_command('build_ext')
for ext in build_cmd.extensions:
- if isinstance(ext,Library):
+ if isinstance(ext, Library):
continue
fullname = build_cmd.get_ext_fullname(ext.name)
filename = build_cmd.get_ext_filename(fullname)
if not os.path.basename(filename).startswith('dl-'):
- if os.path.exists(os.path.join(self.bdist_dir,filename)):
+ if os.path.exists(os.path.join(self.bdist_dir, filename)):
ext_outputs.append(filename)
return all_outputs, ext_outputs
@@ -324,19 +330,21 @@ NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split())
def walk_egg(egg_dir):
"""Walk an unpacked egg's contents, skipping the metadata directory"""
walker = os.walk(egg_dir)
- base,dirs,files = next(walker)
+ base, dirs, files = next(walker)
if 'EGG-INFO' in dirs:
dirs.remove('EGG-INFO')
- yield base,dirs,files
+ yield base, dirs, files
for bdf in walker:
yield bdf
+
def analyze_egg(egg_dir, stubs):
# check for existing flag in EGG-INFO
- for flag,fn in safety_flags.items():
- if os.path.exists(os.path.join(egg_dir,'EGG-INFO',fn)):
+ for flag, fn in safety_flags.items():
+ if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)):
return flag
- if not can_scan(): return False
+ if not can_scan():
+ return False
safe = True
for base, dirs, files in walk_egg(egg_dir):
for name in files:
@@ -347,36 +355,39 @@ def analyze_egg(egg_dir, stubs):
safe = scan_module(egg_dir, base, name, stubs) and safe
return safe
+
def write_safety_flag(egg_dir, safe):
# Write or remove zip safety flag file(s)
- for flag,fn in safety_flags.items():
+ for flag, fn in safety_flags.items():
fn = os.path.join(egg_dir, fn)
if os.path.exists(fn):
if safe is None or bool(safe) != flag:
os.unlink(fn)
- elif safe is not None and bool(safe)==flag:
- f = open(fn,'wt')
+ elif safe is not None and bool(safe) == flag:
+ f = open(fn, 'wt')
f.write('\n')
f.close()
+
safety_flags = {
True: 'zip-safe',
False: 'not-zip-safe',
}
+
def scan_module(egg_dir, base, name, stubs):
"""Check whether module possibly uses unsafe-for-zipfile stuff"""
- filename = os.path.join(base,name)
+ filename = os.path.join(base, name)
if filename[:-1] in stubs:
- return True # Extension module
- pkg = base[len(egg_dir)+1:].replace(os.sep,'.')
- module = pkg+(pkg and '.' or '')+os.path.splitext(name)[0]
+ return True # Extension module
+ pkg = base[len(egg_dir) + 1:].replace(os.sep, '.')
+ module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0]
if sys.version_info < (3, 3):
- skip = 8 # skip magic & date
+ skip = 8 # skip magic & date
else:
skip = 12 # skip magic & date & file size
- f = open(filename,'rb')
+ f = open(filename, 'rb')
f.read(skip)
code = marshal.load(f)
f.close()
@@ -396,21 +407,24 @@ def scan_module(egg_dir, base, name, stubs):
log.warn("%s: module MAY be using inspect.%s", module, bad)
safe = False
if '__name__' in symbols and '__main__' in symbols and '.' not in module:
- if sys.version[:3]=="2.4": # -m works w/zipfiles in 2.5
+ if sys.version[:3] == "2.4": # -m works w/zipfiles in 2.5
log.warn("%s: top-level module may be 'python -m' script", module)
safe = False
return safe
+
def iter_symbols(code):
"""Yield names and strings used by `code` and its nested code objects"""
- for name in code.co_names: yield name
+ for name in code.co_names:
+ yield name
for const in code.co_consts:
- if isinstance(const,basestring):
+ if isinstance(const, basestring):
yield const
- elif isinstance(const,CodeType):
+ elif isinstance(const, CodeType):
for name in iter_symbols(const):
yield name
+
def can_scan():
if not sys.platform.startswith('java') and sys.platform != 'cli':
# CPython, PyPy, etc.
@@ -426,8 +440,9 @@ INSTALL_DIRECTORY_ATTRS = [
'install_lib', 'install_dir', 'install_data', 'install_base'
]
+
def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
- mode='w'):
+ mode='w'):
"""Create a zip file from all the files under 'base_dir'. The output
zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
Python module (if available) or the InfoZIP "zip" utility (if installed
@@ -435,6 +450,7 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
raises DistutilsExecError. Returns the name of the output zip file.
"""
import zipfile
+
mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
@@ -442,13 +458,14 @@ def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=None,
for name in names:
path = os.path.normpath(os.path.join(dirname, name))
if os.path.isfile(path):
- p = path[len(base_dir)+1:]
+ p = path[len(base_dir) + 1:]
if not dry_run:
z.write(path, p)
log.debug("adding '%s'" % p)
if compress is None:
- compress = (sys.version>="2.4") # avoid 2.3 zipimport bug when 64 bits
+ # avoid 2.3 zipimport bug when 64 bits
+ compress = (sys.version >= "2.4")
compression = [zipfile.ZIP_STORED, zipfile.ZIP_DEFLATED][bool(compress)]
if not dry_run:
diff --git a/setuptools/command/bdist_rpm.py b/setuptools/command/bdist_rpm.py
index 99386824..70730927 100755
--- a/setuptools/command/bdist_rpm.py
+++ b/setuptools/command/bdist_rpm.py
@@ -1,5 +1,6 @@
import distutils.command.bdist_rpm as orig
+
class bdist_rpm(orig.bdist_rpm):
"""
Override the default bdist_rpm behavior to do the following:
@@ -19,7 +20,7 @@ class bdist_rpm(orig.bdist_rpm):
def _make_spec_file(self):
version = self.distribution.get_version()
- rpmversion = version.replace('-','_')
+ rpmversion = version.replace('-', '_')
spec = orig.bdist_rpm._make_spec_file(self)
line23 = '%define version ' + version
line24 = '%define version ' + rpmversion
diff --git a/setuptools/command/bdist_wininst.py b/setuptools/command/bdist_wininst.py
index f9d8d4f0..073de97b 100755
--- a/setuptools/command/bdist_wininst.py
+++ b/setuptools/command/bdist_wininst.py
@@ -1,5 +1,6 @@
import distutils.command.bdist_wininst as orig
+
class bdist_wininst(orig.bdist_wininst):
def reinitialize_command(self, command, reinit_subcommands=0):
"""
diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py
index e08131d7..53bf9cd3 100644
--- a/setuptools/command/build_ext.py
+++ b/setuptools/command/build_ext.py
@@ -1,26 +1,29 @@
from distutils.command.build_ext import build_ext as _du_build_ext
+from distutils.file_util import copy_file
+from distutils.ccompiler import new_compiler
+from distutils.sysconfig import customize_compiler
+from distutils.errors import DistutilsError
+from distutils import log
+import os
+import sys
+
+from setuptools.extension import Library
+
try:
# Attempt to use Pyrex for building extensions, if available
from Pyrex.Distutils.build_ext import build_ext as _build_ext
except ImportError:
_build_ext = _du_build_ext
-import os
-import sys
-from distutils.file_util import copy_file
-from setuptools.extension import Library
-from distutils.ccompiler import new_compiler
-from distutils.sysconfig import customize_compiler
try:
# Python 2.7 or >=3.2
from sysconfig import _CONFIG_VARS
except ImportError:
from distutils.sysconfig import get_config_var
+
get_config_var("LDSHARED") # make sure _config_vars is initialized
del get_config_var
from distutils.sysconfig import _config_vars as _CONFIG_VARS
-from distutils import log
-from distutils.errors import DistutilsError
have_rtld = False
use_stubs = False
@@ -31,11 +34,13 @@ if sys.platform == "darwin":
elif os.name != 'nt':
try:
from dl import RTLD_NOW
+
have_rtld = True
use_stubs = True
except ImportError:
pass
+
def if_dl(s):
if have_rtld:
return s
@@ -59,8 +64,9 @@ class build_ext(_build_ext):
modpath = fullname.split('.')
package = '.'.join(modpath[:-1])
package_dir = build_py.get_package_dir(package)
- dest_filename = os.path.join(package_dir,os.path.basename(filename))
- src_filename = os.path.join(self.build_lib,filename)
+ dest_filename = os.path.join(package_dir,
+ os.path.basename(filename))
+ src_filename = os.path.join(self.build_lib, filename)
# Always copy, even if source is older than destination, to ensure
# that the right extensions for the current Python/platform are
@@ -72,7 +78,8 @@ class build_ext(_build_ext):
if ext._needs_stub:
self.write_stub(package_dir or os.curdir, ext, True)
- if _build_ext is not _du_build_ext and not hasattr(_build_ext,'pyrex_sources'):
+ if _build_ext is not _du_build_ext and not hasattr(_build_ext,
+ 'pyrex_sources'):
# Workaround for problems using some Pyrex versions w/SWIG and/or 2.4
def swig_sources(self, sources, *otherargs):
# first do any Pyrex processing
@@ -81,15 +88,15 @@ class build_ext(_build_ext):
return _du_build_ext.swig_sources(self, sources, *otherargs)
def get_ext_filename(self, fullname):
- filename = _build_ext.get_ext_filename(self,fullname)
+ filename = _build_ext.get_ext_filename(self, fullname)
if fullname in self.ext_map:
ext = self.ext_map[fullname]
- if isinstance(ext,Library):
+ if isinstance(ext, Library):
fn, ext = os.path.splitext(filename)
- return self.shlib_compiler.library_filename(fn,libtype)
+ return self.shlib_compiler.library_filename(fn, libtype)
elif use_stubs and ext._links_to_dynamic:
- d,fn = os.path.split(filename)
- return os.path.join(d,'dl-'+fn)
+ d, fn = os.path.split(filename)
+ return os.path.join(d, 'dl-' + fn)
return filename
def initialize_options(self):
@@ -103,7 +110,7 @@ class build_ext(_build_ext):
self.extensions = self.extensions or []
self.check_extensions_list(self.extensions)
self.shlibs = [ext for ext in self.extensions
- if isinstance(ext, Library)]
+ if isinstance(ext, Library)]
if self.shlibs:
self.setup_shlib_compiler()
for ext in self.extensions:
@@ -118,9 +125,10 @@ class build_ext(_build_ext):
ltd = ext._links_to_dynamic = \
self.shlibs and self.links_to_dynamic(ext) or False
- ext._needs_stub = ltd and use_stubs and not isinstance(ext,Library)
+ ext._needs_stub = ltd and use_stubs and not isinstance(ext,
+ Library)
filename = ext._file_name = self.get_ext_filename(fullname)
- libdir = os.path.dirname(os.path.join(self.build_lib,filename))
+ libdir = os.path.dirname(os.path.join(self.build_lib, filename))
if ltd and libdir not in ext.library_dirs:
ext.library_dirs.append(libdir)
if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs:
@@ -134,7 +142,8 @@ class build_ext(_build_ext):
tmp = _CONFIG_VARS.copy()
try:
# XXX Help! I don't have any idea whether these are right...
- _CONFIG_VARS['LDSHARED'] = "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup"
+ _CONFIG_VARS['LDSHARED'] = (
+ "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup")
_CONFIG_VARS['CCSHARED'] = " -dynamiclib"
_CONFIG_VARS['SO'] = ".dylib"
customize_compiler(compiler)
@@ -148,7 +157,7 @@ class build_ext(_build_ext):
compiler.set_include_dirs(self.include_dirs)
if self.define is not None:
# 'define' option is a list of (name,value) tuples
- for (name,value) in self.define:
+ for (name, value) in self.define:
compiler.define_macro(name, value)
if self.undef is not None:
for macro in self.undef:
@@ -166,16 +175,16 @@ class build_ext(_build_ext):
compiler.link_shared_object = link_shared_object.__get__(compiler)
def get_export_symbols(self, ext):
- if isinstance(ext,Library):
+ if isinstance(ext, Library):
return ext.export_symbols
- return _build_ext.get_export_symbols(self,ext)
+ return _build_ext.get_export_symbols(self, ext)
def build_extension(self, ext):
_compiler = self.compiler
try:
- if isinstance(ext,Library):
+ if isinstance(ext, Library):
self.compiler = self.shlib_compiler
- _build_ext.build_extension(self,ext)
+ _build_ext.build_extension(self, ext)
if ext._needs_stub:
self.write_stub(
self.get_finalized_command('build_py').build_lib, ext
@@ -189,9 +198,10 @@ class build_ext(_build_ext):
# XXX as dynamic, and not just using a locally-found version or a
# XXX static-compiled version
libnames = dict.fromkeys([lib._full_name for lib in self.shlibs])
- pkg = '.'.join(ext._full_name.split('.')[:-1]+[''])
+ pkg = '.'.join(ext._full_name.split('.')[:-1] + [''])
for libname in ext.libraries:
- if pkg+libname in libnames: return True
+ if pkg + libname in libnames:
+ return True
return False
def get_outputs(self):
@@ -200,26 +210,29 @@ class build_ext(_build_ext):
for ext in self.extensions:
if ext._needs_stub:
base = os.path.join(self.build_lib, *ext._full_name.split('.'))
- outputs.append(base+'.py')
- outputs.append(base+'.pyc')
+ outputs.append(base + '.py')
+ outputs.append(base + '.pyc')
if optimize:
- outputs.append(base+'.pyo')
+ outputs.append(base + '.pyo')
return outputs
def write_stub(self, output_dir, ext, compile=False):
- log.info("writing stub loader for %s to %s",ext._full_name, output_dir)
- stub_file = os.path.join(output_dir, *ext._full_name.split('.'))+'.py'
+ log.info("writing stub loader for %s to %s", ext._full_name,
+ output_dir)
+ stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) +
+ '.py')
if compile and os.path.exists(stub_file):
- raise DistutilsError(stub_file+" already exists! Please delete.")
+ raise DistutilsError(stub_file + " already exists! Please delete.")
if not self.dry_run:
- f = open(stub_file,'w')
+ f = open(stub_file, 'w')
f.write(
'\n'.join([
"def __bootstrap__():",
" global __bootstrap__, __file__, __loader__",
- " import sys, os, pkg_resources, imp"+if_dl(", dl"),
- " __file__ = pkg_resources.resource_filename(__name__,%r)"
- % os.path.basename(ext._file_name),
+ " import sys, os, pkg_resources, imp" + if_dl(", dl"),
+ " __file__ = pkg_resources.resource_filename"
+ "(__name__,%r)"
+ % os.path.basename(ext._file_name),
" del __bootstrap__",
" if '__loader__' in globals():",
" del __loader__",
@@ -233,12 +246,13 @@ class build_ext(_build_ext):
if_dl(" sys.setdlopenflags(old_flags)"),
" os.chdir(old_dir)",
"__bootstrap__()",
- "" # terminal \n
+ "" # terminal \n
])
)
f.close()
if compile:
from distutils.util import byte_compile
+
byte_compile([stub_file], optimize=0,
force=True, dry_run=self.dry_run)
optimize = self.get_finalized_command('install_lib').optimize
@@ -249,13 +263,14 @@ class build_ext(_build_ext):
os.unlink(stub_file)
-if use_stubs or os.name=='nt':
+if use_stubs or os.name == 'nt':
# Build shared libraries
#
- def link_shared_object(self, objects, output_libname, output_dir=None,
- libraries=None, library_dirs=None, runtime_library_dirs=None,
- export_symbols=None, debug=0, extra_preargs=None,
- extra_postargs=None, build_temp=None, target_lang=None):
+ def link_shared_object(
+ self, objects, output_libname, output_dir=None, libraries=None,
+ library_dirs=None, runtime_library_dirs=None, export_symbols=None,
+ debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
+ target_lang=None):
self.link(
self.SHARED_LIBRARY, objects, output_libname,
output_dir, libraries, library_dirs, runtime_library_dirs,
@@ -266,18 +281,19 @@ else:
# Build static libraries everywhere else
libtype = 'static'
- def link_shared_object(self, objects, output_libname, output_dir=None,
- libraries=None, library_dirs=None, runtime_library_dirs=None,
- export_symbols=None, debug=0, extra_preargs=None,
- extra_postargs=None, build_temp=None, target_lang=None):
+ def link_shared_object(
+ self, objects, output_libname, output_dir=None, libraries=None,
+ library_dirs=None, runtime_library_dirs=None, export_symbols=None,
+ debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
+ target_lang=None):
# XXX we need to either disallow these attrs on Library instances,
- # or warn/abort here if set, or something...
- #libraries=None, library_dirs=None, runtime_library_dirs=None,
- #export_symbols=None, extra_preargs=None, extra_postargs=None,
- #build_temp=None
+ # or warn/abort here if set, or something...
+ # libraries=None, library_dirs=None, runtime_library_dirs=None,
+ # export_symbols=None, extra_preargs=None, extra_postargs=None,
+ # build_temp=None
- assert output_dir is None # distutils build_ext doesn't pass this
- output_dir,filename = os.path.split(output_libname)
+ assert output_dir is None # distutils build_ext doesn't pass this
+ output_dir, filename = os.path.split(output_libname)
basename, ext = os.path.splitext(filename)
if self.library_filename("x").startswith('lib'):
# strip 'lib' prefix; this is kludgy if some platform uses
diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py
index 53bfb7df..98080694 100644
--- a/setuptools/command/build_py.py
+++ b/setuptools/command/build_py.py
@@ -1,10 +1,10 @@
+from glob import glob
+from distutils.util import convert_path
+import distutils.command.build_py as orig
import os
import sys
import fnmatch
import textwrap
-import distutils.command.build_py as orig
-from distutils.util import convert_path
-from glob import glob
try:
from setuptools.lib2to3_ex import Mixin2to3
@@ -13,6 +13,7 @@ except ImportError:
def run_2to3(self, files, doctests=True):
"do nothing"
+
class build_py(orig.build_py, Mixin2to3):
"""Enhanced 'build_py' command that includes data files with packages
@@ -22,11 +23,14 @@ class build_py(orig.build_py, Mixin2to3):
Also, this version of the 'build_py' command allows you to specify both
'py_modules' and 'packages' in the same setup operation.
"""
+
def finalize_options(self):
orig.build_py.finalize_options(self)
self.package_data = self.distribution.package_data
- self.exclude_package_data = self.distribution.exclude_package_data or {}
- if 'data_files' in self.__dict__: del self.__dict__['data_files']
+ self.exclude_package_data = (self.distribution.exclude_package_data or
+ {})
+ if 'data_files' in self.__dict__:
+ del self.__dict__['data_files']
self.__updated_files = []
self.__doctests_2to3 = []
@@ -51,13 +55,14 @@ class build_py(orig.build_py, Mixin2to3):
self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0))
def __getattr__(self, attr):
- if attr=='data_files': # lazily compute data files
+ if attr == 'data_files': # lazily compute data files
self.data_files = files = self._get_data_files()
return files
- return orig.build_py.__getattr__(self,attr)
+ return orig.build_py.__getattr__(self, attr)
def build_module(self, module, module_file, package):
- outfile, copied = orig.build_py.build_module(self, module, module_file, package)
+ outfile, copied = orig.build_py.build_module(self, module, module_file,
+ package)
if copied:
self.__updated_files.append(outfile)
return outfile, copied
@@ -74,12 +79,12 @@ class build_py(orig.build_py, Mixin2to3):
build_dir = os.path.join(*([self.build_lib] + package.split('.')))
# Length of path to strip from found files
- plen = len(src_dir)+1
+ plen = len(src_dir) + 1
# Strip directory from globbed filenames
filenames = [
file[plen:] for file in self.find_data_files(package, src_dir)
- ]
+ ]
data.append((package, src_dir, build_dir, filenames))
return data
@@ -102,7 +107,8 @@ class build_py(orig.build_py, Mixin2to3):
srcfile = os.path.join(src_dir, filename)
outf, copied = self.copy_file(srcfile, target)
srcfile = os.path.abspath(srcfile)
- if copied and srcfile in self.distribution.convert_2to3_doctests:
+ if (copied and
+ srcfile in self.distribution.convert_2to3_doctests):
self.__doctests_2to3.append(outf)
def analyze_manifest(self):
@@ -117,21 +123,22 @@ class build_py(orig.build_py, Mixin2to3):
self.run_command('egg_info')
ei_cmd = self.get_finalized_command('egg_info')
for path in ei_cmd.filelist.files:
- d,f = os.path.split(assert_relative(path))
+ d, f = os.path.split(assert_relative(path))
prev = None
oldf = f
- while d and d!=prev and d not in src_dirs:
+ while d and d != prev and d not in src_dirs:
prev = d
d, df = os.path.split(d)
f = os.path.join(df, f)
if d in src_dirs:
- if path.endswith('.py') and f==oldf:
- continue # it's a module, not data
- mf.setdefault(src_dirs[d],[]).append(path)
+ if path.endswith('.py') and f == oldf:
+ continue # it's a module, not data
+ mf.setdefault(src_dirs[d], []).append(path)
- def get_data_files(self): pass # kludge 2.4 for lazy computation
+ def get_data_files(self):
+ pass # kludge 2.4 for lazy computation
- if sys.version<"2.4": # Python 2.4 already has this code
+ if sys.version < "2.4": # Python 2.4 already has this code
def get_outputs(self, include_bytecode=1):
"""Return complete list of files copied to the build directory
@@ -142,9 +149,9 @@ class build_py(orig.build_py, Mixin2to3):
"""
return orig.build_py.get_outputs(self, include_bytecode) + [
os.path.join(build_dir, filename)
- for package, src_dir, build_dir,filenames in self.data_files
+ for package, src_dir, build_dir, filenames in self.data_files
for filename in filenames
- ]
+ ]
def check_package(self, package, package_dir):
"""Check namespace packages' __init__ for declare_namespace"""
@@ -160,25 +167,26 @@ class build_py(orig.build_py, Mixin2to3):
return init_py
for pkg in self.distribution.namespace_packages:
- if pkg==package or pkg.startswith(package+'.'):
+ if pkg == package or pkg.startswith(package + '.'):
break
else:
return init_py
- f = open(init_py,'rbU')
+ f = open(init_py, 'rbU')
if 'declare_namespace'.encode() not in f.read():
from distutils.errors import DistutilsError
+
raise DistutilsError(
- "Namespace package problem: %s is a namespace package, but its\n"
- "__init__.py does not call declare_namespace()! Please fix it.\n"
- '(See the setuptools manual under "Namespace Packages" for '
- "details.)\n" % (package,)
+ "Namespace package problem: %s is a namespace package, but "
+ "its\n__init__.py does not call declare_namespace()! Please "
+ 'fix it.\n(See the setuptools manual under '
+ '"Namespace Packages" for details.)\n"' % (package,)
)
f.close()
return init_py
def initialize_options(self):
- self.packages_checked={}
+ self.packages_checked = {}
orig.build_py.initialize_options(self)
def get_package_dir(self, package):
@@ -202,7 +210,7 @@ class build_py(orig.build_py, Mixin2to3):
seen = {}
return [
f for f in files if f not in bad
- and f not in seen and seen.setdefault(f,1) # ditch dupes
+ and f not in seen and seen.setdefault(f, 1) # ditch dupes
]
@@ -210,6 +218,7 @@ def assert_relative(path):
if not os.path.isabs(path):
return path
from distutils.errors import DistutilsSetupError
+
msg = textwrap.dedent("""
Error: setup script specifies an absolute path:
diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py
index 129184ca..368b64fe 100755
--- a/setuptools/command/develop.py
+++ b/setuptools/command/develop.py
@@ -1,11 +1,14 @@
-from setuptools.command.easy_install import easy_install
-from distutils.util import convert_path, subst_vars
-from pkg_resources import Distribution, PathMetadata, normalize_path
+from distutils.util import convert_path
from distutils import log
from distutils.errors import DistutilsError, DistutilsOptionError
-import os, sys, setuptools, glob
+import os
+import glob
+from pkg_resources import Distribution, PathMetadata, normalize_path
+from setuptools.command.easy_install import easy_install
from setuptools.compat import PY3
+import setuptools
+
class develop(easy_install):
"""Set up package for development"""
@@ -34,53 +37,50 @@ class develop(easy_install):
self.egg_path = None
easy_install.initialize_options(self)
self.setup_path = None
- self.always_copy_from = '.' # always copy eggs installed in curdir
-
-
+ self.always_copy_from = '.' # always copy eggs installed in curdir
def finalize_options(self):
ei = self.get_finalized_command("egg_info")
if ei.broken_egg_info:
- raise DistutilsError(
- "Please rename %r to %r before using 'develop'"
- % (ei.egg_info, ei.broken_egg_info)
- )
+ template = "Please rename %r to %r before using 'develop'"
+ args = ei.egg_info, ei.broken_egg_info
+ raise DistutilsError(template % args)
self.args = [ei.egg_name]
-
-
-
easy_install.finalize_options(self)
self.expand_basedirs()
self.expand_dirs()
# pick up setup-dir .egg files only: no .egg-info
self.package_index.scan(glob.glob('*.egg'))
- self.egg_link = os.path.join(self.install_dir, ei.egg_name+'.egg-link')
+ self.egg_link = os.path.join(self.install_dir, ei.egg_name +
+ '.egg-link')
self.egg_base = ei.egg_base
if self.egg_path is None:
self.egg_path = os.path.abspath(ei.egg_base)
target = normalize_path(self.egg_base)
- if normalize_path(os.path.join(self.install_dir, self.egg_path)) != target:
+ egg_path = normalize_path(os.path.join(self.install_dir,
+ self.egg_path))
+ if egg_path != target:
raise DistutilsOptionError(
"--egg-path must be a relative path from the install"
- " directory to "+target
- )
+ " directory to " + target
+ )
# Make a distribution for the package's source
self.dist = Distribution(
target,
PathMetadata(target, os.path.abspath(ei.egg_info)),
- project_name = ei.egg_name
+ project_name=ei.egg_name
)
- p = self.egg_base.replace(os.sep,'/')
- if p!= os.curdir:
- p = '../' * (p.count('/')+1)
+ p = self.egg_base.replace(os.sep, '/')
+ if p != os.curdir:
+ p = '../' * (p.count('/') + 1)
self.setup_path = p
p = normalize_path(os.path.join(self.install_dir, self.egg_path, p))
- if p != normalize_path(os.curdir):
+ if p != normalize_path(os.curdir):
raise DistutilsOptionError(
"Can't get a consistent path to setup script from"
" installation directory", p, normalize_path(os.curdir))
@@ -106,7 +106,8 @@ class develop(easy_install):
ei_cmd = self.get_finalized_command("egg_info")
self.egg_path = build_path
self.dist.location = build_path
- self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info) # XXX
+ # XXX
+ self.dist._provider = PathMetadata(build_path, ei_cmd.egg_info)
else:
# Without 2to3 inplace works fine:
self.run_command('egg_info')
@@ -123,21 +124,21 @@ class develop(easy_install):
# create an .egg-link in the installation dir, pointing to our egg
log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
if not self.dry_run:
- f = open(self.egg_link,"w")
+ f = open(self.egg_link, "w")
f.write(self.egg_path + "\n" + self.setup_path)
f.close()
# postprocess the installed distro, fixing up .pth, installing scripts,
# and handling requirements
self.process_distribution(None, self.dist, not self.no_deps)
-
def uninstall_link(self):
if os.path.exists(self.egg_link):
log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)
egg_link_file = open(self.egg_link)
contents = [line.rstrip() for line in egg_link_file]
egg_link_file.close()
- if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):
+ if contents not in ([self.egg_path],
+ [self.egg_path, self.setup_path]):
log.warn("Link points to %s: uninstall aborted", contents)
return
if not self.dry_run:
@@ -151,7 +152,7 @@ class develop(easy_install):
def install_egg_scripts(self, dist):
if dist is not self.dist:
# Installing a dependency, so fall back to normal behavior
- return easy_install.install_egg_scripts(self,dist)
+ return easy_install.install_egg_scripts(self, dist)
# create wrapper scripts in the script dir, pointing to dist.scripts
@@ -162,8 +163,7 @@ class develop(easy_install):
for script_name in self.distribution.scripts or []:
script_path = os.path.abspath(convert_path(script_name))
script_name = os.path.basename(script_path)
- f = open(script_path,'rU')
+ f = open(script_path, 'rU')
script_text = f.read()
f.close()
self.install_script(dist, script_name, script_text, script_path)
-
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index ad7f4725..68548272 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -12,6 +12,14 @@ __ https://pythonhosted.org/setuptools/easy_install.html
"""
+from glob import glob
+from distutils.util import get_platform
+from distutils.util import convert_path, subst_vars
+from distutils.errors import DistutilsArgError, DistutilsOptionError, \
+ DistutilsError, DistutilsPlatformError
+from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
+from distutils import log, dir_util
+from distutils.command.build_scripts import first_line_re
import sys
import os
import zipimport
@@ -26,21 +34,10 @@ import textwrap
import warnings
import site
import struct
-from glob import glob
-from distutils import log, dir_util
-from distutils.command.build_scripts import first_line_re
-
-import pkg_resources
from setuptools import Command, _dont_write_bytecode
from setuptools.sandbox import run_setup
from setuptools.py31compat import get_path, get_config_vars
-
-from distutils.util import get_platform
-from distutils.util import convert_path, subst_vars
-from distutils.errors import DistutilsArgError, DistutilsOptionError, \
- DistutilsError, DistutilsPlatformError
-from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
from setuptools.command import setopt
from setuptools.archive_util import unpack_archive
from setuptools.package_index import PackageIndex
@@ -54,18 +51,22 @@ from pkg_resources import (
Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound,
VersionConflict, DEVELOP_DIST,
)
+import pkg_resources
+
sys_executable = os.environ.get('__PYVENV_LAUNCHER__',
- os.path.normpath(sys.executable))
+ os.path.normpath(sys.executable))
__all__ = [
'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg',
'main', 'get_exe_prefixes',
]
+
def is_64bit():
return struct.calcsize("P") == 8
+
def samefile(p1, p2):
both_exist = os.path.exists(p1) and os.path.exists(p2)
use_samefile = hasattr(os.path, 'samefile') and both_exist
@@ -75,9 +76,11 @@ def samefile(p1, p2):
norm_p2 = os.path.normpath(os.path.normcase(p2))
return norm_p1 == norm_p2
+
if PY2:
def _to_ascii(s):
return s
+
def isascii(s):
try:
unicode(s, 'ascii')
@@ -87,6 +90,7 @@ if PY2:
else:
def _to_ascii(s):
return s.encode('ascii')
+
def isascii(s):
try:
s.encode('ascii')
@@ -94,6 +98,7 @@ else:
except UnicodeError:
return False
+
class easy_install(Command):
"""Manage a download/build/install process"""
description = "Find/get/install Python packages"
@@ -111,22 +116,22 @@ class easy_install(Command):
("index-url=", "i", "base URL of Python Package Index"),
("find-links=", "f", "additional URL(s) to search for packages"),
("build-directory=", "b",
- "download/extract/build in DIR; keep the results"),
+ "download/extract/build in DIR; keep the results"),
('optimize=', 'O',
- "also compile with optimization: -O1 for \"python -O\", "
- "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
+ "also compile with optimization: -O1 for \"python -O\", "
+ "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"),
('record=', None,
- "filename in which to record list of installed files"),
+ "filename in which to record list of installed files"),
('always-unzip', 'Z', "don't install as a zipfile, no matter what"),
- ('site-dirs=','S',"list of directories where .pth files work"),
+ ('site-dirs=', 'S', "list of directories where .pth files work"),
('editable', 'e', "Install specified packages in editable form"),
('no-deps', 'N', "don't install dependencies"),
('allow-hosts=', 'H', "pattern(s) that hostnames must match"),
('local-snapshots-ok', 'l',
- "allow building eggs from local checkouts"),
+ "allow building eggs from local checkouts"),
('version', None, "print version information and exit"),
('no-find-links', None,
- "Don't load find-links defined in packages being installed")
+ "Don't load find-links defined in packages being installed")
]
boolean_options = [
'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy',
@@ -160,10 +165,10 @@ class easy_install(Command):
self.editable = self.no_deps = self.allow_hosts = None
self.root = self.prefix = self.no_report = None
self.version = None
- self.install_purelib = None # for pure module distributions
- self.install_platlib = None # non-pure (dists w/ extensions)
- self.install_headers = None # for C/C++ headers
- self.install_lib = None # set to either purelib or platlib
+ self.install_purelib = None # for pure module distributions
+ self.install_platlib = None # non-pure (dists w/ extensions)
+ self.install_headers = None # for C/C++ headers
+ self.install_lib = None # set to either purelib or platlib
self.install_scripts = None
self.install_data = None
self.install_base = None
@@ -198,7 +203,8 @@ class easy_install(Command):
if os.path.exists(filename) or os.path.islink(filename):
log.info("Deleting %s", filename)
if not self.dry_run:
- if os.path.isdir(filename) and not os.path.islink(filename):
+ if (os.path.isdir(filename) and
+ not os.path.islink(filename)):
rmtree(filename)
else:
os.unlink(filename)
@@ -231,7 +237,7 @@ class easy_install(Command):
self.config_vars['usersite'] = self.install_usersite
# fix the install_dir if "--user" was used
- #XXX: duplicate of the code in the setup command
+ # XXX: duplicate of the code in the setup command
if self.user and site.ENABLE_USER_SITE:
self.create_home_path()
if self.install_userbase is None:
@@ -246,7 +252,8 @@ class easy_install(Command):
self.expand_basedirs()
self.expand_dirs()
- self._expand('install_dir','script_dir','build_directory','site_dirs')
+ self._expand('install_dir', 'script_dir', 'build_directory',
+ 'site_dirs')
# If a non-default installation directory was specified, default the
# script directory to match it.
if self.script_dir is None:
@@ -258,12 +265,12 @@ class easy_install(Command):
# Let install_dir get set by install_lib command, which in turn
# gets its info from the install command, and takes into account
# --prefix and --home and all that other crud.
- self.set_undefined_options('install_lib',
- ('install_dir','install_dir')
+ self.set_undefined_options(
+ 'install_lib', ('install_dir', 'install_dir')
)
# Likewise, set default script_dir from 'install_scripts.install_dir'
- self.set_undefined_options('install_scripts',
- ('install_dir', 'script_dir')
+ self.set_undefined_options(
+ 'install_scripts', ('install_dir', 'script_dir')
)
if self.user and self.install_purelib:
@@ -277,18 +284,20 @@ class easy_install(Command):
self.all_site_dirs = get_site_dirs()
if self.site_dirs is not None:
site_dirs = [
- os.path.expanduser(s.strip()) for s in self.site_dirs.split(',')
+ os.path.expanduser(s.strip()) for s in
+ self.site_dirs.split(',')
]
for d in site_dirs:
if not os.path.isdir(d):
log.warn("%s (in --site-dirs) does not exist", d)
elif normalize_path(d) not in normpath:
raise DistutilsOptionError(
- d+" (in --site-dirs) is not on sys.path"
+ d + " (in --site-dirs) is not on sys.path"
)
else:
self.all_site_dirs.append(normalize_path(d))
- if not self.editable: self.check_site_dir()
+ if not self.editable:
+ self.check_site_dir()
self.index_url = self.index_url or "https://pypi.python.org/simple"
self.shadow_path = self.all_site_dirs[:]
for path_item in self.install_dir, normalize_path(self.script_dir):
@@ -301,9 +310,9 @@ class easy_install(Command):
hosts = ['*']
if self.package_index is None:
self.package_index = self.create_index(
- self.index_url, search_path = self.shadow_path, hosts=hosts,
+ self.index_url, search_path=self.shadow_path, hosts=hosts,
)
- self.local_index = Environment(self.shadow_path+sys.path)
+ self.local_index = Environment(self.shadow_path + sys.path)
if self.find_links is not None:
if isinstance(self.find_links, basestring):
@@ -311,14 +320,15 @@ class easy_install(Command):
else:
self.find_links = []
if self.local_snapshots_ok:
- self.package_index.scan_egg_links(self.shadow_path+sys.path)
+ self.package_index.scan_egg_links(self.shadow_path + sys.path)
if not self.no_find_links:
self.package_index.add_find_links(self.find_links)
- self.set_undefined_options('install_lib', ('optimize','optimize'))
- if not isinstance(self.optimize,int):
+ self.set_undefined_options('install_lib', ('optimize', 'optimize'))
+ if not isinstance(self.optimize, int):
try:
self.optimize = int(self.optimize)
- if not (0 <= self.optimize <= 2): raise ValueError
+ if not (0 <= self.optimize <= 2):
+ raise ValueError
except ValueError:
raise DistutilsOptionError("--optimize must be 0, 1, or 2")
@@ -350,7 +360,7 @@ class easy_install(Command):
"""Calls `os.path.expanduser` on install dirs."""
self._expand_attrs(['install_purelib', 'install_platlib',
'install_lib', 'install_headers',
- 'install_scripts', 'install_data',])
+ 'install_scripts', 'install_data', ])
def run(self):
if self.verbose != self.distribution.verbose:
@@ -360,11 +370,12 @@ class easy_install(Command):
self.easy_install(spec, not self.no_deps)
if self.record:
outputs = self.outputs
- if self.root: # strip any package prefix
+ if self.root: # strip any package prefix
root_len = len(self.root)
for counter in range(len(outputs)):
outputs[counter] = outputs[counter][root_len:]
from distutils import file_util
+
self.execute(
file_util.write_file, (self.record, outputs),
"writing list of installed files to '%s'" %
@@ -392,7 +403,7 @@ class easy_install(Command):
"""Verify that self.install_dir is .pth-capable dir, if needed"""
instdir = normalize_path(self.install_dir)
- pth_file = os.path.join(instdir,'easy-install.pth')
+ pth_file = os.path.join(instdir, 'easy-install.pth')
# Is it a configured, PYTHONPATH, implicit, or explicit site dir?
is_site_dir = instdir in self.all_site_dirs
@@ -402,13 +413,14 @@ class easy_install(Command):
is_site_dir = self.check_pth_processing()
else:
# make sure we can write to target dir
- testfile = self.pseudo_tempname()+'.write-test'
+ testfile = self.pseudo_tempname() + '.write-test'
test_exists = os.path.exists(testfile)
try:
- if test_exists: os.unlink(testfile)
- open(testfile,'w').close()
+ if test_exists:
+ os.unlink(testfile)
+ open(testfile, 'w').close()
os.unlink(testfile)
- except (OSError,IOError):
+ except (OSError, IOError):
self.cant_write_to_target()
if not is_site_dir and not self.multi_version:
@@ -421,13 +433,13 @@ class easy_install(Command):
else:
self.pth_file = None
- PYTHONPATH = os.environ.get('PYTHONPATH','').split(os.pathsep)
+ PYTHONPATH = os.environ.get('PYTHONPATH', '').split(os.pathsep)
if instdir not in map(normalize_path, [_f for _f in PYTHONPATH if _f]):
# only PYTHONPATH dirs need a site.py, so pretend it's there
self.sitepy_installed = True
elif self.multi_version and not os.path.exists(pth_file):
- self.sitepy_installed = True # don't need site.py in this case
- self.pth_file = None # and don't create a .pth file
+ self.sitepy_installed = True # don't need site.py in this case
+ self.pth_file = None # and don't create a .pth file
self.install_dir = instdir
def cant_write_to_target(self):
@@ -473,32 +485,36 @@ Please make the appropriate changes for your system and try again.
"""Empirically verify whether .pth files are supported in inst. dir"""
instdir = self.install_dir
log.info("Checking .pth file support in %s", instdir)
- pth_file = self.pseudo_tempname()+".pth"
- ok_file = pth_file+'.ok'
+ pth_file = self.pseudo_tempname() + ".pth"
+ ok_file = pth_file + '.ok'
ok_exists = os.path.exists(ok_file)
try:
- if ok_exists: os.unlink(ok_file)
+ if ok_exists:
+ os.unlink(ok_file)
dirname = os.path.dirname(ok_file)
if not os.path.exists(dirname):
os.makedirs(dirname)
- f = open(pth_file,'w')
- except (OSError,IOError):
+ f = open(pth_file, 'w')
+ except (OSError, IOError):
self.cant_write_to_target()
else:
try:
- f.write("import os; f = open(%r, 'w'); f.write('OK'); f.close()\n" % (ok_file,))
+ f.write("import os; f = open(%r, 'w'); f.write('OK'); "
+ "f.close()\n" % (ok_file,))
f.close()
- f=None
+ f = None
executable = sys.executable
- if os.name=='nt':
- dirname,basename = os.path.split(executable)
- alt = os.path.join(dirname,'pythonw.exe')
- if basename.lower()=='python.exe' and os.path.exists(alt):
+ if os.name == 'nt':
+ dirname, basename = os.path.split(executable)
+ alt = os.path.join(dirname, 'pythonw.exe')
+ if (basename.lower() == 'python.exe' and
+ os.path.exists(alt)):
# use pythonw.exe to avoid opening a console window
executable = alt
from distutils.spawn import spawn
- spawn([executable,'-E','-c','pass'],0)
+
+ spawn([executable, '-E', '-c', 'pass'], 0)
if os.path.exists(ok_file):
log.info(
@@ -527,7 +543,7 @@ Please make the appropriate changes for your system and try again.
continue
self.install_script(
dist, script_name,
- dist.get_metadata('scripts/'+script_name)
+ dist.get_metadata('scripts/' + script_name)
)
self.install_wrapper_scripts(dist)
@@ -535,7 +551,7 @@ Please make the appropriate changes for your system and try again.
if os.path.isdir(path):
for base, dirs, files in os.walk(path):
for filename in files:
- self.outputs.append(os.path.join(base,filename))
+ self.outputs.append(os.path.join(base, filename))
else:
self.outputs.append(path)
@@ -547,7 +563,7 @@ Please make the appropriate changes for your system and try again.
% (spec,)
)
- def check_editable(self,spec):
+ def check_editable(self, spec):
if not self.editable:
return
@@ -560,15 +576,17 @@ Please make the appropriate changes for your system and try again.
def easy_install(self, spec, deps=False):
tmpdir = tempfile.mkdtemp(prefix="easy_install-")
download = None
- if not self.editable: self.install_site_py()
+ if not self.editable:
+ self.install_site_py()
try:
- if not isinstance(spec,Requirement):
+ if not isinstance(spec, Requirement):
if URL_SCHEME(spec):
# It's a url, download it to tmpdir and process
self.not_editable(spec)
download = self.package_index.download(spec, tmpdir)
- return self.install_item(None, download, tmpdir, deps, True)
+ return self.install_item(None, download, tmpdir, deps,
+ True)
elif os.path.exists(spec):
# Existing file or directory, just process it directly
@@ -579,15 +597,15 @@ Please make the appropriate changes for your system and try again.
self.check_editable(spec)
dist = self.package_index.fetch_distribution(
- spec, tmpdir, self.upgrade, self.editable, not self.always_copy,
- self.local_index
+ spec, tmpdir, self.upgrade, self.editable,
+ not self.always_copy, self.local_index
)
if dist is None:
msg = "Could not find suitable distribution for %r" % spec
if self.always_copy:
- msg+=" (--always-copy skips system and development eggs)"
+ msg += " (--always-copy skips system and development eggs)"
raise DistutilsError(msg)
- elif dist.precedence==DEVELOP_DIST:
+ elif dist.precedence == DEVELOP_DIST:
# .egg-info dists don't need installing, just process deps
self.process_distribution(spec, dist, deps, "Using")
return dist
@@ -614,10 +632,10 @@ Please make the appropriate changes for your system and try again.
# at this point, we know it's a local .egg, we just don't know if
# it's already installed.
for dist in self.local_index[spec.project_name]:
- if dist.location==download:
+ if dist.location == download:
break
else:
- install_needed = True # it's not in the local index
+ install_needed = True # it's not in the local index
log.info("Processing %s", os.path.basename(download))
@@ -646,13 +664,6 @@ Please make the appropriate changes for your system and try again.
def process_distribution(self, requirement, dist, deps=True, *info):
self.update_pth(dist)
self.package_index.add(dist)
- # First remove the dist from self.local_index, to avoid problems using
- # old cached data in case its underlying file has been replaced.
- #
- # This is a quick-fix for a zipimporter caching issue in case the dist
- # has been implemented as and already loaded from a zip file that got
- # replaced later on. For more detailed information see setuptools issue
- # #168 at 'http://bitbucket.org/pypa/setuptools/issue/168'.
if dist in self.local_index[dist.key]:
self.local_index.remove(dist)
self.local_index.add(dist)
@@ -711,17 +722,18 @@ Please make the appropriate changes for your system and try again.
def maybe_move(self, spec, dist_filename, setup_base):
dst = os.path.join(self.build_directory, spec.key)
if os.path.exists(dst):
- msg = "%r already exists in %s; build directory %s will not be kept"
+ msg = ("%r already exists in %s; build directory %s will not be "
+ "kept")
log.warn(msg, spec.key, self.build_directory, setup_base)
return setup_base
if os.path.isdir(dist_filename):
setup_base = dist_filename
else:
- if os.path.dirname(dist_filename)==setup_base:
- os.unlink(dist_filename) # get it out of the tmp dir
+ if os.path.dirname(dist_filename) == setup_base:
+ os.unlink(dist_filename) # get it out of the tmp dir
contents = os.listdir(setup_base)
- if len(contents)==1:
- dist_filename = os.path.join(setup_base,contents[0])
+ if len(contents) == 1:
+ dist_filename = os.path.join(setup_base, contents[0])
if os.path.isdir(dist_filename):
# if the only thing there is a directory, move it instead
setup_base = dist_filename
@@ -739,34 +751,31 @@ Please make the appropriate changes for your system and try again.
spec = str(dist.as_requirement())
is_script = is_python_script(script_text, script_name)
- def get_template(filename):
- """
- There are a couple of template scripts in the package. This
- function loads one of them and prepares it for use.
-
- These templates use triple-quotes to escape variable
- substitutions so the scripts get the 2to3 treatment when build
- on Python 3. The templates cannot use triple-quotes naturally.
- """
- raw_bytes = resource_string('setuptools', template_name)
- template_str = raw_bytes.decode('utf-8')
- clean_template = template_str.replace('"""', '')
- return clean_template
-
if is_script:
- # See https://bitbucket.org/pypa/setuptools/issue/134 for info
- # on script file naming and downstream issues with SVR4
- template_name = 'script template.py'
- if dev_path:
- template_name = template_name.replace('.py', ' (dev).py')
script_text = (get_script_header(script_text) +
- get_template(template_name) % locals())
+ self._load_template(dev_path) % locals())
self.write_script(script_name, _to_ascii(script_text), 'b')
+ @staticmethod
+ def _load_template(dev_path):
+ """
+ There are a couple of template scripts in the package. This
+ function loads one of them and prepares it for use.
+ """
+ # See https://bitbucket.org/pypa/setuptools/issue/134 for info
+ # on script file naming and downstream issues with SVR4
+ name = 'script.tmpl'
+ if dev_path:
+ name = name.replace('.tmpl', ' (dev).tmpl')
+
+ raw_bytes = resource_string('setuptools', name)
+ return raw_bytes.decode('utf-8')
+
def write_script(self, script_name, contents, mode="t", blockers=()):
"""Write an executable file to the scripts directory"""
- self.delete_blockers( # clean up old .py/.pyw w/o a script
- [os.path.join(self.script_dir,x) for x in blockers])
+ self.delete_blockers( # clean up old .py/.pyw w/o a script
+ [os.path.join(self.script_dir, x) for x in blockers]
+ )
log.info("Installing %s script to %s", script_name, self.script_dir)
target = os.path.join(self.script_dir, script_name)
self.add_output(target)
@@ -776,10 +785,10 @@ Please make the appropriate changes for your system and try again.
ensure_directory(target)
if os.path.exists(target):
os.unlink(target)
- f = open(target,"w"+mode)
+ f = open(target, "w" + mode)
f.write(contents)
f.close()
- chmod(target, 0o777-mask)
+ chmod(target, 0o777 - mask)
def install_eggs(self, spec, dist_filename, tmpdir):
# .egg dirs or files are already built, so just return them
@@ -795,7 +804,7 @@ Please make the appropriate changes for your system and try again.
elif os.path.isdir(dist_filename):
setup_base = os.path.abspath(dist_filename)
- if (setup_base.startswith(tmpdir) # something we downloaded
+ if (setup_base.startswith(tmpdir) # something we downloaded
and self.build_directory and spec is not None):
setup_base = self.maybe_move(spec, dist_filename, setup_base)
@@ -806,11 +815,13 @@ Please make the appropriate changes for your system and try again.
setups = glob(os.path.join(setup_base, '*', 'setup.py'))
if not setups:
raise DistutilsError(
- "Couldn't find a setup script in %s" % os.path.abspath(dist_filename)
+ "Couldn't find a setup script in %s" %
+ os.path.abspath(dist_filename)
)
- if len(setups)>1:
+ if len(setups) > 1:
raise DistutilsError(
- "Multiple setup scripts in %s" % os.path.abspath(dist_filename)
+ "Multiple setup scripts in %s" %
+ os.path.abspath(dist_filename)
)
setup_script = setups[0]
@@ -823,13 +834,15 @@ Please make the appropriate changes for your system and try again.
def egg_distribution(self, egg_path):
if os.path.isdir(egg_path):
- metadata = PathMetadata(egg_path,os.path.join(egg_path,'EGG-INFO'))
+ metadata = PathMetadata(egg_path, os.path.join(egg_path,
+ 'EGG-INFO'))
else:
metadata = EggMetadata(zipimport.zipimporter(egg_path))
- return Distribution.from_filename(egg_path,metadata=metadata)
+ return Distribution.from_filename(egg_path, metadata=metadata)
def install_egg(self, egg_path, tmpdir):
- destination = os.path.join(self.install_dir,os.path.basename(egg_path))
+ destination = os.path.join(self.install_dir,
+ os.path.basename(egg_path))
destination = os.path.abspath(destination)
if not self.dry_run:
ensure_directory(destination)
@@ -839,24 +852,33 @@ Please make the appropriate changes for your system and try again.
if os.path.isdir(destination) and not os.path.islink(destination):
dir_util.remove_tree(destination, dry_run=self.dry_run)
elif os.path.exists(destination):
- self.execute(os.unlink,(destination,),"Removing "+destination)
- uncache_zipdir(destination)
- if os.path.isdir(egg_path):
- if egg_path.startswith(tmpdir):
- f,m = shutil.move, "Moving"
+ self.execute(os.unlink, (destination,), "Removing " +
+ destination)
+ try:
+ new_dist_is_zipped = False
+ if os.path.isdir(egg_path):
+ if egg_path.startswith(tmpdir):
+ f, m = shutil.move, "Moving"
+ else:
+ f, m = shutil.copytree, "Copying"
+ elif self.should_unzip(dist):
+ self.mkpath(destination)
+ f, m = self.unpack_and_compile, "Extracting"
else:
- f,m = shutil.copytree, "Copying"
- elif self.should_unzip(dist):
- self.mkpath(destination)
- f,m = self.unpack_and_compile, "Extracting"
- elif egg_path.startswith(tmpdir):
- f,m = shutil.move, "Moving"
- else:
- f,m = shutil.copy2, "Copying"
-
- self.execute(f, (egg_path, destination),
- (m+" %s to %s") %
- (os.path.basename(egg_path),os.path.dirname(destination)))
+ new_dist_is_zipped = True
+ if egg_path.startswith(tmpdir):
+ f, m = shutil.move, "Moving"
+ else:
+ f, m = shutil.copy2, "Copying"
+ self.execute(f, (egg_path, destination),
+ (m + " %s to %s") %
+ (os.path.basename(egg_path),
+ os.path.dirname(destination)))
+ update_dist_caches(destination,
+ fix_zipimporter_caches=new_dist_is_zipped)
+ except:
+ update_dist_caches(destination, fix_zipimporter_caches=False)
+ raise
self.add_output(destination)
return self.egg_distribution(destination)
@@ -871,30 +893,32 @@ Please make the appropriate changes for your system and try again.
# Create a dummy distribution object until we build the real distro
dist = Distribution(
None,
- project_name=cfg.get('metadata','name'),
- version=cfg.get('metadata','version'), platform=get_platform(),
+ project_name=cfg.get('metadata', 'name'),
+ version=cfg.get('metadata', 'version'), platform=get_platform(),
)
# Convert the .exe to an unpacked egg
- egg_path = dist.location = os.path.join(tmpdir, dist.egg_name()+'.egg')
+ egg_path = dist.location = os.path.join(tmpdir, dist.egg_name() +
+ '.egg')
egg_tmp = egg_path + '.tmp'
_egg_info = os.path.join(egg_tmp, 'EGG-INFO')
pkg_inf = os.path.join(_egg_info, 'PKG-INFO')
- ensure_directory(pkg_inf) # make sure EGG-INFO dir exists
- dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX
+ ensure_directory(pkg_inf) # make sure EGG-INFO dir exists
+ dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX
self.exe_to_egg(dist_filename, egg_tmp)
# Write EGG-INFO/PKG-INFO
if not os.path.exists(pkg_inf):
- f = open(pkg_inf,'w')
+ f = open(pkg_inf, 'w')
f.write('Metadata-Version: 1.0\n')
- for k,v in cfg.items('metadata'):
+ for k, v in cfg.items('metadata'):
if k != 'target_version':
- f.write('%s: %s\n' % (k.replace('_','-').title(), v))
+ f.write('%s: %s\n' % (k.replace('_', '-').title(), v))
f.close()
- script_dir = os.path.join(_egg_info,'scripts')
- self.delete_blockers( # delete entry-point scripts to avoid duping
- [os.path.join(script_dir,args[0]) for args in get_script_args(dist)]
+ script_dir = os.path.join(_egg_info, 'scripts')
+ self.delete_blockers( # delete entry-point scripts to avoid duping
+ [os.path.join(script_dir, args[0]) for args in
+ get_script_args(dist)]
)
# Build .egg file from tmpdir
bdist_egg.make_zipfile(
@@ -910,11 +934,12 @@ Please make the appropriate changes for your system and try again.
to_compile = []
native_libs = []
top_level = {}
- def process(src,dst):
+
+ def process(src, dst):
s = src.lower()
- for old,new in prefixes:
+ for old, new in prefixes:
if s.startswith(old):
- src = new+src[len(old):]
+ src = new + src[len(old):]
parts = src.split('/')
dst = os.path.join(egg_tmp, *parts)
dl = dst.lower()
@@ -922,35 +947,37 @@ Please make the appropriate changes for your system and try again.
parts[-1] = bdist_egg.strip_module(parts[-1])
top_level[os.path.splitext(parts[0])[0]] = 1
native_libs.append(src)
- elif dl.endswith('.py') and old!='SCRIPTS/':
+ elif dl.endswith('.py') and old != 'SCRIPTS/':
top_level[os.path.splitext(parts[0])[0]] = 1
to_compile.append(dst)
return dst
if not src.endswith('.pth'):
log.warn("WARNING: can't process %s", src)
return None
+
# extract, tracking .pyd/.dll->native_libs and .py -> to_compile
unpack_archive(dist_filename, egg_tmp, process)
stubs = []
for res in native_libs:
- if res.lower().endswith('.pyd'): # create stubs for .pyd's
+ if res.lower().endswith('.pyd'): # create stubs for .pyd's
parts = res.split('/')
resource = parts[-1]
- parts[-1] = bdist_egg.strip_module(parts[-1])+'.py'
+ parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py'
pyfile = os.path.join(egg_tmp, *parts)
to_compile.append(pyfile)
stubs.append(pyfile)
bdist_egg.write_stub(resource, pyfile)
- self.byte_compile(to_compile) # compile .py's
- bdist_egg.write_safety_flag(os.path.join(egg_tmp,'EGG-INFO'),
+ self.byte_compile(to_compile) # compile .py's
+ bdist_egg.write_safety_flag(
+ os.path.join(egg_tmp, 'EGG-INFO'),
bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag
- for name in 'top_level','native_libs':
+ for name in 'top_level', 'native_libs':
if locals()[name]:
- txt = os.path.join(egg_tmp, 'EGG-INFO', name+'.txt')
+ txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt')
if not os.path.exists(txt):
- f = open(txt,'w')
- f.write('\n'.join(locals()[name])+'\n')
+ f = open(txt, 'w')
+ f.write('\n'.join(locals()[name]) + '\n')
f.close()
def installation_report(self, req, dist, what="Installed"):
@@ -968,7 +995,7 @@ these examples, in order to select the desired version:
pkg_resources.require("%(name)s==%(version)s") # this exact version
pkg_resources.require("%(name)s>=%(version)s") # this version or higher
"""
- if self.install_dir not in map(normalize_path,sys.path):
+ if self.install_dir not in map(normalize_path, sys.path):
msg += """
Note also that the installation directory must be on sys.path at runtime for
@@ -978,7 +1005,7 @@ PYTHONPATH, or by being added to sys.path by your code.)
eggloc = dist.location
name = dist.project_name
version = dist.version
- extras = '' # TODO: self.report_extras(req, dist)
+ extras = '' # TODO: self.report_extras(req, dist)
return msg % locals()
def report_editable(self, spec, setup_script):
@@ -999,15 +1026,15 @@ See the setuptools documentation for the "develop" command for more info.
sys.modules.setdefault('distutils.command.egg_info', egg_info)
args = list(args)
- if self.verbose>2:
+ if self.verbose > 2:
v = 'v' * (self.verbose - 1)
- args.insert(0,'-'+v)
- elif self.verbose<2:
- args.insert(0,'-q')
+ args.insert(0, '-' + v)
+ elif self.verbose < 2:
+ args.insert(0, '-q')
if self.dry_run:
- args.insert(0,'-n')
+ args.insert(0, '-n')
log.info(
- "Running %s %s", setup_script[len(setup_base)+1:], ' '.join(args)
+ "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args)
)
try:
run_setup(setup_script, args)
@@ -1033,11 +1060,11 @@ See the setuptools documentation for the "develop" command for more info.
eggs.append(self.install_egg(dist.location, setup_base))
if not eggs and not self.dry_run:
log.warn("No eggs found in %s (setup script problem?)",
- dist_dir)
+ dist_dir)
return eggs
finally:
rmtree(dist_dir)
- log.set_verbosity(self.verbose) # restore our log verbosity
+ log.set_verbosity(self.verbose) # restore our log verbosity
def _set_fetcher_options(self, base):
"""
@@ -1047,7 +1074,7 @@ See the setuptools documentation for the "develop" command for more info.
are available to that command as well.
"""
# find the fetch options from easy_install and write them out
- # to the setup.cfg file.
+ # to the setup.cfg file.
ei_opts = self.distribution.get_option_dict('easy_install').copy()
fetch_directives = (
'find_links', 'site_dirs', 'index_url', 'optimize',
@@ -1055,7 +1082,8 @@ See the setuptools documentation for the "develop" command for more info.
)
fetch_options = {}
for key, val in ei_opts.items():
- if key not in fetch_directives: continue
+ if key not in fetch_directives:
+ continue
fetch_options[key.replace('_', '-')] = val[1]
# create a settings dictionary suitable for `edit_config`
settings = dict(easy_install=fetch_options)
@@ -1066,7 +1094,7 @@ See the setuptools documentation for the "develop" command for more info.
if self.pth_file is None:
return
- for d in self.pth_file[dist.key]: # drop old entries
+ for d in self.pth_file[dist.key]: # drop old entries
if self.multi_version or d.location != dist.location:
log.info("Removing %s from easy-install.pth file", d)
self.pth_file.remove(d)
@@ -1081,7 +1109,7 @@ See the setuptools documentation for the "develop" command for more info.
)
else:
log.info("Adding %s to easy-install.pth file", dist)
- self.pth_file.add(dist) # add new entry
+ self.pth_file.add(dist) # add new entry
if dist.location not in self.shadow_path:
self.shadow_path.append(dist.location)
@@ -1089,19 +1117,20 @@ See the setuptools documentation for the "develop" command for more info.
self.pth_file.save()
- if dist.key=='setuptools':
+ if dist.key == 'setuptools':
# Ensure that setuptools itself never becomes unavailable!
# XXX should this check for latest version?
- filename = os.path.join(self.install_dir,'setuptools.pth')
- if os.path.islink(filename): os.unlink(filename)
+ filename = os.path.join(self.install_dir, 'setuptools.pth')
+ if os.path.islink(filename):
+ os.unlink(filename)
f = open(filename, 'wt')
- f.write(self.pth_file.make_relative(dist.location)+'\n')
+ f.write(self.pth_file.make_relative(dist.location) + '\n')
f.close()
def unpack_progress(self, src, dst):
# Progress filter for unpacking
log.debug("Unpacking %s to %s", src, dst)
- return dst # only unpack-and-compile skips files for dry run
+ return dst # only unpack-and-compile skips files for dry run
def unpack_and_compile(self, egg_path, destination):
to_compile = []
@@ -1112,7 +1141,7 @@ See the setuptools documentation for the "develop" command for more info.
to_compile.append(dst)
elif dst.endswith('.dll') or dst.endswith('.so'):
to_chmod.append(dst)
- self.unpack_progress(src,dst)
+ self.unpack_progress(src, dst)
return not self.dry_run and dst or None
unpack_archive(egg_path, destination, pf)
@@ -1128,6 +1157,7 @@ See the setuptools documentation for the "develop" command for more info.
return
from distutils.util import byte_compile
+
try:
# try to make the byte compile messages quieter
log.set_verbosity(self.verbose - 1)
@@ -1139,7 +1169,7 @@ See the setuptools documentation for the "develop" command for more info.
dry_run=self.dry_run
)
finally:
- log.set_verbosity(self.verbose) # restore original verbosity
+ log.set_verbosity(self.verbose) # restore original verbosity
def no_default_version_msg(self):
template = """bad install directory or PYTHONPATH
@@ -1170,7 +1200,7 @@ Here are some of your options for correcting the problem:
https://pythonhosted.org/setuptools/easy_install.html#custom-installation-locations
Please make the appropriate changes for your system and try again."""
- return template % (self.install_dir, os.environ.get('PYTHONPATH',''))
+ return template % (self.install_dir, os.environ.get('PYTHONPATH', ''))
def install_site_py(self):
"""Make sure there's a site.py in the target dir, if needed"""
@@ -1184,7 +1214,7 @@ Please make the appropriate changes for your system and try again."""
if os.path.exists(sitepy):
log.debug("Checking existing site.py in %s", self.install_dir)
- f = open(sitepy,'rb')
+ f = open(sitepy, 'rb')
current = f.read()
# we want str, not bytes
if PY3:
@@ -1201,7 +1231,7 @@ Please make the appropriate changes for your system and try again."""
log.info("Creating %s", sitepy)
if not self.dry_run:
ensure_directory(sitepy)
- f = open(sitepy,'wb')
+ f = open(sitepy, 'wb')
f.write(source)
f.close()
self.byte_compile([sitepy])
@@ -1219,15 +1249,15 @@ Please make the appropriate changes for your system and try again."""
os.makedirs(path, 0o700)
INSTALL_SCHEMES = dict(
- posix = dict(
- install_dir = '$base/lib/python$py_version_short/site-packages',
- script_dir = '$base/bin',
+ posix=dict(
+ install_dir='$base/lib/python$py_version_short/site-packages',
+ script_dir='$base/bin',
),
)
DEFAULT_SCHEME = dict(
- install_dir = '$base/Lib/site-packages',
- script_dir = '$base/Scripts',
+ install_dir='$base/Lib/site-packages',
+ script_dir='$base/Scripts',
)
def _expand(self, *attrs):
@@ -1237,12 +1267,13 @@ Please make the appropriate changes for your system and try again."""
# Set default install_dir/scripts from --prefix
config_vars = config_vars.copy()
config_vars['base'] = self.prefix
- scheme = self.INSTALL_SCHEMES.get(os.name,self.DEFAULT_SCHEME)
- for attr,val in scheme.items():
- if getattr(self,attr,None) is None:
- setattr(self,attr,val)
+ scheme = self.INSTALL_SCHEMES.get(os.name, self.DEFAULT_SCHEME)
+ for attr, val in scheme.items():
+ if getattr(self, attr, None) is None:
+ setattr(self, attr, val)
from distutils.util import subst_vars
+
for attr in attrs:
val = getattr(self, attr)
if val is not None:
@@ -1251,6 +1282,7 @@ Please make the appropriate changes for your system and try again."""
val = os.path.expanduser(val)
setattr(self, attr, val)
+
def get_site_dirs():
# return a list of 'site' dirs
sitedirs = [_f for _f in os.environ.get('PYTHONPATH',
@@ -1264,10 +1296,10 @@ def get_site_dirs():
sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
elif os.sep == '/':
sitedirs.extend([os.path.join(prefix,
- "lib",
- "python" + sys.version[:3],
- "site-packages"),
- os.path.join(prefix, "lib", "site-python")])
+ "lib",
+ "python" + sys.version[:3],
+ "site-packages"),
+ os.path.join(prefix, "lib", "site-python")])
else:
sitedirs.extend(
[prefix, os.path.join(prefix, "lib", "site-packages")]
@@ -1287,7 +1319,8 @@ def get_site_dirs():
'site-packages'))
lib_paths = get_path('purelib'), get_path('platlib')
for site_lib in lib_paths:
- if site_lib not in sitedirs: sitedirs.append(site_lib)
+ if site_lib not in sitedirs:
+ sitedirs.append(site_lib)
if site.ENABLE_USER_SITE:
sitedirs.append(site.USER_SITE)
@@ -1318,12 +1351,12 @@ def expand_paths(inputs):
if not name.endswith('.pth'):
# We only care about the .pth files
continue
- if name in ('easy-install.pth','setuptools.pth'):
+ if name in ('easy-install.pth', 'setuptools.pth'):
# Ignore .pth files that we control
continue
# Read the .pth file
- f = open(os.path.join(dirname,name))
+ f = open(os.path.join(dirname, name))
lines = list(yield_lines(f))
f.close()
@@ -1343,7 +1376,7 @@ def extract_wininst_cfg(dist_filename):
Returns a ConfigParser.RawConfigParser, or None
"""
- f = open(dist_filename,'rb')
+ f = open(dist_filename, 'rb')
try:
endrec = zipfile._EndRecData(f)
if endrec is None:
@@ -1352,21 +1385,23 @@ def extract_wininst_cfg(dist_filename):
prepended = (endrec[9] - endrec[5]) - endrec[6]
if prepended < 12: # no wininst data here
return None
- f.seek(prepended-12)
+ f.seek(prepended - 12)
from setuptools.compat import StringIO, ConfigParser
import struct
- tag, cfglen, bmlen = struct.unpack("<iii",f.read(12))
+
+ tag, cfglen, bmlen = struct.unpack("<iii", f.read(12))
if tag not in (0x1234567A, 0x1234567B):
- return None # not a valid tag
+ return None # not a valid tag
- f.seek(prepended-(12+cfglen))
- cfg = ConfigParser.RawConfigParser({'version':'','target_version':''})
+ f.seek(prepended - (12 + cfglen))
+ cfg = ConfigParser.RawConfigParser(
+ {'version': '', 'target_version': ''})
try:
part = f.read(cfglen)
# part is in bytes, but we need to read up to the first null
- # byte.
- if sys.version_info >= (2,6):
+ # byte.
+ if sys.version_info >= (2, 6):
null_byte = bytes([0])
else:
null_byte = chr(0)
@@ -1399,25 +1434,25 @@ def get_exe_prefixes(exe_filename):
for info in z.infolist():
name = info.filename
parts = name.split('/')
- if len(parts)==3 and parts[2]=='PKG-INFO':
+ if len(parts) == 3 and parts[2] == 'PKG-INFO':
if parts[1].endswith('.egg-info'):
- prefixes.insert(0,('/'.join(parts[:2]), 'EGG-INFO/'))
+ prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/'))
break
if len(parts) != 2 or not name.endswith('.pth'):
continue
if name.endswith('-nspkg.pth'):
continue
- if parts[0].upper() in ('PURELIB','PLATLIB'):
+ if parts[0].upper() in ('PURELIB', 'PLATLIB'):
contents = z.read(name)
if PY3:
contents = contents.decode()
for pth in yield_lines(contents):
- pth = pth.strip().replace('\\','/')
+ pth = pth.strip().replace('\\', '/')
if not pth.startswith('import'):
- prefixes.append((('%s/%s/' % (parts[0],pth)), ''))
+ prefixes.append((('%s/%s/' % (parts[0], pth)), ''))
finally:
z.close()
- prefixes = [(x.lower(),y) for x, y in prefixes]
+ prefixes = [(x.lower(), y) for x, y in prefixes]
prefixes.sort()
prefixes.reverse()
return prefixes
@@ -1431,6 +1466,7 @@ def parse_requirement_arg(spec):
"Not a URL, existing file, or requirement spec: %r" % (spec,)
)
+
class PthDistributions(Environment):
"""A .pth file with Distribution paths in it"""
@@ -1450,7 +1486,7 @@ class PthDistributions(Environment):
saw_import = False
seen = dict.fromkeys(self.sitedirs)
if os.path.isfile(self.filename):
- f = open(self.filename,'rt')
+ f = open(self.filename, 'rt')
for line in f:
if line.startswith('import'):
saw_import = True
@@ -1462,17 +1498,17 @@ class PthDistributions(Environment):
# skip non-existent paths, in case somebody deleted a package
# manually, and duplicate paths as well
path = self.paths[-1] = normalize_path(
- os.path.join(self.basedir,path)
+ os.path.join(self.basedir, path)
)
if not os.path.exists(path) or path in seen:
- self.paths.pop() # skip it
- self.dirty = True # we cleaned up, so we're dirty now :)
+ self.paths.pop() # skip it
+ self.dirty = True # we cleaned up, so we're dirty now :)
continue
seen[path] = 1
f.close()
if self.paths and not saw_import:
- self.dirty = True # ensure anything we touch has import wrappers
+ self.dirty = True # ensure anything we touch has import wrappers
while self.paths and not self.paths[-1].strip():
self.paths.pop()
@@ -1481,7 +1517,7 @@ class PthDistributions(Environment):
if not self.dirty:
return
- data = '\n'.join(map(self.make_relative,self.paths))
+ data = '\n'.join(map(self.make_relative, self.paths))
if data:
log.debug("Saving %s", self.filename)
data = (
@@ -1495,7 +1531,7 @@ class PthDistributions(Environment):
if os.path.islink(self.filename):
os.unlink(self.filename)
- f = open(self.filename,'wt')
+ f = open(self.filename, 'wt')
f.write(data)
f.close()
@@ -1508,9 +1544,9 @@ class PthDistributions(Environment):
def add(self, dist):
"""Add `dist` to the distribution map"""
if (dist.location not in self.paths and (
- dist.location not in self.sitedirs or
- dist.location == os.getcwd() # account for '.' being in PYTHONPATH
- )):
+ dist.location not in self.sitedirs or
+ dist.location == os.getcwd() # account for '.' being in PYTHONPATH
+ )):
self.paths.append(dist.location)
self.dirty = True
Environment.add(self, dist)
@@ -1522,13 +1558,13 @@ class PthDistributions(Environment):
self.dirty = True
Environment.remove(self, dist)
- def make_relative(self,path):
+ def make_relative(self, path):
npath, last = os.path.split(normalize_path(path))
baselen = len(self.basedir)
parts = [last]
- sep = os.altsep=='/' and '/' or os.sep
- while len(npath)>=baselen:
- if npath==self.basedir:
+ sep = os.altsep == '/' and '/' or os.sep
+ while len(npath) >= baselen:
+ if npath == self.basedir:
parts.append(os.curdir)
parts.reverse()
return sep.join(parts)
@@ -1552,12 +1588,13 @@ def _first_line_re():
def get_script_header(script_text, executable=sys_executable, wininst=False):
"""Create a #! line, getting options (if any) from script_text"""
- first = (script_text+'\n').splitlines()[0]
+ first = (script_text + '\n').splitlines()[0]
match = _first_line_re().match(first)
options = ''
if match:
options = match.group(1) or ''
- if options: options = ' '+options
+ if options:
+ options = ' ' + options
if wininst:
executable = "python.exe"
else:
@@ -1567,50 +1604,199 @@ def get_script_header(script_text, executable=sys_executable, wininst=False):
# Non-ascii path to sys.executable, use -x to prevent warnings
if options:
if options.strip().startswith('-'):
- options = ' -x'+options.strip()[1:]
- # else: punt, we can't do it, let the warning happen anyway
+ options = ' -x' + options.strip()[1:]
+ # else: punt, we can't do it, let the warning happen anyway
else:
options = ' -x'
executable = fix_jython_executable(executable, options)
hdr = "#!%(executable)s%(options)s\n" % locals()
return hdr
+
def auto_chmod(func, arg, exc):
- if func is os.remove and os.name=='nt':
+ if func is os.remove and os.name == 'nt':
chmod(arg, stat.S_IWRITE)
return func(arg)
et, ev, _ = sys.exc_info()
- reraise(et, (ev[0], ev[1] + (" %s %s" % (func,arg))))
-
-def uncache_zipdir(path):
- """
- Remove any globally cached zip file related data for `path`
+ reraise(et, (ev[0], ev[1] + (" %s %s" % (func, arg))))
- Stale zipimport.zipimporter objects need to be removed when a zip file is
- replaced as they contain cached zip file directory information. If they are
- asked to get data from their zip file, they will use that cached
- information to calculate the data location in the zip file. This calculated
- location may be incorrect for the replaced zip file, which may in turn
- cause the read operation to either fail or return incorrect data.
- Note we have no way to clear any local caches from here. That is left up to
- whomever is in charge of maintaining that cache.
+def update_dist_caches(dist_path, fix_zipimporter_caches):
+ """
+ Fix any globally cached `dist_path` related data
+
+ `dist_path` should be a path of a newly installed egg distribution (zipped
+ or unzipped).
+
+ sys.path_importer_cache contains finder objects that have been cached when
+ importing data from the original distribution. Any such finders need to be
+ cleared since the replacement distribution might be packaged differently,
+ e.g. a zipped egg distribution might get replaced with an unzipped egg
+ folder or vice versa. Having the old finders cached may then cause Python
+ to attempt loading modules from the replacement distribution using an
+ incorrect loader.
+
+ zipimport.zipimporter objects are Python loaders charged with importing
+ data packaged inside zip archives. If stale loaders referencing the
+ original distribution, are left behind, they can fail to load modules from
+ the replacement distribution. E.g. if an old zipimport.zipimporter instance
+ is used to load data from a new zipped egg archive, it may cause the
+ operation to attempt to locate the requested data in the wrong location -
+ one indicated by the original distribution's zip archive directory
+ information. Such an operation may then fail outright, e.g. report having
+ read a 'bad local file header', or even worse, it may fail silently &
+ return invalid data.
+
+ zipimport._zip_directory_cache contains cached zip archive directory
+ information for all existing zipimport.zipimporter instances and all such
+ instances connected to the same archive share the same cached directory
+ information.
+
+ If asked, and the underlying Python implementation allows it, we can fix
+ all existing zipimport.zipimporter instances instead of having to track
+ them down and remove them one by one, by updating their shared cached zip
+ archive directory information. This, of course, assumes that the
+ replacement distribution is packaged as a zipped egg.
+
+ If not asked to fix existing zipimport.zipimporter instances, we still do
+ our best to clear any remaining zipimport.zipimporter related cached data
+ that might somehow later get used when attempting to load data from the new
+ distribution and thus cause such load operations to fail. Note that when
+ tracking down such remaining stale data, we can not catch every conceivable
+ usage from here, and we clear only those that we know of and have found to
+ cause problems if left alive. Any remaining caches should be updated by
+ whomever is in charge of maintaining them, i.e. they should be ready to
+ handle us replacing their zip archives with new distributions at runtime.
"""
- normalized_path = normalize_path(path)
- _uncache(normalized_path, zipimport._zip_directory_cache)
+ # There are several other known sources of stale zipimport.zipimporter
+ # instances that we do not clear here, but might if ever given a reason to
+ # do so:
+ # * Global setuptools pkg_resources.working_set (a.k.a. 'master working
+ # set') may contain distributions which may in turn contain their
+ # zipimport.zipimporter loaders.
+ # * Several zipimport.zipimporter loaders held by local variables further
+ # up the function call stack when running the setuptools installation.
+ # * Already loaded modules may have their __loader__ attribute set to the
+ # exact loader instance used when importing them. Python 3.4 docs state
+ # that this information is intended mostly for introspection and so is
+ # not expected to cause us problems.
+ normalized_path = normalize_path(dist_path)
_uncache(normalized_path, sys.path_importer_cache)
+ if fix_zipimporter_caches:
+ _replace_zip_directory_cache_data(normalized_path)
+ else:
+ # Here, even though we do not want to fix existing and now stale
+ # zipimporter cache information, we still want to remove it. Related to
+ # Python's zip archive directory information cache, we clear each of
+ # its stale entries in two phases:
+ # 1. Clear the entry so attempting to access zip archive information
+ # via any existing stale zipimport.zipimporter instances fails.
+ # 2. Remove the entry from the cache so any newly constructed
+ # zipimport.zipimporter instances do not end up using old stale
+ # zip archive directory information.
+ # This whole stale data removal step does not seem strictly necessary,
+ # but has been left in because it was done before we started replacing
+ # the zip archive directory information cache content if possible, and
+ # there are no relevant unit tests that we can depend on to tell us if
+ # this is really needed.
+ _remove_and_clear_zip_directory_cache_data(normalized_path)
+
+
+def _collect_zipimporter_cache_entries(normalized_path, cache):
+ """
+ Return zipimporter cache entry keys related to a given normalized path.
-def _uncache(normalized_path, cache):
- to_remove = []
+ Alternative path spellings (e.g. those using different character case or
+ those using alternative path separators) related to the same path are
+ included. Any sub-path entries are included as well, i.e. those
+ corresponding to zip archives embedded in other zip archives.
+
+ """
+ result = []
prefix_len = len(normalized_path)
for p in cache:
np = normalize_path(p)
if (np.startswith(normalized_path) and
np[prefix_len:prefix_len + 1] in (os.sep, '')):
- to_remove.append(p)
- for p in to_remove:
+ result.append(p)
+ return result
+
+
+def _update_zipimporter_cache(normalized_path, cache, updater=None):
+ """
+ Update zipimporter cache data for a given normalized path.
+
+ Any sub-path entries are processed as well, i.e. those corresponding to zip
+ archives embedded in other zip archives.
+
+ Given updater is a callable taking a cache entry key and the original entry
+ (after already removing the entry from the cache), and expected to update
+ the entry and possibly return a new one to be inserted in its place.
+ Returning None indicates that the entry should not be replaced with a new
+ one. If no updater is given, the cache entries are simply removed without
+ any additional processing, the same as if the updater simply returned None.
+
+ """
+ for p in _collect_zipimporter_cache_entries(normalized_path, cache):
+ # N.B. pypy's custom zipimport._zip_directory_cache implementation does
+ # not support the complete dict interface:
+ # * Does not support item assignment, thus not allowing this function
+ # to be used only for removing existing cache entries.
+ # * Does not support the dict.pop() method, forcing us to use the
+ # get/del patterns instead. For more detailed information see the
+ # following links:
+ # https://bitbucket.org/pypa/setuptools/issue/202/more-robust-zipimporter-cache-invalidation#comment-10495960
+ # https://bitbucket.org/pypy/pypy/src/dd07756a34a41f674c0cacfbc8ae1d4cc9ea2ae4/pypy/module/zipimport/interp_zipimport.py#cl-99
+ old_entry = cache[p]
del cache[p]
+ new_entry = updater and updater(p, old_entry)
+ if new_entry is not None:
+ cache[p] = new_entry
+
+
+def _uncache(normalized_path, cache):
+ _update_zipimporter_cache(normalized_path, cache)
+
+
+def _remove_and_clear_zip_directory_cache_data(normalized_path):
+ def clear_and_remove_cached_zip_archive_directory_data(path, old_entry):
+ old_entry.clear()
+
+ _update_zipimporter_cache(
+ normalized_path, zipimport._zip_directory_cache,
+ updater=clear_and_remove_cached_zip_archive_directory_data)
+
+# PyPy Python implementation does not allow directly writing to the
+# zipimport._zip_directory_cache and so prevents us from attempting to correct
+# its content. The best we can do there is clear the problematic cache content
+# and have PyPy repopulate it as needed. The downside is that if there are any
+# stale zipimport.zipimporter instances laying around, attempting to use them
+# will fail due to not having its zip archive directory information available
+# instead of being automatically corrected to use the new correct zip archive
+# directory information.
+if '__pypy__' in sys.builtin_module_names:
+ _replace_zip_directory_cache_data = \
+ _remove_and_clear_zip_directory_cache_data
+else:
+ def _replace_zip_directory_cache_data(normalized_path):
+ def replace_cached_zip_archive_directory_data(path, old_entry):
+ # N.B. In theory, we could load the zip directory information just
+ # once for all updated path spellings, and then copy it locally and
+ # update its contained path strings to contain the correct
+ # spelling, but that seems like a way too invasive move (this cache
+ # structure is not officially documented anywhere and could in
+ # theory change with new Python releases) for no significant
+ # benefit.
+ old_entry.clear()
+ zipimport.zipimporter(path)
+ old_entry.update(zipimport._zip_directory_cache[path])
+ return old_entry
+
+ _update_zipimporter_cache(
+ normalized_path, zipimport._zip_directory_cache,
+ updater=replace_cached_zip_archive_directory_data)
+
def is_python(text, filename='<string>'):
"Is this string a valid Python script?"
@@ -1621,15 +1807,18 @@ def is_python(text, filename='<string>'):
else:
return True
+
def is_sh(executable):
"""Determine if the specified executable is a .sh (contains a #! line)"""
try:
fp = open(executable)
magic = fp.read(2)
fp.close()
- except (OSError,IOError): return executable
+ except (OSError, IOError):
+ return executable
return magic == '#!'
+
def nt_quote_arg(arg):
"""Quote a command line argument according to Windows parsing rules"""
@@ -1646,7 +1835,7 @@ def nt_quote_arg(arg):
nb += 1
elif c == '"':
# double preceding backslashes, then add a \"
- result.append('\\' * (nb*2) + '\\"')
+ result.append('\\' * (nb * 2) + '\\"')
nb = 0
else:
if nb:
@@ -1658,29 +1847,33 @@ def nt_quote_arg(arg):
result.append('\\' * nb)
if needquote:
- result.append('\\' * nb) # double the trailing backslashes
+ result.append('\\' * nb) # double the trailing backslashes
result.append('"')
return ''.join(result)
+
def is_python_script(script_text, filename):
"""Is this text, as a whole, a Python script? (as opposed to shell/bat/etc.
"""
if filename.endswith('.py') or filename.endswith('.pyw'):
- return True # extension says it's Python
+ return True # extension says it's Python
if is_python(script_text, filename):
- return True # it's syntactically valid Python
+ return True # it's syntactically valid Python
if script_text.startswith('#!'):
# It begins with a '#!' line, so check if 'python' is in it somewhere
return 'python' in script_text.splitlines()[0].lower()
- return False # Not any Python I can recognize
+ return False # Not any Python I can recognize
+
try:
from os import chmod as _chmod
except ImportError:
# Jython compatibility
- def _chmod(*args): pass
+ def _chmod(*args):
+ pass
+
def chmod(path, mode):
log.debug("changing mode of %s to %o", path, mode)
@@ -1690,10 +1883,12 @@ def chmod(path, mode):
e = sys.exc_info()[1]
log.debug("chmod failed: %s", e)
+
def fix_jython_executable(executable, options):
if sys.platform.startswith('java') and is_sh(executable):
# Workaround for Jython is not needed on Linux systems.
import java
+
if java.lang.System.getProperty("os.name") == "Linux":
return executable
@@ -1742,19 +1937,19 @@ class ScriptWriter(object):
for name, ep in dist.get_entry_map(group).items():
script_text = gen_class.template % locals()
for res in gen_class._get_script_args(type_, name, header,
- script_text):
+ script_text):
yield res
@classmethod
def get_writer(cls, force_windows):
- if force_windows or sys.platform=='win32':
+ if force_windows or sys.platform == 'win32':
return WindowsScriptWriter.get_writer()
return cls
@classmethod
def _get_script_args(cls, type_, name, header, script_text):
# Simply write the stub with no extension.
- yield (name, header+script_text)
+ yield (name, header + script_text)
class WindowsScriptWriter(ScriptWriter):
@@ -1777,12 +1972,12 @@ class WindowsScriptWriter(ScriptWriter):
ext = dict(console='.pya', gui='.pyw')[type_]
if ext not in os.environ['PATHEXT'].lower().split(';'):
warnings.warn("%s not listed in PATHEXT; scripts will not be "
- "recognized as executables." % ext, UserWarning)
+ "recognized as executables." % ext, UserWarning)
old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe']
old.remove(ext)
header = cls._adjust_header(type_, header)
- blockers = [name+x for x in old]
- yield name+ext, header+script_text, 't', blockers
+ blockers = [name + x for x in old]
+ yield name + ext, header + script_text, 't', blockers
@staticmethod
def _adjust_header(type_, orig_header):
@@ -1809,33 +2004,35 @@ class WindowsExecutableLauncherWriter(WindowsScriptWriter):
"""
For Windows, add a .py extension and an .exe launcher
"""
- if type_=='gui':
+ if type_ == 'gui':
launcher_type = 'gui'
ext = '-script.pyw'
old = ['.pyw']
else:
launcher_type = 'cli'
ext = '-script.py'
- old = ['.py','.pyc','.pyo']
+ old = ['.py', '.pyc', '.pyo']
hdr = cls._adjust_header(type_, header)
- blockers = [name+x for x in old]
- yield (name+ext, hdr+script_text, 't', blockers)
+ blockers = [name + x for x in old]
+ yield (name + ext, hdr + script_text, 't', blockers)
yield (
- name+'.exe', get_win_launcher(launcher_type),
- 'b' # write in binary mode
+ name + '.exe', get_win_launcher(launcher_type),
+ 'b' # write in binary mode
)
if not is_64bit():
# install a manifest for the launcher to prevent Windows
- # from detecting it as an installer (which it will for
+ # from detecting it as an installer (which it will for
# launchers like easy_install.exe). Consider only
# adding a manifest for launchers detected as installers.
# See Distribute #143 for details.
m_name = name + '.exe.manifest'
yield (m_name, load_launcher_manifest(name), 't')
+
# for backward-compatibility
get_script_args = ScriptWriter.get_script_args
+
def get_win_launcher(type):
"""
Load the Windows launcher (executable) suitable for launching a script.
@@ -1845,7 +2042,7 @@ def get_win_launcher(type):
Returns the executable as a byte string.
"""
launcher_fn = '%s.exe' % type
- if platform.machine().lower()=='arm':
+ if platform.machine().lower() == 'arm':
launcher_fn = launcher_fn.replace(".", "-arm.")
if is_64bit():
launcher_fn = launcher_fn.replace(".", "-64.")
@@ -1853,6 +2050,7 @@ def get_win_launcher(type):
launcher_fn = launcher_fn.replace(".", "-32.")
return resource_string('setuptools', launcher_fn)
+
def load_launcher_manifest(name):
manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml')
if PY2:
@@ -1860,6 +2058,7 @@ def load_launcher_manifest(name):
else:
return manifest.decode('utf-8') % vars()
+
def rmtree(path, ignore_errors=False, onerror=auto_chmod):
"""Recursively delete a directory tree.
@@ -1895,19 +2094,23 @@ def rmtree(path, ignore_errors=False, onerror=auto_chmod):
except os.error:
onerror(os.rmdir, path, sys.exc_info())
+
def current_umask():
tmp = os.umask(0o022)
os.umask(tmp)
return tmp
+
def bootstrap():
# This function is called when setuptools*.egg is run using /bin/sh
import setuptools
+
argv0 = os.path.dirname(setuptools.__path__[0])
sys.argv[0] = argv0
sys.argv.append(argv0)
main()
+
def main(argv=None, **kw):
from setuptools import setup
from setuptools.dist import Distribution
@@ -1934,16 +2137,16 @@ usage: %(script)s [options] requirement_or_url ...
class DistributionWithoutHelpCommands(Distribution):
common_usage = ""
- def _show_help(self,*args,**kw):
- with_ei_usage(lambda: Distribution._show_help(self,*args,**kw))
+ def _show_help(self, *args, **kw):
+ with_ei_usage(lambda: Distribution._show_help(self, *args, **kw))
if argv is None:
argv = sys.argv[1:]
- with_ei_usage(lambda:
- setup(
- script_args = ['-q','easy_install', '-v']+argv,
- script_name = sys.argv[0] or 'easy_install',
+ with_ei_usage(
+ lambda: setup(
+ script_args=['-q', 'easy_install', '-v'] + argv,
+ script_name=sys.argv[0] or 'easy_install',
distclass=DistributionWithoutHelpCommands, **kw
)
)
diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py
index be326ac2..a1818edc 100755
--- a/setuptools/command/egg_info.py
+++ b/setuptools/command/egg_info.py
@@ -2,22 +2,22 @@
Create a distribution's .egg-info directory and contents"""
+from distutils.filelist import FileList as _FileList
+from distutils.util import convert_path
+from distutils import log
+import distutils.errors
import os
import re
import sys
-import io
from setuptools import Command
-import distutils.errors
-from distutils import log
from setuptools.command.sdist import sdist
-from setuptools.compat import basestring, PY3, unicode
+from setuptools.compat import basestring, PY3, StringIO
from setuptools import svn_utils
-from distutils.util import convert_path
-from distutils.filelist import FileList as _FileList
-from pkg_resources import (parse_requirements, safe_name, parse_version,
- safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
from setuptools.command.sdist import walk_revctrl
+from pkg_resources import (
+ parse_requirements, safe_name, parse_version,
+ safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename)
import setuptools.unicode_utils as unicode_utils
@@ -28,11 +28,11 @@ class egg_info(Command):
('egg-base=', 'e', "directory containing .egg-info directories"
" (default: top of the source tree)"),
('tag-svn-revision', 'r',
- "Add subversion revision ID to version number"),
+ "Add subversion revision ID to version number"),
('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
('tag-build=', 'b', "Specify explicit tag to add to version number"),
('no-svn-revision', 'R',
- "Don't add subversion revision ID [default]"),
+ "Don't add subversion revision ID [default]"),
('no-date', 'D', "Don't include date stamp [default]"),
]
@@ -53,6 +53,7 @@ class egg_info(Command):
def save_version_info(self, filename):
from setuptools.command.setopt import edit_config
+
values = dict(
egg_info=dict(
tag_svn_revision=0,
@@ -69,23 +70,25 @@ class egg_info(Command):
try:
list(
- parse_requirements('%s==%s' % (self.egg_name,self.egg_version))
+ parse_requirements('%s==%s' % (self.egg_name,
+ self.egg_version))
)
except ValueError:
raise distutils.errors.DistutilsOptionError(
"Invalid distribution name or version syntax: %s-%s" %
- (self.egg_name,self.egg_version)
+ (self.egg_name, self.egg_version)
)
if self.egg_base is None:
dirs = self.distribution.package_dir
- self.egg_base = (dirs or {}).get('',os.curdir)
+ self.egg_base = (dirs or {}).get('', os.curdir)
self.ensure_dirname('egg_base')
- self.egg_info = to_filename(self.egg_name)+'.egg-info'
+ self.egg_info = to_filename(self.egg_name) + '.egg-info'
if self.egg_base != os.curdir:
self.egg_info = os.path.join(self.egg_base, self.egg_info)
- if '-' in self.egg_name: self.check_broken_egg_info()
+ if '-' in self.egg_name:
+ self.check_broken_egg_info()
# Set package version for the benefit of dumber commands
# (e.g. sdist, bdist_wininst, etc.)
@@ -97,7 +100,7 @@ class egg_info(Command):
# to the version info
#
pd = self.distribution._patched_dist
- if pd is not None and pd.key==self.egg_name.lower():
+ if pd is not None and pd.key == self.egg_name.lower():
pd._version = self.egg_version
pd._parsed_version = parse_version(self.egg_version)
self.distribution._patched_dist = None
@@ -155,7 +158,7 @@ class egg_info(Command):
installer = self.distribution.fetch_build_egg
for ep in iter_entry_points('egg_info.writers'):
writer = ep.load(installer=installer)
- writer(self, ep.name, os.path.join(self.egg_info,ep.name))
+ writer(self, ep.name, os.path.join(self.egg_info, ep.name))
# Get rid of native_libs.txt if it was put there by older bdist_egg
nl = os.path.join(self.egg_info, "native_libs.txt")
@@ -167,13 +170,14 @@ class egg_info(Command):
def tags(self):
version = ''
if self.tag_build:
- version+=self.tag_build
+ version += self.tag_build
if self.tag_svn_revision:
rev = self.get_svn_revision()
if rev: # is 0 if it's not an svn working copy
version += '-r%s' % rev
if self.tag_date:
import time
+
version += time.strftime("-%Y%m%d")
return version
@@ -183,32 +187,33 @@ class egg_info(Command):
def find_sources(self):
"""Generate SOURCES.txt manifest file"""
- manifest_filename = os.path.join(self.egg_info,"SOURCES.txt")
+ manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
mm = manifest_maker(self.distribution)
mm.manifest = manifest_filename
mm.run()
self.filelist = mm.filelist
def check_broken_egg_info(self):
- bei = self.egg_name+'.egg-info'
+ bei = self.egg_name + '.egg-info'
if self.egg_base != os.curdir:
bei = os.path.join(self.egg_base, bei)
if os.path.exists(bei):
log.warn(
- "-"*78+'\n'
+ "-" * 78 + '\n'
"Note: Your current .egg-info directory has a '-' in its name;"
'\nthis will not work correctly with "setup.py develop".\n\n'
- 'Please rename %s to %s to correct this problem.\n'+'-'*78,
+ 'Please rename %s to %s to correct this problem.\n' + '-' * 78,
bei, self.egg_info
)
self.broken_egg_info = self.egg_info
- self.egg_info = bei # make it work for now
+ self.egg_info = bei # make it work for now
+
class FileList(_FileList):
"""File list that accepts only existing, platform-independent paths"""
def append(self, item):
- if item.endswith('\r'): # Fix older sdists built on Windows
+ if item.endswith('\r'): # Fix older sdists built on Windows
item = item[:-1]
path = convert_path(item)
@@ -231,29 +236,28 @@ class FileList(_FileList):
def _safe_path(self, path):
enc_warn = "'%s' not %s encodable -- skipping"
- #To avoid accidental trans-codings errors, first to unicode
+ # To avoid accidental trans-codings errors, first to unicode
u_path = unicode_utils.filesys_decode(path)
if u_path is None:
log.warn("'%s' in unexpected encoding -- skipping" % path)
return False
- #Must ensure utf-8 encodability
+ # Must ensure utf-8 encodability
utf8_path = unicode_utils.try_encode(u_path, "utf-8")
if utf8_path is None:
log.warn(enc_warn, path, 'utf-8')
return False
try:
- #accept is either way checks out
+ # accept is either way checks out
if os.path.exists(u_path) or os.path.exists(utf8_path):
return True
- #this will catch any encode errors decoding u_path
+ # this will catch any encode errors decoding u_path
except UnicodeEncodeError:
log.warn(enc_warn, path, sys.getfilesystemencoding())
class manifest_maker(sdist):
-
template = "MANIFEST.in"
def initialize_options(self):
@@ -268,7 +272,7 @@ class manifest_maker(sdist):
def run(self):
self.filelist = FileList()
if not os.path.exists(self.manifest):
- self.write_manifest() # it must exist so it'll get in the list
+ self.write_manifest() # it must exist so it'll get in the list
self.filelist.findall()
self.add_defaults()
if os.path.exists(self.template):
@@ -289,12 +293,12 @@ class manifest_maker(sdist):
"""
self.filelist._repair()
- #Now _repairs should encodability, but not unicode
+ # Now _repairs should encodability, but not unicode
files = [self._manifest_normalize(f) for f in self.filelist.files]
msg = "writing manifest file '%s'" % self.manifest
self.execute(write_file, (self.manifest, files), msg)
- def warn(self, msg): # suppress missing-file warnings from sdist
+ def warn(self, msg): # suppress missing-file warnings from sdist
if not msg.startswith("standard file not found:"):
sdist.warn(self, msg)
@@ -316,7 +320,7 @@ class manifest_maker(sdist):
self.filelist.exclude_pattern(None, prefix=build.build_base)
self.filelist.exclude_pattern(None, prefix=base_dir)
sep = re.escape(os.sep)
- self.filelist.exclude_pattern(r'(^|'+sep+r')(RCS|CVS|\.svn)'+sep,
+ self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep,
is_regex=1)
@@ -326,10 +330,10 @@ def write_file(filename, contents):
"""
contents = "\n".join(contents)
- #assuming the contents has been vetted for utf-8 encoding
+ # assuming the contents has been vetted for utf-8 encoding
contents = contents.encode("utf-8")
- with open(filename, "wb") as f: # always write POSIX-style manifest
+ with open(filename, "wb") as f: # always write POSIX-style manifest
f.write(contents)
@@ -346,10 +350,12 @@ def write_pkg_info(cmd, basename, filename):
finally:
metadata.name, metadata.version = oldname, oldver
- safe = getattr(cmd.distribution,'zip_safe',None)
+ safe = getattr(cmd.distribution, 'zip_safe', None)
from setuptools.command import bdist_egg
+
bdist_egg.write_safety_flag(cmd.egg_info, safe)
+
def warn_depends_obsolete(cmd, basename, filename):
if os.path.exists(filename):
log.warn(
@@ -364,9 +370,10 @@ def _write_requirements(stream, reqs):
lines = map(append_cr, lines)
stream.writelines(lines)
+
def write_requirements(cmd, basename, filename):
dist = cmd.distribution
- data = io.StringIO() if PY3 else io.BytesIO()
+ data = StringIO()
_write_requirements(data, dist.install_requires)
extras_require = dist.extras_require or {}
for extra in sorted(extras_require):
@@ -374,48 +381,52 @@ def write_requirements(cmd, basename, filename):
_write_requirements(data, extras_require[extra])
cmd.write_or_delete_file("requirements", filename, data.getvalue())
+
def write_toplevel_names(cmd, basename, filename):
pkgs = dict.fromkeys(
[
- k.split('.',1)[0]
+ k.split('.', 1)[0]
for k in cmd.distribution.iter_distribution_names()
]
)
- cmd.write_file("top-level names", filename, '\n'.join(pkgs)+'\n')
+ cmd.write_file("top-level names", filename, '\n'.join(pkgs) + '\n')
def overwrite_arg(cmd, basename, filename):
write_arg(cmd, basename, filename, True)
+
def write_arg(cmd, basename, filename, force=False):
argname = os.path.splitext(basename)[0]
value = getattr(cmd.distribution, argname, None)
if value is not None:
- value = '\n'.join(value)+'\n'
+ value = '\n'.join(value) + '\n'
cmd.write_or_delete_file(argname, filename, value, force)
+
def write_entries(cmd, basename, filename):
ep = cmd.distribution.entry_points
- if isinstance(ep,basestring) or ep is None:
+ if isinstance(ep, basestring) or ep is None:
data = ep
elif ep is not None:
data = []
for section, contents in sorted(ep.items()):
- if not isinstance(contents,basestring):
+ if not isinstance(contents, basestring):
contents = EntryPoint.parse_group(section, contents)
- contents = '\n'.join(sorted(map(str,contents.values())))
- data.append('[%s]\n%s\n\n' % (section,contents))
+ contents = '\n'.join(sorted(map(str, contents.values())))
+ data.append('[%s]\n%s\n\n' % (section, contents))
data = ''.join(data)
cmd.write_or_delete_file('entry points', filename, data, True)
+
def get_pkg_info_revision():
# See if we can get a -r### off of PKG-INFO, in case this is an sdist of
# a subversion revision
#
if os.path.exists('PKG-INFO'):
- f = open('PKG-INFO','rU')
+ f = open('PKG-INFO', 'rU')
for line in f:
match = re.match(r"Version:.*-r(\d+)\s*$", line)
if match:
diff --git a/setuptools/command/install.py b/setuptools/command/install.py
index 1f489734..d2bca2ec 100644
--- a/setuptools/command/install.py
+++ b/setuptools/command/install.py
@@ -1,22 +1,24 @@
-import setuptools
+from distutils.errors import DistutilsArgError
import inspect
import glob
import warnings
import platform
import distutils.command.install as orig
-from distutils.errors import DistutilsArgError
+
+import setuptools
# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for
-# now. See https://bitbucket.org/pypa/setuptools/issue/199/
+# now. See https://bitbucket.org/pypa/setuptools/issue/199/
_install = orig.install
+
class install(orig.install):
"""Use easy_install to install the package, w/dependencies"""
user_options = orig.install.user_options + [
('old-and-unmanageable', None, "Try not to use this!"),
('single-version-externally-managed', None,
- "used by system package builders to create 'flat' eggs"),
+ "used by system package builders to create 'flat' eggs"),
]
boolean_options = orig.install.boolean_options + [
'old-and-unmanageable', 'single-version-externally-managed',
@@ -115,7 +117,9 @@ class install(orig.install):
cmd.run()
setuptools.bootstrap_install_from = None
+
# XXX Python 3.1 doesn't see _nc if this is inside the class
-install.sub_commands = [
- cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc
- ] + install.new_commands
+install.sub_commands = (
+ [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] +
+ install.new_commands
+)
diff --git a/setuptools/command/install_egg_info.py b/setuptools/command/install_egg_info.py
index 73b5ef73..fd0f118b 100755
--- a/setuptools/command/install_egg_info.py
+++ b/setuptools/command/install_egg_info.py
@@ -1,7 +1,10 @@
+from distutils import log, dir_util
+import os
+
from setuptools import Command
from setuptools.archive_util import unpack_archive
-from distutils import log, dir_util
-import os, pkg_resources
+import pkg_resources
+
class install_egg_info(Command):
"""Install an .egg-info directory for the package"""
@@ -16,26 +19,26 @@ class install_egg_info(Command):
self.install_dir = None
def finalize_options(self):
- self.set_undefined_options('install_lib',('install_dir','install_dir'))
+ self.set_undefined_options('install_lib',
+ ('install_dir', 'install_dir'))
ei_cmd = self.get_finalized_command("egg_info")
basename = pkg_resources.Distribution(
None, None, ei_cmd.egg_name, ei_cmd.egg_version
- ).egg_name()+'.egg-info'
+ ).egg_name() + '.egg-info'
self.source = ei_cmd.egg_info
self.target = os.path.join(self.install_dir, basename)
self.outputs = [self.target]
def run(self):
self.run_command('egg_info')
- target = self.target
if os.path.isdir(self.target) and not os.path.islink(self.target):
dir_util.remove_tree(self.target, dry_run=self.dry_run)
elif os.path.exists(self.target):
- self.execute(os.unlink,(self.target,),"Removing "+self.target)
+ self.execute(os.unlink, (self.target,), "Removing " + self.target)
if not self.dry_run:
pkg_resources.ensure_directory(self.target)
- self.execute(self.copytree, (),
- "Copying %s to %s" % (self.source, self.target)
+ self.execute(
+ self.copytree, (), "Copying %s to %s" % (self.source, self.target)
)
self.install_namespaces()
@@ -44,82 +47,70 @@ class install_egg_info(Command):
def copytree(self):
# Copy the .egg-info tree to site-packages
- def skimmer(src,dst):
+ def skimmer(src, dst):
# filter out source-control directories; note that 'src' is always
# a '/'-separated path, regardless of platform. 'dst' is a
# platform-specific path.
- for skip in '.svn/','CVS/':
- if src.startswith(skip) or '/'+skip in src:
+ for skip in '.svn/', 'CVS/':
+ if src.startswith(skip) or '/' + skip in src:
return None
self.outputs.append(dst)
log.debug("Copying %s to %s", src, dst)
return dst
- unpack_archive(self.source, self.target, skimmer)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ unpack_archive(self.source, self.target, skimmer)
def install_namespaces(self):
nsp = self._get_all_ns_packages()
- if not nsp: return
- filename,ext = os.path.splitext(self.target)
- filename += '-nspkg.pth'; self.outputs.append(filename)
- log.info("Installing %s",filename)
- if not self.dry_run:
- f = open(filename,'wt')
- for pkg in nsp:
- # ensure pkg is not a unicode string under Python 2.7
- pkg = str(pkg)
- pth = tuple(pkg.split('.'))
- trailer = '\n'
- if '.' in pkg:
- trailer = (
- "; m and setattr(sys.modules[%r], %r, m)\n"
- % ('.'.join(pth[:-1]), pth[-1])
- )
- f.write(
- "import sys,types,os; "
- "p = os.path.join(sys._getframe(1).f_locals['sitedir'], "
- "*%(pth)r); "
- "ie = os.path.exists(os.path.join(p,'__init__.py')); "
- "m = not ie and "
- "sys.modules.setdefault(%(pkg)r,types.ModuleType(%(pkg)r)); "
- "mp = (m or []) and m.__dict__.setdefault('__path__',[]); "
- "(p not in mp) and mp.append(p)%(trailer)s"
- % locals()
- )
- f.close()
+ if not nsp:
+ return
+ filename, ext = os.path.splitext(self.target)
+ filename += '-nspkg.pth'
+ self.outputs.append(filename)
+ log.info("Installing %s", filename)
+ lines = map(self._gen_nspkg_line, nsp)
+
+ if self.dry_run:
+ # always generate the lines, even in dry run
+ list(lines)
+ return
+
+ with open(filename, 'wt') as f:
+ f.writelines(lines)
+
+ _nspkg_tmpl = (
+ "import sys, types, os",
+ "p = os.path.join(sys._getframe(1).f_locals['sitedir'], *%(pth)r)",
+ "ie = os.path.exists(os.path.join(p,'__init__.py'))",
+ "m = not ie and "
+ "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))",
+ "mp = (m or []) and m.__dict__.setdefault('__path__',[])",
+ "(p not in mp) and mp.append(p)",
+ )
+ "lines for the namespace installer"
+
+ _nspkg_tmpl_multi = (
+ 'm and setattr(sys.modules[%(parent)r], %(child)r, m)',
+ )
+ "additional line(s) when a parent package is indicated"
+
+ @classmethod
+ def _gen_nspkg_line(cls, pkg):
+ # ensure pkg is not a unicode string under Python 2.7
+ pkg = str(pkg)
+ pth = tuple(pkg.split('.'))
+ tmpl_lines = cls._nspkg_tmpl
+ parent, sep, child = pkg.rpartition('.')
+ if parent:
+ tmpl_lines += cls._nspkg_tmpl_multi
+ return ';'.join(tmpl_lines) % locals() + '\n'
def _get_all_ns_packages(self):
- nsp = {}
+ """Return sorted list of all package namespaces"""
+ nsp = set()
for pkg in self.distribution.namespace_packages or []:
pkg = pkg.split('.')
while pkg:
- nsp['.'.join(pkg)] = 1
+ nsp.add('.'.join(pkg))
pkg.pop()
- nsp=list(nsp)
- nsp.sort() # set up shorter names first
- return nsp
-
-
+ return sorted(nsp)
diff --git a/setuptools/command/install_lib.py b/setuptools/command/install_lib.py
index 747fbabb..d7e117f0 100644
--- a/setuptools/command/install_lib.py
+++ b/setuptools/command/install_lib.py
@@ -1,6 +1,7 @@
import distutils.command.install_lib as orig
import os
+
class install_lib(orig.install_lib):
"""Don't add compiled flags to filenames of non-Python files"""
@@ -15,20 +16,20 @@ class install_lib(orig.install_lib):
exclude = {}
nsp = self.distribution.namespace_packages
svem = (nsp and self.get_finalized_command('install')
- .single_version_externally_managed)
+ .single_version_externally_managed)
if svem:
for pkg in nsp:
parts = pkg.split('.')
while parts:
pkgdir = os.path.join(self.install_dir, *parts)
for f in '__init__.py', '__init__.pyc', '__init__.pyo':
- exclude[os.path.join(pkgdir,f)] = 1
+ exclude[os.path.join(pkgdir, f)] = 1
parts.pop()
return exclude
def copy_tree(
- self, infile, outfile,
- preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1
+ self, infile, outfile,
+ preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1
):
assert preserve_mode and preserve_times and not preserve_symlinks
exclude = self.get_exclusions()
@@ -45,7 +46,8 @@ class install_lib(orig.install_lib):
def pf(src, dst):
if dst in exclude:
- log.warn("Skipping installation of %s (namespace package)",dst)
+ log.warn("Skipping installation of %s (namespace package)",
+ dst)
return False
log.info("copying %s -> %s", src, os.path.dirname(dst))
diff --git a/setuptools/command/install_scripts.py b/setuptools/command/install_scripts.py
index ac373193..eb79fa3c 100755
--- a/setuptools/command/install_scripts.py
+++ b/setuptools/command/install_scripts.py
@@ -1,7 +1,9 @@
+from distutils import log
import distutils.command.install_scripts as orig
-from pkg_resources import Distribution, PathMetadata, ensure_directory
import os
-from distutils import log
+
+from pkg_resources import Distribution, PathMetadata, ensure_directory
+
class install_scripts(orig.install_scripts):
"""Do normal script install, plus any egg_info wrapper scripts"""
@@ -29,7 +31,7 @@ class install_scripts(orig.install_scripts):
ei_cmd.egg_name, ei_cmd.egg_version,
)
bs_cmd = self.get_finalized_command('build_scripts')
- executable = getattr(bs_cmd,'executable',sys_executable)
+ executable = getattr(bs_cmd, 'executable', sys_executable)
is_wininst = getattr(
self.get_finalized_command("bdist_wininst"), '_is_running', False
)
@@ -39,6 +41,7 @@ class install_scripts(orig.install_scripts):
def write_script(self, script_name, contents, mode="t", *ignored):
"""Write an executable file to the scripts directory"""
from setuptools.command.easy_install import chmod, current_umask
+
log.info("Installing %s script to %s", script_name, self.install_dir)
target = os.path.join(self.install_dir, script_name)
self.outfiles.append(target)
@@ -46,7 +49,7 @@ class install_scripts(orig.install_scripts):
mask = current_umask()
if not self.dry_run:
ensure_directory(target)
- f = open(target,"w"+mode)
+ f = open(target, "w" + mode)
f.write(contents)
f.close()
- chmod(target, 0o777-mask)
+ chmod(target, 0o777 - mask)
diff --git a/setuptools/command/launcher manifest.xml b/setuptools/command/launcher manifest.xml
index 844d2264..5972a96d 100644
--- a/setuptools/command/launcher manifest.xml
+++ b/setuptools/command/launcher manifest.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-<assemblyIdentity version="1.0.0.0"
- processorArchitecture="X86"
- name="%(name)s"
- type="win32"/>
+ <assemblyIdentity version="1.0.0.0"
+ processorArchitecture="X86"
+ name="%(name)s"
+ type="win32"/>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
- <security>
- <requestedPrivileges>
- <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
- </requestedPrivileges>
- </security>
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
</trustInfo>
</assembly>
diff --git a/setuptools/command/register.py b/setuptools/command/register.py
index 6694d1c0..8d6336a1 100755
--- a/setuptools/command/register.py
+++ b/setuptools/command/register.py
@@ -1,5 +1,6 @@
import distutils.command.register as orig
+
class register(orig.register):
__doc__ = orig.register.__doc__
diff --git a/setuptools/command/rotate.py b/setuptools/command/rotate.py
index c556aa17..1b073620 100755
--- a/setuptools/command/rotate.py
+++ b/setuptools/command/rotate.py
@@ -1,18 +1,20 @@
-import os
-from setuptools import Command
-from setuptools.compat import basestring
from distutils.util import convert_path
from distutils import log
from distutils.errors import DistutilsOptionError
+import os
+
+from setuptools import Command
+from setuptools.compat import basestring
+
class rotate(Command):
"""Delete older distributions"""
description = "delete older distributions, keeping N newest files"
user_options = [
- ('match=', 'm', "patterns to match (required)"),
+ ('match=', 'm', "patterns to match (required)"),
('dist-dir=', 'd', "directory where the distributions are"),
- ('keep=', 'k', "number of matching distributions to keep"),
+ ('keep=', 'k', "number of matching distributions to keep"),
]
boolean_options = []
@@ -38,21 +40,22 @@ class rotate(Command):
self.match = [
convert_path(p.strip()) for p in self.match.split(',')
]
- self.set_undefined_options('bdist',('dist_dir', 'dist_dir'))
+ self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
def run(self):
self.run_command("egg_info")
from glob import glob
+
for pattern in self.match:
- pattern = self.distribution.get_name()+'*'+pattern
- files = glob(os.path.join(self.dist_dir,pattern))
- files = [(os.path.getmtime(f),f) for f in files]
+ pattern = self.distribution.get_name() + '*' + pattern
+ files = glob(os.path.join(self.dist_dir, pattern))
+ files = [(os.path.getmtime(f), f) for f in files]
files.sort()
files.reverse()
log.info("%d file(s) matching %s", len(files), pattern)
files = files[self.keep:]
- for (t,f) in files:
+ for (t, f) in files:
log.info("Deleting %s", f)
if not self.dry_run:
os.unlink(f)
diff --git a/setuptools/command/saveopts.py b/setuptools/command/saveopts.py
index 7209be4c..611cec55 100755
--- a/setuptools/command/saveopts.py
+++ b/setuptools/command/saveopts.py
@@ -1,7 +1,6 @@
-import distutils, os
-from setuptools import Command
from setuptools.command.setopt import edit_config, option_base
+
class saveopts(option_base):
"""Save command-line options to a file"""
@@ -13,12 +12,11 @@ class saveopts(option_base):
for cmd in dist.command_options:
- if cmd=='saveopts':
- continue # don't save our own options!
+ if cmd == 'saveopts':
+ continue # don't save our own options!
- for opt,(src,val) in dist.get_option_dict(cmd).items():
- if src=="command line":
- settings.setdefault(cmd,{})[opt] = val
+ for opt, (src, val) in dist.get_option_dict(cmd).items():
+ if src == "command line":
+ settings.setdefault(cmd, {})[opt] = val
edit_config(self.filename, settings, self.dry_run)
-
diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py
index f9a5b7b9..2aa1ee20 100755
--- a/setuptools/command/sdist.py
+++ b/setuptools/command/sdist.py
@@ -1,14 +1,14 @@
+from glob import glob
+from distutils.util import convert_path
+from distutils import log
+import distutils.command.sdist as orig
import os
import re
import sys
-from glob import glob
-import pkg_resources
-import distutils.command.sdist as orig
-from distutils.util import convert_path
-from distutils import log
from setuptools import svn_utils
from setuptools.compat import PY3
+import pkg_resources
READMES = ('README', 'README.rst', 'README.txt')
@@ -20,7 +20,7 @@ def walk_revctrl(dirname=''):
yield item
-#TODO will need test case
+# TODO will need test case
class re_finder(object):
"""
Finder that locates files based on entries in a file matched by a
@@ -33,7 +33,7 @@ class re_finder(object):
self.entries_path = convert_path(path)
def _finder(self, dirname, filename):
- f = open(filename,'rU')
+ f = open(filename, 'rU')
try:
data = f.read()
finally:
@@ -51,12 +51,13 @@ class re_finder(object):
if not os.path.isfile(path):
# entries file doesn't exist
return
- for path in self._finder(dirname,path):
+ for path in self._finder(dirname, path):
if os.path.isfile(path):
yield path
elif os.path.isdir(path):
for item in self.find(path):
yield item
+
__call__ = find
@@ -85,7 +86,7 @@ class sdist(orig.sdist):
('dist-dir=', 'd',
"directory to put the source distribution archive(s) in "
"[default: dist]"),
- ]
+ ]
negative_opt = {}
@@ -93,7 +94,7 @@ class sdist(orig.sdist):
self.run_command('egg_info')
ei_cmd = self.get_finalized_command('egg_info')
self.filelist = ei_cmd.filelist
- self.filelist.append(os.path.join(ei_cmd.egg_info,'SOURCES.txt'))
+ self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))
self.check_readme()
# Run sub commands
@@ -103,12 +104,13 @@ class sdist(orig.sdist):
# Call check_metadata only if no 'check' command
# (distutils <= 2.6)
import distutils.command
+
if 'check' not in distutils.command.__all__:
self.check_metadata()
self.make_distribution()
- dist_files = getattr(self.distribution,'dist_files',[])
+ dist_files = getattr(self.distribution, 'dist_files', [])
for file in self.archive_files:
data = ('sdist', '', file)
if data not in dist_files:
@@ -124,13 +126,14 @@ class sdist(orig.sdist):
except:
sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
raise
+
# Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle
# has been fixed, so only override the method if we're using an earlier
# Python.
has_leaky_handle = (
- sys.version_info < (2,7,2)
- or (3,0) <= sys.version_info < (3,1,4)
- or (3,2) <= sys.version_info < (3,2,1)
+ sys.version_info < (2, 7, 2)
+ or (3, 0) <= sys.version_info < (3, 1, 4)
+ or (3, 2) <= sys.version_info < (3, 2, 1)
)
if has_leaky_handle:
read_template = __read_template_hack
@@ -194,7 +197,8 @@ class sdist(orig.sdist):
return
else:
self.warn(
- "standard file not found: should have one of " +', '.join(READMES)
+ "standard file not found: should have one of " +
+ ', '.join(READMES)
)
def make_release_tree(self, base_dir, files):
@@ -202,7 +206,7 @@ class sdist(orig.sdist):
# Save any egg_info command line options used to create this sdist
dest = os.path.join(base_dir, 'setup.cfg')
- if hasattr(os,'link') and os.path.exists(dest):
+ if hasattr(os, 'link') and os.path.exists(dest):
# unlink and re-copy, since it might be hard-linked, and
# we don't want to change the source version
os.unlink(dest)
@@ -220,7 +224,8 @@ class sdist(orig.sdist):
first_line = fp.readline()
finally:
fp.close()
- return first_line != '# file GENERATED by distutils, do NOT edit\n'.encode()
+ return (first_line !=
+ '# file GENERATED by distutils, do NOT edit\n'.encode())
def read_manifest(self):
"""Read the manifest file (named by 'self.manifest') and use it to
diff --git a/setuptools/command/setopt.py b/setuptools/command/setopt.py
index 575653c8..a04d6032 100755
--- a/setuptools/command/setopt.py
+++ b/setuptools/command/setopt.py
@@ -1,9 +1,11 @@
-import os
-import distutils
-from setuptools import Command
from distutils.util import convert_path
from distutils import log
from distutils.errors import DistutilsOptionError
+import distutils
+import os
+
+from setuptools import Command
+
__all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
@@ -13,19 +15,20 @@ def config_file(kind="local"):
`kind` must be one of "local", "global", or "user"
"""
- if kind=='local':
+ if kind == 'local':
return 'setup.cfg'
- if kind=='global':
+ if kind == 'global':
return os.path.join(
- os.path.dirname(distutils.__file__),'distutils.cfg'
+ os.path.dirname(distutils.__file__), 'distutils.cfg'
)
- if kind=='user':
- dot = os.name=='posix' and '.' or ''
+ if kind == 'user':
+ dot = os.name == 'posix' and '.' or ''
return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot))
raise ValueError(
"config_file() type must be 'local', 'global', or 'user'", kind
)
+
def edit_config(filename, settings, dry_run=False):
"""Edit a configuration file to include `settings`
@@ -35,6 +38,7 @@ def edit_config(filename, settings, dry_run=False):
A setting of ``None`` means to delete that setting.
"""
from setuptools.compat import ConfigParser
+
log.debug("Reading configuration from %s", filename)
opts = ConfigParser.RawConfigParser()
opts.read([filename])
@@ -46,39 +50,40 @@ def edit_config(filename, settings, dry_run=False):
if not opts.has_section(section):
log.debug("Adding new section [%s] to %s", section, filename)
opts.add_section(section)
- for option,value in options.items():
+ for option, value in options.items():
if value is None:
log.debug(
"Deleting %s.%s from %s",
section, option, filename
)
- opts.remove_option(section,option)
+ opts.remove_option(section, option)
if not opts.options(section):
log.info("Deleting empty [%s] section from %s",
- section, filename)
+ section, filename)
opts.remove_section(section)
else:
log.debug(
"Setting %s.%s to %r in %s",
section, option, value, filename
)
- opts.set(section,option,value)
+ opts.set(section, option, value)
log.info("Writing %s", filename)
if not dry_run:
with open(filename, 'w') as f:
opts.write(f)
+
class option_base(Command):
"""Abstract base class for commands that mess with config files"""
user_options = [
('global-config', 'g',
- "save options to the site-wide distutils.cfg file"),
+ "save options to the site-wide distutils.cfg file"),
('user-config', 'u',
- "save options to the current user's pydistutils.cfg file"),
+ "save options to the current user's pydistutils.cfg file"),
('filename=', 'f',
- "configuration file to use (default=setup.cfg)"),
+ "configuration file to use (default=setup.cfg)"),
]
boolean_options = [
@@ -100,7 +105,7 @@ class option_base(Command):
filenames.append(self.filename)
if not filenames:
filenames.append(config_file('local'))
- if len(filenames)>1:
+ if len(filenames) > 1:
raise DistutilsOptionError(
"Must specify only one configuration file option",
filenames
@@ -115,9 +120,9 @@ class setopt(option_base):
user_options = [
('command=', 'c', 'command to set an option for'),
- ('option=', 'o', 'option to set'),
- ('set-value=', 's', 'value of the option'),
- ('remove', 'r', 'remove (unset) the value'),
+ ('option=', 'o', 'option to set'),
+ ('set-value=', 's', 'value of the option'),
+ ('remove', 'r', 'remove (unset) the value'),
] + option_base.user_options
boolean_options = option_base.boolean_options + ['remove']
@@ -139,7 +144,7 @@ class setopt(option_base):
def run(self):
edit_config(
self.filename, {
- self.command: {self.option.replace('-','_'):self.set_value}
+ self.command: {self.option.replace('-', '_'): self.set_value}
},
self.dry_run
)
diff --git a/setuptools/command/test.py b/setuptools/command/test.py
index 3c3581a9..18e90ffc 100644
--- a/setuptools/command/test.py
+++ b/setuptools/command/test.py
@@ -1,19 +1,17 @@
-import unittest
-from unittest import TestLoader
-
-from setuptools import Command
from distutils.errors import DistutilsOptionError
+from unittest import TestLoader
+import unittest
import sys
-from pkg_resources import (resource_listdir, resource_exists,
- normalize_path, working_set, _namespace_packages, add_activation_listener,
- require, EntryPoint)
+from pkg_resources import (resource_listdir, resource_exists, normalize_path,
+ working_set, _namespace_packages,
+ add_activation_listener, require, EntryPoint)
+from setuptools import Command
from setuptools.compat import PY3
from setuptools.py31compat import unittest_main
class ScanningLoader(TestLoader):
-
def loadTestsFromModule(self, module):
"""Return a suite of all tests cases contained in the given module
@@ -34,7 +32,7 @@ class ScanningLoader(TestLoader):
submodule = module.__name__ + '.' + file[:-3]
else:
if resource_exists(module.__name__, file + '/__init__.py'):
- submodule = module.__name__+'.'+file
+ submodule = module.__name__ + '.' + file
else:
continue
tests.append(self.loadTestsFromName(submodule))
@@ -42,19 +40,18 @@ class ScanningLoader(TestLoader):
if len(tests) != 1:
return self.suiteClass(tests)
else:
- return tests[0] # don't create a nested suite for only one return
+ return tests[0] # don't create a nested suite for only one return
class test(Command):
-
"""Command to run unit tests after in-place build"""
description = "run unit tests after in-place build"
user_options = [
- ('test-module=','m', "Run 'test_suite' in specified module"),
- ('test-suite=','s',
- "Test suite to run (e.g. 'some_module.test_suite')"),
+ ('test-module=', 'm', "Run 'test_suite' in specified module"),
+ ('test-suite=', 's',
+ "Test suite to run (e.g. 'some_module.test_suite')"),
('test-runner=', 'r', "Test runner to use"),
]
@@ -79,7 +76,7 @@ class test(Command):
self.test_args = [self.test_suite]
if self.verbose:
- self.test_args.insert(0,'--verbose')
+ self.test_args.insert(0, '--verbose')
if self.test_loader is None:
self.test_loader = getattr(self.distribution, 'test_loader', None)
if self.test_loader is None:
@@ -132,7 +129,8 @@ class test(Command):
def run(self):
if self.distribution.install_requires:
- self.distribution.fetch_build_eggs(self.distribution.install_requires)
+ self.distribution.fetch_build_eggs(
+ self.distribution.install_requires)
if self.distribution.tests_require:
self.distribution.fetch_build_eggs(self.distribution.tests_require)
@@ -161,7 +159,7 @@ class test(Command):
list(map(sys.modules.__delitem__, del_modules))
unittest_main(
- None, None, [unittest.__file__]+self.test_args,
+ None, None, [unittest.__file__] + self.test_args,
testLoader=self._resolve_as_ep(self.test_loader),
testRunner=self._resolve_as_ep(self.test_runner),
)
diff --git a/setuptools/command/upload_docs.py b/setuptools/command/upload_docs.py
index cad7a52d..cd6c300c 100644
--- a/setuptools/command/upload_docs.py
+++ b/setuptools/command/upload_docs.py
@@ -5,6 +5,10 @@ Implements a Distutils 'upload_docs' subcommand (upload documentation to
PyPI's pythonhosted.org).
"""
+from base64 import standard_b64encode
+from distutils import log
+from distutils.errors import DistutilsOptionError
+from distutils.command.upload import upload
import os
import socket
import zipfile
@@ -12,14 +16,9 @@ import tempfile
import sys
import shutil
-from base64 import standard_b64encode
+from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3
from pkg_resources import iter_entry_points
-from distutils import log
-from distutils.errors import DistutilsOptionError
-from distutils.command.upload import upload
-
-from setuptools.compat import httplib, urlparse, unicode, iteritems, PY3
errors = 'surrogateescape' if PY3 else 'strict'
@@ -33,7 +32,6 @@ def b(s, encoding='utf-8'):
class upload_docs(upload):
-
description = 'Upload documentation to PyPI'
user_options = [
@@ -42,7 +40,7 @@ class upload_docs(upload):
('show-response', None,
'display full response text from server'),
('upload-dir=', None, 'directory to upload'),
- ]
+ ]
boolean_options = upload.boolean_options
def has_sphinx(self):
@@ -159,7 +157,7 @@ class upload_docs(upload):
elif schema == 'https':
conn = httplib.HTTPSConnection(netloc)
else:
- raise AssertionError("unsupported schema "+schema)
+ raise AssertionError("unsupported schema " + schema)
data = ''
try:
@@ -190,4 +188,4 @@ class upload_docs(upload):
self.announce('Upload failed (%s): %s' % (r.status, r.reason),
log.ERROR)
if self.show_response:
- print('-'*75, r.read(), '-'*75)
+ print('-' * 75, r.read(), '-' * 75)
diff --git a/setuptools/dist.py b/setuptools/dist.py
index b8bd7490..8de95a38 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -34,11 +34,12 @@ _Distribution = _get_unpatched(_Distribution)
def _patch_distribution_metadata_write_pkg_info():
"""
- Workaround issue #197 - Python 3.1 uses an environment-local encoding to
- save the pkg_info. Monkey-patch its write_pkg_info method to correct
- this undesirable behavior.
+ Workaround issue #197 - Python 3 prior to 3.2.2 uses an environment-local
+ encoding to save the pkg_info. Monkey-patch its write_pkg_info method to
+ correct this undesirable behavior.
"""
- if sys.version_info[:2] != (3,1):
+ environment_local = (3,) <= sys.version_info[:3] < (3, 2, 2)
+ if not environment_local:
return
# from Python 3.4
@@ -279,12 +280,13 @@ class Distribution(_Distribution):
def fetch_build_eggs(self, requires):
"""Resolve pre-setup requirements"""
- from pkg_resources import working_set, parse_requirements
- for dist in working_set.resolve(
- parse_requirements(requires), installer=self.fetch_build_egg,
- replace_conflicting=True
- ):
- working_set.add(dist, replace=True)
+ resolved_dists = pkg_resources.working_set.resolve(
+ pkg_resources.parse_requirements(requires),
+ installer=self.fetch_build_egg,
+ replace_conflicting=True,
+ )
+ for dist in resolved_dists:
+ pkg_resources.working_set.add(dist, replace=True)
def finalize_options(self):
_Distribution.finalize_options(self)
diff --git a/setuptools/script template (dev).py b/setuptools/script (dev).tmpl
index b3fe209e..c476673f 100644
--- a/setuptools/script template (dev).py
+++ b/setuptools/script (dev).tmpl
@@ -1,10 +1,10 @@
# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
-__requires__ = """%(spec)r"""
+__requires__ = %(spec)r
import sys
from pkg_resources import require
-require("""%(spec)r""")
+require(%(spec)r)
del require
-__file__ = """%(dev_path)r"""
+__file__ = %(dev_path)r
if sys.version_info < (3, 0):
execfile(__file__)
else:
diff --git a/setuptools/script template.py b/setuptools/script template.py
deleted file mode 100644
index 8dd5d510..00000000
--- a/setuptools/script template.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
-__requires__ = """%(spec)r"""
-import pkg_resources
-pkg_resources.run_script("""%(spec)r""", """%(script_name)r""")
diff --git a/setuptools/script.tmpl b/setuptools/script.tmpl
new file mode 100644
index 00000000..4504e264
--- /dev/null
+++ b/setuptools/script.tmpl
@@ -0,0 +1,4 @@
+# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
+__requires__ = %(spec)r
+import pkg_resources
+pkg_resources.run_script(%(spec)r, %(script_name)r)
diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py
index 18f35c0f..66d182eb 100644
--- a/setuptools/tests/test_develop.py
+++ b/setuptools/tests/test_develop.py
@@ -9,8 +9,6 @@ import unittest
from distutils.errors import DistutilsError
from setuptools.command.develop import develop
-from setuptools.command import easy_install as easy_install_pkg
-from setuptools.compat import StringIO
from setuptools.dist import Distribution
SETUP_PY = """\
@@ -114,11 +112,11 @@ class TestDevelopTest(unittest.TestCase):
os.chdir(self.dir)
try:
try:
- dist = Distribution({'setup_requires': ['I_DONT_EXIST']})
+ Distribution({'setup_requires': ['I_DONT_EXIST']})
except DistutilsError:
e = sys.exc_info()[1]
error = str(e)
- if error == wanted:
+ if error == wanted:
pass
finally:
os.chdir(old_dir)
diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py
index 92f7aff7..fe390728 100644
--- a/setuptools/tests/test_find_packages.py
+++ b/setuptools/tests/test_find_packages.py
@@ -12,12 +12,26 @@ from setuptools.tests.py26compat import skipIf
find_420_packages = setuptools.PEP420PackageFinder.find
+# modeled after CPython's test.support.can_symlink
+def can_symlink():
+ TESTFN = tempfile.mktemp()
+ symlink_path = TESTFN + "can_symlink"
+ try:
+ os.symlink(TESTFN, symlink_path)
+ can = True
+ except (OSError, NotImplementedError, AttributeError):
+ can = False
+ else:
+ os.remove(symlink_path)
+ globals().update(can_symlink=lambda: can)
+ return can
+
def has_symlink():
bad_symlink = (
# Windows symlink directory detection is broken on Python 3.2
platform.system() == 'Windows' and sys.version_info[:2] == (3,2)
)
- return hasattr(os, 'symlink') and not bad_symlink
+ return can_symlink() and not bad_symlink
class TestFindPackages(unittest.TestCase):
diff --git a/setuptools/tests/test_integration.py b/setuptools/tests/test_integration.py
new file mode 100644
index 00000000..7144aa6c
--- /dev/null
+++ b/setuptools/tests/test_integration.py
@@ -0,0 +1,80 @@
+"""Run some integration tests.
+
+Try to install a few packages.
+"""
+
+import glob
+import os
+import sys
+
+import pytest
+
+from setuptools.command.easy_install import easy_install
+from setuptools.command import easy_install as easy_install_pkg
+from setuptools.dist import Distribution
+
+
+@pytest.fixture
+def install_context(request, tmpdir, monkeypatch):
+ """Fixture to set up temporary installation directory.
+ """
+ # Save old values so we can restore them.
+ new_cwd = tmpdir.mkdir('cwd')
+ user_base = tmpdir.mkdir('user_base')
+ user_site = tmpdir.mkdir('user_site')
+ install_dir = tmpdir.mkdir('install_dir')
+
+ def fin():
+ new_cwd.remove()
+ user_base.remove()
+ user_site.remove()
+ install_dir.remove()
+ request.addfinalizer(fin)
+
+ # Change the environment and site settings to control where the
+ # files are installed and ensure we do not overwrite anything.
+ monkeypatch.chdir(new_cwd)
+ monkeypatch.setattr(easy_install_pkg, '__file__', user_site.strpath)
+ monkeypatch.setattr('site.USER_BASE', user_base.strpath)
+ monkeypatch.setattr('site.USER_SITE', user_site.strpath)
+ monkeypatch.setattr('sys.path', sys.path + [install_dir.strpath])
+ monkeypatch.setenv('PYTHONPATH', os.path.pathsep.join(sys.path))
+
+ # Set up the command for performing the installation.
+ dist = Distribution()
+ cmd = easy_install(dist)
+ cmd.install_dir = install_dir.strpath
+ return cmd
+
+
+def _install_one(requirement, cmd, pkgname, modulename):
+ cmd.args = [requirement]
+ cmd.ensure_finalized()
+ cmd.run()
+ target = cmd.install_dir
+ dest_path = glob.glob(os.path.join(target, pkgname + '*.egg'))
+ assert dest_path
+ assert os.path.exists(os.path.join(dest_path[0], pkgname, modulename))
+
+
+def test_stevedore(install_context):
+ _install_one('stevedore', install_context,
+ 'stevedore', 'extension.py')
+
+
+@pytest.mark.xfail
+def test_virtualenvwrapper(install_context):
+ _install_one('virtualenvwrapper', install_context,
+ 'virtualenvwrapper', 'hook_loader.py')
+
+
+@pytest.mark.xfail
+def test_pbr(install_context):
+ _install_one('pbr', install_context,
+ 'pbr', 'core.py')
+
+
+@pytest.mark.xfail
+def test_python_novaclient(install_context):
+ _install_one('python-novaclient', install_context,
+ 'novaclient', 'base.py')
diff --git a/setuptools/version.py b/setuptools/version.py
index 94bcfb01..adcb4271 100644
--- a/setuptools/version.py
+++ b/setuptools/version.py
@@ -1 +1 @@
-__version__ = '3.7'
+__version__ = '5.3'
diff --git a/test.sh b/test.sh
deleted file mode 100644
index ed6d4efc..00000000
--- a/test.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-echo -n "Running tests for Python 2.4..."
-python2.4 setup.py -q test > /dev/null 2> /dev/null
-if [ $? -ne 0 ];then
- echo "Failed"
- exit $1
-else
- echo "Success"
-fi
-
-echo -n "Running tests for Python 2.5..."
-python2.5 setup.py -q test > /dev/null 2> /dev/null
-if [ $? -ne 0 ];then
- echo "Failed"
- exit $1
-else
- echo "Success"
-fi
-
-echo -n "Running tests for Python 2.6..."
-python2.6 setup.py -q test > /dev/null 2> /dev/null
-if [ $? -ne 0 ];then
- echo "Failed"
- exit $1
-else
- echo "Success"
-fi
-
-echo -n "Running tests for Python 2.7..."
-python2.7 setup.py -q test > /dev/null 2> /dev/null
-if [ $? -ne 0 ];then
- echo "Failed"
- exit $1
-else
- echo "Success"
-fi
-
-rm -rf build
-echo -n "Running tests for Python 3.1..."
-python3.1 setup.py -q test > /dev/null 2> /dev/null
-if [ $? -ne 0 ];then
- echo "Failed"
- exit $1
-else
- echo "Success"
-fi
-
-rm -rf build
-echo -n "Running tests for Python 3.2..."
-python3.2 setup.py -q test > /dev/null 2> /dev/null
-if [ $? -ne 0 ];then
- echo "Failed"
- exit $1
-else
- echo "Success"
-fi
-
-rm -rf build
-echo -n "Running tests for Python 3.3..."
-python3.3 setup.py -q test > /dev/null 2> /dev/null
-if [ $? -ne 0 ];then
- echo "Failed"
- exit $1
-else
- echo "Success"
-fi
-
diff --git a/tests/api_tests.txt b/tests/api_tests.txt
index d34f2314..65dba76d 100644
--- a/tests/api_tests.txt
+++ b/tests/api_tests.txt
@@ -418,7 +418,3 @@ Environment Markers
>>> em("'yx' in 'x'")
False
-
-
-
-
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 00000000..06421a73
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,5 @@
+[tox]
+envlist = py26,py27,py31,py32,py33,py34
+[testenv]
+deps=pytest
+commands=py.test