Skip to content

Commit

Permalink
Merge pull request #4473 from takluyver/setup23
Browse files Browse the repository at this point in the history
update script generation in setup.py

These changes:
- Give us scripts called `ipython` and (`ipython2` or `ipython3`) for any installation. (and likewise for each of iptest, ipcontroller, etc.)
- Add a new `setup.py symlink` target, to use instead of `develop`, which installs scripts and symlinks the library into site-packages, without using setuptools.
- Removes the static script entry points - all our entry points are now automatically generated.
  • Loading branch information
minrk committed Nov 5, 2013
2 parents 49af4ae + 4e8f211 commit b908251
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 162 deletions.
16 changes: 0 additions & 16 deletions IPython/parallel/scripts/__init__.py

This file was deleted.

16 changes: 0 additions & 16 deletions IPython/parallel/scripts/ipcluster

This file was deleted.

16 changes: 0 additions & 16 deletions IPython/parallel/scripts/ipcontroller

This file was deleted.

16 changes: 0 additions & 16 deletions IPython/parallel/scripts/ipengine

This file was deleted.

16 changes: 0 additions & 16 deletions IPython/parallel/scripts/iplogger

This file was deleted.

Empty file removed IPython/scripts/__init__.py
Empty file.
24 changes: 0 additions & 24 deletions IPython/scripts/iptest

This file was deleted.

6 changes: 0 additions & 6 deletions IPython/scripts/ipython

This file was deleted.

9 changes: 0 additions & 9 deletions IPython/scripts/irunner

This file was deleted.

21 changes: 13 additions & 8 deletions setup.py
Expand Up @@ -58,8 +58,8 @@
setup_args,
find_packages,
find_package_data,
find_scripts,
build_scripts_rename,
find_entry_points,
build_scripts_entrypt,
find_data_files,
check_for_dependencies,
git_prebuild,
Expand All @@ -68,6 +68,9 @@
require_submodules,
UpdateSubmodules,
CompileCSS,
install_symlinked,
install_lib_symlink,
install_scripts_for_symlink,
)
from setupext import setupext

Expand Down Expand Up @@ -148,7 +151,6 @@ def require_clean_submodules():

# update the manuals when building a source dist
if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
import textwrap

# List of things to be updated. Each entry is a triplet of args for
# target_update()
Expand Down Expand Up @@ -231,6 +233,9 @@ def run(self):
'upload_wininst' : UploadWindowsInstallers,
'submodule' : UpdateSubmodules,
'css' : CompileCSS,
'symlink': install_symlinked,
'install_lib_symlink': install_lib_symlink,
'install_scripts_sym': install_scripts_for_symlink,
}

#---------------------------------------------------------------------------
Expand Down Expand Up @@ -263,7 +268,7 @@ def run(self):
setup_args['cmdclass']['develop'] = require_submodules(develop)

setuptools_extra_args['zip_safe'] = False
setuptools_extra_args['entry_points'] = find_scripts(True, suffix = '3' if PY3 else '')
setuptools_extra_args['entry_points'] = {'console_scripts':find_entry_points()}
setup_args['extras_require'] = dict(
parallel = 'pyzmq>=2.1.11',
qtconsole = ['pyzmq>=2.1.11', 'pygments'],
Expand Down Expand Up @@ -316,10 +321,10 @@ def run(self):
# check for dependencies an inform the user what is needed. This is
# just to make life easy for users.
check_for_dependencies()
setup_args['scripts'] = find_scripts(False)
if PY3:
# Rename scripts with '3' suffix
setup_args['cmdclass']['build_scripts'] = build_scripts_rename
# scripts has to be a non-empty list, or install_scripts isn't called
setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]

setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt

#---------------------------------------------------------------------------
# Do the actual setup now
Expand Down
117 changes: 82 additions & 35 deletions setupbase.py
Expand Up @@ -20,15 +20,14 @@
#-------------------------------------------------------------------------------
# Imports
#-------------------------------------------------------------------------------
import errno
import os
import sys

try:
from configparser import ConfigParser
except:
from ConfigParser import ConfigParser
from distutils.command.build_py import build_py
from distutils.command.build_scripts import build_scripts
from distutils.command.install import install
from distutils.command.install_scripts import install_scripts
from distutils.cmd import Command
from glob import glob
from subprocess import call
Expand Down Expand Up @@ -311,7 +310,7 @@ def target_update(target,deps,cmd):
# Find scripts
#---------------------------------------------------------------------------

def find_scripts(entry_points=False, suffix=''):
def find_entry_points():
"""Find IPython's scripts.
if entry_points is True:
Expand All @@ -322,46 +321,94 @@ def find_scripts(entry_points=False, suffix=''):
suffix is appended to script names if entry_points is True, so that the
Python 3 scripts get named "ipython3" etc.
"""
if entry_points:
console_scripts = [s % suffix for s in [
ep = [
'ipython%s = IPython:start_ipython',
'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
'iptest%s = IPython.testing.iptestcontroller:main',
'irunner%s = IPython.lib.irunner:main',
]]
gui_scripts = []
scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
else:
parallel_scripts = pjoin('IPython','parallel','scripts')
main_scripts = pjoin('IPython','scripts')
scripts = [
pjoin(parallel_scripts, 'ipengine'),
pjoin(parallel_scripts, 'ipcontroller'),
pjoin(parallel_scripts, 'ipcluster'),
pjoin(parallel_scripts, 'iplogger'),
pjoin(main_scripts, 'ipython'),
pjoin(main_scripts, 'irunner'),
pjoin(main_scripts, 'iptest')
]
return scripts
suffix = str(sys.version_info[0])
return [e % '' for e in ep] + [e % suffix for e in ep]

script_src = """#!{executable}
# This script was automatically generated by setup.py
from {mod} import {func}
{func}()
"""

class build_scripts_entrypt(build_scripts):
def run(self):
self.mkpath(self.build_dir)
outfiles = []
for script in find_entry_points():
name, entrypt = script.split('=')
name = name.strip()
entrypt = entrypt.strip()
outfile = os.path.join(self.build_dir, name)
outfiles.append(outfile)
print('Writing script to', outfile)

mod, func = entrypt.split(':')
with open(outfile, 'w') as f:
f.write(script_src.format(executable=sys.executable,
mod=mod, func=func))

return outfiles, outfiles

class install_lib_symlink(Command):
user_options = [
('install-dir=', 'd', "directory to install to"),
]

def initialize_options(self):
self.install_dir = None

class build_scripts_rename(build_scripts):
"""Use this on Python 3 to rename scripts to ipython3 etc."""
_suffix = '3'
def finalize_options(self):
self.set_undefined_options('symlink',
('install_lib', 'install_dir'),
)

def run(self):
if sys.platform == 'win32':
raise Exception("This doesn't work on Windows.")
pkg = os.path.join(os.getcwd(), 'IPython')
dest = os.path.join(self.install_dir, 'IPython')
print('symlinking %s -> %s' % (pkg, dest))
try:
os.symlink(pkg, dest)
except OSError as e:
if e.errno == errno.EEXIST:
print('ALREADY EXISTS')
else:
raise

class install_symlinked(install):
def run(self):
if sys.platform == 'win32':
raise Exception("This doesn't work on Windows.")
install.run(self)

def copy_scripts(self):
outfiles, updated_files = super(build_scripts_rename, self).copy_scripts()
new_outfiles = [p + self._suffix for p in outfiles]
updated_files = [p + self._suffix for p in updated_files]
for old, new in zip(outfiles, new_outfiles):
if os.path.exists(new):
os.unlink(new)
self.move_file(old, new)
return new_outfiles, updated_files

# 'sub_commands': a list of commands this command might have to run to
# get its work done. See cmd.py for more info.
sub_commands = [('install_lib_symlink', lambda self:True),
('install_scripts_sym', lambda self:True),
]

class install_scripts_for_symlink(install_scripts):
"""Redefined to get options from 'symlink' instead of 'install'.
I love distutils almost as much as I love setuptools.
"""
def finalize_options(self):
self.set_undefined_options('build', ('build_scripts', 'build_dir'))
self.set_undefined_options('symlink',
('install_scripts', 'install_dir'),
('force', 'force'),
('skip_build', 'skip_build'),
)

#---------------------------------------------------------------------------
# Verify all dependencies
Expand Down

0 comments on commit b908251

Please sign in to comment.