##// END OF EJS Templates
ipapi: allow specifying shell class in launch_new_instance & make_new instance. Use this in test_embed.py
Ville M. Vainio -
Show More
@@ -1,596 +1,596 b''
1 1 ''' IPython customization API
2 2
3 3 Your one-stop module for configuring & extending ipython
4 4
5 5 The API will probably break when ipython 1.0 is released, but so
6 6 will the other configuration method (rc files).
7 7
8 8 All names prefixed by underscores are for internal use, not part
9 9 of the public api.
10 10
11 11 Below is an example that you can just put to a module and import from ipython.
12 12
13 13 A good practice is to install the config script below as e.g.
14 14
15 15 ~/.ipython/my_private_conf.py
16 16
17 17 And do
18 18
19 19 import_mod my_private_conf
20 20
21 21 in ~/.ipython/ipythonrc
22 22
23 23 That way the module is imported at startup and you can have all your
24 24 personal configuration (as opposed to boilerplate ipythonrc-PROFILENAME
25 25 stuff) in there.
26 26
27 27 -----------------------------------------------
28 28 import IPython.ipapi
29 29 ip = IPython.ipapi.get()
30 30
31 31 def ankka_f(self, arg):
32 32 print "Ankka",self,"says uppercase:",arg.upper()
33 33
34 34 ip.expose_magic("ankka",ankka_f)
35 35
36 36 ip.magic('alias sayhi echo "Testing, hi ok"')
37 37 ip.magic('alias helloworld echo "Hello world"')
38 38 ip.system('pwd')
39 39
40 40 ip.ex('import re')
41 41 ip.ex("""
42 42 def funcci(a,b):
43 43 print a+b
44 44 print funcci(3,4)
45 45 """)
46 46 ip.ex("funcci(348,9)")
47 47
48 48 def jed_editor(self,filename, linenum=None):
49 49 print "Calling my own editor, jed ... via hook!"
50 50 import os
51 51 if linenum is None: linenum = 0
52 52 os.system('jed +%d %s' % (linenum, filename))
53 53 print "exiting jed"
54 54
55 55 ip.set_hook('editor',jed_editor)
56 56
57 57 o = ip.options
58 58 o.autocall = 2 # FULL autocall mode
59 59
60 60 print "done!"
61 61 '''
62 62
63 63 # stdlib imports
64 64 import __builtin__
65 65 import sys
66 66
67 67 try: # Python 2.3 compatibility
68 68 set
69 69 except NameError:
70 70 import sets
71 71 set = sets.Set
72 72
73 73 # our own
74 74 #from IPython.genutils import warn,error
75 75
76 76 class TryNext(Exception):
77 77 """Try next hook exception.
78 78
79 79 Raise this in your hook function to indicate that the next hook handler
80 80 should be used to handle the operation. If you pass arguments to the
81 81 constructor those arguments will be used by the next hook instead of the
82 82 original ones.
83 83 """
84 84
85 85 def __init__(self, *args, **kwargs):
86 86 self.args = args
87 87 self.kwargs = kwargs
88 88
89 89 class UsageError(Exception):
90 90 """ Error in magic function arguments, etc.
91 91
92 92 Something that probably won't warrant a full traceback, but should
93 93 nevertheless interrupt a macro / batch file.
94 94 """
95 95
96 96 class IPyAutocall:
97 97 """ Instances of this class are always autocalled
98 98
99 99 This happens regardless of 'autocall' variable state. Use this to
100 100 develop macro-like mechanisms.
101 101 """
102 102
103 103 def set_ip(self,ip):
104 104 """ Will be used to set _ip point to current ipython instance b/f call
105 105
106 106 Override this method if you don't want this to happen.
107 107
108 108 """
109 109 self._ip = ip
110 110
111 111
112 112 # contains the most recently instantiated IPApi
113 113
114 114 class IPythonNotRunning:
115 115 """Dummy do-nothing class.
116 116
117 117 Instances of this class return a dummy attribute on all accesses, which
118 118 can be called and warns. This makes it easier to write scripts which use
119 119 the ipapi.get() object for informational purposes to operate both with and
120 120 without ipython. Obviously code which uses the ipython object for
121 121 computations will not work, but this allows a wider range of code to
122 122 transparently work whether ipython is being used or not."""
123 123
124 124 def __init__(self,warn=True):
125 125 if warn:
126 126 self.dummy = self._dummy_warn
127 127 else:
128 128 self.dummy = self._dummy_silent
129 129
130 130 def __str__(self):
131 131 return "<IPythonNotRunning>"
132 132
133 133 __repr__ = __str__
134 134
135 135 def __getattr__(self,name):
136 136 return self.dummy
137 137
138 138 def _dummy_warn(self,*args,**kw):
139 139 """Dummy function, which doesn't do anything but warn."""
140 140
141 141 print ("IPython is not running, this is a dummy no-op function")
142 142
143 143 def _dummy_silent(self,*args,**kw):
144 144 """Dummy function, which doesn't do anything and emits no warnings."""
145 145 pass
146 146
147 147 _recent = None
148 148
149 149
150 150 def get(allow_dummy=False,dummy_warn=True):
151 151 """Get an IPApi object.
152 152
153 153 If allow_dummy is true, returns an instance of IPythonNotRunning
154 154 instead of None if not running under IPython.
155 155
156 156 If dummy_warn is false, the dummy instance will be completely silent.
157 157
158 158 Running this should be the first thing you do when writing extensions that
159 159 can be imported as normal modules. You can then direct all the
160 160 configuration operations against the returned object.
161 161 """
162 162 global _recent
163 163 if allow_dummy and not _recent:
164 164 _recent = IPythonNotRunning(dummy_warn)
165 165 return _recent
166 166
167 167 class IPApi:
168 168 """ The actual API class for configuring IPython
169 169
170 170 You should do all of the IPython configuration by getting an IPApi object
171 171 with IPython.ipapi.get() and using the attributes and methods of the
172 172 returned object."""
173 173
174 174 def __init__(self,ip):
175 175
176 176 # All attributes exposed here are considered to be the public API of
177 177 # IPython. As needs dictate, some of these may be wrapped as
178 178 # properties.
179 179
180 180 self.magic = ip.ipmagic
181 181
182 182 self.system = ip.system
183 183
184 184 self.set_hook = ip.set_hook
185 185
186 186 self.set_custom_exc = ip.set_custom_exc
187 187
188 188 self.user_ns = ip.user_ns
189 189 self.user_ns['_ip'] = self
190 190
191 191 self.set_crash_handler = ip.set_crash_handler
192 192
193 193 # Session-specific data store, which can be used to store
194 194 # data that should persist through the ipython session.
195 195 self.meta = ip.meta
196 196
197 197 # The ipython instance provided
198 198 self.IP = ip
199 199
200 200 self.extensions = {}
201 201
202 202 self.dbg = DebugTools(self)
203 203
204 204 global _recent
205 205 _recent = self
206 206
207 207 # Use a property for some things which are added to the instance very
208 208 # late. I don't have time right now to disentangle the initialization
209 209 # order issues, so a property lets us delay item extraction while
210 210 # providing a normal attribute API.
211 211 def get_db(self):
212 212 """A handle to persistent dict-like database (a PickleShareDB object)"""
213 213 return self.IP.db
214 214
215 215 db = property(get_db,None,None,get_db.__doc__)
216 216
217 217 def get_options(self):
218 218 """All configurable variables."""
219 219
220 220 # catch typos by disabling new attribute creation. If new attr creation
221 221 # is in fact wanted (e.g. when exposing new options), do allow_new_attr(True)
222 222 # for the received rc struct.
223 223
224 224 self.IP.rc.allow_new_attr(False)
225 225 return self.IP.rc
226 226
227 227 options = property(get_options,None,None,get_options.__doc__)
228 228
229 229 def expose_magic(self,magicname, func):
230 230 ''' Expose own function as magic function for ipython
231 231
232 232 def foo_impl(self,parameter_s=''):
233 233 """My very own magic!. (Use docstrings, IPython reads them)."""
234 234 print 'Magic function. Passed parameter is between < >: <'+parameter_s+'>'
235 235 print 'The self object is:',self
236 236
237 237 ipapi.expose_magic("foo",foo_impl)
238 238 '''
239 239
240 240 import new
241 241 im = new.instancemethod(func,self.IP, self.IP.__class__)
242 242 old = getattr(self.IP, "magic_" + magicname, None)
243 243 if old:
244 244 self.dbg.debug_stack("Magic redefinition '%s', old %s" % (magicname,
245 245 old))
246 246
247 247 setattr(self.IP, "magic_" + magicname, im)
248 248
249 249 def ex(self,cmd):
250 250 """ Execute a normal python statement in user namespace """
251 251 exec cmd in self.user_ns
252 252
253 253 def ev(self,expr):
254 254 """ Evaluate python expression expr in user namespace
255 255
256 256 Returns the result of evaluation"""
257 257 return eval(expr,self.user_ns)
258 258
259 259 def runlines(self,lines):
260 260 """ Run the specified lines in interpreter, honoring ipython directives.
261 261
262 262 This allows %magic and !shell escape notations.
263 263
264 264 Takes either all lines in one string or list of lines.
265 265 """
266 266
267 267 def cleanup_ipy_script(script):
268 268 """ Make a script safe for _ip.runlines()
269 269
270 270 - Removes empty lines
271 271 - Suffixes all indented blocks that end with unindented lines with empty lines
272 272
273 273 """
274 274 res = []
275 275 lines = script.splitlines()
276 276 level = 0
277 277 for l in lines:
278 278 stripped = l.lstrip()
279 279 if not l.strip():
280 280 continue
281 281 newlevel = len(l) - len(stripped)
282 282 if level > 0 and newlevel == 0:
283 283 # add empty line
284 284 res.append('')
285 285 res.append(l)
286 286 level = newlevel
287 287 return '\n'.join(res) + '\n'
288 288
289 289 if isinstance(lines,basestring):
290 290 script = lines
291 291 else:
292 292 script = '\n'.join(lines)
293 293 clean=cleanup_ipy_script(script)
294 294
295 295 self.IP.runlines(clean)
296 296 def to_user_ns(self,vars, interactive = True):
297 297 """Inject a group of variables into the IPython user namespace.
298 298
299 299 Inputs:
300 300
301 301 - vars: string with variable names separated by whitespace, or a
302 302 dict with name/value pairs.
303 303
304 304 - interactive: if True (default), the var will be listed with
305 305 %whos et. al.
306 306
307 307 This utility routine is meant to ease interactive debugging work,
308 308 where you want to easily propagate some internal variable in your code
309 309 up to the interactive namespace for further exploration.
310 310
311 311 When you run code via %run, globals in your script become visible at
312 312 the interactive prompt, but this doesn't happen for locals inside your
313 313 own functions and methods. Yet when debugging, it is common to want
314 314 to explore some internal variables further at the interactive propmt.
315 315
316 316 Examples:
317 317
318 318 To use this, you first must obtain a handle on the ipython object as
319 319 indicated above, via:
320 320
321 321 import IPython.ipapi
322 322 ip = IPython.ipapi.get()
323 323
324 324 Once this is done, inside a routine foo() where you want to expose
325 325 variables x and y, you do the following:
326 326
327 327 def foo():
328 328 ...
329 329 x = your_computation()
330 330 y = something_else()
331 331
332 332 # This pushes x and y to the interactive prompt immediately, even
333 333 # if this routine crashes on the next line after:
334 334 ip.to_user_ns('x y')
335 335 ...
336 336
337 337 # To expose *ALL* the local variables from the function, use:
338 338 ip.to_user_ns(locals())
339 339
340 340 ...
341 341 # return
342 342
343 343
344 344 If you need to rename variables, the dict input makes it easy. For
345 345 example, this call exposes variables 'foo' as 'x' and 'bar' as 'y'
346 346 in IPython user namespace:
347 347
348 348 ip.to_user_ns(dict(x=foo,y=bar))
349 349 """
350 350
351 351 # print 'vars given:',vars # dbg
352 352
353 353 # We need a dict of name/value pairs to do namespace updates.
354 354 if isinstance(vars,dict):
355 355 # If a dict was given, no need to change anything.
356 356 vdict = vars
357 357 elif isinstance(vars,basestring):
358 358 # If a string with names was given, get the caller's frame to
359 359 # evaluate the given names in
360 360 cf = sys._getframe(1)
361 361 vdict = {}
362 362 for name in vars.split():
363 363 try:
364 364 vdict[name] = eval(name,cf.f_globals,cf.f_locals)
365 365 except:
366 366 print ('could not get var. %s from %s' %
367 367 (name,cf.f_code.co_name))
368 368 else:
369 369 raise ValueError('vars must be a string or a dict')
370 370
371 371 # Propagate variables to user namespace
372 372 self.user_ns.update(vdict)
373 373
374 374 # And configure interactive visibility
375 375 config_ns = self.IP.user_config_ns
376 376 if interactive:
377 377 for name,val in vdict.iteritems():
378 378 config_ns.pop(name,None)
379 379 else:
380 380 for name,val in vdict.iteritems():
381 381 config_ns[name] = val
382 382
383 383
384 384 def expand_alias(self,line):
385 385 """ Expand an alias in the command line
386 386
387 387 Returns the provided command line, possibly with the first word
388 388 (command) translated according to alias expansion rules.
389 389
390 390 [ipython]|16> _ip.expand_aliases("np myfile.txt")
391 391 <16> 'q:/opt/np/notepad++.exe myfile.txt'
392 392 """
393 393
394 394 pre,fn,rest = self.IP.split_user_input(line)
395 395 res = pre + self.IP.expand_aliases(fn,rest)
396 396 return res
397 397
398 398 def itpl(self, s, depth = 1):
399 399 """ Expand Itpl format string s.
400 400
401 401 Only callable from command line (i.e. prefilter results);
402 402 If you use in your scripts, you need to use a bigger depth!
403 403 """
404 404 return self.IP.var_expand(s, depth)
405 405
406 406 def defalias(self, name, cmd):
407 407 """ Define a new alias
408 408
409 409 _ip.defalias('bb','bldmake bldfiles')
410 410
411 411 Creates a new alias named 'bb' in ipython user namespace
412 412 """
413 413
414 414 self.dbg.check_hotname(name)
415 415
416 416
417 417 if name in self.IP.alias_table:
418 418 self.dbg.debug_stack("Alias redefinition: '%s' => '%s' (old '%s')" %
419 419 (name, cmd, self.IP.alias_table[name]))
420 420
421 421
422 422 if callable(cmd):
423 423 self.IP.alias_table[name] = cmd
424 424 import IPython.shadowns
425 425 setattr(IPython.shadowns, name,cmd)
426 426 return
427 427
428 428 if isinstance(cmd,basestring):
429 429 nargs = cmd.count('%s')
430 430 if nargs>0 and cmd.find('%l')>=0:
431 431 raise Exception('The %s and %l specifiers are mutually exclusive '
432 432 'in alias definitions.')
433 433
434 434 self.IP.alias_table[name] = (nargs,cmd)
435 435 return
436 436
437 437 # just put it in - it's probably (0,'foo')
438 438 self.IP.alias_table[name] = cmd
439 439
440 440 def defmacro(self, *args):
441 441 """ Define a new macro
442 442
443 443 2 forms of calling:
444 444
445 445 mac = _ip.defmacro('print "hello"\nprint "world"')
446 446
447 447 (doesn't put the created macro on user namespace)
448 448
449 449 _ip.defmacro('build', 'bldmake bldfiles\nabld build winscw udeb')
450 450
451 451 (creates a macro named 'build' in user namespace)
452 452 """
453 453
454 454 import IPython.macro
455 455
456 456 if len(args) == 1:
457 457 return IPython.macro.Macro(args[0])
458 458 elif len(args) == 2:
459 459 self.user_ns[args[0]] = IPython.macro.Macro(args[1])
460 460 else:
461 461 return Exception("_ip.defmacro must be called with 1 or 2 arguments")
462 462
463 463 def set_next_input(self, s):
464 464 """ Sets the 'default' input string for the next command line.
465 465
466 466 Requires readline.
467 467
468 468 Example:
469 469
470 470 [D:\ipython]|1> _ip.set_next_input("Hello Word")
471 471 [D:\ipython]|2> Hello Word_ # cursor is here
472 472 """
473 473
474 474 self.IP.rl_next_input = s
475 475
476 476 def load(self, mod):
477 477 """ Load an extension.
478 478
479 479 Some modules should (or must) be 'load()':ed, rather than just imported.
480 480
481 481 Loading will do:
482 482
483 483 - run init_ipython(ip)
484 484 - run ipython_firstrun(ip)
485 485
486 486 """
487 487 if mod in self.extensions:
488 488 # just to make sure we don't init it twice
489 489 # note that if you 'load' a module that has already been
490 490 # imported, init_ipython gets run anyway
491 491
492 492 return self.extensions[mod]
493 493 __import__(mod)
494 494 m = sys.modules[mod]
495 495 if hasattr(m,'init_ipython'):
496 496 m.init_ipython(self)
497 497
498 498 if hasattr(m,'ipython_firstrun'):
499 499 already_loaded = self.db.get('firstrun_done', set())
500 500 if mod not in already_loaded:
501 501 m.ipython_firstrun(self)
502 502 already_loaded.add(mod)
503 503 self.db['firstrun_done'] = already_loaded
504 504
505 505 self.extensions[mod] = m
506 506 return m
507 507
508 508
509 509 class DebugTools:
510 510 """ Used for debugging mishaps in api usage
511 511
512 512 So far, tracing redefinitions is supported.
513 513 """
514 514
515 515 def __init__(self, ip):
516 516 self.ip = ip
517 517 self.debugmode = False
518 518 self.hotnames = set()
519 519
520 520 def hotname(self, name_to_catch):
521 521 self.hotnames.add(name_to_catch)
522 522
523 523 def debug_stack(self, msg = None):
524 524 if not self.debugmode:
525 525 return
526 526
527 527 import traceback
528 528 if msg is not None:
529 529 print '====== %s ========' % msg
530 530 traceback.print_stack()
531 531
532 532 def check_hotname(self,name):
533 533 if name in self.hotnames:
534 534 self.debug_stack( "HotName '%s' caught" % name)
535 535
536 def launch_new_instance(user_ns = None):
536 def launch_new_instance(user_ns = None,shellclass = None):
537 537 """ Make and start a new ipython instance.
538 538
539 539 This can be called even without having an already initialized
540 540 ipython session running.
541 541
542 542 This is also used as the egg entry point for the 'ipython' script.
543 543
544 544 """
545 ses = make_session(user_ns)
545 ses = make_session(user_ns,shellclass)
546 546 ses.mainloop()
547 547
548 548
549 549 def make_user_ns(user_ns = None):
550 550 """Return a valid user interactive namespace.
551 551
552 552 This builds a dict with the minimal information needed to operate as a
553 553 valid IPython user namespace, which you can pass to the various embedding
554 554 classes in ipython.
555 555 """
556 556
557 557 if user_ns is None:
558 558 # Set __name__ to __main__ to better match the behavior of the
559 559 # normal interpreter.
560 560 user_ns = {'__name__' :'__main__',
561 561 '__builtins__' : __builtin__,
562 562 }
563 563 else:
564 564 user_ns.setdefault('__name__','__main__')
565 565 user_ns.setdefault('__builtins__',__builtin__)
566 566
567 567 return user_ns
568 568
569 569
570 570 def make_user_global_ns(ns = None):
571 571 """Return a valid user global namespace.
572 572
573 573 Similar to make_user_ns(), but global namespaces are really only needed in
574 574 embedded applications, where there is a distinction between the user's
575 575 interactive namespace and the global one where ipython is running."""
576 576
577 577 if ns is None: ns = {}
578 578 return ns
579 579
580 580
581 def make_session(user_ns = None):
581 def make_session(user_ns = None, shellclass = None):
582 582 """Makes, but does not launch an IPython session.
583 583
584 584 Later on you can call obj.mainloop() on the returned object.
585 585
586 586 Inputs:
587 587
588 588 - user_ns(None): a dict to be used as the user's namespace with initial
589 589 data.
590 590
591 591 WARNING: This should *not* be run when a session exists already."""
592 592
593 593 import IPython.Shell
594 return IPython.Shell.start(user_ns)
595
596
594 if shellclass is None:
595 return IPython.Shell.start(user_ns)
596 return shellclass(user_ns = user_ns)
@@ -1,32 +1,42 b''
1 1 """ An example of one way to embed IPython in your own application
2 2
3 3 This basically means starting up IPython with some of your programs objects visible in the IPython
4 4 user namespace.
5 5
6 6 """
7 7
8 8 import sys
9 sys.path.append('..')
9 sys.path.insert(1,'..')
10 10
11 11 import IPython.ipapi
12 12
13 my_ns = dict(a=10)
14 13
15 ses = IPython.ipapi.make_session(my_ns)
16 14
17 # Now get the ipapi instance, to be stored somewhere in your program for manipulation of the running
18 # IPython session. See http://ipython.scipy.org/moin/IpythonExtensionApi
19
20 ip = ses.IP.getapi()
21
22 # let's play with the ipapi a bit, creating a magic function for a soon-to-be-started IPython
23 def mymagic_f(self,s):
24 print "mymagic says",s
25
26 ip.expose_magic("mymagic",mymagic_f)
27
28 # And finally, start the IPython interaction! This will block until you say Exit.
29
30 ses.mainloop()
31
32 print "IPython session finished! namespace content:",my_ns
15 def test_session(shellclass):
16 print "*****************\nLaunch shell for",shellclass
17 my_ns = dict(a=10)
18 ses = IPython.ipapi.make_session(my_ns)
19
20 # Now get the ipapi instance, to be stored somewhere in your program for manipulation of the running
21 # IPython session. See http://ipython.scipy.org/moin/IpythonExtensionApi
22
23 ip = ses.IP.getapi()
24
25 # let's play with the ipapi a bit, creating a magic function for a soon-to-be-started IPython
26 def mymagic_f(self,s):
27 print "mymagic says",s
28
29 ip.expose_magic("mymagic",mymagic_f)
30
31 # And finally, start the IPython interaction! This will block until you say Exit.
32
33 ses.mainloop()
34
35 print "IPython session for shell ",shellclass," finished! namespace content:"
36 for k,v in my_ns.items():
37 print k,':',str(v)[:80].rstrip()
38
39 import IPython.Shell
40
41 test_session(shellclass = None)
42 test_session(IPython.Shell._select_shell(['ipython', '-q4thread']))
General Comments 0
You need to be logged in to leave comments. Login now