##// END OF EJS Templates
fix ipython-qtconsole when run as a GUI script
Min RK -
Show More
@@ -1,393 +1,398 b''
1 1 # encoding: utf-8
2 2 """
3 3 A base class for a configurable application.
4 4
5 5 Authors:
6 6
7 7 * Brian Granger
8 8 * Min RK
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Copyright (C) 2008-2011 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 22 import logging
23 23 import os
24 24 import re
25 25 import sys
26 26 from copy import deepcopy
27 27
28 28 from IPython.config.configurable import SingletonConfigurable
29 29 from IPython.config.loader import (
30 30 KeyValueConfigLoader, PyFileConfigLoader, Config, ArgumentError
31 31 )
32 32
33 33 from IPython.utils.traitlets import (
34 34 Unicode, List, Int, Enum, Dict, Instance, TraitError
35 35 )
36 36 from IPython.utils.importstring import import_item
37 37 from IPython.utils.text import indent, wrap_paragraphs, dedent
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # function for re-wrapping a helpstring
41 41 #-----------------------------------------------------------------------------
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Descriptions for the various sections
45 45 #-----------------------------------------------------------------------------
46 46
47 47 flag_description = """
48 48 Flags are command-line arguments passed as '--<flag>'.
49 49 These take no parameters, unlike regular key-value arguments.
50 50 They are typically used for setting boolean flags, or enabling
51 51 modes that involve setting multiple options together.
52 52
53 53 Flags *always* begin with '--', never just one '-'.
54 54 """.strip() # trim newlines of front and back
55 55
56 56 alias_description = """
57 57 These are commonly set parameters, given abbreviated aliases for convenience.
58 58 They are set in the same `name=value` way as class parameters, where
59 59 <name> is replaced by the real parameter for which it is an alias.
60 60 """.strip() # trim newlines of front and back
61 61
62 62 keyvalue_description = """
63 63 Parameters are set from command-line arguments of the form:
64 64 `Class.trait=value`. Parameters will *never* be prefixed with '-'.
65 65 This line is evaluated in Python, so simple expressions are allowed, e.g.
66 66 `C.a='range(3)'` For setting C.a=[0,1,2]
67 67 """.strip() # trim newlines of front and back
68 68
69 69 #-----------------------------------------------------------------------------
70 70 # Application class
71 71 #-----------------------------------------------------------------------------
72 72
73 73
74 74 class ApplicationError(Exception):
75 75 pass
76 76
77 77
78 78 class Application(SingletonConfigurable):
79 79 """A singleton application with full configuration support."""
80 80
81 81 # The name of the application, will usually match the name of the command
82 82 # line application
83 83 name = Unicode(u'application')
84 84
85 85 # The description of the application that is printed at the beginning
86 86 # of the help.
87 87 description = Unicode(u'This is an application.')
88 88 # default section descriptions
89 89 flag_description = Unicode(flag_description)
90 90 alias_description = Unicode(alias_description)
91 91 keyvalue_description = Unicode(keyvalue_description)
92 92
93 93
94 94 # A sequence of Configurable subclasses whose config=True attributes will
95 95 # be exposed at the command line.
96 96 classes = List([])
97 97
98 98 # The version string of this application.
99 99 version = Unicode(u'0.0')
100 100
101 101 # The log level for the application
102 102 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
103 103 default_value=logging.WARN,
104 104 config=True,
105 105 help="Set the log level by value or name.")
106 106 def _log_level_changed(self, name, old, new):
107 107 """Adjust the log level when log_level is set."""
108 108 if isinstance(new, basestring):
109 109 new = getattr(logging, new)
110 110 self.log_level = new
111 111 self.log.setLevel(new)
112 112
113 113 # the alias map for configurables
114 114 aliases = Dict(dict(log_level='Application.log_level'))
115 115
116 116 # flags for loading Configurables or store_const style flags
117 117 # flags are loaded from this dict by '--key' flags
118 118 # this must be a dict of two-tuples, the first element being the Config/dict
119 119 # and the second being the help string for the flag
120 120 flags = Dict()
121 121 def _flags_changed(self, name, old, new):
122 122 """ensure flags dict is valid"""
123 123 for key,value in new.iteritems():
124 124 assert len(value) == 2, "Bad flag: %r:%s"%(key,value)
125 125 assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value)
126 126 assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value)
127 127
128 128
129 129 # subcommands for launching other applications
130 130 # if this is not empty, this will be a parent Application
131 131 # this must be a dict of two-tuples,
132 132 # the first element being the application class/import string
133 133 # and the second being the help string for the subcommand
134 134 subcommands = Dict()
135 135 # parse_command_line will initialize a subapp, if requested
136 136 subapp = Instance('IPython.config.application.Application', allow_none=True)
137 137
138 138 # extra command-line arguments that don't set config values
139 139 extra_args = List(Unicode)
140 140
141 141
142 142 def __init__(self, **kwargs):
143 143 SingletonConfigurable.__init__(self, **kwargs)
144 144 # Add my class to self.classes so my attributes appear in command line
145 145 # options.
146 146 self.classes.insert(0, self.__class__)
147 147
148 148 self.init_logging()
149 149
150 150 def _config_changed(self, name, old, new):
151 151 SingletonConfigurable._config_changed(self, name, old, new)
152 152 self.log.debug('Config changed:')
153 153 self.log.debug(repr(new))
154 154
155 155 def init_logging(self):
156 156 """Start logging for this application.
157 157
158 158 The default is to log to stdout using a StreaHandler. The log level
159 159 starts at loggin.WARN, but this can be adjusted by setting the
160 160 ``log_level`` attribute.
161 161 """
162 162 self.log = logging.getLogger(self.__class__.__name__)
163 163 self.log.setLevel(self.log_level)
164 self._log_handler = logging.StreamHandler()
164 if sys.executable.endswith('pythonw.exe'):
165 # this should really go to a file, but file-logging is only
166 # hooked up in parallel applications
167 self._log_handler = logging.StreamHandler(open(os.devnull, 'w'))
168 else:
169 self._log_handler = logging.StreamHandler()
165 170 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
166 171 self._log_handler.setFormatter(self._log_formatter)
167 172 self.log.addHandler(self._log_handler)
168 173
169 174 def initialize(self, argv=None):
170 175 """Do the basic steps to configure me.
171 176
172 177 Override in subclasses.
173 178 """
174 179 self.parse_command_line(argv)
175 180
176 181
177 182 def start(self):
178 183 """Start the app mainloop.
179 184
180 185 Override in subclasses.
181 186 """
182 187 if self.subapp is not None:
183 188 return self.subapp.start()
184 189
185 190 def print_alias_help(self):
186 191 """Print the alias part of the help."""
187 192 if not self.aliases:
188 193 return
189 194
190 195 lines = ['Aliases']
191 196 lines.append('-'*len(lines[0]))
192 197 lines.append('')
193 198 for p in wrap_paragraphs(self.alias_description):
194 199 lines.append(p)
195 200 lines.append('')
196 201
197 202 classdict = {}
198 203 for cls in self.classes:
199 204 # include all parents (up to, but excluding Configurable) in available names
200 205 for c in cls.mro()[:-3]:
201 206 classdict[c.__name__] = c
202 207
203 208 for alias, longname in self.aliases.iteritems():
204 209 classname, traitname = longname.split('.',1)
205 210 cls = classdict[classname]
206 211
207 212 trait = cls.class_traits(config=True)[traitname]
208 213 help = cls.class_get_trait_help(trait)
209 214 help = help.replace(longname, "%s (%s)"%(alias, longname), 1)
210 215 lines.append(help)
211 216 lines.append('')
212 217 print '\n'.join(lines)
213 218
214 219 def print_flag_help(self):
215 220 """Print the flag part of the help."""
216 221 if not self.flags:
217 222 return
218 223
219 224 lines = ['Flags']
220 225 lines.append('-'*len(lines[0]))
221 226 lines.append('')
222 227 for p in wrap_paragraphs(self.flag_description):
223 228 lines.append(p)
224 229 lines.append('')
225 230
226 231 for m, (cfg,help) in self.flags.iteritems():
227 232 lines.append('--'+m)
228 233 lines.append(indent(dedent(help.strip())))
229 234 lines.append('')
230 235 print '\n'.join(lines)
231 236
232 237 def print_subcommands(self):
233 238 """Print the subcommand part of the help."""
234 239 if not self.subcommands:
235 240 return
236 241
237 242 lines = ["Subcommands"]
238 243 lines.append('-'*len(lines[0]))
239 244 for subc, (cls,help) in self.subcommands.iteritems():
240 245 lines.append("%s : %s"%(subc, cls))
241 246 if help:
242 247 lines.append(indent(dedent(help.strip())))
243 248 lines.append('')
244 249 print '\n'.join(lines)
245 250
246 251 def print_help(self, classes=False):
247 252 """Print the help for each Configurable class in self.classes.
248 253
249 254 If classes=False (the default), only flags and aliases are printed.
250 255 """
251 256 self.print_subcommands()
252 257 self.print_flag_help()
253 258 self.print_alias_help()
254 259
255 260 if classes:
256 261 if self.classes:
257 262 print "Class parameters"
258 263 print "----------------"
259 264 print
260 265 for p in wrap_paragraphs(self.keyvalue_description):
261 266 print p
262 267 print
263 268
264 269 for cls in self.classes:
265 270 cls.class_print_help()
266 271 print
267 272 else:
268 273 print "To see all available configurables, use `--help-all`"
269 274 print
270 275
271 276 def print_description(self):
272 277 """Print the application description."""
273 278 for p in wrap_paragraphs(self.description):
274 279 print p
275 280 print
276 281
277 282 def print_version(self):
278 283 """Print the version string."""
279 284 print self.version
280 285
281 286 def update_config(self, config):
282 287 """Fire the traits events when the config is updated."""
283 288 # Save a copy of the current config.
284 289 newconfig = deepcopy(self.config)
285 290 # Merge the new config into the current one.
286 291 newconfig._merge(config)
287 292 # Save the combined config as self.config, which triggers the traits
288 293 # events.
289 294 self.config = newconfig
290 295
291 296 def initialize_subcommand(self, subc, argv=None):
292 297 """Initialize a subcommand with argv."""
293 298 subapp,help = self.subcommands.get(subc)
294 299
295 300 if isinstance(subapp, basestring):
296 301 subapp = import_item(subapp)
297 302
298 303 # clear existing instances
299 304 self.__class__.clear_instance()
300 305 # instantiate
301 306 self.subapp = subapp.instance()
302 307 # and initialize subapp
303 308 self.subapp.initialize(argv)
304 309
305 310 def parse_command_line(self, argv=None):
306 311 """Parse the command line arguments."""
307 312 argv = sys.argv[1:] if argv is None else argv
308 313
309 314 if self.subcommands and len(argv) > 0:
310 315 # we have subcommands, and one may have been specified
311 316 subc, subargv = argv[0], argv[1:]
312 317 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
313 318 # it's a subcommand, and *not* a flag or class parameter
314 319 return self.initialize_subcommand(subc, subargv)
315 320
316 321 if '-h' in argv or '--help' in argv or '--help-all' in argv:
317 322 self.print_description()
318 323 self.print_help('--help-all' in argv)
319 324 self.exit(0)
320 325
321 326 if '--version' in argv:
322 327 self.print_version()
323 328 self.exit(0)
324 329
325 330 loader = KeyValueConfigLoader(argv=argv, aliases=self.aliases,
326 331 flags=self.flags)
327 332 try:
328 333 config = loader.load_config()
329 334 self.update_config(config)
330 335 except (TraitError, ArgumentError) as e:
331 336 self.print_description()
332 337 self.print_help()
333 338 self.log.fatal(str(e))
334 339 self.exit(1)
335 340 # store unparsed args in extra_args
336 341 self.extra_args = loader.extra_args
337 342
338 343 def load_config_file(self, filename, path=None):
339 344 """Load a .py based config file by filename and path."""
340 345 loader = PyFileConfigLoader(filename, path=path)
341 346 config = loader.load_config()
342 347 self.update_config(config)
343 348
344 349 def generate_config_file(self):
345 350 """generate default config file from Configurables"""
346 351 lines = ["# Configuration file for %s."%self.name]
347 352 lines.append('')
348 353 lines.append('c = get_config()')
349 354 lines.append('')
350 355 for cls in self.classes:
351 356 lines.append(cls.class_config_section())
352 357 return '\n'.join(lines)
353 358
354 359 def exit(self, exit_status=0):
355 360 self.log.debug("Exiting application: %s" % self.name)
356 361 sys.exit(exit_status)
357 362
358 363 #-----------------------------------------------------------------------------
359 364 # utility functions, for convenience
360 365 #-----------------------------------------------------------------------------
361 366
362 367 def boolean_flag(name, configurable, set_help='', unset_help=''):
363 368 """Helper for building basic --trait, --no-trait flags.
364 369
365 370 Parameters
366 371 ----------
367 372
368 373 name : str
369 374 The name of the flag.
370 375 configurable : str
371 376 The 'Class.trait' string of the trait to be set/unset with the flag
372 377 set_help : unicode
373 378 help string for --name flag
374 379 unset_help : unicode
375 380 help string for --no-name flag
376 381
377 382 Returns
378 383 -------
379 384
380 385 cfg : dict
381 386 A dict with two keys: 'name', and 'no-name', for setting and unsetting
382 387 the trait, respectively.
383 388 """
384 389 # default helpstrings
385 390 set_help = set_help or "set %s=True"%configurable
386 391 unset_help = unset_help or "set %s=False"%configurable
387 392
388 393 cls,trait = configurable.split('.')
389 394
390 395 setter = {cls : {trait : True}}
391 396 unsetter = {cls : {trait : False}}
392 397 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
393 398
@@ -1,216 +1,216 b''
1 1 #!/usr/bin/env python
2 2 """An Application for launching a kernel
3 3
4 4 Authors
5 5 -------
6 6 * MinRK
7 7 """
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING.txt, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # Standard library imports.
20 20 import os
21 21 import sys
22 22
23 23 # System library imports.
24 24 import zmq
25 25
26 26 # IPython imports.
27 27 from IPython.core.ultratb import FormattedTB
28 28 from IPython.core.application import (
29 29 BaseIPythonApplication, base_flags, base_aliases
30 30 )
31 31 from IPython.utils import io
32 32 from IPython.utils.localinterfaces import LOCALHOST
33 33 from IPython.utils.traitlets import (Any, Instance, Dict, Unicode, Int, Bool,
34 34 DottedObjectName)
35 35 from IPython.utils.importstring import import_item
36 36 # local imports
37 37 from IPython.zmq.heartbeat import Heartbeat
38 38 from IPython.zmq.parentpoller import ParentPollerUnix, ParentPollerWindows
39 39 from IPython.zmq.session import Session
40 40
41 41
42 42 #-----------------------------------------------------------------------------
43 43 # Flags and Aliases
44 44 #-----------------------------------------------------------------------------
45 45
46 46 kernel_aliases = dict(base_aliases)
47 47 kernel_aliases.update({
48 48 'ip' : 'KernelApp.ip',
49 49 'hb' : 'KernelApp.hb_port',
50 50 'shell' : 'KernelApp.shell_port',
51 51 'iopub' : 'KernelApp.iopub_port',
52 52 'stdin' : 'KernelApp.stdin_port',
53 53 'parent': 'KernelApp.parent',
54 54 })
55 55 if sys.platform.startswith('win'):
56 56 kernel_aliases['interrupt'] = 'KernelApp.interrupt'
57 57
58 58 kernel_flags = dict(base_flags)
59 59 kernel_flags.update({
60 60 'no-stdout' : (
61 61 {'KernelApp' : {'no_stdout' : True}},
62 62 "redirect stdout to the null device"),
63 63 'no-stderr' : (
64 64 {'KernelApp' : {'no_stderr' : True}},
65 65 "redirect stderr to the null device"),
66 66 })
67 67
68 68
69 69 #-----------------------------------------------------------------------------
70 70 # Application class for starting a Kernel
71 71 #-----------------------------------------------------------------------------
72 72
73 73 class KernelApp(BaseIPythonApplication):
74 74 name='pykernel'
75 75 aliases = Dict(kernel_aliases)
76 76 flags = Dict(kernel_flags)
77 77 classes = [Session]
78 78 # the kernel class, as an importstring
79 79 kernel_class = DottedObjectName('IPython.zmq.pykernel.Kernel')
80 80 kernel = Any()
81 81 poller = Any() # don't restrict this even though current pollers are all Threads
82 82 heartbeat = Instance(Heartbeat)
83 83 session = Instance('IPython.zmq.session.Session')
84 84 ports = Dict()
85 85
86 86 # connection info:
87 87 ip = Unicode(LOCALHOST, config=True,
88 88 help="Set the IP or interface on which the kernel will listen.")
89 89 hb_port = Int(0, config=True, help="set the heartbeat port [default: random]")
90 90 shell_port = Int(0, config=True, help="set the shell (XREP) port [default: random]")
91 91 iopub_port = Int(0, config=True, help="set the iopub (PUB) port [default: random]")
92 92 stdin_port = Int(0, config=True, help="set the stdin (XREQ) port [default: random]")
93 93
94 94 # streams, etc.
95 95 no_stdout = Bool(False, config=True, help="redirect stdout to the null device")
96 96 no_stderr = Bool(False, config=True, help="redirect stderr to the null device")
97 97 outstream_class = DottedObjectName('IPython.zmq.iostream.OutStream',
98 98 config=True, help="The importstring for the OutStream factory")
99 99 displayhook_class = DottedObjectName('IPython.zmq.displayhook.ZMQDisplayHook',
100 100 config=True, help="The importstring for the DisplayHook factory")
101 101
102 102 # polling
103 103 parent = Int(0, config=True,
104 104 help="""kill this process if its parent dies. On Windows, the argument
105 105 specifies the HANDLE of the parent process, otherwise it is simply boolean.
106 106 """)
107 107 interrupt = Int(0, config=True,
108 108 help="""ONLY USED ON WINDOWS
109 109 Interrupt this process when the parent is signalled.
110 110 """)
111 111
112 112 def init_crash_handler(self):
113 113 # Install minimal exception handling
114 114 sys.excepthook = FormattedTB(mode='Verbose', color_scheme='NoColor',
115 115 ostream=sys.__stdout__)
116 116
117 117 def init_poller(self):
118 118 if sys.platform == 'win32':
119 119 if self.interrupt or self.parent:
120 120 self.poller = ParentPollerWindows(self.interrupt, self.parent)
121 121 elif self.parent:
122 122 self.poller = ParentPollerUnix()
123 123
124 124 def _bind_socket(self, s, port):
125 125 iface = 'tcp://%s' % self.ip
126 126 if port <= 0:
127 127 port = s.bind_to_random_port(iface)
128 128 else:
129 129 s.bind(iface + ':%i'%port)
130 130 return port
131 131
132 132 def init_sockets(self):
133 133 # Create a context, a session, and the kernel sockets.
134 134 io.raw_print("Starting the kernel at pid:", os.getpid())
135 135 context = zmq.Context.instance()
136 136 # Uncomment this to try closing the context.
137 137 # atexit.register(context.term)
138 138
139 139 self.shell_socket = context.socket(zmq.XREP)
140 140 self.shell_port = self._bind_socket(self.shell_socket, self.shell_port)
141 141 self.log.debug("shell XREP Channel on port: %i"%self.shell_port)
142 142
143 143 self.iopub_socket = context.socket(zmq.PUB)
144 144 self.iopub_port = self._bind_socket(self.iopub_socket, self.iopub_port)
145 145 self.log.debug("iopub PUB Channel on port: %i"%self.iopub_port)
146 146
147 147 self.stdin_socket = context.socket(zmq.XREQ)
148 148 self.stdin_port = self._bind_socket(self.stdin_socket, self.stdin_port)
149 149 self.log.debug("stdin XREQ Channel on port: %i"%self.stdin_port)
150 150
151 151 self.heartbeat = Heartbeat(context, (self.ip, self.hb_port))
152 152 self.hb_port = self.heartbeat.port
153 153 self.log.debug("Heartbeat REP Channel on port: %i"%self.hb_port)
154 154
155 155 # Helper to make it easier to connect to an existing kernel, until we have
156 156 # single-port connection negotiation fully implemented.
157 157 self.log.info("To connect another client to this kernel, use:")
158 158 self.log.info("--external shell={0} iopub={1} stdin={2} hb={3}".format(
159 159 self.shell_port, self.iopub_port, self.stdin_port, self.hb_port))
160 160
161 161
162 162 self.ports = dict(shell=self.shell_port, iopub=self.iopub_port,
163 163 stdin=self.stdin_port, hb=self.hb_port)
164 164
165 165 def init_session(self):
166 166 """create our session object"""
167 167 self.session = Session(config=self.config, username=u'kernel')
168 168
169 def init_io(self):
170 """redirects stdout/stderr, and installs a display hook"""
171 # Re-direct stdout/stderr, if necessary.
169 def init_blackhole(self):
170 """redirects stdout/stderr to devnull if necessary"""
172 171 if self.no_stdout or self.no_stderr:
173 172 blackhole = file(os.devnull, 'w')
174 173 if self.no_stdout:
175 174 sys.stdout = sys.__stdout__ = blackhole
176 175 if self.no_stderr:
177 176 sys.stderr = sys.__stderr__ = blackhole
178
179 # Redirect input streams and set a display hook.
180
177
178 def init_io(self):
179 """Redirect input streams and set a display hook."""
181 180 if self.outstream_class:
182 181 outstream_factory = import_item(str(self.outstream_class))
183 182 sys.stdout = outstream_factory(self.session, self.iopub_socket, u'stdout')
184 183 sys.stderr = outstream_factory(self.session, self.iopub_socket, u'stderr')
185 184 if self.displayhook_class:
186 185 displayhook_factory = import_item(str(self.displayhook_class))
187 186 sys.displayhook = displayhook_factory(self.session, self.iopub_socket)
188 187
189 188 def init_kernel(self):
190 189 """Create the Kernel object itself"""
191 190 kernel_factory = import_item(str(self.kernel_class))
192 191 self.kernel = kernel_factory(config=self.config, session=self.session,
193 192 shell_socket=self.shell_socket,
194 193 iopub_socket=self.iopub_socket,
195 194 stdin_socket=self.stdin_socket,
196 195 log=self.log
197 196 )
198 197 self.kernel.record_ports(self.ports)
199 198
200 199 def initialize(self, argv=None):
201 200 super(KernelApp, self).initialize(argv)
201 self.init_blackhole()
202 202 self.init_session()
203 203 self.init_poller()
204 204 self.init_sockets()
205 205 self.init_io()
206 206 self.init_kernel()
207 207
208 208 def start(self):
209 209 self.heartbeat.start()
210 210 if self.poller is not None:
211 211 self.poller.start()
212 212 try:
213 213 self.kernel.start()
214 214 except KeyboardInterrupt:
215 215 pass
216 216
General Comments 0
You need to be logged in to leave comments. Login now