##// END OF EJS Templates
remove unused imports
Srinivas Reddy Thatiparthy -
Show More
@@ -1,1179 +1,1178
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Sphinx directive to support embedded IPython code.
4 4
5 5 This directive allows pasting of entire interactive IPython sessions, prompts
6 6 and all, and their code will actually get re-executed at doc build time, with
7 7 all prompts renumbered sequentially. It also allows you to input code as a pure
8 8 python input by giving the argument python to the directive. The output looks
9 9 like an interactive ipython section.
10 10
11 11 To enable this directive, simply list it in your Sphinx ``conf.py`` file
12 12 (making sure the directory where you placed it is visible to sphinx, as is
13 13 needed for all Sphinx directives). For example, to enable syntax highlighting
14 14 and the IPython directive::
15 15
16 16 extensions = ['IPython.sphinxext.ipython_console_highlighting',
17 17 'IPython.sphinxext.ipython_directive']
18 18
19 19 The IPython directive outputs code-blocks with the language 'ipython'. So
20 20 if you do not have the syntax highlighting extension enabled as well, then
21 21 all rendered code-blocks will be uncolored. By default this directive assumes
22 22 that your prompts are unchanged IPython ones, but this can be customized.
23 23 The configurable options that can be placed in conf.py are:
24 24
25 25 ipython_savefig_dir:
26 26 The directory in which to save the figures. This is relative to the
27 27 Sphinx source directory. The default is `html_static_path`.
28 28 ipython_rgxin:
29 29 The compiled regular expression to denote the start of IPython input
30 30 lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You
31 31 shouldn't need to change this.
32 32 ipython_rgxout:
33 33 The compiled regular expression to denote the start of IPython output
34 34 lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You
35 35 shouldn't need to change this.
36 36 ipython_promptin:
37 37 The string to represent the IPython input prompt in the generated ReST.
38 38 The default is 'In [%d]:'. This expects that the line numbers are used
39 39 in the prompt.
40 40 ipython_promptout:
41 41 The string to represent the IPython prompt in the generated ReST. The
42 42 default is 'Out [%d]:'. This expects that the line numbers are used
43 43 in the prompt.
44 44 ipython_mplbackend:
45 45 The string which specifies if the embedded Sphinx shell should import
46 46 Matplotlib and set the backend. The value specifies a backend that is
47 47 passed to `matplotlib.use()` before any lines in `ipython_execlines` are
48 48 executed. If not specified in conf.py, then the default value of 'agg' is
49 49 used. To use the IPython directive without matplotlib as a dependency, set
50 50 the value to `None`. It may end up that matplotlib is still imported
51 51 if the user specifies so in `ipython_execlines` or makes use of the
52 52 @savefig pseudo decorator.
53 53 ipython_execlines:
54 54 A list of strings to be exec'd in the embedded Sphinx shell. Typical
55 55 usage is to make certain packages always available. Set this to an empty
56 56 list if you wish to have no imports always available. If specified in
57 57 conf.py as `None`, then it has the effect of making no imports available.
58 58 If omitted from conf.py altogether, then the default value of
59 59 ['import numpy as np', 'import matplotlib.pyplot as plt'] is used.
60 60 ipython_holdcount
61 61 When the @suppress pseudo-decorator is used, the execution count can be
62 62 incremented or not. The default behavior is to hold the execution count,
63 63 corresponding to a value of `True`. Set this to `False` to increment
64 64 the execution count after each suppressed command.
65 65
66 66 As an example, to use the IPython directive when `matplotlib` is not available,
67 67 one sets the backend to `None`::
68 68
69 69 ipython_mplbackend = None
70 70
71 71 An example usage of the directive is:
72 72
73 73 .. code-block:: rst
74 74
75 75 .. ipython::
76 76
77 77 In [1]: x = 1
78 78
79 79 In [2]: y = x**2
80 80
81 81 In [3]: print(y)
82 82
83 83 See http://matplotlib.org/sampledoc/ipython_directive.html for additional
84 84 documentation.
85 85
86 86 Pseudo-Decorators
87 87 =================
88 88
89 89 Note: Only one decorator is supported per input. If more than one decorator
90 90 is specified, then only the last one is used.
91 91
92 92 In addition to the Pseudo-Decorators/options described at the above link,
93 93 several enhancements have been made. The directive will emit a message to the
94 94 console at build-time if code-execution resulted in an exception or warning.
95 95 You can suppress these on a per-block basis by specifying the :okexcept:
96 96 or :okwarning: options:
97 97
98 98 .. code-block:: rst
99 99
100 100 .. ipython::
101 101 :okexcept:
102 102 :okwarning:
103 103
104 104 In [1]: 1/0
105 105 In [2]: # raise warning.
106 106
107 107 ToDo
108 108 ----
109 109
110 110 - Turn the ad-hoc test() function into a real test suite.
111 111 - Break up ipython-specific functionality from matplotlib stuff into better
112 112 separated code.
113 113
114 114 Authors
115 115 -------
116 116
117 117 - John D Hunter: orignal author.
118 118 - Fernando Perez: refactoring, documentation, cleanups, port to 0.11.
119 119 - VáclavŠmilauer <eudoxos-AT-arcig.cz>: Prompt generalizations.
120 120 - Skipper Seabold, refactoring, cleanups, pure python addition
121 121 """
122 122
123 123 #-----------------------------------------------------------------------------
124 124 # Imports
125 125 #-----------------------------------------------------------------------------
126 126
127 127 # Stdlib
128 128 import atexit
129 129 import errno
130 130 import os
131 131 import re
132 132 import sys
133 133 import tempfile
134 134 import ast
135 135 import warnings
136 136 import shutil
137 137 from io import StringIO
138 138
139 139 # Third-party
140 140 from docutils.parsers.rst import directives
141 141 from sphinx.util.compat import Directive
142 142
143 143 # Our own
144 144 from traitlets.config import Config
145 145 from IPython import InteractiveShell
146 146 from IPython.core.profiledir import ProfileDir
147 from IPython.utils import io
148 147
149 148 #-----------------------------------------------------------------------------
150 149 # Globals
151 150 #-----------------------------------------------------------------------------
152 151 # for tokenizing blocks
153 152 COMMENT, INPUT, OUTPUT = range(3)
154 153
155 154 #-----------------------------------------------------------------------------
156 155 # Functions and class declarations
157 156 #-----------------------------------------------------------------------------
158 157
159 158 def block_parser(part, rgxin, rgxout, fmtin, fmtout):
160 159 """
161 160 part is a string of ipython text, comprised of at most one
162 161 input, one output, comments, and blank lines. The block parser
163 162 parses the text into a list of::
164 163
165 164 blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...]
166 165
167 166 where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and
168 167 data is, depending on the type of token::
169 168
170 169 COMMENT : the comment string
171 170
172 171 INPUT: the (DECORATOR, INPUT_LINE, REST) where
173 172 DECORATOR: the input decorator (or None)
174 173 INPUT_LINE: the input as string (possibly multi-line)
175 174 REST : any stdout generated by the input line (not OUTPUT)
176 175
177 176 OUTPUT: the output string, possibly multi-line
178 177
179 178 """
180 179 block = []
181 180 lines = part.split('\n')
182 181 N = len(lines)
183 182 i = 0
184 183 decorator = None
185 184 while 1:
186 185
187 186 if i==N:
188 187 # nothing left to parse -- the last line
189 188 break
190 189
191 190 line = lines[i]
192 191 i += 1
193 192 line_stripped = line.strip()
194 193 if line_stripped.startswith('#'):
195 194 block.append((COMMENT, line))
196 195 continue
197 196
198 197 if line_stripped.startswith('@'):
199 198 # Here is where we assume there is, at most, one decorator.
200 199 # Might need to rethink this.
201 200 decorator = line_stripped
202 201 continue
203 202
204 203 # does this look like an input line?
205 204 matchin = rgxin.match(line)
206 205 if matchin:
207 206 lineno, inputline = int(matchin.group(1)), matchin.group(2)
208 207
209 208 # the ....: continuation string
210 209 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
211 210 Nc = len(continuation)
212 211 # input lines can continue on for more than one line, if
213 212 # we have a '\' line continuation char or a function call
214 213 # echo line 'print'. The input line can only be
215 214 # terminated by the end of the block or an output line, so
216 215 # we parse out the rest of the input line if it is
217 216 # multiline as well as any echo text
218 217
219 218 rest = []
220 219 while i<N:
221 220
222 221 # look ahead; if the next line is blank, or a comment, or
223 222 # an output line, we're done
224 223
225 224 nextline = lines[i]
226 225 matchout = rgxout.match(nextline)
227 226 #print "nextline=%s, continuation=%s, starts=%s"%(nextline, continuation, nextline.startswith(continuation))
228 227 if matchout or nextline.startswith('#'):
229 228 break
230 229 elif nextline.startswith(continuation):
231 230 # The default ipython_rgx* treat the space following the colon as optional.
232 231 # However, If the space is there we must consume it or code
233 232 # employing the cython_magic extension will fail to execute.
234 233 #
235 234 # This works with the default ipython_rgx* patterns,
236 235 # If you modify them, YMMV.
237 236 nextline = nextline[Nc:]
238 237 if nextline and nextline[0] == ' ':
239 238 nextline = nextline[1:]
240 239
241 240 inputline += '\n' + nextline
242 241 else:
243 242 rest.append(nextline)
244 243 i+= 1
245 244
246 245 block.append((INPUT, (decorator, inputline, '\n'.join(rest))))
247 246 continue
248 247
249 248 # if it looks like an output line grab all the text to the end
250 249 # of the block
251 250 matchout = rgxout.match(line)
252 251 if matchout:
253 252 lineno, output = int(matchout.group(1)), matchout.group(2)
254 253 if i<N-1:
255 254 output = '\n'.join([output] + lines[i:])
256 255
257 256 block.append((OUTPUT, output))
258 257 break
259 258
260 259 return block
261 260
262 261
263 262 class EmbeddedSphinxShell(object):
264 263 """An embedded IPython instance to run inside Sphinx"""
265 264
266 265 def __init__(self, exec_lines=None):
267 266
268 267 self.cout = StringIO()
269 268
270 269 if exec_lines is None:
271 270 exec_lines = []
272 271
273 272 # Create config object for IPython
274 273 config = Config()
275 274 config.HistoryManager.hist_file = ':memory:'
276 275 config.InteractiveShell.autocall = False
277 276 config.InteractiveShell.autoindent = False
278 277 config.InteractiveShell.colors = 'NoColor'
279 278
280 279 # create a profile so instance history isn't saved
281 280 tmp_profile_dir = tempfile.mkdtemp(prefix='profile_')
282 281 profname = 'auto_profile_sphinx_build'
283 282 pdir = os.path.join(tmp_profile_dir,profname)
284 283 profile = ProfileDir.create_profile_dir(pdir)
285 284
286 285 # Create and initialize global ipython, but don't start its mainloop.
287 286 # This will persist across different EmbededSphinxShell instances.
288 287 IP = InteractiveShell.instance(config=config, profile_dir=profile)
289 288 atexit.register(self.cleanup)
290 289
291 290 sys.stdout = self.cout
292 291 sys.stderr = self.cout
293 292
294 293 # For debugging, so we can see normal output, use this:
295 294 #from IPython.utils.io import Tee
296 295 #sys.stdout = Tee(self.cout, channel='stdout') # dbg
297 296 #sys.stderr = Tee(self.cout, channel='stderr') # dbg
298 297
299 298 # Store a few parts of IPython we'll need.
300 299 self.IP = IP
301 300 self.user_ns = self.IP.user_ns
302 301 self.user_global_ns = self.IP.user_global_ns
303 302
304 303 self.input = ''
305 304 self.output = ''
306 305 self.tmp_profile_dir = tmp_profile_dir
307 306
308 307 self.is_verbatim = False
309 308 self.is_doctest = False
310 309 self.is_suppress = False
311 310
312 311 # Optionally, provide more detailed information to shell.
313 312 # this is assigned by the SetUp method of IPythonDirective
314 313 # to point at itself.
315 314 #
316 315 # So, you can access handy things at self.directive.state
317 316 self.directive = None
318 317
319 318 # on the first call to the savefig decorator, we'll import
320 319 # pyplot as plt so we can make a call to the plt.gcf().savefig
321 320 self._pyplot_imported = False
322 321
323 322 # Prepopulate the namespace.
324 323 for line in exec_lines:
325 324 self.process_input_line(line, store_history=False)
326 325
327 326 def cleanup(self):
328 327 shutil.rmtree(self.tmp_profile_dir, ignore_errors=True)
329 328
330 329 def clear_cout(self):
331 330 self.cout.seek(0)
332 331 self.cout.truncate(0)
333 332
334 333 def process_input_line(self, line, store_history=True):
335 334 """process the input, capturing stdout"""
336 335
337 336 stdout = sys.stdout
338 337 splitter = self.IP.input_splitter
339 338 try:
340 339 sys.stdout = self.cout
341 340 splitter.push(line)
342 341 more = splitter.push_accepts_more()
343 342 if not more:
344 343 source_raw = splitter.raw_reset()
345 344 self.IP.run_cell(source_raw, store_history=store_history)
346 345 finally:
347 346 sys.stdout = stdout
348 347
349 348 def process_image(self, decorator):
350 349 """
351 350 # build out an image directive like
352 351 # .. image:: somefile.png
353 352 # :width 4in
354 353 #
355 354 # from an input like
356 355 # savefig somefile.png width=4in
357 356 """
358 357 savefig_dir = self.savefig_dir
359 358 source_dir = self.source_dir
360 359 saveargs = decorator.split(' ')
361 360 filename = saveargs[1]
362 361 # insert relative path to image file in source (as absolute path for Sphinx)
363 362 outfile = '/' + os.path.relpath(os.path.join(savefig_dir,filename),
364 363 source_dir)
365 364
366 365 imagerows = ['.. image:: %s'%outfile]
367 366
368 367 for kwarg in saveargs[2:]:
369 368 arg, val = kwarg.split('=')
370 369 arg = arg.strip()
371 370 val = val.strip()
372 371 imagerows.append(' :%s: %s'%(arg, val))
373 372
374 373 image_file = os.path.basename(outfile) # only return file name
375 374 image_directive = '\n'.join(imagerows)
376 375 return image_file, image_directive
377 376
378 377 # Callbacks for each type of token
379 378 def process_input(self, data, input_prompt, lineno):
380 379 """
381 380 Process data block for INPUT token.
382 381
383 382 """
384 383 decorator, input, rest = data
385 384 image_file = None
386 385 image_directive = None
387 386
388 387 is_verbatim = decorator=='@verbatim' or self.is_verbatim
389 388 is_doctest = (decorator is not None and \
390 389 decorator.startswith('@doctest')) or self.is_doctest
391 390 is_suppress = decorator=='@suppress' or self.is_suppress
392 391 is_okexcept = decorator=='@okexcept' or self.is_okexcept
393 392 is_okwarning = decorator=='@okwarning' or self.is_okwarning
394 393 is_savefig = decorator is not None and \
395 394 decorator.startswith('@savefig')
396 395
397 396 input_lines = input.split('\n')
398 397 if len(input_lines) > 1:
399 398 if input_lines[-1] != "":
400 399 input_lines.append('') # make sure there's a blank line
401 400 # so splitter buffer gets reset
402 401
403 402 continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2))
404 403
405 404 if is_savefig:
406 405 image_file, image_directive = self.process_image(decorator)
407 406
408 407 ret = []
409 408 is_semicolon = False
410 409
411 410 # Hold the execution count, if requested to do so.
412 411 if is_suppress and self.hold_count:
413 412 store_history = False
414 413 else:
415 414 store_history = True
416 415
417 416 # Note: catch_warnings is not thread safe
418 417 with warnings.catch_warnings(record=True) as ws:
419 418 for i, line in enumerate(input_lines):
420 419 if line.endswith(';'):
421 420 is_semicolon = True
422 421
423 422 if i == 0:
424 423 # process the first input line
425 424 if is_verbatim:
426 425 self.process_input_line('')
427 426 self.IP.execution_count += 1 # increment it anyway
428 427 else:
429 428 # only submit the line in non-verbatim mode
430 429 self.process_input_line(line, store_history=store_history)
431 430 formatted_line = '%s %s'%(input_prompt, line)
432 431 else:
433 432 # process a continuation line
434 433 if not is_verbatim:
435 434 self.process_input_line(line, store_history=store_history)
436 435
437 436 formatted_line = '%s %s'%(continuation, line)
438 437
439 438 if not is_suppress:
440 439 ret.append(formatted_line)
441 440
442 441 if not is_suppress and len(rest.strip()) and is_verbatim:
443 442 # The "rest" is the standard output of the input. This needs to be
444 443 # added when in verbatim mode. If there is no "rest", then we don't
445 444 # add it, as the new line will be added by the processed output.
446 445 ret.append(rest)
447 446
448 447 # Fetch the processed output. (This is not the submitted output.)
449 448 self.cout.seek(0)
450 449 processed_output = self.cout.read()
451 450 if not is_suppress and not is_semicolon:
452 451 #
453 452 # In IPythonDirective.run, the elements of `ret` are eventually
454 453 # combined such that '' entries correspond to newlines. So if
455 454 # `processed_output` is equal to '', then the adding it to `ret`
456 455 # ensures that there is a blank line between consecutive inputs
457 456 # that have no outputs, as in:
458 457 #
459 458 # In [1]: x = 4
460 459 #
461 460 # In [2]: x = 5
462 461 #
463 462 # When there is processed output, it has a '\n' at the tail end. So
464 463 # adding the output to `ret` will provide the necessary spacing
465 464 # between consecutive input/output blocks, as in:
466 465 #
467 466 # In [1]: x
468 467 # Out[1]: 5
469 468 #
470 469 # In [2]: x
471 470 # Out[2]: 5
472 471 #
473 472 # When there is stdout from the input, it also has a '\n' at the
474 473 # tail end, and so this ensures proper spacing as well. E.g.:
475 474 #
476 475 # In [1]: print x
477 476 # 5
478 477 #
479 478 # In [2]: x = 5
480 479 #
481 480 # When in verbatim mode, `processed_output` is empty (because
482 481 # nothing was passed to IP. Sometimes the submitted code block has
483 482 # an Out[] portion and sometimes it does not. When it does not, we
484 483 # need to ensure proper spacing, so we have to add '' to `ret`.
485 484 # However, if there is an Out[] in the submitted code, then we do
486 485 # not want to add a newline as `process_output` has stuff to add.
487 486 # The difficulty is that `process_input` doesn't know if
488 487 # `process_output` will be called---so it doesn't know if there is
489 488 # Out[] in the code block. The requires that we include a hack in
490 489 # `process_block`. See the comments there.
491 490 #
492 491 ret.append(processed_output)
493 492 elif is_semicolon:
494 493 # Make sure there is a newline after the semicolon.
495 494 ret.append('')
496 495
497 496 # context information
498 497 filename = "Unknown"
499 498 lineno = 0
500 499 if self.directive.state:
501 500 filename = self.directive.state.document.current_source
502 501 lineno = self.directive.state.document.current_line
503 502
504 503 # output any exceptions raised during execution to stdout
505 504 # unless :okexcept: has been specified.
506 505 if not is_okexcept and "Traceback" in processed_output:
507 506 s = "\nException in %s at block ending on line %s\n" % (filename, lineno)
508 507 s += "Specify :okexcept: as an option in the ipython:: block to suppress this message\n"
509 508 sys.stdout.write('\n\n>>>' + ('-' * 73))
510 509 sys.stdout.write(s)
511 510 sys.stdout.write(processed_output)
512 511 sys.stdout.write('<<<' + ('-' * 73) + '\n\n')
513 512
514 513 # output any warning raised during execution to stdout
515 514 # unless :okwarning: has been specified.
516 515 if not is_okwarning:
517 516 for w in ws:
518 517 s = "\nWarning in %s at block ending on line %s\n" % (filename, lineno)
519 518 s += "Specify :okwarning: as an option in the ipython:: block to suppress this message\n"
520 519 sys.stdout.write('\n\n>>>' + ('-' * 73))
521 520 sys.stdout.write(s)
522 521 sys.stdout.write(('-' * 76) + '\n')
523 522 s=warnings.formatwarning(w.message, w.category,
524 523 w.filename, w.lineno, w.line)
525 524 sys.stdout.write(s)
526 525 sys.stdout.write('<<<' + ('-' * 73) + '\n')
527 526
528 527 self.cout.truncate(0)
529 528
530 529 return (ret, input_lines, processed_output,
531 530 is_doctest, decorator, image_file, image_directive)
532 531
533 532
534 533 def process_output(self, data, output_prompt, input_lines, output,
535 534 is_doctest, decorator, image_file):
536 535 """
537 536 Process data block for OUTPUT token.
538 537
539 538 """
540 539 # Recall: `data` is the submitted output, and `output` is the processed
541 540 # output from `input_lines`.
542 541
543 542 TAB = ' ' * 4
544 543
545 544 if is_doctest and output is not None:
546 545
547 546 found = output # This is the processed output
548 547 found = found.strip()
549 548 submitted = data.strip()
550 549
551 550 if self.directive is None:
552 551 source = 'Unavailable'
553 552 content = 'Unavailable'
554 553 else:
555 554 source = self.directive.state.document.current_source
556 555 content = self.directive.content
557 556 # Add tabs and join into a single string.
558 557 content = '\n'.join([TAB + line for line in content])
559 558
560 559 # Make sure the output contains the output prompt.
561 560 ind = found.find(output_prompt)
562 561 if ind < 0:
563 562 e = ('output does not contain output prompt\n\n'
564 563 'Document source: {0}\n\n'
565 564 'Raw content: \n{1}\n\n'
566 565 'Input line(s):\n{TAB}{2}\n\n'
567 566 'Output line(s):\n{TAB}{3}\n\n')
568 567 e = e.format(source, content, '\n'.join(input_lines),
569 568 repr(found), TAB=TAB)
570 569 raise RuntimeError(e)
571 570 found = found[len(output_prompt):].strip()
572 571
573 572 # Handle the actual doctest comparison.
574 573 if decorator.strip() == '@doctest':
575 574 # Standard doctest
576 575 if found != submitted:
577 576 e = ('doctest failure\n\n'
578 577 'Document source: {0}\n\n'
579 578 'Raw content: \n{1}\n\n'
580 579 'On input line(s):\n{TAB}{2}\n\n'
581 580 'we found output:\n{TAB}{3}\n\n'
582 581 'instead of the expected:\n{TAB}{4}\n\n')
583 582 e = e.format(source, content, '\n'.join(input_lines),
584 583 repr(found), repr(submitted), TAB=TAB)
585 584 raise RuntimeError(e)
586 585 else:
587 586 self.custom_doctest(decorator, input_lines, found, submitted)
588 587
589 588 # When in verbatim mode, this holds additional submitted output
590 589 # to be written in the final Sphinx output.
591 590 # https://github.com/ipython/ipython/issues/5776
592 591 out_data = []
593 592
594 593 is_verbatim = decorator=='@verbatim' or self.is_verbatim
595 594 if is_verbatim and data.strip():
596 595 # Note that `ret` in `process_block` has '' as its last element if
597 596 # the code block was in verbatim mode. So if there is no submitted
598 597 # output, then we will have proper spacing only if we do not add
599 598 # an additional '' to `out_data`. This is why we condition on
600 599 # `and data.strip()`.
601 600
602 601 # The submitted output has no output prompt. If we want the
603 602 # prompt and the code to appear, we need to join them now
604 603 # instead of adding them separately---as this would create an
605 604 # undesired newline. How we do this ultimately depends on the
606 605 # format of the output regex. I'll do what works for the default
607 606 # prompt for now, and we might have to adjust if it doesn't work
608 607 # in other cases. Finally, the submitted output does not have
609 608 # a trailing newline, so we must add it manually.
610 609 out_data.append("{0} {1}\n".format(output_prompt, data))
611 610
612 611 return out_data
613 612
614 613 def process_comment(self, data):
615 614 """Process data fPblock for COMMENT token."""
616 615 if not self.is_suppress:
617 616 return [data]
618 617
619 618 def save_image(self, image_file):
620 619 """
621 620 Saves the image file to disk.
622 621 """
623 622 self.ensure_pyplot()
624 623 command = 'plt.gcf().savefig("%s")'%image_file
625 624 #print 'SAVEFIG', command # dbg
626 625 self.process_input_line('bookmark ipy_thisdir', store_history=False)
627 626 self.process_input_line('cd -b ipy_savedir', store_history=False)
628 627 self.process_input_line(command, store_history=False)
629 628 self.process_input_line('cd -b ipy_thisdir', store_history=False)
630 629 self.process_input_line('bookmark -d ipy_thisdir', store_history=False)
631 630 self.clear_cout()
632 631
633 632 def process_block(self, block):
634 633 """
635 634 process block from the block_parser and return a list of processed lines
636 635 """
637 636 ret = []
638 637 output = None
639 638 input_lines = None
640 639 lineno = self.IP.execution_count
641 640
642 641 input_prompt = self.promptin % lineno
643 642 output_prompt = self.promptout % lineno
644 643 image_file = None
645 644 image_directive = None
646 645
647 646 found_input = False
648 647 for token, data in block:
649 648 if token == COMMENT:
650 649 out_data = self.process_comment(data)
651 650 elif token == INPUT:
652 651 found_input = True
653 652 (out_data, input_lines, output, is_doctest,
654 653 decorator, image_file, image_directive) = \
655 654 self.process_input(data, input_prompt, lineno)
656 655 elif token == OUTPUT:
657 656 if not found_input:
658 657
659 658 TAB = ' ' * 4
660 659 linenumber = 0
661 660 source = 'Unavailable'
662 661 content = 'Unavailable'
663 662 if self.directive:
664 663 linenumber = self.directive.state.document.current_line
665 664 source = self.directive.state.document.current_source
666 665 content = self.directive.content
667 666 # Add tabs and join into a single string.
668 667 content = '\n'.join([TAB + line for line in content])
669 668
670 669 e = ('\n\nInvalid block: Block contains an output prompt '
671 670 'without an input prompt.\n\n'
672 671 'Document source: {0}\n\n'
673 672 'Content begins at line {1}: \n\n{2}\n\n'
674 673 'Problematic block within content: \n\n{TAB}{3}\n\n')
675 674 e = e.format(source, linenumber, content, block, TAB=TAB)
676 675
677 676 # Write, rather than include in exception, since Sphinx
678 677 # will truncate tracebacks.
679 678 sys.stdout.write(e)
680 679 raise RuntimeError('An invalid block was detected.')
681 680
682 681 out_data = \
683 682 self.process_output(data, output_prompt, input_lines,
684 683 output, is_doctest, decorator,
685 684 image_file)
686 685 if out_data:
687 686 # Then there was user submitted output in verbatim mode.
688 687 # We need to remove the last element of `ret` that was
689 688 # added in `process_input`, as it is '' and would introduce
690 689 # an undesirable newline.
691 690 assert(ret[-1] == '')
692 691 del ret[-1]
693 692
694 693 if out_data:
695 694 ret.extend(out_data)
696 695
697 696 # save the image files
698 697 if image_file is not None:
699 698 self.save_image(image_file)
700 699
701 700 return ret, image_directive
702 701
703 702 def ensure_pyplot(self):
704 703 """
705 704 Ensures that pyplot has been imported into the embedded IPython shell.
706 705
707 706 Also, makes sure to set the backend appropriately if not set already.
708 707
709 708 """
710 709 # We are here if the @figure pseudo decorator was used. Thus, it's
711 710 # possible that we could be here even if python_mplbackend were set to
712 711 # `None`. That's also strange and perhaps worthy of raising an
713 712 # exception, but for now, we just set the backend to 'agg'.
714 713
715 714 if not self._pyplot_imported:
716 715 if 'matplotlib.backends' not in sys.modules:
717 716 # Then ipython_matplotlib was set to None but there was a
718 717 # call to the @figure decorator (and ipython_execlines did
719 718 # not set a backend).
720 719 #raise Exception("No backend was set, but @figure was used!")
721 720 import matplotlib
722 721 matplotlib.use('agg')
723 722
724 723 # Always import pyplot into embedded shell.
725 724 self.process_input_line('import matplotlib.pyplot as plt',
726 725 store_history=False)
727 726 self._pyplot_imported = True
728 727
729 728 def process_pure_python(self, content):
730 729 """
731 730 content is a list of strings. it is unedited directive content
732 731
733 732 This runs it line by line in the InteractiveShell, prepends
734 733 prompts as needed capturing stderr and stdout, then returns
735 734 the content as a list as if it were ipython code
736 735 """
737 736 output = []
738 737 savefig = False # keep up with this to clear figure
739 738 multiline = False # to handle line continuation
740 739 multiline_start = None
741 740 fmtin = self.promptin
742 741
743 742 ct = 0
744 743
745 744 for lineno, line in enumerate(content):
746 745
747 746 line_stripped = line.strip()
748 747 if not len(line):
749 748 output.append(line)
750 749 continue
751 750
752 751 # handle decorators
753 752 if line_stripped.startswith('@'):
754 753 output.extend([line])
755 754 if 'savefig' in line:
756 755 savefig = True # and need to clear figure
757 756 continue
758 757
759 758 # handle comments
760 759 if line_stripped.startswith('#'):
761 760 output.extend([line])
762 761 continue
763 762
764 763 # deal with lines checking for multiline
765 764 continuation = u' %s:'% ''.join(['.']*(len(str(ct))+2))
766 765 if not multiline:
767 766 modified = u"%s %s" % (fmtin % ct, line_stripped)
768 767 output.append(modified)
769 768 ct += 1
770 769 try:
771 770 ast.parse(line_stripped)
772 771 output.append(u'')
773 772 except Exception: # on a multiline
774 773 multiline = True
775 774 multiline_start = lineno
776 775 else: # still on a multiline
777 776 modified = u'%s %s' % (continuation, line)
778 777 output.append(modified)
779 778
780 779 # if the next line is indented, it should be part of multiline
781 780 if len(content) > lineno + 1:
782 781 nextline = content[lineno + 1]
783 782 if len(nextline) - len(nextline.lstrip()) > 3:
784 783 continue
785 784 try:
786 785 mod = ast.parse(
787 786 '\n'.join(content[multiline_start:lineno+1]))
788 787 if isinstance(mod.body[0], ast.FunctionDef):
789 788 # check to see if we have the whole function
790 789 for element in mod.body[0].body:
791 790 if isinstance(element, ast.Return):
792 791 multiline = False
793 792 else:
794 793 output.append(u'')
795 794 multiline = False
796 795 except Exception:
797 796 pass
798 797
799 798 if savefig: # clear figure if plotted
800 799 self.ensure_pyplot()
801 800 self.process_input_line('plt.clf()', store_history=False)
802 801 self.clear_cout()
803 802 savefig = False
804 803
805 804 return output
806 805
807 806 def custom_doctest(self, decorator, input_lines, found, submitted):
808 807 """
809 808 Perform a specialized doctest.
810 809
811 810 """
812 811 from .custom_doctests import doctests
813 812
814 813 args = decorator.split()
815 814 doctest_type = args[1]
816 815 if doctest_type in doctests:
817 816 doctests[doctest_type](self, args, input_lines, found, submitted)
818 817 else:
819 818 e = "Invalid option to @doctest: {0}".format(doctest_type)
820 819 raise Exception(e)
821 820
822 821
823 822 class IPythonDirective(Directive):
824 823
825 824 has_content = True
826 825 required_arguments = 0
827 826 optional_arguments = 4 # python, suppress, verbatim, doctest
828 827 final_argumuent_whitespace = True
829 828 option_spec = { 'python': directives.unchanged,
830 829 'suppress' : directives.flag,
831 830 'verbatim' : directives.flag,
832 831 'doctest' : directives.flag,
833 832 'okexcept': directives.flag,
834 833 'okwarning': directives.flag
835 834 }
836 835
837 836 shell = None
838 837
839 838 seen_docs = set()
840 839
841 840 def get_config_options(self):
842 841 # contains sphinx configuration variables
843 842 config = self.state.document.settings.env.config
844 843
845 844 # get config variables to set figure output directory
846 845 savefig_dir = config.ipython_savefig_dir
847 846 source_dir = self.state.document.settings.env.srcdir
848 847 savefig_dir = os.path.join(source_dir, savefig_dir)
849 848
850 849 # get regex and prompt stuff
851 850 rgxin = config.ipython_rgxin
852 851 rgxout = config.ipython_rgxout
853 852 promptin = config.ipython_promptin
854 853 promptout = config.ipython_promptout
855 854 mplbackend = config.ipython_mplbackend
856 855 exec_lines = config.ipython_execlines
857 856 hold_count = config.ipython_holdcount
858 857
859 858 return (savefig_dir, source_dir, rgxin, rgxout,
860 859 promptin, promptout, mplbackend, exec_lines, hold_count)
861 860
862 861 def setup(self):
863 862 # Get configuration values.
864 863 (savefig_dir, source_dir, rgxin, rgxout, promptin, promptout,
865 864 mplbackend, exec_lines, hold_count) = self.get_config_options()
866 865
867 866 try:
868 867 os.makedirs(savefig_dir)
869 868 except OSError as e:
870 869 if e.errno != errno.EEXIST:
871 870 raise
872 871
873 872 if self.shell is None:
874 873 # We will be here many times. However, when the
875 874 # EmbeddedSphinxShell is created, its interactive shell member
876 875 # is the same for each instance.
877 876
878 877 if mplbackend and 'matplotlib.backends' not in sys.modules:
879 878 import matplotlib
880 879 matplotlib.use(mplbackend)
881 880
882 881 # Must be called after (potentially) importing matplotlib and
883 882 # setting its backend since exec_lines might import pylab.
884 883 self.shell = EmbeddedSphinxShell(exec_lines)
885 884
886 885 # Store IPython directive to enable better error messages
887 886 self.shell.directive = self
888 887
889 888 # reset the execution count if we haven't processed this doc
890 889 #NOTE: this may be borked if there are multiple seen_doc tmp files
891 890 #check time stamp?
892 891 if not self.state.document.current_source in self.seen_docs:
893 892 self.shell.IP.history_manager.reset()
894 893 self.shell.IP.execution_count = 1
895 894 self.seen_docs.add(self.state.document.current_source)
896 895
897 896 # and attach to shell so we don't have to pass them around
898 897 self.shell.rgxin = rgxin
899 898 self.shell.rgxout = rgxout
900 899 self.shell.promptin = promptin
901 900 self.shell.promptout = promptout
902 901 self.shell.savefig_dir = savefig_dir
903 902 self.shell.source_dir = source_dir
904 903 self.shell.hold_count = hold_count
905 904
906 905 # setup bookmark for saving figures directory
907 906 self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir,
908 907 store_history=False)
909 908 self.shell.clear_cout()
910 909
911 910 return rgxin, rgxout, promptin, promptout
912 911
913 912 def teardown(self):
914 913 # delete last bookmark
915 914 self.shell.process_input_line('bookmark -d ipy_savedir',
916 915 store_history=False)
917 916 self.shell.clear_cout()
918 917
919 918 def run(self):
920 919 debug = False
921 920
922 921 #TODO, any reason block_parser can't be a method of embeddable shell
923 922 # then we wouldn't have to carry these around
924 923 rgxin, rgxout, promptin, promptout = self.setup()
925 924
926 925 options = self.options
927 926 self.shell.is_suppress = 'suppress' in options
928 927 self.shell.is_doctest = 'doctest' in options
929 928 self.shell.is_verbatim = 'verbatim' in options
930 929 self.shell.is_okexcept = 'okexcept' in options
931 930 self.shell.is_okwarning = 'okwarning' in options
932 931
933 932 # handle pure python code
934 933 if 'python' in self.arguments:
935 934 content = self.content
936 935 self.content = self.shell.process_pure_python(content)
937 936
938 937 # parts consists of all text within the ipython-block.
939 938 # Each part is an input/output block.
940 939 parts = '\n'.join(self.content).split('\n\n')
941 940
942 941 lines = ['.. code-block:: ipython', '']
943 942 figures = []
944 943
945 944 for part in parts:
946 945 block = block_parser(part, rgxin, rgxout, promptin, promptout)
947 946 if len(block):
948 947 rows, figure = self.shell.process_block(block)
949 948 for row in rows:
950 949 lines.extend([' {0}'.format(line)
951 950 for line in row.split('\n')])
952 951
953 952 if figure is not None:
954 953 figures.append(figure)
955 954
956 955 for figure in figures:
957 956 lines.append('')
958 957 lines.extend(figure.split('\n'))
959 958 lines.append('')
960 959
961 960 if len(lines) > 2:
962 961 if debug:
963 962 print('\n'.join(lines))
964 963 else:
965 964 # This has to do with input, not output. But if we comment
966 965 # these lines out, then no IPython code will appear in the
967 966 # final output.
968 967 self.state_machine.insert_input(
969 968 lines, self.state_machine.input_lines.source(0))
970 969
971 970 # cleanup
972 971 self.teardown()
973 972
974 973 return []
975 974
976 975 # Enable as a proper Sphinx directive
977 976 def setup(app):
978 977 setup.app = app
979 978
980 979 app.add_directive('ipython', IPythonDirective)
981 980 app.add_config_value('ipython_savefig_dir', 'savefig', 'env')
982 981 app.add_config_value('ipython_rgxin',
983 982 re.compile('In \[(\d+)\]:\s?(.*)\s*'), 'env')
984 983 app.add_config_value('ipython_rgxout',
985 984 re.compile('Out\[(\d+)\]:\s?(.*)\s*'), 'env')
986 985 app.add_config_value('ipython_promptin', 'In [%d]:', 'env')
987 986 app.add_config_value('ipython_promptout', 'Out[%d]:', 'env')
988 987
989 988 # We could just let matplotlib pick whatever is specified as the default
990 989 # backend in the matplotlibrc file, but this would cause issues if the
991 990 # backend didn't work in headless environments. For this reason, 'agg'
992 991 # is a good default backend choice.
993 992 app.add_config_value('ipython_mplbackend', 'agg', 'env')
994 993
995 994 # If the user sets this config value to `None`, then EmbeddedSphinxShell's
996 995 # __init__ method will treat it as [].
997 996 execlines = ['import numpy as np', 'import matplotlib.pyplot as plt']
998 997 app.add_config_value('ipython_execlines', execlines, 'env')
999 998
1000 999 app.add_config_value('ipython_holdcount', True, 'env')
1001 1000
1002 1001 metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
1003 1002 return metadata
1004 1003
1005 1004 # Simple smoke test, needs to be converted to a proper automatic test.
1006 1005 def test():
1007 1006
1008 1007 examples = [
1009 1008 r"""
1010 1009 In [9]: pwd
1011 1010 Out[9]: '/home/jdhunter/py4science/book'
1012 1011
1013 1012 In [10]: cd bookdata/
1014 1013 /home/jdhunter/py4science/book/bookdata
1015 1014
1016 1015 In [2]: from pylab import *
1017 1016
1018 1017 In [2]: ion()
1019 1018
1020 1019 In [3]: im = imread('stinkbug.png')
1021 1020
1022 1021 @savefig mystinkbug.png width=4in
1023 1022 In [4]: imshow(im)
1024 1023 Out[4]: <matplotlib.image.AxesImage object at 0x39ea850>
1025 1024
1026 1025 """,
1027 1026 r"""
1028 1027
1029 1028 In [1]: x = 'hello world'
1030 1029
1031 1030 # string methods can be
1032 1031 # used to alter the string
1033 1032 @doctest
1034 1033 In [2]: x.upper()
1035 1034 Out[2]: 'HELLO WORLD'
1036 1035
1037 1036 @verbatim
1038 1037 In [3]: x.st<TAB>
1039 1038 x.startswith x.strip
1040 1039 """,
1041 1040 r"""
1042 1041
1043 1042 In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\
1044 1043 .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv'
1045 1044
1046 1045 In [131]: print url.split('&')
1047 1046 ['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv']
1048 1047
1049 1048 In [60]: import urllib
1050 1049
1051 1050 """,
1052 1051 r"""\
1053 1052
1054 1053 In [133]: import numpy.random
1055 1054
1056 1055 @suppress
1057 1056 In [134]: numpy.random.seed(2358)
1058 1057
1059 1058 @doctest
1060 1059 In [135]: numpy.random.rand(10,2)
1061 1060 Out[135]:
1062 1061 array([[ 0.64524308, 0.59943846],
1063 1062 [ 0.47102322, 0.8715456 ],
1064 1063 [ 0.29370834, 0.74776844],
1065 1064 [ 0.99539577, 0.1313423 ],
1066 1065 [ 0.16250302, 0.21103583],
1067 1066 [ 0.81626524, 0.1312433 ],
1068 1067 [ 0.67338089, 0.72302393],
1069 1068 [ 0.7566368 , 0.07033696],
1070 1069 [ 0.22591016, 0.77731835],
1071 1070 [ 0.0072729 , 0.34273127]])
1072 1071
1073 1072 """,
1074 1073
1075 1074 r"""
1076 1075 In [106]: print x
1077 1076 jdh
1078 1077
1079 1078 In [109]: for i in range(10):
1080 1079 .....: print i
1081 1080 .....:
1082 1081 .....:
1083 1082 0
1084 1083 1
1085 1084 2
1086 1085 3
1087 1086 4
1088 1087 5
1089 1088 6
1090 1089 7
1091 1090 8
1092 1091 9
1093 1092 """,
1094 1093
1095 1094 r"""
1096 1095
1097 1096 In [144]: from pylab import *
1098 1097
1099 1098 In [145]: ion()
1100 1099
1101 1100 # use a semicolon to suppress the output
1102 1101 @savefig test_hist.png width=4in
1103 1102 In [151]: hist(np.random.randn(10000), 100);
1104 1103
1105 1104
1106 1105 @savefig test_plot.png width=4in
1107 1106 In [151]: plot(np.random.randn(10000), 'o');
1108 1107 """,
1109 1108
1110 1109 r"""
1111 1110 # use a semicolon to suppress the output
1112 1111 In [151]: plt.clf()
1113 1112
1114 1113 @savefig plot_simple.png width=4in
1115 1114 In [151]: plot([1,2,3])
1116 1115
1117 1116 @savefig hist_simple.png width=4in
1118 1117 In [151]: hist(np.random.randn(10000), 100);
1119 1118
1120 1119 """,
1121 1120 r"""
1122 1121 # update the current fig
1123 1122 In [151]: ylabel('number')
1124 1123
1125 1124 In [152]: title('normal distribution')
1126 1125
1127 1126
1128 1127 @savefig hist_with_text.png
1129 1128 In [153]: grid(True)
1130 1129
1131 1130 @doctest float
1132 1131 In [154]: 0.1 + 0.2
1133 1132 Out[154]: 0.3
1134 1133
1135 1134 @doctest float
1136 1135 In [155]: np.arange(16).reshape(4,4)
1137 1136 Out[155]:
1138 1137 array([[ 0, 1, 2, 3],
1139 1138 [ 4, 5, 6, 7],
1140 1139 [ 8, 9, 10, 11],
1141 1140 [12, 13, 14, 15]])
1142 1141
1143 1142 In [1]: x = np.arange(16, dtype=float).reshape(4,4)
1144 1143
1145 1144 In [2]: x[0,0] = np.inf
1146 1145
1147 1146 In [3]: x[0,1] = np.nan
1148 1147
1149 1148 @doctest float
1150 1149 In [4]: x
1151 1150 Out[4]:
1152 1151 array([[ inf, nan, 2., 3.],
1153 1152 [ 4., 5., 6., 7.],
1154 1153 [ 8., 9., 10., 11.],
1155 1154 [ 12., 13., 14., 15.]])
1156 1155
1157 1156
1158 1157 """,
1159 1158 ]
1160 1159 # skip local-file depending first example:
1161 1160 examples = examples[1:]
1162 1161
1163 1162 #ipython_directive.DEBUG = True # dbg
1164 1163 #options = dict(suppress=True) # dbg
1165 1164 options = {}
1166 1165 for example in examples:
1167 1166 content = example.split('\n')
1168 1167 IPythonDirective('debug', arguments=None, options=options,
1169 1168 content=content, lineno=0,
1170 1169 content_offset=None, block_text=None,
1171 1170 state=None, state_machine=None,
1172 1171 )
1173 1172
1174 1173 # Run test suite as a script
1175 1174 if __name__=='__main__':
1176 1175 if not os.path.isdir('_static'):
1177 1176 os.mkdir('_static')
1178 1177 test()
1179 1178 print('All OK? Check figures in _static/')
@@ -1,67 +1,66
1 1 """Enable pyglet to be used interacively with prompt_toolkit
2 2 """
3 3
4 import os
5 4 import sys
6 5 import time
7 6 from timeit import default_timer as clock
8 7 import pyglet
9 8
10 9 # On linux only, window.flip() has a bug that causes an AttributeError on
11 10 # window close. For details, see:
12 11 # http://groups.google.com/group/pyglet-users/browse_thread/thread/47c1aab9aa4a3d23/c22f9e819826799e?#c22f9e819826799e
13 12
14 13 if sys.platform.startswith('linux'):
15 14 def flip(window):
16 15 try:
17 16 window.flip()
18 17 except AttributeError:
19 18 pass
20 19 else:
21 20 def flip(window):
22 21 window.flip()
23 22
24 23
25 24 def inputhook(context):
26 25 """Run the pyglet event loop by processing pending events only.
27 26
28 27 This keeps processing pending events until stdin is ready. After
29 28 processing all pending events, a call to time.sleep is inserted. This is
30 29 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
31 30 though for best performance.
32 31 """
33 32 # We need to protect against a user pressing Control-C when IPython is
34 33 # idle and this is running. We trap KeyboardInterrupt and pass.
35 34 try:
36 35 t = clock()
37 36 while not context.input_is_ready():
38 37 pyglet.clock.tick()
39 38 for window in pyglet.app.windows:
40 39 window.switch_to()
41 40 window.dispatch_events()
42 41 window.dispatch_event('on_draw')
43 42 flip(window)
44 43
45 44 # We need to sleep at this point to keep the idle CPU load
46 45 # low. However, if sleep to long, GUI response is poor. As
47 46 # a compromise, we watch how often GUI events are being processed
48 47 # and switch between a short and long sleep time. Here are some
49 48 # stats useful in helping to tune this.
50 49 # time CPU load
51 50 # 0.001 13%
52 51 # 0.005 3%
53 52 # 0.01 1.5%
54 53 # 0.05 0.5%
55 54 used_time = clock() - t
56 55 if used_time > 10.0:
57 56 # print 'Sleep for 1 s' # dbg
58 57 time.sleep(1.0)
59 58 elif used_time > 0.1:
60 59 # Few GUI events coming in, so we can sleep longer
61 60 # print 'Sleep for 0.05 s' # dbg
62 61 time.sleep(0.05)
63 62 else:
64 63 # Many GUI events coming in, so sleep only very little
65 64 time.sleep(0.001)
66 65 except KeyboardInterrupt:
67 66 pass
@@ -1,29 +1,28
1 1 """Test help output of various IPython entry points"""
2 2
3 3 # Copyright (c) IPython Development Team.
4 4 # Distributed under the terms of the Modified BSD License.
5 5
6 6 import IPython.testing.tools as tt
7 from IPython.testing.decorators import skip_without
8 7
9 8
10 9 def test_ipython_help():
11 10 tt.help_all_output_test()
12 11
13 12 def test_profile_help():
14 13 tt.help_all_output_test("profile")
15 14
16 15 def test_profile_list_help():
17 16 tt.help_all_output_test("profile list")
18 17
19 18 def test_profile_create_help():
20 19 tt.help_all_output_test("profile create")
21 20
22 21 def test_locate_help():
23 22 tt.help_all_output_test("locate")
24 23
25 24 def test_locate_profile_help():
26 25 tt.help_all_output_test("locate profile")
27 26
28 27 def test_trust_help():
29 28 tt.help_all_output_test("trust")
@@ -1,73 +1,78
1 1 """cli-specific implementation of process utilities.
2 2
3 3 cli - Common Language Infrastructure for IronPython. Code
4 4 can run on any operating system. Check os.name for os-
5 5 specific settings.
6 6
7 7 This file is only meant to be imported by process.py, not by end-users.
8 8
9 9 This file is largely untested. To become a full drop-in process
10 10 interface for IronPython will probably require you to help fill
11 11 in the details.
12 12 """
13 13
14
14 # Import cli libraries:
15 import clr
15 16 import System
17
18 # Import Python libraries:
16 19 import os
17 from IPython.utils import py3compat
18 20
21 # Import IPython libraries:
22 from IPython.utils import py3compat
23 from ._process_common import arg_split
19 24
20 25 def _find_cmd(cmd):
21 26 """Find the full path to a command using which."""
22 27 paths = System.Environment.GetEnvironmentVariable("PATH").Split(os.pathsep)
23 28 for path in paths:
24 29 filename = os.path.join(path, cmd)
25 30 if System.IO.File.Exists(filename):
26 31 return py3compat.bytes_to_str(filename)
27 32 raise OSError("command %r not found" % cmd)
28 33
29 34 def system(cmd):
30 35 """
31 36 system(cmd) should work in a cli environment on Mac OSX, Linux,
32 37 and Windows
33 38 """
34 39 psi = System.Diagnostics.ProcessStartInfo(cmd)
35 40 psi.RedirectStandardOutput = True
36 41 psi.RedirectStandardError = True
37 42 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
38 43 psi.UseShellExecute = False
39 44 # Start up process:
40 45 reg = System.Diagnostics.Process.Start(psi)
41 46
42 47 def getoutput(cmd):
43 48 """
44 49 getoutput(cmd) should work in a cli environment on Mac OSX, Linux,
45 50 and Windows
46 51 """
47 52 psi = System.Diagnostics.ProcessStartInfo(cmd)
48 53 psi.RedirectStandardOutput = True
49 54 psi.RedirectStandardError = True
50 55 psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
51 56 psi.UseShellExecute = False
52 57 # Start up process:
53 58 reg = System.Diagnostics.Process.Start(psi)
54 59 myOutput = reg.StandardOutput
55 60 output = myOutput.ReadToEnd()
56 61 myError = reg.StandardError
57 62 error = myError.ReadToEnd()
58 63 return output
59 64
60 65 def check_pid(pid):
61 66 """
62 67 Check if a process with the given PID (pid) exists
63 68 """
64 69 try:
65 70 System.Diagnostics.Process.GetProcessById(pid)
66 71 # process with given pid is running
67 72 return True
68 73 except System.InvalidOperationException:
69 74 # process wasn't started by this object (but is running)
70 75 return True
71 76 except System.ArgumentException:
72 77 # process with given pid isn't running
73 78 return False
@@ -1,122 +1,121
1 1 """
2 2 Tools to open .py files as Unicode, using the encoding specified within the file,
3 3 as per PEP 263.
4 4
5 5 Much of the code is taken from the tokenize module in Python 3.2.
6 6 """
7 7
8 8 import io
9 9 from io import TextIOWrapper, BytesIO
10 import os.path
11 10 import re
12 11 from tokenize import open, detect_encoding
13 12
14 13 cookie_re = re.compile(r"coding[:=]\s*([-\w.]+)", re.UNICODE)
15 14 cookie_comment_re = re.compile(r"^\s*#.*coding[:=]\s*([-\w.]+)", re.UNICODE)
16 15
17 16 def source_to_unicode(txt, errors='replace', skip_encoding_cookie=True):
18 17 """Converts a bytes string with python source code to unicode.
19 18
20 19 Unicode strings are passed through unchanged. Byte strings are checked
21 20 for the python source file encoding cookie to determine encoding.
22 21 txt can be either a bytes buffer or a string containing the source
23 22 code.
24 23 """
25 24 if isinstance(txt, str):
26 25 return txt
27 26 if isinstance(txt, bytes):
28 27 buffer = BytesIO(txt)
29 28 else:
30 29 buffer = txt
31 30 try:
32 31 encoding, _ = detect_encoding(buffer.readline)
33 32 except SyntaxError:
34 33 encoding = "ascii"
35 34 buffer.seek(0)
36 35 text = TextIOWrapper(buffer, encoding, errors=errors, line_buffering=True)
37 36 text.mode = 'r'
38 37 if skip_encoding_cookie:
39 38 return u"".join(strip_encoding_cookie(text))
40 39 else:
41 40 return text.read()
42 41
43 42 def strip_encoding_cookie(filelike):
44 43 """Generator to pull lines from a text-mode file, skipping the encoding
45 44 cookie if it is found in the first two lines.
46 45 """
47 46 it = iter(filelike)
48 47 try:
49 48 first = next(it)
50 49 if not cookie_comment_re.match(first):
51 50 yield first
52 51 second = next(it)
53 52 if not cookie_comment_re.match(second):
54 53 yield second
55 54 except StopIteration:
56 55 return
57 56
58 57 for line in it:
59 58 yield line
60 59
61 60 def read_py_file(filename, skip_encoding_cookie=True):
62 61 """Read a Python file, using the encoding declared inside the file.
63 62
64 63 Parameters
65 64 ----------
66 65 filename : str
67 66 The path to the file to read.
68 67 skip_encoding_cookie : bool
69 68 If True (the default), and the encoding declaration is found in the first
70 69 two lines, that line will be excluded from the output - compiling a
71 70 unicode string with an encoding declaration is a SyntaxError in Python 2.
72 71
73 72 Returns
74 73 -------
75 74 A unicode string containing the contents of the file.
76 75 """
77 76 with open(filename) as f: # the open function defined in this module.
78 77 if skip_encoding_cookie:
79 78 return "".join(strip_encoding_cookie(f))
80 79 else:
81 80 return f.read()
82 81
83 82 def read_py_url(url, errors='replace', skip_encoding_cookie=True):
84 83 """Read a Python file from a URL, using the encoding declared inside the file.
85 84
86 85 Parameters
87 86 ----------
88 87 url : str
89 88 The URL from which to fetch the file.
90 89 errors : str
91 90 How to handle decoding errors in the file. Options are the same as for
92 91 bytes.decode(), but here 'replace' is the default.
93 92 skip_encoding_cookie : bool
94 93 If True (the default), and the encoding declaration is found in the first
95 94 two lines, that line will be excluded from the output - compiling a
96 95 unicode string with an encoding declaration is a SyntaxError in Python 2.
97 96
98 97 Returns
99 98 -------
100 99 A unicode string containing the contents of the file.
101 100 """
102 101 # Deferred import for faster start
103 102 from urllib.request import urlopen
104 103 response = urlopen(url)
105 104 buffer = io.BytesIO(response.read())
106 105 return source_to_unicode(buffer, errors, skip_encoding_cookie)
107 106
108 107 def _list_readline(x):
109 108 """Given a list, returns a readline() function that returns the next element
110 109 with each call.
111 110 """
112 111 x = iter(x)
113 112 def readline():
114 113 return next(x)
115 114 return readline
116 115
117 116 # Code for going between .py files and cached .pyc files ----------------------
118 117 try:
119 118 from importlib.util import source_from_cache, cache_from_source
120 119 except ImportError :
121 120 ## deprecated since 3.4
122 121 from imp import source_from_cache, cache_from_source
@@ -1,60 +1,57
1 1 """ This module contains classes - NamedFileInTemporaryDirectory, TemporaryWorkingDirectory.
2 2
3 3 These classes add extra features such as creating a named file in temporary directory and
4 4 creating a context manager for the working directory which is also temporary.
5 5 """
6 6
7 7 import os as _os
8 import warnings as _warnings
9 import sys as _sys
10
11 8 from tempfile import TemporaryDirectory
12 9
10
13 11 class NamedFileInTemporaryDirectory(object):
14 12
15 13 def __init__(self, filename, mode='w+b', bufsize=-1, **kwds):
16 14 """
17 15 Open a file named `filename` in a temporary directory.
18 16
19 17 This context manager is preferred over `NamedTemporaryFile` in
20 18 stdlib `tempfile` when one needs to reopen the file.
21 19
22 20 Arguments `mode` and `bufsize` are passed to `open`.
23 21 Rest of the arguments are passed to `TemporaryDirectory`.
24 22
25 23 """
26 24 self._tmpdir = TemporaryDirectory(**kwds)
27 25 path = _os.path.join(self._tmpdir.name, filename)
28 26 self.file = open(path, mode, bufsize)
29 27
30 28 def cleanup(self):
31 29 self.file.close()
32 30 self._tmpdir.cleanup()
33 31
34 32 __del__ = cleanup
35 33
36 34 def __enter__(self):
37 35 return self.file
38 36
39 37 def __exit__(self, type, value, traceback):
40 38 self.cleanup()
41 39
42 40
43 41 class TemporaryWorkingDirectory(TemporaryDirectory):
44 42 """
45 43 Creates a temporary directory and sets the cwd to that directory.
46 44 Automatically reverts to previous cwd upon cleanup.
47 45 Usage example:
48 46
49 47 with TemporaryWorkingDirectory() as tmpdir:
50 48 ...
51 49 """
52 50 def __enter__(self):
53 51 self.old_wd = _os.getcwd()
54 52 _os.chdir(self.name)
55 53 return super(TemporaryWorkingDirectory, self).__enter__()
56 54
57 55 def __exit__(self, exc, value, tb):
58 56 _os.chdir(self.old_wd)
59 57 return super(TemporaryWorkingDirectory, self).__exit__(exc, value, tb)
60
@@ -1,116 +1,110
1 1 # encoding: utf-8
2 2 """
3 3 Utilities for working with terminals.
4 4
5 5 Authors:
6 6
7 7 * Brian E. Granger
8 8 * Fernando Perez
9 9 * Alexander Belchenko (e-mail: bialix AT ukr.net)
10 10 """
11 11
12 12 # Copyright (c) IPython Development Team.
13 13 # Distributed under the terms of the Modified BSD License.
14 14
15 15 import os
16 16 import sys
17 17 import warnings
18 18 from shutil import get_terminal_size as _get_terminal_size
19 19
20 from . import py3compat
21
22 #-----------------------------------------------------------------------------
23 # Code
24 #-----------------------------------------------------------------------------
25
26 20 # This variable is part of the expected API of the module:
27 21 ignore_termtitle = True
28 22
29 23
30 24
31 25 if os.name == 'posix':
32 26 def _term_clear():
33 27 os.system('clear')
34 28 elif sys.platform == 'win32':
35 29 def _term_clear():
36 30 os.system('cls')
37 31 else:
38 32 def _term_clear():
39 33 pass
40 34
41 35
42 36
43 37 def toggle_set_term_title(val):
44 38 """Control whether set_term_title is active or not.
45 39
46 40 set_term_title() allows writing to the console titlebar. In embedded
47 41 widgets this can cause problems, so this call can be used to toggle it on
48 42 or off as needed.
49 43
50 44 The default state of the module is for the function to be disabled.
51 45
52 46 Parameters
53 47 ----------
54 48 val : bool
55 49 If True, set_term_title() actually writes to the terminal (using the
56 50 appropriate platform-specific module). If False, it is a no-op.
57 51 """
58 52 global ignore_termtitle
59 53 ignore_termtitle = not(val)
60 54
61 55
62 56 def _set_term_title(*args,**kw):
63 57 """Dummy no-op."""
64 58 pass
65 59
66 60
67 61 def _set_term_title_xterm(title):
68 62 """ Change virtual terminal title in xterm-workalikes """
69 63 sys.stdout.write('\033]0;%s\007' % title)
70 64
71 65 if os.name == 'posix':
72 66 TERM = os.environ.get('TERM','')
73 67 if TERM.startswith('xterm'):
74 68 _set_term_title = _set_term_title_xterm
75 69 elif sys.platform == 'win32':
76 70 try:
77 71 import ctypes
78 72
79 73 SetConsoleTitleW = ctypes.windll.kernel32.SetConsoleTitleW
80 74 SetConsoleTitleW.argtypes = [ctypes.c_wchar_p]
81 75
82 76 def _set_term_title(title):
83 77 """Set terminal title using ctypes to access the Win32 APIs."""
84 78 SetConsoleTitleW(title)
85 79 except ImportError:
86 80 def _set_term_title(title):
87 81 """Set terminal title using the 'title' command."""
88 82 global ignore_termtitle
89 83
90 84 try:
91 85 # Cannot be on network share when issuing system commands
92 86 curr = os.getcwd()
93 87 os.chdir("C:")
94 88 ret = os.system("title " + title)
95 89 finally:
96 90 os.chdir(curr)
97 91 if ret:
98 92 # non-zero return code signals error, don't try again
99 93 ignore_termtitle = True
100 94
101 95
102 96 def set_term_title(title):
103 97 """Set terminal title using the necessary platform-dependent calls."""
104 98 if ignore_termtitle:
105 99 return
106 100 _set_term_title(title)
107 101
108 102
109 103 def freeze_term_title():
110 104 warnings.warn("This function is deprecated, use toggle_set_term_title()")
111 105 global ignore_termtitle
112 106 ignore_termtitle = True
113 107
114 108
115 109 def get_terminal_size(defaultx=80, defaulty=25):
116 110 return _get_terminal_size((defaultx, defaulty))
@@ -1,15 +1,13
1 1 import sys
2 2 import warnings
3 3
4 import nose.tools as nt
5
6 from IPython.utils.capture import capture_output
7 4 from IPython.utils.shimmodule import ShimWarning
8 5
6
9 7 def test_shim_warning():
10 8 sys.modules.pop('IPython.config', None)
11 9 with warnings.catch_warnings(record=True) as w:
12 10 warnings.simplefilter("always")
13 11 import IPython.config
14 12 assert len(w) == 1
15 13 assert issubclass(w[-1].category, ShimWarning)
General Comments 0
You need to be logged in to leave comments. Login now