Skip to content

Commit 5496710

Browse files
committed
Removed shell.py entirely and made the embedded shell a proper subclass.
This created a new model :mod:`IPython.core.embed` with a subclass of :class:`IPython.core.iplib.InteractiveShell` called :class:`InteractiveShellEmbed`. This subclass now has all the embedding logic that was in :mod:`shell`.
1 parent 8ce5766 commit 5496710

9 files changed

Lines changed: 212 additions & 323 deletions

File tree

IPython/Shell.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,24 @@
1919
from warnings import warn
2020

2121
msg = """
22-
This module (IPython.Shell) has been moved to a new location
23-
(IPython.core.shell) and is being refactored. Please update your code
24-
to use the new IPython.core.shell module"""
22+
This module (IPython.Shell) is deprecated. The classes that were in this
23+
module have been replaced by:
24+
25+
IPShell->IPython.core.iplib.InteractiveShell
26+
IPShellEmbed->IPython.core.embed.InteractiveShellEmbed
27+
28+
Please migrate your code to use these classes instead.
29+
"""
2530

2631
warn(msg, category=DeprecationWarning, stacklevel=1)
2732

28-
from IPython.core.shell import start, IPShell, IPShellEmbed
33+
from IPython.core.iplib import InteractiveShell as IPShell
34+
from IPython.core.embed import InteractiveShellEmbed as IPShellEmbed
35+
36+
def start(user_ns=None, embedded=False):
37+
"""Return an instance of :class:`InteractiveShell`."""
38+
if embedded:
39+
return InteractiveShellEmbed(user_ns=user_ns)
40+
else:
41+
return InteractiveShell(user_ns=user_ns)
2942

IPython/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@
3434
# Therefore, non-IPython modules can be added to extensions directory
3535
sys.path.append(os.path.join(os.path.dirname(__file__), "extensions"))
3636

37-
38-
# from IPython.core import shell
39-
# Shell = shell
4037
from IPython.core import iplib
4138

4239

IPython/core/embed.py

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#!/usr/bin/env python
2+
# encoding: utf-8
3+
"""
4+
An embedded IPython shell.
5+
6+
Authors:
7+
8+
* Brian Granger
9+
* Fernando Perez
10+
11+
Notes
12+
-----
13+
"""
14+
15+
#-----------------------------------------------------------------------------
16+
# Copyright (C) 2008-2009 The IPython Development Team
17+
#
18+
# Distributed under the terms of the BSD License. The full license is in
19+
# the file COPYING, distributed as part of this software.
20+
#-----------------------------------------------------------------------------
21+
22+
#-----------------------------------------------------------------------------
23+
# Imports
24+
#-----------------------------------------------------------------------------
25+
26+
import sys
27+
28+
from IPython.core import ultratb
29+
from IPython.core.iplib import InteractiveShell
30+
31+
from IPython.utils.traitlets import Bool, Str
32+
from IPython.utils.genutils import ask_yes_no
33+
34+
#-----------------------------------------------------------------------------
35+
# Classes and functions
36+
#-----------------------------------------------------------------------------
37+
38+
# This is an additional magic that is exposed in embedded shells.
39+
def kill_embedded(self,parameter_s=''):
40+
"""%kill_embedded : deactivate for good the current embedded IPython.
41+
42+
This function (after asking for confirmation) sets an internal flag so that
43+
an embedded IPython will never activate again. This is useful to
44+
permanently disable a shell that is being called inside a loop: once you've
45+
figured out what you needed from it, you may then kill it and the program
46+
will then continue to run without the interactive shell interfering again.
47+
"""
48+
49+
kill = ask_yes_no("Are you sure you want to kill this embedded instance "
50+
"(y/n)? [y/N] ",'n')
51+
if kill:
52+
self.embedded_active = False
53+
print "This embedded IPython will not reactivate anymore once you exit."
54+
55+
56+
class InteractiveShellEmbed(InteractiveShell):
57+
58+
dummy_mode = Bool(False)
59+
exit_msg = Str('')
60+
61+
def __init__(self, parent=None, config=None, usage=None,
62+
user_ns=None, user_global_ns=None,
63+
banner1='', banner2='',
64+
custom_exceptions=((),None), exit_msg=''):
65+
66+
# First we need to save the state of sys.displayhook and
67+
# sys.ipcompleter so we can restore it when we are done.
68+
self.save_sys_displayhook()
69+
self.save_sys_ipcompleter()
70+
71+
super(InteractiveShellEmbed,self).__init__(
72+
parent=parent, config=config, usage=usage,
73+
user_ns=user_ns, user_global_ns=user_global_ns,
74+
banner1=banner1, banner2=banner2,
75+
custom_exceptions=custom_exceptions, embedded=True)
76+
77+
self.save_sys_displayhook_embed()
78+
self.exit_msg = exit_msg
79+
self.define_magic("kill_embedded", kill_embedded)
80+
81+
# don't use the ipython crash handler so that user exceptions aren't
82+
# trapped
83+
sys.excepthook = ultratb.FormattedTB(color_scheme = self.colors,
84+
mode = self.xmode,
85+
call_pdb = self.pdb)
86+
87+
self.restore_sys_displayhook()
88+
self.restore_sys_ipcompleter()
89+
90+
def save_sys_displayhook(self):
91+
# sys.displayhook is a global, we need to save the user's original
92+
# Don't rely on __displayhook__, as the user may have changed that.
93+
self.sys_displayhook_orig = sys.displayhook
94+
95+
def save_sys_ipcompleter(self):
96+
"""Save readline completer status."""
97+
try:
98+
#print 'Save completer',sys.ipcompleter # dbg
99+
self.sys_ipcompleter_orig = sys.ipcompleter
100+
except:
101+
pass # not nested with IPython
102+
103+
def restore_sys_displayhook(self):
104+
sys.displayhook = self.sys_displayhook_orig
105+
106+
def restore_sys_ipcompleter(self):
107+
"""Restores the readline completer which was in place.
108+
109+
This allows embedded IPython within IPython not to disrupt the
110+
parent's completion.
111+
"""
112+
try:
113+
self.readline.set_completer(self.sys_ipcompleter_orig)
114+
sys.ipcompleter = self.sys_ipcompleter_orig
115+
except:
116+
pass
117+
118+
def save_sys_displayhook_embed(self):
119+
self.sys_displayhook_embed = sys.displayhook
120+
121+
def restore_sys_displayhook_embed(self):
122+
sys.displayhook = self.sys_displayhook_embed
123+
124+
def __call__(self, header='', local_ns=None, global_ns=None, dummy=None):
125+
"""Activate the interactive interpreter.
126+
127+
__call__(self,header='',local_ns=None,global_ns,dummy=None) -> Start
128+
the interpreter shell with the given local and global namespaces, and
129+
optionally print a header string at startup.
130+
131+
The shell can be globally activated/deactivated using the
132+
set/get_dummy_mode methods. This allows you to turn off a shell used
133+
for debugging globally.
134+
135+
However, *each* time you call the shell you can override the current
136+
state of dummy_mode with the optional keyword parameter 'dummy'. For
137+
example, if you set dummy mode on with IPShell.set_dummy_mode(1), you
138+
can still have a specific call work by making it as IPShell(dummy=0).
139+
140+
The optional keyword parameter dummy controls whether the call
141+
actually does anything.
142+
"""
143+
144+
# If the user has turned it off, go away
145+
if not self.embedded_active:
146+
return
147+
148+
# Normal exits from interactive mode set this flag, so the shell can't
149+
# re-enter (it checks this variable at the start of interactive mode).
150+
self.exit_now = False
151+
152+
# Allow the dummy parameter to override the global __dummy_mode
153+
if dummy or (dummy != 0 and self.dummy_mode):
154+
return
155+
156+
self.restore_sys_displayhook_embed()
157+
158+
if self.has_readline:
159+
self.set_completer()
160+
161+
if self.banner and header:
162+
format = '%s\n%s\n'
163+
else:
164+
format = '%s%s\n'
165+
banner = format % (self.banner,header)
166+
167+
# Call the embedding code with a stack depth of 1 so it can skip over
168+
# our call and get the original caller's namespaces.
169+
self.embed_mainloop(banner, local_ns, global_ns, stack_depth=1)
170+
171+
if self.exit_msg:
172+
print self.exit_msg
173+
174+
# Restore global systems (display, completion)
175+
self.restore_sys_displayhook()
176+
self.restore_sys_ipcompleter()

IPython/core/ipapi.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,25 @@
2929

3030
from IPython.core.error import TryNext, UsageError
3131
from IPython.core.component import Component
32-
from warnings import warn
3332

3433
#-----------------------------------------------------------------------------
3534
# Classes and functions
3635
#-----------------------------------------------------------------------------
3736

38-
msg = """
39-
This module (IPython.core.ipapi) is being deprecated. For now, all we
40-
offer here is the ``get`` function for getting the most recently created
41-
InteractiveShell instance."""
42-
43-
warn(msg, category=DeprecationWarning, stacklevel=1)
44-
45-
4637
def get():
4738
"""Get the most recently created InteractiveShell instance."""
4839
insts = Component.get_instances(name='__IP')
4940
most_recent = insts[0]
5041
for inst in insts[1:]:
5142
if inst.created > most_recent.created:
5243
most_recent = inst
53-
return most_recent.getapi()
44+
return most_recent
45+
46+
def launch_new_instance():
47+
"""Create a run a full blown IPython instance"""
48+
from IPython.core.ipapp import IPythonApp
49+
app = IPythonApp()
50+
app.start()
5451

5552

5653

IPython/core/ipapp.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,6 @@ def construct(self):
304304

305305
# Create an InteractiveShell instance
306306
self.shell = InteractiveShell(
307-
name='__IP',
308307
parent=None,
309308
config=self.master_config
310309
)

IPython/core/iplib.py

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -294,16 +294,16 @@ class InteractiveShell(Component, Magic):
294294
# Subclasses with thread support should override this as needed.
295295
isthreaded = False
296296

297-
def __init__(self, name, parent=None, config=None, usage=None,
297+
def __init__(self, parent=None, config=None, usage=None,
298298
user_ns=None, user_global_ns=None,
299-
banner1='', banner2='',
299+
banner1=None, banner2=None,
300300
custom_exceptions=((),None), embedded=False):
301301

302302
# This is where traitlets with a config_key argument are updated
303303
# from the values on config.
304304
# Ideally, from here on out, the config should only be used when
305305
# passing it to children components.
306-
super(InteractiveShell, self).__init__(parent, config=config, name=name)
306+
super(InteractiveShell, self).__init__(parent, config=config, name='__IP')
307307

308308
self.init_instance_attrs()
309309
self.init_term_title()
@@ -423,9 +423,9 @@ def init_usage(self, usage=None):
423423
def init_banner(self, banner1, banner2):
424424
if self.c: # regular python doesn't print the banner with -c
425425
self.display_banner = False
426-
if banner1:
426+
if banner1 is not None:
427427
self.banner1 = banner1
428-
if banner2:
428+
if banner2 is not None:
429429
self.banner2 = banner2
430430
self.compute_banner()
431431

@@ -1066,10 +1066,10 @@ def init_namespaces(self):
10661066
warn('help() not available - check site.py')
10671067

10681068
def add_builtins(self):
1069-
"""Store ipython references into the builtin namespace.
1069+
"""Store ipython references into the __builtin__ namespace.
10701070
1071-
Some parts of ipython operate via builtins injected here, which hold a
1072-
reference to IPython itself."""
1071+
We strive to modify the __builtin__ namespace as little as possible.
1072+
"""
10731073

10741074
# Install our own quitter instead of the builtins.
10751075
# This used to be in the __init__ method, but this is a better
@@ -1088,25 +1088,7 @@ def add_builtins(self):
10881088
del deepreload
10891089
except ImportError:
10901090
pass
1091-
1092-
# TODO: deprecate all of these, they are unsafe. Why though?
1093-
builtins_new = dict(__IPYTHON__ = self,
1094-
ip_set_hook = self.set_hook,
1095-
jobs = self.jobs,
1096-
# magic = self.magic,
1097-
ipalias = wrap_deprecated(self.ipalias),
1098-
# ipsystem = wrap_deprecated(self.ipsystem,'_ip.system()'),
1099-
)
1100-
for biname,bival in builtins_new.items():
1101-
try:
1102-
# store the orignal value so we can restore it
1103-
self.builtins_added[biname] = __builtin__.__dict__[biname]
1104-
except KeyError:
1105-
# or mark that it wasn't defined, and we'll just delete it at
1106-
# cleanup
1107-
self.builtins_added[biname] = Undefined
1108-
__builtin__.__dict__[biname] = bival
1109-
1091+
11101092
# Keep in the builtins a flag for when IPython is active. We set it
11111093
# with setdefault so that multiple nested IPythons don't clobber one
11121094
# another. Each will increase its value by one upon being activated,

0 commit comments

Comments
 (0)