##// END OF EJS Templates
remove path from external
MinRK -
Show More
@@ -1,325 +1,326 b''
1 1 #!/usr/bin/env python
2 2
3 3 """ PickleShare - a small 'shelve' like datastore with concurrency support
4 4
5 5 Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
6 6 shelve, many processes can access the database simultaneously. Changing a
7 7 value in database is immediately visible to other processes accessing the
8 8 same database.
9 9
10 10 Concurrency is possible because the values are stored in separate files. Hence
11 11 the "database" is a directory where *all* files are governed by PickleShare.
12 12
13 13 Example usage::
14 14
15 15 from pickleshare import *
16 16 db = PickleShareDB('~/testpickleshare')
17 17 db.clear()
18 18 print "Should be empty:",db.items()
19 19 db['hello'] = 15
20 20 db['aku ankka'] = [1,2,313]
21 21 db['paths/are/ok/key'] = [1,(5,46)]
22 22 print db.keys()
23 23 del db['aku ankka']
24 24
25 25 This module is certainly not ZODB, but can be used for low-load
26 26 (non-mission-critical) situations where tiny code size trumps the
27 27 advanced features of a "real" object database.
28 28
29 29 Installation guide: easy_install pickleshare
30 30
31 31 Author: Ville Vainio <vivainio@gmail.com>
32 32 License: MIT open source license.
33 33
34 34 """
35 35 from __future__ import print_function
36 36
37 from IPython.external.path import path as Path
38 37 import stat, time
39 38 import collections
40 39 try:
41 40 import cPickle as pickle
42 41 except ImportError:
43 42 import pickle
44 43 import glob
45 44
45 from path import path as Path
46
46 47 def gethashfile(key):
47 48 return ("%02x" % abs(hash(key) % 256))[-2:]
48 49
49 50 _sentinel = object()
50 51
51 52 class PickleShareDB(collections.MutableMapping):
52 53 """ The main 'connection' object for PickleShare database """
53 54 def __init__(self,root):
54 55 """ Return a db object that will manage the specied directory"""
55 56 self.root = Path(root).expanduser().abspath()
56 57 if not self.root.isdir():
57 58 self.root.makedirs_p()
58 59 # cache has { 'key' : (obj, orig_mod_time) }
59 60 self.cache = {}
60 61
61 62
62 63 def __getitem__(self,key):
63 64 """ db['key'] reading """
64 65 fil = self.root / key
65 66 try:
66 67 mtime = (fil.stat()[stat.ST_MTIME])
67 68 except OSError:
68 69 raise KeyError(key)
69 70
70 71 if fil in self.cache and mtime == self.cache[fil][1]:
71 72 return self.cache[fil][0]
72 73 try:
73 74 # The cached item has expired, need to read
74 75 with fil.open("rb") as f:
75 76 obj = pickle.loads(f.read())
76 77 except:
77 78 raise KeyError(key)
78 79
79 80 self.cache[fil] = (obj,mtime)
80 81 return obj
81 82
82 83 def __setitem__(self,key,value):
83 84 """ db['key'] = 5 """
84 85 fil = self.root / key
85 86 parent = fil.parent
86 87 if parent and not parent.isdir():
87 88 parent.makedirs()
88 89 # We specify protocol 2, so that we can mostly go between Python 2
89 90 # and Python 3. We can upgrade to protocol 3 when Python 2 is obsolete.
90 91 with fil.open('wb') as f:
91 92 pickled = pickle.dump(value, f, protocol=2)
92 93 try:
93 94 self.cache[fil] = (value,fil.mtime)
94 95 except OSError as e:
95 96 if e.errno != 2:
96 97 raise
97 98
98 99 def hset(self, hashroot, key, value):
99 100 """ hashed set """
100 101 hroot = self.root / hashroot
101 102 if not hroot.isdir():
102 103 hroot.makedirs()
103 104 hfile = hroot / gethashfile(key)
104 105 d = self.get(hfile, {})
105 106 d.update( {key : value})
106 107 self[hfile] = d
107 108
108 109
109 110
110 111 def hget(self, hashroot, key, default = _sentinel, fast_only = True):
111 112 """ hashed get """
112 113 hroot = self.root / hashroot
113 114 hfile = hroot / gethashfile(key)
114 115
115 116 d = self.get(hfile, _sentinel )
116 117 #print "got dict",d,"from",hfile
117 118 if d is _sentinel:
118 119 if fast_only:
119 120 if default is _sentinel:
120 121 raise KeyError(key)
121 122
122 123 return default
123 124
124 125 # slow mode ok, works even after hcompress()
125 126 d = self.hdict(hashroot)
126 127
127 128 return d.get(key, default)
128 129
129 130 def hdict(self, hashroot):
130 131 """ Get all data contained in hashed category 'hashroot' as dict """
131 132 hfiles = self.keys(hashroot + "/*")
132 133 hfiles.sort()
133 134 last = len(hfiles) and hfiles[-1] or ''
134 135 if last.endswith('xx'):
135 136 # print "using xx"
136 137 hfiles = [last] + hfiles[:-1]
137 138
138 139 all = {}
139 140
140 141 for f in hfiles:
141 142 # print "using",f
142 143 try:
143 144 all.update(self[f])
144 145 except KeyError:
145 146 print("Corrupt",f,"deleted - hset is not threadsafe!")
146 147 del self[f]
147 148
148 149 self.uncache(f)
149 150
150 151 return all
151 152
152 153 def hcompress(self, hashroot):
153 154 """ Compress category 'hashroot', so hset is fast again
154 155
155 156 hget will fail if fast_only is True for compressed items (that were
156 157 hset before hcompress).
157 158
158 159 """
159 160 hfiles = self.keys(hashroot + "/*")
160 161 all = {}
161 162 for f in hfiles:
162 163 # print "using",f
163 164 all.update(self[f])
164 165 self.uncache(f)
165 166
166 167 self[hashroot + '/xx'] = all
167 168 for f in hfiles:
168 169 p = self.root / f
169 170 if p.basename() == 'xx':
170 171 continue
171 172 p.remove()
172 173
173 174
174 175
175 176 def __delitem__(self,key):
176 177 """ del db["key"] """
177 178 fil = self.root / key
178 179 self.cache.pop(fil,None)
179 180 try:
180 181 fil.remove()
181 182 except OSError:
182 183 # notfound and permission denied are ok - we
183 184 # lost, the other process wins the conflict
184 185 pass
185 186
186 187 def _normalized(self, p):
187 188 """ Make a key suitable for user's eyes """
188 189 return str(self.root.relpathto(p)).replace('\\','/')
189 190
190 191 def keys(self, globpat = None):
191 192 """ All keys in DB, or all keys matching a glob"""
192 193
193 194 if globpat is None:
194 195 files = self.root.walkfiles()
195 196 else:
196 197 files = [Path(p) for p in glob.glob(self.root/globpat)]
197 198 return [self._normalized(p) for p in files if p.isfile()]
198 199
199 200 def __iter__(self):
200 201 return iter(self.keys())
201 202
202 203 def __len__(self):
203 204 return len(self.keys())
204 205
205 206 def uncache(self,*items):
206 207 """ Removes all, or specified items from cache
207 208
208 209 Use this after reading a large amount of large objects
209 210 to free up memory, when you won't be needing the objects
210 211 for a while.
211 212
212 213 """
213 214 if not items:
214 215 self.cache = {}
215 216 for it in items:
216 217 self.cache.pop(it,None)
217 218
218 219 def waitget(self,key, maxwaittime = 60 ):
219 220 """ Wait (poll) for a key to get a value
220 221
221 222 Will wait for `maxwaittime` seconds before raising a KeyError.
222 223 The call exits normally if the `key` field in db gets a value
223 224 within the timeout period.
224 225
225 226 Use this for synchronizing different processes or for ensuring
226 227 that an unfortunately timed "db['key'] = newvalue" operation
227 228 in another process (which causes all 'get' operation to cause a
228 229 KeyError for the duration of pickling) won't screw up your program
229 230 logic.
230 231 """
231 232
232 233 wtimes = [0.2] * 3 + [0.5] * 2 + [1]
233 234 tries = 0
234 235 waited = 0
235 236 while 1:
236 237 try:
237 238 val = self[key]
238 239 return val
239 240 except KeyError:
240 241 pass
241 242
242 243 if waited > maxwaittime:
243 244 raise KeyError(key)
244 245
245 246 time.sleep(wtimes[tries])
246 247 waited+=wtimes[tries]
247 248 if tries < len(wtimes) -1:
248 249 tries+=1
249 250
250 251 def getlink(self,folder):
251 252 """ Get a convenient link for accessing items """
252 253 return PickleShareLink(self, folder)
253 254
254 255 def __repr__(self):
255 256 return "PickleShareDB('%s')" % self.root
256 257
257 258
258 259
259 260 class PickleShareLink:
260 261 """ A shortdand for accessing nested PickleShare data conveniently.
261 262
262 263 Created through PickleShareDB.getlink(), example::
263 264
264 265 lnk = db.getlink('myobjects/test')
265 266 lnk.foo = 2
266 267 lnk.bar = lnk.foo + 5
267 268
268 269 """
269 270 def __init__(self, db, keydir ):
270 271 self.__dict__.update(locals())
271 272
272 273 def __getattr__(self,key):
273 274 return self.__dict__['db'][self.__dict__['keydir']+'/' + key]
274 275 def __setattr__(self,key,val):
275 276 self.db[self.keydir+'/' + key] = val
276 277 def __repr__(self):
277 278 db = self.__dict__['db']
278 279 keys = db.keys( self.__dict__['keydir'] +"/*")
279 280 return "<PickleShareLink '%s': %s>" % (
280 281 self.__dict__['keydir'],
281 282 ";".join([Path(k).basename() for k in keys]))
282 283
283 284 def main():
284 285 import textwrap
285 286 usage = textwrap.dedent("""\
286 287 pickleshare - manage PickleShare databases
287 288
288 289 Usage:
289 290
290 291 pickleshare dump /path/to/db > dump.txt
291 292 pickleshare load /path/to/db < dump.txt
292 293 pickleshare test /path/to/db
293 294 """)
294 295 DB = PickleShareDB
295 296 import sys
296 297 if len(sys.argv) < 2:
297 298 print(usage)
298 299 return
299 300
300 301 cmd = sys.argv[1]
301 302 args = sys.argv[2:]
302 303 if cmd == 'dump':
303 304 if not args: args= ['.']
304 305 db = DB(args[0])
305 306 import pprint
306 307 pprint.pprint(db.items())
307 308 elif cmd == 'load':
308 309 cont = sys.stdin.read()
309 310 db = DB(args[0])
310 311 data = eval(cont)
311 312 db.clear()
312 313 for k,v in db.items():
313 314 db[k] = v
314 315 elif cmd == 'testwait':
315 316 db = DB(args[0])
316 317 db.clear()
317 318 print(db.waitget('250'))
318 319 elif cmd == 'test':
319 320 test()
320 321 stress()
321 322
322 323 if __name__== "__main__":
323 324 main()
324 325
325 326
@@ -1,784 +1,765 b''
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with strings and text.
4 4
5 5 Inheritance diagram:
6 6
7 7 .. inheritance-diagram:: IPython.utils.text
8 8 :parts: 3
9 9 """
10 10
11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2008-2011 The IPython Development Team
13 #
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
16 #-----------------------------------------------------------------------------
17
18 #-----------------------------------------------------------------------------
19 # Imports
20 #-----------------------------------------------------------------------------
21
22 11 import os
23 12 import re
24 13 import sys
25 14 import textwrap
26 15 from string import Formatter
27 16
28 from IPython.external.path import path
29 17 from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest
30 18 from IPython.utils import py3compat
31 19
32 #-----------------------------------------------------------------------------
33 # Declarations
34 #-----------------------------------------------------------------------------
35
36 20 # datetime.strftime date format for ipython
37 21 if sys.platform == 'win32':
38 22 date_format = "%B %d, %Y"
39 23 else:
40 24 date_format = "%B %-d, %Y"
41 25
42
43 #-----------------------------------------------------------------------------
44 # Code
45 #-----------------------------------------------------------------------------
46
47 26 class LSString(str):
48 27 """String derivative with a special access attributes.
49 28
50 29 These are normal strings, but with the special attributes:
51 30
52 31 .l (or .list) : value as list (split on newlines).
53 32 .n (or .nlstr): original value (the string itself).
54 33 .s (or .spstr): value as whitespace-separated string.
55 .p (or .paths): list of path objects
34 .p (or .paths): list of path objects (requires path.py package)
56 35
57 36 Any values which require transformations are computed only once and
58 37 cached.
59 38
60 39 Such strings are very useful to efficiently interact with the shell, which
61 40 typically only understands whitespace-separated options for commands."""
62 41
63 42 def get_list(self):
64 43 try:
65 44 return self.__list
66 45 except AttributeError:
67 46 self.__list = self.split('\n')
68 47 return self.__list
69 48
70 49 l = list = property(get_list)
71 50
72 51 def get_spstr(self):
73 52 try:
74 53 return self.__spstr
75 54 except AttributeError:
76 55 self.__spstr = self.replace('\n',' ')
77 56 return self.__spstr
78 57
79 58 s = spstr = property(get_spstr)
80 59
81 60 def get_nlstr(self):
82 61 return self
83 62
84 63 n = nlstr = property(get_nlstr)
85 64
86 65 def get_paths(self):
66 from path import path
87 67 try:
88 68 return self.__paths
89 69 except AttributeError:
90 70 self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)]
91 71 return self.__paths
92 72
93 73 p = paths = property(get_paths)
94 74
95 75 # FIXME: We need to reimplement type specific displayhook and then add this
96 76 # back as a custom printer. This should also be moved outside utils into the
97 77 # core.
98 78
99 79 # def print_lsstring(arg):
100 80 # """ Prettier (non-repr-like) and more informative printer for LSString """
101 81 # print "LSString (.p, .n, .l, .s available). Value:"
102 82 # print arg
103 83 #
104 84 #
105 85 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
106 86
107 87
108 88 class SList(list):
109 89 """List derivative with a special access attributes.
110 90
111 91 These are normal lists, but with the special attributes:
112 92
113 93 * .l (or .list) : value as list (the list itself).
114 94 * .n (or .nlstr): value as a string, joined on newlines.
115 95 * .s (or .spstr): value as a string, joined on spaces.
116 * .p (or .paths): list of path objects
96 * .p (or .paths): list of path objects (requires path.py package)
117 97
118 98 Any values which require transformations are computed only once and
119 99 cached."""
120 100
121 101 def get_list(self):
122 102 return self
123 103
124 104 l = list = property(get_list)
125 105
126 106 def get_spstr(self):
127 107 try:
128 108 return self.__spstr
129 109 except AttributeError:
130 110 self.__spstr = ' '.join(self)
131 111 return self.__spstr
132 112
133 113 s = spstr = property(get_spstr)
134 114
135 115 def get_nlstr(self):
136 116 try:
137 117 return self.__nlstr
138 118 except AttributeError:
139 119 self.__nlstr = '\n'.join(self)
140 120 return self.__nlstr
141 121
142 122 n = nlstr = property(get_nlstr)
143 123
144 124 def get_paths(self):
125 from path import path
145 126 try:
146 127 return self.__paths
147 128 except AttributeError:
148 129 self.__paths = [path(p) for p in self if os.path.exists(p)]
149 130 return self.__paths
150 131
151 132 p = paths = property(get_paths)
152 133
153 134 def grep(self, pattern, prune = False, field = None):
154 135 """ Return all strings matching 'pattern' (a regex or callable)
155 136
156 137 This is case-insensitive. If prune is true, return all items
157 138 NOT matching the pattern.
158 139
159 140 If field is specified, the match must occur in the specified
160 141 whitespace-separated field.
161 142
162 143 Examples::
163 144
164 145 a.grep( lambda x: x.startswith('C') )
165 146 a.grep('Cha.*log', prune=1)
166 147 a.grep('chm', field=-1)
167 148 """
168 149
169 150 def match_target(s):
170 151 if field is None:
171 152 return s
172 153 parts = s.split()
173 154 try:
174 155 tgt = parts[field]
175 156 return tgt
176 157 except IndexError:
177 158 return ""
178 159
179 160 if isinstance(pattern, py3compat.string_types):
180 161 pred = lambda x : re.search(pattern, x, re.IGNORECASE)
181 162 else:
182 163 pred = pattern
183 164 if not prune:
184 165 return SList([el for el in self if pred(match_target(el))])
185 166 else:
186 167 return SList([el for el in self if not pred(match_target(el))])
187 168
188 169 def fields(self, *fields):
189 170 """ Collect whitespace-separated fields from string list
190 171
191 172 Allows quick awk-like usage of string lists.
192 173
193 174 Example data (in var a, created by 'a = !ls -l')::
194 175
195 176 -rwxrwxrwx 1 ville None 18 Dec 14 2006 ChangeLog
196 177 drwxrwxrwx+ 6 ville None 0 Oct 24 18:05 IPython
197 178
198 179 * ``a.fields(0)`` is ``['-rwxrwxrwx', 'drwxrwxrwx+']``
199 180 * ``a.fields(1,0)`` is ``['1 -rwxrwxrwx', '6 drwxrwxrwx+']``
200 181 (note the joining by space).
201 182 * ``a.fields(-1)`` is ``['ChangeLog', 'IPython']``
202 183
203 184 IndexErrors are ignored.
204 185
205 186 Without args, fields() just split()'s the strings.
206 187 """
207 188 if len(fields) == 0:
208 189 return [el.split() for el in self]
209 190
210 191 res = SList()
211 192 for el in [f.split() for f in self]:
212 193 lineparts = []
213 194
214 195 for fd in fields:
215 196 try:
216 197 lineparts.append(el[fd])
217 198 except IndexError:
218 199 pass
219 200 if lineparts:
220 201 res.append(" ".join(lineparts))
221 202
222 203 return res
223 204
224 205 def sort(self,field= None, nums = False):
225 206 """ sort by specified fields (see fields())
226 207
227 208 Example::
228 209
229 210 a.sort(1, nums = True)
230 211
231 212 Sorts a by second field, in numerical order (so that 21 > 3)
232 213
233 214 """
234 215
235 216 #decorate, sort, undecorate
236 217 if field is not None:
237 218 dsu = [[SList([line]).fields(field), line] for line in self]
238 219 else:
239 220 dsu = [[line, line] for line in self]
240 221 if nums:
241 222 for i in range(len(dsu)):
242 223 numstr = "".join([ch for ch in dsu[i][0] if ch.isdigit()])
243 224 try:
244 225 n = int(numstr)
245 226 except ValueError:
246 227 n = 0;
247 228 dsu[i][0] = n
248 229
249 230
250 231 dsu.sort()
251 232 return SList([t[1] for t in dsu])
252 233
253 234
254 235 # FIXME: We need to reimplement type specific displayhook and then add this
255 236 # back as a custom printer. This should also be moved outside utils into the
256 237 # core.
257 238
258 239 # def print_slist(arg):
259 240 # """ Prettier (non-repr-like) and more informative printer for SList """
260 241 # print "SList (.p, .n, .l, .s, .grep(), .fields(), sort() available):"
261 242 # if hasattr(arg, 'hideonce') and arg.hideonce:
262 243 # arg.hideonce = False
263 244 # return
264 245 #
265 246 # nlprint(arg) # This was a nested list printer, now removed.
266 247 #
267 248 # print_slist = result_display.when_type(SList)(print_slist)
268 249
269 250
270 251 def indent(instr,nspaces=4, ntabs=0, flatten=False):
271 252 """Indent a string a given number of spaces or tabstops.
272 253
273 254 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
274 255
275 256 Parameters
276 257 ----------
277 258
278 259 instr : basestring
279 260 The string to be indented.
280 261 nspaces : int (default: 4)
281 262 The number of spaces to be indented.
282 263 ntabs : int (default: 0)
283 264 The number of tabs to be indented.
284 265 flatten : bool (default: False)
285 266 Whether to scrub existing indentation. If True, all lines will be
286 267 aligned to the same indentation. If False, existing indentation will
287 268 be strictly increased.
288 269
289 270 Returns
290 271 -------
291 272
292 273 str|unicode : string indented by ntabs and nspaces.
293 274
294 275 """
295 276 if instr is None:
296 277 return
297 278 ind = '\t'*ntabs+' '*nspaces
298 279 if flatten:
299 280 pat = re.compile(r'^\s*', re.MULTILINE)
300 281 else:
301 282 pat = re.compile(r'^', re.MULTILINE)
302 283 outstr = re.sub(pat, ind, instr)
303 284 if outstr.endswith(os.linesep+ind):
304 285 return outstr[:-len(ind)]
305 286 else:
306 287 return outstr
307 288
308 289
309 290 def list_strings(arg):
310 291 """Always return a list of strings, given a string or list of strings
311 292 as input.
312 293
313 294 Examples
314 295 --------
315 296 ::
316 297
317 298 In [7]: list_strings('A single string')
318 299 Out[7]: ['A single string']
319 300
320 301 In [8]: list_strings(['A single string in a list'])
321 302 Out[8]: ['A single string in a list']
322 303
323 304 In [9]: list_strings(['A','list','of','strings'])
324 305 Out[9]: ['A', 'list', 'of', 'strings']
325 306 """
326 307
327 308 if isinstance(arg, py3compat.string_types): return [arg]
328 309 else: return arg
329 310
330 311
331 312 def marquee(txt='',width=78,mark='*'):
332 313 """Return the input string centered in a 'marquee'.
333 314
334 315 Examples
335 316 --------
336 317 ::
337 318
338 319 In [16]: marquee('A test',40)
339 320 Out[16]: '**************** A test ****************'
340 321
341 322 In [17]: marquee('A test',40,'-')
342 323 Out[17]: '---------------- A test ----------------'
343 324
344 325 In [18]: marquee('A test',40,' ')
345 326 Out[18]: ' A test '
346 327
347 328 """
348 329 if not txt:
349 330 return (mark*width)[:width]
350 331 nmark = (width-len(txt)-2)//len(mark)//2
351 332 if nmark < 0: nmark =0
352 333 marks = mark*nmark
353 334 return '%s %s %s' % (marks,txt,marks)
354 335
355 336
356 337 ini_spaces_re = re.compile(r'^(\s+)')
357 338
358 339 def num_ini_spaces(strng):
359 340 """Return the number of initial spaces in a string"""
360 341
361 342 ini_spaces = ini_spaces_re.match(strng)
362 343 if ini_spaces:
363 344 return ini_spaces.end()
364 345 else:
365 346 return 0
366 347
367 348
368 349 def format_screen(strng):
369 350 """Format a string for screen printing.
370 351
371 352 This removes some latex-type format codes."""
372 353 # Paragraph continue
373 354 par_re = re.compile(r'\\$',re.MULTILINE)
374 355 strng = par_re.sub('',strng)
375 356 return strng
376 357
377 358
378 359 def dedent(text):
379 360 """Equivalent of textwrap.dedent that ignores unindented first line.
380 361
381 362 This means it will still dedent strings like:
382 363 '''foo
383 364 is a bar
384 365 '''
385 366
386 367 For use in wrap_paragraphs.
387 368 """
388 369
389 370 if text.startswith('\n'):
390 371 # text starts with blank line, don't ignore the first line
391 372 return textwrap.dedent(text)
392 373
393 374 # split first line
394 375 splits = text.split('\n',1)
395 376 if len(splits) == 1:
396 377 # only one line
397 378 return textwrap.dedent(text)
398 379
399 380 first, rest = splits
400 381 # dedent everything but the first line
401 382 rest = textwrap.dedent(rest)
402 383 return '\n'.join([first, rest])
403 384
404 385
405 386 def wrap_paragraphs(text, ncols=80):
406 387 """Wrap multiple paragraphs to fit a specified width.
407 388
408 389 This is equivalent to textwrap.wrap, but with support for multiple
409 390 paragraphs, as separated by empty lines.
410 391
411 392 Returns
412 393 -------
413 394
414 395 list of complete paragraphs, wrapped to fill `ncols` columns.
415 396 """
416 397 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
417 398 text = dedent(text).strip()
418 399 paragraphs = paragraph_re.split(text)[::2] # every other entry is space
419 400 out_ps = []
420 401 indent_re = re.compile(r'\n\s+', re.MULTILINE)
421 402 for p in paragraphs:
422 403 # presume indentation that survives dedent is meaningful formatting,
423 404 # so don't fill unless text is flush.
424 405 if indent_re.search(p) is None:
425 406 # wrap paragraph
426 407 p = textwrap.fill(p, ncols)
427 408 out_ps.append(p)
428 409 return out_ps
429 410
430 411
431 412 def long_substr(data):
432 413 """Return the longest common substring in a list of strings.
433 414
434 415 Credit: http://stackoverflow.com/questions/2892931/longest-common-substring-from-more-than-two-strings-python
435 416 """
436 417 substr = ''
437 418 if len(data) > 1 and len(data[0]) > 0:
438 419 for i in range(len(data[0])):
439 420 for j in range(len(data[0])-i+1):
440 421 if j > len(substr) and all(data[0][i:i+j] in x for x in data):
441 422 substr = data[0][i:i+j]
442 423 elif len(data) == 1:
443 424 substr = data[0]
444 425 return substr
445 426
446 427
447 428 def strip_email_quotes(text):
448 429 """Strip leading email quotation characters ('>').
449 430
450 431 Removes any combination of leading '>' interspersed with whitespace that
451 432 appears *identically* in all lines of the input text.
452 433
453 434 Parameters
454 435 ----------
455 436 text : str
456 437
457 438 Examples
458 439 --------
459 440
460 441 Simple uses::
461 442
462 443 In [2]: strip_email_quotes('> > text')
463 444 Out[2]: 'text'
464 445
465 446 In [3]: strip_email_quotes('> > text\\n> > more')
466 447 Out[3]: 'text\\nmore'
467 448
468 449 Note how only the common prefix that appears in all lines is stripped::
469 450
470 451 In [4]: strip_email_quotes('> > text\\n> > more\\n> more...')
471 452 Out[4]: '> text\\n> more\\nmore...'
472 453
473 454 So if any line has no quote marks ('>') , then none are stripped from any
474 455 of them ::
475 456
476 457 In [5]: strip_email_quotes('> > text\\n> > more\\nlast different')
477 458 Out[5]: '> > text\\n> > more\\nlast different'
478 459 """
479 460 lines = text.splitlines()
480 461 matches = set()
481 462 for line in lines:
482 463 prefix = re.match(r'^(\s*>[ >]*)', line)
483 464 if prefix:
484 465 matches.add(prefix.group(1))
485 466 else:
486 467 break
487 468 else:
488 469 prefix = long_substr(list(matches))
489 470 if prefix:
490 471 strip = len(prefix)
491 472 text = '\n'.join([ ln[strip:] for ln in lines])
492 473 return text
493 474
494 475 def strip_ansi(source):
495 476 """
496 477 Remove ansi escape codes from text.
497 478
498 479 Parameters
499 480 ----------
500 481 source : str
501 482 Source to remove the ansi from
502 483 """
503 484 return re.sub(r'\033\[(\d|;)+?m', '', source)
504 485
505 486
506 487 class EvalFormatter(Formatter):
507 488 """A String Formatter that allows evaluation of simple expressions.
508 489
509 490 Note that this version interprets a : as specifying a format string (as per
510 491 standard string formatting), so if slicing is required, you must explicitly
511 492 create a slice.
512 493
513 494 This is to be used in templating cases, such as the parallel batch
514 495 script templates, where simple arithmetic on arguments is useful.
515 496
516 497 Examples
517 498 --------
518 499 ::
519 500
520 501 In [1]: f = EvalFormatter()
521 502 In [2]: f.format('{n//4}', n=8)
522 503 Out[2]: '2'
523 504
524 505 In [3]: f.format("{greeting[slice(2,4)]}", greeting="Hello")
525 506 Out[3]: 'll'
526 507 """
527 508 def get_field(self, name, args, kwargs):
528 509 v = eval(name, kwargs)
529 510 return v, name
530 511
531 512 #XXX: As of Python 3.4, the format string parsing no longer splits on a colon
532 513 # inside [], so EvalFormatter can handle slicing. Once we only support 3.4 and
533 514 # above, it should be possible to remove FullEvalFormatter.
534 515
535 516 @skip_doctest_py3
536 517 class FullEvalFormatter(Formatter):
537 518 """A String Formatter that allows evaluation of simple expressions.
538 519
539 520 Any time a format key is not found in the kwargs,
540 521 it will be tried as an expression in the kwargs namespace.
541 522
542 523 Note that this version allows slicing using [1:2], so you cannot specify
543 524 a format string. Use :class:`EvalFormatter` to permit format strings.
544 525
545 526 Examples
546 527 --------
547 528 ::
548 529
549 530 In [1]: f = FullEvalFormatter()
550 531 In [2]: f.format('{n//4}', n=8)
551 532 Out[2]: u'2'
552 533
553 534 In [3]: f.format('{list(range(5))[2:4]}')
554 535 Out[3]: u'[2, 3]'
555 536
556 537 In [4]: f.format('{3*2}')
557 538 Out[4]: u'6'
558 539 """
559 540 # copied from Formatter._vformat with minor changes to allow eval
560 541 # and replace the format_spec code with slicing
561 542 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
562 543 if recursion_depth < 0:
563 544 raise ValueError('Max string recursion exceeded')
564 545 result = []
565 546 for literal_text, field_name, format_spec, conversion in \
566 547 self.parse(format_string):
567 548
568 549 # output the literal text
569 550 if literal_text:
570 551 result.append(literal_text)
571 552
572 553 # if there's a field, output it
573 554 if field_name is not None:
574 555 # this is some markup, find the object and do
575 556 # the formatting
576 557
577 558 if format_spec:
578 559 # override format spec, to allow slicing:
579 560 field_name = ':'.join([field_name, format_spec])
580 561
581 562 # eval the contents of the field for the object
582 563 # to be formatted
583 564 obj = eval(field_name, kwargs)
584 565
585 566 # do any conversion on the resulting object
586 567 obj = self.convert_field(obj, conversion)
587 568
588 569 # format the object and append to the result
589 570 result.append(self.format_field(obj, ''))
590 571
591 572 return u''.join(py3compat.cast_unicode(s) for s in result)
592 573
593 574
594 575 @skip_doctest_py3
595 576 class DollarFormatter(FullEvalFormatter):
596 577 """Formatter allowing Itpl style $foo replacement, for names and attribute
597 578 access only. Standard {foo} replacement also works, and allows full
598 579 evaluation of its arguments.
599 580
600 581 Examples
601 582 --------
602 583 ::
603 584
604 585 In [1]: f = DollarFormatter()
605 586 In [2]: f.format('{n//4}', n=8)
606 587 Out[2]: u'2'
607 588
608 589 In [3]: f.format('23 * 76 is $result', result=23*76)
609 590 Out[3]: u'23 * 76 is 1748'
610 591
611 592 In [4]: f.format('$a or {b}', a=1, b=2)
612 593 Out[4]: u'1 or 2'
613 594 """
614 595 _dollar_pattern = re.compile("(.*?)\$(\$?[\w\.]+)")
615 596 def parse(self, fmt_string):
616 597 for literal_txt, field_name, format_spec, conversion \
617 598 in Formatter.parse(self, fmt_string):
618 599
619 600 # Find $foo patterns in the literal text.
620 601 continue_from = 0
621 602 txt = ""
622 603 for m in self._dollar_pattern.finditer(literal_txt):
623 604 new_txt, new_field = m.group(1,2)
624 605 # $$foo --> $foo
625 606 if new_field.startswith("$"):
626 607 txt += new_txt + new_field
627 608 else:
628 609 yield (txt + new_txt, new_field, "", None)
629 610 txt = ""
630 611 continue_from = m.end()
631 612
632 613 # Re-yield the {foo} style pattern
633 614 yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion)
634 615
635 616 #-----------------------------------------------------------------------------
636 617 # Utils to columnize a list of string
637 618 #-----------------------------------------------------------------------------
638 619
639 620 def _chunks(l, n):
640 621 """Yield successive n-sized chunks from l."""
641 622 for i in py3compat.xrange(0, len(l), n):
642 623 yield l[i:i+n]
643 624
644 625
645 626 def _find_optimal(rlist , separator_size=2 , displaywidth=80):
646 627 """Calculate optimal info to columnize a list of string"""
647 628 for nrow in range(1, len(rlist)+1) :
648 629 chk = list(map(max,_chunks(rlist, nrow)))
649 630 sumlength = sum(chk)
650 631 ncols = len(chk)
651 632 if sumlength+separator_size*(ncols-1) <= displaywidth :
652 633 break;
653 634 return {'columns_numbers' : ncols,
654 635 'optimal_separator_width':(displaywidth - sumlength)/(ncols-1) if (ncols -1) else 0,
655 636 'rows_numbers' : nrow,
656 637 'columns_width' : chk
657 638 }
658 639
659 640
660 641 def _get_or_default(mylist, i, default=None):
661 642 """return list item number, or default if don't exist"""
662 643 if i >= len(mylist):
663 644 return default
664 645 else :
665 646 return mylist[i]
666 647
667 648
668 649 @skip_doctest
669 650 def compute_item_matrix(items, empty=None, *args, **kwargs) :
670 651 """Returns a nested list, and info to columnize items
671 652
672 653 Parameters
673 654 ----------
674 655
675 656 items
676 657 list of strings to columize
677 658 empty : (default None)
678 659 default value to fill list if needed
679 660 separator_size : int (default=2)
680 661 How much caracters will be used as a separation between each columns.
681 662 displaywidth : int (default=80)
682 663 The width of the area onto wich the columns should enter
683 664
684 665 Returns
685 666 -------
686 667
687 668 strings_matrix
688 669
689 670 nested list of string, the outer most list contains as many list as
690 671 rows, the innermost lists have each as many element as colums. If the
691 672 total number of elements in `items` does not equal the product of
692 673 rows*columns, the last element of some lists are filled with `None`.
693 674
694 675 dict_info
695 676 some info to make columnize easier:
696 677
697 678 columns_numbers
698 679 number of columns
699 680 rows_numbers
700 681 number of rows
701 682 columns_width
702 683 list of with of each columns
703 684 optimal_separator_width
704 685 best separator width between columns
705 686
706 687 Examples
707 688 --------
708 689 ::
709 690
710 691 In [1]: l = ['aaa','b','cc','d','eeeee','f','g','h','i','j','k','l']
711 692 ...: compute_item_matrix(l,displaywidth=12)
712 693 Out[1]:
713 694 ([['aaa', 'f', 'k'],
714 695 ['b', 'g', 'l'],
715 696 ['cc', 'h', None],
716 697 ['d', 'i', None],
717 698 ['eeeee', 'j', None]],
718 699 {'columns_numbers': 3,
719 700 'columns_width': [5, 1, 1],
720 701 'optimal_separator_width': 2,
721 702 'rows_numbers': 5})
722 703 """
723 704 info = _find_optimal(list(map(len, items)), *args, **kwargs)
724 705 nrow, ncol = info['rows_numbers'], info['columns_numbers']
725 706 return ([[ _get_or_default(items, c*nrow+i, default=empty) for c in range(ncol) ] for i in range(nrow) ], info)
726 707
727 708
728 709 def columnize(items, separator=' ', displaywidth=80):
729 710 """ Transform a list of strings into a single string with columns.
730 711
731 712 Parameters
732 713 ----------
733 714 items : sequence of strings
734 715 The strings to process.
735 716
736 717 separator : str, optional [default is two spaces]
737 718 The string that separates columns.
738 719
739 720 displaywidth : int, optional [default is 80]
740 721 Width of the display in number of characters.
741 722
742 723 Returns
743 724 -------
744 725 The formatted string.
745 726 """
746 727 if not items :
747 728 return '\n'
748 729 matrix, info = compute_item_matrix(items, separator_size=len(separator), displaywidth=displaywidth)
749 730 fmatrix = [filter(None, x) for x in matrix]
750 731 sjoin = lambda x : separator.join([ y.ljust(w, ' ') for y, w in zip(x, info['columns_width'])])
751 732 return '\n'.join(map(sjoin, fmatrix))+'\n'
752 733
753 734
754 735 def get_text_list(list_, last_sep=' and ', sep=", ", wrap_item_with=""):
755 736 """
756 737 Return a string with a natural enumeration of items
757 738
758 739 >>> get_text_list(['a', 'b', 'c', 'd'])
759 740 'a, b, c and d'
760 741 >>> get_text_list(['a', 'b', 'c'], ' or ')
761 742 'a, b or c'
762 743 >>> get_text_list(['a', 'b', 'c'], ', ')
763 744 'a, b, c'
764 745 >>> get_text_list(['a', 'b'], ' or ')
765 746 'a or b'
766 747 >>> get_text_list(['a'])
767 748 'a'
768 749 >>> get_text_list([])
769 750 ''
770 751 >>> get_text_list(['a', 'b'], wrap_item_with="`")
771 752 '`a` and `b`'
772 753 >>> get_text_list(['a', 'b', 'c', 'd'], " = ", sep=" + ")
773 754 'a + b + c = d'
774 755 """
775 756 if len(list_) == 0:
776 757 return ''
777 758 if wrap_item_with:
778 759 list_ = ['%s%s%s' % (wrap_item_with, item, wrap_item_with) for
779 760 item in list_]
780 761 if len(list_) == 1:
781 762 return list_[0]
782 763 return '%s%s%s' % (
783 764 sep.join(i for i in list_[:-1]),
784 765 last_sep, list_[-1]) No newline at end of file
@@ -1,342 +1,344 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 66 check_for_dependencies,
67 67 git_prebuild,
68 68 check_submodule_status,
69 69 update_submodules,
70 70 require_submodules,
71 71 UpdateSubmodules,
72 72 get_bdist_wheel,
73 73 CompileCSS,
74 74 JavascriptVersion,
75 75 css_js_prerelease,
76 76 install_symlinked,
77 77 install_lib_symlink,
78 78 install_scripts_for_symlink,
79 79 unsymlink,
80 80 )
81 81 from setupext import setupext
82 82
83 83 isfile = os.path.isfile
84 84 pjoin = os.path.join
85 85
86 86 #-------------------------------------------------------------------------------
87 87 # Handle OS specific things
88 88 #-------------------------------------------------------------------------------
89 89
90 90 if os.name in ('nt','dos'):
91 91 os_name = 'windows'
92 92 else:
93 93 os_name = os.name
94 94
95 95 # Under Windows, 'sdist' has not been supported. Now that the docs build with
96 96 # Sphinx it might work, but let's not turn it on until someone confirms that it
97 97 # actually works.
98 98 if os_name == 'windows' and 'sdist' in sys.argv:
99 99 print('The sdist command is not available under Windows. Exiting.')
100 100 sys.exit(1)
101 101
102 102 #-------------------------------------------------------------------------------
103 103 # Make sure we aren't trying to run without submodules
104 104 #-------------------------------------------------------------------------------
105 105 here = os.path.abspath(os.path.dirname(__file__))
106 106
107 107 def require_clean_submodules():
108 108 """Check on git submodules before distutils can do anything
109 109
110 110 Since distutils cannot be trusted to update the tree
111 111 after everything has been set in motion,
112 112 this is not a distutils command.
113 113 """
114 114 # PACKAGERS: Add a return here to skip checks for git submodules
115 115
116 116 # don't do anything if nothing is actually supposed to happen
117 117 for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'):
118 118 if do_nothing in sys.argv:
119 119 return
120 120
121 121 status = check_submodule_status(here)
122 122
123 123 if status == "missing":
124 124 print("checking out submodules for the first time")
125 125 update_submodules(here)
126 126 elif status == "unclean":
127 127 print('\n'.join([
128 128 "Cannot build / install IPython with unclean submodules",
129 129 "Please update submodules with",
130 130 " python setup.py submodule",
131 131 "or",
132 132 " git submodule update",
133 133 "or commit any submodule changes you have made."
134 134 ]))
135 135 sys.exit(1)
136 136
137 137 require_clean_submodules()
138 138
139 139 #-------------------------------------------------------------------------------
140 140 # Things related to the IPython documentation
141 141 #-------------------------------------------------------------------------------
142 142
143 143 # update the manuals when building a source dist
144 144 if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):
145 145
146 146 # List of things to be updated. Each entry is a triplet of args for
147 147 # target_update()
148 148 to_update = [
149 149 # FIXME - Disabled for now: we need to redo an automatic way
150 150 # of generating the magic info inside the rst.
151 151 #('docs/magic.tex',
152 152 #['IPython/Magic.py'],
153 153 #"cd doc && ./update_magic.sh" ),
154 154
155 155 ('docs/man/ipcluster.1.gz',
156 156 ['docs/man/ipcluster.1'],
157 157 'cd docs/man && gzip -9c ipcluster.1 > ipcluster.1.gz'),
158 158
159 159 ('docs/man/ipcontroller.1.gz',
160 160 ['docs/man/ipcontroller.1'],
161 161 'cd docs/man && gzip -9c ipcontroller.1 > ipcontroller.1.gz'),
162 162
163 163 ('docs/man/ipengine.1.gz',
164 164 ['docs/man/ipengine.1'],
165 165 'cd docs/man && gzip -9c ipengine.1 > ipengine.1.gz'),
166 166
167 167 ('docs/man/ipython.1.gz',
168 168 ['docs/man/ipython.1'],
169 169 'cd docs/man && gzip -9c ipython.1 > ipython.1.gz'),
170 170
171 171 ]
172 172
173 173
174 174 [ target_update(*t) for t in to_update ]
175 175
176 176 #---------------------------------------------------------------------------
177 177 # Find all the packages, package data, and data_files
178 178 #---------------------------------------------------------------------------
179 179
180 180 packages = find_packages()
181 181 package_data = find_package_data()
182 182
183 183 data_files = find_data_files()
184 184
185 185 setup_args['packages'] = packages
186 186 setup_args['package_data'] = package_data
187 187 setup_args['data_files'] = data_files
188 188
189 189 #---------------------------------------------------------------------------
190 190 # custom distutils commands
191 191 #---------------------------------------------------------------------------
192 192 # imports here, so they are after setuptools import if there was one
193 193 from distutils.command.sdist import sdist
194 194 from distutils.command.upload import upload
195 195
196 196 class UploadWindowsInstallers(upload):
197 197
198 198 description = "Upload Windows installers to PyPI (only used from tools/release_windows.py)"
199 199 user_options = upload.user_options + [
200 200 ('files=', 'f', 'exe file (or glob) to upload')
201 201 ]
202 202 def initialize_options(self):
203 203 upload.initialize_options(self)
204 204 meta = self.distribution.metadata
205 205 base = '{name}-{version}'.format(
206 206 name=meta.get_name(),
207 207 version=meta.get_version()
208 208 )
209 209 self.files = os.path.join('dist', '%s.*.exe' % base)
210 210
211 211 def run(self):
212 212 for dist_file in glob(self.files):
213 213 self.upload_file('bdist_wininst', 'any', dist_file)
214 214
215 215 setup_args['cmdclass'] = {
216 216 'build_py': css_js_prerelease(
217 217 check_package_data_first(git_prebuild('IPython'))),
218 218 'sdist' : css_js_prerelease(git_prebuild('IPython', sdist)),
219 219 'upload_wininst' : UploadWindowsInstallers,
220 220 'submodule' : UpdateSubmodules,
221 221 'css' : CompileCSS,
222 222 'symlink': install_symlinked,
223 223 'install_lib_symlink': install_lib_symlink,
224 224 'install_scripts_sym': install_scripts_for_symlink,
225 225 'unsymlink': unsymlink,
226 226 'jsversion' : JavascriptVersion,
227 227 }
228 228
229 229 #---------------------------------------------------------------------------
230 230 # Handle scripts, dependencies, and setuptools specific things
231 231 #---------------------------------------------------------------------------
232 232
233 233 # For some commands, use setuptools. Note that we do NOT list install here!
234 234 # If you want a setuptools-enhanced install, just run 'setupegg.py install'
235 235 needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm',
236 236 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel',
237 237 'egg_info', 'easy_install', 'upload', 'install_egg_info',
238 238 ))
239 239
240 240 if len(needs_setuptools.intersection(sys.argv)) > 0:
241 241 import setuptools
242 242
243 243 # This dict is used for passing extra arguments that are setuptools
244 244 # specific to setup
245 245 setuptools_extra_args = {}
246 246
247 247 # setuptools requirements
248 248
249 249 pyzmq = 'pyzmq>=13'
250 250
251 251 extras_require = dict(
252 252 parallel = [pyzmq],
253 253 qtconsole = [pyzmq, 'pygments'],
254 254 doc = ['Sphinx>=1.1', 'numpydoc'],
255 255 test = ['nose>=0.10.1', 'requests'],
256 256 terminal = [],
257 257 nbformat = ['jsonschema>=2.0'],
258 258 notebook = ['tornado>=4.0', pyzmq, 'jinja2', 'pygments', 'mistune>=0.5'],
259 259 nbconvert = ['pygments', 'jinja2', 'mistune>=0.3.1']
260 260 )
261 261
262 262 if not sys.platform.startswith('win'):
263 263 extras_require['notebook'].append('terminado>=0.3.3')
264 264
265 265 if sys.version_info < (3, 3):
266 266 extras_require['test'].append('mock')
267 267
268 268 extras_require['notebook'].extend(extras_require['nbformat'])
269 269 extras_require['nbconvert'].extend(extras_require['nbformat'])
270 270
271 install_requires = []
271 install_requires = [
272 'path.py', # required by pickleshare, remove when pickleshare is added here
273 ]
272 274
273 275 # add readline
274 276 if sys.platform == 'darwin':
275 277 if 'bdist_wheel' in sys.argv[1:] or not setupext.check_for_readline():
276 278 install_requires.append('gnureadline')
277 279 elif sys.platform.startswith('win'):
278 280 extras_require['terminal'].append('pyreadline>=2.0')
279 281
280 282 everything = set()
281 283 for deps in extras_require.values():
282 284 everything.update(deps)
283 285 extras_require['all'] = everything
284 286
285 287 if 'setuptools' in sys.modules:
286 288 # setup.py develop should check for submodules
287 289 from setuptools.command.develop import develop
288 290 setup_args['cmdclass']['develop'] = require_submodules(develop)
289 291 setup_args['cmdclass']['bdist_wheel'] = css_js_prerelease(get_bdist_wheel())
290 292
291 293 setuptools_extra_args['zip_safe'] = False
292 294 setuptools_extra_args['entry_points'] = {
293 295 'console_scripts': find_entry_points(),
294 296 'pygments.lexers': [
295 297 'ipythonconsole = IPython.lib.lexers:IPythonConsoleLexer',
296 298 'ipython = IPython.lib.lexers:IPythonLexer',
297 299 'ipython3 = IPython.lib.lexers:IPython3Lexer',
298 300 ],
299 301 }
300 302 setup_args['extras_require'] = extras_require
301 303 requires = setup_args['install_requires'] = install_requires
302 304
303 305 # Script to be run by the windows binary installer after the default setup
304 306 # routine, to add shortcuts and similar windows-only things. Windows
305 307 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
306 308 # doesn't find them.
307 309 if 'bdist_wininst' in sys.argv:
308 310 if len(sys.argv) > 2 and \
309 311 ('sdist' in sys.argv or 'bdist_rpm' in sys.argv):
310 312 print("ERROR: bdist_wininst must be run alone. Exiting.", file=sys.stderr)
311 313 sys.exit(1)
312 314 setup_args['data_files'].append(
313 315 ['Scripts', ('scripts/ipython.ico', 'scripts/ipython_nb.ico')])
314 316 setup_args['scripts'] = [pjoin('scripts','ipython_win_post_install.py')]
315 317 setup_args['options'] = {"bdist_wininst":
316 318 {"install_script":
317 319 "ipython_win_post_install.py"}}
318 320
319 321 else:
320 322 # If we are installing without setuptools, call this function which will
321 323 # check for dependencies an inform the user what is needed. This is
322 324 # just to make life easy for users.
323 325 for install_cmd in ('install', 'symlink'):
324 326 if install_cmd in sys.argv:
325 327 check_for_dependencies()
326 328 break
327 329 # scripts has to be a non-empty list, or install_scripts isn't called
328 330 setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()]
329 331
330 332 setup_args['cmdclass']['build_scripts'] = build_scripts_entrypt
331 333
332 334 #---------------------------------------------------------------------------
333 335 # Do the actual setup now
334 336 #---------------------------------------------------------------------------
335 337
336 338 setup_args.update(setuptools_extra_args)
337 339
338 340 def main():
339 341 setup(**setup_args)
340 342
341 343 if __name__ == '__main__':
342 344 main()
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (1267 lines changed) Show them Hide them
General Comments 0
You need to be logged in to leave comments. Login now