##// END OF EJS Templates
Merging (slightly modified) Tom Fetherston's demo branch....
Fernando Perez -
r2102:d3a059eb merge
parent child Browse files
Show More
@@ -0,0 +1,85 b''
1 """This is meant to be run from the IPython prompt:
2
3 %run demo-exercizer.py
4
5 It will create demo objects of the example that is embedded in demo.py in a
6 number of ways and allow you to see how they work, just follow the printed
7 directions."""
8
9 #-----------------------------------------------------------------------------
10 # Imports
11 #-----------------------------------------------------------------------------
12
13 # From std lib
14 import StringIO
15 import os
16 import shutil
17 import tempfile
18
19 # From IPython
20 from IPython.demo import (Demo, IPythonDemo, LineDemo, IPythonLineDemo,
21 ClearDemo, ClearIPDemo)
22
23 #-----------------------------------------------------------------------------
24 # Demo code
25 #-----------------------------------------------------------------------------
26
27 example1 = """
28 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
29
30 print 'Hello, welcome to an interactive IPython demo.'
31
32 # The mark below defines a block boundary, which is a point where IPython will
33 # stop execution and return to the interactive prompt. The dashes are actually
34 # optional and used only as a visual aid to clearly separate blocks while
35 # editing the demo code.
36 # <demo> stop
37
38 x = 1
39 y = 2
40
41 # <demo> stop
42
43 # the mark below makes this block as silent
44 # <demo> silent
45
46 print 'This is a silent block, which gets executed but not printed.'
47
48 # <demo> stop
49 # <demo> auto
50 print 'This is an automatic block.'
51 print 'It is executed without asking for confirmation, but printed.'
52 z = x+y
53
54 print 'z=',x
55
56 # <demo> stop
57 # This is just another normal block.
58 print 'z is now:', z
59
60 print 'bye!'
61 """
62 fp = tempfile.mkdtemp(prefix = 'DemoTmp')
63 fd, filename = tempfile.mkstemp(prefix = 'demoExample1File', suffix = '.py',
64 dir = fp)
65 f = os.fdopen(fd, 'wt')
66
67 f.write(example1)
68 f.close()
69
70 my_d = Demo(filename)
71 my_cd = ClearDemo(filename)
72
73 fobj = StringIO.StringIO(example1)
74 str_d = Demo(fobj, title='via stringio')
75
76 print '''
77 The example that is embeded in demo.py file has been used to create
78 the following 3 demos, and should now be available to use:
79 my_d() -- created from a file
80 my_cd() -- created from a file, a ClearDemo
81 str_d() -- same as above, but created via a StringIO object
82 Call by typing their name, (with parentheses), at the
83 ipython prompt, interact with the block, then call again
84 to run the next block.
85 '''
@@ -1,526 +1,554 b''
1 """Module for interactive demos using IPython.
1 """Module for interactive demos using IPython.
2
2
3 This module implements a few classes for running Python scripts interactively
3 This module implements a few classes for running Python scripts interactively
4 in IPython for demonstrations. With very simple markup (a few tags in
4 in IPython for demonstrations. With very simple markup (a few tags in
5 comments), you can control points where the script stops executing and returns
5 comments), you can control points where the script stops executing and returns
6 control to IPython.
6 control to IPython.
7
7
8
8
9 Provided classes
9 Provided classes
10 ================
10 ================
11
11
12 The classes are (see their docstrings for further details):
12 The classes are (see their docstrings for further details):
13
13
14 - Demo: pure python demos
14 - Demo: pure python demos
15
15
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
16 - IPythonDemo: demos with input to be processed by IPython as if it had been
17 typed interactively (so magics work, as well as any other special syntax you
17 typed interactively (so magics work, as well as any other special syntax you
18 may have added via input prefilters).
18 may have added via input prefilters).
19
19
20 - LineDemo: single-line version of the Demo class. These demos are executed
20 - LineDemo: single-line version of the Demo class. These demos are executed
21 one line at a time, and require no markup.
21 one line at a time, and require no markup.
22
22
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
23 - IPythonLineDemo: IPython version of the LineDemo class (the demo is
24 executed a line at a time, but processed via IPython).
24 executed a line at a time, but processed via IPython).
25
25
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
26 - ClearMixin: mixin to make Demo classes with less visual clutter. It
27 declares an empty marquee and a pre_cmd that clears the screen before each
27 declares an empty marquee and a pre_cmd that clears the screen before each
28 block (see Subclassing below).
28 block (see Subclassing below).
29
29
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
30 - ClearDemo, ClearIPDemo: mixin-enabled versions of the Demo and IPythonDemo
31 classes.
31 classes.
32
32
33
33
34 Subclassing
34 Subclassing
35 ===========
35 ===========
36
36
37 The classes here all include a few methods meant to make customization by
37 The classes here all include a few methods meant to make customization by
38 subclassing more convenient. Their docstrings below have some more details:
38 subclassing more convenient. Their docstrings below have some more details:
39
39
40 - marquee(): generates a marquee to provide visible on-screen markers at each
40 - marquee(): generates a marquee to provide visible on-screen markers at each
41 block start and end.
41 block start and end.
42
42
43 - pre_cmd(): run right before the execution of each block.
43 - pre_cmd(): run right before the execution of each block.
44
44
45 - post_cmd(): run right after the execution of each block. If the block
45 - post_cmd(): run right after the execution of each block. If the block
46 raises an exception, this is NOT called.
46 raises an exception, this is NOT called.
47
47
48
48
49 Operation
49 Operation
50 =========
50 =========
51
51
52 The file is run in its own empty namespace (though you can pass it a string of
52 The file is run in its own empty namespace (though you can pass it a string of
53 arguments as if in a command line environment, and it will see those as
53 arguments as if in a command line environment, and it will see those as
54 sys.argv). But at each stop, the global IPython namespace is updated with the
54 sys.argv). But at each stop, the global IPython namespace is updated with the
55 current internal demo namespace, so you can work interactively with the data
55 current internal demo namespace, so you can work interactively with the data
56 accumulated so far.
56 accumulated so far.
57
57
58 By default, each block of code is printed (with syntax highlighting) before
58 By default, each block of code is printed (with syntax highlighting) before
59 executing it and you have to confirm execution. This is intended to show the
59 executing it and you have to confirm execution. This is intended to show the
60 code to an audience first so you can discuss it, and only proceed with
60 code to an audience first so you can discuss it, and only proceed with
61 execution once you agree. There are a few tags which allow you to modify this
61 execution once you agree. There are a few tags which allow you to modify this
62 behavior.
62 behavior.
63
63
64 The supported tags are:
64 The supported tags are:
65
65
66 # <demo> stop
66 # <demo> stop
67
67
68 Defines block boundaries, the points where IPython stops execution of the
68 Defines block boundaries, the points where IPython stops execution of the
69 file and returns to the interactive prompt.
69 file and returns to the interactive prompt.
70
70
71 You can optionally mark the stop tag with extra dashes before and after the
71 You can optionally mark the stop tag with extra dashes before and after the
72 word 'stop', to help visually distinguish the blocks in a text editor:
72 word 'stop', to help visually distinguish the blocks in a text editor:
73
73
74 # <demo> --- stop ---
74 # <demo> --- stop ---
75
75
76
76
77 # <demo> silent
77 # <demo> silent
78
78
79 Make a block execute silently (and hence automatically). Typically used in
79 Make a block execute silently (and hence automatically). Typically used in
80 cases where you have some boilerplate or initialization code which you need
80 cases where you have some boilerplate or initialization code which you need
81 executed but do not want to be seen in the demo.
81 executed but do not want to be seen in the demo.
82
82
83 # <demo> auto
83 # <demo> auto
84
84
85 Make a block execute automatically, but still being printed. Useful for
85 Make a block execute automatically, but still being printed. Useful for
86 simple code which does not warrant discussion, since it avoids the extra
86 simple code which does not warrant discussion, since it avoids the extra
87 manual confirmation.
87 manual confirmation.
88
88
89 # <demo> auto_all
89 # <demo> auto_all
90
90
91 This tag can _only_ be in the first block, and if given it overrides the
91 This tag can _only_ be in the first block, and if given it overrides the
92 individual auto tags to make the whole demo fully automatic (no block asks
92 individual auto tags to make the whole demo fully automatic (no block asks
93 for confirmation). It can also be given at creation time (or the attribute
93 for confirmation). It can also be given at creation time (or the attribute
94 set later) to override what's in the file.
94 set later) to override what's in the file.
95
95
96 While _any_ python file can be run as a Demo instance, if there are no stop
96 While _any_ python file can be run as a Demo instance, if there are no stop
97 tags the whole file will run in a single block (no different that calling
97 tags the whole file will run in a single block (no different that calling
98 first %pycat and then %run). The minimal markup to make this useful is to
98 first %pycat and then %run). The minimal markup to make this useful is to
99 place a set of stop tags; the other tags are only there to let you fine-tune
99 place a set of stop tags; the other tags are only there to let you fine-tune
100 the execution.
100 the execution.
101
101
102 This is probably best explained with the simple example file below. You can
102 This is probably best explained with the simple example file below. You can
103 copy this into a file named ex_demo.py, and try running it via:
103 copy this into a file named ex_demo.py, and try running it via:
104
104
105 from IPython.demo import Demo
105 from IPython.demo import Demo
106 d = Demo('ex_demo.py')
106 d = Demo('ex_demo.py')
107 d() <--- Call the d object (omit the parens if you have autocall set to 2).
107 d() <--- Call the d object (omit the parens if you have autocall set to 2).
108
108
109 Each time you call the demo object, it runs the next block. The demo object
109 Each time you call the demo object, it runs the next block. The demo object
110 has a few useful methods for navigation, like again(), edit(), jump(), seek()
110 has a few useful methods for navigation, like again(), edit(), jump(), seek()
111 and back(). It can be reset for a new run via reset() or reloaded from disk
111 and back(). It can be reset for a new run via reset() or reloaded from disk
112 (in case you've edited the source) via reload(). See their docstrings below.
112 (in case you've edited the source) via reload(). See their docstrings below.
113
113
114 Note: To make this simpler to explore, a file called "demo-exercizer.py" has
115 been added to the "docs/examples/core" directory. Just cd to this directory in
116 an IPython session, and type::
117
118 %run demo-exercizer.py
119
120 and then follow the directions.
114
121
115 Example
122 Example
116 =======
123 =======
117
124
118 The following is a very simple example of a valid demo file.
125 The following is a very simple example of a valid demo file.
119
126
120 #################### EXAMPLE DEMO <ex_demo.py> ###############################
127 #################### EXAMPLE DEMO <ex_demo.py> ###############################
121 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
128 '''A simple interactive demo to illustrate the use of IPython's Demo class.'''
122
129
123 print 'Hello, welcome to an interactive IPython demo.'
130 print 'Hello, welcome to an interactive IPython demo.'
124
131
125 # The mark below defines a block boundary, which is a point where IPython will
132 # The mark below defines a block boundary, which is a point where IPython will
126 # stop execution and return to the interactive prompt. The dashes are actually
133 # stop execution and return to the interactive prompt. The dashes are actually
127 # optional and used only as a visual aid to clearly separate blocks while
134 # optional and used only as a visual aid to clearly separate blocks while
128 editing the demo code.
135 # editing the demo code.
129 # <demo> stop
136 # <demo> stop
130
137
131 x = 1
138 x = 1
132 y = 2
139 y = 2
133
140
134 # <demo> stop
141 # <demo> stop
135
142
136 # the mark below makes this block as silent
143 # the mark below makes this block as silent
137 # <demo> silent
144 # <demo> silent
138
145
139 print 'This is a silent block, which gets executed but not printed.'
146 print 'This is a silent block, which gets executed but not printed.'
140
147
141 # <demo> stop
148 # <demo> stop
142 # <demo> auto
149 # <demo> auto
143 print 'This is an automatic block.'
150 print 'This is an automatic block.'
144 print 'It is executed without asking for confirmation, but printed.'
151 print 'It is executed without asking for confirmation, but printed.'
145 z = x+y
152 z = x+y
146
153
147 print 'z=',x
154 print 'z=',x
148
155
149 # <demo> stop
156 # <demo> stop
150 # This is just another normal block.
157 # This is just another normal block.
151 print 'z is now:', z
158 print 'z is now:', z
152
159
153 print 'bye!'
160 print 'bye!'
154 ################### END EXAMPLE DEMO <ex_demo.py> ############################
161 ################### END EXAMPLE DEMO <ex_demo.py> ############################
155 """
162 """
156
163
157 #*****************************************************************************
164 #*****************************************************************************
158 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
165 # Copyright (C) 2005-2006 Fernando Perez. <Fernando.Perez@colorado.edu>
159 #
166 #
160 # Distributed under the terms of the BSD License. The full license is in
167 # Distributed under the terms of the BSD License. The full license is in
161 # the file COPYING, distributed as part of this software.
168 # the file COPYING, distributed as part of this software.
162 #
169 #
163 #*****************************************************************************
170 #*****************************************************************************
164
171
165 import exceptions
172 import exceptions
166 import os
173 import os
167 import re
174 import re
168 import shlex
175 import shlex
169 import sys
176 import sys
170
177
171 from IPython.PyColorize import Parser
178 from IPython.PyColorize import Parser
172 from IPython.genutils import marquee, file_read, file_readlines
179 from IPython.genutils import marquee, file_read, file_readlines, Term
173
180
174 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
181 __all__ = ['Demo','IPythonDemo','LineDemo','IPythonLineDemo','DemoError']
175
182
176 class DemoError(exceptions.Exception): pass
183 class DemoError(exceptions.Exception): pass
177
184
178 def re_mark(mark):
185 def re_mark(mark):
179 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
186 return re.compile(r'^\s*#\s+<demo>\s+%s\s*$' % mark,re.MULTILINE)
180
187
181 class Demo(object):
188 class Demo(object):
182
189
183 re_stop = re_mark('-*\s?stop\s?-*')
190 re_stop = re_mark('-*\s?stop\s?-*')
184 re_silent = re_mark('silent')
191 re_silent = re_mark('silent')
185 re_auto = re_mark('auto')
192 re_auto = re_mark('auto')
186 re_auto_all = re_mark('auto_all')
193 re_auto_all = re_mark('auto_all')
187
194
188 def __init__(self,fname,arg_str='',auto_all=None):
195 def __init__(self,src,title='',arg_str='',auto_all=None):
189 """Make a new demo object. To run the demo, simply call the object.
196 """Make a new demo object. To run the demo, simply call the object.
190
197
191 See the module docstring for full details and an example (you can use
198 See the module docstring for full details and an example (you can use
192 IPython.Demo? in IPython to see it).
199 IPython.Demo? in IPython to see it).
193
200
194 Inputs:
201 Inputs:
195
202
196 - fname = filename.
203 - src is either a file, or file-like object, or a
204 string that can be resolved to a filename.
197
205
198 Optional inputs:
206 Optional inputs:
207
208 - title: a string to use as the demo name. Of most use when the demo
209 you are making comes from an object that has no filename, or if you
210 want an alternate denotation distinct from the filename.
199
211
200 - arg_str(''): a string of arguments, internally converted to a list
212 - arg_str(''): a string of arguments, internally converted to a list
201 just like sys.argv, so the demo script can see a similar
213 just like sys.argv, so the demo script can see a similar
202 environment.
214 environment.
203
215
204 - auto_all(None): global flag to run all blocks automatically without
216 - auto_all(None): global flag to run all blocks automatically without
205 confirmation. This attribute overrides the block-level tags and
217 confirmation. This attribute overrides the block-level tags and
206 applies to the whole demo. It is an attribute of the object, and
218 applies to the whole demo. It is an attribute of the object, and
207 can be changed at runtime simply by reassigning it to a boolean
219 can be changed at runtime simply by reassigning it to a boolean
208 value.
220 value.
209 """
221 """
210
222 if hasattr(src, "read"):
211 self.fname = fname
223 # It seems to be a file or a file-like object
212 self.sys_argv = [fname] + shlex.split(arg_str)
224 self.fobj = src
225 self.fname = "from a file-like object"
226 if title == '':
227 self.title = "from a file-like object"
228 else:
229 self.title = title
230 else:
231 # Assume it's a string or something that can be converted to one
232 self.fobj = open(src)
233 self.fname = src
234 if title == '':
235 (filepath, filename) = os.path.split(src)
236 self.title = filename
237 else:
238 self.title = title
239 self.sys_argv = [src] + shlex.split(arg_str)
213 self.auto_all = auto_all
240 self.auto_all = auto_all
214
241
215 # get a few things from ipython. While it's a bit ugly design-wise,
242 # get a few things from ipython. While it's a bit ugly design-wise,
216 # it ensures that things like color scheme and the like are always in
243 # it ensures that things like color scheme and the like are always in
217 # sync with the ipython mode being used. This class is only meant to
244 # sync with the ipython mode being used. This class is only meant to
218 # be used inside ipython anyways, so it's OK.
245 # be used inside ipython anyways, so it's OK.
219 self.ip_ns = __IPYTHON__.user_ns
246 self.ip_ns = __IPYTHON__.user_ns
220 self.ip_colorize = __IPYTHON__.pycolorize
247 self.ip_colorize = __IPYTHON__.pycolorize
221 self.ip_showtb = __IPYTHON__.showtraceback
248 self.ip_showtb = __IPYTHON__.showtraceback
222 self.ip_runlines = __IPYTHON__.runlines
249 self.ip_runlines = __IPYTHON__.runlines
223 self.shell = __IPYTHON__
250 self.shell = __IPYTHON__
224
251
225 # load user data and initialize data structures
252 # load user data and initialize data structures
226 self.reload()
253 self.reload()
227
254
228 def reload(self):
255 def reload(self):
229 """Reload source from disk and initialize state."""
256 """Reload source from disk and initialize state."""
230 # read data and parse into blocks
257 # read data and parse into blocks
231 self.src = file_read(self.fname)
258 self.src = self.fobj.read()
232 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
259 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
233 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
260 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
234 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
261 self._auto = [bool(self.re_auto.findall(b)) for b in src_b]
235
262
236 # if auto_all is not given (def. None), we read it from the file
263 # if auto_all is not given (def. None), we read it from the file
237 if self.auto_all is None:
264 if self.auto_all is None:
238 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
265 self.auto_all = bool(self.re_auto_all.findall(src_b[0]))
239 else:
266 else:
240 self.auto_all = bool(self.auto_all)
267 self.auto_all = bool(self.auto_all)
241
268
242 # Clean the sources from all markup so it doesn't get displayed when
269 # Clean the sources from all markup so it doesn't get displayed when
243 # running the demo
270 # running the demo
244 src_blocks = []
271 src_blocks = []
245 auto_strip = lambda s: self.re_auto.sub('',s)
272 auto_strip = lambda s: self.re_auto.sub('',s)
246 for i,b in enumerate(src_b):
273 for i,b in enumerate(src_b):
247 if self._auto[i]:
274 if self._auto[i]:
248 src_blocks.append(auto_strip(b))
275 src_blocks.append(auto_strip(b))
249 else:
276 else:
250 src_blocks.append(b)
277 src_blocks.append(b)
251 # remove the auto_all marker
278 # remove the auto_all marker
252 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
279 src_blocks[0] = self.re_auto_all.sub('',src_blocks[0])
253
280
254 self.nblocks = len(src_blocks)
281 self.nblocks = len(src_blocks)
255 self.src_blocks = src_blocks
282 self.src_blocks = src_blocks
256
283
257 # also build syntax-highlighted source
284 # also build syntax-highlighted source
258 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
285 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
259
286
260 # ensure clean namespace and seek offset
287 # ensure clean namespace and seek offset
261 self.reset()
288 self.reset()
262
289
263 def reset(self):
290 def reset(self):
264 """Reset the namespace and seek pointer to restart the demo"""
291 """Reset the namespace and seek pointer to restart the demo"""
265 self.user_ns = {}
292 self.user_ns = {}
266 self.finished = False
293 self.finished = False
267 self.block_index = 0
294 self.block_index = 0
268
295
269 def _validate_index(self,index):
296 def _validate_index(self,index):
270 if index<0 or index>=self.nblocks:
297 if index<0 or index>=self.nblocks:
271 raise ValueError('invalid block index %s' % index)
298 raise ValueError('invalid block index %s' % index)
272
299
273 def _get_index(self,index):
300 def _get_index(self,index):
274 """Get the current block index, validating and checking status.
301 """Get the current block index, validating and checking status.
275
302
276 Returns None if the demo is finished"""
303 Returns None if the demo is finished"""
277
304
278 if index is None:
305 if index is None:
279 if self.finished:
306 if self.finished:
280 print 'Demo finished. Use reset() if you want to rerun it.'
307 print >>Term.cout, 'Demo finished. Use <demo_name>.reset() if you want to rerun it.'
281 return None
308 return None
282 index = self.block_index
309 index = self.block_index
283 else:
310 else:
284 self._validate_index(index)
311 self._validate_index(index)
285 return index
312 return index
286
313
287 def seek(self,index):
314 def seek(self,index):
288 """Move the current seek pointer to the given block.
315 """Move the current seek pointer to the given block.
289
316
290 You can use negative indices to seek from the end, with identical
317 You can use negative indices to seek from the end, with identical
291 semantics to those of Python lists."""
318 semantics to those of Python lists."""
292 if index<0:
319 if index<0:
293 index = self.nblocks + index
320 index = self.nblocks + index
294 self._validate_index(index)
321 self._validate_index(index)
295 self.block_index = index
322 self.block_index = index
296 self.finished = False
323 self.finished = False
297
324
298 def back(self,num=1):
325 def back(self,num=1):
299 """Move the seek pointer back num blocks (default is 1)."""
326 """Move the seek pointer back num blocks (default is 1)."""
300 self.seek(self.block_index-num)
327 self.seek(self.block_index-num)
301
328
302 def jump(self,num=1):
329 def jump(self,num=1):
303 """Jump a given number of blocks relative to the current one.
330 """Jump a given number of blocks relative to the current one.
304
331
305 The offset can be positive or negative, defaults to 1."""
332 The offset can be positive or negative, defaults to 1."""
306 self.seek(self.block_index+num)
333 self.seek(self.block_index+num)
307
334
308 def again(self):
335 def again(self):
309 """Move the seek pointer back one block and re-execute."""
336 """Move the seek pointer back one block and re-execute."""
310 self.back(1)
337 self.back(1)
311 self()
338 self()
312
339
313 def edit(self,index=None):
340 def edit(self,index=None):
314 """Edit a block.
341 """Edit a block.
315
342
316 If no number is given, use the last block executed.
343 If no number is given, use the last block executed.
317
344
318 This edits the in-memory copy of the demo, it does NOT modify the
345 This edits the in-memory copy of the demo, it does NOT modify the
319 original source file. If you want to do that, simply open the file in
346 original source file. If you want to do that, simply open the file in
320 an editor and use reload() when you make changes to the file. This
347 an editor and use reload() when you make changes to the file. This
321 method is meant to let you change a block during a demonstration for
348 method is meant to let you change a block during a demonstration for
322 explanatory purposes, without damaging your original script."""
349 explanatory purposes, without damaging your original script."""
323
350
324 index = self._get_index(index)
351 index = self._get_index(index)
325 if index is None:
352 if index is None:
326 return
353 return
327 # decrease the index by one (unless we're at the very beginning), so
354 # decrease the index by one (unless we're at the very beginning), so
328 # that the default demo.edit() call opens up the sblock we've last run
355 # that the default demo.edit() call opens up the sblock we've last run
329 if index>0:
356 if index>0:
330 index -= 1
357 index -= 1
331
358
332 filename = self.shell.mktempfile(self.src_blocks[index])
359 filename = self.shell.mktempfile(self.src_blocks[index])
333 self.shell.hooks.editor(filename,1)
360 self.shell.hooks.editor(filename,1)
334 new_block = file_read(filename)
361 new_block = file_read(filename)
335 # update the source and colored block
362 # update the source and colored block
336 self.src_blocks[index] = new_block
363 self.src_blocks[index] = new_block
337 self.src_blocks_colored[index] = self.ip_colorize(new_block)
364 self.src_blocks_colored[index] = self.ip_colorize(new_block)
338 self.block_index = index
365 self.block_index = index
339 # call to run with the newly edited index
366 # call to run with the newly edited index
340 self()
367 self()
341
368
342 def show(self,index=None):
369 def show(self,index=None):
343 """Show a single block on screen"""
370 """Show a single block on screen"""
344
371
345 index = self._get_index(index)
372 index = self._get_index(index)
346 if index is None:
373 if index is None:
347 return
374 return
348
375
349 print self.marquee('<%s> block # %s (%s remaining)' %
376 print >>Term.cout, self.marquee('<%s> block # %s (%s remaining)' %
350 (self.fname,index,self.nblocks-index-1))
377 (self.title,index,self.nblocks-index-1))
351 sys.stdout.write(self.src_blocks_colored[index])
378 print >>Term.cout,(self.src_blocks_colored[index])
352 sys.stdout.flush()
379 sys.stdout.flush()
353
380
354 def show_all(self):
381 def show_all(self):
355 """Show entire demo on screen, block by block"""
382 """Show entire demo on screen, block by block"""
356
383
357 fname = self.fname
384 fname = self.title
385 title = self.title
358 nblocks = self.nblocks
386 nblocks = self.nblocks
359 silent = self._silent
387 silent = self._silent
360 marquee = self.marquee
388 marquee = self.marquee
361 for index,block in enumerate(self.src_blocks_colored):
389 for index,block in enumerate(self.src_blocks_colored):
362 if silent[index]:
390 if silent[index]:
363 print marquee('<%s> SILENT block # %s (%s remaining)' %
391 print >>Term.cout, marquee('<%s> SILENT block # %s (%s remaining)' %
364 (fname,index,nblocks-index-1))
392 (title,index,nblocks-index-1))
365 else:
393 else:
366 print marquee('<%s> block # %s (%s remaining)' %
394 print >>Term.cout, marquee('<%s> block # %s (%s remaining)' %
367 (fname,index,nblocks-index-1))
395 (title,index,nblocks-index-1))
368 print block,
396 print >>Term.cout, block,
369 sys.stdout.flush()
397 sys.stdout.flush()
370
398
371 def runlines(self,source):
399 def runlines(self,source):
372 """Execute a string with one or more lines of code"""
400 """Execute a string with one or more lines of code"""
373
401
374 exec source in self.user_ns
402 exec source in self.user_ns
375
403
376 def __call__(self,index=None):
404 def __call__(self,index=None):
377 """run a block of the demo.
405 """run a block of the demo.
378
406
379 If index is given, it should be an integer >=1 and <= nblocks. This
407 If index is given, it should be an integer >=1 and <= nblocks. This
380 means that the calling convention is one off from typical Python
408 means that the calling convention is one off from typical Python
381 lists. The reason for the inconsistency is that the demo always
409 lists. The reason for the inconsistency is that the demo always
382 prints 'Block n/N, and N is the total, so it would be very odd to use
410 prints 'Block n/N, and N is the total, so it would be very odd to use
383 zero-indexing here."""
411 zero-indexing here."""
384
412
385 index = self._get_index(index)
413 index = self._get_index(index)
386 if index is None:
414 if index is None:
387 return
415 return
388 try:
416 try:
389 marquee = self.marquee
417 marquee = self.marquee
390 next_block = self.src_blocks[index]
418 next_block = self.src_blocks[index]
391 self.block_index += 1
419 self.block_index += 1
392 if self._silent[index]:
420 if self._silent[index]:
393 print marquee('Executing silent block # %s (%s remaining)' %
421 print >>Term.cout, marquee('Executing silent block # %s (%s remaining)' %
394 (index,self.nblocks-index-1))
422 (index,self.nblocks-index-1))
395 else:
423 else:
396 self.pre_cmd()
424 self.pre_cmd()
397 self.show(index)
425 self.show(index)
398 if self.auto_all or self._auto[index]:
426 if self.auto_all or self._auto[index]:
399 print marquee('output:')
427 print >>Term.cout, marquee('output:')
400 else:
428 else:
401 print marquee('Press <q> to quit, <Enter> to execute...'),
429 print >>Term.cout, marquee('Press <q> to quit, <Enter> to execute...'),
402 ans = raw_input().strip()
430 ans = raw_input().strip()
403 if ans:
431 if ans:
404 print marquee('Block NOT executed')
432 print >>Term.cout, marquee('Block NOT executed')
405 return
433 return
406 try:
434 try:
407 save_argv = sys.argv
435 save_argv = sys.argv
408 sys.argv = self.sys_argv
436 sys.argv = self.sys_argv
409 self.runlines(next_block)
437 self.runlines(next_block)
410 self.post_cmd()
438 self.post_cmd()
411 finally:
439 finally:
412 sys.argv = save_argv
440 sys.argv = save_argv
413
441
414 except:
442 except:
415 self.ip_showtb(filename=self.fname)
443 self.ip_showtb(filename=self.fname)
416 else:
444 else:
417 self.ip_ns.update(self.user_ns)
445 self.ip_ns.update(self.user_ns)
418
446
419 if self.block_index == self.nblocks:
447 if self.block_index == self.nblocks:
420 mq1 = self.marquee('END OF DEMO')
448 mq1 = self.marquee('END OF DEMO')
421 if mq1:
449 if mq1:
422 # avoid spurious prints if empty marquees are used
450 # avoid spurious print >>Term.cout,s if empty marquees are used
423 print
451 print >>Term.cout
424 print mq1
452 print >>Term.cout, mq1
425 print self.marquee('Use reset() if you want to rerun it.')
453 print >>Term.cout, self.marquee('Use <demo_name>.reset() if you want to rerun it.')
426 self.finished = True
454 self.finished = True
427
455
428 # These methods are meant to be overridden by subclasses who may wish to
456 # These methods are meant to be overridden by subclasses who may wish to
429 # customize the behavior of of their demos.
457 # customize the behavior of of their demos.
430 def marquee(self,txt='',width=78,mark='*'):
458 def marquee(self,txt='',width=78,mark='*'):
431 """Return the input string centered in a 'marquee'."""
459 """Return the input string centered in a 'marquee'."""
432 return marquee(txt,width,mark)
460 return marquee(txt,width,mark)
433
461
434 def pre_cmd(self):
462 def pre_cmd(self):
435 """Method called before executing each block."""
463 """Method called before executing each block."""
436 pass
464 pass
437
465
438 def post_cmd(self):
466 def post_cmd(self):
439 """Method called after executing each block."""
467 """Method called after executing each block."""
440 pass
468 pass
441
469
442
470
443 class IPythonDemo(Demo):
471 class IPythonDemo(Demo):
444 """Class for interactive demos with IPython's input processing applied.
472 """Class for interactive demos with IPython's input processing applied.
445
473
446 This subclasses Demo, but instead of executing each block by the Python
474 This subclasses Demo, but instead of executing each block by the Python
447 interpreter (via exec), it actually calls IPython on it, so that any input
475 interpreter (via exec), it actually calls IPython on it, so that any input
448 filters which may be in place are applied to the input block.
476 filters which may be in place are applied to the input block.
449
477
450 If you have an interactive environment which exposes special input
478 If you have an interactive environment which exposes special input
451 processing, you can use this class instead to write demo scripts which
479 processing, you can use this class instead to write demo scripts which
452 operate exactly as if you had typed them interactively. The default Demo
480 operate exactly as if you had typed them interactively. The default Demo
453 class requires the input to be valid, pure Python code.
481 class requires the input to be valid, pure Python code.
454 """
482 """
455
483
456 def runlines(self,source):
484 def runlines(self,source):
457 """Execute a string with one or more lines of code"""
485 """Execute a string with one or more lines of code"""
458
486
459 self.shell.runlines(source)
487 self.shell.runlines(source)
460
488
461 class LineDemo(Demo):
489 class LineDemo(Demo):
462 """Demo where each line is executed as a separate block.
490 """Demo where each line is executed as a separate block.
463
491
464 The input script should be valid Python code.
492 The input script should be valid Python code.
465
493
466 This class doesn't require any markup at all, and it's meant for simple
494 This class doesn't require any markup at all, and it's meant for simple
467 scripts (with no nesting or any kind of indentation) which consist of
495 scripts (with no nesting or any kind of indentation) which consist of
468 multiple lines of input to be executed, one at a time, as if they had been
496 multiple lines of input to be executed, one at a time, as if they had been
469 typed in the interactive prompt."""
497 typed in the interactive prompt."""
470
498
471 def reload(self):
499 def reload(self):
472 """Reload source from disk and initialize state."""
500 """Reload source from disk and initialize state."""
473 # read data and parse into blocks
501 # read data and parse into blocks
474 src_b = [l for l in file_readlines(self.fname) if l.strip()]
502 src_b = [l for l in self.fobj.readline() if l.strip()]
475 nblocks = len(src_b)
503 nblocks = len(src_b)
476 self.src = os.linesep.join(file_readlines(self.fname))
504 self.src = os.linesep.join(self.fobj.readlines())
477 self._silent = [False]*nblocks
505 self._silent = [False]*nblocks
478 self._auto = [True]*nblocks
506 self._auto = [True]*nblocks
479 self.auto_all = True
507 self.auto_all = True
480 self.nblocks = nblocks
508 self.nblocks = nblocks
481 self.src_blocks = src_b
509 self.src_blocks = src_b
482
510
483 # also build syntax-highlighted source
511 # also build syntax-highlighted source
484 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
512 self.src_blocks_colored = map(self.ip_colorize,self.src_blocks)
485
513
486 # ensure clean namespace and seek offset
514 # ensure clean namespace and seek offset
487 self.reset()
515 self.reset()
488
516
489
517
490 class IPythonLineDemo(IPythonDemo,LineDemo):
518 class IPythonLineDemo(IPythonDemo,LineDemo):
491 """Variant of the LineDemo class whose input is processed by IPython."""
519 """Variant of the LineDemo class whose input is processed by IPython."""
492 pass
520 pass
493
521
494
522
495 class ClearMixin(object):
523 class ClearMixin(object):
496 """Use this mixin to make Demo classes with less visual clutter.
524 """Use this mixin to make Demo classes with less visual clutter.
497
525
498 Demos using this mixin will clear the screen before every block and use
526 Demos using this mixin will clear the screen before every block and use
499 blank marquees.
527 blank marquees.
500
528
501 Note that in order for the methods defined here to actually override those
529 Note that in order for the methods defined here to actually override those
502 of the classes it's mixed with, it must go /first/ in the inheritance
530 of the classes it's mixed with, it must go /first/ in the inheritance
503 tree. For example:
531 tree. For example:
504
532
505 class ClearIPDemo(ClearMixin,IPythonDemo): pass
533 class ClearIPDemo(ClearMixin,IPythonDemo): pass
506
534
507 will provide an IPythonDemo class with the mixin's features.
535 will provide an IPythonDemo class with the mixin's features.
508 """
536 """
509
537
510 def marquee(self,txt='',width=78,mark='*'):
538 def marquee(self,txt='',width=78,mark='*'):
511 """Blank marquee that returns '' no matter what the input."""
539 """Blank marquee that returns '' no matter what the input."""
512 return ''
540 return ''
513
541
514 def pre_cmd(self):
542 def pre_cmd(self):
515 """Method called before executing each block.
543 """Method called before executing each block.
516
544
517 This one simply clears the screen."""
545 This one simply clears the screen."""
518 os.system('clear')
546 import IPython.platutils
519
547 IPython.platutils.term_clear()
520
548
521 class ClearDemo(ClearMixin,Demo):
549 class ClearDemo(ClearMixin,Demo):
522 pass
550 pass
523
551
524
552
525 class ClearIPDemo(ClearMixin,IPythonDemo):
553 class ClearIPDemo(ClearMixin,IPythonDemo):
526 pass
554 pass
@@ -1,106 +1,109 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """ Proxy module for accessing platform specific utility functions.
2 """ Proxy module for accessing platform specific utility functions.
3
3
4 Importing this module should give you the implementations that are correct
4 Importing this module should give you the implementations that are correct
5 for your operation system, from platutils_PLATFORMNAME module.
5 for your operation system, from platutils_PLATFORMNAME module.
6 """
6 """
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #*****************************************************************************
13 #*****************************************************************************
14
14
15 import os
15 import os
16 import sys
16 import sys
17 import warnings
17 import warnings
18
18
19 # Import the platform-specific implementations
19 # Import the platform-specific implementations
20 if os.name == 'posix':
20 if os.name == 'posix':
21 import platutils_posix as _platutils
21 import platutils_posix as _platutils
22 elif sys.platform == 'win32':
22 elif sys.platform == 'win32':
23 import platutils_win32 as _platutils
23 import platutils_win32 as _platutils
24 else:
24 else:
25 import platutils_dummy as _platutils
25 import platutils_dummy as _platutils
26 import warnings
26 import warnings
27 warnings.warn("Platutils not available for platform '%s', some features may be missing" %
27 warnings.warn("Platutils not available for platform '%s', some features may be missing" %
28 os.name)
28 os.name)
29 del warnings
29 del warnings
30
30
31
31
32 # Functionality that's logically common to all platforms goes here, each
32 # Functionality that's logically common to all platforms goes here, each
33 # platform-specific module only provides the bits that are OS-dependent.
33 # platform-specific module only provides the bits that are OS-dependent.
34
34
35 # XXX - I'm still not happy with a module global for this, but at least now
35 # XXX - I'm still not happy with a module global for this, but at least now
36 # there is a public, cross-platform way of toggling the term title control on
36 # there is a public, cross-platform way of toggling the term title control on
37 # and off. We should make this a stateful object later on so that each user
37 # and off. We should make this a stateful object later on so that each user
38 # can have its own instance if needed.
38 # can have its own instance if needed.
39 def term_clear():
40 _platutils.term_clear()
41
39 def toggle_set_term_title(val):
42 def toggle_set_term_title(val):
40 """Control whether set_term_title is active or not.
43 """Control whether set_term_title is active or not.
41
44
42 set_term_title() allows writing to the console titlebar. In embedded
45 set_term_title() allows writing to the console titlebar. In embedded
43 widgets this can cause problems, so this call can be used to toggle it on
46 widgets this can cause problems, so this call can be used to toggle it on
44 or off as needed.
47 or off as needed.
45
48
46 The default state of the module is for the function to be disabled.
49 The default state of the module is for the function to be disabled.
47
50
48 Parameters
51 Parameters
49 ----------
52 ----------
50 val : bool
53 val : bool
51 If True, set_term_title() actually writes to the terminal (using the
54 If True, set_term_title() actually writes to the terminal (using the
52 appropriate platform-specific module). If False, it is a no-op.
55 appropriate platform-specific module). If False, it is a no-op.
53 """
56 """
54 _platutils.ignore_termtitle = not(val)
57 _platutils.ignore_termtitle = not(val)
55
58
56
59
57 def set_term_title(title):
60 def set_term_title(title):
58 """Set terminal title using the necessary platform-dependent calls."""
61 """Set terminal title using the necessary platform-dependent calls."""
59
62
60 if _platutils.ignore_termtitle:
63 if _platutils.ignore_termtitle:
61 return
64 return
62 _platutils.set_term_title(title)
65 _platutils.set_term_title(title)
63
66
64
67
65 class FindCmdError(Exception):
68 class FindCmdError(Exception):
66 pass
69 pass
67
70
68 def find_cmd(cmd):
71 def find_cmd(cmd):
69 """Find full path to executable cmd in a cross platform manner.
72 """Find full path to executable cmd in a cross platform manner.
70
73
71 This function tries to determine the full path to a command line program
74 This function tries to determine the full path to a command line program
72 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
75 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
73 time it will use the version that is first on the users `PATH`. If
76 time it will use the version that is first on the users `PATH`. If
74 cmd is `python` return `sys.executable`.
77 cmd is `python` return `sys.executable`.
75
78
76 Parameters
79 Parameters
77 ----------
80 ----------
78 cmd : str
81 cmd : str
79 The command line program to look for.
82 The command line program to look for.
80 """
83 """
81 if cmd == 'python':
84 if cmd == 'python':
82 return sys.executable
85 return sys.executable
83 try:
86 try:
84 path = _platutils.find_cmd(cmd)
87 path = _platutils.find_cmd(cmd)
85 except:
88 except:
86 raise FindCmdError('command could not be found: %s' % cmd)
89 raise FindCmdError('command could not be found: %s' % cmd)
87 # which returns empty if not found
90 # which returns empty if not found
88 if path == '':
91 if path == '':
89 raise FindCmdError('command could not be found: %s' % cmd)
92 raise FindCmdError('command could not be found: %s' % cmd)
90 return path
93 return path
91
94
92 def get_long_path_name(path):
95 def get_long_path_name(path):
93 """Expand a path into its long form.
96 """Expand a path into its long form.
94
97
95 On Windows this expands any ~ in the paths. On other platforms, it is
98 On Windows this expands any ~ in the paths. On other platforms, it is
96 a null operation.
99 a null operation.
97 """
100 """
98 return _platutils.get_long_path_name(path)
101 return _platutils.get_long_path_name(path)
99
102
100 #-----------------------------------------------------------------------------
103 #-----------------------------------------------------------------------------
101 # Deprecated functions
104 # Deprecated functions
102 #-----------------------------------------------------------------------------
105 #-----------------------------------------------------------------------------
103 def freeze_term_title():
106 def freeze_term_title():
107 import warnings
104 warnings.warn("This function is deprecated, use toggle_set_term_title()")
108 warnings.warn("This function is deprecated, use toggle_set_term_title()")
105 _platutils.ignore_termtitle = True
109 _platutils.ignore_termtitle = True
106
@@ -1,40 +1,47 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """ Platform specific utility functions, posix version
2 """ Platform specific utility functions, posix version
3
3
4 Importing this module directly is not portable - rather, import platutils
4 Importing this module directly is not portable - rather, import platutils
5 to use these functions in platform agnostic fashion.
5 to use these functions in platform agnostic fashion.
6 """
6 """
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #*****************************************************************************
13 #*****************************************************************************
14
14
15 import sys
15 import sys
16 import os
16 import os
17
17
18 ignore_termtitle = True
18 ignore_termtitle = True
19
19
20 def _dummy_op(*a, **b):
20 def _dummy_op(*a, **b):
21 """ A no-op function """
21 """ A no-op function """
22
22
23
23 def _set_term_title_xterm(title):
24 def _set_term_title_xterm(title):
24 """ Change virtual terminal title in xterm-workalikes """
25 """ Change virtual terminal title in xterm-workalikes """
25
26
26 sys.stdout.write('\033]0;%s\007' % title)
27 sys.stdout.write('\033]0;%s\007' % title)
27
28
28
29
29 if os.environ.get('TERM','') == 'xterm':
30 if os.environ.get('TERM','') == 'xterm':
30 set_term_title = _set_term_title_xterm
31 set_term_title = _set_term_title_xterm
31 else:
32 else:
32 set_term_title = _dummy_op
33 set_term_title = _dummy_op
33
34
35
34 def find_cmd(cmd):
36 def find_cmd(cmd):
35 """Find the full path to a command using which."""
37 """Find the full path to a command using which."""
36 return os.popen('which %s' % cmd).read().strip()
38 return os.popen('which %s' % cmd).read().strip()
37
39
40
38 def get_long_path_name(path):
41 def get_long_path_name(path):
39 """Dummy no-op."""
42 """Dummy no-op."""
40 return path
43 return path
44
45
46 def term_clear():
47 os.system('clear')
@@ -1,82 +1,87 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """ Platform specific utility functions, win32 version
2 """ Platform specific utility functions, win32 version
3
3
4 Importing this module directly is not portable - rather, import platutils
4 Importing this module directly is not portable - rather, import platutils
5 to use these functions in platform agnostic fashion.
5 to use these functions in platform agnostic fashion.
6 """
6 """
7
7
8 #*****************************************************************************
8 #*****************************************************************************
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
9 # Copyright (C) 2001-2006 Fernando Perez <fperez@colorado.edu>
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #*****************************************************************************
13 #*****************************************************************************
14
14
15 import os
15 import os
16
16
17 ignore_termtitle = True
17 ignore_termtitle = True
18
18
19 try:
19 try:
20 import ctypes
20 import ctypes
21
21
22 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
22 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
23 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
23 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
24
24
25 def set_term_title(title):
25 def set_term_title(title):
26 """Set terminal title using ctypes to access the Win32 APIs."""
26 """Set terminal title using ctypes to access the Win32 APIs."""
27 SetConsoleTitleW(title)
27 SetConsoleTitleW(title)
28
28
29 except ImportError:
29 except ImportError:
30 def set_term_title(title):
30 def set_term_title(title):
31 """Set terminal title using the 'title' command."""
31 """Set terminal title using the 'title' command."""
32 global ignore_termtitle
32 global ignore_termtitle
33
33
34 try:
34 try:
35 # Cannot be on network share when issuing system commands
35 # Cannot be on network share when issuing system commands
36 curr = os.getcwd()
36 curr = os.getcwd()
37 os.chdir("C:")
37 os.chdir("C:")
38 ret = os.system("title " + title)
38 ret = os.system("title " + title)
39 finally:
39 finally:
40 os.chdir(curr)
40 os.chdir(curr)
41 if ret:
41 if ret:
42 # non-zero return code signals error, don't try again
42 # non-zero return code signals error, don't try again
43 ignore_termtitle = True
43 ignore_termtitle = True
44
44
45
45 def find_cmd(cmd):
46 def find_cmd(cmd):
46 """Find the full path to a .bat or .exe using the win32api module."""
47 """Find the full path to a .bat or .exe using the win32api module."""
47 try:
48 try:
48 import win32api
49 import win32api
49 except ImportError:
50 except ImportError:
50 raise ImportError('you need to have pywin32 installed for this to work')
51 raise ImportError('you need to have pywin32 installed for this to work')
51 else:
52 else:
52 try:
53 try:
53 (path, offest) = win32api.SearchPath(os.environ['PATH'],cmd + '.exe')
54 (path, offest) = win32api.SearchPath(os.environ['PATH'],cmd + '.exe')
54 except:
55 except:
55 (path, offset) = win32api.SearchPath(os.environ['PATH'],cmd + '.bat')
56 (path, offset) = win32api.SearchPath(os.environ['PATH'],cmd + '.bat')
56 return path
57 return path
57
58
58
59
59 def get_long_path_name(path):
60 def get_long_path_name(path):
60 """Get a long path name (expand ~) on Windows using ctypes.
61 """Get a long path name (expand ~) on Windows using ctypes.
61
62
62 Examples
63 Examples
63 --------
64 --------
64
65
65 >>> get_long_path_name('c:\\docume~1')
66 >>> get_long_path_name('c:\\docume~1')
66 u'c:\\\\Documents and Settings'
67 u'c:\\\\Documents and Settings'
67
68
68 """
69 """
69 try:
70 try:
70 import ctypes
71 import ctypes
71 except ImportError:
72 except ImportError:
72 raise ImportError('you need to have ctypes installed for this to work')
73 raise ImportError('you need to have ctypes installed for this to work')
73 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
74 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
74 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
75 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
75 ctypes.c_uint ]
76 ctypes.c_uint ]
76
77
77 buf = ctypes.create_unicode_buffer(260)
78 buf = ctypes.create_unicode_buffer(260)
78 rv = _GetLongPathName(path, buf, 260)
79 rv = _GetLongPathName(path, buf, 260)
79 if rv == 0 or rv > 260:
80 if rv == 0 or rv > 260:
80 return path
81 return path
81 else:
82 else:
82 return buf.value
83 return buf.value
84
85
86 def term_clear():
87 os.system('cls')
General Comments 0
You need to be logged in to leave comments. Login now