Show More
@@ -4,6 +4,7 b' from __future__ import print_function' | |||||
4 | from collections import namedtuple |
|
4 | from collections import namedtuple | |
5 | import sys |
|
5 | import sys | |
6 | import time |
|
6 | import time | |
|
7 | import uuid | |||
7 |
|
8 | |||
8 | # System library imports |
|
9 | # System library imports | |
9 | from pygments.lexers import PythonLexer |
|
10 | from pygments.lexers import PythonLexer | |
@@ -137,6 +138,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
137 | self._input_splitter = self._input_splitter_class(input_mode='cell') |
|
138 | self._input_splitter = self._input_splitter_class(input_mode='cell') | |
138 | self._kernel_manager = None |
|
139 | self._kernel_manager = None | |
139 | self._request_info = {} |
|
140 | self._request_info = {} | |
|
141 | self._callback_dict = {} | |||
140 |
|
142 | |||
141 | # Configure the ConsoleWidget. |
|
143 | # Configure the ConsoleWidget. | |
142 | self.tab_width = 4 |
|
144 | self.tab_width = 4 | |
@@ -311,6 +313,62 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
311 | cursor.movePosition(QtGui.QTextCursor.Left, n=len(text)) |
|
313 | cursor.movePosition(QtGui.QTextCursor.Left, n=len(text)) | |
312 | self._complete_with_items(cursor, rep['content']['matches']) |
|
314 | self._complete_with_items(cursor, rep['content']['matches']) | |
313 |
|
315 | |||
|
316 | def _silent_exec_callback(self, expr, callback): | |||
|
317 | """Silently execute `expr` in the kernel and call `callback` with reply | |||
|
318 | ||||
|
319 | the `expr` is evaluated silently in the kernel (without) output in | |||
|
320 | the frontend. Call `callback` with the | |||
|
321 | `repr <http://docs.python.org/library/functions.html#repr> `_ as first argument | |||
|
322 | ||||
|
323 | Parameters | |||
|
324 | ---------- | |||
|
325 | expr : string | |||
|
326 | valid string to be executed by the kernel. | |||
|
327 | callback : function | |||
|
328 | function accepting one arguement, as a string. The string will be | |||
|
329 | the `repr` of the result of evaluating `expr` | |||
|
330 | ||||
|
331 | The `callback` is called with the 'repr()' of the result of `expr` as | |||
|
332 | first argument. To get the object, do 'eval()' onthe passed value. | |||
|
333 | ||||
|
334 | See Also | |||
|
335 | -------- | |||
|
336 | _handle_exec_callback : private method, deal with calling callback with reply | |||
|
337 | ||||
|
338 | """ | |||
|
339 | ||||
|
340 | # generate uuid, which would be used as a indication of wether or not | |||
|
341 | # the unique request originate from here (can use msg id ?) | |||
|
342 | local_uuid = str(uuid.uuid1()) | |||
|
343 | msg_id = self.kernel_manager.shell_channel.execute('', | |||
|
344 | silent=True, user_expressions={ local_uuid:expr }) | |||
|
345 | self._callback_dict[local_uuid] = callback | |||
|
346 | self._request_info['execute'] = self._ExecutionRequest(msg_id, 'silent_exec_callback') | |||
|
347 | ||||
|
348 | def _handle_exec_callback(self, msg): | |||
|
349 | """Execute `callback` corresonding to `msg` reply, after ``_silent_exec_callback`` | |||
|
350 | ||||
|
351 | Parameters | |||
|
352 | ---------- | |||
|
353 | msg : raw message send by the kernel containing an `user_expressions` | |||
|
354 | and having a 'silent_exec_callback' kind. | |||
|
355 | ||||
|
356 | Notes | |||
|
357 | ----- | |||
|
358 | This fonction will look for a `callback` associated with the | |||
|
359 | corresponding message id. Association has been made by | |||
|
360 | `_silent_exec_callback`. `callback` is then called with the `repr()` | |||
|
361 | of the value of corresponding `user_expressions` as argument. | |||
|
362 | `callback` is then removed from the known list so that any message | |||
|
363 | coming again with the same id won't trigger it. | |||
|
364 | ||||
|
365 | """ | |||
|
366 | ||||
|
367 | user_exp = msg['content']['user_expressions'] | |||
|
368 | for expression in user_exp: | |||
|
369 | if expression in self._callback_dict: | |||
|
370 | self._callback_dict.pop(expression)(user_exp[expression]) | |||
|
371 | ||||
314 | def _handle_execute_reply(self, msg): |
|
372 | def _handle_execute_reply(self, msg): | |
315 | """ Handles replies for code execution. |
|
373 | """ Handles replies for code execution. | |
316 | """ |
|
374 | """ | |
@@ -342,6 +400,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):' | |||||
342 |
|
400 | |||
343 | self._show_interpreter_prompt_for_reply(msg) |
|
401 | self._show_interpreter_prompt_for_reply(msg) | |
344 | self.executed.emit(msg) |
|
402 | self.executed.emit(msg) | |
|
403 | elif info and info.id == msg['parent_header']['msg_id'] and \ | |||
|
404 | info.kind == 'silent_exec_callback' and not self._hidden: | |||
|
405 | self._handle_exec_callback(msg) | |||
345 | else: |
|
406 | else: | |
346 | super(FrontendWidget, self)._handle_execute_reply(msg) |
|
407 | super(FrontendWidget, self)._handle_execute_reply(msg) | |
347 |
|
408 |
@@ -20,6 +20,7 b' Authors:' | |||||
20 |
|
20 | |||
21 | # stdlib imports |
|
21 | # stdlib imports | |
22 | import sys |
|
22 | import sys | |
|
23 | import re | |||
23 | import webbrowser |
|
24 | import webbrowser | |
24 | from threading import Thread |
|
25 | from threading import Thread | |
25 |
|
26 | |||
@@ -544,10 +545,89 b' class MainWindow(QtGui.QMainWindow):' | |||||
544 |
|
545 | |||
545 | self.kernel_menu.addSeparator() |
|
546 | self.kernel_menu.addSeparator() | |
546 |
|
547 | |||
|
548 | def _make_dynamic_magic(self,magic): | |||
|
549 | """Return a function `fun` that will execute `magic` on active frontend. | |||
|
550 | ||||
|
551 | Parameters | |||
|
552 | ---------- | |||
|
553 | magic : string | |||
|
554 | string that will be executed as is when the returned function is called | |||
|
555 | ||||
|
556 | Returns | |||
|
557 | ------- | |||
|
558 | fun : function | |||
|
559 | function with no parameters, when called will execute `magic` on the | |||
|
560 | current active frontend at call time | |||
|
561 | ||||
|
562 | See Also | |||
|
563 | -------- | |||
|
564 | populate_all_magic_menu : generate the "All Magics..." menu | |||
|
565 | ||||
|
566 | Notes | |||
|
567 | ----- | |||
|
568 | `fun` execute `magic` an active frontend at the moment it is triggerd, | |||
|
569 | not the active frontend at the moment it has been created. | |||
|
570 | ||||
|
571 | This function is mostly used to create the "All Magics..." Menu at run time. | |||
|
572 | """ | |||
|
573 | # need to level nested function to be sure to past magic | |||
|
574 | # on active frontend **at run time**. | |||
|
575 | def inner_dynamic_magic(): | |||
|
576 | self.active_frontend.execute(magic) | |||
|
577 | inner_dynamic_magic.__name__ = "dynamics_magic_s" | |||
|
578 | return inner_dynamic_magic | |||
|
579 | ||||
|
580 | def populate_all_magic_menu(self, listofmagic=None): | |||
|
581 | """Clean "All Magics..." menu and repopulate it with `listofmagic` | |||
|
582 | ||||
|
583 | Parameters | |||
|
584 | ---------- | |||
|
585 | listofmagic : string, | |||
|
586 | repr() of a list of strings, send back by the kernel | |||
|
587 | ||||
|
588 | Notes | |||
|
589 | ----- | |||
|
590 | `listofmagic`is a repr() of list because it is fed with the result of | |||
|
591 | a 'user_expression' | |||
|
592 | """ | |||
|
593 | alm_magic_menu = self.all_magic_menu | |||
|
594 | alm_magic_menu.clear() | |||
|
595 | ||||
|
596 | # list of protected magic that don't like to be called without argument | |||
|
597 | # append '?' to the end to print the docstring when called from the menu | |||
|
598 | protected_magic = set(["more","less","load_ext","pycat","loadpy","save"]) | |||
|
599 | magics=re.findall('\w+', listofmagic) | |||
|
600 | for magic in magics: | |||
|
601 | if magic in protected_magic: | |||
|
602 | pmagic = '%s%s%s'%('%',magic,'?') | |||
|
603 | else: | |||
|
604 | pmagic = '%s%s'%('%',magic) | |||
|
605 | xaction = QtGui.QAction(pmagic, | |||
|
606 | self, | |||
|
607 | triggered=self._make_dynamic_magic(pmagic) | |||
|
608 | ) | |||
|
609 | alm_magic_menu.addAction(xaction) | |||
|
610 | ||||
|
611 | def update_all_magic_menu(self): | |||
|
612 | """ Update the list on magic in the "All Magics..." Menu | |||
|
613 | ||||
|
614 | Request the kernel with the list of availlable magic and populate the | |||
|
615 | menu with the list received back | |||
|
616 | ||||
|
617 | """ | |||
|
618 | # first define a callback which will get the list of all magic and put it in the menu. | |||
|
619 | self.active_frontend._silent_exec_callback('get_ipython().lsmagic()', self.populate_all_magic_menu) | |||
|
620 | ||||
547 | def init_magic_menu(self): |
|
621 | def init_magic_menu(self): | |
548 | self.magic_menu = self.menuBar().addMenu("&Magic") |
|
622 | self.magic_menu = self.menuBar().addMenu("&Magic") | |
549 | self.all_magic_menu = self.magic_menu.addMenu("&All Magics") |
|
623 | self.all_magic_menu = self.magic_menu.addMenu("&All Magics") | |
550 |
|
624 | |||
|
625 | # this action should not appear as it will be cleard when menu | |||
|
626 | # will be updated at first kernel response. | |||
|
627 | self.pop = QtGui.QAction("&Update All Magic Menu ", | |||
|
628 | self, triggered=self.update_all_magic_menu) | |||
|
629 | self.add_menu_action(self.all_magic_menu, self.pop) | |||
|
630 | ||||
551 | self.reset_action = QtGui.QAction("&Reset", |
|
631 | self.reset_action = QtGui.QAction("&Reset", | |
552 | self, |
|
632 | self, | |
553 | statusTip="Clear all varible from workspace", |
|
633 | statusTip="Clear all varible from workspace", | |
@@ -583,34 +663,7 b' class MainWindow(QtGui.QMainWindow):' | |||||
583 | statusTip="List interactive variable with detail", |
|
663 | statusTip="List interactive variable with detail", | |
584 | triggered=self.whos_magic_active_frontend) |
|
664 | triggered=self.whos_magic_active_frontend) | |
585 | self.add_menu_action(self.magic_menu, self.whos_action) |
|
665 | self.add_menu_action(self.magic_menu, self.whos_action) | |
586 |
|
666 | |||
587 | # allmagics submenu: |
|
|||
588 |
|
||||
589 | #for now this is just a copy and paste, but we should get this dynamically |
|
|||
590 | magiclist=["%alias", "%autocall", "%automagic", "%bookmark", "%cd", "%clear", |
|
|||
591 | "%colors", "%debug", "%dhist", "%dirs", "%doctest_mode", "%ed", "%edit", "%env", "%gui", |
|
|||
592 | "%guiref", "%hist", "%history", "%install_default_config", "%install_profiles", |
|
|||
593 | "%less", "%load_ext", "%loadpy", "%logoff", "%logon", "%logstart", "%logstate", |
|
|||
594 | "%logstop", "%lsmagic", "%macro", "%magic", "%man", "%more", "%notebook", "%page", |
|
|||
595 | "%pastebin", "%pdb", "%pdef", "%pdoc", "%pfile", "%pinfo", "%pinfo2", "%popd", "%pprint", |
|
|||
596 | "%precision", "%profile", "%prun", "%psearch", "%psource", "%pushd", "%pwd", "%pycat", |
|
|||
597 | "%pylab", "%quickref", "%recall", "%rehashx", "%reload_ext", "%rep", "%rerun", |
|
|||
598 | "%reset", "%reset_selective", "%run", "%save", "%sc", "%sx", "%tb", "%time", "%timeit", |
|
|||
599 | "%unalias", "%unload_ext", "%who", "%who_ls", "%whos", "%xdel", "%xmode"] |
|
|||
600 |
|
||||
601 | def make_dynamic_magic(i): |
|
|||
602 | def inner_dynamic_magic(): |
|
|||
603 | self.active_frontend.execute(i) |
|
|||
604 | inner_dynamic_magic.__name__ = "dynamics_magic_%s" % i |
|
|||
605 | return inner_dynamic_magic |
|
|||
606 |
|
||||
607 | for magic in magiclist: |
|
|||
608 | xaction = QtGui.QAction(magic, |
|
|||
609 | self, |
|
|||
610 | triggered=make_dynamic_magic(magic) |
|
|||
611 | ) |
|
|||
612 | self.all_magic_menu.addAction(xaction) |
|
|||
613 |
|
||||
614 | def init_window_menu(self): |
|
667 | def init_window_menu(self): | |
615 | self.window_menu = self.menuBar().addMenu("&Window") |
|
668 | self.window_menu = self.menuBar().addMenu("&Window") | |
616 | if sys.platform == 'darwin': |
|
669 | if sys.platform == 'darwin': |
@@ -451,6 +451,10 b' class IPythonQtConsoleApp(BaseIPythonApplication):' | |||||
451 | self.window.log = self.log |
|
451 | self.window.log = self.log | |
452 | self.window.add_tab_with_frontend(self.widget) |
|
452 | self.window.add_tab_with_frontend(self.widget) | |
453 | self.window.init_menu_bar() |
|
453 | self.window.init_menu_bar() | |
|
454 | ||||
|
455 | # we need to populate the 'Magic Menu' once the kernel has answer at least once | |||
|
456 | self.kernel_manager.shell_channel.first_reply.connect(self.window.pop.trigger) | |||
|
457 | ||||
454 | self.window.setWindowTitle('Python' if self.pure else 'IPython') |
|
458 | self.window.setWindowTitle('Python' if self.pure else 'IPython') | |
455 |
|
459 | |||
456 | def init_colors(self): |
|
460 | def init_colors(self): |
General Comments 0
You need to be logged in to leave comments.
Login now