##// END OF EJS Templates
Make single setup script work on Python 2 and Python 3.
Thomas Kluyver -
Show More
@@ -1,272 +1,286 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.txt, distributed with this software.
18 18 #-----------------------------------------------------------------------------
19 19
20 20 #-----------------------------------------------------------------------------
21 21 # Minimal Python version sanity check
22 22 #-----------------------------------------------------------------------------
23 from __future__ import print_function
23 24
24 25 import sys
25 26
26 27 # This check is also made in IPython/__init__, don't forget to update both when
27 28 # changing Python version requirements.
28 if sys.version[0:3] < '2.6':
29 error = """\
30 ERROR: 'IPython requires Python Version 2.6 or above.'
31 Exiting."""
32 print >> sys.stderr, error
33 sys.exit(1)
29 #~ if sys.version[0:3] < '2.6':
30 #~ error = """\
31 #~ ERROR: 'IPython requires Python Version 2.6 or above.'
32 #~ Exiting."""
33 #~ print >> sys.stderr, error
34 #~ sys.exit(1)
35
36 PY3 = (sys.version_info[0] >= 3)
34 37
35 38 # At least we're on the python version we need, move on.
36 39
37 40 #-------------------------------------------------------------------------------
38 41 # Imports
39 42 #-------------------------------------------------------------------------------
40 43
41 44 # Stdlib imports
42 45 import os
43 46 import shutil
44 47
45 48 from glob import glob
46 49
47 50 # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
48 51 # update it when the contents of directories change.
49 52 if os.path.exists('MANIFEST'): os.remove('MANIFEST')
50 53
51 54 from distutils.core import setup
52 55
56 # On Python 3, we need distribute (new setuptools) to do the 2to3 conversion
57 if PY3:
58 import setuptools
59
53 60 # Our own imports
54 from IPython.utils.path import target_update
61 from setupbase import target_update
55 62
56 63 from setupbase import (
57 64 setup_args,
58 65 find_packages,
59 66 find_package_data,
60 67 find_scripts,
61 68 find_data_files,
62 69 check_for_dependencies,
63 70 record_commit_info,
64 71 )
65 72 from setupext import setupext
66 73
67 74 isfile = os.path.isfile
68 75 pjoin = os.path.join
69 76
70 77 #-----------------------------------------------------------------------------
71 78 # Function definitions
72 79 #-----------------------------------------------------------------------------
73 80
74 81 def cleanup():
75 82 """Clean up the junk left around by the build process"""
76 83 if "develop" not in sys.argv:
77 84 try:
78 85 shutil.rmtree('ipython.egg-info')
79 86 except:
80 87 try:
81 88 os.unlink('ipython.egg-info')
82 89 except:
83 90 pass
84 91
85 92 #-------------------------------------------------------------------------------
86 93 # Handle OS specific things
87 94 #-------------------------------------------------------------------------------
88 95
89 96 if os.name == 'posix':
90 97 os_name = 'posix'
91 98 elif os.name in ['nt','dos']:
92 99 os_name = 'windows'
93 100 else:
94 print 'Unsupported operating system:',os.name
101 print('Unsupported operating system:',os.name)
95 102 sys.exit(1)
96 103
97 104 # Under Windows, 'sdist' has not been supported. Now that the docs build with
98 105 # Sphinx it might work, but let's not turn it on until someone confirms that it
99 106 # actually works.
100 107 if os_name == 'windows' and 'sdist' in sys.argv:
101 print 'The sdist command is not available under Windows. Exiting.'
108 print('The sdist command is not available under Windows. Exiting.')
102 109 sys.exit(1)
103 110
104 111 #-------------------------------------------------------------------------------
105 112 # Things related to the IPython documentation
106 113 #-------------------------------------------------------------------------------
107 114
108 115 # update the manuals when building a source dist
109 116 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
110 117 import textwrap
111 118
112 119 # List of things to be updated. Each entry is a triplet of args for
113 120 # target_update()
114 121 to_update = [
115 122 # FIXME - Disabled for now: we need to redo an automatic way
116 123 # of generating the magic info inside the rst.
117 124 #('docs/magic.tex',
118 125 #['IPython/Magic.py'],
119 126 #"cd doc && ./update_magic.sh" ),
120 127
121 128 ('docs/man/ipcluster.1.gz',
122 129 ['docs/man/ipcluster.1'],
123 130 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
124 131
125 132 ('docs/man/ipcontroller.1.gz',
126 133 ['docs/man/ipcontroller.1'],
127 134 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
128 135
129 136 ('docs/man/ipengine.1.gz',
130 137 ['docs/man/ipengine.1'],
131 138 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
132 139
133 140 ('docs/man/iplogger.1.gz',
134 141 ['docs/man/iplogger.1'],
135 142 'cd docs/man && gzip -9c iplogger.1 > iplogger.1.gz'),
136 143
137 144 ('docs/man/ipython.1.gz',
138 145 ['docs/man/ipython.1'],
139 146 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
140 147
141 148 ('docs/man/irunner.1.gz',
142 149 ['docs/man/irunner.1'],
143 150 'cd docs/man && gzip -9c irunner.1 > irunner.1.gz'),
144 151
145 152 ('docs/man/pycolor.1.gz',
146 153 ['docs/man/pycolor.1'],
147 154 'cd docs/man && gzip -9c pycolor.1 > pycolor.1.gz'),
148 155 ]
149 156
150 157 # Only build the docs if sphinx is present
151 158 try:
152 159 import sphinx
153 160 except ImportError:
154 161 pass
155 162 else:
156 163 # The Makefile calls the do_sphinx scripts to build html and pdf, so
157 164 # just one target is enough to cover all manual generation
158 165
159 166 # First, compute all the dependencies that can force us to rebuild the
160 167 # docs. Start with the main release file that contains metadata
161 168 docdeps = ['IPython/core/release.py']
162 169 # Inculde all the reST sources
163 170 pjoin = os.path.join
164 171 for dirpath,dirnames,filenames in os.walk('docs/source'):
165 172 if dirpath in ['_static','_templates']:
166 173 continue
167 174 docdeps += [ pjoin(dirpath,f) for f in filenames
168 175 if f.endswith('.txt') ]
169 176 # and the examples
170 177 for dirpath,dirnames,filenames in os.walk('docs/example'):
171 178 docdeps += [ pjoin(dirpath,f) for f in filenames
172 179 if not f.endswith('~') ]
173 180 # then, make them all dependencies for the main html docs
174 181 to_update.append(
175 182 ('docs/dist/index.html',
176 183 docdeps,
177 184 "cd docs && make dist")
178 185 )
179 186
180 187 [ target_update(*t) for t in to_update ]
181 188
182 189 #---------------------------------------------------------------------------
183 190 # Find all the packages, package data, and data_files
184 191 #---------------------------------------------------------------------------
185 192
186 193 packages = find_packages()
187 194 package_data = find_package_data()
188 195 data_files = find_data_files()
189 196
197 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython')}
198 setup_args['packages'] = packages
199 setup_args['package_data'] = package_data
200 setup_args['data_files'] = data_files
201
190 202 #---------------------------------------------------------------------------
191 203 # Handle scripts, dependencies, and setuptools specific things
192 204 #---------------------------------------------------------------------------
193 205
194 206 # For some commands, use setuptools. Note that we do NOT list install here!
195 207 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
196 208 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
197 209 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info',
198 210 'egg_info', 'easy_install', 'upload',
199 211 ))
200 212 if sys.platform == 'win32':
201 213 # Depend on setuptools for install on *Windows only*
202 214 # If we get script-installation working without setuptools,
203 215 # then we can back off, but until then use it.
204 216 # See Issue #369 on GitHub for more
205 217 needs_setuptools.add('install')
206 218
207 219 if len(needs_setuptools.intersection(sys.argv)) > 0:
208 220 import setuptools
209 221
210 222 # This dict is used for passing extra arguments that are setuptools
211 223 # specific to setup
212 224 setuptools_extra_args = {}
213 225
214 226 if 'setuptools' in sys.modules:
215 227 setuptools_extra_args['zip_safe'] = False
216 228 setuptools_extra_args['entry_points'] = find_scripts(True)
217 229 setup_args['extras_require'] = dict(
218 230 parallel = 'pyzmq>=2.1.4',
219 231 zmq = 'pyzmq>=2.1.4',
220 232 doc = 'Sphinx>=0.3',
221 233 test = 'nose>=0.10.1',
222 234 notebook = 'tornado>=2.0'
223 235 )
224 236 requires = setup_args.setdefault('install_requires', [])
225 237 setupext.display_status = False
226 238 if not setupext.check_for_readline():
227 239 if sys.platform == 'darwin':
228 240 requires.append('readline')
229 241 elif sys.platform.startswith('win') and sys.maxsize < 2**32:
230 242 # only require pyreadline on 32b Windows, due to 64b bug in pyreadline:
231 243 # https://bugs.launchpad.net/pyreadline/+bug/787574
232 244 requires.append('pyreadline')
233 245 else:
234 246 pass
235 247 # do we want to install readline here?
236 248
237 249 # Script to be run by the windows binary installer after the default setup
238 250 # routine, to add shortcuts and similar windows-only things. Windows
239 251 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
240 252 # doesn't find them.
241 253 if 'bdist_wininst' in sys.argv:
242 254 if len(sys.argv) > 2 and \
243 255 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
244 256 print >> sys.stderr, "ERROR: bdist_wininst must be run alone. Exiting."
245 257 sys.exit(1)
246 258 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
247 259 setup_args['options'] = {"bdist_wininst":
248 260 {"install_script":
249 261 "ipython_win_post_install.py"}}
262
263 if PY3:
264 setuptools_extra_args['use_2to3'] = True
265 from setuptools.command.build_py import build_py
266 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython', build_cmd=build_py)}
267 setuptools_extra_args['entry_points'] = find_scripts(True, suffix='3')
250 268 else:
251 269 # If we are running without setuptools, call this function which will
252 270 # check for dependencies an inform the user what is needed. This is
253 271 # just to make life easy for users.
254 272 check_for_dependencies()
255 273 setup_args['scripts'] = find_scripts(False)
256 274
257 275 #---------------------------------------------------------------------------
258 276 # Do the actual setup now
259 277 #---------------------------------------------------------------------------
260 278
261 setup_args['cmdclass'] = {'build_py': record_commit_info('IPython')}
262 setup_args['packages'] = packages
263 setup_args['package_data'] = package_data
264 setup_args['data_files'] = data_files
265 279 setup_args.update(setuptools_extra_args)
266 280
267 281 def main():
268 282 setup(**setup_args)
269 283 cleanup()
270 284
271 285 if __name__ == '__main__':
272 286 main()
@@ -1,390 +1,428 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 from __future__ import print_function
12 12
13 13 #-------------------------------------------------------------------------------
14 14 # Copyright (C) 2008 The IPython Development Team
15 15 #
16 16 # Distributed under the terms of the BSD License. The full license is in
17 17 # the file COPYING, distributed as part of this software.
18 18 #-------------------------------------------------------------------------------
19 19
20 20 #-------------------------------------------------------------------------------
21 21 # Imports
22 22 #-------------------------------------------------------------------------------
23 23 import os
24 24 import sys
25 25
26 26 try:
27 27 from configparser import ConfigParser
28 28 except:
29 29 from ConfigParser import ConfigParser
30 30 from distutils.command.build_py import build_py
31 31 from glob import glob
32 32
33 33 from setupext import install_data_ext
34 34
35 35 #-------------------------------------------------------------------------------
36 36 # Useful globals and utility functions
37 37 #-------------------------------------------------------------------------------
38 38
39 39 # A few handy globals
40 40 isfile = os.path.isfile
41 41 pjoin = os.path.join
42 42
43 43 def oscmd(s):
44 44 print(">", s)
45 45 os.system(s)
46 46
47 47 try:
48 48 execfile
49 49 except NameError:
50 50 def execfile(fname, globs, locs=None):
51 51 locs = locs or globs
52 52 exec(compile(open(fname).read(), fname, "exec"), globs, locs)
53 53
54 54 # A little utility we'll need below, since glob() does NOT allow you to do
55 55 # exclusion on multiple endings!
56 56 def file_doesnt_endwith(test,endings):
57 57 """Return true if test is a file and its name does NOT end with any
58 58 of the strings listed in endings."""
59 59 if not isfile(test):
60 60 return False
61 61 for e in endings:
62 62 if test.endswith(e):
63 63 return False
64 64 return True
65 65
66 66 #---------------------------------------------------------------------------
67 67 # Basic project information
68 68 #---------------------------------------------------------------------------
69 69
70 70 # release.py contains version, authors, license, url, keywords, etc.
71 71 execfile(pjoin('IPython','core','release.py'), globals())
72 72
73 73 # Create a dict with the basic information
74 74 # This dict is eventually passed to setup after additional keys are added.
75 75 setup_args = dict(
76 76 name = name,
77 77 version = version,
78 78 description = description,
79 79 long_description = long_description,
80 80 author = author,
81 81 author_email = author_email,
82 82 url = url,
83 83 download_url = download_url,
84 84 license = license,
85 85 platforms = platforms,
86 86 keywords = keywords,
87 87 classifiers = classifiers,
88 88 cmdclass = {'install_data': install_data_ext},
89 89 )
90 90
91 91
92 92 #---------------------------------------------------------------------------
93 93 # Find packages
94 94 #---------------------------------------------------------------------------
95 95
96 96 def find_packages():
97 97 """
98 98 Find all of IPython's packages.
99 99 """
100 100 excludes = ['deathrow']
101 101 packages = []
102 102 for dir,subdirs,files in os.walk('IPython'):
103 103 package = dir.replace(os.path.sep, '.')
104 104 if any([ package.startswith('IPython.'+exc) for exc in excludes ]):
105 105 # package is to be excluded (e.g. deathrow)
106 106 continue
107 107 if '__init__.py' not in files:
108 108 # not a package
109 109 continue
110 110 packages.append(package)
111 111 return packages
112 112
113 113 #---------------------------------------------------------------------------
114 114 # Find package data
115 115 #---------------------------------------------------------------------------
116 116
117 117 def find_package_data():
118 118 """
119 119 Find IPython's package_data.
120 120 """
121 121 # This is not enough for these things to appear in an sdist.
122 122 # We need to muck with the MANIFEST to get this to work
123 123
124 124 # exclude static things that we don't ship (e.g. mathjax)
125 125 excludes = ['mathjax']
126 126
127 127 # add 'static/' prefix to exclusions, and tuplify for use in startswith
128 128 excludes = tuple([os.path.join('static', ex) for ex in excludes])
129 129
130 130 # walk notebook resources:
131 131 cwd = os.getcwd()
132 132 os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook'))
133 133 static_walk = list(os.walk('static'))
134 134 os.chdir(cwd)
135 135 static_data = []
136 136 for parent, dirs, files in static_walk:
137 137 if parent.startswith(excludes):
138 138 continue
139 139 for f in files:
140 140 static_data.append(os.path.join(parent, f))
141 141
142 142 package_data = {
143 143 'IPython.config.profile' : ['README*', '*/*.py'],
144 144 'IPython.testing' : ['*.txt'],
145 145 'IPython.frontend.html.notebook' : ['templates/*'] + static_data,
146 146 'IPython.frontend.qt.console' : ['resources/icon/*.svg'],
147 147 }
148 148 return package_data
149 149
150 150
151 151 #---------------------------------------------------------------------------
152 152 # Find data files
153 153 #---------------------------------------------------------------------------
154 154
155 155 def make_dir_struct(tag,base,out_base):
156 156 """Make the directory structure of all files below a starting dir.
157 157
158 158 This is just a convenience routine to help build a nested directory
159 159 hierarchy because distutils is too stupid to do this by itself.
160 160
161 161 XXX - this needs a proper docstring!
162 162 """
163 163
164 164 # we'll use these a lot below
165 165 lbase = len(base)
166 166 pathsep = os.path.sep
167 167 lpathsep = len(pathsep)
168 168
169 169 out = []
170 170 for (dirpath,dirnames,filenames) in os.walk(base):
171 171 # we need to strip out the dirpath from the base to map it to the
172 172 # output (installation) path. This requires possibly stripping the
173 173 # path separator, because otherwise pjoin will not work correctly
174 174 # (pjoin('foo/','/bar') returns '/bar').
175 175
176 176 dp_eff = dirpath[lbase:]
177 177 if dp_eff.startswith(pathsep):
178 178 dp_eff = dp_eff[lpathsep:]
179 179 # The output path must be anchored at the out_base marker
180 180 out_path = pjoin(out_base,dp_eff)
181 181 # Now we can generate the final filenames. Since os.walk only produces
182 182 # filenames, we must join back with the dirpath to get full valid file
183 183 # paths:
184 184 pfiles = [pjoin(dirpath,f) for f in filenames]
185 185 # Finally, generate the entry we need, which is a pari of (output
186 186 # path, files) for use as a data_files parameter in install_data.
187 187 out.append((out_path, pfiles))
188 188
189 189 return out
190 190
191 191
192 192 def find_data_files():
193 193 """
194 194 Find IPython's data_files.
195 195
196 196 Most of these are docs.
197 197 """
198 198
199 199 docdirbase = pjoin('share', 'doc', 'ipython')
200 200 manpagebase = pjoin('share', 'man', 'man1')
201 201
202 202 # Simple file lists can be made by hand
203 203 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
204 204 if not manpages:
205 205 # When running from a source tree, the manpages aren't gzipped
206 206 manpages = filter(isfile, glob(pjoin('docs','man','*.1')))
207 207 igridhelpfiles = filter(isfile,
208 208 glob(pjoin('IPython','extensions','igrid_help.*')))
209 209
210 210 # For nested structures, use the utility above
211 211 example_files = make_dir_struct(
212 212 'data',
213 213 pjoin('docs','examples'),
214 214 pjoin(docdirbase,'examples')
215 215 )
216 216 manual_files = make_dir_struct(
217 217 'data',
218 218 pjoin('docs','html'),
219 219 pjoin(docdirbase,'manual')
220 220 )
221 221
222 222 # And assemble the entire output list
223 223 data_files = [ (manpagebase, manpages),
224 224 (pjoin(docdirbase, 'extensions'), igridhelpfiles),
225 225 ] + manual_files + example_files
226 226
227 227 return data_files
228 228
229 229
230 230 def make_man_update_target(manpage):
231 231 """Return a target_update-compliant tuple for the given manpage.
232 232
233 233 Parameters
234 234 ----------
235 235 manpage : string
236 236 Name of the manpage, must include the section number (trailing number).
237 237
238 238 Example
239 239 -------
240 240
241 241 >>> make_man_update_target('ipython.1') #doctest: +NORMALIZE_WHITESPACE
242 242 ('docs/man/ipython.1.gz',
243 243 ['docs/man/ipython.1'],
244 244 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz')
245 245 """
246 246 man_dir = pjoin('docs', 'man')
247 247 manpage_gz = manpage + '.gz'
248 248 manpath = pjoin(man_dir, manpage)
249 249 manpath_gz = pjoin(man_dir, manpage_gz)
250 250 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
251 251 locals() )
252 252 return (manpath_gz, [manpath], gz_cmd)
253 253
254 # The two functions below are copied from IPython.utils.path, so we don't need
255 # to import IPython during setup, which fails on Python 3.
256
257 def target_outdated(target,deps):
258 """Determine whether a target is out of date.
259
260 target_outdated(target,deps) -> 1/0
261
262 deps: list of filenames which MUST exist.
263 target: single filename which may or may not exist.
264
265 If target doesn't exist or is older than any file listed in deps, return
266 true, otherwise return false.
267 """
268 try:
269 target_time = os.path.getmtime(target)
270 except os.error:
271 return 1
272 for dep in deps:
273 dep_time = os.path.getmtime(dep)
274 if dep_time > target_time:
275 #print "For target",target,"Dep failed:",dep # dbg
276 #print "times (dep,tar):",dep_time,target_time # dbg
277 return 1
278 return 0
279
280
281 def target_update(target,deps,cmd):
282 """Update a target with a given command given a list of dependencies.
283
284 target_update(target,deps,cmd) -> runs cmd if target is outdated.
285
286 This is just a wrapper around target_outdated() which calls the given
287 command if target is outdated."""
288
289 if target_outdated(target,deps):
290 system(cmd)
291
254 292 #---------------------------------------------------------------------------
255 293 # Find scripts
256 294 #---------------------------------------------------------------------------
257 295
258 296 def find_scripts(entry_points=False, suffix=''):
259 297 """Find IPython's scripts.
260 298
261 299 if entry_points is True:
262 300 return setuptools entry_point-style definitions
263 301 else:
264 302 return file paths of plain scripts [default]
265 303
266 304 suffix is appended to script names if entry_points is True, so that the
267 305 Python 3 scripts get named "ipython3" etc.
268 306 """
269 307 if entry_points:
270 308 console_scripts = [s % suffix for s in [
271 309 'ipython%s = IPython.frontend.terminal.ipapp:launch_new_instance',
272 310 'pycolor%s = IPython.utils.PyColorize:main',
273 311 'ipcontroller%s = IPython.parallel.apps.ipcontrollerapp:launch_new_instance',
274 312 'ipengine%s = IPython.parallel.apps.ipengineapp:launch_new_instance',
275 313 'iplogger%s = IPython.parallel.apps.iploggerapp:launch_new_instance',
276 314 'ipcluster%s = IPython.parallel.apps.ipclusterapp:launch_new_instance',
277 315 'iptest%s = IPython.testing.iptest:main',
278 316 'irunner%s = IPython.lib.irunner:main'
279 317 ]]
280 318 gui_scripts = [s % suffix for s in [
281 319 'ipython%s-qtconsole = IPython.frontend.qt.console.qtconsoleapp:main',
282 320 ]]
283 321 scripts = dict(console_scripts=console_scripts, gui_scripts=gui_scripts)
284 322 else:
285 323 parallel_scripts = pjoin('IPython','parallel','scripts')
286 324 main_scripts = pjoin('IPython','scripts')
287 325 scripts = [
288 326 pjoin(parallel_scripts, 'ipengine'),
289 327 pjoin(parallel_scripts, 'ipcontroller'),
290 328 pjoin(parallel_scripts, 'ipcluster'),
291 329 pjoin(parallel_scripts, 'iplogger'),
292 330 pjoin(main_scripts, 'ipython'),
293 331 pjoin(main_scripts, 'pycolor'),
294 332 pjoin(main_scripts, 'irunner'),
295 333 pjoin(main_scripts, 'iptest')
296 334 ]
297 335 return scripts
298 336
299 337 #---------------------------------------------------------------------------
300 338 # Verify all dependencies
301 339 #---------------------------------------------------------------------------
302 340
303 341 def check_for_dependencies():
304 342 """Check for IPython's dependencies.
305 343
306 344 This function should NOT be called if running under setuptools!
307 345 """
308 346 from setupext.setupext import (
309 347 print_line, print_raw, print_status,
310 348 check_for_sphinx, check_for_pygments,
311 349 check_for_nose, check_for_pexpect,
312 350 check_for_pyzmq, check_for_readline
313 351 )
314 352 print_line()
315 353 print_raw("BUILDING IPYTHON")
316 354 print_status('python', sys.version)
317 355 print_status('platform', sys.platform)
318 356 if sys.platform == 'win32':
319 357 print_status('Windows version', sys.getwindowsversion())
320 358
321 359 print_raw("")
322 360 print_raw("OPTIONAL DEPENDENCIES")
323 361
324 362 check_for_sphinx()
325 363 check_for_pygments()
326 364 check_for_nose()
327 365 check_for_pexpect()
328 366 check_for_pyzmq()
329 367 check_for_readline()
330 368
331 369 def record_commit_info(pkg_dir, build_cmd=build_py):
332 370 """ Return extended build command class for recording commit
333 371
334 372 The extended command tries to run git to find the current commit, getting
335 373 the empty string if it fails. It then writes the commit hash into a file
336 374 in the `pkg_dir` path, named ``.git_commit_info.ini``.
337 375
338 376 In due course this information can be used by the package after it is
339 377 installed, to tell you what commit it was installed from if known.
340 378
341 379 To make use of this system, you need a package with a .git_commit_info.ini
342 380 file - e.g. ``myproject/.git_commit_info.ini`` - that might well look like
343 381 this::
344 382
345 383 # This is an ini file that may contain information about the code state
346 384 [commit hash]
347 385 # The line below may contain a valid hash if it has been substituted
348 386 # during 'git archive'
349 387 archive_subst_hash=$Format:%h$
350 388 # This line may be modified by the install process
351 389 install_hash=
352 390
353 391 The .git_commit_info file above is also designed to be used with git
354 392 substitution - so you probably also want a ``.gitattributes`` file in the
355 393 root directory of your working tree that contains something like this::
356 394
357 395 myproject/.git_commit_info.ini export-subst
358 396
359 397 That will cause the ``.git_commit_info.ini`` file to get filled in by ``git
360 398 archive`` - useful in case someone makes such an archive - for example with
361 399 via the github 'download source' button.
362 400
363 401 Although all the above will work as is, you might consider having something
364 402 like a ``get_info()`` function in your package to display the commit
365 403 information at the terminal. See the ``pkg_info.py`` module in the nipy
366 404 package for an example.
367 405 """
368 406 class MyBuildPy(build_cmd):
369 407 ''' Subclass to write commit data into installation tree '''
370 408 def run(self):
371 409 build_cmd.run(self)
372 410 import subprocess
373 411 proc = subprocess.Popen('git rev-parse --short HEAD',
374 412 stdout=subprocess.PIPE,
375 413 stderr=subprocess.PIPE,
376 414 shell=True)
377 415 repo_commit, _ = proc.communicate()
378 416 # We write the installation commit even if it's empty
379 417 cfg_parser = ConfigParser()
380 418 cfg_parser.read(pjoin(pkg_dir, '.git_commit_info.ini'))
381 419 if not cfg_parser.has_section('commit hash'):
382 420 # just in case the ini file is empty or doesn't exist, somehow
383 421 # we don't want the next line to raise
384 422 cfg_parser.add_section('commit hash')
385 423 cfg_parser.set('commit hash', 'install_hash', repo_commit.decode('ascii'))
386 424 out_pth = pjoin(self.build_lib, pkg_dir, '.git_commit_info.ini')
387 425 out_file = open(out_pth, 'wt')
388 426 cfg_parser.write(out_file)
389 427 out_file.close()
390 428 return MyBuildPy
@@ -1,176 +1,177 b''
1 1 # encoding: utf-8
2 from __future__ import print_function
2 3
3 4 __docformat__ = "restructuredtext en"
4 5
5 6 #-------------------------------------------------------------------------------
6 7 # Copyright (C) 2008 The IPython Development Team
7 8 #
8 9 # Distributed under the terms of the BSD License. The full license is in
9 10 # the file COPYING, distributed as part of this software.
10 11 #-------------------------------------------------------------------------------
11 12
12 13 #-------------------------------------------------------------------------------
13 14 # Imports
14 15 #-------------------------------------------------------------------------------
15 16
16 17 import sys, os
17 18 from textwrap import fill
18 19
19 20 display_status=True
20 21
21 22 def check_display(f):
22 23 """decorator to allow display methods to be muted by mod.display_status"""
23 24 def maybe_display(*args, **kwargs):
24 25 if display_status:
25 26 return f(*args, **kwargs)
26 27 return maybe_display
27 28
28 29 @check_display
29 30 def print_line(char='='):
30 print char * 76
31 print(char * 76)
31 32
32 33 @check_display
33 34 def print_status(package, status):
34 35 initial_indent = "%22s: " % package
35 36 indent = ' ' * 24
36 print fill(str(status), width=76,
37 print(fill(str(status), width=76,
37 38 initial_indent=initial_indent,
38 subsequent_indent=indent)
39 subsequent_indent=indent))
39 40
40 41 @check_display
41 42 def print_message(message):
42 43 indent = ' ' * 24 + "* "
43 print fill(str(message), width=76,
44 print(fill(str(message), width=76,
44 45 initial_indent=indent,
45 subsequent_indent=indent)
46 subsequent_indent=indent))
46 47
47 48 @check_display
48 49 def print_raw(section):
49 print section
50 print(section)
50 51
51 52 #-------------------------------------------------------------------------------
52 53 # Tests for specific packages
53 54 #-------------------------------------------------------------------------------
54 55
55 56 def check_for_ipython():
56 57 try:
57 58 import IPython
58 59 except ImportError:
59 60 print_status("IPython", "Not found")
60 61 return False
61 62 else:
62 63 print_status("IPython", IPython.__version__)
63 64 return True
64 65
65 66 def check_for_sphinx():
66 67 try:
67 68 import sphinx
68 69 except ImportError:
69 70 print_status('sphinx', "Not found (required for building documentation)")
70 71 return False
71 72 else:
72 73 print_status('sphinx', sphinx.__version__)
73 74 return True
74 75
75 76 def check_for_pygments():
76 77 try:
77 78 import pygments
78 79 except ImportError:
79 80 print_status('pygments', "Not found (required for syntax highlighting documentation)")
80 81 return False
81 82 else:
82 83 print_status('pygments', pygments.__version__)
83 84 return True
84 85
85 86 def check_for_nose():
86 87 try:
87 88 import nose
88 89 except ImportError:
89 90 print_status('nose', "Not found (required for running the test suite)")
90 91 return False
91 92 else:
92 93 print_status('nose', nose.__version__)
93 94 return True
94 95
95 96 def check_for_pexpect():
96 97 try:
97 98 import pexpect
98 99 except ImportError:
99 100 print_status("pexpect", "no (required for running standalone doctests)")
100 101 return False
101 102 else:
102 103 print_status("pexpect", pexpect.__version__)
103 104 return True
104 105
105 106 def check_for_httplib2():
106 107 try:
107 108 import httplib2
108 109 except ImportError:
109 110 print_status("httplib2", "no (required for blocking http clients)")
110 111 return False
111 112 else:
112 113 print_status("httplib2","yes")
113 114 return True
114 115
115 116 def check_for_sqlalchemy():
116 117 try:
117 118 import sqlalchemy
118 119 except ImportError:
119 120 print_status("sqlalchemy", "no (required for the ipython1 notebook)")
120 121 return False
121 122 else:
122 123 print_status("sqlalchemy","yes")
123 124 return True
124 125
125 126 def check_for_simplejson():
126 127 try:
127 128 import simplejson
128 129 except ImportError:
129 130 print_status("simplejson", "no (required for the ipython1 notebook)")
130 131 return False
131 132 else:
132 133 print_status("simplejson","yes")
133 134 return True
134 135
135 136 def check_for_pyzmq():
136 137 try:
137 138 import zmq
138 139 except ImportError:
139 140 print_status('pyzmq', "no (required for qtconsole, notebook, and parallel computing capabilities)")
140 141 return False
141 142 else:
142 143 # pyzmq 2.1.10 adds pyzmq_version_info funtion for returning
143 144 # version as a tuple
144 145 if hasattr(zmq, 'pyzmq_version_info'):
145 146 if zmq.pyzmq_version_info() >= (2,1,4):
146 147 print_status("pyzmq", zmq.__version__)
147 148 return True
148 149 else:
149 150 # this branch can never occur, at least until we update our
150 151 # pyzmq dependency beyond 2.1.10
151 152 return False
152 153 # this is necessarily earlier than 2.1.10, so string comparison is
153 154 # okay
154 155 if zmq.__version__ < '2.1.4':
155 156 print_status('pyzmq', "no (have %s, but require >= 2.1.4 for"
156 157 " qtconsole and parallel computing capabilities)"%zmq.__version__)
157 158 return False
158 159 else:
159 160 print_status("pyzmq", zmq.__version__)
160 161 return True
161 162
162 163 def check_for_readline():
163 164 try:
164 165 import readline
165 166 except ImportError:
166 167 try:
167 168 import pyreadline
168 169 except ImportError:
169 170 print_status('readline', "no (required for good interactive behavior)")
170 171 return False
171 172 else:
172 173 print_status('readline', "yes pyreadline-"+pyreadline.release.version)
173 174 return True
174 175 else:
175 176 print_status('readline', "yes")
176 177 return True
General Comments 0
You need to be logged in to leave comments. Login now