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 ...@@ -26,3 +26,14 @@ dae247400d0ca1fdfaf38db275622c9bec550b08 0.6.13
0502d5117d8304ab21084912758ed28812a5a8f1 0.6.17 0502d5117d8304ab21084912758ed28812a5a8f1 0.6.17
74108d7f07343556a8db94e8122221a43243f586 0.6.18 74108d7f07343556a8db94e8122221a43243f586 0.6.18
611910892a0421633d72677979f94a25ef590d54 0.6.19 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 @@ ...@@ -2,11 +2,112 @@
CHANGES 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 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 0.6.19
......
...@@ -7,14 +7,20 @@ Contributors ...@@ -7,14 +7,20 @@ Contributors
* Arfrever Frehtes Taifersar Arahesis * Arfrever Frehtes Taifersar Arahesis
* Christophe Combelles * Christophe Combelles
* Daniel Stutzbach * Daniel Stutzbach
* Daniel Holth
* Hanno Schlichting * Hanno Schlichting
* Jannis Leidel * Jannis Leidel
* Jason R. Coombs
* Jim Fulton
* Justin Azoff
* Lennart Regebro * Lennart Regebro
* Marc Abramowitz
* Martin von Löwis * Martin von Löwis
* Noufal Ibrahim * Noufal Ibrahim
* Philip Jenvey * Philip Jenvey
* Reinout van Rees * Reinout van Rees
* Robert Myers * Robert Myers
* Stefan H. Holek
* Tarek Ziadé * Tarek Ziadé
* Toshio Kuratomi * Toshio Kuratomi
......
...@@ -6,22 +6,16 @@ Distribute is using Mercurial. ...@@ -6,22 +6,16 @@ Distribute is using Mercurial.
Grab the code at bitbucket:: 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 - add a note in CHANGES.txt
And remember that 0.6 is only bug fixes, and the APIs should And remember that 0.6 (the only development line) is only bug fixes, and the
be fully backward compatible with Setuptools. APIs should be fully backward compatible with Setuptools.
You can run the tests via:: You can run the tests via::
......
...@@ -2,6 +2,7 @@ recursive-include setuptools *.py *.txt *.exe ...@@ -2,6 +2,7 @@ recursive-include setuptools *.py *.txt *.exe
recursive-include tests *.py *.c *.pyx *.txt recursive-include tests *.py *.c *.pyx *.txt
recursive-include setuptools/tests *.html recursive-include setuptools/tests *.html
recursive-include docs *.py *.txt *.conf *.css *.css_t Makefile indexsidebar.html recursive-include docs *.py *.txt *.conf *.css *.css_t Makefile indexsidebar.html
recursive-include _markerlib *.py
include *.py include *.py
include *.txt include *.txt
include MANIFEST.in include MANIFEST.in
......
...@@ -99,9 +99,9 @@ Source installation ...@@ -99,9 +99,9 @@ Source installation
Download the source tarball, uncompress it, then run the install command:: 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 $ curl -O http://pypi.python.org/packages/source/d/distribute/distribute-0.6.29.tar.gz
$ tar -xzvf distribute-0.6.20.tar.gz $ tar -xzvf distribute-0.6.29.tar.gz
$ cd distribute-0.6.20 $ cd distribute-0.6.29
$ python setup.py install $ 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 ...@@ -19,6 +19,8 @@ import time
import fnmatch import fnmatch
import tempfile import tempfile
import tarfile import tarfile
import optparse
from distutils import log from distutils import log
try: try:
...@@ -46,7 +48,7 @@ except ImportError: ...@@ -46,7 +48,7 @@ except ImportError:
args = [quote(arg) for arg in args] args = [quote(arg) for arg in args]
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 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/" DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
SETUPTOOLS_FAKED_VERSION = "0.6c11" SETUPTOOLS_FAKED_VERSION = "0.6c11"
...@@ -63,7 +65,7 @@ Description: xxx ...@@ -63,7 +65,7 @@ Description: xxx
""" % SETUPTOOLS_FAKED_VERSION """ % SETUPTOOLS_FAKED_VERSION
def _install(tarball): def _install(tarball, install_args=()):
# extracting the tarball # extracting the tarball
tmpdir = tempfile.mkdtemp() tmpdir = tempfile.mkdtemp()
log.warn('Extracting in %s', tmpdir) log.warn('Extracting in %s', tmpdir)
...@@ -81,7 +83,7 @@ def _install(tarball): ...@@ -81,7 +83,7 @@ def _install(tarball):
# installing # installing
log.warn('Installing Distribute') 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('Something went wrong during the installation.')
log.warn('See the error message above.') log.warn('See the error message above.')
finally: finally:
...@@ -144,7 +146,7 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, ...@@ -144,7 +146,7 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
except ImportError: except ImportError:
return _do_download(version, download_base, to_dir, download_delay) return _do_download(version, download_base, to_dir, download_delay)
try: try:
pkg_resources.require("distribute>="+version) pkg_resources.require("distribute>=" + version)
return return
except pkg_resources.VersionConflict: except pkg_resources.VersionConflict:
e = sys.exc_info()[1] e = sys.exc_info()[1]
...@@ -167,6 +169,7 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, ...@@ -167,6 +169,7 @@ def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
if not no_fake: if not no_fake:
_create_fake_setuptools_pkg_info(to_dir) _create_fake_setuptools_pkg_info(to_dir)
def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
to_dir=os.curdir, delay=15): to_dir=os.curdir, delay=15):
"""Download distribute from a specified location and return its filename """Download distribute from a specified location and return its filename
...@@ -203,6 +206,7 @@ def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, ...@@ -203,6 +206,7 @@ def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL,
dst.close() dst.close()
return os.path.realpath(saveto) return os.path.realpath(saveto)
def _no_sandbox(function): def _no_sandbox(function):
def __no_sandbox(*args, **kw): def __no_sandbox(*args, **kw):
try: try:
...@@ -227,6 +231,7 @@ def _no_sandbox(function): ...@@ -227,6 +231,7 @@ def _no_sandbox(function):
return __no_sandbox return __no_sandbox
def _patch_file(path, content): def _patch_file(path, content):
"""Will backup the file then patch it""" """Will backup the file then patch it"""
existing_content = open(path).read() existing_content = open(path).read()
...@@ -245,15 +250,18 @@ def _patch_file(path, content): ...@@ -245,15 +250,18 @@ def _patch_file(path, content):
_patch_file = _no_sandbox(_patch_file) _patch_file = _no_sandbox(_patch_file)
def _same_content(path, content): def _same_content(path, content):
return open(path).read() == content return open(path).read() == content
def _rename_path(path): def _rename_path(path):
new_name = path + '.OLD.%s' % time.time() 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) os.rename(path, new_name)
return new_name return new_name
def _remove_flat_installation(placeholder): def _remove_flat_installation(placeholder):
if not os.path.isdir(placeholder): if not os.path.isdir(placeholder):
log.warn('Unkown installation at %s', placeholder) log.warn('Unkown installation at %s', placeholder)
...@@ -267,7 +275,7 @@ def _remove_flat_installation(placeholder): ...@@ -267,7 +275,7 @@ def _remove_flat_installation(placeholder):
log.warn('Could not locate setuptools*.egg-info') log.warn('Could not locate setuptools*.egg-info')
return return
log.warn('Removing elements out of the way...') log.warn('Moving elements out of the way...')
pkg_info = os.path.join(placeholder, file) pkg_info = os.path.join(placeholder, file)
if os.path.isdir(pkg_info): if os.path.isdir(pkg_info):
patched = _patch_egg_dir(pkg_info) patched = _patch_egg_dir(pkg_info)
...@@ -289,11 +297,13 @@ def _remove_flat_installation(placeholder): ...@@ -289,11 +297,13 @@ def _remove_flat_installation(placeholder):
_remove_flat_installation = _no_sandbox(_remove_flat_installation) _remove_flat_installation = _no_sandbox(_remove_flat_installation)
def _after_install(dist): def _after_install(dist):
log.warn('After install bootstrap.') log.warn('After install bootstrap.')
placeholder = dist.get_command_obj('install').install_purelib placeholder = dist.get_command_obj('install').install_purelib
_create_fake_setuptools_pkg_info(placeholder) _create_fake_setuptools_pkg_info(placeholder)
def _create_fake_setuptools_pkg_info(placeholder): def _create_fake_setuptools_pkg_info(placeholder):
if not placeholder or not os.path.exists(placeholder): if not placeholder or not os.path.exists(placeholder):
log.warn('Could not find the install location') log.warn('Could not find the install location')
...@@ -307,7 +317,11 @@ def _create_fake_setuptools_pkg_info(placeholder): ...@@ -307,7 +317,11 @@ def _create_fake_setuptools_pkg_info(placeholder):
return return
log.warn('Creating %s', pkg_info) 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: try:
f.write(SETUPTOOLS_PKG_INFO) f.write(SETUPTOOLS_PKG_INFO)
finally: finally:
...@@ -321,7 +335,10 @@ def _create_fake_setuptools_pkg_info(placeholder): ...@@ -321,7 +335,10 @@ def _create_fake_setuptools_pkg_info(placeholder):
finally: finally:
f.close() 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): def _patch_egg_dir(path):
# let's check if it's already patched # let's check if it's already patched
...@@ -343,6 +360,7 @@ def _patch_egg_dir(path): ...@@ -343,6 +360,7 @@ def _patch_egg_dir(path):
_patch_egg_dir = _no_sandbox(_patch_egg_dir) _patch_egg_dir = _no_sandbox(_patch_egg_dir)
def _before_install(): def _before_install():
log.warn('Before install bootstrap.') log.warn('Before install bootstrap.')
_fake_setuptools() _fake_setuptools()
...@@ -351,7 +369,7 @@ def _before_install(): ...@@ -351,7 +369,7 @@ def _before_install():
def _under_prefix(location): def _under_prefix(location):
if 'install' not in sys.argv: if 'install' not in sys.argv:
return True 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 index, arg in enumerate(args):
for option in ('--root', '--prefix'): for option in ('--root', '--prefix'):
if arg.startswith('%s=' % option): if arg.startswith('%s=' % option):
...@@ -359,7 +377,7 @@ def _under_prefix(location): ...@@ -359,7 +377,7 @@ def _under_prefix(location):
return location.startswith(top_dir) return location.startswith(top_dir)
elif arg == option: elif arg == option:
if len(args) > index: if len(args) > index:
top_dir = args[index+1] top_dir = args[index + 1]
return location.startswith(top_dir) return location.startswith(top_dir)
if arg == '--user' and USER_SITE is not None: if arg == '--user' and USER_SITE is not None:
return location.startswith(USER_SITE) return location.startswith(USER_SITE)
...@@ -376,11 +394,14 @@ def _fake_setuptools(): ...@@ -376,11 +394,14 @@ def _fake_setuptools():
return return
ws = pkg_resources.working_set ws = pkg_resources.working_set
try: try:
setuptools_dist = ws.find(pkg_resources.Requirement.parse('setuptools', setuptools_dist = ws.find(
replacement=False)) pkg_resources.Requirement.parse('setuptools', replacement=False)
)
except TypeError: except TypeError:
# old distribute API # 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: if setuptools_dist is None:
log.warn('No setuptools distribution found') log.warn('No setuptools distribution found')
...@@ -414,7 +435,7 @@ def _fake_setuptools(): ...@@ -414,7 +435,7 @@ def _fake_setuptools():
res = _patch_egg_dir(setuptools_location) res = _patch_egg_dir(setuptools_location)
if not res: if not res:
return return
log.warn('Patched done.') log.warn('Patching complete.')
_relaunch() _relaunch()
...@@ -422,7 +443,8 @@ def _relaunch(): ...@@ -422,7 +443,8 @@ def _relaunch():
log.warn('Relaunching...') log.warn('Relaunching...')
# we have to relaunch the process # we have to relaunch the process
# pip marker to avoid a relaunch bug # 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' sys.argv[0] = 'setup.py'
args = [sys.executable] + sys.argv args = [sys.executable] + sys.argv
sys.exit(subprocess.call(args)) sys.exit(subprocess.call(args))
...@@ -448,7 +470,7 @@ def _extractall(self, path=".", members=None): ...@@ -448,7 +470,7 @@ def _extractall(self, path=".", members=None):
# Extract directories with a safe mode. # Extract directories with a safe mode.
directories.append(tarinfo) directories.append(tarinfo)
tarinfo = copy.copy(tarinfo) tarinfo = copy.copy(tarinfo)
tarinfo.mode = 448 # decimal for oct 0700 tarinfo.mode = 448 # decimal for oct 0700
self.extract(tarinfo, path) self.extract(tarinfo, path)
# Reverse sort directories. # Reverse sort directories.
...@@ -475,11 +497,39 @@ def _extractall(self, path=".", members=None): ...@@ -475,11 +497,39 @@ def _extractall(self, path=".", members=None):
self._dbg(1, "tarfile: %s" % e) 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""" """Install or upgrade setuptools and EasyInstall"""
tarball = download_setuptools() options = _parse_args()
_install(tarball) tarball = download_setuptools(download_base=options.download_base)
_install(tarball, _build_install_args(options))
if __name__ == '__main__': if __name__ == '__main__':
main(sys.argv[1:]) main()
...@@ -48,9 +48,9 @@ copyright = u'2009-2011, The fellowship of the packaging' ...@@ -48,9 +48,9 @@ copyright = u'2009-2011, The fellowship of the packaging'
# built documents. # built documents.
# #
# The short X.Y version. # The short X.Y version.
version = '0.6.17' version = '0.6.29'
# The full version, including alpha/beta/rc tags. # 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 # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
......
...@@ -875,9 +875,6 @@ Command-Line Options ...@@ -875,9 +875,6 @@ Command-Line Options
judgment and force an installation directory to be treated as if it judgment and force an installation directory to be treated as if it
supported ``.pth`` files. 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) ``--no-deps, -N`` (New in 0.6a6)
Don't install any dependencies. This is intended as a convenience for 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 tools that wrap eggs in a platform-specific packaging system. (We don't
...@@ -940,194 +937,65 @@ Command-Line Options ...@@ -940,194 +937,65 @@ Command-Line Options
Custom Installation Locations Custom Installation Locations
----------------------------- -----------------------------
EasyInstall manages what packages are active using Python ``.pth`` files, which By default, EasyInstall installs python packages into Python's main ``site-packages`` directory,
are normally only usable in Python's main ``site-packages`` directory. On some and manages them using a custom ``.pth`` file in that same directory.
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``.
2. The active distutils configuration file(s) or ``easy_install`` command line Very often though, a user or developer wants ``easy_install`` to install and manage python packages
should include the custom directory in the ``--site-dirs`` option, so that in an alternative location, usually for one of 3 reasons:
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.)
As long as both of these things have been done, your custom installation 1. They don't have access to write to the main Python site-packages directory.
location is good to go.
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 Historically, there have been many approaches to achieve custom installation.
``~/Library/Python/2.x/site-packages`` directory as your custom installation The following section lists only the easiest and most relevant approaches [1]_.
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
[install] `Use the "--user" option`_
install_lib = ~/Library/Python/$py_version_short/site-packages
install_scripts = ~/bin
This will tell the distutils and EasyInstall to always install packages in `Use the "--user" option and customize "PYTHONUSERBASE"`_
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.)
Once you have done this, you can follow the normal `installation instructions`_ `Use "virtualenv"`_
and use ``easy_install`` without any other special options or steps.
(Note, however, that ``~/bin`` is not in the default ``PATH``, so you may have .. [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.
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``.
.. _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 Use the "--user" option
system, but don't have root access, you can create your own "virtual" ~~~~~~~~~~~~~~~~~~~~~~~
Python installation, which uses its own library directories and some symlinks With Python 2.6 came the User scheme for installation, which means that all
to the site-wide Python. 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
Please refer to the `virtualenv`_ documentation for creating such an for the ``site.USER_BASE`` variable. This mode of installation can be turned on by
environment. 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 .. _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" Package Index "API"
------------------- -------------------
......
...@@ -26,18 +26,20 @@ directory, as opposed from the source directory as is normally done. ...@@ -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 Distribute will convert all Python files, and also all doctests in Python
files. However, if you have doctests located in separate text files, these files. However, if you have doctests located in separate text files, these
will not automatically be converted. By adding them to the will not automatically be converted. By adding them to the
``convert_2to3_doctests`` keyword parameter Distrubute will convert them as ``convert_2to3_doctests`` keyword parameter Distrubute will convert them as
well. well.
By default, the conversion uses all fixers in the ``lib2to3.fixers`` package. 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 use additional fixers, the parameter ``use_2to3_fixers`` can be set
to a list of names of packages containing fixers. 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:: A typical setup.py can look something like this::
from setuptools import setup from setuptools import setup
setup( setup(
name='your.module', name='your.module',
version = '1.0', version = '1.0',
...@@ -49,7 +51,8 @@ A typical setup.py can look something like this:: ...@@ -49,7 +51,8 @@ A typical setup.py can look something like this::
test_suite = 'your.module.tests', test_suite = 'your.module.tests',
use_2to3 = True, use_2to3 = True,
convert_2to3_doctests = ['src/your/module/README.txt'], 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 Differential conversion
...@@ -58,10 +61,10 @@ Differential conversion ...@@ -58,10 +61,10 @@ Differential conversion
Note that a file will only be copied and converted during the build process 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 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 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 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 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. and no conversion will happen.
In general, if code doesn't seem to be converted, deleting the build directory 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. ...@@ -80,12 +83,6 @@ already converted code, and hence no 2to3 conversion is needed during install.
Advanced features 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, 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``. 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. ...@@ -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 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 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 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():: dict and pass that dict into setup()::
from setuptools import setup from setuptools import setup
import sys import sys
extra = {} extra = {}
if sys.version_info >= (3,): if sys.version_info >= (3,):
extra['use_2to3'] = True extra['use_2to3'] = True
extra['convert_2to3_doctests'] = ['src/your/module/README.txt'] extra['convert_2to3_doctests'] = ['src/your/module/README.txt']
extra['use_2to3_fixers'] = ['your.fixers'] extra['use_2to3_fixers'] = ['your.fixers']
setup( setup(
name='your.module', name='your.module',
version = '1.0', version = '1.0',
......
...@@ -756,17 +756,18 @@ e.g.:: ...@@ -756,17 +756,18 @@ e.g.::
include_package_data = True include_package_data = True
) )
This tells setuptools to install any data files it finds in your packages. The This tells setuptools to install any data files it finds in your packages.
data files must be under CVS or Subversion control, or else they must be The data files must be under CVS or Subversion control, or else they must be
specified via the distutils' ``MANIFEST.in`` file. (They can also be tracked specified via the distutils' ``MANIFEST.in`` file. (They can also be tracked
by another revision control system, using an appropriate plugin. See the by another revision control system, using an appropriate plugin. See the
section below on `Adding Support for Other Revision Control Systems`_ for section below on `Adding Support for Other Revision Control Systems`_ for
information on how to write such plugins.) information on how to write such plugins.)
If you want finer-grained control over what files are included (for example, if If the data files are not under version control, or are not in a supported
you have documentation files in your package directories and want to exclude version control system, or if you want finer-grained control over what files
them from installation), then you can also use the ``package_data`` keyword, are included (for example, if you have documentation files in your package
e.g.:: directories and want to exclude them from installation), then you can also use
the ``package_data`` keyword, e.g.::
from setuptools import setup, find_packages from setuptools import setup, find_packages
setup( setup(
...@@ -822,7 +823,10 @@ converts slashes to appropriate platform-specific separators at build time. ...@@ -822,7 +823,10 @@ converts slashes to appropriate platform-specific separators at build time.
(Note: although the ``package_data`` argument was previously only available in (Note: although the ``package_data`` argument was previously only available in
``setuptools``, it was also added to the Python ``distutils`` package as of ``setuptools``, it was also added to the Python ``distutils`` package as of
Python 2.4; there is `some documentation for the feature`__ available on the Python 2.4; there is `some documentation for the feature`__ available on the
python.org website.) python.org website. If using the setuptools-specific ``include_package_data``
argument, files specified by ``package_data`` will *not* be automatically
added to the manifest unless they are tracked by a supported version control
system, or are listed in the MANIFEST.in file.)
__ http://docs.python.org/dist/node11.html __ http://docs.python.org/dist/node11.html
...@@ -1082,6 +1086,14 @@ update the ``easy-install.pth`` file to include your project's source code, ...@@ -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 thereby making it available on ``sys.path`` for all programs using that Python
installation. 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 In addition, the ``develop`` command creates wrapper scripts in the target
script directory that will run your in-development scripts after ensuring that script directory that will run your in-development scripts after ensuring that
all your ``install_requires`` packages are available on ``sys.path``. all your ``install_requires`` packages are available on ``sys.path``.
......
...@@ -25,9 +25,12 @@ ...@@ -25,9 +25,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <string.h>
#include <windows.h>
#include <tchar.h>
#include <fcntl.h> #include <fcntl.h>
#include "windows.h"
int child_pid=0;
int fail(char *format, char *data) { int fail(char *format, char *data) {
/* Print error message to stderr and return 2 */ /* Print error message to stderr and return 2 */
...@@ -35,10 +38,6 @@ int fail(char *format, char *data) { ...@@ -35,10 +38,6 @@ int fail(char *format, char *data) {
return 2; return 2;
} }
char *quoted(char *data) { char *quoted(char *data) {
int i, ln = strlen(data), nb; int i, ln = strlen(data), nb;
...@@ -90,7 +89,7 @@ char *loadable_exe(char *exename) { ...@@ -90,7 +89,7 @@ char *loadable_exe(char *exename) {
/* Return the absolute filename for spawnv */ /* Return the absolute filename for spawnv */
result = calloc(MAX_PATH, sizeof(char)); result = calloc(MAX_PATH, sizeof(char));
strncpy(result, exename, MAX_PATH); strncpy(result, exename, MAX_PATH);
/*if (result) GetModuleFileName(hPython, result, MAX_PATH); /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
FreeLibrary(hPython); */ FreeLibrary(hPython); */
return result; return result;
...@@ -160,8 +159,82 @@ char **parse_argv(char *cmdline, int *argc) ...@@ -160,8 +159,82 @@ char **parse_argv(char *cmdline, int *argc)
} while (1); } 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) { int run(int argc, char **argv, int is_gui) {
...@@ -173,10 +246,11 @@ 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 **newargs, **newargsp, **parsedargs; /* argument array for exec */
char *ptr, *end; /* working pointers for string manipulation */ char *ptr, *end; /* working pointers for string manipulation */
char *cmdline;
int i, parsedargc; /* loop counter */ int i, parsedargc; /* loop counter */
/* compute script name from our .exe name*/ /* compute script name from our .exe name*/
GetModuleFileName(NULL, script, sizeof(script)); GetModuleFileNameA(NULL, script, sizeof(script));
end = script + strlen(script); end = script + strlen(script);
while( end>script && *end != '.') while( end>script && *end != '.')
*end-- = '\0'; *end-- = '\0';
...@@ -236,12 +310,18 @@ int run(int argc, char **argv, int is_gui) { ...@@ -236,12 +310,18 @@ int run(int argc, char **argv, int is_gui) {
return fail("Could not exec %s", ptr); /* shouldn't get here! */ 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) { int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
return run(__argc, __argv, GUI); return run(__argc, __argv, GUI);
} }
int main(int argc, char** argv) {
return run(argc, argv, GUI);
}
...@@ -535,6 +535,10 @@ class WorkingSet(object): ...@@ -535,6 +535,10 @@ class WorkingSet(object):
""" """
seen = {} seen = {}
for item in self.entries: for item in self.entries:
if item not in self.entry_keys:
# workaround a cache issue
continue
for key in self.entry_keys[item]: for key in self.entry_keys[item]:
if key not in seen: if key not in seen:
seen[key]=1 seen[key]=1
...@@ -1350,6 +1354,14 @@ class DefaultProvider(EggProvider): ...@@ -1350,6 +1354,14 @@ class DefaultProvider(EggProvider):
register_loader_type(type(None), DefaultProvider) 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): class EmptyProvider(NullProvider):
"""Provider that returns nothing for all requests""" """Provider that returns nothing for all requests"""
...@@ -1763,7 +1775,7 @@ def find_on_path(importer, path_item, only=False): ...@@ -1763,7 +1775,7 @@ def find_on_path(importer, path_item, only=False):
# scan for .egg and .egg-info in directory # scan for .egg and .egg-info in directory
for entry in os.listdir(path_item): for entry in os.listdir(path_item):
lower = entry.lower() 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) fullpath = os.path.join(path_item, entry)
if os.path.isdir(fullpath): if os.path.isdir(fullpath):
# egg-info directory, allow getting metadata # egg-info directory, allow getting metadata
...@@ -1784,6 +1796,14 @@ def find_on_path(importer, path_item, only=False): ...@@ -1784,6 +1796,14 @@ def find_on_path(importer, path_item, only=False):
break break
register_finder(ImpWrapper,find_on_path) 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_handlers={})
_declare_state('dict', _namespace_packages={}) _declare_state('dict', _namespace_packages={})
...@@ -1883,6 +1903,14 @@ def file_ns_handler(importer, path_item, packageName, module): ...@@ -1883,6 +1903,14 @@ def file_ns_handler(importer, path_item, packageName, module):
register_namespace_handler(ImpWrapper,file_ns_handler) register_namespace_handler(ImpWrapper,file_ns_handler)
register_namespace_handler(zipimport.zipimporter,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): def null_ns_handler(importer, path_item, packageName, module):
return None return None
...@@ -1941,7 +1969,7 @@ replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get ...@@ -1941,7 +1969,7 @@ replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
def _parse_version_parts(s): def _parse_version_parts(s):
for part in component_re.split(s): for part in component_re.split(s):
part = replace(part,part) part = replace(part,part)
if not part or part=='.': if part in ['', '.']:
continue continue
if part[:1] in '0123456789': if part[:1] in '0123456789':
yield part.zfill(8) # pad for numeric comparison yield part.zfill(8) # pad for numeric comparison
...@@ -1984,8 +2012,6 @@ def parse_version(s): ...@@ -1984,8 +2012,6 @@ def parse_version(s):
parts = [] parts = []
for part in _parse_version_parts(s.lower()): for part in _parse_version_parts(s.lower()):
if part.startswith('*'): 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 # remove trailing zeros from each series of numeric parts
while parts and parts[-1]=='00000000': while parts and parts[-1]=='00000000':
parts.pop() parts.pop()
...@@ -2122,6 +2148,8 @@ def _remove_md5_fragment(location): ...@@ -2122,6 +2148,8 @@ def _remove_md5_fragment(location):
class Distribution(object): class Distribution(object):
"""Wrap an actual or potential sys.path entry w/metadata""" """Wrap an actual or potential sys.path entry w/metadata"""
PKG_INFO = 'PKG-INFO'
def __init__(self, def __init__(self,
location=None, metadata=None, project_name=None, version=None, location=None, metadata=None, project_name=None, version=None,
py_version=PY_MAJOR, platform=None, precedence = EGG_DIST py_version=PY_MAJOR, platform=None, precedence = EGG_DIST
...@@ -2139,12 +2167,14 @@ class Distribution(object): ...@@ -2139,12 +2167,14 @@ class Distribution(object):
def from_location(cls,location,basename,metadata=None,**kw): def from_location(cls,location,basename,metadata=None,**kw):
project_name, version, py_version, platform = [None]*4 project_name, version, py_version, platform = [None]*4
basename, ext = os.path.splitext(basename) 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) match = EGG_NAME(basename)
if match: if match:
project_name, version, py_version, platform = match.group( project_name, version, py_version, platform = match.group(
'name','ver','pyver','plat' 'name','ver','pyver','plat'
) )
cls = _distributionImpl[ext.lower()]
return cls( return cls(
location, metadata, project_name=project_name, version=version, location, metadata, project_name=project_name, version=version,
py_version=py_version, platform=platform, **kw py_version=py_version, platform=platform, **kw
...@@ -2207,13 +2237,13 @@ class Distribution(object): ...@@ -2207,13 +2237,13 @@ class Distribution(object):
try: try:
return self._version return self._version
except AttributeError: except AttributeError:
for line in self._get_metadata('PKG-INFO'): for line in self._get_metadata(self.PKG_INFO):
if line.lower().startswith('version:'): if line.lower().startswith('version:'):
self._version = safe_version(line.split(':',1)[1].strip()) self._version = safe_version(line.split(':',1)[1].strip())
return self._version return self._version
else: else:
raise ValueError( 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) version = property(version)
...@@ -2444,6 +2474,74 @@ class Distribution(object): ...@@ -2444,6 +2474,74 @@ class Distribution(object):
extras = property(extras) 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): def issue_warning(*args,**kw):
level = 1 level = 1
g = globals() 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 @@ ...@@ -2,6 +2,10 @@
"""Distutils setup file, used to install or test 'setuptools'""" """Distutils setup file, used to install or test 'setuptools'"""
import sys import sys
import os import os
import textwrap
# Allow to run setup.py from another directory.
os.chdir(os.path.dirname(os.path.abspath(__file__)))
src_root = None src_root = None
do_2to3 = False do_2to3 = False
...@@ -28,7 +32,7 @@ if sys.version_info >= (3,) and do_2to3: ...@@ -28,7 +32,7 @@ if sys.version_info >= (3,) and do_2to3:
util.run_2to3(outfiles_2to3) util.run_2to3(outfiles_2to3)
# arrange setup to use the copy # 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 src_root = tmp_src
from distutils.util import convert_path from distutils.util import convert_path
...@@ -38,7 +42,7 @@ init_path = convert_path('setuptools/command/__init__.py') ...@@ -38,7 +42,7 @@ init_path = convert_path('setuptools/command/__init__.py')
exec(open(init_path).read(), d) exec(open(init_path).read(), d)
SETUP_COMMANDS = d['__all__'] SETUP_COMMANDS = d['__all__']
VERSION = "0.6.20" VERSION = "0.6.29"
from setuptools import setup, find_packages from setuptools import setup, find_packages
from setuptools.command.build_py import build_py as _build_py from setuptools.command.build_py import build_py as _build_py
...@@ -174,7 +178,8 @@ dist = setup( ...@@ -174,7 +178,8 @@ dist = setup(
"test_loader = setuptools.dist:check_importable", "test_loader = setuptools.dist:check_importable",
"use_2to3 = setuptools.dist:assert_bool", "use_2to3 = setuptools.dist:assert_bool",
"convert_2to3_doctests = setuptools.dist:assert_string_list", "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": [ "egg_info.writers": [
...@@ -198,23 +203,28 @@ dist = setup( ...@@ -198,23 +203,28 @@ dist = setup(
}, },
classifiers = [f.strip() for f in """ classifiers = textwrap.dedent("""
Development Status :: 5 - Production/Stable Development Status :: 5 - Production/Stable
Intended Audience :: Developers Intended Audience :: Developers
License :: OSI Approved :: Python Software Foundation License License :: OSI Approved :: Python Software Foundation License
License :: OSI Approved :: Zope Public License License :: OSI Approved :: Zope Public License
Operating System :: OS Independent Operating System :: OS Independent
Programming Language :: Python Programming Language :: Python :: 2.4
Programming Language :: Python :: 3 Programming Language :: Python :: 2.5
Topic :: Software Development :: Libraries :: Python Modules Programming Language :: Python :: 2.6
Topic :: System :: Archiving :: Packaging Programming Language :: Python :: 2.7
Topic :: System :: Systems Administration Programming Language :: Python :: 3
Topic :: Utilities""".splitlines() if f.strip()], 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, scripts = scripts,
) )
if _being_installed(): if _being_installed():
from distribute_setup import _after_install from distribute_setup import _after_install
_after_install(dist) _after_install(dist)
...@@ -180,19 +180,22 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): ...@@ -180,19 +180,22 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
try: try:
tarobj.chown = lambda *args: None # don't do any chowning! tarobj.chown = lambda *args: None # don't do any chowning!
for member in tarobj: for member in tarobj:
if member.isfile() or member.isdir(): name = member.name
name = member.name # don't extract absolute paths or ones with .. in them
# don't extract absolute paths or ones with .. in them if not name.startswith('/') and '..' not in name:
if not name.startswith('/') and '..' not in name: prelim_dst = os.path.join(extract_dir, *name.split('/'))
dst = os.path.join(extract_dir, *name.split('/')) final_dst = progress_filter(name, prelim_dst)
dst = progress_filter(name, dst) # If progress_filter returns None, then we do not extract
if dst: # this file
if dst.endswith(os.sep): # TODO: Do we really need to limit to just these file types?
dst = dst[:-1] # tarobj.extract() will handle all files on all platforms,
try: # turning file types that aren't allowed on that platform into
tarobj._extract_member(member,dst) # XXX Ugh # regular files.
except tarfile.ExtractError: if final_dst and (member.isfile() or member.isdir() or
pass # chown/chmod/mkfifo/mknode/makedev failed member.islnk() or member.issym()):
tarobj.extract(member, extract_dir)
if final_dst != prelim_dst:
shutil.move(prelim_dst, final_dst)
return True return True
finally: finally:
tarobj.close() tarobj.close()
......
No preview for this file type
...@@ -14,7 +14,6 @@ if sys.version>='2.5': ...@@ -14,7 +14,6 @@ if sys.version>='2.5':
from distutils.command.bdist import bdist from distutils.command.bdist import bdist
if 'egg' not in bdist.format_commands: if 'egg' not in bdist.format_commands:
bdist.format_command['egg'] = ('bdist_egg', "Python .egg file") bdist.format_command['egg'] = ('bdist_egg', "Python .egg file")
bdist.format_commands.append('egg') bdist.format_commands.append('egg')
......
...@@ -426,8 +426,12 @@ def scan_module(egg_dir, base, name, stubs): ...@@ -426,8 +426,12 @@ def scan_module(egg_dir, base, name, stubs):
return True # Extension module return True # Extension module
pkg = base[len(egg_dir)+1:].replace(os.sep,'.') pkg = base[len(egg_dir)+1:].replace(os.sep,'.')
module = pkg+(pkg and '.' or '')+os.path.splitext(name)[0] module = pkg+(pkg and '.' or '')+os.path.splitext(name)[0]
f = open(filename,'rb'); f.read(8) # skip magic & date if sys.version_info < (3, 3):
code = marshal.load(f); f.close() 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 safe = True
symbols = dict.fromkeys(iter_symbols(code)) symbols = dict.fromkeys(iter_symbols(code))
for bad in ['__file__', '__path__']: for bad in ['__file__', '__path__']:
......
...@@ -28,13 +28,8 @@ try: ...@@ -28,13 +28,8 @@ try:
if not files: if not files:
return return
log.info("Fixing "+" ".join(files)) log.info("Fixing "+" ".join(files))
if not self.fixer_names: self.__build_fixer_names()
self.fixer_names = [] self.__exclude_fixers()
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))
if doctests: if doctests:
if setuptools.run_2to3_on_doctests: if setuptools.run_2to3_on_doctests:
r = DistutilsRefactoringTool(self.fixer_names) r = DistutilsRefactoringTool(self.fixer_names)
...@@ -42,6 +37,23 @@ try: ...@@ -42,6 +37,23 @@ try:
else: else:
_Mixin2to3.run_2to3(self, files) _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: except ImportError:
class Mixin2to3: class Mixin2to3:
def run_2to3(self, files, doctests=True): def run_2to3(self, files, doctests=True):
...@@ -201,8 +213,8 @@ class build_py(_build_py, Mixin2to3): ...@@ -201,8 +213,8 @@ class build_py(_build_py, Mixin2to3):
else: else:
return init_py return init_py
f = open(init_py,'rU') f = open(init_py,'rbU')
if 'declare_namespace' not in f.read(): if 'declare_namespace'.encode() not in f.read():
from distutils import log from distutils import log
log.warn( log.warn(
"WARNING: %s is a namespace package, but its __init__.py does\n" "WARNING: %s is a namespace package, but its __init__.py does\n"
......
...@@ -3,7 +3,7 @@ from distutils.util import convert_path, subst_vars ...@@ -3,7 +3,7 @@ from distutils.util import convert_path, subst_vars
from pkg_resources import Distribution, PathMetadata, normalize_path from pkg_resources import Distribution, PathMetadata, normalize_path
from distutils import log from distutils import log
from distutils.errors import DistutilsError, DistutilsOptionError from distutils.errors import DistutilsError, DistutilsOptionError
import os, setuptools, glob import os, sys, setuptools, glob
class develop(easy_install): class develop(easy_install):
"""Set up package for development""" """Set up package for development"""
...@@ -84,11 +84,35 @@ class develop(easy_install): ...@@ -84,11 +84,35 @@ class develop(easy_install):
" installation directory", p, normalize_path(os.curdir)) " installation directory", p, normalize_path(os.curdir))
def install_for_development(self): def install_for_development(self):
# Ensure metadata is up-to-date if sys.version_info >= (3,) and getattr(self.distribution, 'use_2to3', False):
self.run_command('egg_info') # If we run 2to3 we can not do this inplace:
# Build extensions in-place
self.reinitialize_command('build_ext', inplace=1) # Ensure metadata is up-to-date
self.run_command('build_ext') 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 self.install_site_py() # ensure that target dir is site-safe
if setuptools.bootstrap_install_from: if setuptools.bootstrap_install_from:
self.easy_install(setuptools.bootstrap_install_from) self.easy_install(setuptools.bootstrap_install_from)
......
...@@ -10,7 +10,15 @@ file, or visit the `EasyInstall home page`__. ...@@ -10,7 +10,15 @@ file, or visit the `EasyInstall home page`__.
__ http://packages.python.org/distribute/easy_install.html __ 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 glob import glob
from setuptools import Command, _dont_write_bytecode from setuptools import Command, _dont_write_bytecode
from setuptools.sandbox import run_setup from setuptools.sandbox import run_setup
...@@ -21,6 +29,7 @@ from distutils.sysconfig import get_python_lib, get_config_vars ...@@ -21,6 +29,7 @@ from distutils.sysconfig import get_python_lib, get_config_vars
from distutils.errors import DistutilsArgError, DistutilsOptionError, \ from distutils.errors import DistutilsArgError, DistutilsOptionError, \
DistutilsError, DistutilsPlatformError DistutilsError, DistutilsPlatformError
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
from setuptools.command import setopt
from setuptools.archive_util import unpack_archive from setuptools.archive_util import unpack_archive
from setuptools.package_index import PackageIndex from setuptools.package_index import PackageIndex
from setuptools.package_index import URL_SCHEME from setuptools.package_index import URL_SCHEME
...@@ -43,6 +52,10 @@ __all__ = [ ...@@ -43,6 +52,10 @@ __all__ = [
import site import site
HAS_USER_SITE = not sys.version < "2.6" and site.ENABLE_USER_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): def samefile(p1,p2):
if hasattr(os.path,'samefile') and ( if hasattr(os.path,'samefile') and (
os.path.exists(p1) and os.path.exists(p2) os.path.exists(p1) and os.path.exists(p2)
...@@ -730,22 +743,26 @@ Please make the appropriate changes for your system and try again. ...@@ -730,22 +743,26 @@ Please make the appropriate changes for your system and try again.
spec = str(dist.as_requirement()) spec = str(dist.as_requirement())
is_script = is_python_script(script_text, script_name) is_script = is_python_script(script_text, script_name)
if is_script and dev_path: def get_template(filename):
script_text = get_script_header(script_text) + ( """
"# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r\n" There are a couple of template scripts in the package. This
"__requires__ = %(spec)r\n" function loads one of them and prepares it for use.
"from pkg_resources import require; require(%(spec)r)\n"
"del require\n" These templates use triple-quotes to escape variable
"__file__ = %(dev_path)r\n" substitutions so the scripts get the 2to3 treatment when build
"execfile(__file__)\n" on Python 3. The templates cannot use triple-quotes naturally.
) % locals() """
elif is_script: raw_bytes = resource_string('setuptools', template_name)
script_text = get_script_header(script_text) + ( template_str = raw_bytes.decode('utf-8')
"# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r\n" clean_template = template_str.replace('"""', '')
"__requires__ = %(spec)r\n" return clean_template
"import pkg_resources\n"
"pkg_resources.run_script(%(spec)r, %(script_name)r)\n" if is_script:
) % locals() 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') self.write_script(script_name, _to_ascii(script_text), 'b')
def write_script(self, script_name, contents, mode="t", blockers=()): 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. ...@@ -756,12 +773,13 @@ Please make the appropriate changes for your system and try again.
target = os.path.join(self.script_dir, script_name) target = os.path.join(self.script_dir, script_name)
self.add_output(target) self.add_output(target)
mask = current_umask()
if not self.dry_run: if not self.dry_run:
ensure_directory(target) ensure_directory(target)
f = open(target,"w"+mode) f = open(target,"w"+mode)
f.write(contents) f.write(contents)
f.close() 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. ...@@ -1078,11 +1096,14 @@ See the setuptools documentation for the "develop" command for more info.
def build_and_install(self, setup_script, setup_base): def build_and_install(self, setup_script, setup_base):
args = ['bdist_egg', '--dist-dir'] args = ['bdist_egg', '--dist-dir']
dist_dir = tempfile.mkdtemp( dist_dir = tempfile.mkdtemp(
prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script) prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script)
) )
try: try:
self._set_fetcher_options(os.path.dirname(setup_script))
args.append(dist_dir) args.append(dist_dir)
self.run_setup(setup_script, setup_base, args) self.run_setup(setup_script, setup_base, args)
all_eggs = Environment([dist_dir]) all_eggs = Environment([dist_dir])
eggs = [] eggs = []
...@@ -1097,6 +1118,30 @@ See the setuptools documentation for the "develop" command for more info. ...@@ -1097,6 +1118,30 @@ See the setuptools documentation for the "develop" command for more info.
rmtree(dist_dir) rmtree(dist_dir)
log.set_verbosity(self.verbose) # restore our log verbosity log.set_verbosity(self.verbose) # restore our log verbosity
def _set_fetcher_options(self, base):
"""
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): def update_pth(self,dist):
if self.pth_file is None: if self.pth_file is None:
return return
...@@ -1431,7 +1476,19 @@ def extract_wininst_cfg(dist_filename): ...@@ -1431,7 +1476,19 @@ def extract_wininst_cfg(dist_filename):
f.seek(prepended-(12+cfglen)) f.seek(prepended-(12+cfglen))
cfg = ConfigParser.RawConfigParser({'version':'','target_version':''}) cfg = ConfigParser.RawConfigParser({'version':'','target_version':''})
try: 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: except ConfigParser.Error:
return None return None
if not cfg.has_section('metadata') or not cfg.has_section('Setup'): 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): ...@@ -1777,7 +1834,10 @@ def get_script_args(dist, executable=sys_executable, wininst=False):
ext, launcher = '-script.py', 'cli.exe' ext, launcher = '-script.py', 'cli.exe'
old = ['.py','.pyc','.pyo'] old = ['.py','.pyc','.pyo']
new_header = re.sub('(?i)pythonw.exe','python.exe',header) 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': if os.path.exists(new_header[2:-1]) or sys.platform!='win32':
hdr = new_header hdr = new_header
else: else:
...@@ -1827,6 +1887,11 @@ def rmtree(path, ignore_errors=False, onerror=auto_chmod): ...@@ -1827,6 +1887,11 @@ def rmtree(path, ignore_errors=False, onerror=auto_chmod):
except os.error: except os.error:
onerror(os.rmdir, path, sys.exc_info()) onerror(os.rmdir, path, sys.exc_info())
def current_umask():
tmp = os.umask(022)
os.umask(tmp)
return tmp
def bootstrap(): def bootstrap():
# This function is called when setuptools*.egg is run using /bin/sh # This function is called when setuptools*.egg is run using /bin/sh
import setuptools; argv0 = os.path.dirname(setuptools.__path__[0]) import setuptools; argv0 = os.path.dirname(setuptools.__path__[0])
......
...@@ -163,7 +163,12 @@ class egg_info(Command): ...@@ -163,7 +163,12 @@ class egg_info(Command):
os.unlink(filename) os.unlink(filename)
def tagged_version(self): 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): def run(self):
self.mkpath(self.egg_info) self.mkpath(self.egg_info)
...@@ -288,6 +293,19 @@ class FileList(FileList): ...@@ -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): class manifest_maker(sdist):
template = "MANIFEST.in" template = "MANIFEST.in"
...@@ -312,6 +330,7 @@ class manifest_maker(sdist): ...@@ -312,6 +330,7 @@ class manifest_maker(sdist):
self.prune_file_list() self.prune_file_list()
self.filelist.sort() self.filelist.sort()
self.filelist.remove_duplicates() self.filelist.remove_duplicates()
self.filelist.files = [compose(path) for path in self.filelist.files]
self.write_manifest() self.write_manifest()
def write_manifest (self): def write_manifest (self):
......
...@@ -89,6 +89,8 @@ class install_egg_info(Command): ...@@ -89,6 +89,8 @@ class install_egg_info(Command):
if not self.dry_run: if not self.dry_run:
f = open(filename,'wt') f = open(filename,'wt')
for pkg in nsp: for pkg in nsp:
# ensure pkg is not a unicode string under Python 2.7
pkg = str(pkg)
pth = tuple(pkg.split('.')) pth = tuple(pkg.split('.'))
trailer = '\n' trailer = '\n'
if '.' in pkg: if '.' in pkg:
......
...@@ -39,15 +39,16 @@ class install_scripts(_install_scripts): ...@@ -39,15 +39,16 @@ class install_scripts(_install_scripts):
def write_script(self, script_name, contents, mode="t", *ignored): def write_script(self, script_name, contents, mode="t", *ignored):
"""Write an executable file to the scripts directory""" """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) log.info("Installing %s script to %s", script_name, self.install_dir)
target = os.path.join(self.install_dir, script_name) target = os.path.join(self.install_dir, script_name)
self.outfiles.append(target) self.outfiles.append(target)
mask = current_umask()
if not self.dry_run: if not self.dry_run:
ensure_directory(target) ensure_directory(target)
f = open(target,"w"+mode) f = open(target,"w"+mode)
f.write(contents) f.write(contents)
f.close() f.close()
chmod(target,0x1ED) # 0755 chmod(target, 0x1FF-mask) # 0777
...@@ -4,6 +4,8 @@ from distutils import log ...@@ -4,6 +4,8 @@ from distutils import log
import os, re, sys, pkg_resources import os, re, sys, pkg_resources
from glob import glob from glob import glob
READMES = ('README', 'README.rst', 'README.txt')
entities = [ entities = [
("&lt;","<"), ("&gt;", ">"), ("&quot;", '"'), ("&apos;", "'"), ("&lt;","<"), ("&gt;", ">"), ("&quot;", '"'), ("&apos;", "'"),
("&amp;", "&") ("&amp;", "&")
...@@ -97,7 +99,7 @@ def entries_finder(dirname, filename): ...@@ -97,7 +99,7 @@ def entries_finder(dirname, filename):
for match in entries_pattern.finditer(data): for match in entries_pattern.finditer(data):
yield joinpath(dirname,unescape(match.group(1))) yield joinpath(dirname,unescape(match.group(1)))
else: else:
log.warn("unrecognized .svn/entries format in %s", dirname) log.warn("unrecognized .svn/entries format in %s", os.path.abspath(dirname))
finders = [ finders = [
...@@ -145,7 +147,17 @@ class sdist(_sdist): ...@@ -145,7 +147,17 @@ class sdist(_sdist):
self.filelist = ei_cmd.filelist self.filelist = ei_cmd.filelist
self.filelist.append(os.path.join(ei_cmd.egg_info,'SOURCES.txt')) self.filelist.append(os.path.join(ei_cmd.egg_info,'SOURCES.txt'))
self.check_readme() 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() self.make_distribution()
dist_files = getattr(self.distribution,'dist_files',[]) dist_files = getattr(self.distribution,'dist_files',[])
...@@ -155,7 +167,7 @@ class sdist(_sdist): ...@@ -155,7 +167,7 @@ class sdist(_sdist):
dist_files.append(data) dist_files.append(data)
def add_defaults(self): def add_defaults(self):
standards = [('README', 'README.txt'), standards = [READMES,
self.distribution.script_name] self.distribution.script_name]
for fn in standards: for fn in standards:
if isinstance(fn, tuple): if isinstance(fn, tuple):
...@@ -186,6 +198,14 @@ class sdist(_sdist): ...@@ -186,6 +198,14 @@ class sdist(_sdist):
if self.distribution.has_pure_modules(): if self.distribution.has_pure_modules():
build_py = self.get_finalized_command('build_py') build_py = self.get_finalized_command('build_py')
self.filelist.extend(build_py.get_source_files()) self.filelist.extend(build_py.get_source_files())
# This functionality is incompatible with include_package_data, and
# will in fact create an infinite recursion if include_package_data
# is True. Use of include_package_data will imply that
# distutils-style automatic handling of package_data is disabled
if not self.distribution.include_package_data:
for _, src_dir, _, filenames in build_py.data_files:
self.filelist.extend([os.path.join(src_dir, filename)
for filename in filenames])
if self.distribution.has_ext_modules(): if self.distribution.has_ext_modules():
build_ext = self.get_finalized_command('build_ext') build_ext = self.get_finalized_command('build_ext')
...@@ -199,24 +219,33 @@ class sdist(_sdist): ...@@ -199,24 +219,33 @@ class sdist(_sdist):
build_scripts = self.get_finalized_command('build_scripts') build_scripts = self.get_finalized_command('build_scripts')
self.filelist.extend(build_scripts.get_source_files()) 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: try:
_sdist.read_template(self) _sdist.read_template(self)
except: 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() sys.exc_info()[2].tb_next.tb_frame.f_locals['template'].close()
raise 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): def check_readme(self):
alts = ("README", "README.txt") for f in READMES:
for f in alts:
if os.path.exists(f): if os.path.exists(f):
return return
else: else:
self.warn( 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): ...@@ -233,7 +262,34 @@ class sdist(_sdist):
self.get_finalized_command('egg_info').save_version_info(dest) 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 ...@@ -2,6 +2,7 @@ from setuptools import Command
from distutils.errors import DistutilsOptionError from distutils.errors import DistutilsOptionError
import sys import sys
from pkg_resources import * from pkg_resources import *
from pkg_resources import _namespace_packages
from unittest import TestLoader, main from unittest import TestLoader, main
class ScanningLoader(TestLoader): class ScanningLoader(TestLoader):
...@@ -81,7 +82,7 @@ class test(Command): ...@@ -81,7 +82,7 @@ class test(Command):
def with_project_on_sys_path(self, func): 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: # If we run 2to3 we can not do this inplace:
# Ensure metadata is up-to-date # Ensure metadata is up-to-date
...@@ -139,11 +140,28 @@ class test(Command): ...@@ -139,11 +140,28 @@ class test(Command):
def run_tests(self): def run_tests(self):
import unittest 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_ep = EntryPoint.parse("x="+self.test_loader)
loader_class = loader_ep.load(require=False) loader_class = loader_ep.load(require=False)
cks = loader_class()
unittest.main( unittest.main(
None, None, [unittest.__file__]+self.test_args, None, None, [unittest.__file__]+self.test_args,
testLoader = loader_class() testLoader = cks
) )
......
...@@ -91,7 +91,7 @@ class upload(Command): ...@@ -91,7 +91,7 @@ class upload(Command):
comment = "built on %s" % platform.platform(terse=1) comment = "built on %s" % platform.platform(terse=1)
data = { data = {
':action':'file_upload', ':action':'file_upload',
'protcol_version':'1', 'protocol_version':'1',
'name':self.distribution.get_name(), 'name':self.distribution.get_name(),
'version':self.distribution.get_version(), 'version':self.distribution.get_version(),
'content':(basename,content), 'content':(basename,content),
......
...@@ -267,6 +267,7 @@ class Distribution(_Distribution): ...@@ -267,6 +267,7 @@ class Distribution(_Distribution):
def fetch_build_egg(self, req): def fetch_build_egg(self, req):
"""Fetch an egg needed for building""" """Fetch an egg needed for building"""
try: try:
cmd = self._egg_fetcher cmd = self._egg_fetcher
cmd.package_index.to_scan = [] cmd.package_index.to_scan = []
...@@ -290,7 +291,7 @@ class Distribution(_Distribution): ...@@ -290,7 +291,7 @@ class Distribution(_Distribution):
cmd = easy_install( cmd = easy_install(
dist, args=["x"], install_dir=os.curdir, exclude_scripts=True, dist, args=["x"], install_dir=os.curdir, exclude_scripts=True,
always_copy=False, build_directory=None, editable=False, always_copy=False, build_directory=None, editable=False,
upgrade=False, multi_version=True, no_report = True upgrade=False, multi_version=True, no_report=True, user=False
) )
cmd.ensure_finalized() cmd.ensure_finalized()
self._egg_fetcher = cmd self._egg_fetcher = cmd
...@@ -642,6 +643,38 @@ class Distribution(_Distribution): ...@@ -642,6 +643,38 @@ class Distribution(_Distribution):
name = name[:-6] name = name[:-6]
yield name 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 # Install it throughout the distutils
for module in distutils.dist, distutils.core, distutils.cmd: for module in distutils.dist, distutils.core, distutils.cmd:
module.Distribution = Distribution module.Distribution = Distribution
......
from distutils.core import Extension as _Extension import sys
import distutils.core
import distutils.extension
from setuptools.dist import _get_unpatched from setuptools.dist import _get_unpatched
_Extension = _get_unpatched(_Extension)
# Prefer Cython to Pyrex _Extension = _get_unpatched(distutils.core.Extension)
pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
for pyrex_impl in pyrex_impls: def have_pyrex():
try: """
# from (pyrex_impl) import build_ext Return True if Cython or Pyrex can be imported.
build_ext = __import__(pyrex_impl, fromlist=['build_ext']).build_ext """
break pyrex_impls = 'Cython.Distutils.build_ext', 'Pyrex.Distutils.build_ext'
except: for pyrex_impl in pyrex_impls:
pass try:
have_pyrex = 'build_ext' in globals() # from (pyrex_impl) import build_ext
__import__(pyrex_impl, fromlist=['build_ext']).build_ext
return True
except Exception:
pass
return False
class Extension(_Extension): class Extension(_Extension):
"""Extension that uses '.c' files in place of '.pyx' files""" """Extension that uses '.c' files in place of '.pyx' files"""
if not have_pyrex: def __init__(self, *args, **kw):
# convert .pyx extensions to .c _Extension.__init__(self, *args, **kw)
def __init__(self,*args,**kw): if not have_pyrex():
_Extension.__init__(self,*args,**kw) self._convert_pyx_sources_to_c()
sources = []
for s in self.sources: def _convert_pyx_sources_to_c(self):
if s.endswith('.pyx'): "convert .pyx extensions to .c"
sources.append(s[:-3]+'c') def pyx_to_c(source):
else: if source.endswith('.pyx'):
sources.append(s) source = source[:-4] + '.c'
self.sources = sources return source
self.sources = map(pyx_to_c, self.sources)
class Library(Extension): class Library(Extension):
"""Just like a regular Extension, but built as a library instead""" """Just like a regular Extension, but built as a library instead"""
import sys, distutils.core, distutils.extension
distutils.core.Extension = Extension distutils.core.Extension = Extension
distutils.extension.Extension = Extension distutils.extension.Extension = Extension
if 'distutils.command.build_ext' in sys.modules: if 'distutils.command.build_ext' in sys.modules:
sys.modules['distutils.command.build_ext'].Extension = Extension sys.modules['distutils.command.build_ext'].Extension = Extension
No preview for this file type
"""PyPI and direct package downloading""" """PyPI and direct package downloading"""
import sys, os.path, re, shutil, random, socket import sys, os.path, re, shutil, random, socket
import base64
from pkg_resources import * from pkg_resources import *
from distutils import log from distutils import log
from distutils.errors import DistutilsError from distutils.errors import DistutilsError
...@@ -201,7 +202,7 @@ class PackageIndex(Environment): ...@@ -201,7 +202,7 @@ class PackageIndex(Environment):
return return
self.info("Reading %s", url) 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 if f is None: return
self.fetched_urls[url] = self.fetched_urls[f.url] = True self.fetched_urls[url] = self.fetched_urls[f.url] = True
...@@ -764,19 +765,41 @@ def socket_timeout(timeout=15): ...@@ -764,19 +765,41 @@ def socket_timeout(timeout=15):
return _socket_timeout return _socket_timeout
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): def open_with_auth(url):
"""Open a urllib2 request, handling HTTP authentication""" """Open a urllib2 request, handling HTTP authentication"""
scheme, netloc, path, params, query, frag = urlparse(url) 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'): if scheme in ('http', 'https'):
auth, host = splituser(netloc) auth, host = splituser(netloc)
else: else:
auth = None auth = None
if auth: if auth:
auth = "Basic " + unquote(auth).encode('base64').strip() auth = "Basic " + _encode_auth(auth)
new_url = urlunparse((scheme,host,path,params,query,frag)) new_url = urlunparse((scheme,host,path,params,query,frag))
request = urllib2.Request(new_url) request = urllib2.Request(new_url)
request.add_header("Authorization", auth) request.add_header("Authorization", auth)
......
...@@ -42,8 +42,14 @@ def run_setup(setup_script, args): ...@@ -42,8 +42,14 @@ def run_setup(setup_script, args):
finally: finally:
pkg_resources.__setstate__(pr_state) pkg_resources.__setstate__(pr_state)
sys.modules.update(save_modules) sys.modules.update(save_modules)
for key in list(sys.modules): # remove any modules imported within the sandbox
if key not in save_modules: del sys.modules[key] 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) os.chdir(old_dir)
sys.path[:] = save_path sys.path[:] = save_path
sys.argv[:] = save_argv sys.argv[:] = save_argv
...@@ -163,12 +169,12 @@ else: ...@@ -163,12 +169,12 @@ else:
_EXCEPTIONS = [] _EXCEPTIONS = []
try: try:
from win32com.client.gencache import GetGeneratePath from win32com.client.gencache import GetGeneratePath
_EXCEPTIONS.append(GetGeneratePath()) _EXCEPTIONS.append(GetGeneratePath())
del GetGeneratePath del GetGeneratePath
except ImportError: except ImportError:
# it appears pywin32 is not installed, so no need to exclude. # it appears pywin32 is not installed, so no need to exclude.
pass pass
class DirectorySandbox(AbstractSandbox): class DirectorySandbox(AbstractSandbox):
"""Restrict operations to a single subdirectory - pseudo-chroot""" """Restrict operations to a single subdirectory - pseudo-chroot"""
......
# 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""" """Tests for the 'setuptools' package"""
from unittest import TestSuite, TestCase, makeSuite, defaultTestLoader import sys
import distutils.core, distutils.cmd import os
import unittest
import doctest
import distutils.core
import distutils.cmd
from distutils.errors import DistutilsOptionError, DistutilsPlatformError from distutils.errors import DistutilsOptionError, DistutilsPlatformError
from distutils.errors import DistutilsSetupError from distutils.errors import DistutilsSetupError
import setuptools, setuptools.dist
from setuptools import Feature
from distutils.core import Extension 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.compat import func_code
from setuptools.depends import *
from distutils.version import StrictVersion, LooseVersion import setuptools.dist
from distutils.util import convert_path import setuptools.depends as dep
import sys, os.path from setuptools import Feature
from setuptools.depends import Require
def additional_tests(): def additional_tests():
import doctest, unittest import doctest, unittest
...@@ -36,55 +39,60 @@ def makeSetup(**args): ...@@ -36,55 +39,60 @@ def makeSetup(**args):
try: try:
return setuptools.setup(**args) return setuptools.setup(**args)
finally: finally:
distutils.core_setup_stop_after = None distutils.core._setup_stop_after = None
class DependsTests(TestCase): class DependsTests(unittest.TestCase):
def testExtractConst(self): 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(): def f1():
global x,y,z global x, y, z
x = "test" x = "test"
y = z y = z
fc = func_code(f1) fc = func_code(f1)
# unrecognized name # unrecognized name
self.assertEqual(extract_constant(fc,'q', -1), None) self.assertEqual(dep.extract_constant(fc,'q', -1), None)
# constant assigned # constant assigned
self.assertEqual(extract_constant(fc,'x', -1), "test") self.assertEqual(dep.extract_constant(fc,'x', -1), "test")
# expression assigned # expression assigned
self.assertEqual(extract_constant(fc,'y', -1), -1) self.assertEqual(dep.extract_constant(fc,'y', -1), -1)
# recognized name, not assigned # recognized name, not assigned
self.assertEqual(extract_constant(fc,'z', -1), None) self.assertEqual(dep.extract_constant(fc,'z', -1), None)
def testFindModule(self): def testFindModule(self):
self.assertRaises(ImportError, find_module, 'no-such.-thing') self.assertRaises(ImportError, dep.find_module, 'no-such.-thing')
self.assertRaises(ImportError, find_module, 'setuptools.non-existent') self.assertRaises(ImportError, dep.find_module, 'setuptools.non-existent')
f,p,i = find_module('setuptools.tests'); f.close() f,p,i = dep.find_module('setuptools.tests')
f.close()
def testModuleExtract(self): 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__ from email import __version__
self.assertEqual( self.assertEqual(
get_module_constant('email','__version__'), __version__ dep.get_module_constant('email','__version__'), __version__
) )
self.assertEqual( self.assertEqual(
get_module_constant('sys','version'), sys.version dep.get_module_constant('sys','version'), sys.version
) )
self.assertEqual( self.assertEqual(
get_module_constant('setuptools.tests','__doc__'),__doc__ dep.get_module_constant('setuptools.tests','__doc__'),__doc__
) )
def testRequire(self): 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') req = Require('Email','1.0.3','email')
...@@ -96,21 +104,21 @@ class DependsTests(TestCase): ...@@ -96,21 +104,21 @@ class DependsTests(TestCase):
from email import __version__ from email import __version__
self.assertEqual(req.get_version(), __version__) self.assertEqual(req.get_version(), __version__)
self.assert_(req.version_ok('1.0.9')) self.assertTrue(req.version_ok('1.0.9'))
self.assert_(not req.version_ok('0.9.1')) self.assertTrue(not req.version_ok('0.9.1'))
self.assert_(not req.version_ok('unknown')) self.assertTrue(not req.version_ok('unknown'))
self.assert_(req.is_present()) self.assertTrue(req.is_present())
self.assert_(req.is_current()) self.assertTrue(req.is_current())
req = Require('Email 3000','03000','email',format=LooseVersion) req = Require('Email 3000','03000','email',format=LooseVersion)
self.assert_(req.is_present()) self.assertTrue(req.is_present())
self.assert_(not req.is_current()) self.assertTrue(not req.is_current())
self.assert_(not req.version_ok('unknown')) self.assertTrue(not req.version_ok('unknown'))
req = Require('Do-what-I-mean','1.0','d-w-i-m') req = Require('Do-what-I-mean','1.0','d-w-i-m')
self.assert_(not req.is_present()) self.assertTrue(not req.is_present())
self.assert_(not req.is_current()) self.assertTrue(not req.is_current())
req = Require('Tests', None, 'tests', homepage="http://example.com") req = Require('Tests', None, 'tests', homepage="http://example.com")
self.assertEqual(req.format, None) self.assertEqual(req.format, None)
...@@ -120,11 +128,11 @@ class DependsTests(TestCase): ...@@ -120,11 +128,11 @@ class DependsTests(TestCase):
self.assertEqual(req.homepage, 'http://example.com') self.assertEqual(req.homepage, 'http://example.com')
paths = [os.path.dirname(p) for p in __path__] paths = [os.path.dirname(p) for p in __path__]
self.assert_(req.is_present(paths)) self.assertTrue(req.is_present(paths))
self.assert_(req.is_current(paths)) self.assertTrue(req.is_current(paths))
class DistroTests(TestCase): class DistroTests(unittest.TestCase):
def setUp(self): def setUp(self):
self.e1 = Extension('bar.ext',['bar.c']) self.e1 = Extension('bar.ext',['bar.c'])
...@@ -137,10 +145,8 @@ class DistroTests(TestCase): ...@@ -137,10 +145,8 @@ class DistroTests(TestCase):
package_dir = {}, package_dir = {},
) )
def testDistroType(self): def testDistroType(self):
self.assert_(isinstance(self.dist,setuptools.dist.Distribution)) self.assertTrue(isinstance(self.dist,setuptools.dist.Distribution))
def testExcludePackage(self): def testExcludePackage(self):
self.dist.exclude_package('a') self.dist.exclude_package('a')
...@@ -159,12 +165,6 @@ class DistroTests(TestCase): ...@@ -159,12 +165,6 @@ class DistroTests(TestCase):
# test removals from unspecified options # test removals from unspecified options
makeSetup().exclude_package('x') makeSetup().exclude_package('x')
def testIncludeExclude(self): def testIncludeExclude(self):
# remove an extension # remove an extension
self.dist.exclude(ext_modules=[self.e1]) self.dist.exclude(ext_modules=[self.e1])
...@@ -191,20 +191,17 @@ class DistroTests(TestCase): ...@@ -191,20 +191,17 @@ class DistroTests(TestCase):
dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2]) dist.exclude(packages=['a'], py_modules=['b'], ext_modules=[self.e2])
def testContents(self): 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.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.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.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): def testInvalidIncludeExclude(self):
self.assertRaises(DistutilsSetupError, self.assertRaises(DistutilsSetupError,
...@@ -234,20 +231,7 @@ class DistroTests(TestCase): ...@@ -234,20 +231,7 @@ class DistroTests(TestCase):
) )
class FeatureTests(unittest.TestCase):
class FeatureTests(TestCase):
def setUp(self): def setUp(self):
self.req = Require('Distutils','1.0.3','distutils') self.req = Require('Distutils','1.0.3','distutils')
...@@ -271,12 +255,12 @@ class FeatureTests(TestCase): ...@@ -271,12 +255,12 @@ class FeatureTests(TestCase):
) )
def testDefaults(self): def testDefaults(self):
self.assert_(not self.assertTrue(not
Feature( Feature(
"test",standard=True,remove='x',available=False "test",standard=True,remove='x',available=False
).include_by_default() ).include_by_default()
) )
self.assert_( self.assertTrue(
Feature("test",standard=True,remove='x').include_by_default() Feature("test",standard=True,remove='x').include_by_default()
) )
# Feature must have either kwargs, removes, or require_features # Feature must have either kwargs, removes, or require_features
...@@ -290,33 +274,33 @@ class FeatureTests(TestCase): ...@@ -290,33 +274,33 @@ class FeatureTests(TestCase):
def testFeatureOptions(self): def testFeatureOptions(self):
dist = self.dist dist = self.dist
self.assert_( self.assertTrue(
('with-dwim',None,'include DWIM') in dist.feature_options ('with-dwim',None,'include DWIM') in dist.feature_options
) )
self.assert_( self.assertTrue(
('without-dwim',None,'exclude DWIM (default)') in dist.feature_options ('without-dwim',None,'exclude DWIM (default)') in dist.feature_options
) )
self.assert_( self.assertTrue(
('with-bar',None,'include bar (default)') in dist.feature_options ('with-bar',None,'include bar (default)') in dist.feature_options
) )
self.assert_( self.assertTrue(
('without-bar',None,'exclude bar') in dist.feature_options ('without-bar',None,'exclude bar') in dist.feature_options
) )
self.assertEqual(dist.feature_negopt['without-foo'],'with-foo') self.assertEqual(dist.feature_negopt['without-foo'],'with-foo')
self.assertEqual(dist.feature_negopt['without-bar'],'with-bar') self.assertEqual(dist.feature_negopt['without-bar'],'with-bar')
self.assertEqual(dist.feature_negopt['without-dwim'],'with-dwim') 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): def testUseFeatures(self):
dist = self.dist dist = self.dist
self.assertEqual(dist.with_foo,1) self.assertEqual(dist.with_foo,1)
self.assertEqual(dist.with_bar,0) self.assertEqual(dist.with_bar,0)
self.assertEqual(dist.with_baz,1) self.assertEqual(dist.with_baz,1)
self.assert_(not 'bar_et' in dist.py_modules) self.assertTrue(not 'bar_et' in dist.py_modules)
self.assert_(not 'pkg.bar' in dist.packages) self.assertTrue(not 'pkg.bar' in dist.packages)
self.assert_('pkg.baz' in dist.packages) self.assertTrue('pkg.baz' in dist.packages)
self.assert_('scripts/baz_it' in dist.scripts) self.assertTrue('scripts/baz_it' in dist.scripts)
self.assert_(('libfoo','foo/foofoo.c') in dist.libraries) self.assertTrue(('libfoo','foo/foofoo.c') in dist.libraries)
self.assertEqual(dist.ext_modules,[]) self.assertEqual(dist.ext_modules,[])
self.assertEqual(dist.require_features, [self.req]) self.assertEqual(dist.require_features, [self.req])
...@@ -329,11 +313,11 @@ class FeatureTests(TestCase): ...@@ -329,11 +313,11 @@ class FeatureTests(TestCase):
SystemExit, makeSetup, features = {'x':Feature('x', remove='y')} SystemExit, makeSetup, features = {'x':Feature('x', remove='y')}
) )
class TestCommandTests(TestCase): class TestCommandTests(unittest.TestCase):
def testTestIsCommand(self): def testTestIsCommand(self):
test_cmd = makeSetup().get_command_obj('test') 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): def testLongOptSuiteWNoDefault(self):
ts1 = makeSetup(script_args=['test','--test-suite=foo.tests.suite']) ts1 = makeSetup(script_args=['test','--test-suite=foo.tests.suite'])
...@@ -365,8 +349,3 @@ class TestCommandTests(TestCase): ...@@ -365,8 +349,3 @@ class TestCommandTests(TestCase):
ts5 = makeSetup().get_command_obj('test') ts5 = makeSetup().get_command_obj('test')
ts5.ensure_finalized() ts5.ensure_finalized()
self.assertEqual(ts5.test_suite, None) 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 """Basic http server for tests to simulate PyPI or custom indexes
""" """
import sys import sys
from threading import Thread import time
import threading
import BaseHTTPServer
from setuptools.compat import (urllib2, URLError, HTTPServer, from setuptools.compat import (urllib2, URLError, HTTPServer,
SimpleHTTPRequestHandler) SimpleHTTPRequestHandler)
...@@ -16,32 +18,64 @@ class IndexServer(HTTPServer): ...@@ -16,32 +18,64 @@ class IndexServer(HTTPServer):
# The index files should be located in setuptools/tests/indexes # The index files should be located in setuptools/tests/indexes
s.stop() s.stop()
""" """
def __init__(self): def __init__(self, server_address=('', 0),
HTTPServer.__init__(self, ('', 0), SimpleHTTPRequestHandler) RequestHandlerClass=SimpleHTTPRequestHandler):
HTTPServer.__init__(self, server_address, RequestHandlerClass)
self._run = True self._run = True
def serve(self): def serve(self):
while True: while self._run:
self.handle_request() self.handle_request()
if not self._run: break
def start(self): def start(self):
self.thread = Thread(target=self.serve) self.thread = threading.Thread(target=self.serve)
self.thread.start() self.thread.start()
def stop(self): 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 self._run = False
url = 'http://127.0.0.1:%(server_port)s/' % vars(self)
try: try:
if sys.version > '2.6': if sys.version_info >= (2, 6):
urllib2.urlopen('http://127.0.0.1:%s/' % self.server_port, urllib2.urlopen(url, timeout=5)
None, 5)
else: else:
urllib2.urlopen('http://127.0.0.1:%s/' % self.server_port) urllib2.urlopen(url)
except URLError: except URLError:
# ignore any errors; all that's important is the request
pass pass
self.thread.join() self.thread.join()
def base_url(self): def base_url(self):
port = self.server_port port = self.server_port
return 'http://127.0.0.1:%s/setuptools/tests/indexes/' % 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 ...@@ -14,38 +14,62 @@ from setuptools.dist import Distribution
SETUP_PY = """\ SETUP_PY = """\
from setuptools import setup from setuptools import setup
setup(name='foo') setup(name='foo',
packages=['foo'],
use_2to3=True,
)
"""
INIT_PY = """print "foo"
""" """
class TestDevelopTest(unittest.TestCase): class TestDevelopTest(unittest.TestCase):
def setUp(self): def setUp(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return
# Directory structure
self.dir = tempfile.mkdtemp() self.dir = tempfile.mkdtemp()
os.mkdir(os.path.join(self.dir, 'foo'))
# setup.py
setup = os.path.join(self.dir, 'setup.py') setup = os.path.join(self.dir, 'setup.py')
f = open(setup, 'w') f = open(setup, 'w')
f.write(SETUP_PY) f.write(SETUP_PY)
f.close() f.close()
self.old_cwd = os.getcwd() 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) os.chdir(self.dir)
if sys.version >= "2.6": self.old_base = site.USER_BASE
self.old_base = site.USER_BASE site.USER_BASE = tempfile.mkdtemp()
site.USER_BASE = tempfile.mkdtemp() self.old_site = site.USER_SITE
self.old_site = site.USER_SITE site.USER_SITE = tempfile.mkdtemp()
site.USER_SITE = tempfile.mkdtemp()
def tearDown(self): def tearDown(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return
os.chdir(self.old_cwd) os.chdir(self.old_cwd)
shutil.rmtree(self.dir) shutil.rmtree(self.dir)
if sys.version >= "2.6": shutil.rmtree(site.USER_BASE)
shutil.rmtree(site.USER_BASE) shutil.rmtree(site.USER_SITE)
shutil.rmtree(site.USER_SITE) site.USER_BASE = self.old_base
site.USER_BASE = self.old_base site.USER_SITE = self.old_site
site.USER_SITE = self.old_site
def test_develop(self): def test_develop(self):
if sys.version < "2.6" or hasattr(sys, 'real_prefix'): if sys.version < "2.6" or hasattr(sys, 'real_prefix'):
return return
dist = Distribution() dist = Distribution(
dict(name='foo',
packages=['foo'],
use_2to3=True,
version='0.0',
))
dist.script_name = 'setup.py' dist.script_name = 'setup.py'
cmd = develop(dist) cmd = develop(dist)
cmd.user = 1 cmd.user = 1
...@@ -53,7 +77,7 @@ class TestDevelopTest(unittest.TestCase): ...@@ -53,7 +77,7 @@ class TestDevelopTest(unittest.TestCase):
cmd.install_dir = site.USER_SITE cmd.install_dir = site.USER_SITE
cmd.user = 1 cmd.user = 1
old_stdout = sys.stdout old_stdout = sys.stdout
sys.stdout = StringIO() #sys.stdout = StringIO()
try: try:
cmd.run() cmd.run()
finally: finally:
...@@ -62,9 +86,17 @@ class TestDevelopTest(unittest.TestCase): ...@@ -62,9 +86,17 @@ class TestDevelopTest(unittest.TestCase):
# let's see if we got our egg link at the right place # let's see if we got our egg link at the right place
content = os.listdir(site.USER_SITE) content = os.listdir(site.USER_SITE)
content.sort() 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 " wanted = ("Could not find suitable distribution for "
"Requirement.parse('I-DONT-EXIST')") "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 """Easy install Tests
""" """
import sys import sys
import os, shutil, tempfile, unittest import os
import shutil
import tempfile
import unittest
import site 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 easy_install, get_script_args, main
from setuptools.command.easy_install import PthDistributions from setuptools.command.easy_install import PthDistributions
from setuptools.command import easy_install as easy_install_pkg from setuptools.command import easy_install as easy_install_pkg
from setuptools.dist import Distribution from setuptools.dist import Distribution
from pkg_resources import Distribution as PRDistribution from pkg_resources import Distribution as PRDistribution
import setuptools.tests.server
try: try:
import multiprocessing # import multiprocessing solely for the purpose of testing its existence
__import__('multiprocessing')
import logging import logging
_LOG = logging.getLogger('test_easy_install') _LOG = logging.getLogger('test_easy_install')
logging.basicConfig(level=logging.INFO, stream=sys.stderr) logging.basicConfig(level=logging.INFO, stream=sys.stderr)
...@@ -58,7 +69,7 @@ class TestEasyInstallTest(unittest.TestCase): ...@@ -58,7 +69,7 @@ class TestEasyInstallTest(unittest.TestCase):
try: try:
cmd.install_site_py() cmd.install_site_py()
sitepy = os.path.join(cmd.install_dir, 'site.py') sitepy = os.path.join(cmd.install_dir, 'site.py')
self.assert_(os.path.exists(sitepy)) self.assertTrue(os.path.exists(sitepy))
finally: finally:
shutil.rmtree(cmd.install_dir) shutil.rmtree(cmd.install_dir)
...@@ -67,11 +78,11 @@ class TestEasyInstallTest(unittest.TestCase): ...@@ -67,11 +78,11 @@ class TestEasyInstallTest(unittest.TestCase):
old_platform = sys.platform old_platform = sys.platform
try: try:
name, script = next(get_script_args(dist)) name, script = [i for i in next(get_script_args(dist))][0:2]
finally: finally:
sys.platform = old_platform sys.platform = old_platform
self.assertEquals(script, WANTED) self.assertEqual(script, WANTED)
def test_no_setup_cfg(self): def test_no_setup_cfg(self):
# makes sure easy_install as a command (main) # makes sure easy_install as a command (main)
...@@ -92,7 +103,7 @@ class TestEasyInstallTest(unittest.TestCase): ...@@ -92,7 +103,7 @@ class TestEasyInstallTest(unittest.TestCase):
opts = self.command_options opts = self.command_options
if 'easy_install' in opts: if 'easy_install' in opts:
assert 'find_links' not in opts['easy_install'], msg 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._old_parse_command_line = Distribution.parse_command_line
Distribution.parse_command_line = _parse_command_line Distribution.parse_command_line = _parse_command_line
...@@ -100,33 +111,36 @@ class TestEasyInstallTest(unittest.TestCase): ...@@ -100,33 +111,36 @@ class TestEasyInstallTest(unittest.TestCase):
old_wd = os.getcwd() old_wd = os.getcwd()
try: try:
os.chdir(dir) os.chdir(dir)
main([]) reset_setup_stop_context(
lambda: self.assertRaises(SystemExit, main, [])
)
finally: finally:
os.chdir(old_wd) os.chdir(old_wd)
shutil.rmtree(dir) shutil.rmtree(dir)
Distribution.parse_command_line = Distribution._old_parse_command_line
def test_no_find_links(self): def test_no_find_links(self):
# new option '--no-find-links', that blocks find-links added at # new option '--no-find-links', that blocks find-links added at
# the project level # the project level
dist = Distribution() dist = Distribution()
cmd = easy_install(dist) cmd = easy_install(dist)
cmd.check_pth_processing = lambda : True cmd.check_pth_processing = lambda: True
cmd.no_find_links = True cmd.no_find_links = True
cmd.find_links = ['link1', 'link2'] cmd.find_links = ['link1', 'link2']
cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok') cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
cmd.args = ['ok'] cmd.args = ['ok']
cmd.ensure_finalized() cmd.ensure_finalized()
self.assertEquals(cmd.package_index.scanned_urls, {}) self.assertEqual(cmd.package_index.scanned_urls, {})
# let's try without it (default behavior) # let's try without it (default behavior)
cmd = easy_install(dist) cmd = easy_install(dist)
cmd.check_pth_processing = lambda : True cmd.check_pth_processing = lambda: True
cmd.find_links = ['link1', 'link2'] cmd.find_links = ['link1', 'link2']
cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok') cmd.install_dir = os.path.join(tempfile.mkdtemp(), 'ok')
cmd.args = ['ok'] cmd.args = ['ok']
cmd.ensure_finalized() cmd.ensure_finalized()
keys = sorted(cmd.package_index.scanned_urls.keys()) keys = sorted(cmd.package_index.scanned_urls.keys())
self.assertEquals(keys, ['link1', 'link2']) self.assertEqual(keys, ['link1', 'link2'])
class TestPTHFileWriter(unittest.TestCase): class TestPTHFileWriter(unittest.TestCase):
...@@ -135,15 +149,19 @@ class TestPTHFileWriter(unittest.TestCase): ...@@ -135,15 +149,19 @@ class TestPTHFileWriter(unittest.TestCase):
if a distribution is in site but also the cwd if a distribution is in site but also the cwd
''' '''
pth = PthDistributions('does-not_exist', [os.getcwd()]) pth = PthDistributions('does-not_exist', [os.getcwd()])
self.assert_(not pth.dirty) self.assertTrue(not pth.dirty)
pth.add(PRDistribution(os.getcwd())) pth.add(PRDistribution(os.getcwd()))
self.assert_(pth.dirty) self.assertTrue(pth.dirty)
def test_add_from_site_is_ignored(self): def test_add_from_site_is_ignored(self):
pth = PthDistributions('does-not_exist', ['/test/location/does-not-have-to-exist']) if os.name != 'nt':
self.assert_(not pth.dirty) location = '/test/location/does-not-have-to-exist'
pth.add(PRDistribution('/test/location/does-not-have-to-exist')) else:
self.assert_(not pth.dirty) 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): class TestUserInstallTest(unittest.TestCase):
...@@ -168,7 +186,7 @@ class TestUserInstallTest(unittest.TestCase): ...@@ -168,7 +186,7 @@ class TestUserInstallTest(unittest.TestCase):
def tearDown(self): def tearDown(self):
os.chdir(self.old_cwd) os.chdir(self.old_cwd)
shutil.rmtree(self.dir) shutil.rmtree(self.dir)
if sys.version >= "2.6": if sys.version >= "2.6":
shutil.rmtree(site.USER_BASE) shutil.rmtree(site.USER_BASE)
shutil.rmtree(site.USER_SITE) shutil.rmtree(site.USER_SITE)
site.USER_BASE = self.old_base site.USER_BASE = self.old_base
...@@ -220,7 +238,7 @@ class TestUserInstallTest(unittest.TestCase): ...@@ -220,7 +238,7 @@ class TestUserInstallTest(unittest.TestCase):
sys.path.append(target) sys.path.append(target)
old_ppath = os.environ.get('PYTHONPATH') old_ppath = os.environ.get('PYTHONPATH')
os.environ['PYTHONPATH'] = ':'.join(sys.path) os.environ['PYTHONPATH'] = os.path.pathsep.join(sys.path)
try: try:
dist = Distribution() dist = Distribution()
dist.script_name = 'setup.py' dist.script_name = 'setup.py'
...@@ -230,13 +248,212 @@ class TestUserInstallTest(unittest.TestCase): ...@@ -230,13 +248,212 @@ class TestUserInstallTest(unittest.TestCase):
cmd.ensure_finalized() cmd.ensure_finalized()
cmd.local_index.scan([new_location]) cmd.local_index.scan([new_location])
res = cmd.easy_install('foo') res = cmd.easy_install('foo')
self.assertEquals(res.location, new_location) self.assertEqual(os.path.realpath(res.location),
os.path.realpath(new_location))
finally: finally:
sys.path.remove(target) sys.path.remove(target)
shutil.rmtree(new_location) for basedir in [new_location, target, ]:
shutil.rmtree(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: if old_ppath is not None:
os.environ['PYTHONPATH'] = old_ppath os.environ['PYTHONPATH'] = old_ppath
else: else:
del os.environ['PYTHONPATH'] del os.environ['PYTHONPATH']
def test_setup_requires(self):
"""Regression test for issue #318
Ensures that a package with setup_requires can be installed when
distribute is installed in the user site-packages without causing a
SandboxViolation.
"""
test_setup_attrs = {
'name': 'test_pkg', 'version': '0.0',
'setup_requires': ['foobar'],
'dependency_links': [os.path.abspath(self.dir)]
}
test_pkg = os.path.join(self.dir, 'test_pkg')
test_setup_py = os.path.join(test_pkg, 'setup.py')
test_setup_cfg = os.path.join(test_pkg, 'setup.cfg')
os.mkdir(test_pkg)
f = open(test_setup_py, 'w')
f.write(textwrap.dedent("""\
import setuptools
setuptools.setup(**%r)
""" % test_setup_attrs))
f.close()
foobar_path = os.path.join(self.dir, 'foobar-0.1.tar.gz')
make_trivial_sdist(
foobar_path,
textwrap.dedent("""\
import setuptools
setuptools.setup(
name='foobar',
version='0.1'
)
"""))
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StringIO()
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 """Package Index Tests
""" """
# More would be better!
import sys import sys
import os, shutil, tempfile, unittest import unittest
import pkg_resources import pkg_resources
from setuptools.compat import urllib2, httplib, HTTPError from setuptools.compat import urllib2, httplib, HTTPError
import distutils.errors
import setuptools.package_index import setuptools.package_index
from setuptools.tests.server import IndexServer from setuptools.tests.server import IndexServer
class TestPackageIndex(unittest.TestCase): class TestPackageIndex(unittest.TestCase):
def test_bad_urls(self): def test_bad_url_bad_port(self):
index = setuptools.package_index.PackageIndex() index = setuptools.package_index.PackageIndex()
url = 'http://127.0.0.1:0/nonesuch/test_package_index' url = 'http://127.0.0.1:0/nonesuch/test_package_index'
try: try:
v = index.open_url(url) v = index.open_url(url)
except Exception: except Exception:
v = sys.exc_info()[1] v = sys.exc_info()[1]
self.assert_(url in str(v)) self.assertTrue(url in str(v))
else: else:
self.assert_(isinstance(v, HTTPError)) self.assertTrue(isinstance(v, HTTPError))
def test_bad_url_typo(self):
# issue 16 # issue 16
# easy_install inquant.contentmirror.plone breaks because of a typo # easy_install inquant.contentmirror.plone breaks because of a typo
# in its home URL # in its home URL
...@@ -33,9 +34,14 @@ class TestPackageIndex(unittest.TestCase): ...@@ -33,9 +34,14 @@ class TestPackageIndex(unittest.TestCase):
v = index.open_url(url) v = index.open_url(url)
except Exception: except Exception:
v = sys.exc_info()[1] v = sys.exc_info()[1]
self.assert_(url in str(v)) self.assertTrue(url in str(v))
else: 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): def _urlopen(*args):
raise httplib.BadStatusLine('line') raise httplib.BadStatusLine('line')
...@@ -48,20 +54,35 @@ class TestPackageIndex(unittest.TestCase): ...@@ -48,20 +54,35 @@ class TestPackageIndex(unittest.TestCase):
v = index.open_url(url) v = index.open_url(url)
except Exception: except Exception:
v = sys.exc_info()[1] v = sys.exc_info()[1]
self.assert_('line' in str(v)) self.assertTrue('line' in str(v))
else: else:
raise AssertionError('Should have raise here!') raise AssertionError('Should have raise here!')
finally: finally:
urllib2.urlopen = old_urlopen 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 # issue 20
url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk' url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk'
try: try:
index.open_url(url) index.open_url(url)
except Exception: except distutils.errors.DistutilsError:
v = sys.exc_info()[1] error = sys.exc_info()[1]
self.assert_('nonnumeric port' in str(v)) 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 # issue #160
if sys.version_info[0] == 2 and sys.version_info[1] == 7: if sys.version_info[0] == 2 and sys.version_info[1] == 7:
...@@ -71,13 +92,12 @@ class TestPackageIndex(unittest.TestCase): ...@@ -71,13 +92,12 @@ class TestPackageIndex(unittest.TestCase):
'http://www.famfamfam.com/">') 'http://www.famfamfam.com/">')
index.process_index(url, page) index.process_index(url, page)
def test_url_ok(self): def test_url_ok(self):
index = setuptools.package_index.PackageIndex( index = setuptools.package_index.PackageIndex(
hosts=('www.example.com',) hosts=('www.example.com',)
) )
url = 'file:///tmp/test_package_index' 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): def test_links_priority(self):
""" """
...@@ -94,6 +114,10 @@ class TestPackageIndex(unittest.TestCase): ...@@ -94,6 +114,10 @@ class TestPackageIndex(unittest.TestCase):
is used is used
-> Distribute should use the link from pypi, not the external one. -> 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 # start an index server
server = IndexServer() server = IndexServer()
server.start() server.start()
...@@ -106,11 +130,11 @@ class TestPackageIndex(unittest.TestCase): ...@@ -106,11 +130,11 @@ class TestPackageIndex(unittest.TestCase):
server.stop() server.stop()
# the distribution has been found # 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 # 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 # 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): def test_parse_bdist_wininst(self):
self.assertEqual(setuptools.package_index.parse_bdist_wininst( self.assertEqual(setuptools.package_index.parse_bdist_wininst(
...@@ -121,5 +145,3 @@ class TestPackageIndex(unittest.TestCase): ...@@ -121,5 +145,3 @@ class TestPackageIndex(unittest.TestCase):
'reportlab-2.5.win-amd64-py2.7.exe'), ('reportlab-2.5', '2.7', 'win-amd64')) 'reportlab-2.5.win-amd64-py2.7.exe'), ('reportlab-2.5', '2.7', 'win-amd64'))
self.assertEqual(setuptools.package_index.parse_bdist_wininst( self.assertEqual(setuptools.package_index.parse_bdist_wininst(
'reportlab-2.5.win-amd64.exe'), ('reportlab-2.5', None, 'win-amd64')) 'reportlab-2.5.win-amd64.exe'), ('reportlab-2.5', None, 'win-amd64'))
...@@ -9,6 +9,16 @@ try: frozenset ...@@ -9,6 +9,16 @@ try: frozenset
except NameError: except NameError:
from sets import ImmutableSet as frozenset 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): class Metadata(EmptyProvider):
"""Mock object to return metadata as if from an on-disk distribution""" """Mock object to return metadata as if from an on-disk distribution"""
...@@ -36,7 +46,7 @@ class DistroTests(TestCase): ...@@ -36,7 +46,7 @@ class DistroTests(TestCase):
ad.add(Distribution.from_filename("FooPkg-1.2-py2.4.egg")) ad.add(Distribution.from_filename("FooPkg-1.2-py2.4.egg"))
# Name is in there now # Name is in there now
self.assert_(ad['FooPkg']) self.assertTrue(ad['FooPkg'])
# But only 1 package # But only 1 package
self.assertEqual(list(ad), ['foopkg']) self.assertEqual(list(ad), ['foopkg'])
...@@ -219,7 +229,7 @@ class EntryPointTests(TestCase): ...@@ -219,7 +229,7 @@ class EntryPointTests(TestCase):
self.assertEqual(ep.module_name,"setuptools.tests.test_resources") self.assertEqual(ep.module_name,"setuptools.tests.test_resources")
self.assertEqual(ep.attrs, ("EntryPointTests",)) self.assertEqual(ep.attrs, ("EntryPointTests",))
self.assertEqual(ep.extras, ("x",)) self.assertEqual(ep.extras, ("x",))
self.assert_(ep.load() is EntryPointTests) self.assertTrue(ep.load() is EntryPointTests)
self.assertEqual( self.assertEqual(
str(ep), str(ep),
"foo = setuptools.tests.test_resources:EntryPointTests [x]" "foo = setuptools.tests.test_resources:EntryPointTests [x]"
...@@ -319,20 +329,20 @@ class RequirementsTests(TestCase): ...@@ -319,20 +329,20 @@ class RequirementsTests(TestCase):
foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg") foo_dist = Distribution.from_filename("FooPkg-1.3_1.egg")
twist11 = Distribution.from_filename("Twisted-1.1.egg") twist11 = Distribution.from_filename("Twisted-1.1.egg")
twist12 = Distribution.from_filename("Twisted-1.2.egg") twist12 = Distribution.from_filename("Twisted-1.2.egg")
self.assert_(parse_version('1.2') in r) self.assertTrue(parse_version('1.2') in r)
self.assert_(parse_version('1.1') not in r) self.assertTrue(parse_version('1.1') not in r)
self.assert_('1.2' in r) self.assertTrue('1.2' in r)
self.assert_('1.1' not in r) self.assertTrue('1.1' not in r)
self.assert_(foo_dist not in r) self.assertTrue(foo_dist not in r)
self.assert_(twist11 not in r) self.assertTrue(twist11 not in r)
self.assert_(twist12 in r) self.assertTrue(twist12 in r)
def testAdvancedContains(self): def testAdvancedContains(self):
r, = parse_requirements("Foo>=1.2,<=1.3,==1.9,>2.0,!=2.5,<3.0,==4.5") 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'): 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'): 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): def testOptionsAndHashing(self):
...@@ -354,14 +364,14 @@ class RequirementsTests(TestCase): ...@@ -354,14 +364,14 @@ class RequirementsTests(TestCase):
r2 = Requirement.parse("foo!=0.3a4") r2 = Requirement.parse("foo!=0.3a4")
d = Distribution.from_filename d = Distribution.from_filename
self.assert_(d("foo-0.3a4.egg") not in r1) self.assertTrue(d("foo-0.3a4.egg") not in r1)
self.assert_(d("foo-0.3a1.egg") not in r1) self.assertTrue(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 r2)
self.assert_(d("foo-0.3a2.egg") in r1) self.assertTrue(d("foo-0.3a2.egg") in r1)
self.assert_(d("foo-0.3a2.egg") in r2) self.assertTrue(d("foo-0.3a2.egg") in r2)
self.assert_(d("foo-0.3a3.egg") in r2) self.assertTrue(d("foo-0.3a3.egg") in r2)
self.assert_(d("foo-0.3a5.egg") in r2) self.assertTrue(d("foo-0.3a5.egg") in r2)
def testDistributeSetuptoolsOverride(self): def testDistributeSetuptoolsOverride(self):
# Plain setuptools or distribute mean we return distribute. # Plain setuptools or distribute mean we return distribute.
...@@ -468,27 +478,29 @@ class ParseTests(TestCase): ...@@ -468,27 +478,29 @@ class ParseTests(TestCase):
p1, p2 = parse_version(s1),parse_version(s2) p1, p2 = parse_version(s1),parse_version(s2)
self.assertEqual(p1,p2, (s1,s2,p1,p2)) self.assertEqual(p1,p2, (s1,s2,p1,p2))
c('1.2-rc1', '1.2rc1')
c('0.4', '0.4.0') c('0.4', '0.4.0')
c('0.4.0.0', '0.4.0') c('0.4.0.0', '0.4.0')
c('0.4.0-0', '0.4-0') c('0.4.0-0', '0.4-0')
c('0pl1', '0.0pl1') c('0pl1', '0.0pl1')
c('0pre1', '0.0c1') c('0pre1', '0.0c1')
c('0.0.0preview1', '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') c('1.2a1', '1.2.a.1'); c('1.2...a', '1.2a')
def testVersionOrdering(self): def testVersionOrdering(self):
def c(s1,s2): def c(s1,s2):
p1, p2 = parse_version(s1),parse_version(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','2.1.1')
c('2.1.0','2.10')
c('2a1','2b0') c('2a1','2b0')
c('2b1','2c0')
c('2a1','2.1') c('2a1','2.1')
c('2.3a1', '2.3') c('2.3a1', '2.3')
c('2.1-1', '2.1-2') c('2.1-1', '2.1-2')
c('2.1-1', '2.1.1') c('2.1-1', '2.1.1')
c('2.1', '2.1.1-1')
c('2.1', '2.1pl4') c('2.1', '2.1pl4')
c('2.1a0-20040501', '2.1') c('2.1a0-20040501', '2.1')
c('1.1', '02.1') c('1.1', '02.1')
...@@ -499,8 +511,20 @@ class ParseTests(TestCase): ...@@ -499,8 +511,20 @@ class ParseTests(TestCase):
c('0.4', '4.0') c('0.4', '4.0')
c('0.0.4', '0.4.0') c('0.0.4', '0.4.0')
c('0pl1', '0.4pl1') c('0pl1', '0.4pl1')
c('2.1.0-rc1','2.1.0')
c('2.1dev','2.1a0') 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 =""" torture ="""
0.80.1-3 0.80.1-2 0.80.1-1 0.79.9999+0.80.0pre4-1 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): ...@@ -554,12 +578,12 @@ class ScriptHeaderTests(TestCase):
self.assertEqual(get_script_header('#!/usr/bin/python -x', self.assertEqual(get_script_header('#!/usr/bin/python -x',
executable=exe), executable=exe),
'#!%s -x\n' % 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() sys.stdout = sys.stderr = StringIO()
self.assertEqual(get_script_header('#!/usr/bin/python', self.assertEqual(get_script_header('#!/usr/bin/python',
executable=self.non_ascii_exe), executable=self.non_ascii_exe),
'#!%s -x\n' % 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: finally:
sys.platform = platform sys.platform = platform
sys.stdout = stdout sys.stdout = stdout
...@@ -581,6 +605,13 @@ class NamespaceTests(TestCase): ...@@ -581,6 +605,13 @@ class NamespaceTests(TestCase):
pkg_resources._namespace_packages = self._ns_pkgs.copy() pkg_resources._namespace_packages = self._ns_pkgs.copy()
sys.path = self._prev_sys_path[:] 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): def test_two_levels_deep(self):
""" """
Test nested namespace packages Test nested namespace packages
...@@ -604,13 +635,13 @@ class NamespaceTests(TestCase): ...@@ -604,13 +635,13 @@ class NamespaceTests(TestCase):
pkg2_init.write(ns_str) pkg2_init.write(ns_str)
pkg2_init.close() pkg2_init.close()
import pkg1 import pkg1
self.assertTrue("pkg1" in pkg_resources._namespace_packages.keys()) self._assertIn("pkg1", pkg_resources._namespace_packages.keys())
try: try:
import pkg1.pkg2 import pkg1.pkg2
except ImportError: except ImportError:
self.fail("Distribute tried to import the parent namespace package") self.fail("Distribute tried to import the parent namespace package")
# check the _namespace_packages dict # 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"]) self.assertEqual(pkg_resources._namespace_packages["pkg1"], ["pkg1.pkg2"])
# check the __path__ attribute contains both paths # check the __path__ attribute contains both paths
self.assertEqual(pkg1.pkg2.__path__, [ 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(): def __boot():
import sys, imp, os, os.path import sys, os, os.path
PYTHONPATH = os.environ.get('PYTHONPATH') PYTHONPATH = os.environ.get('PYTHONPATH')
if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH): if PYTHONPATH is None or (sys.platform=='win32' and not PYTHONPATH):
PYTHONPATH = [] PYTHONPATH = []
...@@ -23,6 +23,7 @@ def __boot(): ...@@ -23,6 +23,7 @@ def __boot():
break break
else: else:
try: try:
import imp # Avoid import loop in Python >= 3.3
stream, path, descr = imp.find_module('site',[item]) stream, path, descr = imp.find_module('site',[item])
except ImportError: except ImportError:
continue continue
......
#!/bin/sh #!/bin/sh
echo -n "Running tests for Python 2.3..." echo -n "Running tests for Python 2.4..."
python2.3 setup.py -q test > /dev/null 2> /dev/null python2.4 setup.py -q test > /dev/null 2> /dev/null
if [ $? -ne 0 ];then if [ $? -ne 0 ];then
echo "Failed" echo "Failed"
exit $1 exit $1
...@@ -8,8 +8,8 @@ else ...@@ -8,8 +8,8 @@ else
echo "Success" echo "Success"
fi fi
echo -n "Running tests for Python 2.4..." echo -n "Running tests for Python 2.5..."
python2.4 setup.py -q test > /dev/null 2> /dev/null python2.5 setup.py -q test > /dev/null 2> /dev/null
if [ $? -ne 0 ];then if [ $? -ne 0 ];then
echo "Failed" echo "Failed"
exit $1 exit $1
...@@ -17,8 +17,8 @@ else ...@@ -17,8 +17,8 @@ else
echo "Success" echo "Success"
fi fi
echo -n "Running tests for Python 2.5..." echo -n "Running tests for Python 2.6..."
python2.5 setup.py -q test > /dev/null 2> /dev/null python2.6 setup.py -q test > /dev/null 2> /dev/null
if [ $? -ne 0 ];then if [ $? -ne 0 ];then
echo "Failed" echo "Failed"
exit $1 exit $1
...@@ -26,8 +26,8 @@ else ...@@ -26,8 +26,8 @@ else
echo "Success" echo "Success"
fi fi
echo -n "Running tests for Python 2.6..." echo -n "Running tests for Python 2.7..."
python2.6 setup.py -q test > /dev/null 2> /dev/null python2.7 setup.py -q test > /dev/null 2> /dev/null
if [ $? -ne 0 ];then if [ $? -ne 0 ];then
echo "Failed" echo "Failed"
exit $1 exit $1
...@@ -45,3 +45,23 @@ else ...@@ -45,3 +45,23 @@ else
echo "Success" echo "Success"
fi 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): ...@@ -43,13 +43,13 @@ class TestSetup(unittest.TestCase):
# now trying to import it # now trying to import it
sys.path[0] = egg sys.path[0] = egg
import setuptools import setuptools
self.assert_(setuptools.__file__.startswith(egg)) self.assertTrue(setuptools.__file__.startswith(egg))
def test_do_download(self): def test_do_download(self):
tmpdir = tempfile.mkdtemp() tmpdir = tempfile.mkdtemp()
_do_download(DEFAULT_VERSION, DEFAULT_URL, tmpdir, 1) _do_download(DEFAULT_VERSION, DEFAULT_URL, tmpdir, 1)
import setuptools import setuptools
self.assert_(setuptools.bootstrap_install_from.startswith(tmpdir)) self.assertTrue(setuptools.bootstrap_install_from.startswith(tmpdir))
def test_install(self): def test_install(self):
def _faked(*args): def _faked(*args):
...@@ -58,7 +58,7 @@ class TestSetup(unittest.TestCase): ...@@ -58,7 +58,7 @@ class TestSetup(unittest.TestCase):
_install(self.tarball) _install(self.tarball)
def test_use_setuptools(self): def test_use_setuptools(self):
self.assertEquals(use_setuptools(), None) self.assertEqual(use_setuptools(), None)
# make sure fake_setuptools is not called by default # make sure fake_setuptools is not called by default
import pkg_resources 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