magics.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. """Extra magics for terminal use."""
  2. # Copyright (c) IPython Development Team.
  3. # Distributed under the terms of the Modified BSD License.
  4. from logging import error
  5. import os
  6. import sys
  7. from IPython.core.error import TryNext, UsageError
  8. from IPython.core.magic import Magics, magics_class, line_magic
  9. from IPython.lib.clipboard import ClipboardEmpty
  10. from IPython.testing.skipdoctest import skip_doctest
  11. from IPython.utils.text import SList, strip_email_quotes
  12. from IPython.utils import py3compat
  13. def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False):
  14. """ Yield pasted lines until the user enters the given sentinel value.
  15. """
  16. if not quiet:
  17. print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \
  18. % sentinel)
  19. prompt = ":"
  20. else:
  21. prompt = ""
  22. while True:
  23. try:
  24. l = l_input(prompt)
  25. if l == sentinel:
  26. return
  27. else:
  28. yield l
  29. except EOFError:
  30. print('<EOF>')
  31. return
  32. @magics_class
  33. class TerminalMagics(Magics):
  34. def __init__(self, shell):
  35. super(TerminalMagics, self).__init__(shell)
  36. def store_or_execute(self, block, name, store_history=False):
  37. """ Execute a block, or store it in a variable, per the user's request.
  38. """
  39. if name:
  40. # If storing it for further editing
  41. self.shell.user_ns[name] = SList(block.splitlines())
  42. print("Block assigned to '%s'" % name)
  43. else:
  44. b = self.preclean_input(block)
  45. self.shell.user_ns['pasted_block'] = b
  46. self.shell.using_paste_magics = True
  47. try:
  48. self.shell.run_cell(b, store_history)
  49. finally:
  50. self.shell.using_paste_magics = False
  51. def preclean_input(self, block):
  52. lines = block.splitlines()
  53. while lines and not lines[0].strip():
  54. lines = lines[1:]
  55. return strip_email_quotes('\n'.join(lines))
  56. def rerun_pasted(self, name='pasted_block'):
  57. """ Rerun a previously pasted command.
  58. """
  59. b = self.shell.user_ns.get(name)
  60. # Sanity checks
  61. if b is None:
  62. raise UsageError('No previous pasted block available')
  63. if not isinstance(b, str):
  64. raise UsageError(
  65. "Variable 'pasted_block' is not a string, can't execute")
  66. print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b)))
  67. self.shell.run_cell(b)
  68. @line_magic
  69. def autoindent(self, parameter_s = ''):
  70. """Toggle autoindent on/off (deprecated)"""
  71. self.shell.set_autoindent()
  72. print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent])
  73. @skip_doctest
  74. @line_magic
  75. def cpaste(self, parameter_s=''):
  76. """Paste & execute a pre-formatted code block from clipboard.
  77. You must terminate the block with '--' (two minus-signs) or Ctrl-D
  78. alone on the line. You can also provide your own sentinel with '%paste
  79. -s %%' ('%%' is the new sentinel for this operation).
  80. The block is dedented prior to execution to enable execution of method
  81. definitions. '>' and '+' characters at the beginning of a line are
  82. ignored, to allow pasting directly from e-mails, diff files and
  83. doctests (the '...' continuation prompt is also stripped). The
  84. executed block is also assigned to variable named 'pasted_block' for
  85. later editing with '%edit pasted_block'.
  86. You can also pass a variable name as an argument, e.g. '%cpaste foo'.
  87. This assigns the pasted block to variable 'foo' as string, without
  88. dedenting or executing it (preceding >>> and + is still stripped)
  89. '%cpaste -r' re-executes the block previously entered by cpaste.
  90. '%cpaste -q' suppresses any additional output messages.
  91. Do not be alarmed by garbled output on Windows (it's a readline bug).
  92. Just press enter and type -- (and press enter again) and the block
  93. will be what was just pasted.
  94. Shell escapes are not supported (yet).
  95. See Also
  96. --------
  97. paste : automatically pull code from clipboard.
  98. Examples
  99. --------
  100. ::
  101. In [8]: %cpaste
  102. Pasting code; enter '--' alone on the line to stop.
  103. :>>> a = ["world!", "Hello"]
  104. :>>> print(" ".join(sorted(a)))
  105. :--
  106. Hello world!
  107. ::
  108. In [8]: %cpaste
  109. Pasting code; enter '--' alone on the line to stop.
  110. :>>> %alias_magic t timeit
  111. :>>> %t -n1 pass
  112. :--
  113. Created `%t` as an alias for `%timeit`.
  114. Created `%%t` as an alias for `%%timeit`.
  115. 354 ns ± 224 ns per loop (mean ± std. dev. of 7 runs, 1 loop each)
  116. """
  117. opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
  118. if 'r' in opts:
  119. self.rerun_pasted()
  120. return
  121. quiet = ('q' in opts)
  122. sentinel = opts.get('s', u'--')
  123. block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet))
  124. self.store_or_execute(block, name, store_history=True)
  125. @line_magic
  126. def paste(self, parameter_s=''):
  127. """Paste & execute a pre-formatted code block from clipboard.
  128. The text is pulled directly from the clipboard without user
  129. intervention and printed back on the screen before execution (unless
  130. the -q flag is given to force quiet mode).
  131. The block is dedented prior to execution to enable execution of method
  132. definitions. '>' and '+' characters at the beginning of a line are
  133. ignored, to allow pasting directly from e-mails, diff files and
  134. doctests (the '...' continuation prompt is also stripped). The
  135. executed block is also assigned to variable named 'pasted_block' for
  136. later editing with '%edit pasted_block'.
  137. You can also pass a variable name as an argument, e.g. '%paste foo'.
  138. This assigns the pasted block to variable 'foo' as string, without
  139. executing it (preceding >>> and + is still stripped).
  140. Options:
  141. -r: re-executes the block previously entered by cpaste.
  142. -q: quiet mode: do not echo the pasted text back to the terminal.
  143. IPython statements (magics, shell escapes) are not supported (yet).
  144. See Also
  145. --------
  146. cpaste : manually paste code into terminal until you mark its end.
  147. """
  148. opts, name = self.parse_options(parameter_s, 'rq', mode='string')
  149. if 'r' in opts:
  150. self.rerun_pasted()
  151. return
  152. try:
  153. block = self.shell.hooks.clipboard_get()
  154. except TryNext as clipboard_exc:
  155. message = getattr(clipboard_exc, 'args')
  156. if message:
  157. error(message[0])
  158. else:
  159. error('Could not get text from the clipboard.')
  160. return
  161. except ClipboardEmpty as e:
  162. raise UsageError("The clipboard appears to be empty") from e
  163. # By default, echo back to terminal unless quiet mode is requested
  164. if 'q' not in opts:
  165. sys.stdout.write(self.shell.pycolorize(block))
  166. if not block.endswith("\n"):
  167. sys.stdout.write("\n")
  168. sys.stdout.write("## -- End pasted text --\n")
  169. self.store_or_execute(block, name, store_history=True)
  170. # Class-level: add a '%cls' magic only on Windows
  171. if sys.platform == 'win32':
  172. @line_magic
  173. def cls(self, s):
  174. """Clear screen.
  175. """
  176. os.system("cls")