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