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.
......
This diff is collapsed.
...@@ -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""")
This diff is collapsed.
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)
This diff is collapsed.
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