##// END OF EJS Templates
Merge pull request #8461 from minrk/optional-deps...
Kyle Kelley -
r21382:5a106ac3 merge
parent child Browse files
Show More
@@ -1,271 +1,273 b''
1 1 #!/usr/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 """Setup script for IPython.
4 4
5 5 Under Posix environments it works like a typical setup.py script.
6 6 Under Windows, the command sdist is not supported, since IPython
7 7 requires utilities which are not available under Windows."""
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (c) 2008-2011, IPython Development Team.
11 11 # Copyright (c) 2001-2007, Fernando Perez <fernando.perez@colorado.edu>
12 12 # Copyright (c) 2001, Janko Hauser <jhauser@zscout.de>
13 13 # Copyright (c) 2001, Nathaniel Gray <n8gray@caltech.edu>
14 14 #
15 15 # Distributed under the terms of the Modified BSD License.
16 16 #
17 17 # The full license is in the file COPYING.rst, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Minimal Python version sanity check
22 22 #-----------------------------------------------------------------------------
23 23 from __future__ import print_function
24 24
25 25 import sys
26 26
27 27 # This check is also made in IPython/__init__, don't forget to update both when
28 28 # changing Python version requirements.
29 29 v = sys.version_info
30 30 if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)):
31 31 error = "ERROR: IPython requires Python version 2.7 or 3.3 or above."
32 32 print(error, file=sys.stderr)
33 33 sys.exit(1)
34 34
35 35 PY3 = (sys.version_info[0] >= 3)
36 36
37 37 # At least we're on the python version we need, move on.
38 38
39 39 #-------------------------------------------------------------------------------
40 40 # Imports
41 41 #-------------------------------------------------------------------------------
42 42
43 43 # Stdlib imports
44 44 import os
45 45 import shutil
46 46
47 47 from glob import glob
48 48
49 49 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
50 50 # update it when the contents of directories change.
51 51 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
52 52
53 53 from distutils.core import setup
54 54
55 55 # Our own imports
56 56 from setupbase import target_update
57 57
58 58 from setupbase import (
59 59 setup_args,
60 60 find_packages,
61 61 find_package_data,
62 62 check_package_data_first,
63 63 find_entry_points,
64 64 build_scripts_entrypt,
65 65 find_data_files,
66 check_for_readline,
67 66 git_prebuild,
68 get_bdist_wheel,
69 67 install_symlinked,
70 68 install_lib_symlink,
71 69 install_scripts_for_symlink,
72 70 unsymlink,
73 71 )
74 72
75 73 isfile = os.path.isfile
76 74 pjoin = os.path.join
77 75
78 76 #-------------------------------------------------------------------------------
79 77 # Handle OS specific things
80 78 #-------------------------------------------------------------------------------
81 79
82 80 if os.name in ('nt','dos'):
83 81 os_name = 'windows'
84 82 else:
85 83 os_name = os.name
86 84
87 85 # Under Windows, 'sdist' has not been supported. Now that the docs build with
88 86 # Sphinx it might work, but let's not turn it on until someone confirms that it
89 87 # actually works.
90 88 if os_name == 'windows' and 'sdist' in sys.argv:
91 89 print('The sdist command is not available under Windows. Exiting.')
92 90 sys.exit(1)
93 91
94 92
95 93 #-------------------------------------------------------------------------------
96 94 # Things related to the IPython documentation
97 95 #-------------------------------------------------------------------------------
98 96
99 97 # update the manuals when building a source dist
100 98 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
101 99
102 100 # List of things to be updated. Each entry is a triplet of args for
103 101 # target_update()
104 102 to_update = [
105 103 ('docs/man/ipython.1.gz',
106 104 ['docs/man/ipython.1'],
107 105 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
108 106 ]
109 107
110 108
111 109 [ target_update(*t) for t in to_update ]
112 110
113 111 #---------------------------------------------------------------------------
114 112 # Find all the packages, package data, and data_files
115 113 #---------------------------------------------------------------------------
116 114
117 115 packages = find_packages()
118 116 package_data = find_package_data()
119 117
120 118 data_files = find_data_files()
121 119
122 120 setup_args['packages'] = packages
123 121 setup_args['package_data'] = package_data
124 122 setup_args['data_files'] = data_files
125 123
126 124 #---------------------------------------------------------------------------
127 125 # custom distutils commands
128 126 #---------------------------------------------------------------------------
129 127 # imports here, so they are after setuptools import if there was one
130 128 from distutils.command.sdist import sdist
131 129 from distutils.command.upload import upload
132 130
133 131 class UploadWindowsInstallers(upload):
134 132
135 133 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
136 134 user_options = upload.user_options + [
137 135 ('files=', 'f', 'exe file (or glob) to upload')
138 136 ]
139 137 def initialize_options(self):
140 138 upload.initialize_options(self)
141 139 meta = self.distribution.metadata
142 140 base = '{name}-{version}'.format(
143 141 name=meta.get_name(),
144 142 version=meta.get_version()
145 143 )
146 144 self.files = os.path.join('dist', '%s.*.exe' % base)
147 145
148 146 def run(self):
149 147 for dist_file in glob(self.files):
150 148 self.upload_file('bdist_wininst', 'any', dist_file)
151 149
152 150 setup_args['cmdclass'] = {
153 151 'build_py': \
154 152 check_package_data_first(git_prebuild('IPython')),
155 153 'sdist' : git_prebuild('IPython', sdist),
156 154 'upload_wininst' : UploadWindowsInstallers,
157 155 'symlink': install_symlinked,
158 156 'install_lib_symlink': install_lib_symlink,
159 157 'install_scripts_sym': install_scripts_for_symlink,
160 158 'unsymlink': unsymlink,
161 159 }
162 160
163 161
164 162 #---------------------------------------------------------------------------
165 163 # Handle scripts, dependencies, and setuptools specific things
166 164 #---------------------------------------------------------------------------
167 165
168 166 # For some commands, use setuptools. Note that we do NOT list install here!
169 167 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
170 168 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
171 169 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
172 170 'egg_info', 'easy_install', 'upload', 'install_egg_info',
173 171 ))
174 172
175 173 if len(needs_setuptools.intersection(sys.argv)) > 0:
176 174 import setuptools
177 175
178 176 # This dict is used for passing extra arguments that are setuptools
179 177 # specific to setup
180 178 setuptools_extra_args = {}
181 179
182 180 # setuptools requirements
183 181
184 pyzmq = 'pyzmq>=13'
185
186 182 extras_require = dict(
187 183 parallel = ['ipyparallel'],
188 184 qtconsole = ['qtconsole'],
189 185 doc = ['Sphinx>=1.1', 'numpydoc'],
190 186 test = ['nose>=0.10.1', 'requests', 'testpath'],
191 187 terminal = [],
192 188 kernel = ['ipykernel'],
193 189 nbformat = ['nbformat'],
194 190 notebook = ['notebook'],
195 191 nbconvert = ['nbconvert'],
196 192 )
197
198 if sys.version_info < (3, 3):
199 extras_require['test'].append('mock')
200
201 193 install_requires = [
202 194 'decorator',
203 195 'pickleshare',
204 196 'simplegeneric>0.8',
205 197 'traitlets',
206 198 ]
207 199
208 # add platform-specific dependencies
209 if sys.platform == 'darwin':
210 install_requires.append('appnope')
211 if 'bdist_wheel' in sys.argv[1:] or not check_for_readline():
212 install_requires.append('gnureadline')
213
214 if sys.platform.startswith('win'):
215 extras_require['terminal'].append('pyreadline>=2.0')
216 else:
217 install_requires.append('pexpect')
200 # Platform-specific dependencies:
201 # This is the correct way to specify these,
202 # but requires pip >= 6. pip < 6 ignores these.
203 extras_require.update({
204 ':sys_platform != "win32"': ['pexpect'],
205 ':sys_platform == "darwin"': ['appnope', 'gnureadline'],
206 'terminal:sys_platform == "win32"': ['pyreadline>=2'],
207 'test:python_version == "2.7"': ['mock'],
208 })
209 # FIXME: re-specify above platform dependencies for pip < 6
210 # These would result in non-portable bdists.
211 if not any(arg.startswith('bdist') for arg in sys.argv):
212 if sys.version_info < (3, 3):
213 extras_require['test'].append('mock')
214
215 if sys.platform == 'darwin':
216 install_requires.extend(['appnope', 'gnureadline'])
217
218 if sys.platform.startswith('win'):
219 extras_require['terminal'].append('pyreadline>=2.0')
220 else:
221 install_requires.append('pexpect')
218 222
219 223 everything = set()
220 224 for deps in extras_require.values():
221 225 everything.update(deps)
222 226 extras_require['all'] = everything
223 227
224 228 if 'setuptools' in sys.modules:
225 setup_args['cmdclass']['bdist_wheel'] = get_bdist_wheel()
226
227 229 setuptools_extra_args['zip_safe'] = False
228 230 setuptools_extra_args['entry_points'] = {
229 231 'console_scripts': find_entry_points(),
230 232 'pygments.lexers': [
231 233 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
232 234 'ipython = IPython.lib.lexers:IPythonLexer',
233 235 'ipython3 = IPython.lib.lexers:IPython3Lexer',
234 236 ],
235 237 }
236 238 setup_args['extras_require'] = extras_require
237 239 requires = setup_args['install_requires'] = install_requires
238 240
239 241 # Script to be run by the windows binary installer after the default setup
240 242 # routine, to add shortcuts and similar windows-only things. Windows
241 243 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
242 244 # doesn't find them.
243 245 if 'bdist_wininst' in sys.argv:
244 246 if len(sys.argv) > 2 and \
245 247 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
246 248 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
247 249 sys.exit(1)
248 250 setup_args['data_files'].append(
249 251 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
250 252 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
251 253 setup_args['options'] = {"bdist_wininst":
252 254 {"install_script":
253 255 "ipython_win_post_install.py"}}
254 256
255 257 else:
256 258 # scripts has to be a non-empty list, or install_scripts isn't called
257 259 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
258 260
259 261 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
260 262
261 263 #---------------------------------------------------------------------------
262 264 # Do the actual setup now
263 265 #---------------------------------------------------------------------------
264 266
265 267 setup_args.update(setuptools_extra_args)
266 268
267 269 def main():
268 270 setup(**setup_args)
269 271
270 272 if __name__ == '__main__':
271 273 main()
@@ -1,554 +1,466 b''
1 1 # encoding: utf-8
2 2 """
3 3 This module defines the things that are used in setup.py for building IPython
4 4
5 5 This includes:
6 6
7 7 * The basic arguments to setup
8 8 * Functions for finding things like packages, package data, etc.
9 9 * A function for checking dependencies.
10 10 """
11 11
12 12 # Copyright (c) IPython Development Team.
13 13 # Distributed under the terms of the Modified BSD License.
14 14
15 15 from __future__ import print_function
16 16
17 17 import errno
18 18 import os
19 19 import sys
20 20
21 21 from distutils import log
22 22 from distutils.command.build_py import build_py
23 23 from distutils.command.build_scripts import build_scripts
24 24 from distutils.command.install import install
25 25 from distutils.command.install_scripts import install_scripts
26 26 from distutils.cmd import Command
27 27 from distutils.errors import DistutilsExecError
28 28 from fnmatch import fnmatch
29 29 from glob import glob
30 30 from subprocess import Popen, PIPE
31 31
32 32 from setupext import install_data_ext
33 33
34 34 #-------------------------------------------------------------------------------
35 35 # Useful globals and utility functions
36 36 #-------------------------------------------------------------------------------
37 37
38 38 # A few handy globals
39 39 isfile = os.path.isfile
40 40 pjoin = os.path.join
41 41 repo_root = os.path.dirname(os.path.abspath(__file__))
42 42
43 43 def oscmd(s):
44 44 print(">", s)
45 45 os.system(s)
46 46
47 47 # Py3 compatibility hacks, without assuming IPython itself is installed with
48 48 # the full py3compat machinery.
49 49
50 50 try:
51 51 execfile
52 52 except NameError:
53 53 def execfile(fname, globs, locs=None):
54 54 locs = locs or globs
55 55 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
56 56
57 57 # A little utility we'll need below, since glob() does NOT allow you to do
58 58 # exclusion on multiple endings!
59 59 def file_doesnt_endwith(test,endings):
60 60 """Return true if test is a file and its name does NOT end with any
61 61 of the strings listed in endings."""
62 62 if not isfile(test):
63 63 return False
64 64 for e in endings:
65 65 if test.endswith(e):
66 66 return False
67 67 return True
68 68
69 69 #---------------------------------------------------------------------------
70 70 # Basic project information
71 71 #---------------------------------------------------------------------------
72 72
73 73 # release.py contains version, authors, license, url, keywords, etc.
74 74 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
75 75
76 76 # Create a dict with the basic information
77 77 # This dict is eventually passed to setup after additional keys are added.
78 78 setup_args = dict(
79 79 name = name,
80 80 version = version,
81 81 description = description,
82 82 long_description = long_description,
83 83 author = author,
84 84 author_email = author_email,
85 85 url = url,
86 86 download_url = download_url,
87 87 license = license,
88 88 platforms = platforms,
89 89 keywords = keywords,
90 90 classifiers = classifiers,
91 91 cmdclass = {'install_data': install_data_ext},
92 92 )
93 93
94 94
95 95 #---------------------------------------------------------------------------
96 96 # Find packages
97 97 #---------------------------------------------------------------------------
98 98
99 99 def find_packages():
100 100 """
101 101 Find all of IPython's packages.
102 102 """
103 103 excludes = ['deathrow', 'quarantine']
104 104 packages = []
105 105 for dir,subdirs,files in os.walk('IPython'):
106 106 package = dir.replace(os.path.sep, '.')
107 107 if any(package.startswith('IPython.'+exc) for exc in excludes):
108 108 # package is to be excluded (e.g. deathrow)
109 109 continue
110 110 if '__init__.py' not in files:
111 111 # not a package
112 112 continue
113 113 packages.append(package)
114 114 return packages
115 115
116 116 #---------------------------------------------------------------------------
117 117 # Find package data
118 118 #---------------------------------------------------------------------------
119 119
120 120 def find_package_data():
121 121 """
122 122 Find IPython's package_data.
123 123 """
124 124 # This is not enough for these things to appear in an sdist.
125 125 # We need to muck with the MANIFEST to get this to work
126 126
127 127 package_data = {
128 128 'IPython.core' : ['profile/README*'],
129 129 'IPython.core.tests' : ['*.png', '*.jpg'],
130 130 'IPython.lib.tests' : ['*.wav'],
131 131 'IPython.testing.plugin' : ['*.txt'],
132 132 }
133 133
134 134 return package_data
135 135
136 136
137 137 def check_package_data(package_data):
138 138 """verify that package_data globs make sense"""
139 139 print("checking package data")
140 140 for pkg, data in package_data.items():
141 141 pkg_root = pjoin(*pkg.split('.'))
142 142 for d in data:
143 143 path = pjoin(pkg_root, d)
144 144 if '*' in path:
145 145 assert len(glob(path)) > 0, "No files match pattern %s" % path
146 146 else:
147 147 assert os.path.exists(path), "Missing package data: %s" % path
148 148
149 149
150 150 def check_package_data_first(command):
151 151 """decorator for checking package_data before running a given command
152 152
153 153 Probably only needs to wrap build_py
154 154 """
155 155 class DecoratedCommand(command):
156 156 def run(self):
157 157 check_package_data(self.package_data)
158 158 command.run(self)
159 159 return DecoratedCommand
160 160
161 161
162 162 #---------------------------------------------------------------------------
163 163 # Find data files
164 164 #---------------------------------------------------------------------------
165 165
166 166 def make_dir_struct(tag,base,out_base):
167 167 """Make the directory structure of all files below a starting dir.
168 168
169 169 This is just a convenience routine to help build a nested directory
170 170 hierarchy because distutils is too stupid to do this by itself.
171 171
172 172 XXX - this needs a proper docstring!
173 173 """
174 174
175 175 # we'll use these a lot below
176 176 lbase = len(base)
177 177 pathsep = os.path.sep
178 178 lpathsep = len(pathsep)
179 179
180 180 out = []
181 181 for (dirpath,dirnames,filenames) in os.walk(base):
182 182 # we need to strip out the dirpath from the base to map it to the
183 183 # output (installation) path. This requires possibly stripping the
184 184 # path separator, because otherwise pjoin will not work correctly
185 185 # (pjoin('foo/','/bar') returns '/bar').
186 186
187 187 dp_eff = dirpath[lbase:]
188 188 if dp_eff.startswith(pathsep):
189 189 dp_eff = dp_eff[lpathsep:]
190 190 # The output path must be anchored at the out_base marker
191 191 out_path = pjoin(out_base,dp_eff)
192 192 # Now we can generate the final filenames. Since os.walk only produces
193 193 # filenames, we must join back with the dirpath to get full valid file
194 194 # paths:
195 195 pfiles = [pjoin(dirpath,f) for f in filenames]
196 196 # Finally, generate the entry we need, which is a pari of (output
197 197 # path, files) for use as a data_files parameter in install_data.
198 198 out.append((out_path, pfiles))
199 199
200 200 return out
201 201
202 202
203 203 def find_data_files():
204 204 """
205 205 Find IPython's data_files.
206 206
207 207 Just man pages at this point.
208 208 """
209 209
210 210 manpagebase = pjoin('share', 'man', 'man1')
211 211
212 212 # Simple file lists can be made by hand
213 213 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
214 214 if not manpages:
215 215 # When running from a source tree, the manpages aren't gzipped
216 216 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
217 217
218 218 # And assemble the entire output list
219 219 data_files = [ (manpagebase, manpages) ]
220 220
221 221 return data_files
222 222
223 223
224 224 def make_man_update_target(manpage):
225 225 """Return a target_update-compliant tuple for the given manpage.
226 226
227 227 Parameters
228 228 ----------
229 229 manpage : string
230 230 Name of the manpage, must include the section number (trailing number).
231 231
232 232 Example
233 233 -------
234 234
235 235 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
236 236 ('docs/man/ipython.1.gz',
237 237 ['docs/man/ipython.1'],
238 238 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
239 239 """
240 240 man_dir = pjoin('docs', 'man')
241 241 manpage_gz = manpage + '.gz'
242 242 manpath = pjoin(man_dir, manpage)
243 243 manpath_gz = pjoin(man_dir, manpage_gz)
244 244 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
245 245 locals() )
246 246 return (manpath_gz, [manpath], gz_cmd)
247 247
248 248 # The two functions below are copied from IPython.utils.path, so we don't need
249 249 # to import IPython during setup, which fails on Python 3.
250 250
251 251 def target_outdated(target,deps):
252 252 """Determine whether a target is out of date.
253 253
254 254 target_outdated(target,deps) -> 1/0
255 255
256 256 deps: list of filenames which MUST exist.
257 257 target: single filename which may or may not exist.
258 258
259 259 If target doesn't exist or is older than any file listed in deps, return
260 260 true, otherwise return false.
261 261 """
262 262 try:
263 263 target_time = os.path.getmtime(target)
264 264 except os.error:
265 265 return 1
266 266 for dep in deps:
267 267 dep_time = os.path.getmtime(dep)
268 268 if dep_time > target_time:
269 269 #print "For target",target,"Dep failed:",dep # dbg
270 270 #print "times (dep,tar):",dep_time,target_time # dbg
271 271 return 1
272 272 return 0
273 273
274 274
275 275 def target_update(target,deps,cmd):
276 276 """Update a target with a given command given a list of dependencies.
277 277
278 278 target_update(target,deps,cmd) -> runs cmd if target is outdated.
279 279
280 280 This is just a wrapper around target_outdated() which calls the given
281 281 command if target is outdated."""
282 282
283 283 if target_outdated(target,deps):
284 284 os.system(cmd)
285 285
286 286 #---------------------------------------------------------------------------
287 287 # Find scripts
288 288 #---------------------------------------------------------------------------
289 289
290 290 def find_entry_points():
291 291 """Defines the command line entry points for IPython
292 292
293 293 This always uses setuptools-style entry points. When setuptools is not in
294 294 use, our own build_scripts_entrypt class below parses these and builds
295 295 command line scripts.
296 296
297 297 Each of our entry points gets both a plain name, e.g. ipython, and one
298 298 suffixed with the Python major version number, e.g. ipython3.
299 299 """
300 300 ep = [
301 301 'ipython%s = IPython:start_ipython',
302 302 'iptest%s = IPython.testing.iptestcontroller:main',
303 303 ]
304 304 suffix = str(sys.version_info[0])
305 305 return [e % '' for e in ep] + [e % suffix for e in ep]
306 306
307 307 script_src = """#!{executable}
308 308 # This script was automatically generated by setup.py
309 309 if __name__ == '__main__':
310 310 from {mod} import {func}
311 311 {func}()
312 312 """
313 313
314 314 class build_scripts_entrypt(build_scripts):
315 315 """Build the command line scripts
316 316
317 317 Parse setuptools style entry points and write simple scripts to run the
318 318 target functions.
319 319
320 320 On Windows, this also creates .cmd wrappers for the scripts so that you can
321 321 easily launch them from a command line.
322 322 """
323 323 def run(self):
324 324 self.mkpath(self.build_dir)
325 325 outfiles = []
326 326 for script in find_entry_points():
327 327 name, entrypt = script.split('=')
328 328 name = name.strip()
329 329 entrypt = entrypt.strip()
330 330 outfile = os.path.join(self.build_dir, name)
331 331 outfiles.append(outfile)
332 332 print('Writing script to', outfile)
333 333
334 334 mod, func = entrypt.split(':')
335 335 with open(outfile, 'w') as f:
336 336 f.write(script_src.format(executable=sys.executable,
337 337 mod=mod, func=func))
338 338
339 339 if sys.platform == 'win32':
340 340 # Write .cmd wrappers for Windows so 'ipython' etc. work at the
341 341 # command line
342 342 cmd_file = os.path.join(self.build_dir, name + '.cmd')
343 343 cmd = '@"{python}" "%~dp0\{script}" %*\r\n'.format(
344 344 python=sys.executable, script=name)
345 345 log.info("Writing %s wrapper script" % cmd_file)
346 346 with open(cmd_file, 'w') as f:
347 347 f.write(cmd)
348 348
349 349 return outfiles, outfiles
350 350
351 351 class install_lib_symlink(Command):
352 352 user_options = [
353 353 ('install-dir=', 'd', "directory to install to"),
354 354 ]
355 355
356 356 def initialize_options(self):
357 357 self.install_dir = None
358 358
359 359 def finalize_options(self):
360 360 self.set_undefined_options('symlink',
361 361 ('install_lib', 'install_dir'),
362 362 )
363 363
364 364 def run(self):
365 365 if sys.platform == 'win32':
366 366 raise Exception("This doesn't work on Windows.")
367 367 pkg = os.path.join(os.getcwd(), 'IPython')
368 368 dest = os.path.join(self.install_dir, 'IPython')
369 369 if os.path.islink(dest):
370 370 print('removing existing symlink at %s' % dest)
371 371 os.unlink(dest)
372 372 print('symlinking %s -> %s' % (pkg, dest))
373 373 os.symlink(pkg, dest)
374 374
375 375 class unsymlink(install):
376 376 def run(self):
377 377 dest = os.path.join(self.install_lib, 'IPython')
378 378 if os.path.islink(dest):
379 379 print('removing symlink at %s' % dest)
380 380 os.unlink(dest)
381 381 else:
382 382 print('No symlink exists at %s' % dest)
383 383
384 384 class install_symlinked(install):
385 385 def run(self):
386 386 if sys.platform == 'win32':
387 387 raise Exception("This doesn't work on Windows.")
388 388
389 389 # Run all sub-commands (at least those that need to be run)
390 390 for cmd_name in self.get_sub_commands():
391 391 self.run_command(cmd_name)
392 392
393 393 # 'sub_commands': a list of commands this command might have to run to
394 394 # get its work done. See cmd.py for more info.
395 395 sub_commands = [('install_lib_symlink', lambda self:True),
396 396 ('install_scripts_sym', lambda self:True),
397 397 ]
398 398
399 399 class install_scripts_for_symlink(install_scripts):
400 400 """Redefined to get options from 'symlink' instead of 'install'.
401 401
402 402 I love distutils almost as much as I love setuptools.
403 403 """
404 404 def finalize_options(self):
405 405 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
406 406 self.set_undefined_options('symlink',
407 407 ('install_scripts', 'install_dir'),
408 408 ('force', 'force'),
409 409 ('skip_build', 'skip_build'),
410 410 )
411 411
412 #---------------------------------------------------------------------------
413 # Verify all dependencies
414 #---------------------------------------------------------------------------
415
416 def check_for_readline():
417 """Check for GNU readline"""
418 try:
419 import gnureadline as readline
420 except ImportError:
421 pass
422 else:
423 return True
424 try:
425 import readline
426 except ImportError:
427 return False
428 else:
429 if sys.platform == 'darwin' and 'libedit' in readline.__doc__:
430 print("Ignoring readline linked to libedit", file=sys.stderr)
431 return False
432 return True
433 412
434 413 #---------------------------------------------------------------------------
435 414 # VCS related
436 415 #---------------------------------------------------------------------------
437 416
438 417
439 418 def git_prebuild(pkg_dir, build_cmd=build_py):
440 419 """Return extended build or sdist command class for recording commit
441 420
442 421 records git commit in IPython.utils._sysinfo.commit
443 422
444 423 for use in IPython.utils.sysinfo.sys_info() calls after installation.
445 424 """
446 425
447 426 class MyBuildPy(build_cmd):
448 427 ''' Subclass to write commit data into installation tree '''
449 428 def run(self):
450 429 build_cmd.run(self)
451 430 # this one will only fire for build commands
452 431 if hasattr(self, 'build_lib'):
453 432 self._record_commit(self.build_lib)
454 433
455 434 def make_release_tree(self, base_dir, files):
456 435 # this one will fire for sdist
457 436 build_cmd.make_release_tree(self, base_dir, files)
458 437 self._record_commit(base_dir)
459 438
460 439 def _record_commit(self, base_dir):
461 440 import subprocess
462 441 proc = subprocess.Popen('git rev-parse --short HEAD',
463 442 stdout=subprocess.PIPE,
464 443 stderr=subprocess.PIPE,
465 444 shell=True)
466 445 repo_commit, _ = proc.communicate()
467 446 repo_commit = repo_commit.strip().decode("ascii")
468 447
469 448 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
470 449 if os.path.isfile(out_pth) and not repo_commit:
471 450 # nothing to write, don't clobber
472 451 return
473 452
474 453 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
475 454
476 455 # remove to avoid overwriting original via hard link
477 456 try:
478 457 os.remove(out_pth)
479 458 except (IOError, OSError):
480 459 pass
481 460 with open(out_pth, 'w') as out_file:
482 461 out_file.writelines([
483 462 '# GENERATED BY setup.py\n',
484 463 'commit = u"%s"\n' % repo_commit,
485 464 ])
486 465 return MyBuildPy
487 466
488
489
490 #---------------------------------------------------------------------------
491 # bdist related
492 #---------------------------------------------------------------------------
493
494 def get_bdist_wheel():
495 """Construct bdist_wheel command for building wheels
496
497 Constructs py2-none-any tag, instead of py2.7-none-any
498 """
499 class RequiresWheel(Command):
500 description = "Dummy command for missing bdist_wheel"
501 user_options = []
502
503 def initialize_options(self):
504 pass
505
506 def finalize_options(self):
507 pass
508
509 def run(self):
510 print("bdist_wheel requires the wheel package")
511 sys.exit(1)
512
513 if 'setuptools' not in sys.modules:
514 return RequiresWheel
515 else:
516 try:
517 from wheel.bdist_wheel import bdist_wheel, read_pkg_info, write_pkg_info
518 except ImportError:
519 return RequiresWheel
520
521 class bdist_wheel_tag(bdist_wheel):
522
523 def add_requirements(self, metadata_path):
524 """transform platform-dependent requirements"""
525 pkg_info = read_pkg_info(metadata_path)
526 # pkg_info is an email.Message object (?!)
527 # we have to remove the unconditional 'readline' and/or 'pyreadline' entries
528 # and transform them to conditionals
529 requires = pkg_info.get_all('Requires-Dist')
530 del pkg_info['Requires-Dist']
531 def _remove_startswith(lis, prefix):
532 """like list.remove, but with startswith instead of =="""
533 found = False
534 for idx, item in enumerate(lis):
535 if item.startswith(prefix):
536 found = True
537 break
538 if found:
539 lis.pop(idx)
540
541 for pkg in ("gnureadline", "pyreadline", "mock", "terminado", "appnope", "pexpect"):
542 _remove_startswith(requires, pkg)
543 requires.append("gnureadline; sys.platform == 'darwin' and platform.python_implementation == 'CPython'")
544 requires.append("pyreadline (>=2.0); extra == 'terminal' and sys.platform == 'win32' and platform.python_implementation == 'CPython'")
545 requires.append("pyreadline (>=2.0); extra == 'all' and sys.platform == 'win32' and platform.python_implementation == 'CPython'")
546 requires.append("mock; extra == 'test' and python_version < '3.3'")
547 requires.append("appnope; sys.platform == 'darwin'")
548 requires.append("pexpect; sys.platform != 'win32'")
549 for r in requires:
550 pkg_info['Requires-Dist'] = r
551 write_pkg_info(metadata_path, pkg_info)
552
553 return bdist_wheel_tag
554
General Comments 0
You need to be logged in to leave comments. Login now