##// END OF EJS Templates
Backport PR #12809: Allow passing a custom CachingCompiler to the interactive shell
Sylvain Corlay -
Show More
@@ -99,7 +99,7 b' class CachingCompiler(codeop.Compile):'
99 99 Arguments are exactly the same as ast.parse (in the standard library),
100 100 and are passed to the built-in compile function."""
101 101 return compile(source, filename, symbol, self.flags | PyCF_ONLY_AST, 1)
102
102
103 103 def reset_compiler_flags(self):
104 104 """Reset compiler flags to default state."""
105 105 # This value is copied from codeop.Compile.__init__, so if that ever
@@ -112,25 +112,53 b' class CachingCompiler(codeop.Compile):'
112 112 """
113 113 return self.flags
114 114
115 def cache(self, code, number=0):
115 def get_code_name(self, raw_code, transformed_code, number):
116 """Compute filename given the code, and the cell number.
117
118 Parameters
119 ----------
120 raw_code : str
121 The raw cell code.
122 transformed_code : str
123 The executable Python source code to cache and compile.
124 number : int
125 A number which forms part of the code's name. Used for the execution
126 counter.
127
128 Returns
129 -------
130 The computed filename.
131 """
132 return code_name(transformed_code, number)
133
134 def cache(self, transformed_code, number=0, raw_code=None):
116 135 """Make a name for a block of code, and cache the code.
117 136
118 137 Parameters
119 138 ----------
120 code : str
121 The Python source code to cache.
139 transformed_code : str
140 The executable Python source code to cache and compile.
122 141 number : int
123 142 A number which forms part of the code's name. Used for the execution
124 143 counter.
144 raw_code : str
145 The raw code before transformation, if None, set to `transformed_code`.
125 146
126 147 Returns
127 148 -------
128 149 The name of the cached code (as a string). Pass this as the filename
129 150 argument to compilation, so that tracebacks are correctly hooked up.
130 151 """
131 name = code_name(code, number)
132 entry = (len(code), time.time(),
133 [line+'\n' for line in code.splitlines()], name)
152 if raw_code is None:
153 raw_code = transformed_code
154
155 name = self.get_code_name(raw_code, transformed_code, number)
156 entry = (
157 len(transformed_code),
158 time.time(),
159 [line + "\n" for line in transformed_code.splitlines()],
160 name,
161 )
134 162 linecache.cache[name] = entry
135 163 linecache._ipython_cache[name] = entry
136 164 return name
@@ -146,7 +174,7 b' class CachingCompiler(codeop.Compile):'
146 174 yield
147 175 finally:
148 176 # turn off only the bits we turned on so that something like
149 # __future__ that set flags stays.
177 # __future__ that set flags stays.
150 178 self.flags &= ~turn_on_bits
151 179
152 180
@@ -340,7 +340,7 b' class InteractiveShell(SingletonConfigurable):'
340 340 """An enhanced, interactive shell for Python."""
341 341
342 342 _instance = None
343
343
344 344 ast_transformers = List([], help=
345 345 """
346 346 A list of ast.NodeTransformer subclass instances, which will be applied
@@ -407,7 +407,7 b' class InteractiveShell(SingletonConfigurable):'
407 407 Enable magic commands to be called without the leading %.
408 408 """
409 409 ).tag(config=True)
410
410
411 411 banner1 = Unicode(default_banner,
412 412 help="""The part of the banner to be printed before the profile"""
413 413 ).tag(config=True)
@@ -443,7 +443,8 b' class InteractiveShell(SingletonConfigurable):'
443 443 display_formatter = Instance(DisplayFormatter, allow_none=True)
444 444 displayhook_class = Type(DisplayHook)
445 445 display_pub_class = Type(DisplayPublisher)
446
446 compiler_class = Type(CachingCompiler)
447
447 448 sphinxify_docstring = Bool(False, help=
448 449 """
449 450 Enables rich html representation of docstrings. (This requires the
@@ -534,7 +535,7 b' class InteractiveShell(SingletonConfigurable):'
534 535 ).tag(config=True)
535 536
536 537 # deprecated prompt traits:
537
538
538 539 prompt_in1 = Unicode('In [\\#]: ',
539 540 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
540 541 ).tag(config=True)
@@ -547,14 +548,14 b' class InteractiveShell(SingletonConfigurable):'
547 548 prompts_pad_left = Bool(True,
548 549 help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly."
549 550 ).tag(config=True)
550
551
551 552 @observe('prompt_in1', 'prompt_in2', 'prompt_out', 'prompt_pad_left')
552 553 def _prompt_trait_changed(self, change):
553 554 name = change['name']
554 555 warn("InteractiveShell.{name} is deprecated since IPython 4.0"
555 556 " and ignored since 5.0, set TerminalInteractiveShell.prompts"
556 557 " object directly.".format(name=name))
557
558
558 559 # protect against weird cases where self.config may not exist:
559 560
560 561 show_rewritten_input = Bool(True,
@@ -638,7 +639,7 b' class InteractiveShell(SingletonConfigurable):'
638 639 self.init_profile_dir(profile_dir)
639 640 self.init_instance_attrs()
640 641 self.init_environment()
641
642
642 643 # Check if we're in a virtualenv, and set up sys.path.
643 644 self.init_virtualenv()
644 645
@@ -748,7 +749,7 b' class InteractiveShell(SingletonConfigurable):'
748 749 self.more = False
749 750
750 751 # command compiler
751 self.compile = CachingCompiler()
752 self.compile = self.compiler_class()
752 753
753 754 # Make an empty namespace, which extension writers can rely on both
754 755 # existing and NEVER being used by ipython itself. This gives them a
@@ -975,7 +976,7 b' class InteractiveShell(SingletonConfigurable):'
975 976 #-------------------------------------------------------------------------
976 977 # Things related to the banner
977 978 #-------------------------------------------------------------------------
978
979
979 980 @property
980 981 def banner(self):
981 982 banner = self.banner1
@@ -989,7 +990,7 b' class InteractiveShell(SingletonConfigurable):'
989 990 if banner is None:
990 991 banner = self.banner
991 992 sys.stdout.write(banner)
992
993
993 994 #-------------------------------------------------------------------------
994 995 # Things related to hooks
995 996 #-------------------------------------------------------------------------
@@ -1006,10 +1007,10 b' class InteractiveShell(SingletonConfigurable):'
1006 1007 # default hooks have priority 100, i.e. low; user hooks should have
1007 1008 # 0-100 priority
1008 1009 self.set_hook(hook_name,getattr(hooks,hook_name), 100, _warn_deprecated=False)
1009
1010
1010 1011 if self.display_page:
1011 1012 self.set_hook('show_in_pager', page.as_hook(page.display_page), 90)
1012
1013
1013 1014 def set_hook(self,name,hook, priority=50, str_key=None, re_key=None,
1014 1015 _warn_deprecated=True):
1015 1016 """set_hook(name,hook) -> sets an internal IPython hook.
@@ -1073,7 +1074,7 b' class InteractiveShell(SingletonConfigurable):'
1073 1074 warn("ip.register_post_execute is deprecated, use "
1074 1075 "ip.events.register('post_run_cell', func) instead.", stacklevel=2)
1075 1076 self.events.register('post_run_cell', func)
1076
1077
1077 1078 def _clear_warning_registry(self):
1078 1079 # clear the warning registry, so that different code blocks with
1079 1080 # overlapping line number ranges don't cause spurious suppression of
@@ -1115,12 +1116,12 b' class InteractiveShell(SingletonConfigurable):'
1115 1116 else:
1116 1117 main_mod.__dict__.clear()
1117 1118 main_mod.__name__ = modname
1118
1119
1119 1120 main_mod.__file__ = filename
1120 1121 # It seems pydoc (and perhaps others) needs any module instance to
1121 1122 # implement a __nonzero__ method
1122 1123 main_mod.__nonzero__ = lambda : True
1123
1124
1124 1125 return main_mod
1125 1126
1126 1127 def clear_main_mod_cache(self):
@@ -1273,7 +1274,7 b' class InteractiveShell(SingletonConfigurable):'
1273 1274 'user_local':self.user_ns,
1274 1275 'builtin':builtin_mod.__dict__
1275 1276 }
1276
1277
1277 1278 @property
1278 1279 def user_global_ns(self):
1279 1280 return self.user_module.__dict__
@@ -1306,17 +1307,17 b' class InteractiveShell(SingletonConfigurable):'
1306 1307 user_ns.setdefault("__name__", "__main__")
1307 1308 user_module = DummyMod()
1308 1309 user_module.__dict__ = user_ns
1309
1310
1310 1311 if user_module is None:
1311 1312 user_module = types.ModuleType("__main__",
1312 1313 doc="Automatically created module for IPython interactive environment")
1313
1314
1314 1315 # We must ensure that __builtin__ (without the final 's') is always
1315 1316 # available and pointing to the __builtin__ *module*. For more details:
1316 1317 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1317 1318 user_module.__dict__.setdefault('__builtin__', builtin_mod)
1318 1319 user_module.__dict__.setdefault('__builtins__', builtin_mod)
1319
1320
1320 1321 if user_ns is None:
1321 1322 user_ns = user_module.__dict__
1322 1323
@@ -1372,7 +1373,7 b' class InteractiveShell(SingletonConfigurable):'
1372 1373 # For more details:
1373 1374 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1374 1375 ns = {}
1375
1376
1376 1377 # make global variables for user access to the histories
1377 1378 ns['_ih'] = self.history_manager.input_hist_parsed
1378 1379 ns['_oh'] = self.history_manager.output_hist
@@ -1385,7 +1386,7 b' class InteractiveShell(SingletonConfigurable):'
1385 1386
1386 1387 # Store myself as the public api!!!
1387 1388 ns['get_ipython'] = self.get_ipython
1388
1389
1389 1390 ns['exit'] = self.exiter
1390 1391 ns['quit'] = self.exiter
1391 1392
@@ -1399,7 +1400,7 b' class InteractiveShell(SingletonConfigurable):'
1399 1400
1400 1401 # Finally, update the real user's namespace
1401 1402 self.user_ns.update(ns)
1402
1403
1403 1404 @property
1404 1405 def all_ns_refs(self):
1405 1406 """Get a list of references to all the namespace dictionaries in which
@@ -1425,7 +1426,7 b' class InteractiveShell(SingletonConfigurable):'
1425 1426 # Reset last execution result
1426 1427 self.last_execution_succeeded = True
1427 1428 self.last_execution_result = None
1428
1429
1429 1430 # Flush cached output items
1430 1431 if self.displayhook.do_full_cache:
1431 1432 self.displayhook.flush()
@@ -1490,7 +1491,7 b' class InteractiveShell(SingletonConfigurable):'
1490 1491 raise ValueError("Refusing to delete %s" % varname)
1491 1492
1492 1493 ns_refs = self.all_ns_refs
1493
1494
1494 1495 if by_name: # Delete by name
1495 1496 for ns in ns_refs:
1496 1497 try:
@@ -1765,8 +1766,14 b' class InteractiveShell(SingletonConfigurable):'
1765 1766 if meth == 'pdoc':
1766 1767 pmethod(info.obj, oname, formatter)
1767 1768 elif meth == 'pinfo':
1768 pmethod(info.obj, oname, formatter, info,
1769 enable_html_pager=self.enable_html_pager, **kw)
1769 pmethod(
1770 info.obj,
1771 oname,
1772 formatter,
1773 info,
1774 enable_html_pager=self.enable_html_pager,
1775 **kw
1776 )
1770 1777 else:
1771 1778 pmethod(info.obj, oname)
1772 1779 else:
@@ -1890,7 +1897,7 b' class InteractiveShell(SingletonConfigurable):'
1890 1897 print('Exception type :', etype)
1891 1898 print('Exception value:', value)
1892 1899 print('Traceback :', tb)
1893
1900
1894 1901 def validate_stb(stb):
1895 1902 """validate structured traceback return type
1896 1903
@@ -1919,7 +1926,7 b' class InteractiveShell(SingletonConfigurable):'
1919 1926 else:
1920 1927 def wrapped(self,etype,value,tb,tb_offset=None):
1921 1928 """wrap CustomTB handler, to protect IPython from user code
1922
1929
1923 1930 This makes it harder (but not impossible) for custom exception
1924 1931 handlers to crash IPython.
1925 1932 """
@@ -1968,10 +1975,10 b' class InteractiveShell(SingletonConfigurable):'
1968 1975
1969 1976 def _get_exc_info(self, exc_tuple=None):
1970 1977 """get exc_info from a given tuple, sys.exc_info() or sys.last_type etc.
1971
1978
1972 1979 Ensures sys.last_type,value,traceback hold the exc_info we found,
1973 1980 from whichever source.
1974
1981
1975 1982 raises ValueError if none of these contain any information
1976 1983 """
1977 1984 if exc_tuple is None:
@@ -1983,10 +1990,10 b' class InteractiveShell(SingletonConfigurable):'
1983 1990 if hasattr(sys, 'last_type'):
1984 1991 etype, value, tb = sys.last_type, sys.last_value, \
1985 1992 sys.last_traceback
1986
1993
1987 1994 if etype is None:
1988 1995 raise ValueError("No exception to find")
1989
1996
1990 1997 # Now store the exception info in sys.last_type etc.
1991 1998 # WARNING: these variables are somewhat deprecated and not
1992 1999 # necessarily safe to use in a threaded environment, but tools
@@ -1995,16 +2002,16 b' class InteractiveShell(SingletonConfigurable):'
1995 2002 sys.last_type = etype
1996 2003 sys.last_value = value
1997 2004 sys.last_traceback = tb
1998
2005
1999 2006 return etype, value, tb
2000
2007
2001 2008 def show_usage_error(self, exc):
2002 2009 """Show a short message for UsageErrors
2003
2010
2004 2011 These are special exceptions that shouldn't show a traceback.
2005 2012 """
2006 2013 print("UsageError: %s" % exc, file=sys.stderr)
2007
2014
2008 2015 def get_exception_only(self, exc_tuple=None):
2009 2016 """
2010 2017 Return as a string (ending with a newline) the exception that
@@ -2118,7 +2125,7 b' class InteractiveShell(SingletonConfigurable):'
2118 2125
2119 2126 def init_readline(self):
2120 2127 """DEPRECATED
2121
2128
2122 2129 Moved to terminal subclass, here only to simplify the init logic."""
2123 2130 # Set a number of methods that depend on readline to be no-op
2124 2131 warnings.warn('`init_readline` is no-op since IPython 5.0 and is Deprecated',
@@ -2285,12 +2292,13 b' class InteractiveShell(SingletonConfigurable):'
2285 2292 # should be split into a prompt manager and displayhook. We probably
2286 2293 # even need a centralize colors management object.
2287 2294 self.run_line_magic('colors', self.colors)
2288
2295
2289 2296 # Defined here so that it's included in the documentation
2290 2297 @functools.wraps(magic.MagicsManager.register_function)
2291 2298 def register_magic_function(self, func, magic_kind='line', magic_name=None):
2292 self.magics_manager.register_function(func,
2293 magic_kind=magic_kind, magic_name=magic_name)
2299 self.magics_manager.register_function(
2300 func, magic_kind=magic_kind, magic_name=magic_name
2301 )
2294 2302
2295 2303 def run_line_magic(self, magic_name, line, _stack_depth=1):
2296 2304 """Execute the given line magic.
@@ -2525,7 +2533,7 b' class InteractiveShell(SingletonConfigurable):'
2525 2533 ec = 130
2526 2534 if ec > 128:
2527 2535 ec = -(ec - 128)
2528
2536
2529 2537 # We explicitly do NOT return the subprocess status code, because
2530 2538 # a non-None value would trigger :func:`sys.displayhook` calls.
2531 2539 # Instead, we store the exit_code in user_ns. Note the semantics
@@ -2588,7 +2596,7 b' class InteractiveShell(SingletonConfigurable):'
2588 2596 def init_payload(self):
2589 2597 self.payload_manager = PayloadManager(parent=self)
2590 2598 self.configurables.append(self.payload_manager)
2591
2599
2592 2600 #-------------------------------------------------------------------------
2593 2601 # Things related to the prefilter
2594 2602 #-------------------------------------------------------------------------
@@ -2628,13 +2636,13 b' class InteractiveShell(SingletonConfigurable):'
2628 2636
2629 2637 def _user_obj_error(self):
2630 2638 """return simple exception dict
2631
2639
2632 2640 for use in user_expressions
2633 2641 """
2634
2642
2635 2643 etype, evalue, tb = self._get_exc_info()
2636 2644 stb = self.InteractiveTB.get_exception_only(etype, evalue)
2637
2645
2638 2646 exc_info = {
2639 2647 u'status' : 'error',
2640 2648 u'traceback' : stb,
@@ -2643,13 +2651,13 b' class InteractiveShell(SingletonConfigurable):'
2643 2651 }
2644 2652
2645 2653 return exc_info
2646
2654
2647 2655 def _format_user_obj(self, obj):
2648 2656 """format a user object to display dict
2649
2657
2650 2658 for use in user_expressions
2651 2659 """
2652
2660
2653 2661 data, md = self.display_formatter.format(obj)
2654 2662 value = {
2655 2663 'status' : 'ok',
@@ -2657,7 +2665,7 b' class InteractiveShell(SingletonConfigurable):'
2657 2665 'metadata' : md,
2658 2666 }
2659 2667 return value
2660
2668
2661 2669 def user_expressions(self, expressions):
2662 2670 """Evaluate a dict of expressions in the user's namespace.
2663 2671
@@ -2676,7 +2684,7 b' class InteractiveShell(SingletonConfigurable):'
2676 2684 out = {}
2677 2685 user_ns = self.user_ns
2678 2686 global_ns = self.user_global_ns
2679
2687
2680 2688 for key, expr in expressions.items():
2681 2689 try:
2682 2690 value = self._format_user_obj(eval(expr, global_ns, user_ns))
@@ -3092,12 +3100,14 b' class InteractiveShell(SingletonConfigurable):'
3092 3100 # Our own compiler remembers the __future__ environment. If we want to
3093 3101 # run code with a separate __future__ environment, use the default
3094 3102 # compiler
3095 compiler = self.compile if shell_futures else CachingCompiler()
3103 compiler = self.compile if shell_futures else self.compiler_class()
3096 3104
3097 3105 _run_async = False
3098 3106
3099 3107 with self.builtin_trap:
3100 cell_name = self.compile.cache(cell, self.execution_count)
3108 cell_name = self.compile.cache(
3109 cell, self.execution_count, raw_code=raw_cell
3110 )
3101 3111
3102 3112 with self.display_trap:
3103 3113 # Compile to bytecode
@@ -3203,13 +3213,13 b' class InteractiveShell(SingletonConfigurable):'
3203 3213
3204 3214 def transform_ast(self, node):
3205 3215 """Apply the AST transformations from self.ast_transformers
3206
3216
3207 3217 Parameters
3208 3218 ----------
3209 3219 node : ast.Node
3210 3220 The root node to be transformed. Typically called with the ast.Module
3211 3221 produced by parsing user input.
3212
3222
3213 3223 Returns
3214 3224 -------
3215 3225 An ast.Node corresponding to the node it was called with. Note that it
@@ -3256,7 +3266,7 b' class InteractiveShell(SingletonConfigurable):'
3256 3266 Experimental value: 'async' Will try to run top level interactive
3257 3267 async/await code in default runner, this will not respect the
3258 3268 interactivity setting and will only run the last node if it is an
3259 expression.
3269 expression.
3260 3270
3261 3271 compiler : callable
3262 3272 A function with the same interface as the built-in compile(), to turn
@@ -3477,17 +3487,17 b' class InteractiveShell(SingletonConfigurable):'
3477 3487
3478 3488 def enable_gui(self, gui=None):
3479 3489 raise NotImplementedError('Implement enable_gui in a subclass')
3480
3490
3481 3491 def enable_matplotlib(self, gui=None):
3482 3492 """Enable interactive matplotlib and inline figure support.
3483
3493
3484 3494 This takes the following steps:
3485
3495
3486 3496 1. select the appropriate eventloop and matplotlib backend
3487 3497 2. set up matplotlib for interactive use with that backend
3488 3498 3. configure formatters for inline figure display
3489 3499 4. enable the selected gui eventloop
3490
3500
3491 3501 Parameters
3492 3502 ----------
3493 3503 gui : optional, string
@@ -3501,7 +3511,7 b' class InteractiveShell(SingletonConfigurable):'
3501 3511 """
3502 3512 from IPython.core import pylabtools as pt
3503 3513 gui, backend = pt.find_gui_and_backend(gui, self.pylab_gui_select)
3504
3514
3505 3515 if gui != 'inline':
3506 3516 # If we have our first gui selection, store it
3507 3517 if self.pylab_gui_select is None:
@@ -3511,16 +3521,16 b' class InteractiveShell(SingletonConfigurable):'
3511 3521 print('Warning: Cannot change to a different GUI toolkit: %s.'
3512 3522 ' Using %s instead.' % (gui, self.pylab_gui_select))
3513 3523 gui, backend = pt.find_gui_and_backend(self.pylab_gui_select)
3514
3524
3515 3525 pt.activate_matplotlib(backend)
3516 3526 pt.configure_inline_support(self, backend)
3517
3527
3518 3528 # Now we must activate the gui pylab wants to use, and fix %run to take
3519 3529 # plot updates into account
3520 3530 self.enable_gui(gui)
3521 3531 self.magics_manager.registry['ExecutionMagics'].default_runner = \
3522 3532 pt.mpl_runner(self.safe_execfile)
3523
3533
3524 3534 return gui, backend
3525 3535
3526 3536 def enable_pylab(self, gui=None, import_all=True, welcome_message=False):
@@ -3530,7 +3540,7 b' class InteractiveShell(SingletonConfigurable):'
3530 3540 namespace all of numpy and pylab, and configures IPython to correctly
3531 3541 interact with the GUI event loop. The GUI backend to be used can be
3532 3542 optionally selected with the optional ``gui`` argument.
3533
3543
3534 3544 This method only adds preloading the namespace to InteractiveShell.enable_matplotlib.
3535 3545
3536 3546 Parameters
@@ -3550,9 +3560,9 b' class InteractiveShell(SingletonConfigurable):'
3550 3560 This argument is ignored, no welcome message will be displayed.
3551 3561 """
3552 3562 from IPython.core.pylabtools import import_pylab
3553
3563
3554 3564 gui, backend = self.enable_matplotlib(gui)
3555
3565
3556 3566 # We want to prevent the loading of pylab to pollute the user's
3557 3567 # namespace as shown by the %who* magics, so we execute the activation
3558 3568 # code in an empty namespace, and we update *both* user_ns and
General Comments 0
You need to be logged in to leave comments. Login now