##// END OF EJS Templates
Move project_urls to setup.cfg
James Morris -
Show More
@@ -1,7 +1,12 b''
1 1 [metadata]
2 2 license_file = LICENSE
3 project_urls =
4 Documentation = https://ipython.readthedocs.io/
5 Funding = https://numfocus.org/
6 Source = https://github.com/ipython/ipython
7 Tracker = https://github.com/ipython/ipython/issues
3 8
4 9 [velin]
5 10 ignore_patterns =
6 11 IPython/core/tests,
7 12 IPython/testing
@@ -1,361 +1,355 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 import os
16 16 import re
17 17 import sys
18 18 from glob import glob
19 19 from logging import log
20 20
21 21 from setuptools import Command
22 22 from setuptools.command.build_py import build_py
23 23
24 24 from setuptools.command.install import install
25 25 from setuptools.command.install_scripts import install_scripts
26 26
27 27 from setupext import install_data_ext
28 28
29 29 #-------------------------------------------------------------------------------
30 30 # Useful globals and utility functions
31 31 #-------------------------------------------------------------------------------
32 32
33 33 # A few handy globals
34 34 isfile = os.path.isfile
35 35 pjoin = os.path.join
36 36 repo_root = os.path.dirname(os.path.abspath(__file__))
37 37
38 38 def execfile(fname, globs, locs=None):
39 39 locs = locs or globs
40 40 with open(fname) as f:
41 41 exec(compile(f.read(), fname, "exec"), globs, locs)
42 42
43 43 # A little utility we'll need below, since glob() does NOT allow you to do
44 44 # exclusion on multiple endings!
45 45 def file_doesnt_endwith(test,endings):
46 46 """Return true if test is a file and its name does NOT end with any
47 47 of the strings listed in endings."""
48 48 if not isfile(test):
49 49 return False
50 50 for e in endings:
51 51 if test.endswith(e):
52 52 return False
53 53 return True
54 54
55 55 #---------------------------------------------------------------------------
56 56 # Basic project information
57 57 #---------------------------------------------------------------------------
58 58
59 59 # release.py contains version, authors, license, url, keywords, etc.
60 60 execfile(pjoin(repo_root, 'IPython','core','release.py'), globals())
61 61
62 62 # Create a dict with the basic information
63 63 # This dict is eventually passed to setup after additional keys are added.
64 64 setup_args = dict(
65 65 name = name,
66 66 version = version,
67 67 description = description,
68 68 long_description = long_description,
69 69 author = author,
70 70 author_email = author_email,
71 71 url = url,
72 72 license = license,
73 73 platforms = platforms,
74 74 keywords = keywords,
75 75 classifiers = classifiers,
76 76 cmdclass = {'install_data': install_data_ext},
77 project_urls={
78 'Documentation': 'https://ipython.readthedocs.io/',
79 'Funding' : 'https://numfocus.org/',
80 'Source' : 'https://github.com/ipython/ipython',
81 'Tracker' : 'https://github.com/ipython/ipython/issues',
82 }
83 77 )
84 78
85 79
86 80 #---------------------------------------------------------------------------
87 81 # Find packages
88 82 #---------------------------------------------------------------------------
89 83
90 84 def find_packages():
91 85 """
92 86 Find all of IPython's packages.
93 87 """
94 88 excludes = ['deathrow', 'quarantine']
95 89 packages = []
96 90 for directory, subdirs, files in os.walk("IPython"):
97 91 package = directory.replace(os.path.sep, ".")
98 92 if any(package.startswith("IPython." + exc) for exc in excludes):
99 93 # package is to be excluded (e.g. deathrow)
100 94 continue
101 95 if '__init__.py' not in files:
102 96 # not a package
103 97 continue
104 98 packages.append(package)
105 99 return packages
106 100
107 101 #---------------------------------------------------------------------------
108 102 # Find package data
109 103 #---------------------------------------------------------------------------
110 104
111 105 def find_package_data():
112 106 """
113 107 Find IPython's package_data.
114 108 """
115 109 # This is not enough for these things to appear in an sdist.
116 110 # We need to muck with the MANIFEST to get this to work
117 111
118 112 package_data = {
119 113 'IPython.core' : ['profile/README*'],
120 114 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'],
121 115 'IPython.lib.tests' : ['*.wav'],
122 116 'IPython.testing.plugin' : ['*.txt'],
123 117 }
124 118
125 119 return package_data
126 120
127 121
128 122 def check_package_data(package_data):
129 123 """verify that package_data globs make sense"""
130 124 print("checking package data")
131 125 for pkg, data in package_data.items():
132 126 pkg_root = pjoin(*pkg.split('.'))
133 127 for d in data:
134 128 path = pjoin(pkg_root, d)
135 129 if '*' in path:
136 130 assert len(glob(path)) > 0, "No files match pattern %s" % path
137 131 else:
138 132 assert os.path.exists(path), "Missing package data: %s" % path
139 133
140 134
141 135 def check_package_data_first(command):
142 136 """decorator for checking package_data before running a given command
143 137
144 138 Probably only needs to wrap build_py
145 139 """
146 140 class DecoratedCommand(command):
147 141 def run(self):
148 142 check_package_data(self.package_data)
149 143 command.run(self)
150 144 return DecoratedCommand
151 145
152 146
153 147 #---------------------------------------------------------------------------
154 148 # Find data files
155 149 #---------------------------------------------------------------------------
156 150
157 151 def find_data_files():
158 152 """
159 153 Find IPython's data_files.
160 154
161 155 Just man pages at this point.
162 156 """
163 157
164 158 if "freebsd" in sys.platform:
165 159 manpagebase = pjoin('man', 'man1')
166 160 else:
167 161 manpagebase = pjoin('share', 'man', 'man1')
168 162
169 163 # Simple file lists can be made by hand
170 164 manpages = [f for f in glob(pjoin('docs','man','*.1.gz')) if isfile(f)]
171 165 if not manpages:
172 166 # When running from a source tree, the manpages aren't gzipped
173 167 manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)]
174 168
175 169 # And assemble the entire output list
176 170 data_files = [ (manpagebase, manpages) ]
177 171
178 172 return data_files
179 173
180 174
181 175 # The two functions below are copied from IPython.utils.path, so we don't need
182 176 # to import IPython during setup, which fails on Python 3.
183 177
184 178 def target_outdated(target,deps):
185 179 """Determine whether a target is out of date.
186 180
187 181 target_outdated(target,deps) -> 1/0
188 182
189 183 deps: list of filenames which MUST exist.
190 184 target: single filename which may or may not exist.
191 185
192 186 If target doesn't exist or is older than any file listed in deps, return
193 187 true, otherwise return false.
194 188 """
195 189 try:
196 190 target_time = os.path.getmtime(target)
197 191 except os.error:
198 192 return 1
199 193 for dep in deps:
200 194 dep_time = os.path.getmtime(dep)
201 195 if dep_time > target_time:
202 196 #print "For target",target,"Dep failed:",dep # dbg
203 197 #print "times (dep,tar):",dep_time,target_time # dbg
204 198 return 1
205 199 return 0
206 200
207 201
208 202 def target_update(target,deps,cmd):
209 203 """Update a target with a given command given a list of dependencies.
210 204
211 205 target_update(target,deps,cmd) -> runs cmd if target is outdated.
212 206
213 207 This is just a wrapper around target_outdated() which calls the given
214 208 command if target is outdated."""
215 209
216 210 if target_outdated(target,deps):
217 211 os.system(cmd)
218 212
219 213 #---------------------------------------------------------------------------
220 214 # Find scripts
221 215 #---------------------------------------------------------------------------
222 216
223 217 def find_entry_points():
224 218 """Defines the command line entry points for IPython
225 219
226 220 This always uses setuptools-style entry points. When setuptools is not in
227 221 use, our own build_scripts_entrypt class below parses these and builds
228 222 command line scripts.
229 223
230 224 Each of our entry points gets both a plain name, e.g. ipython, and one
231 225 suffixed with the Python major version number, e.g. ipython3.
232 226 """
233 227 ep = [
234 228 'ipython%s = IPython:start_ipython',
235 229 ]
236 230 suffix = str(sys.version_info[0])
237 231 return [e % '' for e in ep] + [e % suffix for e in ep]
238 232
239 233 class install_lib_symlink(Command):
240 234 user_options = [
241 235 ('install-dir=', 'd', "directory to install to"),
242 236 ]
243 237
244 238 def initialize_options(self):
245 239 self.install_dir = None
246 240
247 241 def finalize_options(self):
248 242 self.set_undefined_options('symlink',
249 243 ('install_lib', 'install_dir'),
250 244 )
251 245
252 246 def run(self):
253 247 if sys.platform == 'win32':
254 248 raise Exception("This doesn't work on Windows.")
255 249 pkg = os.path.join(os.getcwd(), 'IPython')
256 250 dest = os.path.join(self.install_dir, 'IPython')
257 251 if os.path.islink(dest):
258 252 print('removing existing symlink at %s' % dest)
259 253 os.unlink(dest)
260 254 print('symlinking %s -> %s' % (pkg, dest))
261 255 os.symlink(pkg, dest)
262 256
263 257 class unsymlink(install):
264 258 def run(self):
265 259 dest = os.path.join(self.install_lib, 'IPython')
266 260 if os.path.islink(dest):
267 261 print('removing symlink at %s' % dest)
268 262 os.unlink(dest)
269 263 else:
270 264 print('No symlink exists at %s' % dest)
271 265
272 266 class install_symlinked(install):
273 267 def run(self):
274 268 if sys.platform == 'win32':
275 269 raise Exception("This doesn't work on Windows.")
276 270
277 271 # Run all sub-commands (at least those that need to be run)
278 272 for cmd_name in self.get_sub_commands():
279 273 self.run_command(cmd_name)
280 274
281 275 # 'sub_commands': a list of commands this command might have to run to
282 276 # get its work done. See cmd.py for more info.
283 277 sub_commands = [('install_lib_symlink', lambda self:True),
284 278 ('install_scripts_sym', lambda self:True),
285 279 ]
286 280
287 281 class install_scripts_for_symlink(install_scripts):
288 282 """Redefined to get options from 'symlink' instead of 'install'.
289 283
290 284 I love distutils almost as much as I love setuptools.
291 285 """
292 286 def finalize_options(self):
293 287 self.set_undefined_options('build', ('build_scripts', 'build_dir'))
294 288 self.set_undefined_options('symlink',
295 289 ('install_scripts', 'install_dir'),
296 290 ('force', 'force'),
297 291 ('skip_build', 'skip_build'),
298 292 )
299 293
300 294
301 295 #---------------------------------------------------------------------------
302 296 # VCS related
303 297 #---------------------------------------------------------------------------
304 298
305 299
306 300 def git_prebuild(pkg_dir, build_cmd=build_py):
307 301 """Return extended build or sdist command class for recording commit
308 302
309 303 records git commit in IPython.utils._sysinfo.commit
310 304
311 305 for use in IPython.utils.sysinfo.sys_info() calls after installation.
312 306 """
313 307
314 308 class MyBuildPy(build_cmd):
315 309 ''' Subclass to write commit data into installation tree '''
316 310 def run(self):
317 311 # loose as `.dev` is suppose to be invalid
318 312 print("check version number")
319 313 loose_pep440re = re.compile(r'^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$')
320 314 if not loose_pep440re.match(version):
321 315 raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version)
322 316
323 317
324 318 build_cmd.run(self)
325 319 # this one will only fire for build commands
326 320 if hasattr(self, 'build_lib'):
327 321 self._record_commit(self.build_lib)
328 322
329 323 def make_release_tree(self, base_dir, files):
330 324 # this one will fire for sdist
331 325 build_cmd.make_release_tree(self, base_dir, files)
332 326 self._record_commit(base_dir)
333 327
334 328 def _record_commit(self, base_dir):
335 329 import subprocess
336 330 proc = subprocess.Popen('git rev-parse --short HEAD',
337 331 stdout=subprocess.PIPE,
338 332 stderr=subprocess.PIPE,
339 333 shell=True)
340 334 repo_commit, _ = proc.communicate()
341 335 repo_commit = repo_commit.strip().decode("ascii")
342 336
343 337 out_pth = pjoin(base_dir, pkg_dir, 'utils', '_sysinfo.py')
344 338 if os.path.isfile(out_pth) and not repo_commit:
345 339 # nothing to write, don't clobber
346 340 return
347 341
348 342 print("writing git commit '%s' to %s" % (repo_commit, out_pth))
349 343
350 344 # remove to avoid overwriting original via hard link
351 345 try:
352 346 os.remove(out_pth)
353 347 except (IOError, OSError):
354 348 pass
355 349 with open(out_pth, 'w') as out_file:
356 350 out_file.writelines([
357 351 '# GENERATED BY setup.py\n',
358 352 'commit = u"%s"\n' % repo_commit,
359 353 ])
360 354 return MyBuildPy
361 355
General Comments 0
You need to be logged in to leave comments. Login now