summaryrefslogtreecommitdiff
path: root/setuptools
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools')
-rwxr-xr-xsetuptools/command/develop.py27
-rwxr-xr-xsetuptools/command/easy_install.py28
-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
6 files changed, 131 insertions, 72 deletions
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/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'