summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.hgtags6
-rw-r--r--.travis.yml4
-rw-r--r--CHANGES.txt56
-rw-r--r--CONTRIBUTORS.txt36
-rwxr-xr-xREADME.txt12
-rw-r--r--docs/setuptools.txt17
-rw-r--r--ez_setup.py30
-rwxr-xr-xsetup.py10
-rw-r--r--setuptools.egg-info/dependency_links.txt4
-rw-r--r--setuptools.egg-info/entry_points.txt124
-rw-r--r--setuptools.egg-info/requires.txt8
-rw-r--r--setuptools/__init__.py11
-rwxr-xr-xsetuptools/command/bdist_wininst.py74
-rwxr-xr-xsetuptools/command/easy_install.py2
-rw-r--r--setuptools/command/install.py1
-rwxr-xr-xsetuptools/command/install_egg_info.py2
-rw-r--r--setuptools/command/install_lib.py13
-rwxr-xr-xsetuptools/command/install_scripts.py1
-rw-r--r--setuptools/dist.py259
-rw-r--r--setuptools/extension.py27
-rw-r--r--setuptools/py31compat.py26
-rw-r--r--setuptools/svn_utils.py35
-rw-r--r--setuptools/tests/__init__.py84
-rw-r--r--setuptools/tests/test_bdist_egg.py7
-rw-r--r--setuptools/tests/test_build_ext.py3
-rw-r--r--setuptools/tests/test_develop.py6
-rw-r--r--setuptools/tests/test_easy_install.py5
-rw-r--r--setuptools/tests/test_find_packages.py38
-rw-r--r--setuptools/tests/test_test.py6
-rw-r--r--setuptools/version.py2
30 files changed, 641 insertions, 268 deletions
diff --git a/.hgtags b/.hgtags
index ac040628..b5abdc07 100644
--- a/.hgtags
+++ b/.hgtags
@@ -119,3 +119,9 @@ ab1c2a26e06f2a2006e8e867e4d41ccf1d6cf9b2 2.2b1
caab085e829f29679d0e47430b2761af6b20fc76 2.1.2
39f7ef5ef22183f3eba9e05a46068e1d9fd877b0 2.2
faba785e9b9e05ba890d0851ef1f3287c32fcac2 3.0b1
+8e8c50925f18eafb7e66fe020aa91a85b9a4b122 3.0
+cd9e857476ac70515f7436f846b593f696ac672d 3.0.1
+bad1f30ee0dfa7a2af4f428d06f62efa39ca48db 3.0.2
+47224d55ddc6bb08c1d17a219f124d0d9c524491 3.1
+07c459bea1c58ff52e0576fc29c1865d18a83b09 3.2
+b306e681a945406833fb297ae10241e2241fc22b 3.3
diff --git a/.travis.yml b/.travis.yml
index e13a5d4f..bf0aeba6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,4 +6,6 @@ python:
- 3.3
- pypy
# command to run tests
-script: python setup.py test
+script:
+ - python setup.py test
+ - python ez_setup.py --version 3.0.2
diff --git a/CHANGES.txt b/CHANGES.txt
index 9ec8c092..7a9ed446 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,9 +3,54 @@ CHANGES
=======
---
+4.0
+---
+
+* Issue #97: ``find_packages()`` now supports PEP 420 namespace packages. It
+ does so by considering all subdirectories of the start directory that
+ aren't regular packages to be PEP 420 namespace packages (on Python 3.3+
+ only).
+
+---
+3.3
+---
+
+* Add ``include`` parameter to ``setuptools.find_packages()``.
+
+---
+3.2
+---
+
+* Pull Request #39: Add support for C++ targets from Cython ``.pyx`` files.
+* Issue #162: Update dependency on certifi to 1.0.1.
+* Issue #164: Update dependency on wincertstore to 0.2.
+
+---
+3.1
+---
+
+* Issue #161: Restore Features functionality to allow backward compatibility
+ (for Features) until the uses of that functionality is sufficiently removed.
+
+-----
+3.0.2
+-----
+
+* Correct typo in previous bugfix.
+
+-----
+3.0.1
+-----
+
+* Issue #157: Restore support for Python 2.6 in bootstrap script where
+ ``zipfile.ZipFile`` does not yet have support for context managers.
+
+---
3.0
---
+* Issue #125: Prevent Subversion support from creating a ~/.subversion
+ directory just for checking the presence of a Subversion repository.
* Issue #12: Namespace packages are now imported lazily. That is, the mere
declaration of a namespace package in an egg on ``sys.path`` no longer
causes it to be imported when ``pkg_resources`` is imported. Note that this
@@ -23,19 +68,10 @@ CHANGES
security vulnerabilities presented by use of tar archives in ez_setup.py.
It also leverages the security features added to ZipFile.extract in Python 2.7.4.
* Issue #65: Removed deprecated Features functionality.
-* Issue #97: ``find_packages()`` now supports PEP 420 namespace packages. It
- does so by considering all subdirectories of the start directory that
- aren't regular packages to be PEP 420 namespace packages (on Python 3.3+
- only). Also, a list of packages to include can be now be specified; this
- provides an easy way to narrow the list of candidate directories.
-
----
-2.3
----
-
* Pull Request #28: Remove backport of ``_bytecode_filenames`` which is
available in Python 2.6 and later, but also has better compatibility with
Python 3 environments.
+* Issue #156: Fix spelling of __PYVENV_LAUNCHER__ variable.
---
2.2
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
deleted file mode 100644
index dd0b8c7f..00000000
--- a/CONTRIBUTORS.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-============
-Contributors
-============
-
-* Alex Grönholm
-* Alice Bevan-McGregor
-* Arfrever Frehtes Taifersar Arahesis
-* Christophe Combelles
-* Daniel Stutzbach
-* Daniel Holth
-* Dirley Rodrigues
-* Donald Stufft
-* Grigory Petrov
-* Hanno Schlichting
-* Jannis Leidel
-* Jason R. Coombs
-* Jim Fulton
-* Jonathan Lange
-* Justin Azoff
-* Lennart Regebro
-* Marc Abramowitz
-* Martin von Löwis
-* Noufal Ibrahim
-* Pedro Algarvio
-* Pete Hollobon
-* Phillip J. Eby
-* Philip Jenvey
-* Philip Thiem
-* Reinout van Rees
-* Robert Myers
-* Stefan H. Holek
-* Tarek Ziadé
-* Toshio Kuratomi
-
-If you think you name is missing, please add it (alpha order by first name)
-
diff --git a/README.txt b/README.txt
index 4871735d..a6f6acba 100755
--- a/README.txt
+++ b/README.txt
@@ -12,12 +12,15 @@ Installation Instructions
The recommended way to bootstrap setuptools on any system is to download
`ez_setup.py`_ and run it using the target Python environment. Different
operating systems have different recommended techniques to accomplish this
-basic routine, so here are some examples to get you started.
+basic routine, so below are some examples to get you started.
Setuptools requires Python 2.6 or later. To install setuptools
on Python 2.4 or Python 2.5, use the `bootstrap script for Setuptools 1.x
<https://bitbucket.org/pypa/setuptools/raw/bootstrap-py24/ez_setup.py>`_.
+The link provided to ez_setup.py is a bookmark to bootstrap script for the
+latest known stable release.
+
.. _ez_setup.py: https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
Windows 8 (Powershell)
@@ -74,8 +77,7 @@ install to the system Python::
> wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | sudo python
-Alternatively, on Python 2.6 and later, Setuptools may be installed to a
-user-local path::
+Alternatively, Setuptools may be installed to a user-local path::
> wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python - --user
@@ -83,7 +85,9 @@ Unix including Mac OS X (curl)
==============================
If your system has curl installed, follow the ``wget`` instructions but
-replace ``wget`` with ``curl`` and ``-O`` with ``-o``.
+replace ``wget`` with ``curl`` and ``-O`` with ``-o``. For example::
+
+ > curl https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -o - | python
Advanced Installation
diff --git a/docs/setuptools.txt b/docs/setuptools.txt
index d277dcb5..68467dc1 100644
--- a/docs/setuptools.txt
+++ b/docs/setuptools.txt
@@ -416,19 +416,22 @@ the ``packages`` argument of ``setup()``. However, for very large projects
(Twisted, PEAK, Zope, Chandler, etc.), it can be a big burden to keep the
package list updated. That's what ``setuptools.find_packages()`` is for.
-``find_packages()`` takes a source directory, and a list of package names or
-patterns to exclude. If omitted, the source directory defaults to the same
+``find_packages()`` takes a source directory and two lists of package name
+patterns to exclude and include. If omitted, the source directory defaults to
+the same
directory as the setup script. Some projects use a ``src`` or ``lib``
directory as the root of their source tree, and those projects would of course
use ``"src"`` or ``"lib"`` as the first argument to ``find_packages()``. (And
such projects also need something like ``package_dir = {'':'src'}`` in their
``setup()`` arguments, but that's just a normal distutils thing.)
-Anyway, ``find_packages()`` walks the target directory, and finds Python
-packages by looking for ``__init__.py`` files. It then filters the list of
-packages using the exclusion patterns.
+Anyway, ``find_packages()`` walks the target directory, filtering by inclusion
+patterns, and finds Python packages (any directory). On Python 3.2 and
+earlier, packages are only recognized if they include an ``__init__.py`` file.
+Finally, exclusion patterns are applied to remove matching packages.
-Exclusion patterns are package names, optionally including wildcards. For
+Inclusion and exclusion patterns are package names, optionally including
+wildcards. For
example, ``find_packages(exclude=["*.tests"])`` will exclude all packages whose
last name part is ``tests``. Or, ``find_packages(exclude=["*.tests",
"*.tests.*"])`` will also exclude any subpackages of packages named ``tests``,
@@ -442,7 +445,7 @@ in order to cover all the bases. Really, the exclusion patterns are intended
to cover simpler use cases than this, like excluding a single, specified
package and its subpackages.
-Regardless of the target directory or exclusions, the ``find_packages()``
+Regardless of the parameters, the ``find_packages()``
function returns a list of package names suitable for use as the ``packages``
argument to ``setup()``, and so is usually the easiest way to set that
argument in your setup script. Especially since it frees you from having to
diff --git a/ez_setup.py b/ez_setup.py
index e4a357eb..0b598312 100644
--- a/ez_setup.py
+++ b/ez_setup.py
@@ -31,7 +31,7 @@ try:
except ImportError:
USER_SITE = None
-DEFAULT_VERSION = "3.0"
+DEFAULT_VERSION = "4.0"
DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
def _python_cmd(*args):
@@ -64,6 +64,19 @@ def _build_egg(egg, archive_filename, to_dir):
raise IOError('Could not build the egg.')
+def get_zip_class():
+ """
+ Supplement ZipFile class to support context manager for Python 2.6
+ """
+ class ContextualZipFile(zipfile.ZipFile):
+ def __enter__(self):
+ return self
+ def __exit__(self, type, value, traceback):
+ self.close
+ return zipfile.ZipFile if hasattr(zipfile.ZipFile, '__exit__') else \
+ ContextualZipFile
+
+
@contextlib.contextmanager
def archive_context(filename):
# extracting the archive
@@ -72,7 +85,7 @@ def archive_context(filename):
old_wd = os.getcwd()
try:
os.chdir(tmpdir)
- with zipfile.ZipFile(filename) as archive:
+ with get_zip_class()(filename) as archive:
archive.extractall()
# going in the directory
@@ -297,15 +310,22 @@ def _parse_args():
const=lambda: download_file_insecure, default=get_best_downloader,
help='Use internal, non-validating downloader'
)
+ parser.add_option(
+ '--version', help="Specify which version to download",
+ default=DEFAULT_VERSION,
+ )
options, args = parser.parse_args()
# positional arguments are ignored
return options
-def main(version=DEFAULT_VERSION):
+def main():
"""Install or upgrade setuptools and EasyInstall"""
options = _parse_args()
- archive = download_setuptools(download_base=options.download_base,
- downloader_factory=options.downloader_factory)
+ archive = download_setuptools(
+ version=options.version,
+ download_base=options.download_base,
+ downloader_factory=options.downloader_factory,
+ )
return _install(archive, _build_install_args(options))
if __name__ == '__main__':
diff --git a/setup.py b/setup.py
index 5d19cd96..3d5307d5 100755
--- a/setup.py
+++ b/setup.py
@@ -121,7 +121,7 @@ setup_params = dict(
py_modules = ['pkg_resources', 'easy_install'],
- zip_safe = (sys.version>="2.5"), # <2.5 needs unzipped for -m to work
+ zip_safe = True,
cmdclass = {'test': test},
entry_points = {
@@ -188,12 +188,12 @@ setup_params = dict(
Topic :: Utilities
""").strip().splitlines(),
extras_require = {
- "ssl:sys_platform=='win32'": "wincertstore==0.1",
- "certs": "certifi==0.0.8",
+ "ssl:sys_platform=='win32'": "wincertstore==0.2",
+ "certs": "certifi==1.0.1",
},
dependency_links = [
- 'https://pypi.python.org/packages/source/c/certifi/certifi-0.0.8.tar.gz#md5=dc5f5e7f0b5fc08d27654b17daa6ecec',
- 'https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.1.zip#md5=2f9accbebe8f7b4c06ac7aa83879b81c',
+ 'https://pypi.python.org/packages/source/c/certifi/certifi-1.0.1.tar.gz#md5=45f5cb94b8af9e1df0f9450a8f61b790',
+ 'https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2',
],
scripts = [],
# tests_require = "setuptools[ssl]",
diff --git a/setuptools.egg-info/dependency_links.txt b/setuptools.egg-info/dependency_links.txt
index b1c9a2c9..b454c168 100644
--- a/setuptools.egg-info/dependency_links.txt
+++ b/setuptools.egg-info/dependency_links.txt
@@ -1,2 +1,2 @@
-https://pypi.python.org/packages/source/c/certifi/certifi-0.0.8.tar.gz#md5=dc5f5e7f0b5fc08d27654b17daa6ecec
-https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.1.zip#md5=2f9accbebe8f7b4c06ac7aa83879b81c
+https://pypi.python.org/packages/source/c/certifi/certifi-1.0.1.tar.gz#md5=45f5cb94b8af9e1df0f9450a8f61b790
+https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2
diff --git a/setuptools.egg-info/entry_points.txt b/setuptools.egg-info/entry_points.txt
index 5e417433..560a7041 100644
--- a/setuptools.egg-info/entry_points.txt
+++ b/setuptools.egg-info/entry_points.txt
@@ -1,62 +1,62 @@
-[egg_info.writers]
-top_level.txt = setuptools.command.egg_info:write_toplevel_names
-depends.txt = setuptools.command.egg_info:warn_depends_obsolete
-PKG-INFO = setuptools.command.egg_info:write_pkg_info
-requires.txt = setuptools.command.egg_info:write_requirements
-entry_points.txt = setuptools.command.egg_info:write_entries
-namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
-dependency_links.txt = setuptools.command.egg_info:overwrite_arg
-eager_resources.txt = setuptools.command.egg_info:overwrite_arg
-
-[distutils.commands]
-install = setuptools.command.install:install
-develop = setuptools.command.develop:develop
-bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
-build_ext = setuptools.command.build_ext:build_ext
-install_scripts = setuptools.command.install_scripts:install_scripts
-rotate = setuptools.command.rotate:rotate
-saveopts = setuptools.command.saveopts:saveopts
-alias = setuptools.command.alias:alias
-bdist_egg = setuptools.command.bdist_egg:bdist_egg
-easy_install = setuptools.command.easy_install:easy_install
-install_egg_info = setuptools.command.install_egg_info:install_egg_info
-install_lib = setuptools.command.install_lib:install_lib
-egg_info = setuptools.command.egg_info:egg_info
-sdist = setuptools.command.sdist:sdist
-build_py = setuptools.command.build_py:build_py
-upload_docs = setuptools.command.upload_docs:upload_docs
-register = setuptools.command.register:register
-bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
-test = setuptools.command.test:test
-setopt = setuptools.command.setopt:setopt
-
-[distutils.setup_keywords]
-namespace_packages = setuptools.dist:check_nsp
-zip_safe = setuptools.dist:assert_bool
-use_2to3 = setuptools.dist:assert_bool
-test_suite = setuptools.dist:check_test_suite
-eager_resources = setuptools.dist:assert_string_list
-dependency_links = setuptools.dist:assert_string_list
-test_loader = setuptools.dist:check_importable
-extras_require = setuptools.dist:check_extras
-convert_2to3_doctests = setuptools.dist:assert_string_list
-install_requires = setuptools.dist:check_requirements
-tests_require = setuptools.dist:check_requirements
-use_2to3_fixers = setuptools.dist:assert_string_list
-entry_points = setuptools.dist:check_entry_points
-package_data = setuptools.dist:check_package_data
-include_package_data = setuptools.dist:assert_bool
-use_2to3_exclude_fixers = setuptools.dist:assert_string_list
-packages = setuptools.dist:check_packages
-exclude_package_data = setuptools.dist:check_package_data
-
-[setuptools.installation]
-eggsecutable = setuptools.command.easy_install:bootstrap
-
-[setuptools.file_finders]
-svn_cvs = setuptools.command.sdist:_default_revctrl
-
-[console_scripts]
-easy_install = setuptools.command.easy_install:main
-easy_install-3.4 = setuptools.command.easy_install:main
-
+[setuptools.installation]
+eggsecutable = setuptools.command.easy_install:bootstrap
+
+[egg_info.writers]
+entry_points.txt = setuptools.command.egg_info:write_entries
+dependency_links.txt = setuptools.command.egg_info:overwrite_arg
+eager_resources.txt = setuptools.command.egg_info:overwrite_arg
+top_level.txt = setuptools.command.egg_info:write_toplevel_names
+namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
+depends.txt = setuptools.command.egg_info:warn_depends_obsolete
+requires.txt = setuptools.command.egg_info:write_requirements
+PKG-INFO = setuptools.command.egg_info:write_pkg_info
+
+[setuptools.file_finders]
+svn_cvs = setuptools.command.sdist:_default_revctrl
+
+[console_scripts]
+easy_install-3.4 = setuptools.command.easy_install:main
+easy_install = setuptools.command.easy_install:main
+
+[distutils.setup_keywords]
+use_2to3_fixers = setuptools.dist:assert_string_list
+dependency_links = setuptools.dist:assert_string_list
+packages = setuptools.dist:check_packages
+use_2to3_exclude_fixers = setuptools.dist:assert_string_list
+convert_2to3_doctests = setuptools.dist:assert_string_list
+use_2to3 = setuptools.dist:assert_bool
+exclude_package_data = setuptools.dist:check_package_data
+entry_points = setuptools.dist:check_entry_points
+test_loader = setuptools.dist:check_importable
+namespace_packages = setuptools.dist:check_nsp
+zip_safe = setuptools.dist:assert_bool
+extras_require = setuptools.dist:check_extras
+eager_resources = setuptools.dist:assert_string_list
+tests_require = setuptools.dist:check_requirements
+package_data = setuptools.dist:check_package_data
+test_suite = setuptools.dist:check_test_suite
+include_package_data = setuptools.dist:assert_bool
+install_requires = setuptools.dist:check_requirements
+
+[distutils.commands]
+upload_docs = setuptools.command.upload_docs:upload_docs
+egg_info = setuptools.command.egg_info:egg_info
+install_scripts = setuptools.command.install_scripts:install_scripts
+saveopts = setuptools.command.saveopts:saveopts
+bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
+rotate = setuptools.command.rotate:rotate
+install = setuptools.command.install:install
+bdist_egg = setuptools.command.bdist_egg:bdist_egg
+test = setuptools.command.test:test
+install_egg_info = setuptools.command.install_egg_info:install_egg_info
+install_lib = setuptools.command.install_lib:install_lib
+sdist = setuptools.command.sdist:sdist
+register = setuptools.command.register:register
+develop = setuptools.command.develop:develop
+build_py = setuptools.command.build_py:build_py
+setopt = setuptools.command.setopt:setopt
+build_ext = setuptools.command.build_ext:build_ext
+alias = setuptools.command.alias:alias
+easy_install = setuptools.command.easy_install:easy_install
+bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
+
diff --git a/setuptools.egg-info/requires.txt b/setuptools.egg-info/requires.txt
index 4fd464d8..a49a923e 100644
--- a/setuptools.egg-info/requires.txt
+++ b/setuptools.egg-info/requires.txt
@@ -1,7 +1,7 @@
-[ssl:sys_platform=='win32']
-wincertstore==0.1
-
[certs]
-certifi==0.0.8 \ No newline at end of file
+certifi==1.0.1
+
+[ssl:sys_platform=='win32']
+wincertstore==0.2 \ No newline at end of file
diff --git a/setuptools/__init__.py b/setuptools/__init__.py
index 6d7b4f38..86afab63 100644
--- a/setuptools/__init__.py
+++ b/setuptools/__init__.py
@@ -6,14 +6,15 @@ import distutils.core
import distutils.filelist
from distutils.core import Command as _Command
from distutils.util import convert_path
+from fnmatch import fnmatchcase
import setuptools.version
from setuptools.extension import Extension
-from setuptools.dist import Distribution, _get_unpatched
+from setuptools.dist import Distribution, Feature, _get_unpatched
from setuptools.depends import Require
__all__ = [
- 'setup', 'Distribution', 'Command', 'Extension', 'Require',
+ 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
'find_packages'
]
@@ -43,13 +44,11 @@ def find_packages(where='.', exclude=(), include=()):
The list of included packages is built up first and then any explicitly
excluded packages are removed from it.
-
"""
- from fnmatch import fnmatchcase
- include = list(include)
- exclude = list(exclude) + ['ez_setup', '*__pycache__']
out = []
stack=[(convert_path(where), '')]
+ include = list(include)
+ exclude = list(exclude) + ['ez_setup', '*__pycache__']
while stack:
where,prefix = stack.pop(0)
for name in os.listdir(where):
diff --git a/setuptools/command/bdist_wininst.py b/setuptools/command/bdist_wininst.py
index e8521f83..d4d195a0 100755
--- a/setuptools/command/bdist_wininst.py
+++ b/setuptools/command/bdist_wininst.py
@@ -1,82 +1,20 @@
from distutils.command.bdist_wininst import bdist_wininst as _bdist_wininst
-import os, sys
class bdist_wininst(_bdist_wininst):
- _good_upload = _bad_upload = None
-
- def create_exe(self, arcname, fullname, bitmap=None):
- _bdist_wininst.create_exe(self, arcname, fullname, bitmap)
- installer_name = self.get_installer_filename(fullname)
- if self.target_version:
- pyversion = self.target_version
- # fix 2.5+ bdist_wininst ignoring --target-version spec
- self._bad_upload = ('bdist_wininst', 'any', installer_name)
- else:
- pyversion = 'any'
- self._good_upload = ('bdist_wininst', pyversion, installer_name)
-
- def _fix_upload_names(self):
- good, bad = self._good_upload, self._bad_upload
- dist_files = getattr(self.distribution, 'dist_files', [])
- if bad in dist_files:
- dist_files.remove(bad)
- if good not in dist_files:
- dist_files.append(good)
-
- def reinitialize_command (self, command, reinit_subcommands=0):
+ def reinitialize_command(self, command, reinit_subcommands=0):
+ """
+ Supplement reinitialize_command to work around
+ http://bugs.python.org/issue20819
+ """
cmd = self.distribution.reinitialize_command(
command, reinit_subcommands)
if command in ('install', 'install_lib'):
- cmd.install_lib = None # work around distutils bug
+ cmd.install_lib = None
return cmd
def run(self):
self._is_running = True
try:
_bdist_wininst.run(self)
- self._fix_upload_names()
finally:
self._is_running = False
-
-
- if not hasattr(_bdist_wininst, 'get_installer_filename'):
- def get_installer_filename(self, fullname):
- # Factored out to allow overriding in subclasses
- if self.target_version:
- # if we create an installer for a specific python version,
- # it's better to include this in the name
- installer_name = os.path.join(self.dist_dir,
- "%s.win32-py%s.exe" %
- (fullname, self.target_version))
- else:
- installer_name = os.path.join(self.dist_dir,
- "%s.win32.exe" % fullname)
- return installer_name
- # get_installer_filename()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index 8e39ee80..4f497c3b 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -53,7 +53,7 @@ from pkg_resources import (
VersionConflict, DEVELOP_DIST,
)
-sys_executable = os.environ.get('__VENV_LAUNCHER__',
+sys_executable = os.environ.get('__PYVENV_LAUNCHER__',
os.path.normpath(sys.executable))
__all__ = [
diff --git a/setuptools/command/install.py b/setuptools/command/install.py
index 459cd3cd..784e8efd 100644
--- a/setuptools/command/install.py
+++ b/setuptools/command/install.py
@@ -25,7 +25,6 @@ class install(_install):
_install.initialize_options(self)
self.old_and_unmanageable = None
self.single_version_externally_managed = None
- self.no_compile = None # make DISTUTILS_DEBUG work right!
def finalize_options(self):
_install.finalize_options(self)
diff --git a/setuptools/command/install_egg_info.py b/setuptools/command/install_egg_info.py
index f44b34b5..73b5ef73 100755
--- a/setuptools/command/install_egg_info.py
+++ b/setuptools/command/install_egg_info.py
@@ -1,7 +1,7 @@
from setuptools import Command
from setuptools.archive_util import unpack_archive
from distutils import log, dir_util
-import os, shutil, pkg_resources
+import os, pkg_resources
class install_egg_info(Command):
"""Install an .egg-info directory for the package"""
diff --git a/setuptools/command/install_lib.py b/setuptools/command/install_lib.py
index c508cd33..63dc11fe 100644
--- a/setuptools/command/install_lib.py
+++ b/setuptools/command/install_lib.py
@@ -14,10 +14,9 @@ class install_lib(_install_lib):
def get_exclusions(self):
exclude = {}
nsp = self.distribution.namespace_packages
-
- if (nsp and self.get_finalized_command('install')
- .single_version_externally_managed
- ):
+ svem = (nsp and self.get_finalized_command('install')
+ .single_version_externally_managed)
+ if svem:
for pkg in nsp:
parts = pkg.split('.')
while parts:
@@ -62,9 +61,3 @@ class install_lib(_install_lib):
if exclude:
return [f for f in outputs if f not in exclude]
return outputs
-
-
-
-
-
-
diff --git a/setuptools/command/install_scripts.py b/setuptools/command/install_scripts.py
index 105dabca..1c6cc51d 100755
--- a/setuptools/command/install_scripts.py
+++ b/setuptools/command/install_scripts.py
@@ -51,4 +51,3 @@ class install_scripts(_install_scripts):
f.write(contents)
f.close()
chmod(target, 0x1FF-mask) # 0777
-
diff --git a/setuptools/dist.py b/setuptools/dist.py
index dcb9ba4e..0801ae74 100644
--- a/setuptools/dist.py
+++ b/setuptools/dist.py
@@ -3,12 +3,15 @@ __all__ = ['Distribution']
import re
import os
import sys
+import warnings
import distutils.log
import distutils.core
import distutils.cmd
from distutils.core import Distribution as _Distribution
-from distutils.errors import DistutilsSetupError
+from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,
+ DistutilsSetupError)
+from setuptools.depends import Require
from setuptools.compat import numeric_types, basestring
import pkg_resources
@@ -134,7 +137,7 @@ def check_packages(dist, attr, value):
class Distribution(_Distribution):
- """Distribution with support for tests and package data
+ """Distribution with support for features, tests, and package data
This is an enhanced version of 'distutils.dist.Distribution' that
effectively adds the following new optional keyword arguments to 'setup()':
@@ -161,6 +164,21 @@ class Distribution(_Distribution):
EasyInstall and requests one of your extras, the corresponding
additional requirements will be installed if needed.
+ 'features' **deprecated** -- a dictionary mapping option names to
+ 'setuptools.Feature'
+ objects. Features are a portion of the distribution that can be
+ included or excluded based on user options, inter-feature dependencies,
+ and availability on the current system. Excluded features are omitted
+ from all setup commands, including source and binary distributions, so
+ you can create multiple distributions from the same source tree.
+ Feature names should be valid Python identifiers, except that they may
+ contain the '-' (minus) sign. Features can be included or excluded
+ via the command line options '--with-X' and '--without-X', where 'X' is
+ the name of the feature. Whether a feature is included by default, and
+ whether you are allowed to control this from the command line, is
+ determined by the Feature object. See the 'Feature' class for more
+ information.
+
'test_suite' -- the name of a test suite to run for the 'test' command.
If the user runs 'python setup.py test', the package will be installed,
and the named test suite will be run. The format is the same as
@@ -182,7 +200,8 @@ class Distribution(_Distribution):
for manipulating the distribution's contents. For example, the 'include()'
and 'exclude()' methods can be thought of as in-place add and subtract
commands that add or remove packages, modules, extensions, and so on from
- the distribution.
+ the distribution. They are used by the feature subsystem to configure the
+ distribution for the included and excluded features.
"""
_patched_dist = None
@@ -204,6 +223,11 @@ class Distribution(_Distribution):
have_package_data = hasattr(self, "package_data")
if not have_package_data:
self.package_data = {}
+ _attrs_dict = attrs or {}
+ if 'features' in _attrs_dict or 'require_features' in _attrs_dict:
+ Feature.warn_deprecated()
+ self.require_features = []
+ self.features = {}
self.dist_files = []
self.src_root = attrs and attrs.pop("src_root", None)
self.patch_missing_pkg_info(attrs)
@@ -221,6 +245,17 @@ class Distribution(_Distribution):
# Some people apparently take "version number" too literally :)
self.metadata.version = str(self.metadata.version)
+ def parse_command_line(self):
+ """Process features after parsing command line options"""
+ result = _Distribution.parse_command_line(self)
+ if self.features:
+ self._finalize_features()
+ return result
+
+ def _feature_attrname(self,name):
+ """Convert feature name to corresponding option attribute name"""
+ return 'with_'+name.replace('-','_')
+
def fetch_build_eggs(self, requires):
"""Resolve pre-setup requirements"""
from pkg_resources import working_set, parse_requirements
@@ -232,6 +267,8 @@ class Distribution(_Distribution):
def finalize_options(self):
_Distribution.finalize_options(self)
+ if self.features:
+ self._set_global_opts_from_features()
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
value = getattr(self,ep.name,None)
@@ -276,6 +313,47 @@ class Distribution(_Distribution):
self._egg_fetcher = cmd
return cmd.easy_install(req)
+ def _set_global_opts_from_features(self):
+ """Add --with-X/--without-X options based on optional features"""
+
+ go = []
+ no = self.negative_opt.copy()
+
+ for name,feature in self.features.items():
+ self._set_feature(name,None)
+ feature.validate(self)
+
+ if feature.optional:
+ descr = feature.description
+ incdef = ' (default)'
+ excdef=''
+ if not feature.include_by_default():
+ excdef, incdef = incdef, excdef
+
+ go.append(('with-'+name, None, 'include '+descr+incdef))
+ go.append(('without-'+name, None, 'exclude '+descr+excdef))
+ no['without-'+name] = 'with-'+name
+
+ self.global_options = self.feature_options = go + self.global_options
+ self.negative_opt = self.feature_negopt = no
+
+ def _finalize_features(self):
+ """Add/remove features and resolve dependencies between them"""
+
+ # First, flag all the enabled items (and thus their dependencies)
+ for name,feature in self.features.items():
+ enabled = self.feature_is_included(name)
+ if enabled or (enabled is None and feature.include_by_default()):
+ feature.include_in(self)
+ self._set_feature(name,1)
+
+ # Then disable the rest, so that off-by-default features don't
+ # get flagged as errors when they're required by an enabled feature
+ for name,feature in self.features.items():
+ if not self.feature_is_included(name):
+ feature.exclude_from(self)
+ self._set_feature(name,0)
+
def get_command_class(self, command):
"""Pluggable version of get_command_class()"""
if command in self.cmdclass:
@@ -295,6 +373,25 @@ class Distribution(_Distribution):
self.cmdclass[ep.name] = cmdclass
return _Distribution.print_commands(self)
+ def _set_feature(self,name,status):
+ """Set feature's inclusion status"""
+ setattr(self,self._feature_attrname(name),status)
+
+ def feature_is_included(self,name):
+ """Return 1 if feature is included, 0 if excluded, 'None' if unknown"""
+ return getattr(self,self._feature_attrname(name))
+
+ def include_feature(self,name):
+ """Request inclusion of feature named 'name'"""
+
+ if self.feature_is_included(name)==0:
+ descr = self.features[name].description
+ raise DistutilsOptionError(
+ descr + " is required, but was excluded or is not available"
+ )
+ self.features[name].include_in(self)
+ self._set_feature(name,1)
+
def include(self,**attrs):
"""Add items to distribution that are named in keyword arguments
@@ -542,3 +639,159 @@ class Distribution(_Distribution):
# Install it throughout the distutils
for module in distutils.dist, distutils.core, distutils.cmd:
module.Distribution = Distribution
+
+
+class Feature:
+ """
+ **deprecated** -- The `Feature` facility was never completely implemented
+ or supported, `has reported issues
+ <https://bitbucket.org/pypa/setuptools/issue/58>`_ and will be removed in
+ a future version.
+
+ A subset of the distribution that can be excluded if unneeded/wanted
+
+ Features are created using these keyword arguments:
+
+ 'description' -- a short, human readable description of the feature, to
+ be used in error messages, and option help messages.
+
+ 'standard' -- if true, the feature is included by default if it is
+ available on the current system. Otherwise, the feature is only
+ included if requested via a command line '--with-X' option, or if
+ another included feature requires it. The default setting is 'False'.
+
+ 'available' -- if true, the feature is available for installation on the
+ current system. The default setting is 'True'.
+
+ 'optional' -- if true, the feature's inclusion can be controlled from the
+ command line, using the '--with-X' or '--without-X' options. If
+ false, the feature's inclusion status is determined automatically,
+ based on 'availabile', 'standard', and whether any other feature
+ requires it. The default setting is 'True'.
+
+ 'require_features' -- a string or sequence of strings naming features
+ that should also be included if this feature is included. Defaults to
+ empty list. May also contain 'Require' objects that should be
+ added/removed from the distribution.
+
+ 'remove' -- a string or list of strings naming packages to be removed
+ from the distribution if this feature is *not* included. If the
+ feature *is* included, this argument is ignored. This argument exists
+ to support removing features that "crosscut" a distribution, such as
+ defining a 'tests' feature that removes all the 'tests' subpackages
+ provided by other features. The default for this argument is an empty
+ list. (Note: the named package(s) or modules must exist in the base
+ distribution when the 'setup()' function is initially called.)
+
+ other keywords -- any other keyword arguments are saved, and passed to
+ the distribution's 'include()' and 'exclude()' methods when the
+ feature is included or excluded, respectively. So, for example, you
+ could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be
+ added or removed from the distribution as appropriate.
+
+ A feature must include at least one 'requires', 'remove', or other
+ keyword argument. Otherwise, it can't affect the distribution in any way.
+ Note also that you can subclass 'Feature' to create your own specialized
+ feature types that modify the distribution in other ways when included or
+ excluded. See the docstrings for the various methods here for more detail.
+ Aside from the methods, the only feature attributes that distributions look
+ at are 'description' and 'optional'.
+ """
+
+ @staticmethod
+ def warn_deprecated():
+ warnings.warn(
+ "Features are deprecated and will be removed in a future "
+ "version. See http://bitbucket.org/pypa/setuptools/65.",
+ DeprecationWarning,
+ stacklevel=3,
+ )
+
+ def __init__(self, description, standard=False, available=True,
+ optional=True, require_features=(), remove=(), **extras):
+ self.warn_deprecated()
+
+ self.description = description
+ self.standard = standard
+ self.available = available
+ self.optional = optional
+ if isinstance(require_features,(str,Require)):
+ require_features = require_features,
+
+ self.require_features = [
+ r for r in require_features if isinstance(r,str)
+ ]
+ er = [r for r in require_features if not isinstance(r,str)]
+ if er: extras['require_features'] = er
+
+ if isinstance(remove,str):
+ remove = remove,
+ self.remove = remove
+ self.extras = extras
+
+ if not remove and not require_features and not extras:
+ raise DistutilsSetupError(
+ "Feature %s: must define 'require_features', 'remove', or at least one"
+ " of 'packages', 'py_modules', etc."
+ )
+
+ def include_by_default(self):
+ """Should this feature be included by default?"""
+ return self.available and self.standard
+
+ def include_in(self,dist):
+
+ """Ensure feature and its requirements are included in distribution
+
+ You may override this in a subclass to perform additional operations on
+ the distribution. Note that this method may be called more than once
+ per feature, and so should be idempotent.
+
+ """
+
+ if not self.available:
+ raise DistutilsPlatformError(
+ self.description+" is required,"
+ "but is not available on this platform"
+ )
+
+ dist.include(**self.extras)
+
+ for f in self.require_features:
+ dist.include_feature(f)
+
+ def exclude_from(self,dist):
+
+ """Ensure feature is excluded from distribution
+
+ You may override this in a subclass to perform additional operations on
+ the distribution. This method will be called at most once per
+ feature, and only after all included features have been asked to
+ include themselves.
+ """
+
+ dist.exclude(**self.extras)
+
+ if self.remove:
+ for item in self.remove:
+ dist.exclude_package(item)
+
+ def validate(self,dist):
+
+ """Verify that feature makes sense in context of distribution
+
+ This method is called by the distribution just before it parses its
+ command line. It checks to ensure that the 'remove' attribute, if any,
+ contains only valid package/module names that are present in the base
+ distribution when 'setup()' is called. You may override it in a
+ subclass to perform any other required validation of the feature
+ against a target distribution.
+ """
+
+ for item in self.remove:
+ if not dist.has_contents_for(item):
+ raise DistutilsSetupError(
+ "%s wants to be able to remove %s, but the distribution"
+ " doesn't contain any packages or modules under %s"
+ % (self.description, item, item)
+ )
diff --git a/setuptools/extension.py b/setuptools/extension.py
index d7892d3d..ab5908da 100644
--- a/setuptools/extension.py
+++ b/setuptools/extension.py
@@ -1,4 +1,6 @@
import sys
+import re
+import functools
import distutils.core
import distutils.extension
@@ -26,16 +28,21 @@ class Extension(_Extension):
def __init__(self, *args, **kw):
_Extension.__init__(self, *args, **kw)
- if not have_pyrex():
- self._convert_pyx_sources_to_c()
-
- def _convert_pyx_sources_to_c(self):
- "convert .pyx extensions to .c"
- def pyx_to_c(source):
- if source.endswith('.pyx'):
- source = source[:-4] + '.c'
- return source
- self.sources = list(map(pyx_to_c, self.sources))
+ self._convert_pyx_sources_to_lang()
+
+ def _convert_pyx_sources_to_lang(self):
+ """
+ Replace sources with .pyx extensions to sources with the target
+ language extension. This mechanism allows language authors to supply
+ pre-converted sources but to prefer the .pyx sources.
+ """
+ if have_pyrex():
+ # the build has Cython, so allow it to compile the .pyx files
+ return
+ lang = self.language or ''
+ target_ext = '.cpp' if lang.lower() == 'c++' else '.c'
+ sub = functools.partial(re.sub, '.pyx$', target_ext)
+ self.sources = list(map(sub, self.sources))
class Library(Extension):
"""Just like a regular Extension, but built as a library instead"""
diff --git a/setuptools/py31compat.py b/setuptools/py31compat.py
index dbb324b0..e6b2910a 100644
--- a/setuptools/py31compat.py
+++ b/setuptools/py31compat.py
@@ -9,3 +9,29 @@ except ImportError:
if name not in ('platlib', 'purelib'):
raise ValueError("Name must be purelib or platlib")
return get_python_lib(name=='platlib')
+
+try:
+ # Python >=3.2
+ from tempfile import TemporaryDirectory
+except ImportError:
+ import shutil
+ import tempfile
+ class TemporaryDirectory(object):
+ """"
+ Very simple temporary directory context manager.
+ Will try to delete afterward, but will also ignore OS and similar
+ errors on deletion.
+ """
+ def __init__(self):
+ self.name = None # Handle mkdtemp raising an exception
+ self.name = tempfile.mkdtemp()
+
+ def __enter__(self):
+ return self.name
+
+ def __exit__(self, exctype, excvalue, exctrace):
+ try:
+ shutil.rmtree(self.name, True)
+ except OSError: #removal errors are not the only possible
+ pass
+ self.name = None
diff --git a/setuptools/svn_utils.py b/setuptools/svn_utils.py
index a9bdc5c3..8fc552fa 100644
--- a/setuptools/svn_utils.py
+++ b/setuptools/svn_utils.py
@@ -9,6 +9,7 @@ import codecs
import unicodedata
import warnings
from setuptools.compat import unicode
+from setuptools.py31compat import TemporaryDirectory
from xml.sax.saxutils import unescape
try:
@@ -27,7 +28,6 @@ from subprocess import Popen as _Popen, PIPE as _PIPE
# http://stackoverflow.com/questions/5658622/
# python-subprocess-popen-environment-path
-
def _run_command(args, stdout=_PIPE, stderr=_PIPE, encoding=None, stream=0):
#regarding the shell argument, see: http://bugs.python.org/issue8557
try:
@@ -231,7 +231,16 @@ class SvnInfo(object):
@staticmethod
def get_svn_version():
- code, data = _run_command(['svn', '--version', '--quiet'])
+ # Temp config directory should be enough to check for repository
+ # This is needed because .svn always creates .subversion and
+ # some operating systems do not handle dot directory correctly.
+ # Real queries in real svn repos with be concerned with it creation
+ with TemporaryDirectory() as tempdir:
+ code, data = _run_command(['svn',
+ '--config-dir', tempdir,
+ '--version',
+ '--quiet'])
+
if code == 0 and data:
return data.strip()
else:
@@ -247,13 +256,22 @@ class SvnInfo(object):
@classmethod
def load(cls, dirname=''):
normdir = os.path.normpath(dirname)
- code, data = _run_command(['svn', 'info', normdir])
+
+ # Temp config directory should be enough to check for repository
+ # This is needed because .svn always creates .subversion and
+ # some operating systems do not handle dot directory correctly.
+ # Real queries in real svn repos with be concerned with it creation
+ with TemporaryDirectory() as tempdir:
+ code, data = _run_command(['svn',
+ '--config-dir', tempdir,
+ 'info', normdir])
+
# Must check for some contents, as some use empty directories
- # in testcases
+ # in testcases, however only enteries is needed also the info
+ # command above MUST have worked
svn_dir = os.path.join(normdir, '.svn')
- has_svn = (os.path.isfile(os.path.join(svn_dir, 'entries')) or
- os.path.isfile(os.path.join(svn_dir, 'dir-props')) or
- os.path.isfile(os.path.join(svn_dir, 'dir-prop-base')))
+ is_svn_wd = (not code or
+ os.path.isfile(os.path.join(svn_dir, 'entries')))
svn_version = tuple(cls.get_svn_version().split('.'))
@@ -262,7 +280,8 @@ class SvnInfo(object):
except ValueError:
base_svn_version = tuple()
- if not has_svn:
+ if not is_svn_wd:
+ #return an instance of this NO-OP class
return SvnInfo(dirname)
if code or not base_svn_version or base_svn_version < (1, 3):
diff --git a/setuptools/tests/__init__.py b/setuptools/tests/__init__.py
index a8eb7110..b5328ce6 100644
--- a/setuptools/tests/__init__.py
+++ b/setuptools/tests/__init__.py
@@ -14,6 +14,7 @@ from setuptools.compat import func_code
from setuptools.compat import func_code
import setuptools.dist
import setuptools.depends as dep
+from setuptools import Feature
from setuptools.depends import Require
def additional_tests():
@@ -230,6 +231,89 @@ class DistroTests(unittest.TestCase):
self.dist.exclude, package_dir=['q']
)
+
+class FeatureTests(unittest.TestCase):
+
+ def setUp(self):
+ self.req = Require('Distutils','1.0.3','distutils')
+ self.dist = makeSetup(
+ features={
+ 'foo': Feature("foo",standard=True,require_features=['baz',self.req]),
+ 'bar': Feature("bar", standard=True, packages=['pkg.bar'],
+ py_modules=['bar_et'], remove=['bar.ext'],
+ ),
+ 'baz': Feature(
+ "baz", optional=False, packages=['pkg.baz'],
+ scripts = ['scripts/baz_it'],
+ libraries=[('libfoo','foo/foofoo.c')]
+ ),
+ 'dwim': Feature("DWIM", available=False, remove='bazish'),
+ },
+ script_args=['--without-bar', 'install'],
+ packages = ['pkg.bar', 'pkg.foo'],
+ py_modules = ['bar_et', 'bazish'],
+ ext_modules = [Extension('bar.ext',['bar.c'])]
+ )
+
+ def testDefaults(self):
+ self.assertTrue(not
+ Feature(
+ "test",standard=True,remove='x',available=False
+ ).include_by_default()
+ )
+ self.assertTrue(
+ Feature("test",standard=True,remove='x').include_by_default()
+ )
+ # Feature must have either kwargs, removes, or require_features
+ self.assertRaises(DistutilsSetupError, Feature, "test")
+
+ def testAvailability(self):
+ self.assertRaises(
+ DistutilsPlatformError,
+ self.dist.features['dwim'].include_in, self.dist
+ )
+
+ def testFeatureOptions(self):
+ dist = self.dist
+ self.assertTrue(
+ ('with-dwim',None,'include DWIM') in dist.feature_options
+ )
+ self.assertTrue(
+ ('without-dwim',None,'exclude DWIM (default)') in dist.feature_options
+ )
+ self.assertTrue(
+ ('with-bar',None,'include bar (default)') in dist.feature_options
+ )
+ self.assertTrue(
+ ('without-bar',None,'exclude bar') in dist.feature_options
+ )
+ self.assertEqual(dist.feature_negopt['without-foo'],'with-foo')
+ self.assertEqual(dist.feature_negopt['without-bar'],'with-bar')
+ self.assertEqual(dist.feature_negopt['without-dwim'],'with-dwim')
+ self.assertTrue(not 'without-baz' in dist.feature_negopt)
+
+ def testUseFeatures(self):
+ dist = self.dist
+ self.assertEqual(dist.with_foo,1)
+ self.assertEqual(dist.with_bar,0)
+ self.assertEqual(dist.with_baz,1)
+ self.assertTrue(not 'bar_et' in dist.py_modules)
+ self.assertTrue(not 'pkg.bar' in dist.packages)
+ self.assertTrue('pkg.baz' in dist.packages)
+ self.assertTrue('scripts/baz_it' in dist.scripts)
+ self.assertTrue(('libfoo','foo/foofoo.c') in dist.libraries)
+ self.assertEqual(dist.ext_modules,[])
+ self.assertEqual(dist.require_features, [self.req])
+
+ # If we ask for bar, it should fail because we explicitly disabled
+ # it on the command line
+ self.assertRaises(DistutilsOptionError, dist.include_feature, 'bar')
+
+ def testFeatureWithInvalidRemove(self):
+ self.assertRaises(
+ SystemExit, makeSetup, features = {'x':Feature('x', remove='y')}
+ )
+
class TestCommandTests(unittest.TestCase):
def testTestIsCommand(self):
diff --git a/setuptools/tests/test_bdist_egg.py b/setuptools/tests/test_bdist_egg.py
index 1a122186..cf4bcd11 100644
--- a/setuptools/tests/test_bdist_egg.py
+++ b/setuptools/tests/test_bdist_egg.py
@@ -1,9 +1,12 @@
"""develop tests
"""
+import os
+import re
+import shutil
+import site
import sys
-import os, re, shutil, tempfile, unittest
import tempfile
-import site
+import unittest
from distutils.errors import DistutilsError
from setuptools.compat import StringIO
diff --git a/setuptools/tests/test_build_ext.py b/setuptools/tests/test_build_ext.py
index a520ced9..a92e53ae 100644
--- a/setuptools/tests/test_build_ext.py
+++ b/setuptools/tests/test_build_ext.py
@@ -1,6 +1,6 @@
"""build_ext tests
"""
-import os, shutil, tempfile, unittest
+import unittest
from distutils.command.build_ext import build_ext as distutils_build_ext
from setuptools.command.build_ext import build_ext
from setuptools.dist import Distribution
@@ -17,4 +17,3 @@ class TestBuildExtTest(unittest.TestCase):
res = cmd.get_ext_filename('foo')
wanted = distutils_build_ext.get_ext_filename(cmd, 'foo')
assert res == wanted
-
diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py
index 7b90161a..18f35c0f 100644
--- a/setuptools/tests/test_develop.py
+++ b/setuptools/tests/test_develop.py
@@ -1,9 +1,11 @@
"""develop tests
"""
+import os
+import shutil
+import site
import sys
-import os, shutil, tempfile, unittest
import tempfile
-import site
+import unittest
from distutils.errors import DistutilsError
from setuptools.command.develop import develop
diff --git a/setuptools/tests/test_easy_install.py b/setuptools/tests/test_easy_install.py
index d2cc7a0f..70e2ad99 100644
--- a/setuptools/tests/test_easy_install.py
+++ b/setuptools/tests/test_easy_install.py
@@ -208,8 +208,9 @@ class TestUserInstallTest(unittest.TestCase):
cmd.ensure_finalized()
cmd.local_index.scan([new_location])
res = cmd.easy_install('foo')
- self.assertEqual(os.path.realpath(res.location),
- os.path.realpath(new_location))
+ actual = os.path.normcase(os.path.realpath(res.location))
+ expected = os.path.normcase(os.path.realpath(new_location))
+ self.assertEqual(actual, expected)
finally:
sys.path.remove(target)
for basedir in [new_location, target, ]:
diff --git a/setuptools/tests/test_find_packages.py b/setuptools/tests/test_find_packages.py
index 017cccfc..3e2619fc 100644
--- a/setuptools/tests/test_find_packages.py
+++ b/setuptools/tests/test_find_packages.py
@@ -6,6 +6,7 @@ import tempfile
import unittest
from setuptools import find_packages
+from setuptools.tests.py26compat import skipIf
PEP420 = sys.version_info[:2] >= (3, 3)
@@ -62,49 +63,62 @@ class TestFindPackages(unittest.TestCase):
fp.close()
return path
- @unittest.skipIf(PEP420, 'Not a PEP 420 env')
+ @skipIf(PEP420, 'Not a PEP 420 env')
def test_regular_package(self):
self._touch('__init__.py', self.pkg_dir)
packages = find_packages(self.dist_dir)
self.assertEqual(packages, ['pkg', 'pkg.subpkg'])
+ def test_include_excludes_other(self):
+ """
+ If include is specified, other packages should be excluded.
+ """
+ self._touch('__init__.py', self.pkg_dir)
+ alt_dir = self._mkdir('other_pkg', self.dist_dir)
+ self._touch('__init__.py', alt_dir)
+ packages = find_packages(self.dist_dir, include=['other_pkg'])
+ self.assertEqual(packages, ['other_pkg'])
+
def test_dir_with_dot_is_skipped(self):
shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets'))
data_dir = self._mkdir('some.data', self.pkg_dir)
self._touch('__init__.py', data_dir)
self._touch('file.dat', data_dir)
packages = find_packages(self.dist_dir)
- self.assertNotIn('pkg.some.data', packages)
+ self.assertTrue('pkg.some.data' not in packages)
+
+ def _assert_packages(self, actual, expected):
+ self.assertEqual(set(actual), set(expected))
- @unittest.skipIf(not PEP420, 'PEP 420 only')
+ @skipIf(not PEP420, 'PEP 420 only')
def test_pep420_ns_package(self):
packages = find_packages(
self.dist_dir, include=['pkg*'], exclude=['pkg.subpkg.assets'])
- self.assertEqual(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
+ self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
- @unittest.skipIf(not PEP420, 'PEP 420 only')
+ @skipIf(not PEP420, 'PEP 420 only')
def test_pep420_ns_package_no_includes(self):
packages = find_packages(
self.dist_dir, exclude=['pkg.subpkg.assets'])
- self.assertEqual(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg'])
+ self._assert_packages(packages, ['docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg'])
- @unittest.skipIf(not PEP420, 'PEP 420 only')
+ @skipIf(not PEP420, 'PEP 420 only')
def test_pep420_ns_package_no_includes_or_excludes(self):
packages = find_packages(self.dist_dir)
expected = [
'docs', 'pkg', 'pkg.nspkg', 'pkg.subpkg', 'pkg.subpkg.assets']
- self.assertEqual(packages, expected)
+ self._assert_packages(packages, expected)
- @unittest.skipIf(not PEP420, 'PEP 420 only')
+ @skipIf(not PEP420, 'PEP 420 only')
def test_regular_package_with_nested_pep420_ns_packages(self):
self._touch('__init__.py', self.pkg_dir)
packages = find_packages(
self.dist_dir, exclude=['docs', 'pkg.subpkg.assets'])
- self.assertEqual(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
+ self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
- @unittest.skipIf(not PEP420, 'PEP 420 only')
+ @skipIf(not PEP420, 'PEP 420 only')
def test_pep420_ns_package_no_non_package_dirs(self):
shutil.rmtree(self.docs_dir)
shutil.rmtree(os.path.join(self.dist_dir, 'pkg/subpkg/assets'))
packages = find_packages(self.dist_dir)
- self.assertEqual(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
+ self._assert_packages(packages, ['pkg', 'pkg.nspkg', 'pkg.subpkg'])
diff --git a/setuptools/tests/test_test.py b/setuptools/tests/test_test.py
index 7a06a403..f85123b0 100644
--- a/setuptools/tests/test_test.py
+++ b/setuptools/tests/test_test.py
@@ -2,10 +2,12 @@
"""develop tests
"""
+import os
+import shutil
+import site
import sys
-import os, shutil, tempfile, unittest
import tempfile
-import site
+import unittest
from distutils.errors import DistutilsError
from setuptools.compat import StringIO
diff --git a/setuptools/version.py b/setuptools/version.py
index f7d2e869..a93f0518 100644
--- a/setuptools/version.py
+++ b/setuptools/version.py
@@ -1 +1 @@
-__version__ = '3.0'
+__version__ = '4.0'