PageRenderTime 22ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/itmi_vcfqc_optimized_with_globus_transfer/pymodules/python2.7/lib/python/ipython-2.2.0-py2.7.egg/IPython/qt/console/ipython_widget.py

https://gitlab.com/pooja043/Globus_Docker_4
Python | 603 lines | 491 code | 33 blank | 79 comment | 34 complexity | 02d44984fec4ba5641e13b160a3015e8 MD5 | raw file
  1. """A FrontendWidget that emulates the interface of the console IPython.
  2. This supports the additional functionality provided by the IPython kernel.
  3. """
  4. #-----------------------------------------------------------------------------
  5. # Imports
  6. #-----------------------------------------------------------------------------
  7. # Standard library imports
  8. from collections import namedtuple
  9. import os.path
  10. import re
  11. from subprocess import Popen
  12. import sys
  13. import time
  14. from textwrap import dedent
  15. # System library imports
  16. from IPython.external.qt import QtCore, QtGui
  17. # Local imports
  18. from IPython.core.inputsplitter import IPythonInputSplitter
  19. from IPython.core.inputtransformer import ipy_prompt
  20. from IPython.utils.traitlets import Bool, Unicode
  21. from .frontend_widget import FrontendWidget
  22. from . import styles
  23. #-----------------------------------------------------------------------------
  24. # Constants
  25. #-----------------------------------------------------------------------------
  26. # Default strings to build and display input and output prompts (and separators
  27. # in between)
  28. default_in_prompt = 'In [<span class="in-prompt-number">%i</span>]: '
  29. default_out_prompt = 'Out[<span class="out-prompt-number">%i</span>]: '
  30. default_input_sep = '\n'
  31. default_output_sep = ''
  32. default_output_sep2 = ''
  33. # Base path for most payload sources.
  34. zmq_shell_source = 'IPython.kernel.zmq.zmqshell.ZMQInteractiveShell'
  35. if sys.platform.startswith('win'):
  36. default_editor = 'notepad'
  37. else:
  38. default_editor = ''
  39. #-----------------------------------------------------------------------------
  40. # IPythonWidget class
  41. #-----------------------------------------------------------------------------
  42. class IPythonWidget(FrontendWidget):
  43. """ A FrontendWidget for an IPython kernel.
  44. """
  45. # If set, the 'custom_edit_requested(str, int)' signal will be emitted when
  46. # an editor is needed for a file. This overrides 'editor' and 'editor_line'
  47. # settings.
  48. custom_edit = Bool(False)
  49. custom_edit_requested = QtCore.Signal(object, object)
  50. editor = Unicode(default_editor, config=True,
  51. help="""
  52. A command for invoking a system text editor. If the string contains a
  53. {filename} format specifier, it will be used. Otherwise, the filename
  54. will be appended to the end the command.
  55. """)
  56. editor_line = Unicode(config=True,
  57. help="""
  58. The editor command to use when a specific line number is requested. The
  59. string should contain two format specifiers: {line} and {filename}. If
  60. this parameter is not specified, the line number option to the %edit
  61. magic will be ignored.
  62. """)
  63. style_sheet = Unicode(config=True,
  64. help="""
  65. A CSS stylesheet. The stylesheet can contain classes for:
  66. 1. Qt: QPlainTextEdit, QFrame, QWidget, etc
  67. 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
  68. 3. IPython: .error, .in-prompt, .out-prompt, etc
  69. """)
  70. syntax_style = Unicode(config=True,
  71. help="""
  72. If not empty, use this Pygments style for syntax highlighting.
  73. Otherwise, the style sheet is queried for Pygments style
  74. information.
  75. """)
  76. # Prompts.
  77. in_prompt = Unicode(default_in_prompt, config=True)
  78. out_prompt = Unicode(default_out_prompt, config=True)
  79. input_sep = Unicode(default_input_sep, config=True)
  80. output_sep = Unicode(default_output_sep, config=True)
  81. output_sep2 = Unicode(default_output_sep2, config=True)
  82. # FrontendWidget protected class variables.
  83. _input_splitter_class = IPythonInputSplitter
  84. _prompt_transformer = IPythonInputSplitter(physical_line_transforms=[ipy_prompt()],
  85. logical_line_transforms=[],
  86. python_line_transforms=[],
  87. )
  88. # IPythonWidget protected class variables.
  89. _PromptBlock = namedtuple('_PromptBlock', ['block', 'length', 'number'])
  90. _payload_source_edit = 'edit_magic'
  91. _payload_source_exit = 'ask_exit'
  92. _payload_source_next_input = 'set_next_input'
  93. _payload_source_page = 'page'
  94. _retrying_history_request = False
  95. #---------------------------------------------------------------------------
  96. # 'object' interface
  97. #---------------------------------------------------------------------------
  98. def __init__(self, *args, **kw):
  99. super(IPythonWidget, self).__init__(*args, **kw)
  100. # IPythonWidget protected variables.
  101. self._payload_handlers = {
  102. self._payload_source_edit : self._handle_payload_edit,
  103. self._payload_source_exit : self._handle_payload_exit,
  104. self._payload_source_page : self._handle_payload_page,
  105. self._payload_source_next_input : self._handle_payload_next_input }
  106. self._previous_prompt_obj = None
  107. self._keep_kernel_on_exit = None
  108. # Initialize widget styling.
  109. if self.style_sheet:
  110. self._style_sheet_changed()
  111. self._syntax_style_changed()
  112. else:
  113. self.set_default_style()
  114. self._guiref_loaded = False
  115. #---------------------------------------------------------------------------
  116. # 'BaseFrontendMixin' abstract interface
  117. #---------------------------------------------------------------------------
  118. def _handle_complete_reply(self, rep):
  119. """ Reimplemented to support IPython's improved completion machinery.
  120. """
  121. self.log.debug("complete: %s", rep.get('content', ''))
  122. cursor = self._get_cursor()
  123. info = self._request_info.get('complete')
  124. if info and info.id == rep['parent_header']['msg_id'] and \
  125. info.pos == cursor.position():
  126. matches = rep['content']['matches']
  127. text = rep['content']['matched_text']
  128. offset = len(text)
  129. # Clean up matches with period and path separators if the matched
  130. # text has not been transformed. This is done by truncating all
  131. # but the last component and then suitably decreasing the offset
  132. # between the current cursor position and the start of completion.
  133. if len(matches) > 1 and matches[0][:offset] == text:
  134. parts = re.split(r'[./\\]', text)
  135. sep_count = len(parts) - 1
  136. if sep_count:
  137. chop_length = sum(map(len, parts[:sep_count])) + sep_count
  138. matches = [ match[chop_length:] for match in matches ]
  139. offset -= chop_length
  140. # Move the cursor to the start of the match and complete.
  141. cursor.movePosition(QtGui.QTextCursor.Left, n=offset)
  142. self._complete_with_items(cursor, matches)
  143. def _handle_execute_reply(self, msg):
  144. """ Reimplemented to support prompt requests.
  145. """
  146. msg_id = msg['parent_header'].get('msg_id')
  147. info = self._request_info['execute'].get(msg_id)
  148. if info and info.kind == 'prompt':
  149. content = msg['content']
  150. if content['status'] == 'aborted':
  151. self._show_interpreter_prompt()
  152. else:
  153. number = content['execution_count'] + 1
  154. self._show_interpreter_prompt(number)
  155. self._request_info['execute'].pop(msg_id)
  156. else:
  157. super(IPythonWidget, self)._handle_execute_reply(msg)
  158. def _handle_history_reply(self, msg):
  159. """ Implemented to handle history tail replies, which are only supported
  160. by the IPython kernel.
  161. """
  162. content = msg['content']
  163. if 'history' not in content:
  164. self.log.error("History request failed: %r"%content)
  165. if content.get('status', '') == 'aborted' and \
  166. not self._retrying_history_request:
  167. # a *different* action caused this request to be aborted, so
  168. # we should try again.
  169. self.log.error("Retrying aborted history request")
  170. # prevent multiple retries of aborted requests:
  171. self._retrying_history_request = True
  172. # wait out the kernel's queue flush, which is currently timed at 0.1s
  173. time.sleep(0.25)
  174. self.kernel_client.shell_channel.history(hist_access_type='tail',n=1000)
  175. else:
  176. self._retrying_history_request = False
  177. return
  178. # reset retry flag
  179. self._retrying_history_request = False
  180. history_items = content['history']
  181. self.log.debug("Received history reply with %i entries", len(history_items))
  182. items = []
  183. last_cell = u""
  184. for _, _, cell in history_items:
  185. cell = cell.rstrip()
  186. if cell != last_cell:
  187. items.append(cell)
  188. last_cell = cell
  189. self._set_history(items)
  190. def _handle_pyout(self, msg):
  191. """ Reimplemented for IPython-style "display hook".
  192. """
  193. self.log.debug("pyout: %s", msg.get('content', ''))
  194. if not self._hidden and self._is_from_this_session(msg):
  195. self.flush_clearoutput()
  196. content = msg['content']
  197. prompt_number = content.get('execution_count', 0)
  198. data = content['data']
  199. if 'text/html' in data:
  200. self._append_plain_text(self.output_sep, True)
  201. self._append_html(self._make_out_prompt(prompt_number), True)
  202. html = data['text/html']
  203. self._append_plain_text('\n', True)
  204. self._append_html(html + self.output_sep2, True)
  205. elif 'text/plain' in data:
  206. self._append_plain_text(self.output_sep, True)
  207. self._append_html(self._make_out_prompt(prompt_number), True)
  208. text = data['text/plain']
  209. # If the repr is multiline, make sure we start on a new line,
  210. # so that its lines are aligned.
  211. if "\n" in text and not self.output_sep.endswith("\n"):
  212. self._append_plain_text('\n', True)
  213. self._append_plain_text(text + self.output_sep2, True)
  214. def _handle_display_data(self, msg):
  215. """ The base handler for the ``display_data`` message.
  216. """
  217. self.log.debug("display: %s", msg.get('content', ''))
  218. # For now, we don't display data from other frontends, but we
  219. # eventually will as this allows all frontends to monitor the display
  220. # data. But we need to figure out how to handle this in the GUI.
  221. if not self._hidden and self._is_from_this_session(msg):
  222. self.flush_clearoutput()
  223. source = msg['content']['source']
  224. data = msg['content']['data']
  225. metadata = msg['content']['metadata']
  226. # In the regular IPythonWidget, we simply print the plain text
  227. # representation.
  228. if 'text/html' in data:
  229. html = data['text/html']
  230. self._append_html(html, True)
  231. elif 'text/plain' in data:
  232. text = data['text/plain']
  233. self._append_plain_text(text, True)
  234. # This newline seems to be needed for text and html output.
  235. self._append_plain_text(u'\n', True)
  236. def _handle_kernel_info_reply(self, rep):
  237. """ Handle kernel info replies.
  238. """
  239. if not self._guiref_loaded:
  240. if rep['content'].get('language') == 'python':
  241. self._load_guiref_magic()
  242. self._guiref_loaded = True
  243. def _started_channels(self):
  244. """Reimplemented to make a history request and load %guiref."""
  245. super(IPythonWidget, self)._started_channels()
  246. # The reply will trigger %guiref load provided language=='python'
  247. self.kernel_client.kernel_info()
  248. self.kernel_client.shell_channel.history(hist_access_type='tail',
  249. n=1000)
  250. def _started_kernel(self):
  251. """Load %guiref when the kernel starts (if channels are also started).
  252. Principally triggered by kernel restart.
  253. """
  254. if self.kernel_client.shell_channel is not None:
  255. self._load_guiref_magic()
  256. def _load_guiref_magic(self):
  257. """Load %guiref magic."""
  258. self.kernel_client.shell_channel.execute('\n'.join([
  259. "try:",
  260. " _usage",
  261. "except:",
  262. " from IPython.core import usage as _usage",
  263. " get_ipython().register_magic_function(_usage.page_guiref, 'line', 'guiref')",
  264. " del _usage",
  265. ]), silent=True)
  266. #---------------------------------------------------------------------------
  267. # 'ConsoleWidget' public interface
  268. #---------------------------------------------------------------------------
  269. #---------------------------------------------------------------------------
  270. # 'FrontendWidget' public interface
  271. #---------------------------------------------------------------------------
  272. def execute_file(self, path, hidden=False):
  273. """ Reimplemented to use the 'run' magic.
  274. """
  275. # Use forward slashes on Windows to avoid escaping each separator.
  276. if sys.platform == 'win32':
  277. path = os.path.normpath(path).replace('\\', '/')
  278. # Perhaps we should not be using %run directly, but while we
  279. # are, it is necessary to quote or escape filenames containing spaces
  280. # or quotes.
  281. # In earlier code here, to minimize escaping, we sometimes quoted the
  282. # filename with single quotes. But to do this, this code must be
  283. # platform-aware, because run uses shlex rather than python string
  284. # parsing, so that:
  285. # * In Win: single quotes can be used in the filename without quoting,
  286. # and we cannot use single quotes to quote the filename.
  287. # * In *nix: we can escape double quotes in a double quoted filename,
  288. # but can't escape single quotes in a single quoted filename.
  289. # So to keep this code non-platform-specific and simple, we now only
  290. # use double quotes to quote filenames, and escape when needed:
  291. if ' ' in path or "'" in path or '"' in path:
  292. path = '"%s"' % path.replace('"', '\\"')
  293. self.execute('%%run %s' % path, hidden=hidden)
  294. #---------------------------------------------------------------------------
  295. # 'FrontendWidget' protected interface
  296. #---------------------------------------------------------------------------
  297. def _complete(self):
  298. """ Reimplemented to support IPython's improved completion machinery.
  299. """
  300. # We let the kernel split the input line, so we *always* send an empty
  301. # text field. Readline-based frontends do get a real text field which
  302. # they can use.
  303. text = ''
  304. # Send the completion request to the kernel
  305. msg_id = self.kernel_client.shell_channel.complete(
  306. text, # text
  307. self._get_input_buffer_cursor_line(), # line
  308. self._get_input_buffer_cursor_column(), # cursor_pos
  309. self.input_buffer) # block
  310. pos = self._get_cursor().position()
  311. info = self._CompletionRequest(msg_id, pos)
  312. self._request_info['complete'] = info
  313. def _process_execute_error(self, msg):
  314. """ Reimplemented for IPython-style traceback formatting.
  315. """
  316. content = msg['content']
  317. traceback = '\n'.join(content['traceback']) + '\n'
  318. if False:
  319. # FIXME: For now, tracebacks come as plain text, so we can't use
  320. # the html renderer yet. Once we refactor ultratb to produce
  321. # properly styled tracebacks, this branch should be the default
  322. traceback = traceback.replace(' ', '&nbsp;')
  323. traceback = traceback.replace('\n', '<br/>')
  324. ename = content['ename']
  325. ename_styled = '<span class="error">%s</span>' % ename
  326. traceback = traceback.replace(ename, ename_styled)
  327. self._append_html(traceback)
  328. else:
  329. # This is the fallback for now, using plain text with ansi escapes
  330. self._append_plain_text(traceback)
  331. def _process_execute_payload(self, item):
  332. """ Reimplemented to dispatch payloads to handler methods.
  333. """
  334. handler = self._payload_handlers.get(item['source'])
  335. if handler is None:
  336. # We have no handler for this type of payload, simply ignore it
  337. return False
  338. else:
  339. handler(item)
  340. return True
  341. def _show_interpreter_prompt(self, number=None):
  342. """ Reimplemented for IPython-style prompts.
  343. """
  344. # If a number was not specified, make a prompt number request.
  345. if number is None:
  346. msg_id = self.kernel_client.shell_channel.execute('', silent=True)
  347. info = self._ExecutionRequest(msg_id, 'prompt')
  348. self._request_info['execute'][msg_id] = info
  349. return
  350. # Show a new prompt and save information about it so that it can be
  351. # updated later if the prompt number turns out to be wrong.
  352. self._prompt_sep = self.input_sep
  353. self._show_prompt(self._make_in_prompt(number), html=True)
  354. block = self._control.document().lastBlock()
  355. length = len(self._prompt)
  356. self._previous_prompt_obj = self._PromptBlock(block, length, number)
  357. # Update continuation prompt to reflect (possibly) new prompt length.
  358. self._set_continuation_prompt(
  359. self._make_continuation_prompt(self._prompt), html=True)
  360. def _show_interpreter_prompt_for_reply(self, msg):
  361. """ Reimplemented for IPython-style prompts.
  362. """
  363. # Update the old prompt number if necessary.
  364. content = msg['content']
  365. # abort replies do not have any keys:
  366. if content['status'] == 'aborted':
  367. if self._previous_prompt_obj:
  368. previous_prompt_number = self._previous_prompt_obj.number
  369. else:
  370. previous_prompt_number = 0
  371. else:
  372. previous_prompt_number = content['execution_count']
  373. if self._previous_prompt_obj and \
  374. self._previous_prompt_obj.number != previous_prompt_number:
  375. block = self._previous_prompt_obj.block
  376. # Make sure the prompt block has not been erased.
  377. if block.isValid() and block.text():
  378. # Remove the old prompt and insert a new prompt.
  379. cursor = QtGui.QTextCursor(block)
  380. cursor.movePosition(QtGui.QTextCursor.Right,
  381. QtGui.QTextCursor.KeepAnchor,
  382. self._previous_prompt_obj.length)
  383. prompt = self._make_in_prompt(previous_prompt_number)
  384. self._prompt = self._insert_html_fetching_plain_text(
  385. cursor, prompt)
  386. # When the HTML is inserted, Qt blows away the syntax
  387. # highlighting for the line, so we need to rehighlight it.
  388. self._highlighter.rehighlightBlock(cursor.block())
  389. self._previous_prompt_obj = None
  390. # Show a new prompt with the kernel's estimated prompt number.
  391. self._show_interpreter_prompt(previous_prompt_number + 1)
  392. #---------------------------------------------------------------------------
  393. # 'IPythonWidget' interface
  394. #---------------------------------------------------------------------------
  395. def set_default_style(self, colors='lightbg'):
  396. """ Sets the widget style to the class defaults.
  397. Parameters
  398. ----------
  399. colors : str, optional (default lightbg)
  400. Whether to use the default IPython light background or dark
  401. background or B&W style.
  402. """
  403. colors = colors.lower()
  404. if colors=='lightbg':
  405. self.style_sheet = styles.default_light_style_sheet
  406. self.syntax_style = styles.default_light_syntax_style
  407. elif colors=='linux':
  408. self.style_sheet = styles.default_dark_style_sheet
  409. self.syntax_style = styles.default_dark_syntax_style
  410. elif colors=='nocolor':
  411. self.style_sheet = styles.default_bw_style_sheet
  412. self.syntax_style = styles.default_bw_syntax_style
  413. else:
  414. raise KeyError("No such color scheme: %s"%colors)
  415. #---------------------------------------------------------------------------
  416. # 'IPythonWidget' protected interface
  417. #---------------------------------------------------------------------------
  418. def _edit(self, filename, line=None):
  419. """ Opens a Python script for editing.
  420. Parameters
  421. ----------
  422. filename : str
  423. A path to a local system file.
  424. line : int, optional
  425. A line of interest in the file.
  426. """
  427. if self.custom_edit:
  428. self.custom_edit_requested.emit(filename, line)
  429. elif not self.editor:
  430. self._append_plain_text('No default editor available.\n'
  431. 'Specify a GUI text editor in the `IPythonWidget.editor` '
  432. 'configurable to enable the %edit magic')
  433. else:
  434. try:
  435. filename = '"%s"' % filename
  436. if line and self.editor_line:
  437. command = self.editor_line.format(filename=filename,
  438. line=line)
  439. else:
  440. try:
  441. command = self.editor.format()
  442. except KeyError:
  443. command = self.editor.format(filename=filename)
  444. else:
  445. command += ' ' + filename
  446. except KeyError:
  447. self._append_plain_text('Invalid editor command.\n')
  448. else:
  449. try:
  450. Popen(command, shell=True)
  451. except OSError:
  452. msg = 'Opening editor with command "%s" failed.\n'
  453. self._append_plain_text(msg % command)
  454. def _make_in_prompt(self, number):
  455. """ Given a prompt number, returns an HTML In prompt.
  456. """
  457. try:
  458. body = self.in_prompt % number
  459. except TypeError:
  460. # allow in_prompt to leave out number, e.g. '>>> '
  461. body = self.in_prompt
  462. return '<span class="in-prompt">%s</span>' % body
  463. def _make_continuation_prompt(self, prompt):
  464. """ Given a plain text version of an In prompt, returns an HTML
  465. continuation prompt.
  466. """
  467. end_chars = '...: '
  468. space_count = len(prompt.lstrip('\n')) - len(end_chars)
  469. body = '&nbsp;' * space_count + end_chars
  470. return '<span class="in-prompt">%s</span>' % body
  471. def _make_out_prompt(self, number):
  472. """ Given a prompt number, returns an HTML Out prompt.
  473. """
  474. body = self.out_prompt % number
  475. return '<span class="out-prompt">%s</span>' % body
  476. #------ Payload handlers --------------------------------------------------
  477. # Payload handlers with a generic interface: each takes the opaque payload
  478. # dict, unpacks it and calls the underlying functions with the necessary
  479. # arguments.
  480. def _handle_payload_edit(self, item):
  481. self._edit(item['filename'], item['line_number'])
  482. def _handle_payload_exit(self, item):
  483. self._keep_kernel_on_exit = item['keepkernel']
  484. self.exit_requested.emit(self)
  485. def _handle_payload_next_input(self, item):
  486. self.input_buffer = item['text']
  487. def _handle_payload_page(self, item):
  488. # Since the plain text widget supports only a very small subset of HTML
  489. # and we have no control over the HTML source, we only page HTML
  490. # payloads in the rich text widget.
  491. if item['html'] and self.kind == 'rich':
  492. self._page(item['html'], html=True)
  493. else:
  494. self._page(item['text'], html=False)
  495. #------ Trait change handlers --------------------------------------------
  496. def _style_sheet_changed(self):
  497. """ Set the style sheets of the underlying widgets.
  498. """
  499. self.setStyleSheet(self.style_sheet)
  500. if self._control is not None:
  501. self._control.document().setDefaultStyleSheet(self.style_sheet)
  502. bg_color = self._control.palette().window().color()
  503. self._ansi_processor.set_background_color(bg_color)
  504. if self._page_control is not None:
  505. self._page_control.document().setDefaultStyleSheet(self.style_sheet)
  506. def _syntax_style_changed(self):
  507. """ Set the style for the syntax highlighter.
  508. """
  509. if self._highlighter is None:
  510. # ignore premature calls
  511. return
  512. if self.syntax_style:
  513. self._highlighter.set_style(self.syntax_style)
  514. else:
  515. self._highlighter.set_style_sheet(self.style_sheet)
  516. #------ Trait default initializers -----------------------------------------
  517. def _banner_default(self):
  518. from IPython.core.usage import default_gui_banner
  519. return default_gui_banner