Commit fb8c7cf0 authored by Jason R. Coombs's avatar Jason R. Coombs

Merge with upstream

--HG--
branch : distribute
parents 32ba6930 db678072
......@@ -26,3 +26,14 @@ dae247400d0ca1fdfaf38db275622c9bec550b08 0.6.13
0502d5117d8304ab21084912758ed28812a5a8f1 0.6.17
74108d7f07343556a8db94e8122221a43243f586 0.6.18
611910892a0421633d72677979f94a25ef590d54 0.6.19
a7cf5ae137f1646adf86ce5d6b5d8b7bd6eab69f 0.6.20
c4a375336d552129aef174486018ed09c212d684 0.6.20
de44acab3cfce1f5bc811d6c0fa1a88ca0e9533f 0.6.21
1a1ab844f03e10528ae693ad3cb45064e08f49e5 0.6.23
1a1ab844f03e10528ae693ad3cb45064e08f49e5 0.6.23
9406c5dac8429216f1a264e6f692fdc534476acd 0.6.23
7fd7b6e30a0effa082baed1c4103a0efa56be98c 0.6.24
6124053afb5c98f11e146ae62049b4c232d50dc5 0.6.25
b69f072c000237435e17b8bbb304ba6f957283eb 0.6.26
469c3b948e41ef28752b3cdf3c7fb9618355ebf5 0.6.27
fc379e63586ad3c6838e1bda216548ba8270b8f0 0.6.28
language: python
python:
- 2.5
- 2.6
- 2.7
- 3.2
# command to run tests
script: python setup.py test
......@@ -2,11 +2,112 @@
CHANGES
=======
------
0.6.29
------
* Issue #320: Fix check for "createable" in distribute_setup.py.
* Issue #305: Remove a warning that was triggered during normal operations.
* Issue #311: Print metadata in UTF-8 independent of platform.
* Issue #303: Read manifest file with UTF-8 encoding under Python 3.
* Issue #301: Allow to run tests of namespace packages when using 2to3.
* Issue #304: Prevent import loop in site.py under Python 3.3.
* Issue #283: Reenable scanning of *.pyc / *.pyo files on Python 3.3.
* Issue #299: The develop command didn't work on Python 3, when using 2to3,
as the egg link would go to the Python 2 source. Linking to the 2to3'd code
in build/lib makes it work, although you will have to rebuild the module
before testing it.
* Issue #306: Even if 2to3 is used, we build in-place under Python 2.
* Issue #307: Prints the full path when .svn/entries is broken.
* Issue #313: Support for sdist subcommands (Python 2.7)
* Issue #314: test_local_index() would fail an OS X.
* Issue #310: Non-ascii characters in a namespace __init__.py causes errors.
* Issue #218: Improved documentation on behavior of `package_data` and
`include_package_data`. Files indicated by `package_data` are now included
in the manifest.
* `distribute_setup.py` now allows a `--download-base` argument for retrieving
distribute from a specified location.
------
0.6.28
------
* Issue #294: setup.py can now be invoked from any directory.
* Scripts are now installed honoring the umask.
* Added support for .dist-info directories.
* Issue #283: Fix and disable scanning of *.pyc / *.pyo files on Python 3.3.
------
0.6.27
------
* Support current snapshots of CPython 3.3.
* Distribute now recognizes README.rst as a standard, default readme file.
* Exclude 'encodings' modules when removing modules from sys.modules.
Workaround for #285.
* Issue #231: Don't fiddle with system python when used with buildout
(bootstrap.py)
------
0.6.26
------
* Issue #183: Symlinked files are now extracted from source distributions.
* Issue #227: Easy_install fetch parameters are now passed during the
installation of a source distribution; now fulfillment of setup_requires
dependencies will honor the parameters passed to easy_install.
------
0.6.25
------
* Issue #258: Workaround a cache issue
* Issue #260: distribute_setup.py now accepts the --user parameter for
Python 2.6 and later.
* Issue #262: package_index.open_with_auth no longer throws LookupError
on Python 3.
* Issue #269: AttributeError when an exception occurs reading Manifest.in
on late releases of Python.
* Issue #272: Prevent TypeError when namespace package names are unicode
and single-install-externally-managed is used. Also fixes PIP issue
449.
* Issue #273: Legacy script launchers now install with Python2/3 support.
------
0.6.24
------
* Issue #249: Added options to exclude 2to3 fixers
------
0.6.23
------
* Issue #244: Fixed a test
* Issue #243: Fixed a test
* Issue #239: Fixed a test
* Issue #240: Fixed a test
* Issue #241: Fixed a test
* Issue #237: Fixed a test
* Issue #238: easy_install now uses 64bit executable wrappers on 64bit Python
* Issue #208: Fixed parsed_versions, it now honors post-releases as noted in the documentation
* Issue #207: Windows cli and gui wrappers pass CTRL-C to child python process
* Issue #227: easy_install now passes its arguments to setup.py bdist_egg
* Issue #225: Fixed a NameError on Python 2.5, 2.4
------
0.6.21
------
* Issue #225: FIxed a regression on py2.4
------
0.6.20
------
* ADD STUFF HERE
* Issue #135: Include url in warning when processing URLs in package_index.
* Issue #212: Fix issue where easy_instal fails on Python 3 on windows installer.
* Issue #213: Fix typo in documentation.
------
0.6.19
......
......@@ -7,14 +7,20 @@ Contributors
* Arfrever Frehtes Taifersar Arahesis
* Christophe Combelles
* Daniel Stutzbach
* Daniel Holth
* Hanno Schlichting
* Jannis Leidel
* Jason R. Coombs
* Jim Fulton
* Justin Azoff
* Lennart Regebro
* Marc Abramowitz
* Martin von Löwis
* Noufal Ibrahim
* Philip Jenvey
* Reinout van Rees
* Robert Myers
* Stefan H. Holek
* Tarek Ziadé
* Toshio Kuratomi
......
......@@ -6,22 +6,16 @@ Distribute is using Mercurial.
Grab the code at bitbucket::
$ hg clone https://tarek@bitbucket.org/tarek/distribute distribute
$ hg clone https://bitbucket.org/tarek/distribute
If you want to work in the 0.6 branch, you have to switch to it::
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:
$ hg update 0.6-maintenance
$ hg branch
0.6-maintenance
If you make some changes, don't forget to:
- backport it to the 0.7 branch
- add a note in CHANGES.txt
And remember that 0.6 is only bug fixes, and the APIs should
be fully backward compatible with Setuptools.
And remember that 0.6 (the only development line) is only bug fixes, and the
APIs should be fully backward compatible with Setuptools.
You can run the tests via::
......
......@@ -2,6 +2,7 @@ recursive-include setuptools *.py *.txt *.exe
recursive-include tests *.py *.c *.pyx *.txt
recursive-include setuptools/tests *.html
recursive-include docs *.py *.txt *.conf *.css *.css_t Makefile indexsidebar.html
recursive-include _markerlib *.py
include *.py
include *.txt
include MANIFEST.in
......
......@@ -99,9 +99,9 @@ Source installation
Download the source tarball, uncompress it, then run the install command::
$ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.20.tar.gz
$ tar -xzvf distribute-0.6.20.tar.gz
$ cd distribute-0.6.20
$ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.29.tar.gz
$ tar -xzvf distribute-0.6.29.tar.gz
$ cd distribute-0.6.29
$ python setup.py install
---------------------------
......
try:
import ast
from _markerlib.markers import default_environment, compile, interpret
except ImportError:
if 'ast' in globals():
raise
def default_environment():
return {}
def compile(marker):
def marker_fn(environment=None, override=None):
# 'empty markers are True' heuristic won't install extra deps.
return not marker.strip()
marker_fn.__doc__ = marker
return marker_fn
def interpret(marker, environment=None, override=None):
return compile(marker)()
# -*- coding: utf-8 -*-
"""Interpret PEP 345 environment markers.
EXPR [in|==|!=|not in] EXPR [or|and] ...
where EXPR belongs to any of those:
python_version = '%s.%s' % (sys.version_info[0], sys.version_info[1])
python_full_version = sys.version.split()[0]
os.name = os.name
sys.platform = sys.platform
platform.version = platform.version()
platform.machine = platform.machine()
platform.python_implementation = platform.python_implementation()
a free string, like '2.6', or 'win32'
"""
__all__ = ['default_environment', 'compile', 'interpret']
from ast import Compare, BoolOp, Attribute, Name, Load, Str, cmpop, boolop
from ast import parse, copy_location, NodeTransformer
import os
import platform
import sys
import weakref
_builtin_compile = compile
from platform import python_implementation
# restricted set of variables
_VARS = {'sys.platform': sys.platform,
'python_version': '%s.%s' % sys.version_info[:2],
# FIXME parsing sys.platform is not reliable, but there is no other
# way to get e.g. 2.7.2+, and the PEP is defined with sys.version
'python_full_version': sys.version.split(' ', 1)[0],
'os.name': os.name,
'platform.version': platform.version(),
'platform.machine': platform.machine(),
'platform.python_implementation': python_implementation(),
'extra': None # wheel extension
}
def default_environment():
"""Return copy of default PEP 385 globals dictionary."""
return dict(_VARS)
class ASTWhitelist(NodeTransformer):
def __init__(self, statement):
self.statement = statement # for error messages
ALLOWED = (Compare, BoolOp, Attribute, Name, Load, Str, cmpop, boolop)
def visit(self, node):
"""Ensure statement only contains allowed nodes."""
if not isinstance(node, self.ALLOWED):
raise SyntaxError('Not allowed in environment markers.\n%s\n%s' %
(self.statement,
(' ' * node.col_offset) + '^'))
return NodeTransformer.visit(self, node)
def visit_Attribute(self, node):
"""Flatten one level of attribute access."""
new_node = Name("%s.%s" % (node.value.id, node.attr), node.ctx)
return copy_location(new_node, node)
def parse_marker(marker):
tree = parse(marker, mode='eval')
new_tree = ASTWhitelist(marker).generic_visit(tree)
return new_tree
def compile_marker(parsed_marker):
return _builtin_compile(parsed_marker, '<environment marker>', 'eval',
dont_inherit=True)
_cache = weakref.WeakValueDictionary()
def compile(marker):
"""Return compiled marker as a function accepting an environment dict."""
try:
return _cache[marker]
except KeyError:
pass
if not marker.strip():
def marker_fn(environment=None, override=None):
""""""
return True
else:
compiled_marker = compile_marker(parse_marker(marker))
def marker_fn(environment=None, override=None):
"""override updates environment"""
if override is None:
override = {}
if environment is None:
environment = default_environment()
environment.update(override)
return eval(compiled_marker, environment)
marker_fn.__doc__ = marker
_cache[marker] = marker_fn
return _cache[marker]
def interpret(marker, environment=None):
return compile(marker)(environment)
[distutils.commands]
bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
rotate = setuptools.command.rotate:rotate
develop = setuptools.command.develop:develop
setopt = setuptools.command.setopt:setopt
build_py = setuptools.command.build_py:build_py
saveopts = setuptools.command.saveopts:saveopts
egg_info = setuptools.command.egg_info:egg_info
register = setuptools.command.register:register
upload_docs = setuptools.command.upload_docs:upload_docs
install_egg_info = setuptools.command.install_egg_info:install_egg_info
alias = setuptools.command.alias:alias
easy_install = setuptools.command.easy_install:easy_install
install_scripts = setuptools.command.install_scripts:install_scripts
bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
bdist_egg = setuptools.command.bdist_egg:bdist_egg
install = setuptools.command.install:install
test = setuptools.command.test:test
install_lib = setuptools.command.install_lib:install_lib
build_ext = setuptools.command.build_ext:build_ext
sdist = setuptools.command.sdist:sdist
[egg_info.writers]
dependency_links.txt = setuptools.command.egg_info:overwrite_arg
requires.txt = setuptools.command.egg_info:write_requirements
PKG-INFO = setuptools.command.egg_info:write_pkg_info
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
entry_points.txt = setuptools.command.egg_info:write_entries
depends.txt = setuptools.command.egg_info:warn_depends_obsolete
[console_scripts]
easy_install = setuptools.command.easy_install:main
easy_install-2.6 = setuptools.command.easy_install:main
[setuptools.file_finders]
svn_cvs = setuptools.command.sdist:_default_revctrl
[distutils.setup_keywords]
dependency_links = setuptools.dist:assert_string_list
entry_points = setuptools.dist:check_entry_points
extras_require = setuptools.dist:check_extras
package_data = setuptools.dist:check_package_data
install_requires = setuptools.dist:check_requirements
use_2to3 = setuptools.dist:assert_bool
use_2to3_fixers = setuptools.dist:assert_string_list
include_package_data = setuptools.dist:assert_bool
exclude_package_data = setuptools.dist:check_package_data
namespace_packages = setuptools.dist:check_nsp
test_suite = setuptools.dist:check_test_suite
eager_resources = setuptools.dist:assert_string_list
zip_safe = setuptools.dist:assert_bool
test_loader = setuptools.dist:check_importable
packages = setuptools.dist:check_packages
convert_2to3_doctests = setuptools.dist:assert_string_list
tests_require = setuptools.dist:check_requirements
[setuptools.installation]
eggsecutable = setuptools.command.easy_install:bootstrap
......@@ -19,6 +19,8 @@ import time
import fnmatch
import tempfile
import tarfile
import optparse
from distutils import log
try:
......@@ -46,7 +48,7 @@ except ImportError:
args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
DEFAULT_VERSION = "0.6.20"
DEFAULT_VERSION = "0.6.29"
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11"
......@@ -63,7 +65,7 @@ Description: xxx
""" % SETUPTOOLS_FAKED_VERSION
def _install(tarball):
def _install(tarball, install_args=()):
# extracting the tarball
tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir)
......@@ -81,7 +83,7 @@ def _install(tarball):
# installing
log.warn('Installing Distribute')
if not _python_cmd('setup.py', 'install'):
if not _python_cmd('setup.py', 'install', *install_args):
log.warn('Something went wrong during the installation.')
log.warn('See the error message above.')
finally:
......@@ -144,7 +146,7 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
except ImportError:
return _do_download(version, download_base, to_dir, download_delay)
try:
pkg_resources.require("distribute>="+version)
pkg_resources.require("distribute>=" + version)
return
except pkg_resources.VersionConflict:
e = sys.exc_info()[1]
......@@ -167,6 +169,7 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
if not no_fake:
_create_fake_setuptools_pkg_info(to_dir)
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, delay=15):
"""Download distribute from a specified location and return its filename
......@@ -203,6 +206,7 @@ def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
dst.close()
return os.path.realpath(saveto)
def _no_sandbox(function):
def __no_sandbox(*args, **kw):
try:
......@@ -227,6 +231,7 @@ def _no_sandbox(function):
return __no_sandbox
def _patch_file(path, content):
"""Will backup the file then patch it"""
existing_content = open(path).read()
......@@ -245,15 +250,18 @@ def _patch_file(path, content):
_patch_file = _no_sandbox(_patch_file)
def _same_content(path, content):
return open(path).read() == content
def _rename_path(path):
new_name = path + '.OLD.%s' % time.time()
log.warn('Renaming %s into %s', path, new_name)
log.warn('Renaming %s to %s', path, new_name)
os.rename(path, new_name)
return new_name
def _remove_flat_installation(placeholder):
if not os.path.isdir(placeholder):
log.warn('Unkown installation at %s', placeholder)
......@@ -267,7 +275,7 @@ def _remove_flat_installation(placeholder):
log.warn('Could not locate setuptools*.egg-info')
return
log.warn('Removing elements out of the way...')
log.warn('Moving elements out of the way...')
pkg_info = os.path.join(placeholder, file)
if os.path.isdir(pkg_info):
patched = _patch_egg_dir(pkg_info)
......@@ -289,11 +297,13 @@ def _remove_flat_installation(placeholder):
_remove_flat_installation = _no_sandbox(_remove_flat_installation)
def _after_install(dist):
log.warn('After install bootstrap.')
placeholder = dist.get_command_obj('install').install_purelib
_create_fake_setuptools_pkg_info(placeholder)
def _create_fake_setuptools_pkg_info(placeholder):
if not placeholder or not os.path.exists(placeholder):
log.warn('Could not find the install location')
......@@ -307,7 +317,11 @@ def _create_fake_setuptools_pkg_info(placeholder):
return
log.warn('Creating %s', pkg_info)
f = open(pkg_info, 'w')
try:
f = open(pkg_info, 'w')
except EnvironmentError:
log.warn("Don't have permissions to write %s, skipping", pkg_info)
return
try:
f.write(SETUPTOOLS_PKG_INFO)
finally:
......@@ -321,7 +335,10 @@ def _create_fake_setuptools_pkg_info(placeholder):
finally:
f.close()
_create_fake_setuptools_pkg_info = _no_sandbox(_create_fake_setuptools_pkg_info)
_create_fake_setuptools_pkg_info = _no_sandbox(
_create_fake_setuptools_pkg_info
)
def _patch_egg_dir(path):
# let's check if it's already patched
......@@ -343,6 +360,7 @@ def _patch_egg_dir(path):
_patch_egg_dir = _no_sandbox(_patch_egg_dir)
def _before_install():
log.warn('Before install bootstrap.')
_fake_setuptools()
......@@ -351,7 +369,7 @@ def _before_install():
def _under_prefix(location):
if 'install' not in sys.argv:
return True
args = sys.argv[sys.argv.index('install')+1:]
args = sys.argv[sys.argv.index('install') + 1:]
for index, arg in enumerate(args):
for option in ('--root', '--prefix'):
if arg.startswith('%s=' % option):
......@@ -359,7 +377,7 @@ def _under_prefix(location):
return location.startswith(top_dir)
elif arg == option:
if len(args) > index:
top_dir = args[index+1]
top_dir = args[index + 1]
return location.startswith(top_dir)
if arg == '--user' and USER_SITE is not None:
return location.startswith(USER_SITE)
......@@ -376,11 +394,14 @@ def _fake_setuptools():
return
ws = pkg_resources.working_set
try:
setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools',
replacement=False))
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools', replacement=False)
)
except TypeError:
# old distribute API
setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools'))
setuptools_dist = ws.find(
pkg_resources.Requirement.parse('setuptools')
)
if setuptools_dist is None:
log.warn('No setuptools distribution found')
......@@ -414,7 +435,7 @@ def _fake_setuptools():
res = _patch_egg_dir(setuptools_location)
if not res:
return
log.warn('Patched done.')
log.warn('Patching complete.')
_relaunch()
......@@ -422,7 +443,8 @@ def _relaunch():
log.warn('Relaunching...')
# we have to relaunch the process
# pip marker to avoid a relaunch bug
if sys.argv[:3] == ['-c', 'install', '--single-version-externally-managed']:
_cmd = ['-c', 'install', '--single-version-externally-managed']
if sys.argv[:3] == _cmd:
sys.argv[0] = 'setup.py'
args = [sys.executable] + sys.argv
sys.exit(subprocess.call(args))
......@@ -448,7 +470,7 @@ def _extractall(self, path=".", members=None):
# Extract directories with a safe mode.
directories.append(tarinfo)
tarinfo = copy.copy(tarinfo)
tarinfo.mode = 448 # decimal for oct 0700
tarinfo.mode = 448 # decimal for oct 0700
self.extract(tarinfo, path)
# Reverse sort directories.
......@@ -475,11 +497,39 @@ def _extractall(self, path=".", members=None):
self._dbg(1, "tarfile: %s" % e)
def main(argv, version=DEFAULT_VERSION):
def _build_install_args(options):
"""
Build the arguments to 'python setup.py install' on the distribute package
"""
install_args = []
if options.user_install:
if sys.version_info < (2, 6):
log.warn("--user requires Python 2.6 or later")
raise SystemExit(1)
install_args.append('--user')
return install_args
def _parse_args():
"""
Parse the command line for options
"""
parser = optparse.OptionParser()
parser.add_option(
'--user', dest='user_install', action='store_true', default=False,
help='install in user site package (requires Python 2.6 or later)')
parser.add_option(
'--download-base', dest='download_base', metavar="URL",
default=DEFAULT_URL,
help='alternative URL from where to download the distribute package')
options, args = parser.parse_args()
# positional arguments are ignored
return options
def main(version=DEFAULT_VERSION):
"""Install or upgrade setuptools and EasyInstall"""
tarball = download_setuptools()
_install(tarball)
options = _parse_args()
tarball = download_setuptools(download_base=options.download_base)
_install(tarball, _build_install_args(options))
if __name__ == '__main__':
main(sys.argv[1:])
main()
......@@ -48,9 +48,9 @@ copyright = u'2009-2011, The fellowship of the packaging'
# built documents.
#
# The short X.Y version.
version = '0.6.17'
version = '0.6.29'
# The full version, including alpha/beta/rc tags.
release = '0.6.17'
release = '0.6.29'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
......@@ -875,9 +875,6 @@ Command-Line Options
judgment and force an installation directory to be treated as if it
supported ``.pth`` files.
(If you want to *make* a non-``PYTHONPATH`` directory support ``.pth``
files, please see the `Administrator Installation`_ section below.)
``--no-deps, -N`` (New in 0.6a6)
Don't install any dependencies. This is intended as a convenience for
tools that wrap eggs in a platform-specific packaging system. (We don't
......@@ -940,194 +937,65 @@ Command-Line Options
Custom Installation Locations
-----------------------------
EasyInstall manages what packages are active using Python ``.pth`` files, which
are normally only usable in Python's main ``site-packages`` directory. On some
platforms (such as Mac OS X), there are additional ``site-packages``
directories that you can use besides the main one, but usually there is only
one directory on the system where you can install packages without extra steps.
There are many reasons, however, why you might want to install packages
somewhere other than the ``site-packages`` directory. For example, you might
not have write access to that directory. You may be working with unstable
versions of packages that you don't want to install system-wide. And so on.
The following sections describe various approaches to custom installation; feel
free to choose which one best suits your system and needs.
`Administrator Installation`_
This approach is for when you have write access to ``site-packages`` (or
another directory where ``.pth`` files are processed), but don't want to
install packages there. This can also be used by a system administrator
to enable each user having their own private directories that EasyInstall
will use to install packages.
`Mac OS X "User" Installation`_
This approach produces a result similar to an administrator installation
that gives each user their own private package directory, but on Mac OS X
the hard part has already been done for you. This is probably the best
approach for Mac OS X users.
`Creating a "Virtual" Python`_
This approach is for when you don't have "root" or access to write to the
``site-packages`` directory, and would like to be able to set up one or
more "virtual python" executables for your projects. This approach
gives you the benefits of multiple Python installations, but without having
to actually install Python more than once and use up lots of disk space.
(Only the Python executable is copied; the libraries will be symlinked
from the systemwide Python.)
If you don't already have any ``PYTHONPATH`` customization or
special distutils configuration, and you can't use either of the preceding
approaches, this is probably the best one for you.
`"Traditional" PYTHONPATH-based Installation`_
If you already have a custom ``PYTHONPATH``, and/or a custom distutils
configuration, and don't want to change any of your existing setup, you may
be interested in this approach. (If you're using a custom ``.pth`` file to
point to your custom installation location, however, you should use
`Administrator Installation`_ to enable ``.pth`` processing in the custom
location instead, as that is easier and more flexible than this approach.)
Administrator Installation
~~~~~~~~~~~~~~~~~~~~~~~~~~
If you have root access to your machine, you can easily configure it to allow
each user to have their own directory where Python packages can be installed
and managed by EasyInstall.
First, create an ``altinstall.pth`` file in Python's ``site-packages``
directory, containing the following line (substituting the correct Python
version)::
import os, site; site.addsitedir(os.path.expanduser('~/lib/python2.3'))
This will automatically add each user's ``~/lib/python2.X`` directory to
``sys.path`` (if it exists), *and* it will process any ``.pth`` files in that
directory -- which is what makes it usable with EasyInstall.
The next step is to create or modify ``distutils.cfg`` in the ``distutils``
directory of your Python library. The correct directory will be something like
``/usr/lib/python2.X/distutils`` on most Posix systems and something like
``C:\\Python2X\Lib\distutils`` on Windows machines. Add the following lines
to the file, substituting the correct Python version if necessary:
.. code-block:: ini
[install]
install_lib = ~/lib/python2.3
# This next line is optional but often quite useful; it directs EasyInstall
# and the distutils to install scripts in the user's "bin" directory. For
# Mac OS X framework Python builds, you should use /usr/local/bin instead,
# because neither ~/bin nor the default script installation location are on
# the system PATH.
#
install_scripts = ~/bin
This will configure the distutils and EasyInstall to install packages to the
user's home directory by default.
Of course, you aren't limited to using a ``~/lib/python2.X`` directory with
this approach. You can substitute a specific systemwide directory if you like.
You can also edit ``~/.pydistutils.cfg`` (or ``~/pydistutils.cfg`` on Windows)
instead of changing the master ``distutils.cfg`` file. The true keys of this
approach are simply that:
1. any custom installation directory must be added to ``sys.path`` using a
``site.addsitedir()`` call from a working ``.pth`` file or
``sitecustomize.py``.
By default, EasyInstall installs python packages into Python's main ``site-packages`` directory,
and manages them using a custom ``.pth`` file in that same directory.
2. The active distutils configuration file(s) or ``easy_install`` command line
should include the custom directory in the ``--site-dirs`` option, so that
EasyInstall knows that ``.pth`` files will work in that location. (This is
because Python does not keep track of what directories are or aren't enabled
for ``.pth`` processing, in any way that EasyInstall can find out.)
Very often though, a user or developer wants ``easy_install`` to install and manage python packages
in an alternative location, usually for one of 3 reasons:
As long as both of these things have been done, your custom installation
location is good to go.
1. They don't have access to write to the main Python site-packages directory.
2. They want a user-specific stash of packages, that is not visible to other users.
Mac OS X "User" Installation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3. They want to isolate a set of packages to a specific python application, usually to minimize
the possibility of version conflicts.
If you are on a Mac OS X machine, you should just use the
``~/Library/Python/2.x/site-packages`` directory as your custom installation
location, because it is already configured to process ``.pth`` files, and
EasyInstall already knows this.
Before installing EasyInstall/setuptools, just create a ``~/.pydistutils.cfg``
file with the following contents (or add this to the existing contents):
.. code-block:: ini
Historically, there have been many approaches to achieve custom installation.
The following section lists only the easiest and most relevant approaches [1]_.
[install]
install_lib = ~/Library/Python/$py_version_short/site-packages
install_scripts = ~/bin
`Use the "--user" option`_
This will tell the distutils and EasyInstall to always install packages in
your personal ``site-packages`` directory, and scripts to ``~/bin``. (Note: do
*not* replace ``$py_version_short`` with an actual Python version in the
configuration file! The distutils will substitute the correct value at
runtime, so that the above configuration file should work correctly no matter
what Python version you use, now or in the future.)
`Use the "--user" option and customize "PYTHONUSERBASE"`_
Once you have done this, you can follow the normal `installation instructions`_
and use ``easy_install`` without any other special options or steps.
`Use "virtualenv"`_
(Note, however, that ``~/bin`` is not in the default ``PATH``, so you may have
to refer to scripts by their full location. You may want to modify your shell
startup script (likely ``.bashrc`` or ``.profile``) or your
``~/.MacOSX/environment.plist`` to include ``~/bin`` in your ``PATH``.
.. [1] There are older ways to achieve custom installation using various ``easy_install`` and ``setup.py install`` options, combined with ``PYTHONPATH`` and/or ``PYTHONUSERBASE`` alterations, but all of these are effectively deprecated by the User scheme brought in by `PEP-370`_ in Python 2.6.
.. _PEP-370: http://www.python.org/dev/peps/pep-0370/
Creating a "Virtual" Python
~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you are on a Linux, BSD, Cygwin, or other similar Unix-like operating
system, but don't have root access, you can create your own "virtual"
Python installation, which uses its own library directories and some symlinks
to the site-wide Python.
Please refer to the `virtualenv`_ documentation for creating such an
environment.
Use the "--user" option
~~~~~~~~~~~~~~~~~~~~~~~
With Python 2.6 came the User scheme for installation, which means that all
python distributions support an alternative install location that is specific to a user [2]_ [3]_.
The Default location for each OS is explained in the python documentation
for the ``site.USER_BASE`` variable. This mode of installation can be turned on by
specifying the ``--user`` option to ``setup.py install`` or ``easy_install``.
This approach serves the need to have a user-specific stash of packages.
.. [2] Prior to Python2.6, Mac OS X offered a form of the User scheme. That is now subsumed into the User scheme introduced in Python 2.6.
.. [3] Prior to the User scheme, there was the Home scheme, which is still available, but requires more effort than the User scheme to get packages recognized.
Use the "--user" option and customize "PYTHONUSERBASE"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The User scheme install location can be customized by setting the ``PYTHONUSERBASE`` environment
variable, which updates the value of ``site.USER_BASE``. To isolate packages to a specific
application, simply set the OS environment of that application to a specific value of
``PYTHONUSERBASE``, that contains just those packages.
Use "virtualenv"
~~~~~~~~~~~~~~~~
"virtualenv" is a 3rd-party python package that effectively "clones" a python installation, thereby
creating an isolated location to intall packages. The evolution of "virtualenv" started before the existence
of the User installation scheme. "virtualenv" provides a version of ``easy_install`` that is
scoped to the cloned python install and is used in the normal way. "virtualenv" does offer various features
that the User installation scheme alone does not provide, e.g. the ability to hide the main python site-packages.
Please refer to the `virtualenv`_ documentation for more details.
.. _virtualenv: http://pypi.python.org/pypi/virtualenv
"Traditional" ``PYTHONPATH``-based Installation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This installation method is not as robust or as flexible as `creating a
"virtual" python`_ installation, as it uses various tricks to fool Python into
processing ``.pth`` files where it normally wouldn't. We suggest you at least
consider using one of the other approaches, as they will generally result in
a cleaner, more usable Python configuration. However, if for some reason you
can't or won't use one of the other approaches, here's how to do it.
Assuming that you want to install packages in a directory called ``~/py-lib``,
and scripts in ``~/bin``, here's what you need to do:
First, edit ``~/.pydistutils.cfg`` to include these settings, if you don't
already have them:
.. code-block:: ini
[install]
install_lib = ~/py-lib
install_scripts = ~/bin
Be sure to do this *before* you try to run the ``distribute_setup.py``
installation script. Then, follow the standard `installation instructions`_,
but make sure that ``~/py-lib`` is listed in your ``PYTHONPATH`` environment
variable.
Your library installation directory *must* be in listed in ``PYTHONPATH``,
not only when you install packages with EasyInstall, but also when you use
any packages that are installed using EasyInstall. You will probably want to
edit your ``~/.profile`` or other configuration file(s) to ensure that it is
set, if you haven't already got this set up on your machine.
Package Index "API"
-------------------
......
......@@ -26,18 +26,20 @@ directory, as opposed from the source directory as is normally done.
Distribute will convert all Python files, and also all doctests in Python
files. However, if you have doctests located in separate text files, these
will not automatically be converted. By adding them to the
``convert_2to3_doctests`` keyword parameter Distrubute will convert them as
well.
will not automatically be converted. By adding them to the
``convert_2to3_doctests`` keyword parameter Distrubute will convert them as
well.
By default, the conversion uses all fixers in the ``lib2to3.fixers`` package.
To use additional fixes, the parameter ``use_2to3_fixers`` can be set
to a list of names of packages containing fixers.
To use additional fixers, the parameter ``use_2to3_fixers`` can be set
to a list of names of packages containing fixers. To exclude fixers, the
parameter ``use_2to3_exclude_fixers`` can be set to fixer names to be
skipped.
A typical setup.py can look something like this::
from setuptools import setup
setup(
name='your.module',
version = '1.0',
......@@ -49,7 +51,8 @@ A typical setup.py can look something like this::
test_suite = 'your.module.tests',
use_2to3 = True,
convert_2to3_doctests = ['src/your/module/README.txt'],
use_2to3_fixers = ['your.fixers']
use_2to3_fixers = ['your.fixers'],
use_2to3_exclude_fixers = ['lib2to3.fixes.fix_import'],
)
Differential conversion
......@@ -58,10 +61,10 @@ Differential conversion
Note that a file will only be copied and converted during the build process
if the source file has been changed. If you add a file to the doctests
that should be converted, it will not be converted the next time you run
the tests, since it hasn't been modified. You need to remove it from the
the tests, since it hasn't been modified. You need to remove it from the
build directory. Also if you run the build, install or test commands before
adding the use_2to3 parameter, you will have to remove the build directory
before you run the test command, as the files otherwise will seem updated,
before you run the test command, as the files otherwise will seem updated,
and no conversion will happen.
In general, if code doesn't seem to be converted, deleting the build directory
......@@ -80,12 +83,6 @@ already converted code, and hence no 2to3 conversion is needed during install.
Advanced features
=================
If certain fixers are to be suppressed, this again can be overridden with the
list ``setuptools.command.build_py.build_py.fixer_names``, which at some
point contains the list of all fixer class names. For an example of how this
can be done, see the `jaraco.util <https://bitbucket.org/jaraco/jaraco.util>`_
project.
If you don't want to run the 2to3 conversion on the doctests in Python files,
you can turn that off by setting ``setuptools.use_2to3_on_doctests = False``.
......@@ -96,18 +93,18 @@ Setuptools do not know about the new keyword parameters to support Python 3.
As a result it will warn about the unknown keyword parameters if you use
setuptools instead of Distribute under Python 2. This is not an error, and
install process will continue as normal, but if you want to get rid of that
error this is easy. Simply conditionally add the new parameters into an extra
error this is easy. Simply conditionally add the new parameters into an extra
dict and pass that dict into setup()::
from setuptools import setup
import sys
extra = {}
if sys.version_info >= (3,):
extra['use_2to3'] = True
extra['convert_2to3_doctests'] = ['src/your/module/README.txt']
extra['use_2to3_fixers'] = ['your.fixers']
setup(
name='your.module',
version = '1.0',
......
......@@ -756,17 +756,18 @@ e.g.::
include_package_data = True
)
This tells setuptools to install any data files it finds in your packages. The
data files must be under CVS or Subversion control, or else they must be
This tells setuptools to install any data files it finds in your packages.
The data files must be under CVS or Subversion control, or else they must be
specified via the distutils' ``MANIFEST.in`` file. (They can also be tracked
by another revision control system, using an appropriate plugin. See the
section below on `Adding Support for Other Revision Control Systems`_ for
information on how to write such plugins.)
If you want finer-grained control over what files are included (for example, if
you have documentation files in your package directories and want to exclude
them from installation), then you can also use the ``package_data`` keyword,
e.g.::
If the data files are not under version control, or are not in a supported
version control system, or if you want finer-grained control over what files
are included (for example, if you have documentation files in your package
directories and want to exclude them from installation), then you can also use
the ``package_data`` keyword, e.g.::
from setuptools import setup, find_packages
setup(
......@@ -822,7 +823,10 @@ converts slashes to appropriate platform-specific separators at build time.
(Note: although the ``package_data`` argument was previously only available in
``setuptools``, it was also added to the Python ``distutils`` package as of
Python 2.4; there is `some documentation for the feature`__ available on the
python.org website.)
python.org website. If using the setuptools-specific ``include_package_data``
argument, files specified by ``package_data`` will *not* be automatically
added to the manifest unless they are tracked by a supported version control
system, or are listed in the MANIFEST.in file.)
__ http://docs.python.org/dist/node11.html
......@@ -1082,6 +1086,14 @@ update the ``easy-install.pth`` file to include your project's source code,
thereby making it available on ``sys.path`` for all programs using that Python
installation.
If you have enabled the ``use_2to3`` flag, then of course the ``.egg-link``
will not link directly to your source code when run under Python 3, since
that source code would be made for Python 2 and not work under Python 3.
Instead the ``setup.py develop`` will build Python 3 code under the ``build``
directory, and link there. This means that after doing code changes you will
have to run ``setup.py build`` before these changes are picked up by your
Python 3 installation.
In addition, the ``develop`` command creates wrapper scripts in the target
script directory that will run your in-development scripts after ensuring that
all your ``install_requires`` packages are available on ``sys.path``.
......
......@@ -25,9 +25,12 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <windows.h>
#include <tchar.h>
#include <fcntl.h>
#include "windows.h"
int child_pid=0;
int fail(char *format, char *data) {
/* Print error message to stderr and return 2 */
......@@ -35,10 +38,6 @@ int fail(char *format, char *data) {
return 2;
}
char *quoted(char *data) {
int i, ln = strlen(data), nb;
......@@ -90,7 +89,7 @@ char *loadable_exe(char *exename) {
/* Return the absolute filename for spawnv */
result = calloc(MAX_PATH, sizeof(char));
strncpy(result, exename, MAX_PATH);
/*if (result) GetModuleFileName(hPython, result, MAX_PATH);
/*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
FreeLibrary(hPython); */
return result;
......@@ -160,8 +159,82 @@ char **parse_argv(char *cmdline, int *argc)
} while (1);
}
void pass_control_to_child(DWORD control_type) {
/*
* distribute-issue207
* passes the control event to child process (Python)
*/
if (!child_pid) {
return;
}
GenerateConsoleCtrlEvent(child_pid,0);
}
BOOL control_handler(DWORD control_type) {
/*
* distribute-issue207
* control event handler callback function
*/
switch (control_type) {
case CTRL_C_EVENT:
pass_control_to_child(0);
break;
}
return TRUE;
}
int create_and_wait_for_subprocess(char* command) {
/*
* distribute-issue207
* launches child process (Python)
*/
DWORD return_value = 0;
LPSTR commandline = command;
STARTUPINFOA s_info;
PROCESS_INFORMATION p_info;
ZeroMemory(&p_info, sizeof(p_info));
ZeroMemory(&s_info, sizeof(s_info));
s_info.cb = sizeof(STARTUPINFO);
// set-up control handler callback funciotn
SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
fprintf(stderr, "failed to create process.\n");
return 0;
}
child_pid = p_info.dwProcessId;
// wait for Python to exit
WaitForSingleObject(p_info.hProcess, INFINITE);
if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
fprintf(stderr, "failed to get exit code from process.\n");
return 0;
}
return return_value;
}
char* join_executable_and_args(char *executable, char **args, int argc)
{
/*
* distribute-issue207
* CreateProcess needs a long string of the executable and command-line arguments,
* so we need to convert it from the args that was built
*/
int len,counter;
char* cmdline;
len=strlen(executable)+2;
for (counter=1; counter<argc; counter++) {
len+=strlen(args[counter])+1;
}
cmdline = (char*)calloc(len, sizeof(char));
sprintf(cmdline, "%s", executable);
len=strlen(executable);
for (counter=1; counter<argc; counter++) {
sprintf(cmdline+len, " %s", args[counter]);
len+=strlen(args[counter])+1;
}
return cmdline;
}
int run(int argc, char **argv, int is_gui) {
......@@ -173,10 +246,11 @@ int run(int argc, char **argv, int is_gui) {
char **newargs, **newargsp, **parsedargs; /* argument array for exec */
char *ptr, *end; /* working pointers for string manipulation */
char *cmdline;
int i, parsedargc; /* loop counter */
/* compute script name from our .exe name*/
GetModuleFileName(NULL, script, sizeof(script));
GetModuleFileNameA(NULL, script, sizeof(script));
end = script + strlen(script);
while( end>script && *end != '.')
*end-- = '\0';
......@@ -236,12 +310,18 @@ int run(int argc, char **argv, int is_gui) {
return fail("Could not exec %s", ptr); /* shouldn't get here! */
}
/* We *do* need to wait for a CLI to finish, so use spawn */
return spawnv(P_WAIT, ptr, (const char * const *)(newargs));
/*
* distribute-issue207: using CreateProcessA instead of spawnv
*/
cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
return create_and_wait_for_subprocess(cmdline);
}
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
return run(__argc, __argv, GUI);
}
int main(int argc, char** argv) {
return run(argc, argv, GUI);
}
......@@ -535,6 +535,10 @@ class WorkingSet(object):
"""
seen = {}
for item in self.entries:
if item not in self.entry_keys:
# workaround a cache issue
continue
for key in self.entry_keys[item]:
if key not in seen:
seen[key]=1
......@@ -1350,6 +1354,14 @@ class DefaultProvider(EggProvider):
register_loader_type(type(None), DefaultProvider)
try:
# CPython >=3.3
import _frozen_importlib
except ImportError:
pass
else:
register_loader_type(_frozen_importlib.SourceFileLoader, DefaultProvider)
class EmptyProvider(NullProvider):
"""Provider that returns nothing for all requests"""
......@@ -1763,7 +1775,7 @@ def find_on_path(importer, path_item, only=False):
# scan for .egg and .egg-info in directory
for entry in os.listdir(path_item):
lower = entry.lower()
if lower.endswith('.egg-info'):
if lower.endswith('.egg-info') or lower.endswith('.dist-info'):
fullpath = os.path.join(path_item, entry)
if os.path.isdir(fullpath):
# egg-info directory, allow getting metadata
......@@ -1784,6 +1796,14 @@ def find_on_path(importer, path_item, only=False):
break
register_finder(ImpWrapper,find_on_path)
try:
# CPython >=3.3
import _frozen_importlib
except ImportError:
pass
else:
register_finder(_frozen_importlib.FileFinder, find_on_path)
_declare_state('dict', _namespace_handlers={})
_declare_state('dict', _namespace_packages={})
......@@ -1883,6 +1903,14 @@ def file_ns_handler(importer, path_item, packageName, module):
register_namespace_handler(ImpWrapper,file_ns_handler)
register_namespace_handler(zipimport.zipimporter,file_ns_handler)
try:
# CPython >=3.3
import _frozen_importlib
except ImportError:
pass
else:
register_namespace_handler(_frozen_importlib.FileFinder, file_ns_handler)
def null_ns_handler(importer, path_item, packageName, module):
return None
......@@ -1941,7 +1969,7 @@ replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
def _parse_version_parts(s):
for part in component_re.split(s):
part = replace(part,part)
if not part or part=='.':
if part in ['', '.']:
continue
if part[:1] in '0123456789':
yield part.zfill(8) # pad for numeric comparison
......@@ -1984,8 +2012,6 @@ def parse_version(s):
parts = []
for part in _parse_version_parts(s.lower()):
if part.startswith('*'):
if part<'*final': # remove '-' before a prerelease tag
while parts and parts[-1]=='*final-': parts.pop()
# remove trailing zeros from each series of numeric parts
while parts and parts[-1]=='00000000':
parts.pop()
......@@ -2122,6 +2148,8 @@ def _remove_md5_fragment(location):
class Distribution(object):
"""Wrap an actual or potential sys.path entry w/metadata"""
PKG_INFO = 'PKG-INFO'
def __init__(self,
location=None, metadata=None, project_name=None, version=None,
py_version=PY_MAJOR, platform=None, precedence = EGG_DIST
......@@ -2139,12 +2167,14 @@ class Distribution(object):
def from_location(cls,location,basename,metadata=None,**kw):
project_name, version, py_version, platform = [None]*4
basename, ext = os.path.splitext(basename)
if ext.lower() in (".egg",".egg-info"):
if ext.lower() in _distributionImpl:
# .dist-info gets much metadata differently
match = EGG_NAME(basename)
if match:
project_name, version, py_version, platform = match.group(
'name','ver','pyver','plat'
)
cls = _distributionImpl[ext.lower()]
return cls(
location, metadata, project_name=project_name, version=version,
py_version=py_version, platform=platform, **kw
......@@ -2207,13 +2237,13 @@ class Distribution(object):
try:
return self._version
except AttributeError:
for line in self._get_metadata('PKG-INFO'):
for line in self._get_metadata(self.PKG_INFO):
if line.lower().startswith('version:'):
self._version = safe_version(line.split(':',1)[1].strip())
return self._version
else:
raise ValueError(
"Missing 'Version:' header and/or PKG-INFO file", self
"Missing 'Version:' header and/or %s file" % self.PKG_INFO, self
)
version = property(version)
......@@ -2444,6 +2474,74 @@ class Distribution(object):
extras = property(extras)
class DistInfoDistribution(Distribution):
"""Wrap an actual or potential sys.path entry w/metadata, .dist-info style"""
PKG_INFO = 'METADATA'
EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])")
@property
def _parsed_pkg_info(self):
"""Parse and cache metadata"""
try:
return self._pkg_info
except AttributeError:
from email.parser import Parser
self._pkg_info = Parser().parsestr(self.get_metadata(self.PKG_INFO))
return self._pkg_info
@property
def _dep_map(self):
try:
return self.__dep_map
except AttributeError:
self.__dep_map = self._compute_dependencies()
return self.__dep_map
def _preparse_requirement(self, requires_dist):
"""Convert 'Foobar (1); baz' to ('Foobar ==1', 'baz')
Split environment marker, add == prefix to version specifiers as
necessary, and remove parenthesis.
"""
parts = requires_dist.split(';', 1) + ['']
distvers = parts[0].strip()
mark = parts[1].strip()
distvers = re.sub(self.EQEQ, r"\1==\2\3", distvers)
distvers = distvers.replace('(', '').replace(')', '')
return (distvers, mark)
def _compute_dependencies(self):
"""Recompute this distribution's dependencies."""
from _markerlib import compile as compile_marker
dm = self.__dep_map = {None: []}
reqs = []
# Including any condition expressions
for req in self._parsed_pkg_info.get_all('Requires-Dist') or []:
distvers, mark = self._preparse_requirement(req)
parsed = parse_requirements(distvers).next()
parsed.marker_fn = compile_marker(mark)
reqs.append(parsed)
def reqs_for_extra(extra):
for req in reqs:
if req.marker_fn(override={'extra':extra}):
yield req
common = frozenset(reqs_for_extra(None))
dm[None].extend(common)
for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []:
extra = safe_extra(extra.strip())
dm[extra] = list(frozenset(reqs_for_extra(extra)) - common)
return dm
_distributionImpl = {'.egg': Distribution,
'.egg-info': Distribution,
'.dist-info': DistInfoDistribution }
def issue_warning(*args,**kw):
level = 1
g = globals()
......
#!/usr/bin/env python
"""
Script to fully automate the release process. Requires Python 2.6+
with sphinx installed and the 'hg' command on the path.
"""
from __future__ import print_function
import subprocess
import shutil
import os
import sys
import urllib2
import getpass
import collections
try:
import keyring
except Exception:
pass
VERSION = '0.6.29'
def get_next_version():
digits = map(int, VERSION.split('.'))
digits[-1] += 1
return '.'.join(map(str, digits))
NEXT_VERSION = get_next_version()
files_with_versions = ('docs/conf.py', 'setup.py', 'release.py',
'README.txt', 'distribute_setup.py')
def get_repo_name():
"""
Get the repo name from the hgrc default path.
"""
default = subprocess.check_output('hg paths default').strip()
parts = default.split('/')
if parts[-1] == '':
parts.pop()
return '/'.join(parts[-2:])
def get_mercurial_creds(system='https://bitbucket.org', username=None):
"""
Return named tuple of username,password in much the same way that
Mercurial would (from the keyring).
"""
# todo: consider getting this from .hgrc
username = username or getpass.getuser()
keyring_username = '@@'.join((username, system))
system = '@'.join((keyring_username, 'Mercurial'))
password = (
keyring.get_password(system, keyring_username)
if 'keyring' in globals()
else None
)
if not password:
password = getpass.getpass()
Credential = collections.namedtuple('Credential', 'username password')
return Credential(username, password)
def add_milestone_and_version(version=NEXT_VERSION):
auth = 'Basic ' + ':'.join(get_mercurial_creds()).encode('base64').strip()
headers = {
'Authorization': auth,
}
base = 'https://api.bitbucket.org'
for type in 'milestones', 'versions':
url = (base + '/1.0/repositories/{repo}/issues/{type}'
.format(repo = get_repo_name(), type=type))
req = urllib2.Request(url = url, headers = headers,
data='name='+version)
try:
urllib2.urlopen(req)
except urllib2.HTTPError as e:
print(e.fp.read())
def bump_versions():
list(map(bump_version, files_with_versions))
def bump_version(filename):
with open(filename, 'rb') as f:
lines = [line.replace(VERSION, NEXT_VERSION) for line in f]
with open(filename, 'wb') as f:
f.writelines(lines)
def do_release():
assert all(map(os.path.exists, files_with_versions)), (
"Expected file(s) missing")
assert has_sphinx(), "You must have Sphinx installed to release"
res = raw_input('Have you read through the SCM changelog and '
'confirmed the changelog is current for releasing {VERSION}? '
.format(**globals()))
if not res.lower().startswith('y'):
print("Please do that")
raise SystemExit(1)
print("Travis-CI tests: http://travis-ci.org/#!/jaraco/distribute")
res = raw_input('Have you or has someone verified that the tests '
'pass on this revision? ')
if not res.lower().startswith('y'):
print("Please do that")
raise SystemExit(2)
subprocess.check_call(['hg', 'tag', VERSION])
subprocess.check_call(['hg', 'update', VERSION])
has_docs = build_docs()
if os.path.isdir('./dist'):
shutil.rmtree('./dist')
cmd = [sys.executable, 'setup.py', '-q', 'egg_info', '-RD', '-b', '',
'sdist', 'register', 'upload']
if has_docs:
cmd.append('upload_docs')
subprocess.check_call(cmd)
upload_bootstrap_script()
# update to the tip for the next operation
subprocess.check_call(['hg', 'update'])
# we just tagged the current version, bump for the next release.
bump_versions()
subprocess.check_call(['hg', 'ci', '-m',
'Bumped to {NEXT_VERSION} in preparation for next '
'release.'.format(**globals())])
# push the changes
subprocess.check_call(['hg', 'push'])
add_milestone_and_version()
def has_sphinx():
try:
devnull = open(os.path.devnull, 'wb')
subprocess.Popen(['sphinx-build', '--version'], stdout=devnull,
stderr=subprocess.STDOUT).wait()
except Exception:
return False
return True
def build_docs():
if not os.path.isdir('docs'):
return
if os.path.isdir('docs/build'):
shutil.rmtree('docs/build')
subprocess.check_call([
'sphinx-build',
'-b', 'html',
'-d', 'build/doctrees',
'.',
'build/html',
],
cwd='docs')
return True
def upload_bootstrap_script():
scp_command = 'pscp' if sys.platform.startswith('win') else 'scp'
try:
subprocess.check_call([scp_command, 'distribute_setup.py',
'pypi@ziade.org:python-distribute.org/'])
except:
print("Unable to upload bootstrap script. Ask Tarek to do it.")
if __name__ == '__main__':
do_release()
#!/bin/sh
export VERSION="0.6.20"
# tagging
hg tag $VERSION
hg ci -m "bumped revision"
# creating the releases
rm -rf ./dist
# now preparing the source release, pushing it and its doc
python2.6 setup.py -q egg_info -RDb '' sdist register upload
cd docs/
make html
cd ..
python2.6 setup.py upload_docs
# pushing the bootstrap script
scp distribute_setup.py ziade.org:websites/python-distribute.org/
# starting the new dev
hg push
......@@ -2,6 +2,10 @@
"""Distutils setup file, used to install or test 'setuptools'"""
import sys
import os
import textwrap
# Allow to run setup.py from another directory.
os.chdir(os.path.dirname(os.path.abspath(__file__)))
src_root = None
do_2to3 = False
......@@ -28,7 +32,7 @@ if sys.version_info >= (3,) and do_2to3:
util.run_2to3(outfiles_2to3)
# arrange setup to use the copy
sys.path.insert(0, tmp_src)
sys.path.insert(0, os.path.abspath(tmp_src))
src_root = tmp_src
from distutils.util import convert_path
......@@ -38,7 +42,7 @@ init_path = convert_path('setuptools/command/__init__.py')
exec(open(init_path).read(), d)
SETUP_COMMANDS = d['__all__']
VERSION = "0.6.20"
VERSION = "0.6.29"
from setuptools import setup, find_packages
from setuptools.command.build_py import build_py as _build_py
......@@ -174,7 +178,8 @@ dist = setup(
"test_loader = setuptools.dist:check_importable",
"use_2to3 = setuptools.dist:assert_bool",
"convert_2to3_doctests = setuptools.dist:assert_string_list",
"use_2to3_fixers = setuptools.dist:assert_string_list",
"use_2to3_fixers = setuptools.dist:assert_string_list",
"use_2to3_exclude_fixers = setuptools.dist:assert_string_list",
],
"egg_info.writers": [
......@@ -198,23 +203,28 @@ dist = setup(
},
classifiers = [f.strip() for f in """
Development Status :: 5 - Production/Stable
Intended Audience :: Developers
License :: OSI Approved :: Python Software Foundation License
License :: OSI Approved :: Zope Public License
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 3
Topic :: Software Development :: Libraries :: Python Modules
Topic :: System :: Archiving :: Packaging
Topic :: System :: Systems Administration
Topic :: Utilities""".splitlines() if f.strip()],
classifiers = textwrap.dedent("""
Development Status :: 5 - Production/Stable
Intended Audience :: Developers
License :: OSI Approved :: Python Software Foundation License
License :: OSI Approved :: Zope Public License
Operating System :: OS Independent
Programming Language :: Python :: 2.4
Programming Language :: Python :: 2.5
Programming Language :: Python :: 2.6
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.1
Programming Language :: Python :: 3.2
Programming Language :: Python :: 3.3
Topic :: Software Development :: Libraries :: Python Modules
Topic :: System :: Archiving :: Packaging
Topic :: System :: Systems Administration
Topic :: Utilities
""").strip().splitlines(),
scripts = scripts,
)
if _being_installed():
from distribute_setup import _after_install
_after_install(dist)
......@@ -180,19 +180,22 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
try:
tarobj.chown = lambda *args: None # don't do any chowning!
for member in tarobj:
if member.isfile() or member.isdir():
name = member.name
# don't extract absolute paths or ones with .. in them
if not name.startswith('/') and '..' not in name:
dst = os.path.join(extract_dir, *name.split('/'))
dst = progress_filter(name, dst)
if dst:
if dst.endswith(os.sep):
dst = dst[:-1]
try:
tarobj._extract_member(member,dst) # XXX Ugh
except tarfile.ExtractError:
pass # chown/chmod/mkfifo/mknode/makedev failed
name = member.name
# don't extract absolute paths or ones with .. in them
if not name.startswith('/') and '..' not in name:
prelim_dst = os.path.join(extract_dir, *name.split('/'))
final_dst = progress_filter(name, prelim_dst)
# If progress_filter returns None, then we do not extract
# this file
# TODO: Do we really need to limit to just these file types?
# tarobj.extract() will handle all files on all platforms,
# turning file types that aren't allowed on that platform into
# regular files.
if final_dst and (member.isfile() or member.isdir() or
member.islnk() or member.issym()):
tarobj.extract(member, extract_dir)
if final_dst != prelim_dst:
shutil.move(prelim_dst, final_dst)
return True
finally:
tarobj.close()
......
No preview for this file type
......@@ -14,7 +14,6 @@ if sys.version>='2.5':
from distutils.command.bdist import bdist
if 'egg' not in bdist.format_commands:
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
bdist.format_commands.append('egg')
......
......@@ -426,8 +426,12 @@ def scan_module(egg_dir, base, name, stubs):
return True # Extension module
pkg = base[len(egg_dir)+1:].replace(os.sep,'.')
module = pkg+(pkg and '.' or '')+os.path.splitext(name)[0]
f = open(filename,'rb'); f.read(8) # skip magic & date
code = marshal.load(f); f.close()
if sys.version_info < (3, 3):
skip = 8 # skip magic & date
else:
skip = 12 # skip magic & date & file size
f = open(filename,'rb'); f.read(skip)
code = marshal.load(f); f.close()
safe = True
symbols = dict.fromkeys(iter_symbols(code))
for bad in ['__file__', '__path__']:
......
......@@ -28,13 +28,8 @@ try:
if not files:
return
log.info("Fixing "+" ".join(files))
if not self.fixer_names:
self.fixer_names = []
for p in setuptools.lib2to3_fixer_packages:
self.fixer_names.extend(get_fixers_from_package(p))
if self.distribution.use_2to3_fixers is not None:
for p in self.distribution.use_2to3_fixers:
self.fixer_names.extend(get_fixers_from_package(p))
self.__build_fixer_names()
self.__exclude_fixers()
if doctests:
if setuptools.run_2to3_on_doctests:
r = DistutilsRefactoringTool(self.fixer_names)
......@@ -42,6 +37,23 @@ try:
else:
_Mixin2to3.run_2to3(self, files)
def __build_fixer_names(self):
if self.fixer_names: return
self.fixer_names = []
for p in setuptools.lib2to3_fixer_packages:
self.fixer_names.extend(get_fixers_from_package(p))
if self.distribution.use_2to3_fixers is not None:
for p in self.distribution.use_2to3_fixers:
self.fixer_names.extend(get_fixers_from_package(p))
def __exclude_fixers(self):
excluded_fixers = getattr(self, 'exclude_fixers', [])
if self.distribution.use_2to3_exclude_fixers is not None:
excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers)
for fixer_name in excluded_fixers:
if fixer_name in self.fixer_names:
self.fixer_names.remove(fixer_name)
except ImportError:
class Mixin2to3:
def run_2to3(self, files, doctests=True):
......@@ -201,8 +213,8 @@ class build_py(_build_py, Mixin2to3):
else:
return init_py
f = open(init_py,'rU')
if 'declare_namespace' not in f.read():
f = open(init_py,'rbU')
if 'declare_namespace'.encode() not in f.read():
from distutils import log
log.warn(
"WARNING: %s is a namespace package, but its __init__.py does\n"
......
......@@ -3,7 +3,7 @@ from distutils.util import convert_path, subst_vars
from pkg_resources import Distribution, PathMetadata, normalize_path
from distutils import log
from distutils.errors import DistutilsError, DistutilsOptionError
import os, setuptools, glob
import os, sys, setuptools, glob
class develop(easy_install):
"""Set up package for development"""
......@@ -84,11 +84,35 @@ class develop(easy_install):
" installation directory", p, normalize_path(os.curdir))
def install_for_development(self):
# Ensure metadata is up-to-date
self.run_command('egg_info')
# Build extensions in-place
self.reinitialize_command('build_ext', inplace=1)
self.run_command('build_ext')
if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
# If we run 2to3 we can not do this inplace:
# Ensure metadata is up-to-date
self.reinitialize_command('build_py', inplace=0)
self.run_command('build_py')
bpy_cmd = self.get_finalized_command("build_py")
build_path = normalize_path(bpy_cmd.build_lib)
# Build extensions
self.reinitialize_command('egg_info', egg_base=build_path)
self.run_command('egg_info')
self.reinitialize_command('build_ext', inplace=0)
self.run_command('build_ext')
# Fixup egg-link and easy-install.pth
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
else:
# Without 2to3 inplace works fine:
self.run_command('egg_info')
# Build extensions in-place
self.reinitialize_command('build_ext', inplace=1)
self.run_command('build_ext')
self.install_site_py() # ensure that target dir is site-safe
if setuptools.bootstrap_install_from:
self.easy_install(setuptools.bootstrap_install_from)
......
......@@ -10,7 +10,15 @@ file, or visit the `EasyInstall home page`__.
__ http://packages.python.org/distribute/easy_install.html
"""
import sys, os.path, zipimport, shutil, tempfile, zipfile, re, stat, random
import sys
import os
import zipimport
import shutil
import tempfile
import zipfile
import re
import stat
import random
from glob import glob
from setuptools import Command, _dont_write_bytecode
from setuptools.sandbox import run_setup
......@@ -21,6 +29,7 @@ from distutils.sysconfig import get_python_lib, get_config_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
from setuptools.package_index import URL_SCHEME
......@@ -43,6 +52,10 @@ __all__ = [
import site
HAS_USER_SITE = not sys.version < "2.6" and site.ENABLE_USER_SITE
import struct
def is_64bit():
return struct.calcsize("P") == 8
def samefile(p1,p2):
if hasattr(os.path,'samefile') and (
os.path.exists(p1) and os.path.exists(p2)
......@@ -730,22 +743,26 @@ 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)
if is_script and dev_path:
script_text = get_script_header(script_text) + (
"# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r\n"
"__requires__ = %(spec)r\n"
"from pkg_resources import require; require(%(spec)r)\n"
"del require\n"
"__file__ = %(dev_path)r\n"
"execfile(__file__)\n"
) % locals()
elif is_script:
script_text = get_script_header(script_text) + (
"# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r\n"
"__requires__ = %(spec)r\n"
"import pkg_resources\n"
"pkg_resources.run_script(%(spec)r, %(script_name)r)\n"
) % locals()
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:
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.write_script(script_name, _to_ascii(script_text), 'b')
def write_script(self, script_name, contents, mode="t", blockers=()):
......@@ -756,12 +773,13 @@ Please make the appropriate changes for your system and try again.
target = os.path.join(self.script_dir, script_name)
self.add_output(target)
mask = current_umask()
if not self.dry_run:
ensure_directory(target)
f = open(target,"w"+mode)
f.write(contents)
f.close()
chmod(target,0x1ED) # 0755
chmod(target, 0x1FF-mask) # 0777
......@@ -1078,11 +1096,14 @@ See the setuptools documentation for the "develop" command for more info.
def build_and_install(self, setup_script, setup_base):
args = ['bdist_egg', '--dist-dir']
dist_dir = tempfile.mkdtemp(
prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script)
)
try:
self._set_fetcher_options(os.path.dirname(setup_script))
args.append(dist_dir)
self.run_setup(setup_script, setup_base, args)
all_eggs = Environment([dist_dir])
eggs = []
......@@ -1097,6 +1118,30 @@ See the setuptools documentation for the "develop" command for more info.
rmtree(dist_dir)
log.set_verbosity(self.verbose) # restore our log verbosity
def _set_fetcher_options(self, base):
"""
When easy_install is about to run bdist_egg on a source dist, that
source dist might have 'setup_requires' directives, requiring
additional fetching. Ensure the fetcher options given to easy_install
are available to that command as well.
"""
# find the fetch options from easy_install and write them out
# to the setup.cfg file.
ei_opts = self.distribution.get_option_dict('easy_install').copy()
fetch_directives = (
'find_links', 'site_dirs', 'index_url', 'optimize',
'site_dirs', 'allow_hosts',
)
fetch_options = {}
for key, val in ei_opts.iteritems():
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)
cfg_filename = os.path.join(base, 'setup.cfg')
setopt.edit_config(cfg_filename, settings)
def update_pth(self,dist):
if self.pth_file is None:
return
......@@ -1431,7 +1476,19 @@ def extract_wininst_cfg(dist_filename):
f.seek(prepended-(12+cfglen))
cfg = ConfigParser.RawConfigParser({'version':'','target_version':''})
try:
cfg.readfp(StringIO(f.read(cfglen).split(chr(0),1)[0]))
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):
null_byte = bytes([0])
else:
null_byte = chr(0)
config = part.split(null_byte, 1)[0]
# Now the config is in bytes, but on Python 3, it must be
# unicode for the RawConfigParser, so decode it. Is this the
# right encoding?
config = config.decode('ascii')
cfg.readfp(StringIO(config))
except ConfigParser.Error:
return None
if not cfg.has_section('metadata') or not cfg.has_section('Setup'):
......@@ -1777,7 +1834,10 @@ def get_script_args(dist, executable=sys_executable, wininst=False):
ext, launcher = '-script.py', 'cli.exe'
old = ['.py','.pyc','.pyo']
new_header = re.sub('(?i)pythonw.exe','python.exe',header)
if is_64bit():
launcher = launcher.replace(".", "-64.")
else:
launcher = launcher.replace(".", "-32.")
if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
hdr = new_header
else:
......@@ -1827,6 +1887,11 @@ 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(022)
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])
......
......@@ -163,7 +163,12 @@ class egg_info(Command):
os.unlink(filename)
def tagged_version(self):
return safe_version(self.distribution.get_version() + self.vtags)
version = self.distribution.get_version()
# egg_info may be called more than once for a distribution,
# in which case the version string already contains all tags.
if self.vtags and version.endswith(self.vtags):
return safe_version(version)
return safe_version(version + self.vtags)
def run(self):
self.mkpath(self.egg_info)
......@@ -288,6 +293,19 @@ class FileList(FileList):
def compose(path):
# Apple's HFS Plus returns decomposed UTF-8. Since just about
# everyone else chokes on it, we must make sure to return fully
# composed UTF-8 only.
if sys.getfilesystemencoding().lower() == 'utf-8':
from unicodedata import normalize
if sys.version_info >= (3,):
path = normalize('NFC', path)
else:
path = normalize('NFC', path.decode('utf-8')).encode('utf-8')
return path
class manifest_maker(sdist):
template = "MANIFEST.in"
......@@ -312,6 +330,7 @@ class manifest_maker(sdist):
self.prune_file_list()
self.filelist.sort()
self.filelist.remove_duplicates()
self.filelist.files = [compose(path) for path in self.filelist.files]
self.write_manifest()
def write_manifest (self):
......
......@@ -89,6 +89,8 @@ class install_egg_info(Command):
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:
......
......@@ -39,15 +39,16 @@ class install_scripts(_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
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)
mask = current_umask()
if not self.dry_run:
ensure_directory(target)
f = open(target,"w"+mode)
f.write(contents)
f.close()
chmod(target,0x1ED) # 0755
chmod(target, 0x1FF-mask) # 0777
......@@ -4,6 +4,8 @@ from distutils import log
import os, re, sys, pkg_resources
from glob import glob
READMES = ('README', 'README.rst', 'README.txt')
entities = [
("&lt;","<"), ("&gt;", ">"), ("&quot;", '"'), ("&apos;", "'"),
("&amp;", "&")
......@@ -97,7 +99,7 @@ def entries_finder(dirname, filename):
for match in entries_pattern.finditer(data):
yield joinpath(dirname,unescape(match.group(1)))
else:
log.warn("unrecognized .svn/entries format in %s", dirname)
log.warn("unrecognized .svn/entries format in %s", os.path.abspath(dirname))
finders = [
......@@ -145,7 +147,17 @@ class sdist(_sdist):
self.filelist = ei_cmd.filelist
self.filelist.append(os.path.join(ei_cmd.egg_info,'SOURCES.txt'))
self.check_readme()
self.check_metadata()
# Run sub commands
for cmd_name in self.get_sub_commands():
self.run_command(cmd_name)
# 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',[])
......@@ -155,7 +167,7 @@ class sdist(_sdist):
dist_files.append(data)
def add_defaults(self):
standards = [('README', 'README.txt'),
standards = [READMES,
self.distribution.script_name]
for fn in standards:
if isinstance(fn, tuple):
......@@ -186,6 +198,14 @@ class sdist(_sdist):
if self.distribution.has_pure_modules():
build_py = self.get_finalized_command('build_py')
self.filelist.extend(build_py.get_source_files())
# This functionality is incompatible with include_package_data, and
# will in fact create an infinite recursion if include_package_data
# is True. Use of include_package_data will imply that
# distutils-style automatic handling of package_data is disabled
if not self.distribution.include_package_data:
for _, src_dir, _, filenames in build_py.data_files:
self.filelist.extend([os.path.join(src_dir, filename)
for filename in filenames])
if self.distribution.has_ext_modules():
build_ext = self.get_finalized_command('build_ext')
......@@ -199,24 +219,33 @@ class sdist(_sdist):
build_scripts = self.get_finalized_command('build_scripts')
self.filelist.extend(build_scripts.get_source_files())
def read_template(self):
def __read_template_hack(self):
# This grody hack closes the template file (MANIFEST.in) if an
# exception occurs during read_template.
# Doing so prevents an error when easy_install attempts to delete the
# file.
try:
_sdist.read_template(self)
except:
# grody hack to close the template file (MANIFEST.in)
# this prevents easy_install's attempt at deleting the file from
# dying and thus masking the real error
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.
if (
sys.version_info < (2,7,2)
or (3,0) <= sys.version_info < (3,1,4)
or (3,2) <= sys.version_info < (3,2,1)
):
read_template = __read_template_hack
def check_readme(self):
alts = ("README", "README.txt")
for f in alts:
for f in READMES:
if os.path.exists(f):
return
else:
self.warn(
"standard file not found: should have one of " +', '.join(alts)
"standard file not found: should have one of " +', '.join(READMES)
)
......@@ -233,7 +262,34 @@ class sdist(_sdist):
self.get_finalized_command('egg_info').save_version_info(dest)
def _manifest_is_not_generated(self):
# check for special comment used in 2.7.1 and higher
if not os.path.isfile(self.manifest):
return False
fp = open(self.manifest, 'rbU')
try:
first_line = fp.readline()
finally:
fp.close()
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
fill in 'self.filelist', the list of files to include in the source
distribution.
"""
log.info("reading manifest file '%s'", self.manifest)
manifest = open(self.manifest, 'rbU')
for line in manifest:
if sys.version_info >= (3,):
line = line.decode('UTF-8')
# ignore comments and blank lines
line = line.strip()
if line.startswith('#') or not line:
continue
self.filelist.append(line)
manifest.close()
......
......@@ -2,6 +2,7 @@ from setuptools import Command
from distutils.errors import DistutilsOptionError
import sys
from pkg_resources import *
from pkg_resources import _namespace_packages
from unittest import TestLoader, main
class ScanningLoader(TestLoader):
......@@ -81,7 +82,7 @@ class test(Command):
def with_project_on_sys_path(self, func):
if getattr(self.distribution, 'use_2to3', False):
if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
# If we run 2to3 we can not do this inplace:
# Ensure metadata is up-to-date
......@@ -139,11 +140,28 @@ class test(Command):
def run_tests(self):
import unittest
# Purge modules under test from sys.modules. The test loader will
# re-import them from the build location. Required when 2to3 is used
# with namespace packages.
if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
module = self.test_args[-1].split('.')[0]
if module in _namespace_packages:
del_modules = []
if module in sys.modules:
del_modules.append(module)
module += '.'
for name in sys.modules:
if name.startswith(module):
del_modules.append(name)
map(sys.modules.__delitem__, del_modules)
loader_ep = EntryPoint.parse("x="+self.test_loader)
loader_class = loader_ep.load(require=False)
cks = loader_class()
unittest.main(
None, None, [unittest.__file__]+self.test_args,
testLoader = loader_class()
testLoader = cks
)
......
......@@ -91,7 +91,7 @@ class upload(Command):
comment = "built on %s" % platform.platform(terse=1)
data = {
':action':'file_upload',
'protcol_version':'1',
'protocol_version':'1',
'name':self.distribution.get_name(),
'version':self.distribution.get_version(),
'content':(basename,content),
......
......@@ -267,6 +267,7 @@ class Distribution(_Distribution):
def fetch_build_egg(self, req):
"""Fetch an egg needed for building"""
try:
cmd = self._egg_fetcher
cmd.package_index.to_scan = []
......@@ -290,7 +291,7 @@ class Distribution(_Distribution):
cmd = easy_install(
dist, args=["x"], install_dir=os.curdir, exclude_scripts=True,
always_copy=False, build_directory=None, editable=False,
upgrade=False, multi_version=True, no_report = True
upgrade=False, multi_version=True, no_report=True, user=False
)
cmd.ensure_finalized()
self._egg_fetcher = cmd
......@@ -642,6 +643,38 @@ class Distribution(_Distribution):
name = name[:-6]
yield name
def handle_display_options(self, option_order):
"""If there were any non-global "display-only" options
(--help-commands or the metadata display options) on the command
line, display the requested info and return true; else return
false.
"""
import sys
if sys.version_info < (3,) or self.help_commands:
return _Distribution.handle_display_options(self, option_order)
# Stdout may be StringIO (e.g. in tests)
import io
if not isinstance(sys.stdout, io.TextIOWrapper):
return _Distribution.handle_display_options(self, option_order)
# Print metadata in UTF-8 no matter the platform
encoding = sys.stdout.encoding
errors = sys.stdout.errors
newline = sys.platform != 'win32' and '\n' or None
line_buffering = sys.stdout.line_buffering
sys.stdout = io.TextIOWrapper(
sys.stdout.detach(), 'utf-8', errors, newline, line_buffering)
try:
return _Distribution.handle_display_options(self, option_order)
finally:
sys.stdout = io.TextIOWrapper(
sys.stdout.detach(), encoding, errors, newline, line_buffering)
# Install it throughout the distutils
for module in distutils.dist, distutils.core, distutils.cmd:
module.Distribution = Distribution
......
from distutils.core import Extension as _Extension
import sys
import distutils.core
import distutils.extension
from setuptools.dist import _get_unpatched
_Extension = _get_unpatched(_Extension)
# Prefer Cython to Pyrex
pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
for pyrex_impl in pyrex_impls:
try:
# from (pyrex_impl) import build_ext
build_ext = __import__(pyrex_impl, fromlist=['build_ext']).build_ext
break
except:
pass
have_pyrex = 'build_ext' in globals()
_Extension = _get_unpatched(distutils.core.Extension)
def have_pyrex():
"""
Return True if Cython or Pyrex can be imported.
"""
pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
for pyrex_impl in pyrex_impls:
try:
# from (pyrex_impl) import build_ext
__import__(pyrex_impl, fromlist=['build_ext']).build_ext
return True
except Exception:
pass
return False
class Extension(_Extension):
"""Extension that uses '.c' files in place of '.pyx' files"""
if not have_pyrex:
# convert .pyx extensions to .c
def __init__(self,*args,**kw):
_Extension.__init__(self,*args,**kw)
sources = []
for s in self.sources:
if s.endswith('.pyx'):
sources.append(s[:-3]+'c')
else:
sources.append(s)
self.sources = sources
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 = map(pyx_to_c, self.sources)
class Library(Extension):
"""Just like a regular Extension, but built as a library instead"""
import sys, distutils.core, distutils.extension
distutils.core.Extension = Extension
distutils.extension.Extension = Extension
if 'distutils.command.build_ext' in sys.modules:
sys.modules['distutils.command.build_ext'].Extension = Extension
No preview for this file type
"""PyPI and direct package downloading"""
import sys, os.path, re, shutil, random, socket
import base64
from pkg_resources import *
from distutils import log
from distutils.errors import DistutilsError
......@@ -201,7 +202,7 @@ class PackageIndex(Environment):
return
self.info("Reading %s", url)
f = self.open_url(url, "Download error: %s -- Some packages may not be found!")
f = self.open_url(url, "Download error on %s: %%s -- Some packages may not be found!" % url)
if f is None: return
self.fetched_urls[url] = self.fetched_urls[f.url] = True
......@@ -764,19 +765,41 @@ def socket_timeout(timeout=15):
return _socket_timeout
return _socket_timeout
def _encode_auth(auth):
"""
A function compatible with Python 2.3-3.3 that will encode
auth from a URL suitable for an HTTP header.
>>> _encode_auth('username%3Apassword')
u'dXNlcm5hbWU6cGFzc3dvcmQ='
"""
auth_s = unquote(auth)
# convert to bytes
auth_bytes = auth_s.encode()
# use the legacy interface for Python 2.3 support
encoded_bytes = base64.encodestring(auth_bytes)
# convert back to a string
encoded = encoded_bytes.decode()
# strip the trailing carriage return
return encoded.rstrip()
def open_with_auth(url):
"""Open a urllib2 request, handling HTTP authentication"""
scheme, netloc, path, params, query, frag = urlparse(url)
# Double scheme does not raise on Mac OS X as revealed by a
# failing test. We would expect "nonnumeric port". Refs #20.
if sys.platform == 'darwin':
if netloc.endswith(':'):
raise httplib.InvalidURL("nonnumeric port: ''")
if scheme in ('http', 'https'):
auth, host = splituser(netloc)
else:
auth = None
if auth:
auth = "Basic " + unquote(auth).encode('base64').strip()
auth = "Basic " + _encode_auth(auth)
new_url = urlunparse((scheme,host,path,params,query,frag))
request = urllib2.Request(new_url)
request.add_header("Authorization", auth)
......
......@@ -42,8 +42,14 @@ def run_setup(setup_script, args):
finally:
pkg_resources.__setstate__(pr_state)
sys.modules.update(save_modules)
for key in list(sys.modules):
if key not in save_modules: del sys.modules[key]
# remove any modules imported within the sandbox
del_modules = [
mod_name for mod_name in sys.modules
if mod_name not in save_modules
# exclude any encodings modules. See #285
and not mod_name.startswith('encodings.')
]
map(sys.modules.__delitem__, del_modules)
os.chdir(old_dir)
sys.path[:] = save_path
sys.argv[:] = save_argv
......@@ -163,12 +169,12 @@ else:
_EXCEPTIONS = []
try:
from win32com.client.gencache import GetGeneratePath
_EXCEPTIONS.append(GetGeneratePath())
del GetGeneratePath
from win32com.client.gencache import GetGeneratePath
_EXCEPTIONS.append(GetGeneratePath())
del GetGeneratePath
except ImportError:
# it appears pywin32 is not installed, so no need to exclude.
pass
# it appears pywin32 is not installed, so no need to exclude.
pass
class DirectorySandbox(AbstractSandbox):
"""Restrict operations to a single subdirectory - pseudo-chroot"""
......
# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r
__requires__ = """%(spec)r"""
from pkg_resources import require; require("""%(spec)r""")
del require
__file__ = """%(dev_path)r"""
execfile(__file__)
# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r
__requires__ = """%(spec)r"""
import pkg_resources
pkg_resources.run_script("""%(spec)r""", """%(script_name)r""")
"""Tests for the 'setuptools' package"""
from unittest import TestSuite, TestCase, makeSuite, defaultTestLoader
import distutils.core, distutils.cmd
import sys
import os
import unittest
import doctest
import distutils.core
import distutils.cmd
from distutils.errors import DistutilsOptionError, DistutilsPlatformError
from distutils.errors import DistutilsSetupError
import setuptools, setuptools.dist
from setuptools import Feature
from distutils.core import Extension
extract_constant, get_module_constant = None, None
from distutils.version import LooseVersion
from setuptools.compat import func_code
from setuptools.depends import *
from distutils.version import StrictVersion, LooseVersion
from distutils.util import convert_path
import sys, os.path
import setuptools.dist
import setuptools.depends as dep
from setuptools import Feature
from setuptools.depends import Require
def additional_tests():
import doctest, unittest
......@@ -36,55 +39,60 @@ def makeSetup(**args):
try:
return setuptools.setup(**args)
finally:
distutils.core_setup_stop_after = None
distutils.core._setup_stop_after = None
class DependsTests(TestCase):
class DependsTests(unittest.TestCase):
def testExtractConst(self):
if not extract_constant: return # skip on non-bytecode platforms
if not hasattr(dep, 'extract_constant'):
# skip on non-bytecode platforms
return
def f1():
global x,y,z
global x, y, z
x = "test"
y = z
fc = func_code(f1)
# unrecognized name
self.assertEqual(extract_constant(fc,'q', -1), None)
self.assertEqual(dep.extract_constant(fc,'q', -1), None)
# constant assigned
self.assertEqual(extract_constant(fc,'x', -1), "test")
self.assertEqual(dep.extract_constant(fc,'x', -1), "test")
# expression assigned
self.assertEqual(extract_constant(fc,'y', -1), -1)
self.assertEqual(dep.extract_constant(fc,'y', -1), -1)
# recognized name, not assigned
self.assertEqual(extract_constant(fc,'z', -1), None)
self.assertEqual(dep.extract_constant(fc,'z', -1), None)
def testFindModule(self):
self.assertRaises(ImportError, find_module, 'no-such.-thing')
self.assertRaises(ImportError, find_module, 'setuptools.non-existent')
f,p,i = find_module('setuptools.tests'); f.close()
self.assertRaises(ImportError, dep.find_module, 'no-such.-thing')
self.assertRaises(ImportError, dep.find_module, 'setuptools.non-existent')
f,p,i = dep.find_module('setuptools.tests')
f.close()
def testModuleExtract(self):
if not get_module_constant: return # skip on non-bytecode platforms
if not hasattr(dep, 'get_module_constant'):
# skip on non-bytecode platforms
return
from email import __version__
self.assertEqual(
get_module_constant('email','__version__'), __version__
dep.get_module_constant('email','__version__'), __version__
)
self.assertEqual(
get_module_constant('sys','version'), sys.version
dep.get_module_constant('sys','version'), sys.version
)
self.assertEqual(
get_module_constant('setuptools.tests','__doc__'),__doc__
dep.get_module_constant('setuptools.tests','__doc__'),__doc__
)
def testRequire(self):
if not extract_constant: return # skip on non-bytecode platforms
if not hasattr(dep, 'extract_constant'):
# skip on non-bytecode platformsh
return
req = Require('Email','1.0.3','email')
......@@ -96,21 +104,21 @@ class DependsTests(TestCase):
from email import __version__
self.assertEqual(req.get_version(), __version__)
self.assert_(req.version_ok('1.0.9'))
self.assert_(not req.version_ok('0.9.1'))
self.assert_(not req.version_ok('unknown'))
self.assertTrue(req.version_ok('1.0.9'))
self.assertTrue(not req.version_ok('0.9.1'))
self.assertTrue(not req.version_ok('unknown'))
self.assert_(req.is_present())
self.assert_(req.is_current())
self.assertTrue(req.is_present())
self.assertTrue(req.is_current())
req = Require('Email 3000','03000','email',format=LooseVersion)
self.assert_(req.is_present())
self.assert_(not req.is_current())
self.assert_(not req.version_ok('unknown'))
self.assertTrue(req.is_present())
self.assertTrue(not req.is_current())
self.assertTrue(not req.version_ok('unknown'))
req = Require('Do-what-I-mean','1.0','d-w-i-m')
self.assert_(not req.is_present())
self.assert_(not req.is_current())
self.assertTrue(not req.is_present())
self.assertTrue(not req.is_current())
req = Require('Tests', None, 'tests', homepage="http://example.com")
self.assertEqual(req.format, None)
......@@ -120,11 +128,11 @@ class DependsTests(TestCase):
self.assertEqual(req.homepage, 'http://example.com')
paths = [os.path.dirname(p) for p in __path__]
self.assert_(req.is_present(paths))
self.assert_(req.is_current(paths))
self.assertTrue(req.is_present(paths))
self.assertTrue(req.is_current(paths))
class DistroTests(TestCase):
class DistroTests(unittest.TestCase):
def setUp(self):
self.e1 = Extension('bar.ext',['bar.c'])
......@@ -137,10 +145,8 @@ class DistroTests(TestCase):
package_dir = {},
)
def testDistroType(self):
self.assert_(isinstance(self.dist,setuptools.dist.Distribution))
self.assertTrue(isinstance(self.dist,setuptools.dist.Distribution))
def testExcludePackage(self):
self.dist.exclude_package('a')
......@@ -159,12 +165,6 @@ class DistroTests(TestCase):
# test removals from unspecified options
makeSetup().exclude_package('x')
def testIncludeExclude(self):
# remove an extension
self.dist.exclude(ext_modules=[self.e1])
......@@ -191,20 +191,17 @@ class DistroTests(TestCase):
dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2])
def testContents(self):
self.assert_(self.dist.has_contents_for('a'))
self.assertTrue(self.dist.has_contents_for('a'))
self.dist.exclude_package('a')
self.assert_(not self.dist.has_contents_for('a'))
self.assertTrue(not self.dist.has_contents_for('a'))
self.assert_(self.dist.has_contents_for('b'))
self.assertTrue(self.dist.has_contents_for('b'))
self.dist.exclude_package('b')
self.assert_(not self.dist.has_contents_for('b'))
self.assertTrue(not self.dist.has_contents_for('b'))
self.assert_(self.dist.has_contents_for('c'))
self.assertTrue(self.dist.has_contents_for('c'))
self.dist.exclude_package('c')
self.assert_(not self.dist.has_contents_for('c'))
self.assertTrue(not self.dist.has_contents_for('c'))
def testInvalidIncludeExclude(self):
self.assertRaises(DistutilsSetupError,
......@@ -234,20 +231,7 @@ class DistroTests(TestCase):
)
class FeatureTests(TestCase):
class FeatureTests(unittest.TestCase):
def setUp(self):
self.req = Require('Distutils','1.0.3','distutils')
......@@ -271,12 +255,12 @@ class FeatureTests(TestCase):
)
def testDefaults(self):
self.assert_(not
self.assertTrue(not
Feature(
"test",standard=True,remove='x',available=False
).include_by_default()
)
self.assert_(
self.assertTrue(
Feature("test",standard=True,remove='x').include_by_default()
)
# Feature must have either kwargs, removes, or require_features
......@@ -290,33 +274,33 @@ class FeatureTests(TestCase):
def testFeatureOptions(self):
dist = self.dist
self.assert_(
self.assertTrue(
('with-dwim',None,'include DWIM') in dist.feature_options
)
self.assert_(
self.assertTrue(
('without-dwim',None,'exclude DWIM (default)') in dist.feature_options
)
self.assert_(
self.assertTrue(
('with-bar',None,'include bar (default)') in dist.feature_options
)
self.assert_(
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.assert_(not 'without-baz' in dist.feature_negopt)
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.assert_(not 'bar_et' in dist.py_modules)
self.assert_(not 'pkg.bar' in dist.packages)
self.assert_('pkg.baz' in dist.packages)
self.assert_('scripts/baz_it' in dist.scripts)
self.assert_(('libfoo','foo/foofoo.c') in dist.libraries)
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])
......@@ -329,11 +313,11 @@ class FeatureTests(TestCase):
SystemExit, makeSetup, features = {'x':Feature('x', remove='y')}
)
class TestCommandTests(TestCase):
class TestCommandTests(unittest.TestCase):
def testTestIsCommand(self):
test_cmd = makeSetup().get_command_obj('test')
self.assert_(isinstance(test_cmd, distutils.cmd.Command))
self.assertTrue(isinstance(test_cmd, distutils.cmd.Command))
def testLongOptSuiteWNoDefault(self):
ts1 = makeSetup(script_args=['test','--test-suite=foo.tests.suite'])
......@@ -365,8 +349,3 @@ class TestCommandTests(TestCase):
ts5 = makeSetup().get_command_obj('test')
ts5.ensure_finalized()
self.assertEqual(ts5.test_suite, None)
import unittest
try:
# provide skipIf for Python 2.4-2.6
skipIf = unittest.skipIf
except AttributeError:
def skipIf(condition, reason):
def skipper(func):
def skip(*args, **kwargs):
return
if condition:
return skip
return func
return skipper
"""Basic http server for tests to simulate PyPI or custom indexes
"""
import sys
from threading import Thread
import time
import threading
import BaseHTTPServer
from setuptools.compat import (urllib2, URLError, HTTPServer,
SimpleHTTPRequestHandler)
......@@ -16,32 +18,64 @@ class IndexServer(HTTPServer):
# The index files should be located in setuptools/tests/indexes
s.stop()
"""
def __init__(self):
HTTPServer.__init__(self, ('', 0), SimpleHTTPRequestHandler)
def __init__(self, server_address=('', 0),
RequestHandlerClass=SimpleHTTPRequestHandler):
HTTPServer.__init__(self, server_address, RequestHandlerClass)
self._run = True
def serve(self):
while True:
while self._run:
self.handle_request()
if not self._run: break
def start(self):
self.thread = Thread(target=self.serve)
self.thread = threading.Thread(target=self.serve)
self.thread.start()
def stop(self):
"""self.shutdown is not supported on python < 2.6"""
"Stop the server"
# Let the server finish the last request and wait for a new one.
time.sleep(0.1)
# self.shutdown is not supported on python < 2.6, so just
# set _run to false, and make a request, causing it to
# terminate.
self._run = False
url = 'http://127.0.0.1:%(server_port)s/' % vars(self)
try:
if sys.version > '2.6':
urllib2.urlopen('http://127.0.0.1:%s/' % self.server_port,
None, 5)
if sys.version_info >= (2, 6):
urllib2.urlopen(url, timeout=5)
else:
urllib2.urlopen('http://127.0.0.1:%s/' % self.server_port)
urllib2.urlopen(url)
except URLError:
# ignore any errors; all that's important is the request
pass
self.thread.join()
def base_url(self):
port = self.server_port
return 'http://127.0.0.1:%s/setuptools/tests/indexes/' % port
class RequestRecorder(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
requests = vars(self.server).setdefault('requests', [])
requests.append(self)
self.send_response(200, 'OK')
class MockServer(HTTPServer, threading.Thread):
"""
A simple HTTP Server that records the requests made to it.
"""
def __init__(self, server_address=('', 0),
RequestHandlerClass=RequestRecorder):
HTTPServer.__init__(self, server_address, RequestHandlerClass)
threading.Thread.__init__(self)
self.setDaemon(True)
self.requests = []
def run(self):
self.serve_forever()
def url(self):
return 'http://localhost:%(server_port)s/' % vars(self)
url = property(url)
"""develop tests
"""
import sys
import os, re, shutil, tempfile, unittest
import tempfile
import site
from StringIO import StringIO
from distutils.errors import DistutilsError
from setuptools.command.bdist_egg import bdist_egg
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
SETUP_PY = """\
from setuptools import setup
setup(name='foo', py_modules=['hi'])
"""
class TestDevelopTest(unittest.TestCase):
def setUp(self):
self.dir = tempfile.mkdtemp()
self.old_cwd = os.getcwd()
os.chdir(self.dir)
f = open('setup.py', 'w')
f.write(SETUP_PY)
f.close()
f = open('hi.py', 'w')
f.write('1\n')
f.close()
if sys.version >= "2.6":
self.old_base = site.USER_BASE
site.USER_BASE = tempfile.mkdtemp()
self.old_site = site.USER_SITE
site.USER_SITE = tempfile.mkdtemp()
def tearDown(self):
os.chdir(self.old_cwd)
shutil.rmtree(self.dir)
if sys.version >= "2.6":
shutil.rmtree(site.USER_BASE)
shutil.rmtree(site.USER_SITE)
site.USER_BASE = self.old_base
site.USER_SITE = self.old_site
def test_bdist_egg(self):
dist = Distribution(dict(
script_name='setup.py',
script_args=['bdist_egg'],
name='foo',
py_modules=['hi']
))
os.makedirs(os.path.join('build', 'src'))
old_stdout = sys.stdout
sys.stdout = o = StringIO()
try:
dist.parse_command_line()
dist.run_commands()
finally:
sys.stdout = old_stdout
# let's see if we got our egg link at the right place
[content] = os.listdir('dist')
self.assertTrue(re.match('foo-0.0.0-py[23].\d.egg$', content))
def test_suite():
return unittest.makeSuite(TestDevelopTest)
......@@ -14,38 +14,62 @@ from setuptools.dist import Distribution
SETUP_PY = """\
from setuptools import setup
setup(name='foo')
setup(name='foo',
packages=['foo'],
use_2to3=True,
)
"""
INIT_PY = """print "foo"
"""
class TestDevelopTest(unittest.TestCase):
def setUp(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return
# Directory structure
self.dir = tempfile.mkdtemp()
os.mkdir(os.path.join(self.dir, 'foo'))
# setup.py
setup = os.path.join(self.dir, 'setup.py')
f = open(setup, 'w')
f.write(SETUP_PY)
f.close()
self.old_cwd = os.getcwd()
# foo/__init__.py
init = os.path.join(self.dir, 'foo', '__init__.py')
f = open(init, 'w')
f.write(INIT_PY)
f.close()
os.chdir(self.dir)
if sys.version >= "2.6":
self.old_base = site.USER_BASE
site.USER_BASE = tempfile.mkdtemp()
self.old_site = site.USER_SITE
site.USER_SITE = tempfile.mkdtemp()
self.old_base = site.USER_BASE
site.USER_BASE = tempfile.mkdtemp()
self.old_site = site.USER_SITE
site.USER_SITE = tempfile.mkdtemp()
def tearDown(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return
os.chdir(self.old_cwd)
shutil.rmtree(self.dir)
if sys.version >= "2.6":
shutil.rmtree(site.USER_BASE)
shutil.rmtree(site.USER_SITE)
site.USER_BASE = self.old_base
site.USER_SITE = self.old_site
shutil.rmtree(site.USER_BASE)
shutil.rmtree(site.USER_SITE)
site.USER_BASE = self.old_base
site.USER_SITE = self.old_site
def test_develop(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return
dist = Distribution()
dist = Distribution(
dict(name='foo',
packages=['foo'],
use_2to3=True,
version='0.0',
))
dist.script_name = 'setup.py'
cmd = develop(dist)
cmd.user = 1
......@@ -53,7 +77,7 @@ class TestDevelopTest(unittest.TestCase):
cmd.install_dir = site.USER_SITE
cmd.user = 1
old_stdout = sys.stdout
sys.stdout = StringIO()
#sys.stdout = StringIO()
try:
cmd.run()
finally:
......@@ -62,9 +86,17 @@ class TestDevelopTest(unittest.TestCase):
# let's see if we got our egg link at the right place
content = os.listdir(site.USER_SITE)
content.sort()
self.assertEquals(content, ['UNKNOWN.egg-link', 'easy-install.pth'])
self.assertEqual(content, ['easy-install.pth', 'foo.egg-link'])
# Check that we are using the right code.
path = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt').read().split()[0].strip()
init = open(os.path.join(path, 'foo', '__init__.py'), 'rt').read().strip()
if sys.version < "3":
self.assertEqual(init, 'print "foo"')
else:
self.assertEqual(init, 'print("foo")')
def test_develop_with_setup_requires(self):
def notest_develop_with_setup_requires(self):
wanted = ("Could not find suitable distribution for "
"Requirement.parse('I-DONT-EXIST')")
......
"""Test .dist-info style distributions.
"""
import os
import shutil
import tempfile
import unittest
import textwrap
try:
import ast
except:
pass
import pkg_resources
from setuptools.tests.py26compat import skipIf
def DALS(s):
"dedent and left-strip"
return textwrap.dedent(s).lstrip()
class TestDistInfo(unittest.TestCase):
def test_distinfo(self):
dists = {}
for d in pkg_resources.find_distributions(self.tmpdir):
dists[d.project_name] = d
assert len(dists) == 2, dists
unversioned = dists['UnversionedDistribution']
versioned = dists['VersionedDistribution']
assert versioned.version == '2.718' # from filename
assert unversioned.version == '0.3' # from METADATA
@skipIf('ast' not in globals(),
"ast is used to test conditional dependencies (Python >= 2.6)")
def test_conditional_dependencies(self):
requires = [pkg_resources.Requirement.parse('splort==4'),
pkg_resources.Requirement.parse('quux>=1.1')]
for d in pkg_resources.find_distributions(self.tmpdir):
self.assertEqual(d.requires(), requires[:1])
self.assertEqual(d.requires(extras=('baz',)), requires)
self.assertEqual(d.extras, ['baz'])
def setUp(self):
self.tmpdir = tempfile.mkdtemp()
versioned = os.path.join(self.tmpdir,
'VersionedDistribution-2.718.dist-info')
os.mkdir(versioned)
open(os.path.join(versioned, 'METADATA'), 'w+').write(DALS(
"""
Metadata-Version: 1.2
Name: VersionedDistribution
Requires-Dist: splort (4)
Provides-Extra: baz
Requires-Dist: quux (>=1.1); extra == 'baz'
"""))
unversioned = os.path.join(self.tmpdir,
'UnversionedDistribution.dist-info')
os.mkdir(unversioned)
open(os.path.join(unversioned, 'METADATA'), 'w+').write(DALS(
"""
Metadata-Version: 1.2
Name: UnversionedDistribution
Version: 0.3
Requires-Dist: splort (==4)
Provides-Extra: baz
Requires-Dist: quux (>=1.1); extra == 'baz'
"""))
def tearDown(self):
shutil.rmtree(self.tmpdir)
"""Easy install Tests
"""
import sys
import os, shutil, tempfile, unittest
import os
import shutil
import tempfile
import unittest
import site
from setuptools.compat import StringIO, next
from setuptools.compat import StringIO, BytesIO, next
from setuptools.compat import urlparse
import textwrap
import tarfile
import distutils.core
from setuptools.sandbox import run_setup, SandboxViolation
from setuptools.command.easy_install import easy_install, get_script_args, main
from setuptools.command.easy_install import PthDistributions
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
from pkg_resources import Distribution as PRDistribution
import setuptools.tests.server
try:
import multiprocessing
# import multiprocessing solely for the purpose of testing its existence
__import__('multiprocessing')
import logging
_LOG = logging.getLogger('test_easy_install')
logging.basicConfig(level=logging.INFO, stream=sys.stderr)
......@@ -58,7 +69,7 @@ class TestEasyInstallTest(unittest.TestCase):
try:
cmd.install_site_py()
sitepy = os.path.join(cmd.install_dir, 'site.py')
self.assert_(os.path.exists(sitepy))
self.assertTrue(os.path.exists(sitepy))
finally:
shutil.rmtree(cmd.install_dir)
......@@ -67,11 +78,11 @@ class TestEasyInstallTest(unittest.TestCase):
old_platform = sys.platform
try:
name, script = next(get_script_args(dist))
name, script = [i for i in next(get_script_args(dist))][0:2]
finally:
sys.platform = old_platform
self.assertEquals(script, WANTED)
self.assertEqual(script, WANTED)
def test_no_setup_cfg(self):
# makes sure easy_install as a command (main)
......@@ -92,7 +103,7 @@ class TestEasyInstallTest(unittest.TestCase):
opts = self.command_options
if 'easy_install' in opts:
assert 'find_links' not in opts['easy_install'], msg
return self._old_parse_command_line
return self._old_parse_command_line()
Distribution._old_parse_command_line = Distribution.parse_command_line
Distribution.parse_command_line = _parse_command_line
......@@ -100,33 +111,36 @@ class TestEasyInstallTest(unittest.TestCase):
old_wd = os.getcwd()
try:
os.chdir(dir)
main([])
reset_setup_stop_context(
lambda: self.assertRaises(SystemExit, main, [])
)
finally:
os.chdir(old_wd)
shutil.rmtree(dir)
Distribution.parse_command_line = Distribution._old_parse_command_line
def test_no_find_links(self):
# new option '--no-find-links', that blocks find-links added at
# the project level
dist = Distribution()
cmd = easy_install(dist)
cmd.check_pth_processing = lambda : True
cmd.check_pth_processing = lambda: True
cmd.no_find_links = True
cmd.find_links = ['link1', 'link2']
cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
cmd.args = ['ok']
cmd.ensure_finalized()
self.assertEquals(cmd.package_index.scanned_urls, {})
self.assertEqual(cmd.package_index.scanned_urls, {})
# let's try without it (default behavior)
cmd = easy_install(dist)
cmd.check_pth_processing = lambda : True
cmd.check_pth_processing = lambda: True
cmd.find_links = ['link1', 'link2']
cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
cmd.args = ['ok']
cmd.ensure_finalized()
keys = sorted(cmd.package_index.scanned_urls.keys())
self.assertEquals(keys, ['link1', 'link2'])
self.assertEqual(keys, ['link1', 'link2'])
class TestPTHFileWriter(unittest.TestCase):
......@@ -135,15 +149,19 @@ class TestPTHFileWriter(unittest.TestCase):
if a distribution is in site but also the cwd
'''
pth = PthDistributions('does-not_exist', [os.getcwd()])
self.assert_(not pth.dirty)
self.assertTrue(not pth.dirty)
pth.add(PRDistribution(os.getcwd()))
self.assert_(pth.dirty)
self.assertTrue(pth.dirty)
def test_add_from_site_is_ignored(self):
pth = PthDistributions('does-not_exist', ['/test/location/does-not-have-to-exist'])
self.assert_(not pth.dirty)
pth.add(PRDistribution('/test/location/does-not-have-to-exist'))
self.assert_(not pth.dirty)
if os.name != 'nt':
location = '/test/location/does-not-have-to-exist'
else:
location = 'c:\\does_not_exist'
pth = PthDistributions('does-not_exist', [location, ])
self.assertTrue(not pth.dirty)
pth.add(PRDistribution(location))
self.assertTrue(not pth.dirty)
class TestUserInstallTest(unittest.TestCase):
......@@ -168,7 +186,7 @@ class TestUserInstallTest(unittest.TestCase):
def tearDown(self):
os.chdir(self.old_cwd)
shutil.rmtree(self.dir)
if sys.version >= "2.6":
if sys.version >= "2.6":
shutil.rmtree(site.USER_BASE)
shutil.rmtree(site.USER_SITE)
site.USER_BASE = self.old_base
......@@ -220,7 +238,7 @@ class TestUserInstallTest(unittest.TestCase):
sys.path.append(target)
old_ppath = os.environ.get('PYTHONPATH')
os.environ['PYTHONPATH'] = ':'.join(sys.path)
os.environ['PYTHONPATH'] = os.path.pathsep.join(sys.path)
try:
dist = Distribution()
dist.script_name = 'setup.py'
......@@ -230,13 +248,212 @@ class TestUserInstallTest(unittest.TestCase):
cmd.ensure_finalized()
cmd.local_index.scan([new_location])
res = cmd.easy_install('foo')
self.assertEquals(res.location, new_location)
self.assertEqual(os.path.realpath(res.location),
os.path.realpath(new_location))
finally:
sys.path.remove(target)
shutil.rmtree(new_location)
shutil.rmtree(target)
for basedir in [new_location, target, ]:
if not os.path.exists(basedir) or not os.path.isdir(basedir):
continue
try:
shutil.rmtree(basedir)
except:
pass
if old_ppath is not None:
os.environ['PYTHONPATH'] = old_ppath
else:
del os.environ['PYTHONPATH']
def test_setup_requires(self):
"""Regression test for issue #318
Ensures that a package with setup_requires can be installed when
distribute is installed in the user site-packages without causing a
SandboxViolation.
"""
test_setup_attrs = {
'name': 'test_pkg', 'version': '0.0',
'setup_requires': ['foobar'],
'dependency_links': [os.path.abspath(self.dir)]
}
test_pkg = os.path.join(self.dir, 'test_pkg')
test_setup_py = os.path.join(test_pkg, 'setup.py')
test_setup_cfg = os.path.join(test_pkg, 'setup.cfg')
os.mkdir(test_pkg)
f = open(test_setup_py, 'w')
f.write(textwrap.dedent("""\
import setuptools
setuptools.setup(**%r)
""" % test_setup_attrs))
f.close()
foobar_path = os.path.join(self.dir, 'foobar-0.1.tar.gz')
make_trivial_sdist(
foobar_path,
textwrap.dedent("""\
import setuptools
setuptools.setup(
name='foobar',
version='0.1'
)
"""))
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StringIO()
sys.stderr = StringIO()
try:
reset_setup_stop_context(
lambda: run_setup(test_setup_py, ['install'])
)
except SandboxViolation:
self.fail('Installation caused SandboxViolation')
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
class TestSetupRequires(unittest.TestCase):
def test_setup_requires_honors_fetch_params(self):
"""
When easy_install installs a source distribution which specifies
setup_requires, it should honor the fetch parameters (such as
allow-hosts, index-url, and find-links).
"""
# set up a server which will simulate an alternate package index.
p_index = setuptools.tests.server.MockServer()
p_index.start()
netloc = 1
p_index_loc = urlparse(p_index.url)[netloc]
if p_index_loc.endswith(':0'):
# Some platforms (Jython) don't find a port to which to bind,
# so skip this test for them.
return
# I realize this is all-but-impossible to read, because it was
# ported from some well-factored, safe code using 'with'. If you
# need to maintain this code, consider making the changes in
# the parent revision (of this comment) and then port the changes
# back for Python 2.4 (or deprecate Python 2.4).
def install(dist_file):
def install_at(temp_install_dir):
def install_env():
ei_params = ['--index-url', p_index.url,
'--allow-hosts', p_index_loc,
'--exclude-scripts', '--install-dir', temp_install_dir,
dist_file]
def install_clean_reset():
def install_clean_argv():
# attempt to install the dist. It should fail because
# it doesn't exist.
self.assertRaises(SystemExit,
easy_install_pkg.main, ei_params)
argv_context(install_clean_argv, ['easy_install'])
reset_setup_stop_context(install_clean_reset)
environment_context(install_env, PYTHONPATH=temp_install_dir)
tempdir_context(install_at)
# create an sdist that has a build-time dependency.
self.create_sdist(install)
# there should have been two or three requests to the server
# (three happens on Python 3.3a)
self.assertTrue(2 <= len(p_index.requests) <= 3)
self.assertEqual(p_index.requests[0].path, '/does-not-exist/')
def create_sdist(self, installer):
"""
Create an sdist with a setup_requires dependency (of something that
doesn't exist) and invoke installer on it.
"""
def build_sdist(dir):
dist_path = os.path.join(dir, 'distribute-test-fetcher-1.0.tar.gz')
make_trivial_sdist(
dist_path,
textwrap.dedent("""
import setuptools
setuptools.setup(
name="distribute-test-fetcher",
version="1.0",
setup_requires = ['does-not-exist'],
)
""").lstrip())
installer(dist_path)
tempdir_context(build_sdist)
def make_trivial_sdist(dist_path, setup_py):
"""Create a simple sdist tarball at dist_path, containing just a
setup.py, the contents of which are provided by the setup_py string.
"""
setup_py_file = tarfile.TarInfo(name='setup.py')
try:
# Python 3 (StringIO gets converted to io module)
MemFile = BytesIO
except AttributeError:
MemFile = StringIO
setup_py_bytes = MemFile(setup_py.encode('utf-8'))
setup_py_file.size = len(setup_py_bytes.getvalue())
dist = tarfile.open(dist_path, 'w:gz')
try:
dist.addfile(setup_py_file, fileobj=setup_py_bytes)
finally:
dist.close()
def tempdir_context(f, cd=lambda dir:None):
"""
Invoke f in the context
"""
temp_dir = tempfile.mkdtemp()
orig_dir = os.getcwd()
try:
cd(temp_dir)
f(temp_dir)
finally:
cd(orig_dir)
shutil.rmtree(temp_dir)
def environment_context(f, **updates):
"""
Invoke f in the context
"""
old_env = os.environ.copy()
os.environ.update(updates)
try:
f()
finally:
for key in updates:
del os.environ[key]
os.environ.update(old_env)
def argv_context(f, repl):
"""
Invoke f in the context
"""
old_argv = sys.argv[:]
sys.argv[:] = repl
try:
f()
finally:
sys.argv[:] = old_argv
def reset_setup_stop_context(f):
"""
When the distribute tests are run using setup.py test, and then
one wants to invoke another setup() command (such as easy_install)
within those tests, it's necessary to reset the global variable
in distutils.core so that the setup() command will run naturally.
"""
setup_stop_after = distutils.core._setup_stop_after
distutils.core._setup_stop_after = None
try:
f()
finally:
distutils.core._setup_stop_after = setup_stop_after
import os
import unittest
from setuptools.tests.py26compat import skipIf
try:
import ast
except ImportError:
pass
class TestMarkerlib(unittest.TestCase):
@skipIf('ast' not in globals(),
"ast not available (Python < 2.6?)")
def test_markers(self):
from _markerlib import interpret, default_environment, compile
os_name = os.name
self.assert_(interpret(""))
self.assert_(interpret("os.name != 'buuuu'"))
self.assert_(interpret("python_version > '1.0'"))
self.assert_(interpret("python_version < '5.0'"))
self.assert_(interpret("python_version <= '5.0'"))
self.assert_(interpret("python_version >= '1.0'"))
self.assert_(interpret("'%s' in os.name" % os_name))
self.assert_(interpret("'buuuu' not in os.name"))
self.assertFalse(interpret("os.name == 'buuuu'"))
self.assertFalse(interpret("python_version < '1.0'"))
self.assertFalse(interpret("python_version > '5.0'"))
self.assertFalse(interpret("python_version >= '5.0'"))
self.assertFalse(interpret("python_version <= '1.0'"))
self.assertFalse(interpret("'%s' not in os.name" % os_name))
self.assertFalse(interpret("'buuuu' in os.name and python_version >= '5.0'"))
environment = default_environment()
environment['extra'] = 'test'
self.assert_(interpret("extra == 'test'", environment))
self.assertFalse(interpret("extra == 'doc'", environment))
def raises_nameError():
try:
interpret("python.version == '42'")
except NameError:
pass
else:
raise Exception("Expected NameError")
raises_nameError()
def raises_syntaxError():
try:
interpret("(x for x in (4,))")
except SyntaxError:
pass
else:
raise Exception("Expected SyntaxError")
raises_syntaxError()
statement = "python_version == '5'"
self.assertEqual(compile(statement).__doc__, statement)
"""Package Index Tests
"""
# More would be better!
import sys
import os, shutil, tempfile, unittest
import unittest
import pkg_resources
from setuptools.compat import urllib2, httplib, HTTPError
import distutils.errors
import setuptools.package_index
from setuptools.tests.server import IndexServer
class TestPackageIndex(unittest.TestCase):
def test_bad_urls(self):
def test_bad_url_bad_port(self):
index = setuptools.package_index.PackageIndex()
url = 'http://127.0.0.1:0/nonesuch/test_package_index'
try:
v = index.open_url(url)
except Exception:
v = sys.exc_info()[1]
self.assert_(url in str(v))
self.assertTrue(url in str(v))
else:
self.assert_(isinstance(v, HTTPError))
self.assertTrue(isinstance(v, HTTPError))
def test_bad_url_typo(self):
# issue 16
# easy_install inquant.contentmirror.plone breaks because of a typo
# in its home URL
......@@ -33,9 +34,14 @@ class TestPackageIndex(unittest.TestCase):
v = index.open_url(url)
except Exception:
v = sys.exc_info()[1]
self.assert_(url in str(v))
self.assertTrue(url in str(v))
else:
self.assert_(isinstance(v, HTTPError))
self.assertTrue(isinstance(v, HTTPError))
def test_bad_url_bad_status_line(self):
index = setuptools.package_index.PackageIndex(
hosts=('www.example.com',)
)
def _urlopen(*args):
raise httplib.BadStatusLine('line')
......@@ -48,20 +54,35 @@ class TestPackageIndex(unittest.TestCase):
v = index.open_url(url)
except Exception:
v = sys.exc_info()[1]
self.assert_('line' in str(v))
self.assertTrue('line' in str(v))
else:
raise AssertionError('Should have raise here!')
finally:
urllib2.urlopen = old_urlopen
def test_bad_url_double_scheme(self):
"""
A bad URL with a double scheme should raise a DistutilsError.
"""
index = setuptools.package_index.PackageIndex(
hosts=('www.example.com',)
)
# issue 20
url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk'
try:
index.open_url(url)
except Exception:
v = sys.exc_info()[1]
self.assert_('nonnumeric port' in str(v))
except distutils.errors.DistutilsError:
error = sys.exc_info()[1]
msg = unicode(error)
assert 'nonnumeric port' in msg or 'getaddrinfo failed' in msg or 'Name or service not known' in msg
return
raise RuntimeError("Did not raise")
def test_bad_url_screwy_href(self):
index = setuptools.package_index.PackageIndex(
hosts=('www.example.com',)
)
# issue #160
if sys.version_info[0] == 2 and sys.version_info[1] == 7:
......@@ -71,13 +92,12 @@ class TestPackageIndex(unittest.TestCase):
'http://www.famfamfam.com/">')
index.process_index(url, page)
def test_url_ok(self):
index = setuptools.package_index.PackageIndex(
hosts=('www.example.com',)
)
url = 'file:///tmp/test_package_index'
self.assert_(index.url_ok(url, True))
self.assertTrue(index.url_ok(url, True))
def test_links_priority(self):
"""
......@@ -94,6 +114,10 @@ class TestPackageIndex(unittest.TestCase):
is used
-> Distribute should use the link from pypi, not the external one.
"""
if sys.platform.startswith('java'):
# Skip this test on jython because binding to :0 fails
return
# start an index server
server = IndexServer()
server.start()
......@@ -106,11 +130,11 @@ class TestPackageIndex(unittest.TestCase):
server.stop()
# the distribution has been found
self.assert_('foobar' in pi)
self.assertTrue('foobar' in pi)
# we have only one link, because links are compared without md5
self.assert_(len(pi['foobar'])==1)
self.assertTrue(len(pi['foobar'])==1)
# the link should be from the index
self.assert_('correct_md5' in pi['foobar'][0].location)
self.assertTrue('correct_md5' in pi['foobar'][0].location)
def test_parse_bdist_wininst(self):
self.assertEqual(setuptools.package_index.parse_bdist_wininst(
......@@ -121,5 +145,3 @@ class TestPackageIndex(unittest.TestCase):
'reportlab-2.5.win-amd64-py2.7.exe'), ('reportlab-2.5', '2.7', 'win-amd64'))
self.assertEqual(setuptools.package_index.parse_bdist_wininst(
'reportlab-2.5.win-amd64.exe'), ('reportlab-2.5', None, 'win-amd64'))
......@@ -9,6 +9,16 @@ try: frozenset
except NameError:
from sets import ImmutableSet as frozenset
def safe_repr(obj, short=False):
""" copied from Python2.7"""
try:
result = repr(obj)
except Exception:
result = object.__repr__(obj)
if not short or len(result) < _MAX_LENGTH:
return result
return result[:_MAX_LENGTH] + ' [truncated]...'
class Metadata(EmptyProvider):
"""Mock object to return metadata as if from an on-disk distribution"""
......@@ -36,7 +46,7 @@ class DistroTests(TestCase):
ad.add(Distribution.from_filename("FooPkg-1.2-py2.4.egg"))
# Name is in there now
self.assert_(ad['FooPkg'])
self.assertTrue(ad['FooPkg'])
# But only 1 package
self.assertEqual(list(ad), ['foopkg'])
......@@ -219,7 +229,7 @@ class EntryPointTests(TestCase):
self.assertEqual(ep.module_name,"setuptools.tests.test_resources")
self.assertEqual(ep.attrs, ("EntryPointTests",))
self.assertEqual(ep.extras, ("x",))
self.assert_(ep.load() is EntryPointTests)
self.assertTrue(ep.load() is EntryPointTests)
self.assertEqual(
str(ep),
"foo = setuptools.tests.test_resources:EntryPointTests [x]"
......@@ -319,20 +329,20 @@ class RequirementsTests(TestCase):
foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg")
twist11 = Distribution.from_filename("Twisted-1.1.egg")
twist12 = Distribution.from_filename("Twisted-1.2.egg")
self.assert_(parse_version('1.2') in r)
self.assert_(parse_version('1.1') not in r)
self.assert_('1.2' in r)
self.assert_('1.1' not in r)
self.assert_(foo_dist not in r)
self.assert_(twist11 not in r)
self.assert_(twist12 in r)
self.assertTrue(parse_version('1.2') in r)
self.assertTrue(parse_version('1.1') not in r)
self.assertTrue('1.2' in r)
self.assertTrue('1.1' not in r)
self.assertTrue(foo_dist not in r)
self.assertTrue(twist11 not in r)
self.assertTrue(twist12 in r)
def testAdvancedContains(self):
r, = parse_requirements("Foo>=1.2,<=1.3,==1.9,>2.0,!=2.5,<3.0,==4.5")
for v in ('1.2','1.2.2','1.3','1.9','2.0.1','2.3','2.6','3.0c1','4.5'):
self.assert_(v in r, (v,r))
self.assertTrue(v in r, (v,r))
for v in ('1.2c1','1.3.1','1.5','1.9.1','2.0','2.5','3.0','4.0'):
self.assert_(v not in r, (v,r))
self.assertTrue(v not in r, (v,r))
def testOptionsAndHashing(self):
......@@ -354,14 +364,14 @@ class RequirementsTests(TestCase):
r2 = Requirement.parse("foo!=0.3a4")
d = Distribution.from_filename
self.assert_(d("foo-0.3a4.egg") not in r1)
self.assert_(d("foo-0.3a1.egg") not in r1)
self.assert_(d("foo-0.3a4.egg") not in r2)
self.assertTrue(d("foo-0.3a4.egg") not in r1)
self.assertTrue(d("foo-0.3a1.egg") not in r1)
self.assertTrue(d("foo-0.3a4.egg") not in r2)
self.assert_(d("foo-0.3a2.egg") in r1)
self.assert_(d("foo-0.3a2.egg") in r2)
self.assert_(d("foo-0.3a3.egg") in r2)
self.assert_(d("foo-0.3a5.egg") in r2)
self.assertTrue(d("foo-0.3a2.egg") in r1)
self.assertTrue(d("foo-0.3a2.egg") in r2)
self.assertTrue(d("foo-0.3a3.egg") in r2)
self.assertTrue(d("foo-0.3a5.egg") in r2)
def testDistributeSetuptoolsOverride(self):
# Plain setuptools or distribute mean we return distribute.
......@@ -468,27 +478,29 @@ class ParseTests(TestCase):
p1, p2 = parse_version(s1),parse_version(s2)
self.assertEqual(p1,p2, (s1,s2,p1,p2))
c('1.2-rc1', '1.2rc1')
c('0.4', '0.4.0')
c('0.4.0.0', '0.4.0')
c('0.4.0-0', '0.4-0')
c('0pl1', '0.0pl1')
c('0pre1', '0.0c1')
c('0.0.0preview1', '0c1')
c('0.0c1', '0-rc1')
c('0.0c1', '0rc1')
c('1.2a1', '1.2.a.1'); c('1.2...a', '1.2a')
def testVersionOrdering(self):
def c(s1,s2):
p1, p2 = parse_version(s1),parse_version(s2)
self.assert_(p1<p2, (s1,s2,p1,p2))
self.assertTrue(p1<p2, (s1,s2,p1,p2))
c('2.1','2.1.1')
c('2.1.0','2.10')
c('2a1','2b0')
c('2b1','2c0')
c('2a1','2.1')
c('2.3a1', '2.3')
c('2.1-1', '2.1-2')
c('2.1-1', '2.1.1')
c('2.1', '2.1.1-1')
c('2.1', '2.1pl4')
c('2.1a0-20040501', '2.1')
c('1.1', '02.1')
......@@ -499,8 +511,20 @@ class ParseTests(TestCase):
c('0.4', '4.0')
c('0.0.4', '0.4.0')
c('0pl1', '0.4pl1')
c('2.1.0-rc1','2.1.0')
c('2.1dev','2.1a0')
c('2.1.0rc1','2.1.0')
c('2.1.0','2.1.0-rc0')
c('2.1.0','2.1.0-a')
c('2.1.0','2.1.0-alpha')
c('2.1.0','2.1.0-foo')
c('1.0','1.0-1')
c('1.0-1','1.0.1')
c('1.0a','1.0b')
c('1.0dev','1.0rc1')
c('1.0pre','1.0')
c('1.0pre','1.0')
c('1.0a','1.0-a')
c('1.0rc1','1.0-rc1')
torture ="""
0.80.1-3 0.80.1-2 0.80.1-1 0.79.9999+0.80.0pre4-1
......@@ -554,12 +578,12 @@ class ScriptHeaderTests(TestCase):
self.assertEqual(get_script_header('#!/usr/bin/python -x',
executable=exe),
'#!%s -x\n' % exe)
self.assert_('Unable to adapt shebang line' in sys.stdout.getvalue())
self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalue())
sys.stdout = sys.stderr = StringIO()
self.assertEqual(get_script_header('#!/usr/bin/python',
executable=self.non_ascii_exe),
'#!%s -x\n' % self.non_ascii_exe)
self.assert_('Unable to adapt shebang line' in sys.stdout.getvalue())
self.assertTrue('Unable to adapt shebang line' in sys.stdout.getvalue())
finally:
sys.platform = platform
sys.stdout = stdout
......@@ -581,6 +605,13 @@ class NamespaceTests(TestCase):
pkg_resources._namespace_packages = self._ns_pkgs.copy()
sys.path = self._prev_sys_path[:]
def _assertIn(self, member, container):
""" assertIn and assertTrue does not exist in Python2.3"""
if member not in container:
standardMsg = '%s not found in %s' % (safe_repr(member),
safe_repr(container))
self.fail(self._formatMessage(msg, standardMsg))
def test_two_levels_deep(self):
"""
Test nested namespace packages
......@@ -604,13 +635,13 @@ class NamespaceTests(TestCase):
pkg2_init.write(ns_str)
pkg2_init.close()
import pkg1
self.assertTrue("pkg1" in pkg_resources._namespace_packages.keys())
self._assertIn("pkg1", pkg_resources._namespace_packages.keys())
try:
import pkg1.pkg2
except ImportError:
self.fail("Distribute tried to import the parent namespace package")
# check the _namespace_packages dict
self.assertTrue("pkg1.pkg2" in pkg_resources._namespace_packages.keys())
self._assertIn("pkg1.pkg2", pkg_resources._namespace_packages.keys())
self.assertEqual(pkg_resources._namespace_packages["pkg1"], ["pkg1.pkg2"])
# check the __path__ attribute contains both paths
self.assertEqual(pkg1.pkg2.__path__, [
......
# -*- coding: utf-8 -*-
"""sdist tests"""
import os
import shutil
import sys
import tempfile
import unittest
from StringIO import StringIO
from setuptools.command.sdist import sdist
from setuptools.dist import Distribution
SETUP_ATTRS = {
'name': 'sdist_test',
'version': '0.0',
'packages': ['sdist_test'],
'package_data': {'sdist_test': ['*.txt']}
}
SETUP_PY = """\
from setuptools import setup
setup(**%r)
""" % SETUP_ATTRS
class TestSdistTest(unittest.TestCase):
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
f = open(os.path.join(self.temp_dir, 'setup.py'), 'w')
f.write(SETUP_PY)
f.close()
# Set up the rest of the test package
test_pkg = os.path.join(self.temp_dir, 'sdist_test')
os.mkdir(test_pkg)
# *.rst was not included in package_data, so c.rst should not be
# automatically added to the manifest when not under version control
for fname in ['__init__.py', 'a.txt', 'b.txt', 'c.rst']:
# Just touch the files; their contents are irrelevant
open(os.path.join(test_pkg, fname), 'w').close()
self.old_cwd = os.getcwd()
os.chdir(self.temp_dir)
def tearDown(self):
os.chdir(self.old_cwd)
shutil.rmtree(self.temp_dir)
def test_package_data_in_sdist(self):
"""Regression test for pull request #4: ensures that files listed in
package_data are included in the manifest even if they're not added to
version control.
"""
dist = Distribution(SETUP_ATTRS)
dist.script_name = 'setup.py'
cmd = sdist(dist)
cmd.ensure_finalized()
# squelch output
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StringIO()
sys.stderr = StringIO()
try:
cmd.run()
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
manifest = cmd.filelist.files
self.assertTrue(os.path.join('sdist_test', 'a.txt') in manifest)
self.assertTrue(os.path.join('sdist_test', 'b.txt') in manifest)
self.assertTrue(os.path.join('sdist_test', 'c.rst') not in manifest)
def test_filelist_is_fully_composed(self):
# Test for #303. Requires HFS Plus to fail.
# Add file with non-ASCII filename
filename = os.path.join('sdist_test', 'smörbröd.py')
open(filename, 'w').close()
dist = Distribution(SETUP_ATTRS)
dist.script_name = 'setup.py'
cmd = sdist(dist)
cmd.ensure_finalized()
# squelch output
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StringIO()
sys.stderr = StringIO()
try:
cmd.run()
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
self.assertTrue(filename in cmd.filelist.files)
def test_manifest_is_written_in_utf8(self):
# Test for #303.
# Add file with non-ASCII filename
filename = os.path.join('sdist_test', 'smörbröd.py')
open(filename, 'w').close()
dist = Distribution(SETUP_ATTRS)
dist.script_name = 'setup.py'
cmd = sdist(dist)
cmd.ensure_finalized()
# squelch output
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StringIO()
sys.stderr = StringIO()
try:
cmd.run()
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
manifest = open(os.path.join('sdist_test.egg-info', 'SOURCES.txt'), 'rbU')
contents = manifest.read()
manifest.close()
self.assertTrue(len(contents))
# This must not fail:
contents.decode('UTF-8')
def test_manifest_is_read_in_utf8(self):
# Test for #303.
# Add file with non-ASCII filename
filename = os.path.join('sdist_test', 'smörbröd.py')
open(filename, 'w').close()
dist = Distribution(SETUP_ATTRS)
dist.script_name = 'setup.py'
cmd = sdist(dist)
cmd.ensure_finalized()
# squelch output
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StringIO()
sys.stderr = StringIO()
try:
cmd.run()
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
cmd.filelist.files = []
cmd.manifest = os.path.join('sdist_test.egg-info', 'SOURCES.txt')
cmd.read_manifest()
self.assertTrue(filename in cmd.filelist.files)
def test_suite():
return unittest.defaultTestLoader.loadTestsFromName(__name__)
# -*- coding: UTF-8 -*-
"""develop tests
"""
import sys
import os, shutil, tempfile, unittest
import tempfile
import site
from StringIO import StringIO
from distutils.errors import DistutilsError
from setuptools.command.test import test
from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution
SETUP_PY = """\
from setuptools import setup
setup(name='foo',
packages=['name', 'name.space', 'name.space.tests'],
namespace_packages=['name'],
test_suite='name.space.tests.test_suite',
)
"""
NS_INIT = """# -*- coding: Latin-1 -*-
# Söme Arbiträry Ünicode to test Issüé 310
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
"""
# Make sure this is Latin-1 binary, before writing:
if sys.version_info < (3,):
NS_INIT = NS_INIT.decode('UTF-8')
NS_INIT = NS_INIT.encode('Latin-1')
TEST_PY = """import unittest
class TestTest(unittest.TestCase):
def test_test(self):
print "Foo" # Should fail under Python 3 unless 2to3 is used
test_suite = unittest.makeSuite(TestTest)
"""
class TestTestTest(unittest.TestCase):
def setUp(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return
# Directory structure
self.dir = tempfile.mkdtemp()
os.mkdir(os.path.join(self.dir, 'name'))
os.mkdir(os.path.join(self.dir, 'name', 'space'))
os.mkdir(os.path.join(self.dir, 'name', 'space', 'tests'))
# setup.py
setup = os.path.join(self.dir, 'setup.py')
f = open(setup, 'wt')
f.write(SETUP_PY)
f.close()
self.old_cwd = os.getcwd()
# name/__init__.py
init = os.path.join(self.dir, 'name', '__init__.py')
f = open(init, 'wb')
f.write(NS_INIT)
f.close()
# name/space/__init__.py
init = os.path.join(self.dir, 'name', 'space', '__init__.py')
f = open(init, 'wt')
f.write('#empty\n')
f.close()
# name/space/tests/__init__.py
init = os.path.join(self.dir, 'name', 'space', 'tests', '__init__.py')
f = open(init, 'wt')
f.write(TEST_PY)
f.close()
os.chdir(self.dir)
self.old_base = site.USER_BASE
site.USER_BASE = tempfile.mkdtemp()
self.old_site = site.USER_SITE
site.USER_SITE = tempfile.mkdtemp()
def tearDown(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return
os.chdir(self.old_cwd)
shutil.rmtree(self.dir)
shutil.rmtree(site.USER_BASE)
shutil.rmtree(site.USER_SITE)
site.USER_BASE = self.old_base
site.USER_SITE = self.old_site
def test_test(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return
dist = Distribution(dict(
name='foo',
packages=['name', 'name.space', 'name.space.tests'],
namespace_packages=['name'],
test_suite='name.space.tests.test_suite',
use_2to3=True,
))
dist.script_name = 'setup.py'
cmd = test(dist)
cmd.user = 1
cmd.ensure_finalized()
cmd.install_dir = site.USER_SITE
cmd.user = 1
old_stdout = sys.stdout
sys.stdout = StringIO()
try:
try: # try/except/finally doesn't work in Python 2.4, so we need nested try-statements.
cmd.run()
except SystemExit: # The test runner calls sys.exit, stop that making an error.
pass
finally:
sys.stdout = old_stdout
\ No newline at end of file
def __boot():
import sys, imp, os, os.path
import sys, os, os.path
PYTHONPATH = os.environ.get('PYTHONPATH')
if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH):
PYTHONPATH = []
......@@ -23,6 +23,7 @@ def __boot():
break
else:
try:
import imp # Avoid import loop in Python >= 3.3
stream, path, descr = imp.find_module('site',[item])
except ImportError:
continue
......
#!/bin/sh
echo -n "Running tests for Python 2.3..."
python2.3 setup.py -q test > /dev/null 2> /dev/null
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
......@@ -8,8 +8,8 @@ else
echo "Success"
fi
echo -n "Running tests for Python 2.4..."
python2.4 setup.py -q test > /dev/null 2> /dev/null
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
......@@ -17,8 +17,8 @@ else
echo "Success"
fi
echo -n "Running tests for Python 2.5..."
python2.5 setup.py -q test > /dev/null 2> /dev/null
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
......@@ -26,8 +26,8 @@ else
echo "Success"
fi
echo -n "Running tests for Python 2.6..."
python2.6 setup.py -q test > /dev/null 2> /dev/null
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
......@@ -45,3 +45,23 @@ 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
......@@ -43,13 +43,13 @@ class TestSetup(unittest.TestCase):
# now trying to import it
sys.path[0] = egg
import setuptools
self.assert_(setuptools.__file__.startswith(egg))
self.assertTrue(setuptools.__file__.startswith(egg))
def test_do_download(self):
tmpdir = tempfile.mkdtemp()
_do_download(DEFAULT_VERSION, DEFAULT_URL, tmpdir, 1)
import setuptools
self.assert_(setuptools.bootstrap_install_from.startswith(tmpdir))
self.assertTrue(setuptools.bootstrap_install_from.startswith(tmpdir))
def test_install(self):
def _faked(*args):
......@@ -58,7 +58,7 @@ class TestSetup(unittest.TestCase):
_install(self.tarball)
def test_use_setuptools(self):
self.assertEquals(use_setuptools(), None)
self.assertEqual(use_setuptools(), None)
# make sure fake_setuptools is not called by default
import pkg_resources
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment