aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.hgtags2
-rw-r--r--CHANGES.txt31
-rw-r--r--DEVGUIDE.txt1
-rw-r--r--docs/developer-guide.txt5
-rw-r--r--docs/pkg_resources.txt2
-rw-r--r--docs/setuptools.txt10
-rw-r--r--ez_setup.py4
-rw-r--r--pkg_resources/__init__.py17
-rwxr-xr-xpytest.ini2
-rw-r--r--scripts/upload-old-releases-as-zip.py242
-rwxr-xr-xsetup.py4
-rwxr-xr-xsetuptools/command/develop.py27
-rwxr-xr-xsetuptools/command/easy_install.py28
-rw-r--r--setuptools/command/install_lib.py2
-rw-r--r--setuptools/command/test.py13
-rw-r--r--setuptools/py31compat.py2
-rw-r--r--setuptools/tests/test_develop.py131
-rw-r--r--setuptools/version.py2
-rw-r--r--tox.ini6
19 files changed, 439 insertions, 92 deletions
diff --git a/.hgtags b/.hgtags
index 5729d664..6ed522b4 100644
--- a/.hgtags
+++ b/.hgtags
@@ -223,3 +223,5 @@ b59320212c8371d0be9e5e6c5f7eec392124c009 18.3
1e120f04bcaa2421c4df0eb6678c3019ba4a82f6 18.3.2
6203335278be7543d31790d9fba55739469a4c6c 18.4
31dc6d2ac0f5ab766652602fe6ca716fff7180e7 18.5
+dfe190b09908f6b953209d13573063809de451b8 18.6
+804f87045a901f1dc121cf9149143d654228dc13 18.6.1
diff --git a/CHANGES.txt b/CHANGES.txt
index bd05b8bd..fa89b09b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -2,6 +2,37 @@
CHANGES
=======
+
+----
+18.7
+----
+
+* Update dependency on certify.
+* Pull Request #160: Improve detection of gui script in
+ ``easy_install._adjust_header``.
+* Made ``test.test_args`` a non-data property; alternate fix
+ for the issue reported in Pull Request #155.
+* Issue #453: In ``ez_setup`` bootstrap module, unload all
+ ``pkg_resources`` modules following download.
+* Pull Request #158: Honor `PEP-488
+ <https://www.python.org/dev/peps/pep-0488/>`_ when excluding
+ files for namespace packages.
+
+------
+18.6.1
+------
+
+* Issue #464: Correct regression in invocation of superclass on old-style
+ class on Python 2.
+
+----
+18.6
+----
+
+* Issue #439: When installing entry_point scripts under development,
+ omit the version number of the package, allowing any version of the
+ package to be used.
+
----
18.5
----
diff --git a/DEVGUIDE.txt b/DEVGUIDE.txt
deleted file mode 100644
index 066a3a6b..00000000
--- a/DEVGUIDE.txt
+++ /dev/null
@@ -1 +0,0 @@
-The canonical development guide can be found in docs/developer-guide.txt.
diff --git a/docs/developer-guide.txt b/docs/developer-guide.txt
index 27c304e5..ae33649b 100644
--- a/docs/developer-guide.txt
+++ b/docs/developer-guide.txt
@@ -92,9 +92,10 @@ Testing
The primary tests are run using py.test. To run the tests::
- $ python setup.py ptr
+ $ python setup.py test
-Or install py.test into your environment and run ``py.test``.
+Or install py.test into your environment and run ``PYTHONPATH=. py.test``
+or ``python -m pytest``.
Under continuous integration, additional tests may be run. See the
``.travis.yml`` file for full details on the tests run under Travis-CI.
diff --git a/docs/pkg_resources.txt b/docs/pkg_resources.txt
index 6c6405a8..3d40a1a2 100644
--- a/docs/pkg_resources.txt
+++ b/docs/pkg_resources.txt
@@ -592,7 +592,7 @@ Requirements Parsing
The syntax of a requirement specifier can be defined in EBNF as follows::
- requirement ::= project_name versionspec? extras?
+ requirement ::= project_name extras? versionspec?
versionspec ::= comparison version (',' comparison version)*
comparison ::= '<' | '<=' | '!=' | '==' | '>=' | '>' | '~=' | '==='
extras ::= '[' extralist? ']'
diff --git a/docs/setuptools.txt b/docs/setuptools.txt
index e2753cba..d6a62de8 100644
--- a/docs/setuptools.txt
+++ b/docs/setuptools.txt
@@ -112,10 +112,16 @@ the distutils. Here's a minimal setup script using setuptools::
)
As you can see, it doesn't take much to use setuptools in a project.
-Just by doing the above, this project will be able to produce eggs, upload to
+Run that script in your project folder, alongside the Python packages
+you have developed.
+
+Invoke that script to produce eggs, upload to
PyPI, and automatically include all packages in the directory where the
setup.py lives. See the `Command Reference`_ section below to see what
-commands you can give to this setup script.
+commands you can give to this setup script. For example,
+to produce a source distribution, simply invoke::
+
+ python setup.py sdist
Of course, before you release your project to PyPI, you'll want to add a bit
more information to your setup script to help people find or learn about your
diff --git a/ez_setup.py b/ez_setup.py
index c41c10e9..2f5e4856 100644
--- a/ez_setup.py
+++ b/ez_setup.py
@@ -30,7 +30,7 @@ try:
except ImportError:
USER_SITE = None
-DEFAULT_VERSION = "18.6"
+DEFAULT_VERSION = "18.6.2"
DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
DEFAULT_SAVE_DIR = os.curdir
@@ -125,7 +125,7 @@ def _do_download(version, download_base, to_dir, download_delay):
# Remove previously-imported pkg_resources if present (see
# https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
if 'pkg_resources' in sys.modules:
- del sys.modules['pkg_resources']
+ _unload_pkg_resources()
import setuptools
setuptools.bootstrap_install_from = egg
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py
index 7c3e18b4..46f09a2d 100644
--- a/pkg_resources/__init__.py
+++ b/pkg_resources/__init__.py
@@ -1716,7 +1716,7 @@ class EggProvider(NullProvider):
path = self.module_path
old = None
while path!=old:
- if path.lower().endswith('.egg'):
+ if _is_unpacked_egg(path):
self.egg_name = os.path.basename(path)
self.egg_info = os.path.join(path, 'EGG-INFO')
self.egg_root = path
@@ -2099,7 +2099,7 @@ def find_eggs_in_zip(importer, path_item, only=False):
# don't yield nested distros
return
for subitem in metadata.resource_listdir('/'):
- if subitem.endswith('.egg'):
+ if _is_unpacked_egg(subitem):
subpath = os.path.join(path_item, subitem)
for dist in find_eggs_in_zip(zipimport.zipimporter(subpath), subpath):
yield dist
@@ -2115,8 +2115,7 @@ def find_on_path(importer, path_item, only=False):
path_item = _normalize_cached(path_item)
if os.path.isdir(path_item) and os.access(path_item, os.R_OK):
- if path_item.lower().endswith('.egg'):
- # unpacked egg
+ if _is_unpacked_egg(path_item):
yield Distribution.from_filename(
path_item, metadata=PathMetadata(
path_item, os.path.join(path_item,'EGG-INFO')
@@ -2136,7 +2135,7 @@ def find_on_path(importer, path_item, only=False):
yield Distribution.from_location(
path_item, entry, metadata, precedence=DEVELOP_DIST
)
- elif not only and lower.endswith('.egg'):
+ elif not only and _is_unpacked_egg(entry):
dists = find_distributions(os.path.join(path_item, entry))
for dist in dists:
yield dist
@@ -2283,6 +2282,14 @@ def _normalize_cached(filename, _cache={}):
_cache[filename] = result = normalize_path(filename)
return result
+def _is_unpacked_egg(path):
+ """
+ Determine if given path appears to be an unpacked egg.
+ """
+ return (
+ path.lower().endswith('.egg')
+ )
+
def _set_parent_ns(packageName):
parts = packageName.split('.')
name = parts.pop()
diff --git a/pytest.ini b/pytest.ini
index 91d64bb8..351942f4 100755
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,3 +1,3 @@
[pytest]
-addopts=--doctest-modules --ignore release.py --ignore setuptools/lib2to3_ex.py --ignore tests/manual_test.py --ignore tests/shlib_test --doctest-glob=pkg_resources/api_tests.txt
+addopts=--doctest-modules --ignore release.py --ignore setuptools/lib2to3_ex.py --ignore tests/manual_test.py --ignore tests/shlib_test --doctest-glob=pkg_resources/api_tests.txt --ignore scripts/upload-old-releases-as-zip.py
norecursedirs=dist build *.egg
diff --git a/scripts/upload-old-releases-as-zip.py b/scripts/upload-old-releases-as-zip.py
new file mode 100644
index 00000000..38cfcd55
--- /dev/null
+++ b/scripts/upload-old-releases-as-zip.py
@@ -0,0 +1,242 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# declare and require dependencies
+__requires__ = [
+ 'twine',
+]; __import__('pkg_resources')
+
+import errno
+import glob
+import hashlib
+import json
+import os
+import shutil
+import tarfile
+import codecs
+import urllib.request
+import urllib.parse
+import urllib.error
+from distutils.version import LooseVersion
+
+from twine.commands import upload
+
+
+OK = '\033[92m'
+FAIL = '\033[91m'
+END = '\033[0m'
+DISTRIBUTION = "setuptools"
+
+
+class SetuptoolsOldReleasesWithoutZip:
+ """docstring for SetuptoolsOldReleases"""
+
+ def __init__(self):
+ self.dirpath = './dist'
+ os.makedirs(self.dirpath, exist_ok=True)
+ print("Downloading %s releases..." % DISTRIBUTION)
+ print("All releases will be downloaded to %s" % self.dirpath)
+ self.data_json_setuptools = self.get_json_data(DISTRIBUTION)
+ self.valid_releases_numbers = sorted([
+ release
+ for release in self.data_json_setuptools['releases']
+ # This condition is motivated by 13.0 release, which
+ # comes as "13.0": [], in the json
+ if self.data_json_setuptools['releases'][release]
+ ], key=LooseVersion)
+ self.total_downloaded_ok = 0
+
+ def get_json_data(self, package_name):
+ """
+ "releases": {
+ "0.7.2": [
+ {
+ "has_sig": false,
+ "upload_time": "2013-06-09T16:10:00",
+ "comment_text": "",
+ "python_version": "source",
+ "url": "https://pypi.python.org/packages/source/s/setuptools/setuptools-0.7.2.tar.gz", # NOQA
+ "md5_digest": "de44cd90f8a1c713d6c2bff67bbca65d",
+ "downloads": 159014,
+ "filename": "setuptools-0.7.2.tar.gz",
+ "packagetype": "sdist",
+ "size": 633077
+ }
+ ],
+ "0.7.3": [
+ {
+ "has_sig": false,
+ "upload_time": "2013-06-18T21:08:56",
+ "comment_text": "",
+ "python_version": "source",
+ "url": "https://pypi.python.org/packages/source/s/setuptools/setuptools-0.7.3.tar.gz", # NOQA
+ "md5_digest": "c854adacbf9067d330a847f06f7a8eba",
+ "downloads": 30594,
+ "filename": "setuptools-0.7.3.tar.gz",
+ "packagetype": "sdist",
+ "size": 751152
+ }
+ ],
+ "12.3": [
+ {
+ "has_sig": false,
+ "upload_time": "2015-02-26T19:15:51",
+ "comment_text": "",
+ "python_version": "3.4",
+ "url": "https://pypi.python.org/packages/3.4/s/setuptools/setuptools-12.3-py2.py3-none-any.whl", # NOQA
+ "md5_digest": "31f51a38497a70efadf5ce8d4c2211ab",
+ "downloads": 288451,
+ "filename": "setuptools-12.3-py2.py3-none-any.whl",
+ "packagetype": "bdist_wheel",
+ "size": 501904
+ },
+ {
+ "has_sig": false,
+ "upload_time": "2015-02-26T19:15:43",
+ "comment_text": "",
+ "python_version": "source",
+ "url": "https://pypi.python.org/packages/source/s/setuptools/setuptools-12.3.tar.gz", # NOQA
+ "md5_digest": "67614b6d560fa4f240e99cd553ec7f32",
+ "downloads": 110109,
+ "filename": "setuptools-12.3.tar.gz",
+ "packagetype": "sdist",
+ "size": 635025
+ },
+ {
+ "has_sig": false,
+ "upload_time": "2015-02-26T19:15:47",
+ "comment_text": "",
+ "python_version": "source",
+ "url": "https://pypi.python.org/packages/source/s/setuptools/setuptools-12.3.zip", # NOQA
+ "md5_digest": "abc799e7db6e7281535bf342bfc41a12",
+ "downloads": 67539,
+ "filename": "setuptools-12.3.zip",
+ "packagetype": "sdist",
+ "size": 678783
+ }
+ ],
+ """
+ url = "https://pypi.python.org/pypi/%s/json" % (package_name,)
+ resp = urllib.request.urlopen(urllib.request.Request(url))
+ charset = resp.info().get_content_charset()
+ reader = codecs.getreader(charset)(resp)
+ data = json.load(reader)
+
+ # Mainly for debug.
+ json_filename = "%s/%s.json" % (self.dirpath, DISTRIBUTION)
+ with open(json_filename, 'w') as outfile:
+ json.dump(
+ data,
+ outfile,
+ sort_keys=True,
+ indent=4,
+ separators=(',', ': '),
+ )
+
+ return data
+
+ def get_setuptools_releases_without_zip_counterpart(self):
+ # Get set(all_valid_releases) - set(releases_with_zip), so now we have
+ # the releases without zip.
+ return set(self.valid_releases_numbers) - set([
+ release
+ for release in self.valid_releases_numbers
+ for same_version_release_dict in self.data_json_setuptools['releases'][release] # NOQA
+ if 'zip' in same_version_release_dict['filename']
+ ])
+
+ def download_setuptools_releases_without_zip_counterpart(self):
+ try:
+ releases_without_zip = self.get_setuptools_releases_without_zip_counterpart() # NOQA
+ failed_md5_releases = []
+ # This is a "strange" loop, going through all releases and
+ # testing only the release I need to download, but I thought it
+ # would be mouch more readable than trying to iterate through
+ # releases I need and get into traverse hell values inside dicts
+ # inside dicts of the json to get the distribution's url to
+ # download.
+ for release in self.valid_releases_numbers:
+ if release in releases_without_zip:
+ for same_version_release_dict in self.data_json_setuptools['releases'][release]: # NOQA
+ if 'tar.gz' in same_version_release_dict['filename']:
+ print("Downloading %s..." % release)
+ local_file = '%s/%s' % (
+ self.dirpath,
+ same_version_release_dict["filename"]
+ )
+ urllib.request.urlretrieve(
+ same_version_release_dict["url"],
+ local_file
+ )
+ targz = open(local_file, 'rb').read()
+ hexdigest = hashlib.md5(targz).hexdigest()
+ if (hexdigest != same_version_release_dict['md5_digest']): # NOQA
+ print(FAIL + "FAIL: md5 for %s didn't match!" % release + END) # NOQA
+ failed_md5_releases.append(release)
+ else:
+ self.total_downloaded_ok += 1
+ print('Total releases without zip: %s' % len(releases_without_zip))
+ print('Total downloaded: %s' % self.total_downloaded_ok)
+ if failed_md5_releases:
+ msg = FAIL + (
+ "FAIL: these releases %s failed the md5 check!" %
+ ','.join(failed_md5_releases)
+ ) + END
+ raise Exception(msg)
+ elif self.total_downloaded_ok != len(releases_without_zip):
+ msg = FAIL + (
+ "FAIL: Unknown error occured. Please check the logs."
+ ) + END
+ raise Exception(msg)
+ else:
+ print(OK + "All releases downloaded and md5 checked." + END)
+
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise e
+
+ def convert_targz_to_zip(self):
+ print("Converting the tar.gz to zip...")
+ files = glob.glob('%s/*.tar.gz' % self.dirpath)
+ total_converted = 0
+ for targz in sorted(files, key=LooseVersion):
+ # Extract and remove tar.
+ tar = tarfile.open(targz)
+ tar.extractall(path=self.dirpath)
+ tar.close()
+ os.remove(targz)
+
+ # Zip the extracted tar.
+ setuptools_folder_path = targz.replace('.tar.gz', '')
+ setuptools_folder_name = setuptools_folder_path.split("/")[-1]
+ print(setuptools_folder_name)
+ shutil.make_archive(
+ setuptools_folder_path,
+ 'zip',
+ self.dirpath,
+ setuptools_folder_name
+ )
+ # Exclude extracted tar folder.
+ shutil.rmtree(setuptools_folder_path.replace('.zip', ''))
+ total_converted += 1
+ print('Total converted: %s' % total_converted)
+ if self.total_downloaded_ok != total_converted:
+ msg = FAIL + (
+ "FAIL: Total number of downloaded releases is different"
+ " from converted ones. Please check the logs."
+ ) + END
+ raise Exception(msg)
+ print("Done with the tar.gz->zip. Check folder %s." % main.dirpath)
+
+ def upload_zips_to_pypi(self):
+ print('Uploading to pypi...')
+ zips = sorted(glob.glob('%s/*.zip' % self.dirpath), key=LooseVersion)
+ print("simulated upload of", zips); return
+ upload.upload(dists=zips)
+
+
+if __name__ == '__main__':
+ main = SetuptoolsOldReleasesWithoutZip()
+ main.download_setuptools_releases_without_zip_counterpart()
+ main.convert_targz_to_zip()
+ main.upload_zips_to_pypi()
diff --git a/setup.py b/setup.py
index 6226111d..9d7f228d 100755
--- a/setup.py
+++ b/setup.py
@@ -150,10 +150,10 @@ setup_params = dict(
""").strip().splitlines(),
extras_require={
"ssl:sys_platform=='win32'": "wincertstore==0.2",
- "certs": "certifi==2015.04.28",
+ "certs": "certifi==2015.11.20",
},
dependency_links=[
- 'https://pypi.python.org/packages/source/c/certifi/certifi-2015.04.28.tar.gz#md5=12c7c3a063b2ff97a0f8291d8de41e8c',
+ 'https://pypi.python.org/packages/source/c/certifi/certifi-2015.11.20.tar.gz#md5=25134646672c695c1ff1593c2dd75d08',
'https://pypi.python.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2',
],
scripts=[],
diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py
index 368b64fe..5ae25d71 100755
--- a/setuptools/command/develop.py
+++ b/setuptools/command/develop.py
@@ -167,3 +167,30 @@ class develop(easy_install):
script_text = f.read()
f.close()
self.install_script(dist, script_name, script_text, script_path)
+
+ def install_wrapper_scripts(self, dist):
+ dist = VersionlessRequirement(dist)
+ return easy_install.install_wrapper_scripts(self, dist)
+
+
+class VersionlessRequirement(object):
+ """
+ Adapt a pkg_resources.Distribution to simply return the project
+ name as the 'requirement' so that scripts will work across
+ multiple versions.
+
+ >>> dist = Distribution(project_name='foo', version='1.0')
+ >>> str(dist.as_requirement())
+ 'foo==1.0'
+ >>> adapted_dist = VersionlessRequirement(dist)
+ >>> str(adapted_dist.as_requirement())
+ 'foo'
+ """
+ def __init__(self, dist):
+ self.__dist = dist
+
+ def __getattr__(self, name):
+ return getattr(self.__dist, name)
+
+ def as_requirement(self):
+ return self.project_name
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
index 45d180bb..9e9c5e54 100755
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -20,6 +20,7 @@ from distutils.errors import DistutilsArgError, DistutilsOptionError, \
from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS
from distutils import log, dir_util
from distutils.command.build_scripts import first_line_re
+from distutils.spawn import find_executable
import sys
import os
import zipimport
@@ -760,9 +761,10 @@ class easy_install(Command):
return dst
def install_wrapper_scripts(self, dist):
- if not self.exclude_scripts:
- for args in ScriptWriter.best().get_args(dist):
- self.write_script(*args)
+ if self.exclude_scripts:
+ return
+ for args in ScriptWriter.best().get_args(dist):
+ self.write_script(*args)
def install_script(self, dist, script_name, script_text, dev_path=None):
"""Generate a legacy script wrapper and install it"""
@@ -2125,8 +2127,8 @@ class WindowsScriptWriter(ScriptWriter):
blockers = [name + x for x in old]
yield name + ext, header + script_text, 't', blockers
- @staticmethod
- def _adjust_header(type_, orig_header):
+ @classmethod
+ def _adjust_header(cls, type_, orig_header):
"""
Make sure 'pythonw' is used for gui and and 'python' is used for
console (regardless of what sys.executable is).
@@ -2137,11 +2139,19 @@ class WindowsScriptWriter(ScriptWriter):
pattern, repl = repl, pattern
pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE)
new_header = pattern_ob.sub(string=orig_header, repl=repl)
+ return new_header if cls._use_header(new_header) else orig_header
+
+ @staticmethod
+ def _use_header(new_header):
+ """
+ Should _adjust_header use the replaced header?
+
+ On non-windows systems, always use. On
+ Windows systems, only use the replaced header if it resolves
+ to an executable on the system.
+ """
clean_header = new_header[2:-1].strip('"')
- if sys.platform == 'win32' and not os.path.exists(clean_header):
- # the adjusted version doesn't exist, so return the original
- return orig_header
- return new_header
+ return sys.platform != 'win32' or find_executable(clean_header)
class WindowsExecutableLauncherWriter(WindowsScriptWriter):
diff --git a/setuptools/command/install_lib.py b/setuptools/command/install_lib.py
index 9b772227..78fe6891 100644
--- a/setuptools/command/install_lib.py
+++ b/setuptools/command/install_lib.py
@@ -79,6 +79,8 @@ class install_lib(orig.install_lib):
base = os.path.join('__pycache__', '__init__.' + imp.get_tag())
yield base + '.pyc'
yield base + '.pyo'
+ yield base + '.opt-1.pyc'
+ yield base + '.opt-2.pyc'
def copy_tree(
self, infile, outfile,
diff --git a/setuptools/command/test.py b/setuptools/command/test.py
index 160e21c9..c26f5fc9 100644
--- a/setuptools/command/test.py
+++ b/setuptools/command/test.py
@@ -41,6 +41,17 @@ class ScanningLoader(TestLoader):
return tests[0] # don't create a nested suite for only one return
+# adapted from jaraco.classes.properties:NonDataProperty
+class NonDataProperty(object):
+ def __init__(self, fget):
+ self.fget = fget
+
+ def __get__(self, obj, objtype=None):
+ if obj is None:
+ return self
+ return self.fget(obj)
+
+
class test(Command):
"""Command to run unit tests after in-place build"""
@@ -78,7 +89,7 @@ class test(Command):
if self.test_runner is None:
self.test_runner = getattr(self.distribution, 'test_runner', None)
- @property
+ @NonDataProperty
def test_args(self):
return list(self._test_args())
diff --git a/setuptools/py31compat.py b/setuptools/py31compat.py
index c487ac04..8fe6dd9d 100644
--- a/setuptools/py31compat.py
+++ b/setuptools/py31compat.py
@@ -20,7 +20,7 @@ except ImportError:
import shutil
import tempfile
class TemporaryDirectory(object):
- """"
+ """
Very simple temporary directory context manager.
Will try to delete afterward, but will also ignore OS and similar
errors on deletion.
diff --git a/setuptools/tests/test_develop.py b/setuptools/tests/test_develop.py
index ed1b194a..ab5da00e 100644
--- a/setuptools/tests/test_develop.py
+++ b/setuptools/tests/test_develop.py
@@ -1,13 +1,17 @@
"""develop tests
"""
import os
-import shutil
import site
import sys
-import tempfile
+import io
+
+import pytest
from setuptools.command.develop import develop
from setuptools.dist import Distribution
+from . import contexts
+from setuptools.compat import PY3
+
SETUP_PY = """\
from setuptools import setup
@@ -21,65 +25,52 @@ setup(name='foo',
INIT_PY = """print "foo"
"""
-class TestDevelopTest:
+@pytest.yield_fixture
+def temp_user(monkeypatch):
+ with contexts.tempdir() as user_base:
+ with contexts.tempdir() as user_site:
+ monkeypatch.setattr('site.USER_BASE', user_base)
+ monkeypatch.setattr('site.USER_SITE', user_site)
+ yield
- def setup_method(self, method):
- if hasattr(sys, 'real_prefix'):
- return
- # Directory structure
- self.dir = tempfile.mkdtemp()
- os.mkdir(os.path.join(self.dir, 'foo'))
- # setup.py
- setup = os.path.join(self.dir, 'setup.py')
- f = open(setup, 'w')
+@pytest.yield_fixture
+def test_env(tmpdir, temp_user):
+ target = tmpdir
+ foo = target.mkdir('foo')
+ setup = target / 'setup.py'
+ if setup.isfile():
+ raise ValueError(dir(target))
+ with setup.open('w') as f:
f.write(SETUP_PY)
- f.close()
- self.old_cwd = os.getcwd()
- # foo/__init__.py
- init = os.path.join(self.dir, 'foo', '__init__.py')
- f = open(init, 'w')
+ init = foo / '__init__.py'
+ with init.open('w') as f:
f.write(INIT_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()
+ with target.as_cwd():
+ yield target
- def teardown_method(self, method):
- if hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.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_develop(self):
- if hasattr(sys, 'real_prefix'):
- return
- dist = Distribution(
- dict(name='foo',
- packages=['foo'],
- use_2to3=True,
- version='0.0',
- ))
+class TestDevelop:
+ in_virtualenv = hasattr(sys, 'real_prefix')
+ in_venv = hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix
+ @pytest.mark.skipif(in_virtualenv or in_venv,
+ reason="Cannot run when invoked in a virtualenv or venv")
+ def test_2to3_user_mode(self, test_env):
+ settings = dict(
+ name='foo',
+ packages=['foo'],
+ use_2to3=True,
+ version='0.0',
+ )
+ dist = Distribution(settings)
dist.script_name = 'setup.py'
cmd = develop(dist)
cmd.user = 1
cmd.ensure_finalized()
cmd.install_dir = site.USER_SITE
cmd.user = 1
- old_stdout = sys.stdout
- #sys.stdout = StringIO()
- try:
+ with contexts.quiet():
cmd.run()
- finally:
- sys.stdout = old_stdout
# let's see if we got our egg link at the right place
content = os.listdir(site.USER_SITE)
@@ -87,17 +78,37 @@ class TestDevelopTest:
assert content == ['easy-install.pth', 'foo.egg-link']
# Check that we are using the right code.
- egg_link_file = open(os.path.join(site.USER_SITE, 'foo.egg-link'), 'rt')
- try:
+ fn = os.path.join(site.USER_SITE, 'foo.egg-link')
+ with io.open(fn) as egg_link_file:
path = egg_link_file.read().split()[0].strip()
- finally:
- egg_link_file.close()
- init_file = open(os.path.join(path, 'foo', '__init__.py'), 'rt')
- try:
+ fn = os.path.join(path, 'foo', '__init__.py')
+ with io.open(fn) as init_file:
init = init_file.read().strip()
- finally:
- init_file.close()
- if sys.version < "3":
- assert init == 'print "foo"'
- else:
- assert init == 'print("foo")'
+
+ expected = 'print("foo")' if PY3 else 'print "foo"'
+ assert init == expected
+
+ def test_console_scripts(self, tmpdir):
+ """
+ Test that console scripts are installed and that they reference
+ only the project by name and not the current version.
+ """
+ pytest.skip("TODO: needs a fixture to cause 'develop' "
+ "to be invoked without mutating environment.")
+ settings = dict(
+ name='foo',
+ packages=['foo'],
+ version='0.0',
+ entry_points={
+ 'console_scripts': [
+ 'foocmd = foo:foo',
+ ],
+ },
+ )
+ dist = Distribution(settings)
+ dist.script_name = 'setup.py'
+ cmd = develop(dist)
+ cmd.ensure_finalized()
+ cmd.install_dir = tmpdir
+ cmd.run()
+ #assert '0.0' not in foocmd_text
diff --git a/setuptools/version.py b/setuptools/version.py
index 74e48b04..86ad21c6 100644
--- a/setuptools/version.py
+++ b/setuptools/version.py
@@ -1 +1 @@
-__version__ = '18.6'
+__version__ = '18.6.2'
diff --git a/tox.ini b/tox.ini
index 7aeffdd8..9061869f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,5 @@
[tox]
envlist = py26,py27,py31,py32,py33,py34
+
[testenv]
-deps=
- pytest
- mock
-commands=py.test setuptools {posargs}
+commands=python setup.py test