1#!/usr/bin/env python
2"""An example of how to embed an IPython shell into a running program.
3
4Please see the documentation in the IPython.Shell module for more details.
5
6The accompanying file embed_class_short.py has quick code fragments for
7embedding which you can cut and paste in your code once you understand how
8things work.
9
10The code in this file is deliberately extra-verbose, meant for learning."""
11
12# The basics to get you going:
13
14# IPython injects get_ipython into builtins, so you can know if you have nested
15# copies running.
16
17# Try running this code both at the command line and from inside IPython (with
18# %run example-embed.py)
19
20from IPython.terminal.prompts import Prompts, Token
21
22class CustomPrompt(Prompts):
23
24    def in_prompt_tokens(self, cli=None):
25
26       return [
27            (Token.Prompt, 'In <'),
28            (Token.PromptNum, str(self.shell.execution_count)),
29            (Token.Prompt, '>: '),
30            ]
31
32    def out_prompt_tokens(self):
33       return [
34            (Token.OutPrompt, 'Out<'),
35            (Token.OutPromptNum, str(self.shell.execution_count)),
36            (Token.OutPrompt, '>: '),
37        ]
38
39
40from traitlets.config.loader import Config
41try:
42    get_ipython
43except NameError:
44    nested = 0
45    cfg = Config()
46    cfg.TerminalInteractiveShell.prompts_class=CustomPrompt
47else:
48    print("Running nested copies of IPython.")
49    print("The prompts for the nested copy have been modified")
50    cfg = Config()
51    nested = 1
52
53# First import the embeddable shell class
54from IPython.terminal.embed import InteractiveShellEmbed
55
56# Now create an instance of the embeddable shell. The first argument is a
57# string with options exactly as you would type them if you were starting
58# IPython at the system command line. Any parameters you want to define for
59# configuration can thus be specified here.
60ipshell = InteractiveShellEmbed(config=cfg,
61                       banner1 = 'Dropping into IPython',
62                       exit_msg = 'Leaving Interpreter, back to program.')
63
64# Make a second instance, you can have as many as you want.
65ipshell2 = InteractiveShellEmbed(config=cfg,
66                        banner1 = 'Second IPython instance.')
67
68print('\nHello. This is printed from the main controller program.\n')
69
70# You can then call ipshell() anywhere you need it (with an optional
71# message):
72ipshell('***Called from top level. '
73        'Hit Ctrl-D to exit interpreter and continue program.\n'
74        'Note that if you use %kill_embedded, you can fully deactivate\n'
75        'This embedded instance so it will never turn on again')
76
77print('\nBack in caller program, moving along...\n')
78
79#---------------------------------------------------------------------------
80# More details:
81
82# InteractiveShellEmbed instances don't print the standard system banner and
83# messages. The IPython banner (which actually may contain initialization
84# messages) is available as get_ipython().banner in case you want it.
85
86# InteractiveShellEmbed instances print the following information every time they
87# start:
88
89# - A global startup banner.
90
91# - A call-specific header string, which you can use to indicate where in the
92# execution flow the shell is starting.
93
94# They also print an exit message every time they exit.
95
96# Both the startup banner and the exit message default to None, and can be set
97# either at the instance constructor or at any other time with the
98# by setting the banner and exit_msg attributes.
99
100# The shell instance can be also put in 'dummy' mode globally or on a per-call
101# basis. This gives you fine control for debugging without having to change
102# code all over the place.
103
104# The code below illustrates all this.
105
106
107# This is how the global banner and exit_msg can be reset at any point
108ipshell.banner2 = 'Entering interpreter - New Banner'
109ipshell.exit_msg = 'Leaving interpreter - New exit_msg'
110
111def foo(m):
112    s = 'spam'
113    ipshell('***In foo(). Try %whos, or print s or m:')
114    print('foo says m = ',m)
115
116def bar(n):
117    s = 'eggs'
118    ipshell('***In bar(). Try %whos, or print s or n:')
119    print('bar says n = ',n)
120
121# Some calls to the above functions which will trigger IPython:
122print('Main program calling foo("eggs")\n')
123foo('eggs')
124
125# The shell can be put in 'dummy' mode where calls to it silently return. This
126# allows you, for example, to globally turn off debugging for a program with a
127# single call.
128ipshell.dummy_mode = True
129print('\nTrying to call IPython which is now "dummy":')
130ipshell()
131print('Nothing happened...')
132# The global 'dummy' mode can still be overridden for a single call
133print('\nOverriding dummy mode manually:')
134ipshell(dummy=False)
135
136# Reactivate the IPython shell
137ipshell.dummy_mode = False
138
139print('You can even have multiple embedded instances:')
140ipshell2()
141
142print('\nMain program calling bar("spam")\n')
143bar('spam')
144
145print('Main program finished. Bye!')
146