##// END OF EJS Templates
remove all trailling spaces
Bernardo B. Marques -
Show More
@@ -109,10 +109,10 b' class Application(SingletonConfigurable):'
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({'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
@@ -124,20 +124,20 b' class Application(SingletonConfigurable):'
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
128
127
128
129 129 # subcommands for launching other applications
130 130 # if this is not empty, this will be a parent Application
131 # this must be a dict of two-tuples,
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)
@@ -145,7 +145,7 b' class Application(SingletonConfigurable):'
145 145 # options and config files.
146 146 if self.__class__ not in self.classes:
147 147 self.classes.insert(0, self.__class__)
148
148
149 149 self.init_logging()
150 150
151 151 def _config_changed(self, name, old, new):
@@ -157,7 +157,7 b' class Application(SingletonConfigurable):'
157 157 """Start logging for this application.
158 158
159 159 The default is to log to stdout using a StreaHandler. The log level
160 starts at loggin.WARN, but this can be adjusted by setting the
160 starts at loggin.WARN, but this can be adjusted by setting the
161 161 ``log_level`` attribute.
162 162 """
163 163 self.log = logging.getLogger(self.__class__.__name__)
@@ -174,36 +174,36 b' class Application(SingletonConfigurable):'
174 174
175 175 def initialize(self, argv=None):
176 176 """Do the basic steps to configure me.
177
177
178 178 Override in subclasses.
179 179 """
180 180 self.parse_command_line(argv)
181
182
181
182
183 183 def start(self):
184 184 """Start the app mainloop.
185
185
186 186 Override in subclasses.
187 187 """
188 188 if self.subapp is not None:
189 189 return self.subapp.start()
190
190
191 191 def print_alias_help(self):
192 192 """Print the alias part of the help."""
193 193 if not self.aliases:
194 194 return
195
195
196 196 lines = []
197 197 classdict = {}
198 198 for cls in self.classes:
199 199 # include all parents (up to, but excluding Configurable) in available names
200 200 for c in cls.mro()[:-3]:
201 201 classdict[c.__name__] = c
202
202
203 203 for alias, longname in self.aliases.iteritems():
204 204 classname, traitname = longname.split('.',1)
205 205 cls = classdict[classname]
206
206
207 207 trait = cls.class_traits(config=True)[traitname]
208 208 help = cls.class_get_trait_help(trait).splitlines()
209 209 # reformat first line
@@ -213,12 +213,12 b' class Application(SingletonConfigurable):'
213 213 lines.extend(help)
214 214 # lines.append('')
215 215 print os.linesep.join(lines)
216
216
217 217 def print_flag_help(self):
218 218 """Print the flag part of the help."""
219 219 if not self.flags:
220 220 return
221
221
222 222 lines = []
223 223 for m, (cfg,help) in self.flags.iteritems():
224 224 prefix = '--' if len(m) > 1 else '-'
@@ -226,7 +226,7 b' class Application(SingletonConfigurable):'
226 226 lines.append(indent(dedent(help.strip())))
227 227 # lines.append('')
228 228 print os.linesep.join(lines)
229
229
230 230 def print_options(self):
231 231 if not self.flags and not self.aliases:
232 232 return
@@ -240,12 +240,12 b' class Application(SingletonConfigurable):'
240 240 self.print_flag_help()
241 241 self.print_alias_help()
242 242 print
243
243
244 244 def print_subcommands(self):
245 245 """Print the subcommand part of the help."""
246 246 if not self.subcommands:
247 247 return
248
248
249 249 lines = ["Subcommands"]
250 250 lines.append('-'*len(lines[0]))
251 251 lines.append('')
@@ -258,15 +258,15 b' class Application(SingletonConfigurable):'
258 258 lines.append(indent(dedent(help.strip())))
259 259 lines.append('')
260 260 print os.linesep.join(lines)
261
261
262 262 def print_help(self, classes=False):
263 263 """Print the help for each Configurable class in self.classes.
264
264
265 265 If classes=False (the default), only flags and aliases are printed.
266 266 """
267 267 self.print_subcommands()
268 268 self.print_options()
269
269
270 270 if classes:
271 271 if self.classes:
272 272 print "Class parameters"
@@ -275,7 +275,7 b' class Application(SingletonConfigurable):'
275 275 for p in wrap_paragraphs(self.keyvalue_description):
276 276 print p
277 277 print
278
278
279 279 for cls in self.classes:
280 280 cls.class_print_help()
281 281 print
@@ -315,21 +315,21 b' class Application(SingletonConfigurable):'
315 315 # Save the combined config as self.config, which triggers the traits
316 316 # events.
317 317 self.config = newconfig
318
318
319 319 def initialize_subcommand(self, subc, argv=None):
320 320 """Initialize a subcommand with argv."""
321 321 subapp,help = self.subcommands.get(subc)
322
322
323 323 if isinstance(subapp, basestring):
324 324 subapp = import_item(subapp)
325
325
326 326 # clear existing instances
327 327 self.__class__.clear_instance()
328 328 # instantiate
329 329 self.subapp = subapp.instance()
330 330 # and initialize subapp
331 331 self.subapp.initialize(argv)
332
332
333 333 def parse_command_line(self, argv=None):
334 334 """Parse the command line arguments."""
335 335 argv = sys.argv[1:] if argv is None else argv
@@ -340,7 +340,7 b' class Application(SingletonConfigurable):'
340 340 if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands:
341 341 # it's a subcommand, and *not* a flag or class parameter
342 342 return self.initialize_subcommand(subc, subargv)
343
343
344 344 if '-h' in argv or '--help' in argv or '--help-all' in argv:
345 345 self.print_description()
346 346 self.print_help('--help-all' in argv)
@@ -350,7 +350,7 b' class Application(SingletonConfigurable):'
350 350 if '--version' in argv:
351 351 self.print_version()
352 352 self.exit(0)
353
353
354 354 loader = KVArgParseConfigLoader(argv=argv, aliases=self.aliases,
355 355 flags=self.flags)
356 356 try:
@@ -383,7 +383,7 b' class Application(SingletonConfigurable):'
383 383 else:
384 384 self.log.debug("Loaded config file: %s", loader.full_filename)
385 385 self.update_config(config)
386
386
387 387 def generate_config_file(self):
388 388 """generate default config file from Configurables"""
389 389 lines = ["# Configuration file for %s."%self.name]
@@ -404,10 +404,10 b' class Application(SingletonConfigurable):'
404 404
405 405 def boolean_flag(name, configurable, set_help='', unset_help=''):
406 406 """Helper for building basic --trait, --no-trait flags.
407
407
408 408 Parameters
409 409 ----------
410
410
411 411 name : str
412 412 The name of the flag.
413 413 configurable : str
@@ -416,10 +416,10 b" def boolean_flag(name, configurable, set_help='', unset_help=''):"
416 416 help string for --name flag
417 417 unset_help : unicode
418 418 help string for --no-name flag
419
419
420 420 Returns
421 421 -------
422
422
423 423 cfg : dict
424 424 A dict with two keys: 'name', and 'no-name', for setting and unsetting
425 425 the trait, respectively.
@@ -427,9 +427,9 b" def boolean_flag(name, configurable, set_help='', unset_help=''):"
427 427 # default helpstrings
428 428 set_help = set_help or "set %s=True"%configurable
429 429 unset_help = unset_help or "set %s=False"%configurable
430
430
431 431 cls,trait = configurable.split('.')
432
432
433 433 setter = {cls : {trait : True}}
434 434 unsetter = {cls : {trait : False}}
435 435 return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)}
@@ -55,16 +55,16 b' class Configurable(HasTraits):'
55 55 Parameters
56 56 ----------
57 57 config : Config
58 If this is empty, default values are used. If config is a
58 If this is empty, default values are used. If config is a
59 59 :class:`Config` instance, it will be used to configure the
60 60 instance.
61
61
62 62 Notes
63 63 -----
64 64 Subclasses of Configurable must call the :meth:`__init__` method of
65 :class:`Configurable` *before* doing anything else and using
65 :class:`Configurable` *before* doing anything else and using
66 66 :func:`super`::
67
67
68 68 class MyConfigurable(Configurable):
69 69 def __init__(self, config=None):
70 70 super(MyConfigurable, self).__init__(config)
@@ -82,7 +82,7 b' class Configurable(HasTraits):'
82 82 # making that a class attribute.
83 83 # self.config = deepcopy(config)
84 84 self.config = config
85 # This should go second so individual keyword arguments override
85 # This should go second so individual keyword arguments override
86 86 # the values in config.
87 87 super(Configurable, self).__init__(**kwargs)
88 88 self.created = datetime.datetime.now()
@@ -105,11 +105,11 b' class Configurable(HasTraits):'
105 105 # classes that are Configurable subclasses. This starts with Configurable
106 106 # and works down the mro loading the config for each section.
107 107 section_names = [cls.__name__ for cls in \
108 reversed(self.__class__.__mro__) if
108 reversed(self.__class__.__mro__) if
109 109 issubclass(cls, Configurable) and issubclass(self.__class__, cls)]
110 110
111 111 for sname in section_names:
112 # Don't do a blind getattr as that would cause the config to
112 # Don't do a blind getattr as that would cause the config to
113 113 # dynamically create the section with name self.__class__.__name__.
114 114 if new._has_section(sname):
115 115 my_config = new[sname]
@@ -149,7 +149,7 b' class Configurable(HasTraits):'
149 149 help = cls.class_get_trait_help(v)
150 150 final_help.append(help)
151 151 return '\n'.join(final_help)
152
152
153 153 @classmethod
154 154 def class_get_trait_help(cls, trait):
155 155 """Get the help string for a single trait."""
@@ -167,7 +167,7 b' class Configurable(HasTraits):'
167 167 if 'Enum' in trait.__class__.__name__:
168 168 # include Enum choices
169 169 lines.append(indent('Choices: %r'%(trait.values,)))
170
170
171 171 help = trait.get_metadata('help')
172 172 if help is not None:
173 173 help = '\n'.join(wrap_paragraphs(help, 76))
@@ -185,9 +185,9 b' class Configurable(HasTraits):'
185 185 def c(s):
186 186 """return a commented, wrapped block."""
187 187 s = '\n\n'.join(wrap_paragraphs(s, 78))
188
188
189 189 return '# ' + s.replace('\n', '\n# ')
190
190
191 191 # section header
192 192 breaker = '#' + '-'*78
193 193 s = "# %s configuration"%cls.__name__
@@ -202,7 +202,7 b' class Configurable(HasTraits):'
202 202 if desc:
203 203 lines.append(c(desc))
204 204 lines.append('')
205
205
206 206 parents = []
207 207 for parent in cls.mro():
208 208 # only include parents that are not base classes
@@ -211,20 +211,20 b' class Configurable(HasTraits):'
211 211 if parent is not cls and issubclass(parent, Configurable) and \
212 212 parent.class_traits(config=True):
213 213 parents.append(parent)
214
214
215 215 if parents:
216 216 pstr = ', '.join([ p.__name__ for p in parents ])
217 217 lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr)))
218 218 lines.append('')
219
219
220 220 for name,trait in cls.class_traits(config=True).iteritems():
221 221 help = trait.get_metadata('help') or ''
222 222 lines.append(c(help))
223 223 lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value()))
224 224 lines.append('')
225 225 return '\n'.join(lines)
226
227
226
227
228 228
229 229 class SingletonConfigurable(Configurable):
230 230 """A configurable that only allows one instance.
@@ -235,20 +235,20 b' class SingletonConfigurable(Configurable):'
235 235 """
236 236
237 237 _instance = None
238
238
239 239 @classmethod
240 240 def _walk_mro(cls):
241 241 """Walk the cls.mro() for parent classes that are also singletons
242
242
243 243 For use in instance()
244 244 """
245
245
246 246 for subclass in cls.mro():
247 247 if issubclass(cls, subclass) and \
248 248 issubclass(subclass, SingletonConfigurable) and \
249 249 subclass != SingletonConfigurable:
250 250 yield subclass
251
251
252 252 @classmethod
253 253 def clear_instance(cls):
254 254 """unset _instance for this class and singleton parents.
@@ -260,7 +260,7 b' class SingletonConfigurable(Configurable):'
260 260 # only clear instances that are instances
261 261 # of the calling class
262 262 subclass._instance = None
263
263
264 264 @classmethod
265 265 def instance(cls, *args, **kwargs):
266 266 """Returns a global instance of this class.
@@ -297,7 +297,7 b' class SingletonConfigurable(Configurable):'
297 297 # parent classes' _instance attribute.
298 298 for subclass in cls._walk_mro():
299 299 subclass._instance = inst
300
300
301 301 if isinstance(cls._instance, cls):
302 302 return cls._instance
303 303 else:
@@ -314,15 +314,15 b' class SingletonConfigurable(Configurable):'
314 314
315 315 class LoggingConfigurable(Configurable):
316 316 """A parent class for Configurables that log.
317
317
318 318 Subclasses have a log trait, and the default behavior
319 319 is to get the logger from the currently running Application
320 320 via Application.instance().log.
321 321 """
322
322
323 323 log = Instance('logging.Logger')
324 324 def _log_default(self):
325 325 from IPython.config.application import Application
326 326 return Application.instance().log
327
328
327
328
@@ -53,14 +53,14 b' class ArgumentError(ConfigLoaderError):'
53 53
54 54 class ArgumentParser(argparse.ArgumentParser):
55 55 """Simple argparse subclass that prints help to stdout by default."""
56
56
57 57 def print_help(self, file=None):
58 58 if file is None:
59 59 file = sys.stdout
60 60 return super(ArgumentParser, self).print_help(file)
61
61
62 62 print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__
63
63
64 64 #-----------------------------------------------------------------------------
65 65 # Config class for holding config information
66 66 #-----------------------------------------------------------------------------
@@ -125,10 +125,10 b' class Config(dict):'
125 125 # infinite recursion on top of PyPy. Instead, we manually fish the
126 126 # bound method.
127 127 is_section_key = self.__class__._is_section_key.__get__(self)
128
128
129 129 # Because we use this for an exec namespace, we need to delegate
130 130 # the lookup of names in __builtin__ to itself. This means
131 # that you can't have section or attribute names that are
131 # that you can't have section or attribute names that are
132 132 # builtins.
133 133 try:
134 134 return getattr(builtin_mod, key)
@@ -182,25 +182,25 b' class Config(dict):'
182 182
183 183 class ConfigLoader(object):
184 184 """A object for loading configurations from just about anywhere.
185
185
186 186 The resulting configuration is packaged as a :class:`Struct`.
187
187
188 188 Notes
189 189 -----
190 A :class:`ConfigLoader` does one thing: load a config from a source
190 A :class:`ConfigLoader` does one thing: load a config from a source
191 191 (file, command line arguments) and returns the data as a :class:`Struct`.
192 192 There are lots of things that :class:`ConfigLoader` does not do. It does
193 193 not implement complex logic for finding config files. It does not handle
194 default values or merge multiple configs. These things need to be
194 default values or merge multiple configs. These things need to be
195 195 handled elsewhere.
196 196 """
197 197
198 198 def __init__(self):
199 199 """A base class for config loaders.
200
200
201 201 Examples
202 202 --------
203
203
204 204 >>> cl = ConfigLoader()
205 205 >>> config = cl.load_config()
206 206 >>> config
@@ -213,7 +213,7 b' class ConfigLoader(object):'
213 213
214 214 def load_config(self):
215 215 """Load a config from somewhere, return a :class:`Config` instance.
216
216
217 217 Usually, this will cause self.config to be set and then returned.
218 218 However, in most cases, :meth:`ConfigLoader.clear` should be called
219 219 to erase any previous state.
@@ -233,7 +233,7 b' class FileConfigLoader(ConfigLoader):'
233 233
234 234 class PyFileConfigLoader(FileConfigLoader):
235 235 """A config loader for pure python files.
236
236
237 237 This calls execfile on a plain python file and looks for attributes
238 238 that are all caps. These attribute are added to the config Struct.
239 239 """
@@ -276,10 +276,10 b' class PyFileConfigLoader(FileConfigLoader):'
276 276 # and self.config. The sub-config is loaded with the same path
277 277 # as the parent, but it uses an empty config which is then merged
278 278 # with the parents.
279
279
280 280 # If a profile is specified, the config file will be loaded
281 281 # from that profile
282
282
283 283 def load_subconfig(fname, profile=None):
284 284 # import here to prevent circular imports
285 285 from IPython.core.profiledir import ProfileDir, ProfileDirError
@@ -303,7 +303,7 b' class PyFileConfigLoader(FileConfigLoader):'
303 303 pass
304 304 else:
305 305 self.config._merge(sub_config)
306
306
307 307 # Again, this needs to be a closure and should be used in config
308 308 # files to get the config being loaded.
309 309 def get_config():
@@ -340,7 +340,7 b' class CommandLineConfigLoader(ConfigLoader):'
340 340 # it succeeds. If it still fails, we let it raise.
341 341 exec_str = u'self.config.' + lhs + '=' + repr(rhs)
342 342 exec exec_str in locals(), globals()
343
343
344 344 def _load_flag(self, cfg):
345 345 """update self.config from a flag, which can be a dict or Config"""
346 346 if isinstance(cfg, (dict, Config)):
@@ -373,7 +373,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
373 373 """A config loader that loads key value pairs from the command line.
374 374
375 375 This allows command line options to be gives in the following form::
376
376
377 377 ipython --profile="foo" --InteractiveShell.autocall=False
378 378 """
379 379
@@ -414,13 +414,13 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
414 414 self.argv = argv
415 415 self.aliases = aliases or {}
416 416 self.flags = flags or {}
417
418
417
418
419 419 def clear(self):
420 420 super(KeyValueConfigLoader, self).clear()
421 421 self.extra_args = []
422
423
422
423
424 424 def _decode_argv(self, argv, enc=None):
425 425 """decode argv if bytes, using stin.encoding, falling back on default enc"""
426 426 uargv = []
@@ -432,16 +432,16 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
432 432 arg = arg.decode(enc)
433 433 uargv.append(arg)
434 434 return uargv
435
436
435
436
437 437 def load_config(self, argv=None, aliases=None, flags=None):
438 438 """Parse the configuration and generate the Config object.
439
439
440 440 After loading, any arguments that are not key-value or
441 441 flags will be stored in self.extra_args - a list of
442 442 unparsed command-line arguments. This is used for
443 443 arguments such as input files or subcommands.
444
444
445 445 Parameters
446 446 ----------
447 447 argv : list, optional
@@ -454,7 +454,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
454 454 Of the form: `{'alias' : 'Configurable.trait'}`
455 455 flags : dict
456 456 A dict of flags, keyed by str name. Values can be Config objects
457 or dicts. When the flag is triggered, The config is loaded as
457 or dicts. When the flag is triggered, The config is loaded as
458 458 `self.config.update(cfg)`.
459 459 """
460 460 from IPython.config.configurable import Configurable
@@ -466,20 +466,20 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
466 466 aliases = self.aliases
467 467 if flags is None:
468 468 flags = self.flags
469
469
470 470 # ensure argv is a list of unicode strings:
471 471 uargv = self._decode_argv(argv)
472 472 for idx,raw in enumerate(uargv):
473 473 # strip leading '-'
474 474 item = raw.lstrip('-')
475
475
476 476 if raw == '--':
477 477 # don't parse arguments after '--'
478 478 # this is useful for relaying arguments to scripts, e.g.
479 479 # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py
480 480 self.extra_args.extend(uargv[idx+1:])
481 481 break
482
482
483 483 if kv_pattern.match(raw):
484 484 lhs,rhs = item.split('=',1)
485 485 # Substitute longnames for aliases.
@@ -489,7 +489,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
489 489 # probably a mistyped alias, but not technically illegal
490 490 warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs)
491 491 self._exec_config_str(lhs, rhs)
492
492
493 493 elif flag_pattern.match(raw):
494 494 if item in flags:
495 495 cfg,help = flags[item]
@@ -503,7 +503,7 b' class KeyValueConfigLoader(CommandLineConfigLoader):'
503 503 else:
504 504 raise ArgumentError("Invalid argument: '%s'"%raw)
505 505 else:
506 # keep all args that aren't valid in a list,
506 # keep all args that aren't valid in a list,
507 507 # in case our parent knows what to do with them.
508 508 self.extra_args.append(item)
509 509 return self.config
@@ -541,7 +541,7 b' class ArgParseConfigLoader(CommandLineConfigLoader):'
541 541 self.argv = argv
542 542 self.aliases = aliases or {}
543 543 self.flags = flags or {}
544
544
545 545 self.parser_args = parser_args
546 546 self.version = parser_kw.pop("version", None)
547 547 kwargs = dict(argument_default=argparse.SUPPRESS)
@@ -597,10 +597,10 b' class ArgParseConfigLoader(CommandLineConfigLoader):'
597 597
598 598 class KVArgParseConfigLoader(ArgParseConfigLoader):
599 599 """A config loader that loads aliases and flags with argparse,
600 but will use KVLoader for the rest. This allows better parsing
600 but will use KVLoader for the rest. This allows better parsing
601 601 of common args, such as `ipython -c 'print 5'`, but still gets
602 602 arbitrary config with `ipython --InteractiveShell.use_readline=False`"""
603
603
604 604 def _convert_to_config(self):
605 605 """self.parsed_data->self.config"""
606 606 for k, v in vars(self.parsed_data).iteritems():
@@ -626,14 +626,14 b' class KVArgParseConfigLoader(ArgParseConfigLoader):'
626 626 paa('--'+key, type=unicode, dest=value, nargs=nargs)
627 627 for key, (value, help) in flags.iteritems():
628 628 if key in self.aliases:
629 #
629 #
630 630 self.alias_flags[self.aliases[key]] = value
631 631 continue
632 632 if len(key) is 1:
633 633 paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value)
634 634 else:
635 635 paa('--'+key, action='append_const', dest='_flags', const=value)
636
636
637 637 def _convert_to_config(self):
638 638 """self.parsed_data->self.config, parse unrecognized extra args via KVLoader."""
639 639 # remove subconfigs list from namespace before transforming the Namespace
@@ -642,7 +642,7 b' class KVArgParseConfigLoader(ArgParseConfigLoader):'
642 642 del self.parsed_data._flags
643 643 else:
644 644 subcs = []
645
645
646 646 for k, v in vars(self.parsed_data).iteritems():
647 647 if v is None:
648 648 # it was a flag that shares the name of an alias
@@ -650,10 +650,10 b' class KVArgParseConfigLoader(ArgParseConfigLoader):'
650 650 else:
651 651 # eval the KV assignment
652 652 self._exec_config_str(k, v)
653
653
654 654 for subc in subcs:
655 655 self._load_flag(subc)
656
656
657 657 if self.extra_args:
658 658 sub_parser = KeyValueConfigLoader()
659 659 sub_parser.load_config(self.extra_args)
@@ -49,7 +49,7 b' def default_aliases():'
49 49 # their case. For example, things like 'less' or 'clear' that manipulate
50 50 # the terminal should NOT be declared here, as they will only work if the
51 51 # kernel is running inside a true terminal, and not over the network.
52
52
53 53 if os.name == 'posix':
54 54 default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'),
55 55 ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'),
@@ -94,7 +94,7 b' def default_aliases():'
94 94 ]
95 95 else:
96 96 default_aliases = []
97
97
98 98 return default_aliases
99 99
100 100
@@ -213,33 +213,33 b' class AliasManager(Configurable):'
213 213 return cmd
214 214
215 215 def expand_alias(self, line):
216 """ Expand an alias in the command line
217
218 Returns the provided command line, possibly with the first word
216 """ Expand an alias in the command line
217
218 Returns the provided command line, possibly with the first word
219 219 (command) translated according to alias expansion rules.
220
220
221 221 [ipython]|16> _ip.expand_aliases("np myfile.txt")
222 222 <16> 'q:/opt/np/notepad++.exe myfile.txt'
223 223 """
224
224
225 225 pre,_,fn,rest = split_user_input(line)
226 226 res = pre + self.expand_aliases(fn, rest)
227 227 return res
228 228
229 229 def expand_aliases(self, fn, rest):
230 230 """Expand multiple levels of aliases:
231
231
232 232 if:
233
233
234 234 alias foo bar /tmp
235 235 alias baz foo
236
236
237 237 then:
238
238
239 239 baz huhhahhei -> bar /tmp huhhahhei
240 240 """
241 241 line = fn + " " + rest
242
242
243 243 done = set()
244 244 while 1:
245 245 pre,_,fn,rest = split_user_input(line, shell_line_split)
@@ -259,5 +259,5 b' class AliasManager(Configurable):'
259 259 line=l2
260 260 else:
261 261 break
262
262
263 263 return line
@@ -5,7 +5,7 b' An application for IPython.'
5 5 All top-level applications should use the classes in this module for
6 6 handling configuration and creating componenets.
7 7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 9 object and then create the configurable objects, passing the config to them.
10 10
11 11 Authors:
@@ -78,15 +78,15 b' class BaseIPythonApplication(Application):'
78 78 name = Unicode(u'ipython')
79 79 description = Unicode(u'IPython: an enhanced interactive Python shell.')
80 80 version = Unicode(release.version)
81
81
82 82 aliases = Dict(base_aliases)
83 83 flags = Dict(base_flags)
84 84 classes = List([ProfileDir])
85
85
86 86 # Track whether the config_file has changed,
87 87 # because some logic happens only if we aren't using the default.
88 88 config_file_specified = Bool(False)
89
89
90 90 config_file_name = Unicode(u'ipython_config.py')
91 91 def _config_file_name_default(self):
92 92 return self.name.replace('-','_') + u'_config.py'
@@ -108,13 +108,13 b' class BaseIPythonApplication(Application):'
108 108 )
109 109 def _profile_default(self):
110 110 return "python3" if py3compat.PY3 else "default"
111
111
112 112 def _profile_changed(self, name, old, new):
113 113 self.builtin_profile_dir = os.path.join(
114 114 get_ipython_package_dir(), u'config', u'profile', new
115 115 )
116
117 ipython_dir = Unicode(get_ipython_dir(), config=True,
116
117 ipython_dir = Unicode(get_ipython_dir(), config=True,
118 118 help="""
119 119 The name of the IPython directory. This directory is used for logging
120 120 configuration (through profiles), history storage, etc. The default
@@ -122,16 +122,16 b' class BaseIPythonApplication(Application):'
122 122 the environment variable IPYTHON_DIR.
123 123 """
124 124 )
125
125
126 126 overwrite = Bool(False, config=True,
127 127 help="""Whether to overwrite existing config files when copying""")
128 128 auto_create = Bool(False, config=True,
129 129 help="""Whether to create profile dir if it doesn't exist""")
130
130
131 131 config_files = List(Unicode)
132 132 def _config_files_default(self):
133 133 return [u'ipython_config.py']
134
134
135 135 copy_config_files = Bool(False, config=True,
136 136 help="""Whether to install the default config files into the profile dir.
137 137 If a new profile is being created, and IPython contains config files for that
@@ -147,7 +147,7 b' class BaseIPythonApplication(Application):'
147 147 # ensure even default IPYTHON_DIR exists
148 148 if not os.path.exists(self.ipython_dir):
149 149 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
150
150
151 151 #-------------------------------------------------------------------------
152 152 # Various stages of Application creation
153 153 #-------------------------------------------------------------------------
@@ -183,7 +183,7 b' class BaseIPythonApplication(Application):'
183 183 try:
184 184 Application.load_config_file(
185 185 self,
186 base_config,
186 base_config,
187 187 path=self.config_file_paths
188 188 )
189 189 except IOError:
@@ -198,7 +198,7 b' class BaseIPythonApplication(Application):'
198 198 try:
199 199 Application.load_config_file(
200 200 self,
201 self.config_file_name,
201 self.config_file_name,
202 202 path=self.config_file_paths
203 203 )
204 204 except IOError:
@@ -258,17 +258,17 b' class BaseIPythonApplication(Application):'
258 258 self.exit(1)
259 259 else:
260 260 self.log.info("Using existing profile dir: %r"%location)
261
261
262 262 self.profile_dir = p
263 263 self.config_file_paths.append(p.location)
264
264
265 265 def init_config_files(self):
266 266 """[optionally] copy default config files into profile dir."""
267 267 # copy config files
268 268 path = self.builtin_profile_dir
269 269 if self.copy_config_files:
270 270 src = self.profile
271
271
272 272 cfg = self.config_file_name
273 273 if path and os.path.exists(os.path.join(path, cfg)):
274 274 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
@@ -289,8 +289,8 b' class BaseIPythonApplication(Application):'
289 289 self.log.warn("Staging bundled %s from %s into %r"%(
290 290 cfg, self.profile, self.profile_dir.location)
291 291 )
292
293
292
293
294 294 def stage_default_config_file(self):
295 295 """auto generate default config file, and stage it into the profile."""
296 296 s = self.generate_config_file()
@@ -299,8 +299,8 b' class BaseIPythonApplication(Application):'
299 299 self.log.warn("Generating default config file: %r"%(fname))
300 300 with open(fname, 'w') as f:
301 301 f.write(s)
302
303
302
303
304 304 def initialize(self, argv=None):
305 305 # don't hook up crash handler before parsing command-line
306 306 self.parse_command_line(argv)
@@ -126,7 +126,7 b' def has_open_quotes(s):'
126 126
127 127 def protect_filename(s):
128 128 """Escape a string to protect certain characters."""
129
129
130 130 return "".join([(ch in PROTECTABLES and '\\' + ch or ch)
131 131 for ch in s])
132 132
@@ -156,7 +156,7 b' def expand_user(path):'
156 156 path : str
157 157 String to be expanded. If no ~ is present, the output is the same as the
158 158 input.
159
159
160 160 Returns
161 161 -------
162 162 newpath : str
@@ -170,7 +170,7 b' def expand_user(path):'
170 170 tilde_expand = False
171 171 tilde_val = ''
172 172 newpath = path
173
173
174 174 if path.startswith('~'):
175 175 tilde_expand = True
176 176 rest = path[1:]
@@ -229,7 +229,7 b' class CompletionSplitter(object):'
229 229 automatically builds the necessary """
230 230
231 231 # Private interface
232
232
233 233 # A string of delimiter characters. The default value makes sense for
234 234 # IPython's most typical usage patterns.
235 235 _delims = DELIMS
@@ -265,15 +265,15 b' class CompletionSplitter(object):'
265 265
266 266
267 267 class Completer(Configurable):
268
268
269 269 greedy = CBool(False, config=True,
270 270 help="""Activate greedy completion
271
271
272 272 This will enable completion on elements of lists, results of function calls, etc.,
273 273 but can be unsafe because the code is actually evaluated on TAB.
274 274 """
275 275 )
276
276
277 277 def __init__(self, namespace=None, global_namespace=None, config=None):
278 278 """Create a new completer for the command line.
279 279
@@ -307,7 +307,7 b' class Completer(Configurable):'
307 307 self.global_namespace = {}
308 308 else:
309 309 self.global_namespace = global_namespace
310
310
311 311 super(Completer, self).__init__(config=config)
312 312
313 313 def complete(self, text, state):
@@ -319,7 +319,7 b' class Completer(Configurable):'
319 319 """
320 320 if self.use_main_ns:
321 321 self.namespace = __main__.__dict__
322
322
323 323 if state == 0:
324 324 if "." in text:
325 325 self.matches = self.attr_matches(text)
@@ -369,7 +369,7 b' class Completer(Configurable):'
369 369 m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)
370 370
371 371 if m:
372 expr, attr = m.group(1, 3)
372 expr, attr = m.group(1, 3)
373 373 elif self.greedy:
374 374 m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer)
375 375 if not m2:
@@ -377,7 +377,7 b' class Completer(Configurable):'
377 377 expr, attr = m2.group(1,2)
378 378 else:
379 379 return []
380
380
381 381 try:
382 382 obj = eval(expr, self.namespace)
383 383 except:
@@ -387,7 +387,7 b' class Completer(Configurable):'
387 387 return []
388 388
389 389 words = dir2(obj)
390
390
391 391 try:
392 392 words = generics.complete_object(obj, words)
393 393 except TryNext:
@@ -407,10 +407,10 b' class IPCompleter(Completer):'
407 407 self.splitter.set_delims(GREEDY_DELIMS)
408 408 else:
409 409 self.splitter.set_delims(DELIMS)
410
410
411 411 if self.readline:
412 412 self.readline.set_completer_delims(self.splitter.get_delims())
413
413
414 414 def __init__(self, shell=None, namespace=None, global_namespace=None,
415 415 omit__names=True, alias_table=None, use_readline=True,
416 416 config=None):
@@ -448,7 +448,7 b' class IPCompleter(Completer):'
448 448
449 449 # Readline configuration, only used by the rlcompleter method.
450 450 if use_readline:
451 # We store the right version of readline so that later code
451 # We store the right version of readline so that later code
452 452 import IPython.utils.rlineimpl as readline
453 453 self.readline = readline
454 454 else:
@@ -475,7 +475,7 b' class IPCompleter(Completer):'
475 475 # buffers, to avoid completion problems.
476 476 term = os.environ.get('TERM','xterm')
477 477 self.dumb_terminal = term in ['dumb','emacs']
478
478
479 479 # Special handling of backslashes needed in win32 platforms
480 480 if sys.platform == "win32":
481 481 self.clean_glob = self._clean_glob_win32
@@ -489,7 +489,7 b' class IPCompleter(Completer):'
489 489 self.alias_matches,
490 490 self.python_func_kw_matches,
491 491 ]
492
492
493 493 def all_completions(self, text):
494 494 """
495 495 Wrapper around the complete method for the benefit of emacs
@@ -502,7 +502,7 b' class IPCompleter(Completer):'
502 502
503 503 def _clean_glob_win32(self,text):
504 504 return [f.replace("\\","/")
505 for f in self.glob("%s*" % text)]
505 for f in self.glob("%s*" % text)]
506 506
507 507 def file_matches(self, text):
508 508 """Match filenames, expanding ~USER type strings.
@@ -569,7 +569,7 b' class IPCompleter(Completer):'
569 569 # beginning of filename so that we don't double-write the part
570 570 # of the filename we have so far
571 571 len_lsplit = len(lsplit)
572 matches = [text_prefix + text0 +
572 matches = [text_prefix + text0 +
573 573 protect_filename(f[len_lsplit:]) for f in m0]
574 574 else:
575 575 if open_quotes:
@@ -578,7 +578,7 b' class IPCompleter(Completer):'
578 578 # would cause bugs when the filesystem call is made).
579 579 matches = m0
580 580 else:
581 matches = [text_prefix +
581 matches = [text_prefix +
582 582 protect_filename(f) for f in m0]
583 583
584 584 #io.rprint('mm', matches) # dbg
@@ -595,7 +595,7 b' class IPCompleter(Completer):'
595 595 return [ pre+m for m in magics if m.startswith(baretext)]
596 596
597 597 def alias_matches(self, text):
598 """Match internal system aliases"""
598 """Match internal system aliases"""
599 599 #print 'Completer->alias_matches:',text,'lb',self.text_until_cursor # dbg
600 600
601 601 # if we are not in the first 'item', alias matching
@@ -715,10 +715,10 b' class IPCompleter(Completer):'
715 715
716 716 def dispatch_custom_completer(self, text):
717 717 #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg
718 line = self.line_buffer
718 line = self.line_buffer
719 719 if not line.strip():
720 720 return None
721
721
722 722 # Create a little structure to pass all the relevant information about
723 723 # the current completion to any custom completer.
724 724 event = Bunch()
@@ -727,16 +727,16 b' class IPCompleter(Completer):'
727 727 cmd = line.split(None,1)[0]
728 728 event.command = cmd
729 729 event.text_until_cursor = self.text_until_cursor
730
730
731 731 #print "\ncustom:{%s]\n" % event # dbg
732
732
733 733 # for foo etc, try also to find completer for %foo
734 734 if not cmd.startswith(self.magic_escape):
735 735 try_magic = self.custom_completers.s_matches(
736 self.magic_escape + cmd)
736 self.magic_escape + cmd)
737 737 else:
738 try_magic = []
739
738 try_magic = []
739
740 740 for c in itertools.chain(self.custom_completers.s_matches(cmd),
741 741 try_magic,
742 742 self.custom_completers.flat_matches(self.text_until_cursor)):
@@ -753,9 +753,9 b' class IPCompleter(Completer):'
753 753 return [r for r in res if r.lower().startswith(text_low)]
754 754 except TryNext:
755 755 pass
756
756
757 757 return None
758
758
759 759 def complete(self, text=None, line_buffer=None, cursor_pos=None):
760 760 """Find completions for the given text and line context.
761 761
@@ -785,7 +785,7 b' class IPCompleter(Completer):'
785 785 -------
786 786 text : str
787 787 Text that was actually used in the completion.
788
788
789 789 matches : list
790 790 A list of completion matches.
791 791 """
@@ -803,7 +803,7 b' class IPCompleter(Completer):'
803 803 # If no line buffer is given, assume the input text is all there was
804 804 if line_buffer is None:
805 805 line_buffer = text
806
806
807 807 self.line_buffer = line_buffer
808 808 self.text_until_cursor = self.line_buffer[:cursor_pos]
809 809 #io.rprint('\nCOMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg
@@ -893,7 +893,7 b' class IPCompleter(Completer):'
893 893 import traceback; traceback.print_exc()
894 894 else:
895 895 # The normal production version is here
896
896
897 897 # This method computes the self.matches array
898 898 self.complete(text, line_buffer, cursor_pos)
899 899
@@ -78,7 +78,7 b' def shlex_split(x):'
78 78 if len(endofline) >= 1:
79 79 comps.append(''.join(endofline))
80 80 return comps
81
81
82 82 except ValueError:
83 83 endofline = [x[-1:]]+endofline
84 84 x = x[:-1]
@@ -108,7 +108,7 b' def module_list(path):'
108 108 isfile = os.path.isfile
109 109 pjoin = os.path.join
110 110 basename = os.path.basename
111
111
112 112 # Now find actual path matches for packages or modules
113 113 folder_list = [p for p in folder_list
114 114 if isfile(pjoin(path, p,'__init__.py'))
@@ -125,12 +125,12 b' def get_root_modules():'
125 125
126 126 if 'rootmodules' in ip.db:
127 127 return ip.db['rootmodules']
128
128
129 129 t = time()
130 130 store = False
131 131 modules = list(sys.builtin_module_names)
132 132 for path in sys.path:
133 modules += module_list(path)
133 modules += module_list(path)
134 134 if time() - t >= TIMEOUT_STORAGE and not store:
135 135 store = True
136 136 print("\nCaching the list of root modules, please wait!")
@@ -141,7 +141,7 b' def get_root_modules():'
141 141 print("This is taking too long, we give up.\n")
142 142 ip.db['rootmodules'] = []
143 143 return []
144
144
145 145 modules = set(modules)
146 146 if '__init__' in modules:
147 147 modules.remove('__init__')
@@ -173,7 +173,7 b' def try_import(mod, only_modules=False):'
173 173 if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init:
174 174 completions.extend( [attr for attr in dir(m) if
175 175 is_importable(m, attr, only_modules)])
176
176
177 177 completions.extend(getattr(m, '__all__', []))
178 178 if m_is_init:
179 179 completions.extend(module_list(os.path.dirname(m.__file__)))
@@ -192,22 +192,22 b' def quick_completer(cmd, completions):'
192 192
193 193 Takes either a list of completions, or all completions in string (that will
194 194 be split on whitespace).
195
195
196 196 Example::
197
197
198 198 [d:\ipython]|1> import ipy_completers
199 199 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
200 200 [d:\ipython]|3> foo b<TAB>
201 201 bar baz
202 202 [d:\ipython]|3> foo ba
203 203 """
204
204
205 205 if isinstance(completions, basestring):
206 206 completions = completions.split()
207 207
208 208 def do_complete(self, event):
209 209 return completions
210
210
211 211 get_ipython().set_hook('complete_command',do_complete, str_key = cmd)
212 212
213 213
@@ -226,7 +226,7 b' def module_completion(line):'
226 226 # from whatever <tab> -> 'import '
227 227 if nwords == 3 and words[0] == 'from':
228 228 return ['import ']
229
229
230 230 # 'from xy<tab>' or 'import xy<tab>'
231 231 if nwords < 3 and (words[0] in ['import','from']) :
232 232 if nwords == 1:
@@ -236,7 +236,7 b' def module_completion(line):'
236 236 return get_root_modules()
237 237 completion_list = try_import('.'.join(mod[:-1]), True)
238 238 return ['.'.join(mod[:-1] + [el]) for el in completion_list]
239
239
240 240 # 'from xyz import abc<tab>'
241 241 if nwords >= 3 and words[0] == 'from':
242 242 mod = words[1]
@@ -275,7 +275,7 b' def magic_run_completer(self, event):'
275 275 lglob = glob.glob
276 276 isdir = os.path.isdir
277 277 relpath, tilde_expand, tilde_val = expand_user(relpath)
278
278
279 279 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)]
280 280
281 281 # Find if the user has already typed the first filename, after which we
@@ -305,7 +305,7 b' def cd_completer(self, event):'
305 305 return bkms.keys()
306 306 else:
307 307 return []
308
308
309 309 if event.symbol == '-':
310 310 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
311 311 # jump in directory history by number
@@ -329,7 +329,7 b' def cd_completer(self, event):'
329 329 # we don't want to deal with any of that, complex code
330 330 # for this is elsewhere
331 331 raise TryNext
332
332
333 333 found.append(d)
334 334
335 335 if not found:
@@ -341,7 +341,7 b' def cd_completer(self, event):'
341 341 bkmatches = [s for s in bks if s.startswith(event.symbol)]
342 342 if bkmatches:
343 343 return bkmatches
344
344
345 345 raise TryNext
346 346
347 347 return [compress_user(p, tilde_expand, tilde_val) for p in found]
@@ -67,14 +67,14 b' class CrashHandler(object):'
67 67 message_template = _default_message_template
68 68 section_sep = '\n\n'+'*'*75+'\n\n'
69 69
70 def __init__(self, app, contact_name=None, contact_email=None,
70 def __init__(self, app, contact_name=None, contact_email=None,
71 71 bug_tracker=None, show_crash_traceback=True, call_pdb=False):
72 72 """Create a new crash handler
73 73
74 74 Parameters
75 75 ----------
76 76 app : Application
77 A running :class:`Application` instance, which will be queried at
77 A running :class:`Application` instance, which will be queried at
78 78 crash time for internal information.
79 79
80 80 contact_name : str
@@ -106,7 +106,7 b' class CrashHandler(object):'
106 106 contact_email = contact_email,
107 107 bug_tracker = bug_tracker,
108 108 crash_report_fname = self.crash_report_fname)
109
109
110 110
111 111 def __call__(self, etype, evalue, etb):
112 112 """Handle an exception, call for compatible with sys.excepthook"""
@@ -160,13 +160,13 b' class CrashHandler(object):'
160 160
161 161 def make_report(self,traceback):
162 162 """Return a string containing a crash report."""
163
163
164 164 sec_sep = self.section_sep
165
165
166 166 report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n']
167 167 rpt_add = report.append
168 168 rpt_add(sys_info())
169
169
170 170 try:
171 171 config = pformat(self.app.config)
172 172 rpt_add(sec_sep)
@@ -39,7 +39,7 b' has_pydb = False'
39 39 prompt = 'ipdb> '
40 40 #We have to check this directly from sys.argv, config struct not yet available
41 41 if '-pydb' in sys.argv:
42 try:
42 try:
43 43 import pydb
44 44 if hasattr(pydb.pydb, "runl") and pydb.version>'1.17':
45 45 # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we
@@ -130,7 +130,7 b' class Tracer(object):'
130 130
131 131 This is similar to the pdb.set_trace() function from the std lib, but
132 132 using IPython's enhanced debugger."""
133
133
134 134 self.debugger.set_trace(sys._getframe().f_back)
135 135
136 136
@@ -173,9 +173,9 b' class Pdb(OldPdb):'
173 173 OldPdb.__init__(self,stdin=stdin,stdout=io.stdout)
174 174 else:
175 175 OldPdb.__init__(self,completekey,stdin,stdout)
176
176
177 177 self.prompt = prompt # The default prompt is '(Pdb)'
178
178
179 179 # IPython changes...
180 180 self.is_pydb = has_pydb
181 181
@@ -207,7 +207,7 b' class Pdb(OldPdb):'
207 207 # module and add a few attributes needed for debugging
208 208 self.color_scheme_table = exception_colors()
209 209
210 # shorthands
210 # shorthands
211 211 C = coloransi.TermColors
212 212 cst = self.color_scheme_table
213 213
@@ -250,11 +250,11 b' class Pdb(OldPdb):'
250 250 self.shell.set_completer_frame(self.curframe)
251 251
252 252 def new_do_quit(self, arg):
253
253
254 254 if hasattr(self, 'old_all_completions'):
255 255 self.shell.Completer.all_completions=self.old_all_completions
256
257
256
257
258 258 return OldPdb.do_quit(self, arg)
259 259
260 260 do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit)
@@ -288,9 +288,9 b' class Pdb(OldPdb):'
288 288
289 289 def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3):
290 290 import linecache, repr
291
291
292 292 ret = []
293
293
294 294 Colors = self.color_scheme_table.active_colors
295 295 ColorsNormal = Colors.Normal
296 296 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
@@ -298,9 +298,9 b' class Pdb(OldPdb):'
298 298 tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal)
299 299 tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line,
300 300 ColorsNormal)
301
301
302 302 frame, lineno = frame_lineno
303
303
304 304 return_value = ''
305 305 if '__return__' in frame.f_locals:
306 306 rv = frame.f_locals['__return__']
@@ -311,14 +311,14 b' class Pdb(OldPdb):'
311 311 #s = filename + '(' + `lineno` + ')'
312 312 filename = self.canonic(frame.f_code.co_filename)
313 313 link = tpl_link % filename
314
314
315 315 if frame.f_code.co_name:
316 316 func = frame.f_code.co_name
317 317 else:
318 318 func = "<lambda>"
319
319
320 320 call = ''
321 if func != '?':
321 if func != '?':
322 322 if '__args__' in frame.f_locals:
323 323 args = repr.repr(frame.f_locals['__args__'])
324 324 else:
@@ -332,13 +332,13 b' class Pdb(OldPdb):'
332 332 else:
333 333 ret.append(' ')
334 334 ret.append('%s(%s)%s\n' % (link,lineno,call))
335
335
336 336 start = lineno - 1 - context//2
337 337 lines = linecache.getlines(filename)
338 338 start = max(start, 0)
339 339 start = min(start, len(lines) - context)
340 340 lines = lines[start : start + context]
341
341
342 342 for i,line in enumerate(lines):
343 343 show_arrow = (start + 1 + i == lineno)
344 344 linetpl = (frame is self.curframe or show_arrow) \
@@ -362,7 +362,7 b' class Pdb(OldPdb):'
362 362 if lineno in self.get_file_breaks(filename):
363 363 bps = self.get_breaks(filename, lineno)
364 364 bp = bps[-1]
365
365
366 366 if bp:
367 367 Colors = self.color_scheme_table.active_colors
368 368 bp_mark = str(bp.number)
@@ -387,7 +387,7 b' class Pdb(OldPdb):'
387 387 else:
388 388 num = '%*s' % (numbers_width - len(bp_mark), str(lineno))
389 389 line = tpl_line % (bp_mark_color + bp_mark, num, line)
390
390
391 391 return line
392 392
393 393 def list_command_pydb(self, arg):
@@ -395,7 +395,7 b' class Pdb(OldPdb):'
395 395 filename, first, last = OldPdb.parse_list_cmd(self, arg)
396 396 if filename is not None:
397 397 self.print_list_lines(filename, first, last)
398
398
399 399 def print_list_lines(self, filename, first, last):
400 400 """The printing (as opposed to the parsing part of a 'list'
401 401 command."""
@@ -496,7 +496,7 b' class Pdb(OldPdb):'
496 496 #
497 497 # End hack. The rest of this method is copied verbatim from 2.6 pdb.py
498 498 #######################################################################
499
499
500 500 if not line:
501 501 print >>self.stdout, 'End of file'
502 502 return 0
@@ -49,7 +49,7 b' def display(*objs, **kwargs):'
49 49 """
50 50 include = kwargs.get('include')
51 51 exclude = kwargs.get('exclude')
52
52
53 53 from IPython.core.interactiveshell import InteractiveShell
54 54 inst = InteractiveShell.instance()
55 55 format = inst.display_formatter.format
@@ -237,7 +237,7 b' class DisplayObject(object):'
237 237 in the frontend. The MIME type of the data should match the
238 238 subclasses used, so the Png subclass should be used for 'image/png'
239 239 data. If the data is a URL, the data will first be downloaded
240 and then displayed. If
240 and then displayed. If
241 241
242 242 Parameters
243 243 ----------
@@ -123,7 +123,7 b' class DisplayHook(Configurable):'
123 123 return no_cache_def
124 124 else:
125 125 return p_str
126
126
127 127 def set_colors(self, colors):
128 128 """Set the active color scheme and configure colors for the three
129 129 prompt subsystems."""
@@ -135,7 +135,7 b' class DisplayHook(Configurable):'
135 135 prompts.prompt_specials = prompts.prompt_specials_nocolor
136 136 else:
137 137 prompts.prompt_specials = prompts.prompt_specials_color
138
138
139 139 self.color_table.set_active_scheme(colors)
140 140 self.prompt1.set_colors()
141 141 self.prompt2.set_colors()
@@ -227,7 +227,7 b' class DisplayHook(Configurable):'
227 227 format_dict : dict
228 228 The format dict for the object passed to `sys.displayhook`.
229 229 """
230 # We want to print because we want to always make sure we have a
230 # We want to print because we want to always make sure we have a
231 231 # newline, even if all the prompt separators are ''. This is the
232 232 # standard IPython behavior.
233 233 result_repr = format_dict['text/plain']
@@ -291,7 +291,7 b' class DisplayHook(Configurable):'
291 291
292 292 def __call__(self, result=None):
293 293 """Printing with history cache management.
294
294
295 295 This is invoked everytime the interpreter needs to print, and is
296 296 activated by setting the variable sys.displayhook to it.
297 297 """
@@ -310,17 +310,17 b' class DisplayHook(Configurable):'
310 310 raise ValueError,"You shouldn't have reached the cache flush "\
311 311 "if full caching is not enabled!"
312 312 # delete auto-generated vars from global namespace
313
313
314 314 for n in range(1,self.prompt_count + 1):
315 315 key = '_'+`n`
316 316 try:
317 317 del self.shell.user_ns[key]
318 318 except: pass
319 319 self.shell.user_ns['_oh'].clear()
320
320
321 321 # Release our own references to objects:
322 322 self._, self.__, self.___ = '', '', ''
323
323
324 324 if '_' not in __builtin__.__dict__:
325 325 self.shell.user_ns.update({'_':None,'__':None, '___':None})
326 326 import gc
@@ -87,7 +87,7 b' class DisplayPublisher(Configurable):'
87 87 A string that give the function or method that created the data,
88 88 such as 'IPython.core.page'.
89 89 data : dict
90 A dictionary having keys that are valid MIME types (like
90 A dictionary having keys that are valid MIME types (like
91 91 'text/plain' or 'image/svg+xml') and values that are the data for
92 92 that MIME type. The data itself must be a JSON'able data
93 93 structure. Minimally all data should have the 'text/plain' data,
@@ -128,7 +128,7 b' def publish_display_data(source, data, metadata=None):'
128 128 A string that give the function or method that created the data,
129 129 such as 'IPython.core.page'.
130 130 data : dict
131 A dictionary having keys that are valid MIME types (like
131 A dictionary having keys that are valid MIME types (like
132 132 'text/plain' or 'image/svg+xml') and values that are the data for
133 133 that MIME type. The data itself must be a JSON'able data
134 134 structure. Minimally all data should have the 'text/plain' data,
@@ -32,7 +32,7 b' class IPythonCoreError(Exception):'
32 32
33 33 class TryNext(IPythonCoreError):
34 34 """Try next hook exception.
35
35
36 36 Raise this in your hook function to indicate that the next hook handler
37 37 should be used to handle the operation. If you pass arguments to the
38 38 constructor those arguments will be used by the next hook instead of the
@@ -45,7 +45,7 b' class TryNext(IPythonCoreError):'
45 45
46 46 class UsageError(IPythonCoreError):
47 47 """Error in magic function arguments, etc.
48
48
49 49 Something that probably won't warrant a full traceback, but should
50 nevertheless interrupt a macro / batch file.
50 nevertheless interrupt a macro / batch file.
51 51 """
@@ -27,16 +27,16 b' def exception_colors():'
27 27 >>> print ec.active_colors
28 28 None
29 29
30 Now we activate a color scheme:
30 Now we activate a color scheme:
31 31 >>> ec.set_active_scheme('NoColor')
32 32 >>> ec.active_scheme_name
33 33 'NoColor'
34 34 >>> ec.active_colors.keys()
35 ['em', 'filenameEm', 'excName', 'valEm', 'nameEm', 'line', 'topline',
36 'name', 'caret', 'val', 'vName', 'Normal', 'filename', 'linenoEm',
35 ['em', 'filenameEm', 'excName', 'valEm', 'nameEm', 'line', 'topline',
36 'name', 'caret', 'val', 'vName', 'Normal', 'filename', 'linenoEm',
37 37 'lineno', 'normalEm']
38 38 """
39
39
40 40 ex_colors = ColorSchemeTable()
41 41
42 42 # Populate it with color schemes
@@ -36,13 +36,13 b' class ExtensionManager(Configurable):'
36 36 def load_ipython_extension(ipython):
37 37 # Do things with ipython
38 38
39 This function is called after your extension is imported and the
39 This function is called after your extension is imported and the
40 40 currently active :class:`InteractiveShell` instance is passed as
41 41 the only argument. You can do anything you want with IPython at
42 42 that point, including defining new magic and aliases, adding new
43 43 components, etc.
44 44
45 The :func:`load_ipython_extension` will be called again is you
45 The :func:`load_ipython_extension` will be called again is you
46 46 load or reload the extension again. It is up to the extension
47 47 author to add code to manage that.
48 48
@@ -361,26 +361,26 b' class PlainTextFormatter(BaseFormatter):'
361 361
362 362 # The newline character.
363 363 newline = Unicode('\n', config=True)
364
364
365 365 # format-string for pprinting floats
366 366 float_format = Unicode('%r')
367 367 # setter for float precision, either int or direct format-string
368 368 float_precision = CUnicode('', config=True)
369
369
370 370 def _float_precision_changed(self, name, old, new):
371 371 """float_precision changed, set float_format accordingly.
372
372
373 373 float_precision can be set by int or str.
374 374 This will set float_format, after interpreting input.
375 375 If numpy has been imported, numpy print precision will also be set.
376
376
377 377 integer `n` sets format to '%.nf', otherwise, format set directly.
378
378
379 379 An empty string returns to defaults (repr for float, 8 for numpy).
380
380
381 381 This parameter can be set via the '%precision' magic.
382 382 """
383
383
384 384 if '%' in new:
385 385 # got explicit format string
386 386 fmt = new
@@ -397,7 +397,7 b' class PlainTextFormatter(BaseFormatter):'
397 397 raise ValueError("Precision must be int or format string, not %r"%new)
398 398 except AssertionError:
399 399 raise ValueError("int precision must be non-negative, not %r"%i)
400
400
401 401 fmt = '%%.%if'%i
402 402 if 'numpy' in sys.modules:
403 403 # set numpy precision if it has been imported
@@ -458,7 +458,7 b' class HTMLFormatter(BaseFormatter):'
458 458 this.
459 459
460 460 The return value of this formatter should be a valid HTML snippet that
461 could be injected into an existing DOM. It should *not* include the
461 could be injected into an existing DOM. It should *not* include the
462 462 ```<html>`` or ```<body>`` tags.
463 463 """
464 464 format_type = Unicode('text/html')
@@ -550,7 +550,7 b' class JavascriptFormatter(BaseFormatter):'
550 550 """A Javascript formatter.
551 551
552 552 To define the callables that compute the Javascript representation of
553 your objects, define a :meth:`_repr_javascript_` method or use the
553 your objects, define a :meth:`_repr_javascript_` method or use the
554 554 :meth:`for_type` or :meth:`for_type_by_name` methods to register functions
555 555 that handle this.
556 556
@@ -67,19 +67,19 b' class HistoryManager(Configurable):'
67 67 # Should we log output to the database? (default no)
68 68 db_log_output = Bool(False, config=True)
69 69 # Write to database every x commands (higher values save disk access & power)
70 # Values of 1 or less effectively disable caching.
70 # Values of 1 or less effectively disable caching.
71 71 db_cache_size = Int(0, config=True)
72 72 # The input and output caches
73 73 db_input_cache = List()
74 74 db_output_cache = List()
75
75
76 76 # History saving in separate thread
77 77 save_thread = Instance('IPython.core.history.HistorySavingThread')
78 78 try: # Event is a function returning an instance of _Event...
79 79 save_flag = Instance(threading._Event)
80 80 except AttributeError: # ...until Python 3.3, when it's a class.
81 81 save_flag = Instance(threading.Event)
82
82
83 83 # Private interface
84 84 # Variables used to store the three last inputs from the user. On each new
85 85 # history update, we populate the user's namespace with these, shifted as
@@ -119,7 +119,7 b' class HistoryManager(Configurable):'
119 119 else:
120 120 # The hist_file is probably :memory: or something else.
121 121 raise
122
122
123 123 self.save_flag = threading.Event()
124 124 self.db_input_cache_lock = threading.Lock()
125 125 self.db_output_cache_lock = threading.Lock()
@@ -128,7 +128,7 b' class HistoryManager(Configurable):'
128 128
129 129 self.new_session()
130 130
131
131
132 132 def init_db(self):
133 133 """Connect to the database, and create tables if necessary."""
134 134 # use detect_types so that timestamps return datetime objects
@@ -136,7 +136,7 b' class HistoryManager(Configurable):'
136 136 self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer
137 137 primary key autoincrement, start timestamp,
138 138 end timestamp, num_cmds integer, remark text)""")
139 self.db.execute("""CREATE TABLE IF NOT EXISTS history
139 self.db.execute("""CREATE TABLE IF NOT EXISTS history
140 140 (session integer, line integer, source text, source_raw text,
141 141 PRIMARY KEY (session, line))""")
142 142 # Output history is optional, but ensure the table's there so it can be
@@ -145,17 +145,17 b' class HistoryManager(Configurable):'
145 145 (session integer, line integer, output text,
146 146 PRIMARY KEY (session, line))""")
147 147 self.db.commit()
148
148
149 149 def new_session(self, conn=None):
150 150 """Get a new session number."""
151 151 if conn is None:
152 152 conn = self.db
153
153
154 154 with conn:
155 155 cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL,
156 156 NULL, "") """, (datetime.datetime.now(),))
157 157 self.session_number = cur.lastrowid
158
158
159 159 def end_session(self):
160 160 """Close the database session, filling in the end time and line count."""
161 161 self.writeout_cache()
@@ -164,33 +164,33 b' class HistoryManager(Configurable):'
164 164 session==?""", (datetime.datetime.now(),
165 165 len(self.input_hist_parsed)-1, self.session_number))
166 166 self.session_number = 0
167
167
168 168 def name_session(self, name):
169 169 """Give the current session a name in the history database."""
170 170 with self.db:
171 171 self.db.execute("UPDATE sessions SET remark=? WHERE session==?",
172 172 (name, self.session_number))
173
173
174 174 def reset(self, new_session=True):
175 175 """Clear the session history, releasing all object references, and
176 176 optionally open a new session."""
177 177 self.output_hist.clear()
178 178 # The directory history can't be completely empty
179 179 self.dir_hist[:] = [os.getcwdu()]
180
180
181 181 if new_session:
182 182 if self.session_number:
183 183 self.end_session()
184 184 self.input_hist_parsed[:] = [""]
185 185 self.input_hist_raw[:] = [""]
186 186 self.new_session()
187
187
188 188 ## -------------------------------
189 189 ## Methods for retrieving history:
190 190 ## -------------------------------
191 191 def _run_sql(self, sql, params, raw=True, output=False):
192 192 """Prepares and runs an SQL query for the history database.
193
193
194 194 Parameters
195 195 ----------
196 196 sql : str
@@ -199,7 +199,7 b' class HistoryManager(Configurable):'
199 199 Parameters passed to the SQL query (to replace "?")
200 200 raw, output : bool
201 201 See :meth:`get_range`
202
202
203 203 Returns
204 204 -------
205 205 Tuples as :meth:`get_range`
@@ -214,38 +214,38 b' class HistoryManager(Configurable):'
214 214 if output: # Regroup into 3-tuples, and parse JSON
215 215 return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur)
216 216 return cur
217
218
217
218
219 219 def get_session_info(self, session=0):
220 220 """get info about a session
221
221
222 222 Parameters
223 223 ----------
224
224
225 225 session : int
226 226 Session number to retrieve. The current session is 0, and negative
227 227 numbers count back from current session, so -1 is previous session.
228
228
229 229 Returns
230 230 -------
231
231
232 232 (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode])
233
233
234 234 Sessions that are running or did not exit cleanly will have `end=None`
235 235 and `num_cmds=None`.
236
236
237 237 """
238
238
239 239 if session <= 0:
240 240 session += self.session_number
241
241
242 242 query = "SELECT * from sessions where session == ?"
243 243 return self.db.execute(query, (session,)).fetchone()
244
245
244
245
246 246 def get_tail(self, n=10, raw=True, output=False, include_latest=False):
247 247 """Get the last n lines from the history database.
248
248
249 249 Parameters
250 250 ----------
251 251 n : int
@@ -256,7 +256,7 b' class HistoryManager(Configurable):'
256 256 If False (default), n+1 lines are fetched, and the latest one
257 257 is discarded. This is intended to be used where the function
258 258 is called by a user command, which it should not return.
259
259
260 260 Returns
261 261 -------
262 262 Tuples as :meth:`get_range`
@@ -269,12 +269,12 b' class HistoryManager(Configurable):'
269 269 if not include_latest:
270 270 return reversed(list(cur)[1:])
271 271 return reversed(list(cur))
272
272
273 273 def search(self, pattern="*", raw=True, search_raw=True,
274 274 output=False):
275 275 """Search the database using unix glob-style matching (wildcards
276 276 * and ?).
277
277
278 278 Parameters
279 279 ----------
280 280 pattern : str
@@ -283,7 +283,7 b' class HistoryManager(Configurable):'
283 283 If True, search the raw input, otherwise, the parsed input
284 284 raw, output : bool
285 285 See :meth:`get_range`
286
286
287 287 Returns
288 288 -------
289 289 Tuples as :meth:`get_range`
@@ -294,12 +294,12 b' class HistoryManager(Configurable):'
294 294 self.writeout_cache()
295 295 return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,),
296 296 raw=raw, output=output)
297
297
298 298 def _get_range_session(self, start=1, stop=None, raw=True, output=False):
299 299 """Get input and output history from the current session. Called by
300 300 get_range, and takes similar parameters."""
301 301 input_hist = self.input_hist_raw if raw else self.input_hist_parsed
302
302
303 303 n = len(input_hist)
304 304 if start < 0:
305 305 start += n
@@ -307,17 +307,17 b' class HistoryManager(Configurable):'
307 307 stop = n
308 308 elif stop < 0:
309 309 stop += n
310
310
311 311 for i in range(start, stop):
312 312 if output:
313 313 line = (input_hist[i], self.output_hist_reprs.get(i))
314 314 else:
315 315 line = input_hist[i]
316 316 yield (0, i, line)
317
317
318 318 def get_range(self, session=0, start=1, stop=None, raw=True,output=False):
319 319 """Retrieve input by session.
320
320
321 321 Parameters
322 322 ----------
323 323 session : int
@@ -335,7 +335,7 b' class HistoryManager(Configurable):'
335 335 objects for the current session, or text reprs from previous
336 336 sessions if db_log_output was enabled at the time. Where no output
337 337 is found, None is used.
338
338
339 339 Returns
340 340 -------
341 341 An iterator over the desired lines. Each line is a 3-tuple, either
@@ -346,21 +346,21 b' class HistoryManager(Configurable):'
346 346 return self._get_range_session(start, stop, raw, output)
347 347 if session < 0:
348 348 session += self.session_number
349
349
350 350 if stop:
351 351 lineclause = "line >= ? AND line < ?"
352 352 params = (session, start, stop)
353 353 else:
354 354 lineclause = "line>=?"
355 355 params = (session, start)
356
356
357 357 return self._run_sql("WHERE session==? AND %s""" % lineclause,
358 358 params, raw=raw, output=output)
359
359
360 360 def get_range_by_str(self, rangestr, raw=True, output=False):
361 361 """Get lines of history from a string of ranges, as used by magic
362 362 commands %hist, %save, %macro, etc.
363
363
364 364 Parameters
365 365 ----------
366 366 rangestr : str
@@ -368,7 +368,7 b' class HistoryManager(Configurable):'
368 368 :func:`magic_history` for full details.
369 369 raw, output : bool
370 370 As :meth:`get_range`
371
371
372 372 Returns
373 373 -------
374 374 Tuples as :meth:`get_range`
@@ -376,19 +376,19 b' class HistoryManager(Configurable):'
376 376 for sess, s, e in extract_hist_ranges(rangestr):
377 377 for line in self.get_range(sess, s, e, raw=raw, output=output):
378 378 yield line
379
379
380 380 ## ----------------------------
381 381 ## Methods for storing history:
382 382 ## ----------------------------
383 383 def store_inputs(self, line_num, source, source_raw=None):
384 384 """Store source and raw input in history and create input cache
385 385 variables _i*.
386
386
387 387 Parameters
388 388 ----------
389 389 line_num : int
390 390 The prompt number of this input.
391
391
392 392 source : str
393 393 Python input.
394 394
@@ -400,14 +400,14 b' class HistoryManager(Configurable):'
400 400 source_raw = source
401 401 source = source.rstrip('\n')
402 402 source_raw = source_raw.rstrip('\n')
403
403
404 404 # do not store exit/quit commands
405 405 if self._exit_re.match(source_raw.strip()):
406 406 return
407
407
408 408 self.input_hist_parsed.append(source)
409 409 self.input_hist_raw.append(source_raw)
410
410
411 411 with self.db_input_cache_lock:
412 412 self.db_input_cache.append((line_num, source, source_raw))
413 413 # Trigger to flush cache and write to DB.
@@ -427,12 +427,12 b' class HistoryManager(Configurable):'
427 427 '_iii': self._iii,
428 428 new_i : self._i00 }
429 429 self.shell.user_ns.update(to_main)
430
430
431 431 def store_output(self, line_num):
432 432 """If database output logging is enabled, this saves all the
433 433 outputs from the indicated prompt number to the database. It's
434 434 called by run_cell after code has been executed.
435
435
436 436 Parameters
437 437 ----------
438 438 line_num : int
@@ -441,29 +441,29 b' class HistoryManager(Configurable):'
441 441 if (not self.db_log_output) or (line_num not in self.output_hist_reprs):
442 442 return
443 443 output = self.output_hist_reprs[line_num]
444
444
445 445 with self.db_output_cache_lock:
446 446 self.db_output_cache.append((line_num, output))
447 447 if self.db_cache_size <= 1:
448 448 self.save_flag.set()
449
449
450 450 def _writeout_input_cache(self, conn):
451 451 with conn:
452 452 for line in self.db_input_cache:
453 453 conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)",
454 454 (self.session_number,)+line)
455
455
456 456 def _writeout_output_cache(self, conn):
457 457 with conn:
458 458 for line in self.db_output_cache:
459 459 conn.execute("INSERT INTO output_history VALUES (?, ?, ?)",
460 460 (self.session_number,)+line)
461
461
462 462 def writeout_cache(self, conn=None):
463 463 """Write any entries in the cache to the database."""
464 464 if conn is None:
465 465 conn = self.db
466
466
467 467 with self.db_input_cache_lock:
468 468 try:
469 469 self._writeout_input_cache(conn)
@@ -492,7 +492,7 b' class HistoryManager(Configurable):'
492 492 class HistorySavingThread(threading.Thread):
493 493 """This thread takes care of writing history to the database, so that
494 494 the UI isn't held up while that happens.
495
495
496 496 It waits for the HistoryManager's save_flag to be set, then writes out
497 497 the history cache. The main thread is responsible for setting the flag when
498 498 the cache size reaches a defined threshold."""
@@ -502,7 +502,7 b' class HistorySavingThread(threading.Thread):'
502 502 super(HistorySavingThread, self).__init__()
503 503 self.history_manager = history_manager
504 504 atexit.register(self.stop)
505
505
506 506 def run(self):
507 507 # We need a separate db connection per thread:
508 508 try:
@@ -516,10 +516,10 b' class HistorySavingThread(threading.Thread):'
516 516 except Exception as e:
517 517 print(("The history saving thread hit an unexpected error (%s)."
518 518 "History will not be written to the database.") % repr(e))
519
519
520 520 def stop(self):
521 521 """This can be called from the main thread to safely stop this thread.
522
522
523 523 Note that it does not attempt to write out remaining history before
524 524 exiting. That should be done by calling the HistoryManager's
525 525 end_session method."""
@@ -527,7 +527,7 b' class HistorySavingThread(threading.Thread):'
527 527 self.history_manager.save_flag.set()
528 528 self.join()
529 529
530
530
531 531 # To match, e.g. ~5/8-~2/3
532 532 range_re = re.compile(r"""
533 533 ((?P<startsess>~?\d+)/)?
@@ -539,7 +539,7 b' $""", re.VERBOSE)'
539 539
540 540 def extract_hist_ranges(ranges_str):
541 541 """Turn a string of history ranges into 3-tuples of (session, start, stop).
542
542
543 543 Examples
544 544 --------
545 545 list(extract_input_ranges("~8/5-~7/4 2"))
@@ -578,7 +578,7 b' def _format_lineno(session, line):'
578 578 @skip_doctest
579 579 def magic_history(self, parameter_s = ''):
580 580 """Print input history (_i<n> variables), with most recent last.
581
581
582 582 %history -> print at most 40 inputs (some may be multi-line)\\
583 583 %history n -> print at most n inputs\\
584 584 %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\
@@ -594,7 +594,7 b" def magic_history(self, parameter_s = ''):"
594 594 ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line
595 595 of 6 sessions ago.
596 596 Multiple ranges can be entered, separated by spaces
597
597
598 598 The same syntax is used by %macro, %save, %edit, %rerun
599 599
600 600 Options:
@@ -609,29 +609,29 b" def magic_history(self, parameter_s = ''):"
609 609 doctest-ready output.
610 610
611 611 -r: (default) print the 'raw' history, i.e. the actual commands you typed.
612
612
613 613 -t: print the 'translated' history, as IPython understands it. IPython
614 614 filters your input and converts it all into valid Python source before
615 615 executing it (things like magics or aliases are turned into function
616 616 calls, for example). With this option, you'll see the native history
617 617 instead of the user-entered version: '%cd /' will be seen as
618 618 'get_ipython().magic("%cd /")' instead of '%cd /'.
619
619
620 620 -g: treat the arg as a pattern to grep for in (full) history.
621 621 This includes the saved history (almost all commands ever written).
622 622 Use '%hist -g' to show full saved history (may be very long).
623
623
624 624 -l: get the last n lines from all sessions. Specify n as a single arg, or
625 625 the default is the last 10 lines.
626 626
627 627 -f FILENAME: instead of printing the output to the screen, redirect it to
628 628 the given file. The file is always overwritten, though IPython asks for
629 629 confirmation first if it already exists.
630
630
631 631 Examples
632 632 --------
633 633 ::
634
634
635 635 In [6]: %hist -n 4 6
636 636 4:a = 12
637 637 5:print a**2
@@ -642,10 +642,10 b" def magic_history(self, parameter_s = ''):"
642 642 print('This feature is only available if numbered prompts are in use.')
643 643 return
644 644 opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string')
645
645
646 646 # For brevity
647 647 history_manager = self.shell.history_manager
648
648
649 649 def _format_lineno(session, line):
650 650 """Helper function to format line numbers properly."""
651 651 if session in (0, history_manager.session_number):
@@ -661,22 +661,22 b" def magic_history(self, parameter_s = ''):"
661 661 close_at_end = False
662 662 else:
663 663 if os.path.exists(outfname):
664 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
664 if not io.ask_yes_no("File %r exists. Overwrite?" % outfname):
665 665 print('Aborting.')
666 666 return
667 667
668 668 outfile = open(outfname,'w')
669 669 close_at_end = True
670
670
671 671 print_nums = 'n' in opts
672 672 get_output = 'o' in opts
673 673 pyprompts = 'p' in opts
674 674 # Raw history is the default
675 675 raw = not('t' in opts)
676
676
677 677 default_length = 40
678 678 pattern = None
679
679
680 680 if 'g' in opts: # Glob search
681 681 pattern = "*" + args + "*" if args else "*"
682 682 hist = history_manager.search(pattern, raw=raw, output=get_output)
@@ -692,11 +692,11 b" def magic_history(self, parameter_s = ''):"
692 692 hist = history_manager.get_range_by_str(args, raw, get_output)
693 693 else: # Just get history for the current session
694 694 hist = history_manager.get_range(raw=raw, output=get_output)
695
696 # We could be displaying the entire history, so let's not try to pull it
695
696 # We could be displaying the entire history, so let's not try to pull it
697 697 # into a list in memory. Anything that needs more space will just misalign.
698 698 width = 4
699
699
700 700 for session, lineno, inline in hist:
701 701 # Print user history with tabs expanded to 4 spaces. The GUI clients
702 702 # use hard tabs for easier usability in auto-indented code, but we want
@@ -704,7 +704,7 b" def magic_history(self, parameter_s = ''):"
704 704 if get_output:
705 705 inline, output = inline
706 706 inline = inline.expandtabs(4).rstrip()
707
707
708 708 multiline = "\n" in inline
709 709 line_sep = '\n' if multiline else ' '
710 710 if print_nums:
@@ -727,29 +727,29 b' def magic_rep(self, arg):'
727 727 %rep are equivalent.
728 728
729 729 - %recall (no arguments):
730
730
731 731 Place a string version of last computation result (stored in the special '_'
732 732 variable) to the next input prompt. Allows you to create elaborate command
733 733 lines without using copy-paste::
734
734
735 735 In[1]: l = ["hei", "vaan"]
736 736 In[2]: "".join(l)
737 737 Out[2]: heivaan
738 738 In[3]: %rep
739 739 In[4]: heivaan_ <== cursor blinking
740
740
741 741 %recall 45
742
742
743 743 Place history line 45 on the next input prompt. Use %hist to find
744 744 out the number.
745
745
746 746 %recall 1-4
747
747
748 748 Combine the specified lines into one cell, and place it on the next
749 749 input prompt. See %history for the slice syntax.
750
750
751 751 %recall foo+bar
752
752
753 753 If foo+bar can be evaluated in the user namespace, the result is
754 754 placed at the next input prompt. Otherwise, the history is searched
755 755 for lines which contain that substring, and the most recent one is
@@ -777,18 +777,18 b' def magic_rep(self, arg):'
777 777 else:
778 778 self.set_next_input(cmd.rstrip())
779 779 print("Couldn't evaluate or find in history:", arg)
780
780
781 781 def magic_rerun(self, parameter_s=''):
782 782 """Re-run previous input
783
783
784 784 By default, you can specify ranges of input history to be repeated
785 785 (as with %history). With no arguments, it will repeat the last line.
786
786
787 787 Options:
788
788
789 789 -l <n> : Repeat the last n lines of input, not including the
790 790 current command.
791
791
792 792 -g foo : Repeat the most recent line which contains foo
793 793 """
794 794 opts, args = self.parse_options(parameter_s, 'l:g:', mode='string')
@@ -820,7 +820,7 b" def magic_rerun(self, parameter_s=''):"
820 820
821 821
822 822 def init_ipython(ip):
823 ip.define_magic("rep", magic_rep)
823 ip.define_magic("rep", magic_rep)
824 824 ip.define_magic("recall", magic_rep)
825 825 ip.define_magic("rerun", magic_rerun)
826 826 ip.define_magic("hist",magic_history) # Alternative name
@@ -64,24 +64,24 b' def editor(self,filename, linenum=None):'
64 64 # IPython configures a default editor at startup by reading $EDITOR from
65 65 # the environment, and falling back on vi (unix) or notepad (win32).
66 66 editor = self.editor
67
67
68 68 # marker for at which line to open the file (for existing objects)
69 69 if linenum is None or editor=='notepad':
70 70 linemark = ''
71 71 else:
72 72 linemark = '+%d' % int(linenum)
73
73
74 74 # Enclose in quotes if necessary and legal
75 75 if ' ' in editor and os.path.isfile(editor) and editor[0] != '"':
76 76 editor = '"%s"' % editor
77
77
78 78 # Call the actual editor
79 79 if os.system('%s %s %s' % (editor,linemark,filename)) != 0:
80 80 raise TryNext()
81 81
82 82 import tempfile
83 83 def fix_error_editor(self,filename,linenum,column,msg):
84 """Open the editor at the given filename, linenumber, column and
84 """Open the editor at the given filename, linenumber, column and
85 85 show an error message. This is used for correcting syntax errors.
86 86 The current implementation only has special support for the VIM editor,
87 87 and falls back on the 'editor' hook if VIM is not used.
@@ -110,25 +110,25 b' def synchronize_with_editor(self, filename, linenum, column):'
110 110
111 111 class CommandChainDispatcher:
112 112 """ Dispatch calls to a chain of commands until some func can handle it
113
113
114 114 Usage: instantiate, execute "add" to add commands (with optional
115 115 priority), execute normally via f() calling mechanism.
116
116
117 117 """
118 118 def __init__(self,commands=None):
119 119 if commands is None:
120 120 self.chain = []
121 121 else:
122 122 self.chain = commands
123
124
123
124
125 125 def __call__(self,*args, **kw):
126 """ Command chain is called just like normal func.
127
126 """ Command chain is called just like normal func.
127
128 128 This will call all funcs in chain with the same args as were given to this
129 129 function, and return the result of first func that didn't raise
130 130 TryNext """
131
131
132 132 for prio,cmd in self.chain:
133 133 #print "prio",prio,"cmd",cmd #dbg
134 134 try:
@@ -139,32 +139,32 b' class CommandChainDispatcher:'
139 139 kw = exc.kwargs
140 140 # if no function will accept it, raise TryNext up to the caller
141 141 raise TryNext
142
142
143 143 def __str__(self):
144 144 return str(self.chain)
145
145
146 146 def add(self, func, priority=0):
147 147 """ Add a func to the cmd chain with given priority """
148 148 bisect.insort(self.chain,(priority,func))
149 149
150 150 def __iter__(self):
151 151 """ Return all objects in chain.
152
152
153 153 Handy if the objects are not callable.
154 154 """
155 155 return iter(self.chain)
156 156
157 157
158 def input_prefilter(self,line):
158 def input_prefilter(self,line):
159 159 """ Default input prefilter
160
160
161 161 This returns the line as unchanged, so that the interpreter
162 162 knows that nothing was done and proceeds with "classic" prefiltering
163 (%magics, !shell commands etc.).
164
163 (%magics, !shell commands etc.).
164
165 165 Note that leading whitespace is not passed to this hook. Prefilter
166 166 can't alter indentation.
167
167
168 168 """
169 169 #print "attempt to rewrite",line #dbg
170 170 return line
@@ -172,17 +172,17 b' def input_prefilter(self,line):'
172 172
173 173 def shutdown_hook(self):
174 174 """ default shutdown hook
175
175
176 176 Typically, shotdown hooks should raise TryNext so all shutdown ops are done
177 177 """
178
178
179 179 #print "default shutdown hook ok" # dbg
180 180 return
181 181
182 182
183 183 def late_startup_hook(self):
184 """ Executed after ipython has been constructed and configured
185
184 """ Executed after ipython has been constructed and configured
185
186 186 """
187 187 #print "default startup hook ok" # dbg
188 188
@@ -202,11 +202,11 b' def show_in_pager(self,s):'
202 202
203 203 def pre_prompt_hook(self):
204 204 """ Run before displaying the next prompt
205
206 Use this e.g. to display output from asynchronous operations (in order
207 to not mess up text entry)
205
206 Use this e.g. to display output from asynchronous operations (in order
207 to not mess up text entry)
208 208 """
209
209
210 210 return None
211 211
212 212
@@ -219,7 +219,7 b' def clipboard_get(self):'
219 219 """ Get text from the clipboard.
220 220 """
221 221 from IPython.lib.clipboard import (
222 osx_clipboard_get, tkinter_clipboard_get,
222 osx_clipboard_get, tkinter_clipboard_get,
223 223 win32_clipboard_get
224 224 )
225 225 if sys.platform == 'win32':
@@ -145,7 +145,7 b' class ReadlineNoRecord(object):'
145 145 def __init__(self, shell):
146 146 self.shell = shell
147 147 self._nested_level = 0
148
148
149 149 def __enter__(self):
150 150 if self._nested_level == 0:
151 151 try:
@@ -154,7 +154,7 b' class ReadlineNoRecord(object):'
154 154 except (AttributeError, IndexError): # Can fail with pyreadline
155 155 self.orig_length, self.readline_tail = 999999, []
156 156 self._nested_level += 1
157
157
158 158 def __exit__(self, type, value, traceback):
159 159 self._nested_level -= 1
160 160 if self._nested_level == 0:
@@ -164,7 +164,7 b' class ReadlineNoRecord(object):'
164 164 if e > 0:
165 165 for _ in range(e):
166 166 self.shell.readline.remove_history_item(self.orig_length)
167
167
168 168 # If it still doesn't match, just reload readline history.
169 169 if self.current_length() != self.orig_length \
170 170 or self.get_readline_tail() != self.readline_tail:
@@ -173,10 +173,10 b' class ReadlineNoRecord(object):'
173 173 pass
174 174 # Returning False will cause exceptions to propagate
175 175 return False
176
176
177 177 def current_length(self):
178 178 return self.shell.readline.get_current_history_length()
179
179
180 180 def get_readline_tail(self, n=10):
181 181 """Get the last n items in readline history."""
182 182 end = self.shell.readline.get_current_history_length() + 1
@@ -243,7 +243,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
243 243 get confused with color codes, this capability can be turned off.
244 244 """
245 245 )
246 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
246 colors = CaselessStrEnum(('NoColor','LightBG','Linux'),
247 247 default_value=get_default_colors(), config=True,
248 248 help="Set the color scheme (NoColor, Linux, or LightBG)."
249 249 )
@@ -315,7 +315,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
315 315 quiet = CBool(False, config=True)
316 316
317 317 history_length = Int(10000, config=True)
318
318
319 319 # The readline stuff will eventually be moved to the terminal subclass
320 320 # but for now, we can't do that as readline is welded in everywhere.
321 321 readline_use = CBool(True, config=True)
@@ -345,7 +345,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
345 345 separate_out = SeparateUnicode('', config=True)
346 346 separate_out2 = SeparateUnicode('', config=True)
347 347 wildcards_case_sensitive = CBool(True, config=True)
348 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
348 xmode = CaselessStrEnum(('Context','Plain', 'Verbose'),
349 349 default_value='Context', config=True)
350 350
351 351 # Subcomponents of InteractiveShell
@@ -393,7 +393,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
393 393 # is what we want to do.
394 394 self.save_sys_module_state()
395 395 self.init_sys_modules()
396
396
397 397 # While we're trying to have each part of the code directly access what
398 398 # it needs without keeping redundant references to objects, we have too
399 399 # much legacy code that expects ip.db to exist.
@@ -583,7 +583,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
583 583 def init_io(self):
584 584 # This will just use sys.stdout and sys.stderr. If you want to
585 585 # override sys.stdout and sys.stderr themselves, you need to do that
586 # *before* instantiating this class, because io holds onto
586 # *before* instantiating this class, because io holds onto
587 587 # references to the underlying streams.
588 588 if sys.platform == 'win32' and self.has_readline:
589 589 io.stdout = io.stderr = io.IOStream(self.readline._outputfile)
@@ -593,7 +593,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
593 593
594 594 def init_prompts(self):
595 595 # TODO: This is a pass for now because the prompts are managed inside
596 # the DisplayHook. Once there is a separate prompt manager, this
596 # the DisplayHook. Once there is a separate prompt manager, this
597 597 # will initialize that object and all prompt related information.
598 598 pass
599 599
@@ -682,13 +682,13 b' class InteractiveShell(SingletonConfigurable, Magic):'
682 682 """set_hook(name,hook) -> sets an internal IPython hook.
683 683
684 684 IPython exposes some of its internal API as user-modifiable hooks. By
685 adding your function to one of these hooks, you can modify IPython's
685 adding your function to one of these hooks, you can modify IPython's
686 686 behavior to call at runtime your own routines."""
687 687
688 688 # At some point in the future, this should validate the hook before it
689 689 # accepts it. Probably at least check that the hook takes the number
690 690 # of args it's supposed to.
691
691
692 692 f = types.MethodType(hook,self)
693 693
694 694 # check if the hook is for strdispatcher first
@@ -702,14 +702,14 b' class InteractiveShell(SingletonConfigurable, Magic):'
702 702 sdp.add_re(re.compile(re_key), f, priority )
703 703 self.strdispatchers[name] = sdp
704 704 return
705
705
706 706 dp = getattr(self.hooks, name, None)
707 707 if name not in IPython.core.hooks.__all__:
708 708 print "Warning! Hook '%s' is not one of %s" % \
709 709 (name, IPython.core.hooks.__all__ )
710 710 if not dp:
711 711 dp = IPython.core.hooks.CommandChainDispatcher()
712
712
713 713 try:
714 714 dp.add(f,priority)
715 715 except AttributeError:
@@ -757,7 +757,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
757 757 must therefore make a *copy* of the given namespace, to allow the
758 758 original module's __dict__ to be cleared and reused.
759 759
760
760
761 761 Parameters
762 762 ----------
763 763 ns : a namespace (a dict, typically)
@@ -849,7 +849,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
849 849 else:
850 850 # fallback to our internal debugger
851 851 pm = lambda : self.InteractiveTB.debugger(force=True)
852
852
853 853 with self.readline_no_record:
854 854 pm()
855 855
@@ -923,7 +923,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
923 923 # the script will fail, because the function's closure had references
924 924 # to the original objects, which are now all None. So we must protect
925 925 # these modules from deletion by keeping a cache.
926 #
926 #
927 927 # To avoid keeping stale modules around (we only need the one from the
928 928 # last run), we use a dict keyed with the full path to the script, so
929 929 # only the last version of the module is held in the cache. Note,
@@ -931,7 +931,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
931 931 # __dict__). Because if we try to cache the actual modules, old ones
932 932 # (uncached) could be destroyed while still holding references (such as
933 933 # those held by GUI objects that tend to be long-lived)>
934 #
934 #
935 935 # The %reset command will flush this cache. See the cache_main_mod()
936 936 # and clear_main_mod_cache() methods for details on use.
937 937
@@ -1067,11 +1067,11 b' class InteractiveShell(SingletonConfigurable, Magic):'
1067 1067 # module, and can even mutate at runtime, depending on the context
1068 1068 # (Python makes no guarantees on it). In contrast, __builtin__ is
1069 1069 # always a module object, though it must be explicitly imported.
1070
1070
1071 1071 # For more details:
1072 1072 # http://mail.python.org/pipermail/python-dev/2001-April/014068.html
1073 1073 ns = dict(__builtin__ = builtin_mod)
1074
1074
1075 1075 # Put 'help' in the user namespace
1076 1076 try:
1077 1077 from site import _Helper
@@ -1093,7 +1093,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1093 1093
1094 1094 # Store myself as the public api!!!
1095 1095 ns['get_ipython'] = self.get_ipython
1096
1096
1097 1097 ns['exit'] = self.exiter
1098 1098 ns['quit'] = self.exiter
1099 1099
@@ -1104,14 +1104,14 b' class InteractiveShell(SingletonConfigurable, Magic):'
1104 1104 # Anything put into ns now would show up in %who. Think twice before
1105 1105 # putting anything here, as we really want %who to show the user their
1106 1106 # stuff, not our variables.
1107
1107
1108 1108 # Finally, update the real user's namespace
1109 1109 self.user_ns.update(ns)
1110 1110
1111 1111 def reset(self, new_session=True):
1112 1112 """Clear all internal namespaces, and attempt to release references to
1113 1113 user objects.
1114
1114
1115 1115 If new_session is True, a new history session will be opened.
1116 1116 """
1117 1117 # Clear histories
@@ -1119,11 +1119,11 b' class InteractiveShell(SingletonConfigurable, Magic):'
1119 1119 # Reset counter used to index all histories
1120 1120 if new_session:
1121 1121 self.execution_count = 1
1122
1122
1123 1123 # Flush cached output items
1124 1124 if self.displayhook.do_full_cache:
1125 1125 self.displayhook.flush()
1126
1126
1127 1127 # Restore the user namespaces to minimal usability
1128 1128 for ns in self.ns_refs_table:
1129 1129 ns.clear()
@@ -1137,25 +1137,25 b' class InteractiveShell(SingletonConfigurable, Magic):'
1137 1137 drop_keys.discard('__builtins__')
1138 1138 for k in drop_keys:
1139 1139 del ns[k]
1140
1140
1141 1141 # Restore the user namespaces to minimal usability
1142 1142 self.init_user_ns()
1143 1143
1144 1144 # Restore the default and user aliases
1145 1145 self.alias_manager.clear_aliases()
1146 1146 self.alias_manager.init_aliases()
1147
1147
1148 1148 # Flush the private list of module references kept for script
1149 1149 # execution protection
1150 1150 self.clear_main_mod_cache()
1151
1151
1152 1152 # Clear out the namespace from the last %run
1153 1153 self.new_main_mod()
1154
1154
1155 1155 def del_var(self, varname, by_name=False):
1156 1156 """Delete a variable from the various namespaces, so that, as
1157 1157 far as possible, we're not keeping any hidden references to it.
1158
1158
1159 1159 Parameters
1160 1160 ----------
1161 1161 varname : str
@@ -1170,7 +1170,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1170 1170 ns_refs = self.ns_refs_table + [self.user_ns,
1171 1171 self.user_global_ns, self._user_main_module.__dict__] +\
1172 1172 self._main_ns_cache.values()
1173
1173
1174 1174 if by_name: # Delete by name
1175 1175 for ns in ns_refs:
1176 1176 try:
@@ -1188,12 +1188,12 b' class InteractiveShell(SingletonConfigurable, Magic):'
1188 1188 to_delete = [n for n, o in ns.iteritems() if o is obj]
1189 1189 for name in to_delete:
1190 1190 del ns[name]
1191
1191
1192 1192 # displayhook keeps extra references, but not in a dictionary
1193 1193 for name in ('_', '__', '___'):
1194 1194 if getattr(self.displayhook, name) is obj:
1195 1195 setattr(self.displayhook, name, None)
1196
1196
1197 1197 def reset_selective(self, regex=None):
1198 1198 """Clear selective variables from internal namespaces based on a
1199 1199 specified regular expression.
@@ -1214,8 +1214,8 b' class InteractiveShell(SingletonConfigurable, Magic):'
1214 1214 for ns in self.ns_refs_table:
1215 1215 for var in ns:
1216 1216 if m.search(var):
1217 del ns[var]
1218
1217 del ns[var]
1218
1219 1219 def push(self, variables, interactive=True):
1220 1220 """Inject a group of variables into the IPython user namespace.
1221 1221
@@ -1252,7 +1252,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1252 1252 (name,cf.f_code.co_name))
1253 1253 else:
1254 1254 raise ValueError('variables must be a dict/str/list/tuple')
1255
1255
1256 1256 # Propagate variables to user namespace
1257 1257 self.user_ns.update(vdict)
1258 1258
@@ -1361,11 +1361,11 b' class InteractiveShell(SingletonConfigurable, Magic):'
1361 1361 root = '.'.join(path[:-1])
1362 1362 if info.parent is not None:
1363 1363 try:
1364 target = getattr(info.parent, '__class__')
1365 # The object belongs to a class instance.
1366 try:
1364 target = getattr(info.parent, '__class__')
1365 # The object belongs to a class instance.
1366 try:
1367 1367 target = getattr(target, path[-1])
1368 # The class defines the object.
1368 # The class defines the object.
1369 1369 if isinstance(target, property):
1370 1370 oname = root + '.__class__.' + path[-1]
1371 1371 info = Struct(self._ofind(oname))
@@ -1380,7 +1380,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1380 1380 """Find an object and return a struct with info about it."""
1381 1381 inf = Struct(self._ofind(oname, namespaces))
1382 1382 return Struct(self._ofind_property(oname, inf))
1383
1383
1384 1384 def _inspect(self, meth, oname, namespaces=None, **kw):
1385 1385 """Generic interface to the inspector system.
1386 1386
@@ -1422,7 +1422,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1422 1422 def init_traceback_handlers(self, custom_exceptions):
1423 1423 # Syntax error handler.
1424 1424 self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor')
1425
1425
1426 1426 # The interactive one is initialized with an offset, meaning we always
1427 1427 # want to remove the topmost item in the traceback, which is our own
1428 1428 # internal code. Valid modes: ['Plain','Context','Verbose']
@@ -1526,7 +1526,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1526 1526 care of calling it if needed, so unless you are explicitly catching a
1527 1527 SyntaxError exception, don't try to analyze the stack manually and
1528 1528 simply call this method."""
1529
1529
1530 1530 try:
1531 1531 if exc_tuple is None:
1532 1532 etype, value, tb = sys.exc_info()
@@ -1540,7 +1540,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1540 1540 else:
1541 1541 self.write_err('No traceback available to show.\n')
1542 1542 return
1543
1543
1544 1544 if etype is SyntaxError:
1545 1545 # Though this won't be called by syntax errors in the input
1546 1546 # line, there may be SyntaxError cases with imported code.
@@ -1570,14 +1570,14 b' class InteractiveShell(SingletonConfigurable, Magic):'
1570 1570 else:
1571 1571 stb = self.InteractiveTB.structured_traceback(etype,
1572 1572 value, tb, tb_offset=tb_offset)
1573
1573
1574 1574 if self.call_pdb:
1575 1575 # drop into debugger
1576 1576 self.debugger(force=True)
1577 1577
1578 1578 # Actually show the traceback
1579 1579 self._showtraceback(etype, value, stb)
1580
1580
1581 1581 except KeyboardInterrupt:
1582 1582 self.write_err("\nKeyboardInterrupt\n")
1583 1583
@@ -1604,7 +1604,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1604 1604 sys.last_type = etype
1605 1605 sys.last_value = value
1606 1606 sys.last_traceback = last_traceback
1607
1607
1608 1608 if filename and etype is SyntaxError:
1609 1609 # Work hard to stuff the correct filename in the exception
1610 1610 try:
@@ -1622,13 +1622,13 b' class InteractiveShell(SingletonConfigurable, Magic):'
1622 1622 value = msg, (filename, lineno, offset, line)
1623 1623 stb = self.SyntaxTB.structured_traceback(etype, value, [])
1624 1624 self._showtraceback(etype, value, stb)
1625
1625
1626 1626 # This is overridden in TerminalInteractiveShell to show a message about
1627 1627 # the %paste magic.
1628 1628 def showindentationerror(self):
1629 1629 """Called by run_cell when there's an IndentationError in code entered
1630 1630 at the prompt.
1631
1631
1632 1632 This is overridden in TerminalInteractiveShell to show a message about
1633 1633 the %paste magic."""
1634 1634 self.showsyntaxerror()
@@ -1660,7 +1660,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1660 1660 self.has_readline = True
1661 1661 self.readline = readline
1662 1662 sys.modules['readline'] = readline
1663
1663
1664 1664 # Platform-specific configuration
1665 1665 if os.name == 'nt':
1666 1666 # FIXME - check with Frederick to see if we can harmonize
@@ -1686,7 +1686,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1686 1686 except:
1687 1687 warn('Problems reading readline initialization file <%s>'
1688 1688 % inputrc_name)
1689
1689
1690 1690 # Configure readline according to user's prefs
1691 1691 # This is only done if GNU readline is being used. If libedit
1692 1692 # is being used (as on Leopard) the readline config is
@@ -1707,13 +1707,13 b' class InteractiveShell(SingletonConfigurable, Magic):'
1707 1707 readline.set_completer_delims(delims)
1708 1708 # otherwise we end up with a monster history after a while:
1709 1709 readline.set_history_length(self.history_length)
1710
1710
1711 1711 self.refill_readline_hist()
1712 1712 self.readline_no_record = ReadlineNoRecord(self)
1713 1713
1714 1714 # Configure auto-indent for all platforms
1715 1715 self.set_autoindent(self.autoindent)
1716
1716
1717 1717 def refill_readline_hist(self):
1718 1718 # Load the last 1000 lines from history
1719 1719 self.readline.clear_history()
@@ -1727,13 +1727,13 b' class InteractiveShell(SingletonConfigurable, Magic):'
1727 1727
1728 1728 def set_next_input(self, s):
1729 1729 """ Sets the 'default' input string for the next command line.
1730
1730
1731 1731 Requires readline.
1732
1732
1733 1733 Example:
1734
1734
1735 1735 [D:\ipython]|1> _ip.set_next_input("Hello Word")
1736 [D:\ipython]|2> Hello Word_ # cursor is here
1736 [D:\ipython]|2> Hello Word_ # cursor is here
1737 1737 """
1738 1738 if isinstance(s, unicode):
1739 1739 s = s.encode(self.stdin_encoding, 'replace')
@@ -1770,7 +1770,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1770 1770 from IPython.core.completer import IPCompleter
1771 1771 from IPython.core.completerlib import (module_completer,
1772 1772 magic_run_completer, cd_completer)
1773
1773
1774 1774 self.Completer = IPCompleter(shell=self,
1775 1775 namespace=self.user_ns,
1776 1776 global_namespace=self.user_global_ns,
@@ -1779,7 +1779,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1779 1779 use_readline=self.has_readline,
1780 1780 config=self.config,
1781 1781 )
1782
1782
1783 1783 # Add custom completers to the basic ones built into IPCompleter
1784 1784 sdisp = self.strdispatchers.get('complete_command', StrDispatch())
1785 1785 self.strdispatchers['complete_command'] = sdisp
@@ -1823,7 +1823,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1823 1823
1824 1824 The optional arguments allow the completion to take more context into
1825 1825 account, and are part of the low-level completion API.
1826
1826
1827 1827 This is a wrapper around the completion mechanism, similar to what
1828 1828 readline does at the command line when the TAB key is hit. By
1829 1829 exposing it as a method, it can be used by other non-readline
@@ -1897,11 +1897,11 b' class InteractiveShell(SingletonConfigurable, Magic):'
1897 1897 # We do this first so that magic functions can override it.
1898 1898 if next_input:
1899 1899 self.set_next_input(next_input)
1900
1900
1901 1901 args = arg_s.split(' ',1)
1902 1902 magic_name = args[0]
1903 1903 magic_name = magic_name.lstrip(prefilter.ESC_MAGIC)
1904
1904
1905 1905 try:
1906 1906 magic_args = args[1]
1907 1907 except IndexError:
@@ -1921,14 +1921,14 b' class InteractiveShell(SingletonConfigurable, Magic):'
1921 1921 return result
1922 1922
1923 1923 def define_magic(self, magicname, func):
1924 """Expose own function as magic function for ipython
1925
1924 """Expose own function as magic function for ipython
1925
1926 1926 def foo_impl(self,parameter_s=''):
1927 1927 'My very own magic!. (Use docstrings, IPython reads them).'
1928 1928 print 'Magic function. Passed parameter is between < >:'
1929 1929 print '<%s>' % parameter_s
1930 1930 print 'The self object is:',self
1931
1931
1932 1932 self.define_magic('foo',foo_impl)
1933 1933 """
1934 1934 im = types.MethodType(func,self)
@@ -1948,10 +1948,10 b' class InteractiveShell(SingletonConfigurable, Magic):'
1948 1948 name : str
1949 1949 The name of the macro.
1950 1950 themacro : str or Macro
1951 The action to do upon invoking the macro. If a string, a new
1951 The action to do upon invoking the macro. If a string, a new
1952 1952 Macro object is created by passing the string to it.
1953 1953 """
1954
1954
1955 1955 from IPython.core import macro
1956 1956
1957 1957 if isinstance(themacro, basestring):
@@ -1981,15 +1981,15 b' class InteractiveShell(SingletonConfigurable, Magic):'
1981 1981 # os.system() or use ip.system=ip.system_raw
1982 1982 # if they really want a background process.
1983 1983 raise OSError("Background processes not supported.")
1984
1984
1985 1985 # we explicitly do NOT return the subprocess status code, because
1986 1986 # a non-None value would trigger :func:`sys.displayhook` calls.
1987 1987 # Instead, we store the exit_code in user_ns.
1988 1988 self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=2))
1989
1989
1990 1990 def system_raw(self, cmd):
1991 1991 """Call the given cmd in a subprocess using os.system
1992
1992
1993 1993 Parameters
1994 1994 ----------
1995 1995 cmd : str
@@ -1999,7 +1999,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
1999 1999 # a non-None value would trigger :func:`sys.displayhook` calls.
2000 2000 # Instead, we store the exit_code in user_ns.
2001 2001 self.user_ns['_exit_code'] = os.system(self.var_expand(cmd, depth=2))
2002
2002
2003 2003 # use piped system by default, because it is better behaved
2004 2004 system = system_piped
2005 2005
@@ -2012,7 +2012,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2012 2012 Command to execute (can not end in '&', as background processes are
2013 2013 not supported.
2014 2014 split : bool, optional
2015
2015
2016 2016 If True, split the output into an IPython SList. Otherwise, an
2017 2017 IPython LSString is returned. These are objects similar to normal
2018 2018 lists and strings, with a few convenience attributes for easier
@@ -2076,7 +2076,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2076 2076 into::
2077 2077
2078 2078 ------> f(x)
2079
2079
2080 2080 after the user's input prompt. This helps the user understand that the
2081 2081 input line was transformed automatically by IPython.
2082 2082 """
@@ -2089,7 +2089,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2089 2089 print >> io.stdout, rw
2090 2090 except UnicodeEncodeError:
2091 2091 print "------> " + cmd
2092
2092
2093 2093 #-------------------------------------------------------------------------
2094 2094 # Things related to extracting values/expressions from kernel and user_ns
2095 2095 #-------------------------------------------------------------------------
@@ -2119,7 +2119,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2119 2119 value = self._simple_error()
2120 2120 out[varname] = value
2121 2121 return out
2122
2122
2123 2123 def user_expressions(self, expressions):
2124 2124 """Evaluate a dict of expressions in the user's namespace.
2125 2125
@@ -2129,7 +2129,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2129 2129 A dict with string keys and string values. The expression values
2130 2130 should be valid Python expressions, each of which will be evaluated
2131 2131 in the user namespace.
2132
2132
2133 2133 Returns
2134 2134 -------
2135 2135 A dict, keyed like the input expressions dict, with the repr() of each
@@ -2251,10 +2251,10 b' class InteractiveShell(SingletonConfigurable, Magic):'
2251 2251 except:
2252 2252 self.showtraceback()
2253 2253 warn('Unknown failure executing file: <%s>' % fname)
2254
2254
2255 2255 def run_cell(self, raw_cell, store_history=True):
2256 2256 """Run a complete IPython cell.
2257
2257
2258 2258 Parameters
2259 2259 ----------
2260 2260 raw_cell : str
@@ -2266,11 +2266,11 b' class InteractiveShell(SingletonConfigurable, Magic):'
2266 2266 """
2267 2267 if (not raw_cell) or raw_cell.isspace():
2268 2268 return
2269
2269
2270 2270 for line in raw_cell.splitlines():
2271 2271 self.input_splitter.push(line)
2272 2272 cell = self.input_splitter.source_reset()
2273
2273
2274 2274 with self.builtin_trap:
2275 2275 prefilter_failed = False
2276 2276 if len(cell.splitlines()) == 1:
@@ -2285,18 +2285,18 b' class InteractiveShell(SingletonConfigurable, Magic):'
2285 2285 # don't allow prefilter errors to crash IPython
2286 2286 self.showtraceback()
2287 2287 prefilter_failed = True
2288
2288
2289 2289 # Store raw and processed history
2290 2290 if store_history:
2291 self.history_manager.store_inputs(self.execution_count,
2291 self.history_manager.store_inputs(self.execution_count,
2292 2292 cell, raw_cell)
2293 2293
2294 2294 self.logger.log(cell, raw_cell)
2295
2295
2296 2296 if not prefilter_failed:
2297 2297 # don't run if prefilter failed
2298 2298 cell_name = self.compile.cache(cell, self.execution_count)
2299
2299
2300 2300 with self.display_trap:
2301 2301 try:
2302 2302 code_ast = self.compile.ast_parse(cell, filename=cell_name)
@@ -2309,10 +2309,10 b' class InteractiveShell(SingletonConfigurable, Magic):'
2309 2309 self.showsyntaxerror()
2310 2310 self.execution_count += 1
2311 2311 return None
2312
2312
2313 2313 self.run_ast_nodes(code_ast.body, cell_name,
2314 2314 interactivity="last_expr")
2315
2315
2316 2316 # Execute any registered post-execution functions.
2317 2317 for func, status in self._post_execute.iteritems():
2318 2318 if not status:
@@ -2323,18 +2323,18 b' class InteractiveShell(SingletonConfigurable, Magic):'
2323 2323 self.showtraceback()
2324 2324 # Deactivate failing function
2325 2325 self._post_execute[func] = False
2326
2326
2327 2327 if store_history:
2328 2328 # Write output to the database. Does nothing unless
2329 2329 # history output logging is enabled.
2330 2330 self.history_manager.store_output(self.execution_count)
2331 2331 # Each cell is a *single* input, regardless of how many lines it has
2332 2332 self.execution_count += 1
2333
2333
2334 2334 def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr'):
2335 2335 """Run a sequence of AST nodes. The execution mode depends on the
2336 2336 interactivity parameter.
2337
2337
2338 2338 Parameters
2339 2339 ----------
2340 2340 nodelist : list
@@ -2351,13 +2351,13 b' class InteractiveShell(SingletonConfigurable, Magic):'
2351 2351 """
2352 2352 if not nodelist:
2353 2353 return
2354
2354
2355 2355 if interactivity == 'last_expr':
2356 2356 if isinstance(nodelist[-1], ast.Expr):
2357 2357 interactivity = "last"
2358 2358 else:
2359 2359 interactivity = "none"
2360
2360
2361 2361 if interactivity == 'none':
2362 2362 to_run_exec, to_run_interactive = nodelist, []
2363 2363 elif interactivity == 'last':
@@ -2366,7 +2366,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2366 2366 to_run_exec, to_run_interactive = [], nodelist
2367 2367 else:
2368 2368 raise ValueError("Interactivity was %r" % interactivity)
2369
2369
2370 2370 exec_count = self.execution_count
2371 2371
2372 2372 try:
@@ -2394,7 +2394,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2394 2394 self.showtraceback()
2395 2395
2396 2396 return False
2397
2397
2398 2398 def run_code(self, code_obj):
2399 2399 """Execute a code object.
2400 2400
@@ -2444,7 +2444,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2444 2444 print
2445 2445
2446 2446 return outflag
2447
2447
2448 2448 # For backwards compatibility
2449 2449 runcode = run_code
2450 2450
@@ -2487,7 +2487,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2487 2487
2488 2488 filename = tempfile.mktemp('.py', prefix)
2489 2489 self.tempfiles.append(filename)
2490
2490
2491 2491 if data:
2492 2492 tmp_file = open(filename,'w')
2493 2493 tmp_file.write(data)
@@ -2508,16 +2508,16 b' class InteractiveShell(SingletonConfigurable, Magic):'
2508 2508 if self.quiet:
2509 2509 return True
2510 2510 return ask_yes_no(prompt,default)
2511
2511
2512 2512 def show_usage(self):
2513 2513 """Show a usage message"""
2514 2514 page.page(IPython.core.usage.interactive_usage)
2515
2515
2516 2516 def find_user_code(self, target, raw=True):
2517 2517 """Get a code string from history, file, or a string or macro.
2518
2519 This is mainly used by magic functions.
2520
2518
2519 This is mainly used by magic functions.
2520
2521 2521 Parameters
2522 2522 ----------
2523 2523 target : str
@@ -2527,21 +2527,21 b' class InteractiveShell(SingletonConfigurable, Magic):'
2527 2527 raw : bool
2528 2528 If true (default), retrieve raw history. Has no effect on the other
2529 2529 retrieval mechanisms.
2530
2530
2531 2531 Returns
2532 2532 -------
2533 2533 A string of code.
2534
2534
2535 2535 ValueError is raised if nothing is found, and TypeError if it evaluates
2536 2536 to an object of another type. In each case, .args[0] is a printable
2537 2537 message.
2538 2538 """
2539 code = self.extract_input_lines(target, raw=raw) # Grab history
2539 code = self.extract_input_lines(target, raw=raw) # Grab history
2540 2540 if code:
2541 2541 return code
2542 2542 if os.path.isfile(target): # Read file
2543 2543 return open(target, "r").read()
2544
2544
2545 2545 try: # User namespace
2546 2546 codeobj = eval(target, self.user_ns)
2547 2547 except Exception:
@@ -2551,7 +2551,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
2551 2551 return codeobj
2552 2552 elif isinstance(codeobj, Macro):
2553 2553 return codeobj.value
2554
2554
2555 2555 raise TypeError("%s is neither a string nor a macro." % target,
2556 2556 codeobj)
2557 2557
@@ -2567,20 +2567,20 b' class InteractiveShell(SingletonConfigurable, Magic):'
2567 2567 For things that may depend on startup flags or platform specifics (such
2568 2568 as having readline or not), register a separate atexit function in the
2569 2569 code that has the appropriate information, rather than trying to
2570 clutter
2570 clutter
2571 2571 """
2572 2572 # Close the history session (this stores the end time and line count)
2573 2573 # this must be *before* the tempfile cleanup, in case of temporary
2574 2574 # history db
2575 2575 self.history_manager.end_session()
2576
2576
2577 2577 # Cleanup all tempfiles left around
2578 2578 for tfile in self.tempfiles:
2579 2579 try:
2580 2580 os.unlink(tfile)
2581 2581 except OSError:
2582 2582 pass
2583
2583
2584 2584 # Clear all user namespaces to release all references cleanly.
2585 2585 self.reset(new_session=False)
2586 2586
@@ -58,7 +58,7 b' class Logger(object):'
58 58 return self._logmode
59 59
60 60 logmode = property(_get_mode,_set_mode)
61
61
62 62 def logstart(self,logfname=None,loghead=None,logmode=None,
63 63 log_output=False,timestamp=False,log_raw_input=False):
64 64 """Generate a new log-file with a default header.
@@ -68,7 +68,7 b' class Logger(object):'
68 68 if self.logfile is not None:
69 69 raise RuntimeError('Log file is already active: %s' %
70 70 self.logfname)
71
71
72 72 # The parameters can override constructor defaults
73 73 if logfname is not None: self.logfname = logfname
74 74 if loghead is not None: self.loghead = loghead
@@ -78,7 +78,7 b' class Logger(object):'
78 78 self.timestamp = timestamp
79 79 self.log_output = log_output
80 80 self.log_raw_input = log_raw_input
81
81
82 82 # init depending on the log mode requested
83 83 isfile = os.path.isfile
84 84 logmode = self.logmode
@@ -102,12 +102,12 b' class Logger(object):'
102 102
103 103 elif logmode == 'over':
104 104 if isfile(self.logfname):
105 os.remove(self.logfname)
105 os.remove(self.logfname)
106 106 self.logfile = open(self.logfname,'w')
107 107
108 108 elif logmode == 'rotate':
109 109 if isfile(self.logfname):
110 if isfile(self.logfname+'.001~'):
110 if isfile(self.logfname+'.001~'):
111 111 old = glob.glob(self.logfname+'.*~')
112 112 old.sort()
113 113 old.reverse()
@@ -117,7 +117,7 b' class Logger(object):'
117 117 os.rename(f, root+'.'+`num`.zfill(3)+'~')
118 118 os.rename(self.logfname, self.logfname+'.001~')
119 119 self.logfile = open(self.logfname,'w')
120
120
121 121 if logmode != 'append':
122 122 self.logfile.write(self.loghead)
123 123
@@ -130,7 +130,7 b' class Logger(object):'
130 130 if val not in [False,True,0,1]:
131 131 raise ValueError, \
132 132 'Call switch_log ONLY with a boolean argument, not with:',val
133
133
134 134 label = {0:'OFF',1:'ON',False:'OFF',True:'ON'}
135 135
136 136 if self.logfile is None:
@@ -140,7 +140,7 b" Logging hasn't been started yet (use logstart for that)."
140 140 %logon/%logoff are for temporarily starting and stopping logging for a logfile
141 141 which already exists. But you must first start the logging process with
142 142 %logstart (optionally giving a logfile name)."""
143
143
144 144 else:
145 145 if self.log_active == val:
146 146 print 'Logging is already',label[val]
@@ -205,7 +205,7 b' which already exists. But you must first start the logging process with'
205 205 In order to start logging again, a new logstart() call needs to be
206 206 made, possibly (though not necessarily) with a new filename, mode and
207 207 other options."""
208
208
209 209 if self.logfile is not None:
210 210 self.logfile.close()
211 211 self.logfile = None
@@ -84,13 +84,13 b' def compress_dhist(dh):'
84 84 newhead.append(h)
85 85 done.add(h)
86 86
87 return newhead + tail
87 return newhead + tail
88 88
89 89 def needs_local_scope(func):
90 90 """Decorator to mark magic functions which need to local scope to run."""
91 91 func.needs_local_scope = True
92 92 return func
93
93
94 94 # Used for exception handling in magic_edit
95 95 class MacroToEdit(ValueError): pass
96 96
@@ -101,7 +101,7 b' class MacroToEdit(ValueError): pass'
101 101 # on construction of the main InteractiveShell object. Something odd is going
102 102 # on with super() calls, Configurable and the MRO... For now leave it as-is, but
103 103 # eventually this needs to be clarified.
104 # BG: This is because InteractiveShell inherits from this, but is itself a
104 # BG: This is because InteractiveShell inherits from this, but is itself a
105 105 # Configurable. This messes up the MRO in some way. The fix is that we need to
106 106 # make Magic a configurable that InteractiveShell does not subclass.
107 107
@@ -124,7 +124,7 b' class Magic:'
124 124 # some utility functions
125 125
126 126 def __init__(self,shell):
127
127
128 128 self.options_table = {}
129 129 if profile is None:
130 130 self.magic_prun = self.profile_missing_notice
@@ -153,7 +153,7 b' python-profiler package from non-free.""")'
153 153 ['magic_ls','magic_cd',...]"""
154 154
155 155 # FIXME. This needs a cleanup, in the way the magics list is built.
156
156
157 157 # magics in class definition
158 158 class_magic = lambda fn: fn.startswith('magic_') and \
159 159 callable(Magic.__dict__[fn])
@@ -171,13 +171,13 b' python-profiler package from non-free.""")'
171 171 out.append(fn.replace('magic_','',1))
172 172 out.sort()
173 173 return out
174
174
175 175 def extract_input_lines(self, range_str, raw=False):
176 176 """Return as a string a set of input history slices.
177 177
178 178 Inputs:
179 179
180 - range_str: the set of slices is given as a string, like
180 - range_str: the set of slices is given as a string, like
181 181 "~5/6-~4/2 4:8 9", since this function is for use by magic functions
182 182 which get their arguments as strings. The number before the / is the
183 183 session number: ~n goes n back from the current session.
@@ -195,7 +195,7 b' python-profiler package from non-free.""")'
195 195 lines = self.shell.history_manager.\
196 196 get_range_by_str(range_str, raw=raw)
197 197 return "\n".join(x for _, _, x in lines)
198
198
199 199 def arg_err(self,func):
200 200 """Print docstring if incorrect arguments were passed"""
201 201 print 'Error in arguments:'
@@ -209,7 +209,7 b' python-profiler package from non-free.""")'
209 209 # Magic command names as headers:
210 210 cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC,
211 211 re.MULTILINE)
212 # Magic commands
212 # Magic commands
213 213 cmd_re = re.compile(r'(?P<cmd>%s.+?\b)(?!\}\}:)' % ESC_MAGIC,
214 214 re.MULTILINE)
215 215 # Paragraph continue
@@ -249,11 +249,11 b' python-profiler package from non-free.""")'
249 249 -posix (True): whether to split the input line in POSIX mode or not,
250 250 as per the conventions outlined in the shlex module from the
251 251 standard library."""
252
252
253 253 # inject default options at the beginning of the input line
254 254 caller = sys._getframe(1).f_code.co_name.replace('magic_','')
255 255 arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str)
256
256
257 257 mode = kw.get('mode','string')
258 258 if mode not in ['string','list']:
259 259 raise ValueError,'incorrect mode given: %s' % mode
@@ -272,7 +272,7 b' python-profiler package from non-free.""")'
272 272 try:
273 273 opts,args = getopt(argv,opt_str,*long_opts)
274 274 except GetoptError,e:
275 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
275 raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str,
276 276 " ".join(long_opts)))
277 277 for o,a in opts:
278 278 if o.startswith('--'):
@@ -295,7 +295,7 b' python-profiler package from non-free.""")'
295 295 args = ' '.join(args)
296 296
297 297 return opts,args
298
298
299 299 #......................................................................
300 300 # And now the actual magic functions
301 301
@@ -307,11 +307,11 b' python-profiler package from non-free.""")'
307 307 (' '+mesc).join(self.lsmagic())
308 308 print '\n' + Magic.auto_status[self.shell.automagic]
309 309 return None
310
310
311 311 def magic_magic(self, parameter_s = ''):
312 312 """Print information about the magic function system.
313
314 Supported formats: -latex, -brief, -rest
313
314 Supported formats: -latex, -brief, -rest
315 315 """
316 316
317 317 mode = ''
@@ -338,30 +338,30 b' python-profiler package from non-free.""")'
338 338 break
339 339 if mode == 'brief':
340 340 # only first line
341 if fn.__doc__:
341 if fn.__doc__:
342 342 fndoc = fn.__doc__.split('\n',1)[0]
343 343 else:
344 344 fndoc = 'No documentation'
345 345 else:
346 346 if fn.__doc__:
347 fndoc = fn.__doc__.rstrip()
347 fndoc = fn.__doc__.rstrip()
348 348 else:
349 349 fndoc = 'No documentation'
350
351
350
351
352 352 if mode == 'rest':
353 353 rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(ESC_MAGIC,
354 354 fname,fndoc))
355
355
356 356 else:
357 357 magic_docs.append('%s%s:\n\t%s\n' %(ESC_MAGIC,
358 358 fname,fndoc))
359
359
360 360 magic_docs = ''.join(magic_docs)
361 361
362 362 if mode == 'rest':
363 363 return "".join(rest_docs)
364
364
365 365 if mode == 'latex':
366 366 print self.format_latex(magic_docs)
367 367 return
@@ -369,7 +369,7 b' python-profiler package from non-free.""")'
369 369 magic_docs = format_screen(magic_docs)
370 370 if mode == 'brief':
371 371 return magic_docs
372
372
373 373 outmsg = """
374 374 IPython's 'magic' functions
375 375 ===========================
@@ -495,11 +495,11 b' Currently the magic system has the following functions:\\n"""'
495 495
496 496 def magic_page(self, parameter_s=''):
497 497 """Pretty print the object and display it through a pager.
498
498
499 499 %page [options] OBJECT
500 500
501 501 If no object is given, use _ (last output).
502
502
503 503 Options:
504 504
505 505 -r: page str(object), don't pretty-print it."""
@@ -524,12 +524,12 b' Currently the magic system has the following functions:\\n"""'
524 524
525 525 def magic_pinfo(self, parameter_s='', namespaces=None):
526 526 """Provide detailed information about an object.
527
527
528 528 '%pinfo object' is just a synonym for object? or ?object."""
529
529
530 530 #print 'pinfo par: <%s>' % parameter_s # dbg
531
532
531
532
533 533 # detail_level: 0 -> obj? , 1 -> obj??
534 534 detail_level = 0
535 535 # We need to detect if we got called as 'pinfo pinfo foo', which can
@@ -546,7 +546,7 b' Currently the magic system has the following functions:\\n"""'
546 546
547 547 def magic_pinfo2(self, parameter_s='', namespaces=None):
548 548 """Provide extra detailed information about an object.
549
549
550 550 '%pinfo2 object' is just a synonym for object?? or ??object."""
551 551 self.shell._inspect('pinfo', parameter_s, detail_level=1,
552 552 namespaces=namespaces)
@@ -556,11 +556,11 b' Currently the magic system has the following functions:\\n"""'
556 556 """Print the definition header for any callable object.
557 557
558 558 If the object is a class, print the constructor information.
559
559
560 560 Examples
561 561 --------
562 562 ::
563
563
564 564 In [3]: %pdef urllib.urlopen
565 565 urllib.urlopen(url, data=None, proxies=None)
566 566 """
@@ -615,7 +615,7 b' Currently the magic system has the following functions:\\n"""'
615 615 ?-i a* function
616 616
617 617 Arguments:
618
618
619 619 PATTERN
620 620
621 621 where PATTERN is a string containing * as a wildcard similar to its
@@ -642,8 +642,8 b' Currently the magic system has the following functions:\\n"""'
642 642
643 643 -i/-c: make the pattern case insensitive/sensitive. If neither of
644 644 these options are given, the default is read from your configuration
645 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
646 If this option is not specified in your configuration file, IPython's
645 file, with the option ``InteractiveShell.wildcards_case_sensitive``.
646 If this option is not specified in your configuration file, IPython's
647 647 internal default is to do a case sensitive search.
648 648
649 649 -e/-s NAMESPACE: exclude/search a given namespace. The pattern you
@@ -659,9 +659,9 b' Currently the magic system has the following functions:\\n"""'
659 659 and it contains module-level globals. You can add namespaces to the
660 660 search with -s or exclude them with -e (these options can be given
661 661 more than once).
662
662
663 663 Examples:
664
664
665 665 %psearch a* -> objects beginning with an a
666 666 %psearch -e builtin a* -> objects NOT in the builtin space starting in a
667 667 %psearch a* function -> all functions beginning with an a
@@ -670,11 +670,11 b' Currently the magic system has the following functions:\\n"""'
670 670 %psearch r*.* string -> all strings in modules beginning with r
671 671
672 672 Case sensitve search:
673
673
674 674 %psearch -c a* list all object beginning with lower case a
675 675
676 676 Show objects beginning with a single _:
677
677
678 678 %psearch -a _* list objects beginning with a single underscore"""
679 679 try:
680 680 parameter_s.encode('ascii')
@@ -703,14 +703,14 b' Currently the magic system has the following functions:\\n"""'
703 703 def_search.extend(opt('s',[]))
704 704 ns_exclude = ns_exclude=opt('e',[])
705 705 ns_search = [nm for nm in def_search if nm not in ns_exclude]
706
706
707 707 # Call the actual search
708 708 try:
709 709 psearch(args,shell.ns_table,ns_search,
710 710 show_all=opt('a'),ignore_case=ignore_case)
711 711 except:
712 712 shell.showtraceback()
713
713
714 714 @skip_doctest
715 715 def magic_who_ls(self, parameter_s=''):
716 716 """Return a sorted list of all interactive variables.
@@ -751,7 +751,7 b' Currently the magic system has the following functions:\\n"""'
751 751
752 752 out.sort()
753 753 return out
754
754
755 755 @skip_doctest
756 756 def magic_who(self, parameter_s=''):
757 757 """Print all interactive variables, with some minimal formatting.
@@ -820,7 +820,7 b' Currently the magic system has the following functions:\\n"""'
820 820 The same type filtering of %who can be applied here.
821 821
822 822 For all variables, the type is printed. Additionally it prints:
823
823
824 824 - For {},[],(): their length.
825 825
826 826 - For numpy arrays, a summary with shape, number of
@@ -844,7 +844,7 b' Currently the magic system has the following functions:\\n"""'
844 844 alpha int 123
845 845 beta str test
846 846 """
847
847
848 848 varnames = self.magic_who_ls(parameter_s)
849 849 if not varnames:
850 850 if parameter_s:
@@ -875,13 +875,13 b' Currently the magic system has the following functions:\\n"""'
875 875 # Find all variable names and types so we can figure out column sizes
876 876 def get_vars(i):
877 877 return self.shell.user_ns[i]
878
878
879 879 # some types are well known and can be shorter
880 880 abbrevs = {'IPython.core.macro.Macro' : 'Macro'}
881 881 def type_name(v):
882 882 tn = type(v).__name__
883 883 return abbrevs.get(tn,tn)
884
884
885 885 varlist = map(get_vars,varnames)
886 886
887 887 typelist = []
@@ -927,7 +927,7 b' Currently the magic system has the following functions:\\n"""'
927 927 vsize = Numeric.size(var)
928 928 vbytes = vsize*var.itemsize()
929 929 vdtype = var.typecode()
930
930
931 931 if vbytes < 100000:
932 932 print aformat % (vshape,vsize,vdtype,vbytes)
933 933 else:
@@ -947,19 +947,19 b' Currently the magic system has the following functions:\\n"""'
947 947 print vstr
948 948 else:
949 949 print vstr[:25] + "<...>" + vstr[-25:]
950
950
951 951 def magic_reset(self, parameter_s=''):
952 952 """Resets the namespace by removing all names defined by the user.
953 953
954 954 Parameters
955 955 ----------
956 956 -f : force reset without asking for confirmation.
957
957
958 958 -s : 'Soft' reset: Only clears your namespace, leaving history intact.
959 959 References to objects may be kept. By default (without this option),
960 960 we do a 'hard' reset, giving you a new session and removing all
961 961 references to objects from the current session.
962
962
963 963 Examples
964 964 --------
965 965 In [6]: a = 1
@@ -984,16 +984,16 b' Currently the magic system has the following functions:\\n"""'
984 984 if not ans:
985 985 print 'Nothing done.'
986 986 return
987
987
988 988 if 's' in opts: # Soft reset
989 989 user_ns = self.shell.user_ns
990 990 for i in self.magic_who_ls():
991 991 del(user_ns[i])
992
992
993 993 else: # Hard reset
994 994 self.shell.reset(new_session = False)
995
996
995
996
997 997
998 998 def magic_reset_selective(self, parameter_s=''):
999 999 """Resets the namespace by removing names defined by the user.
@@ -1003,7 +1003,7 b' Currently the magic system has the following functions:\\n"""'
1003 1003 %reset_selective [-f] regex
1004 1004
1005 1005 No action is taken if regex is not included
1006
1006
1007 1007 Options
1008 1008 -f : force reset without asking for confirmation.
1009 1009
@@ -1013,7 +1013,7 b' Currently the magic system has the following functions:\\n"""'
1013 1013 We first fully reset the namespace so your output looks identical to
1014 1014 this example for pedagogical reasons; in practice you do not need a
1015 1015 full reset.
1016
1016
1017 1017 In [1]: %reset -f
1018 1018
1019 1019 Now, with a clean namespace we can make a few variables and use
@@ -1044,9 +1044,9 b' Currently the magic system has the following functions:\\n"""'
1044 1044 In [11]: who_ls
1045 1045 Out[11]: ['a']
1046 1046 """
1047
1047
1048 1048 opts, regex = self.parse_options(parameter_s,'f')
1049
1049
1050 1050 if opts.has_key('f'):
1051 1051 ans = True
1052 1052 else:
@@ -1065,16 +1065,16 b' Currently the magic system has the following functions:\\n"""'
1065 1065 except TypeError:
1066 1066 raise TypeError('regex must be a string or compiled pattern')
1067 1067 for i in self.magic_who_ls():
1068 if m.search(i):
1068 if m.search(i):
1069 1069 del(user_ns[i])
1070
1070
1071 1071 def magic_xdel(self, parameter_s=''):
1072 1072 """Delete a variable, trying to clear it from anywhere that
1073 1073 IPython's machinery has references to it. By default, this uses
1074 1074 the identity of the named object in the user namespace to remove
1075 1075 references held under other names. The object is also removed
1076 1076 from the output history.
1077
1077
1078 1078 Options
1079 1079 -n : Delete the specified name from all namespaces, without
1080 1080 checking their identity.
@@ -1084,7 +1084,7 b' Currently the magic system has the following functions:\\n"""'
1084 1084 self.shell.del_var(varname, ('n' in opts))
1085 1085 except (NameError, ValueError) as e:
1086 1086 print type(e).__name__ +": "+ str(e)
1087
1087
1088 1088 def magic_logstart(self,parameter_s=''):
1089 1089 """Start logging anywhere in a session.
1090 1090
@@ -1125,7 +1125,7 b' Currently the magic system has the following functions:\\n"""'
1125 1125
1126 1126 -t: put timestamps before each input line logged (these are put in
1127 1127 comments)."""
1128
1128
1129 1129 opts,par = self.parse_options(parameter_s,'ort')
1130 1130 log_output = 'o' in opts
1131 1131 log_raw_input = 'r' in opts
@@ -1172,7 +1172,7 b' Currently the magic system has the following functions:\\n"""'
1172 1172 input_hist = self.shell.history_manager.input_hist_raw
1173 1173 else:
1174 1174 input_hist = self.shell.history_manager.input_hist_parsed
1175
1175
1176 1176 if log_output:
1177 1177 log_write = logger.log_write
1178 1178 output_hist = self.shell.history_manager.output_hist
@@ -1186,7 +1186,7 b' Currently the magic system has the following functions:\\n"""'
1186 1186 if timestamp:
1187 1187 # re-enable timestamping
1188 1188 logger.timestamp = True
1189
1189
1190 1190 print ('Activating auto-logging. '
1191 1191 'Current session state plus future input saved.')
1192 1192 logger.logstate()
@@ -1204,7 +1204,7 b' Currently the magic system has the following functions:\\n"""'
1204 1204
1205 1205 You must have previously started logging."""
1206 1206 self.shell.logger.switch_log(0)
1207
1207
1208 1208 def magic_logon(self,parameter_s=''):
1209 1209 """Restart logging.
1210 1210
@@ -1212,14 +1212,14 b' Currently the magic system has the following functions:\\n"""'
1212 1212 stopped with %logoff. For starting logging for the first time, you
1213 1213 must use the %logstart function, which allows you to specify an
1214 1214 optional log filename."""
1215
1215
1216 1216 self.shell.logger.switch_log(1)
1217
1217
1218 1218 def magic_logstate(self,parameter_s=''):
1219 1219 """Print the status of the logging system."""
1220 1220
1221 1221 self.shell.logger.logstate()
1222
1222
1223 1223 def magic_pdb(self, parameter_s=''):
1224 1224 """Control the automatic calling of the pdb interactive debugger.
1225 1225
@@ -1314,7 +1314,7 b' Currently the magic system has the following functions:\\n"""'
1314 1314 When more than one key is provided, additional keys are used as
1315 1315 secondary criteria when the there is equality in all keys selected
1316 1316 before them.
1317
1317
1318 1318 Abbreviations can be used for any key names, as long as the
1319 1319 abbreviation is unambiguous. The following are the keys currently
1320 1320 defined:
@@ -1353,16 +1353,16 b' Currently the magic system has the following functions:\\n"""'
1353 1353 If you want to run complete programs under the profiler's control, use
1354 1354 '%run -p [prof_opts] filename.py [args to program]' where prof_opts
1355 1355 contains profiler specific options as described here.
1356
1356
1357 1357 You can read the complete documentation for the profile module with::
1358
1358
1359 1359 In [1]: import profile; profile.help()
1360 1360 """
1361 1361
1362 1362 opts_def = Struct(D=[''],l=[],s=['time'],T=[''])
1363 1363 # protect user quote marks
1364 1364 parameter_s = parameter_s.replace('"',r'\"').replace("'",r"\'")
1365
1365
1366 1366 if user_mode: # regular user call
1367 1367 opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:',
1368 1368 list_all=1)
@@ -1382,7 +1382,7 b' Currently the magic system has the following functions:\\n"""'
1382 1382 namespace = locals()
1383 1383
1384 1384 opts.merge(opts_def)
1385
1385
1386 1386 prof = profile.Profile()
1387 1387 try:
1388 1388 prof = prof.runctx(arg_str,namespace,namespace)
@@ -1403,7 +1403,7 b' Currently the magic system has the following functions:\\n"""'
1403 1403 lims.append(float(lim))
1404 1404 except ValueError:
1405 1405 lims.append(lim)
1406
1406
1407 1407 # Trap output.
1408 1408 stdout_trap = StringIO()
1409 1409
@@ -1420,7 +1420,7 b' Currently the magic system has the following functions:\\n"""'
1420 1420 stats.print_stats(*lims)
1421 1421 finally:
1422 1422 sys.stdout = sys_stdout
1423
1423
1424 1424 output = stdout_trap.getvalue()
1425 1425 output = output.rstrip()
1426 1426
@@ -1454,7 +1454,7 b' Currently the magic system has the following functions:\\n"""'
1454 1454
1455 1455 Usage:\\
1456 1456 %run [-n -i -t [-N<N>] -d [-b<N>] -p [profile options]] file [args]
1457
1457
1458 1458 Parameters after the filename are passed as command-line arguments to
1459 1459 the program (put in sys.argv). Then, control returns to IPython's
1460 1460 prompt.
@@ -1475,7 +1475,7 b' Currently the magic system has the following functions:\\n"""'
1475 1475 interactive work, while giving each program a 'clean sheet' to run in.
1476 1476
1477 1477 Options:
1478
1478
1479 1479 -n: __name__ is NOT set to '__main__', but to the running file's name
1480 1480 without extension (as python does under import). This allows running
1481 1481 scripts and reloading the definitions in them without calling code
@@ -1520,7 +1520,7 b' Currently the magic system has the following functions:\\n"""'
1520 1520 -d: run your program under the control of pdb, the Python debugger.
1521 1521 This allows you to execute your program step by step, watch variables,
1522 1522 etc. Internally, what IPython does is similar to calling:
1523
1523
1524 1524 pdb.run('execfile("YOURFILENAME")')
1525 1525
1526 1526 with a breakpoint set on line 1 of your file. You can change the line
@@ -1580,10 +1580,10 b' Currently the magic system has the following functions:\\n"""'
1580 1580 if filename.lower().endswith('.ipy'):
1581 1581 self.shell.safe_execfile_ipy(filename)
1582 1582 return
1583
1583
1584 1584 # Control the response to exit() calls made by the script being run
1585 1585 exit_ignore = opts.has_key('e')
1586
1586
1587 1587 # Make sure that the running script gets a proper sys.argv as if it
1588 1588 # were run from a system shell.
1589 1589 save_argv = sys.argv # save it for later restoring
@@ -1626,7 +1626,7 b' Currently the magic system has the following functions:\\n"""'
1626 1626 # This needs to be undone at the end to prevent holding references to
1627 1627 # every single object ever created.
1628 1628 sys.modules[main_mod_name] = main_mod
1629
1629
1630 1630 try:
1631 1631 stats = None
1632 1632 with self.readline_no_record:
@@ -1663,7 +1663,7 b' Currently the magic system has the following functions:\\n"""'
1663 1663 print "%s prompt to start your script." % deb.prompt
1664 1664 try:
1665 1665 deb.run('execfile("%s")' % filename,prog_ns)
1666
1666
1667 1667 except:
1668 1668 etype, value, tb = sys.exc_info()
1669 1669 # Skip three frames in the traceback: the %run one,
@@ -1739,7 +1739,7 b' Currently the magic system has the following functions:\\n"""'
1739 1739 # we can do is to at least restore __builtins__ for the user on
1740 1740 # exit.
1741 1741 self.shell.user_ns['__builtins__'] = builtin_mod
1742
1742
1743 1743 # Ensure key global structures are restored
1744 1744 sys.argv = save_argv
1745 1745 if restore_main:
@@ -1749,7 +1749,7 b' Currently the magic system has the following functions:\\n"""'
1749 1749 # added. Otherwise it will trap references to objects
1750 1750 # contained therein.
1751 1751 del sys.modules[main_mod_name]
1752
1752
1753 1753 return stats
1754 1754
1755 1755 @skip_doctest
@@ -1764,14 +1764,14 b' Currently the magic system has the following functions:\\n"""'
1764 1764
1765 1765 Options:
1766 1766 -n<N>: execute the given statement <N> times in a loop. If this value
1767 is not given, a fitting value is chosen.
1768
1767 is not given, a fitting value is chosen.
1768
1769 1769 -r<R>: repeat the loop iteration <R> times and take the best result.
1770 1770 Default: 3
1771
1771
1772 1772 -t: use time.time to measure the time, which is the default on Unix.
1773 1773 This function measures wall time.
1774
1774
1775 1775 -c: use time.clock to measure the time, which is the default on
1776 1776 Windows and measures wall time. On Unix, resource.getrusage is used
1777 1777 instead and returns the CPU user time.
@@ -1779,7 +1779,7 b' Currently the magic system has the following functions:\\n"""'
1779 1779 -p<P>: use a precision of <P> digits to display the timing result.
1780 1780 Default: 3
1781 1781
1782
1782
1783 1783 Examples:
1784 1784
1785 1785 In [1]: %timeit pass
@@ -1797,7 +1797,7 b' Currently the magic system has the following functions:\\n"""'
1797 1797
1798 1798 In [6]: %timeit -n1 time.sleep(2)
1799 1799 1 loops, best of 3: 2 s per loop
1800
1800
1801 1801
1802 1802 The times reported by %timeit will be slightly higher than those
1803 1803 reported by the timeit.py script when variables are accessed. This is
@@ -1828,10 +1828,10 b' Currently the magic system has the following functions:\\n"""'
1828 1828 # succeeds
1829 1829 #
1830 1830 # See bug: https://bugs.launchpad.net/ipython/+bug/348466
1831
1831
1832 1832 #units = [u"s", u"ms",u'\xb5',"ns"]
1833 1833 units = [u"s", u"ms",u'us',"ns"]
1834
1834
1835 1835 scaling = [1, 1e3, 1e6, 1e9]
1836 1836
1837 1837 opts, stmt = self.parse_options(parameter_s,'n:r:tcp:',
@@ -1857,15 +1857,15 b' Currently the magic system has the following functions:\\n"""'
1857 1857 # Track compilation time so it can be reported if too long
1858 1858 # Minimum time above which compilation time will be reported
1859 1859 tc_min = 0.1
1860
1860
1861 1861 t0 = clock()
1862 1862 code = compile(src, "<magic-timeit>", "exec")
1863 1863 tc = clock()-t0
1864
1864
1865 1865 ns = {}
1866 1866 exec code in self.shell.user_ns, ns
1867 1867 timer.inner = ns["inner"]
1868
1868
1869 1869 if number == 0:
1870 1870 # determine number so that 0.2 <= total time < 2.0
1871 1871 number = 1
@@ -1873,7 +1873,7 b' Currently the magic system has the following functions:\\n"""'
1873 1873 if timer.timeit(number) >= 0.2:
1874 1874 break
1875 1875 number *= 10
1876
1876
1877 1877 best = min(timer.repeat(repeat, number)) / number
1878 1878
1879 1879 if best > 0.0 and best < 1000.0:
@@ -1901,7 +1901,7 b' Currently the magic system has the following functions:\\n"""'
1901 1901 This function provides very basic timing functionality. In Python
1902 1902 2.3, the timeit module offers more control and sophistication, so this
1903 1903 could be rewritten to use it (patches welcome).
1904
1904
1905 1905 Some examples:
1906 1906
1907 1907 In [1]: time 2**128
@@ -1936,14 +1936,14 b' Currently the magic system has the following functions:\\n"""'
1936 1936 Wall time: 0.00 s
1937 1937 Compiler : 0.78 s
1938 1938 """
1939
1939
1940 1940 # fail immediately if the given expression can't be compiled
1941
1941
1942 1942 expr = self.shell.prefilter(parameter_s,False)
1943 1943
1944 1944 # Minimum time above which compilation time will be reported
1945 1945 tc_min = 0.1
1946
1946
1947 1947 try:
1948 1948 mode = 'eval'
1949 1949 t0 = clock()
@@ -1992,7 +1992,7 b' Currently the magic system has the following functions:\\n"""'
1992 1992 %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ...
1993 1993
1994 1994 Options:
1995
1995
1996 1996 -r: use 'raw' input. By default, the 'processed' history is used,
1997 1997 so that magics are loaded in their transformed version to valid
1998 1998 Python. If this option is given, the raw input as typed as the
@@ -2011,7 +2011,7 b' Currently the magic system has the following functions:\\n"""'
2011 2011 notation, where N:M means numbers N through M-1.
2012 2012
2013 2013 For example, if your history contains (%hist prints it):
2014
2014
2015 2015 44: x=1
2016 2016 45: y=3
2017 2017 46: z=x+y
@@ -2036,9 +2036,9 b' Currently the magic system has the following functions:\\n"""'
2036 2036 code instead of printing them when you type their name.
2037 2037
2038 2038 You can view a macro's contents by explicitly printing it with:
2039
2039
2040 2040 'print macro_name'.
2041
2041
2042 2042 """
2043 2043 opts,args = self.parse_options(parameter_s,'r',mode='list')
2044 2044 if not args: # List existing macros
@@ -2048,7 +2048,7 b' Currently the magic system has the following functions:\\n"""'
2048 2048 raise UsageError(
2049 2049 "%macro insufficient args; usage '%macro name n1-n2 n3-4...")
2050 2050 name, codefrom = args[0], " ".join(args[1:])
2051
2051
2052 2052 #print 'rng',ranges # dbg
2053 2053 try:
2054 2054 lines = self.shell.find_user_code(codefrom, 'r' in opts)
@@ -2068,13 +2068,13 b' Currently the magic system has the following functions:\\n"""'
2068 2068 %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ...
2069 2069
2070 2070 Options:
2071
2071
2072 2072 -r: use 'raw' input. By default, the 'processed' history is used,
2073 2073 so that magics are loaded in their transformed version to valid
2074 2074 Python. If this option is given, the raw input as typed as the
2075 2075 command line is used instead.
2076 2076
2077 This function uses the same syntax as %history for input ranges,
2077 This function uses the same syntax as %history for input ranges,
2078 2078 then saves the lines to the filename you specify.
2079 2079
2080 2080 It adds a '.py' extension to the file if you don't do so yourself, and
@@ -2099,7 +2099,7 b' Currently the magic system has the following functions:\\n"""'
2099 2099 f.write(py3compat.cast_unicode(cmds))
2100 2100 print 'The following commands were written to file `%s`:' % fname
2101 2101 print cmds
2102
2102
2103 2103 def magic_pastebin(self, parameter_s = ''):
2104 2104 """Upload code to the 'Lodge it' paste bin, returning the URL."""
2105 2105 try:
@@ -2110,7 +2110,7 b' Currently the magic system has the following functions:\\n"""'
2110 2110 pbserver = ServerProxy('http://paste.pocoo.org/xmlrpc/')
2111 2111 id = pbserver.pastes.newPaste("python", code)
2112 2112 return "http://paste.pocoo.org/show/" + id
2113
2113
2114 2114 def magic_loadpy(self, arg_s):
2115 2115 """Load a .py python script into the GUI console.
2116 2116
@@ -2130,10 +2130,10 b' Currently the magic system has the following functions:\\n"""'
2130 2130 with open(arg_s) as f:
2131 2131 content = f.read()
2132 2132 self.set_next_input(content)
2133
2133
2134 2134 def _find_edit_target(self, args, opts, last_call):
2135 2135 """Utility method used by magic_edit to find what to edit."""
2136
2136
2137 2137 def make_filename(arg):
2138 2138 "Make a filename from the given args"
2139 2139 arg = unquote_filename(arg)
@@ -2141,20 +2141,20 b' Currently the magic system has the following functions:\\n"""'
2141 2141 filename = get_py_filename(arg)
2142 2142 except IOError:
2143 2143 # If it ends with .py but doesn't already exist, assume we want
2144 # a new file.
2144 # a new file.
2145 2145 if arg.endswith('.py'):
2146 2146 filename = arg
2147 2147 else:
2148 2148 filename = None
2149 2149 return filename
2150
2150
2151 2151 # Set a few locals from the options for convenience:
2152 2152 opts_prev = 'p' in opts
2153 2153 opts_raw = 'r' in opts
2154 2154
2155 2155 # custom exceptions
2156 2156 class DataIsObject(Exception): pass
2157
2157
2158 2158 # Default line number value
2159 2159 lineno = opts.get('n',None)
2160 2160
@@ -2162,7 +2162,7 b' Currently the magic system has the following functions:\\n"""'
2162 2162 args = '_%s' % last_call[0]
2163 2163 if not self.shell.user_ns.has_key(args):
2164 2164 args = last_call[1]
2165
2165
2166 2166 # use last_call to remember the state of the previous call, but don't
2167 2167 # let it be clobbered by successive '-p' calls.
2168 2168 try:
@@ -2177,7 +2177,7 b' Currently the magic system has the following functions:\\n"""'
2177 2177 use_temp = True
2178 2178
2179 2179 data = ''
2180
2180
2181 2181 # First, see if the arguments should be a filename.
2182 2182 filename = make_filename(args)
2183 2183 if filename:
@@ -2203,16 +2203,16 b' Currently the magic system has the following functions:\\n"""'
2203 2203 "or as a filename." % args)
2204 2204 return
2205 2205 use_temp = False
2206
2206
2207 2207 except DataIsObject:
2208 2208 # macros have a special edit function
2209 2209 if isinstance(data, Macro):
2210 2210 raise MacroToEdit(data)
2211
2211
2212 2212 # For objects, try to edit the file where they are defined
2213 2213 try:
2214 2214 filename = inspect.getabsfile(data)
2215 if 'fakemodule' in filename.lower() and inspect.isclass(data):
2215 if 'fakemodule' in filename.lower() and inspect.isclass(data):
2216 2216 # class created by %edit? Try to find source
2217 2217 # by looking for method definitions instead, the
2218 2218 # __module__ in those classes is FakeModule.
@@ -2223,9 +2223,9 b' Currently the magic system has the following functions:\\n"""'
2223 2223 filename = inspect.getabsfile(attr)
2224 2224 if filename and 'fakemodule' not in filename.lower():
2225 2225 # change the attribute to be the edit target instead
2226 data = attr
2226 data = attr
2227 2227 break
2228
2228
2229 2229 datafile = 1
2230 2230 except TypeError:
2231 2231 filename = make_filename(args)
@@ -2249,7 +2249,7 b' Currently the magic system has the following functions:\\n"""'
2249 2249 if use_temp:
2250 2250 filename = self.shell.mktempfile(data)
2251 2251 print 'IPython will make a temporary file named:',filename
2252
2252
2253 2253 return filename, lineno, use_temp
2254 2254
2255 2255 def _edit_macro(self,mname,macro):
@@ -2266,7 +2266,7 b' Currently the magic system has the following functions:\\n"""'
2266 2266 def magic_ed(self,parameter_s=''):
2267 2267 """Alias to %edit."""
2268 2268 return self.magic_edit(parameter_s)
2269
2269
2270 2270 @skip_doctest
2271 2271 def magic_edit(self,parameter_s='',last_call=['','']):
2272 2272 """Bring up an editor and execute the resulting code.
@@ -2280,15 +2280,15 b' Currently the magic system has the following functions:\\n"""'
2280 2280 notepad under Windows. See the end of this docstring for how to change
2281 2281 the editor hook.
2282 2282
2283 You can also set the value of this editor via the
2284 ``TerminalInteractiveShell.editor`` option in your configuration file.
2285 This is useful if you wish to use a different editor from your typical
2286 default with IPython (and for Windows users who typically don't set
2283 You can also set the value of this editor via the
2284 ``TerminalInteractiveShell.editor`` option in your configuration file.
2285 This is useful if you wish to use a different editor from your typical
2286 default with IPython (and for Windows users who typically don't set
2287 2287 environment variables).
2288 2288
2289 2289 This command allows you to conveniently edit multi-line code right in
2290 2290 your IPython session.
2291
2291
2292 2292 If called without arguments, %edit opens up an empty editor with a
2293 2293 temporary file and will execute the contents of this file when you
2294 2294 close it (don't forget to save it!).
@@ -2301,7 +2301,7 b' Currently the magic system has the following functions:\\n"""'
2301 2301 you can configure this by providing your own modified hook if your
2302 2302 favorite editor supports line-number specifications with a different
2303 2303 syntax.
2304
2304
2305 2305 -p: this will call the editor with the same data as the previous time
2306 2306 it was used, regardless of how long ago (in your current session) it
2307 2307 was.
@@ -2312,7 +2312,7 b' Currently the magic system has the following functions:\\n"""'
2312 2312 this option is given, the raw input as typed as the command line is
2313 2313 used instead. When you exit the editor, it will be executed by
2314 2314 IPython's own processor.
2315
2315
2316 2316 -x: do not execute the edited code immediately upon exit. This is
2317 2317 mainly useful if you are editing programs which need to be called with
2318 2318 command line arguments, which you can then do using %run.
@@ -2321,7 +2321,7 b' Currently the magic system has the following functions:\\n"""'
2321 2321 Arguments:
2322 2322
2323 2323 If arguments are given, the following possibilites exist:
2324
2324
2325 2325 - If the argument is a filename, IPython will load that into the
2326 2326 editor. It will execute its contents with execfile() when you exit,
2327 2327 loading any code in the file into your interactive namespace.
@@ -2364,18 +2364,18 b' Currently the magic system has the following functions:\\n"""'
2364 2364 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
2365 2365
2366 2366 We can then call the function foo():
2367
2367
2368 2368 In [2]: foo()
2369 2369 foo() was defined in an editing session
2370 2370
2371 2371 Now we edit foo. IPython automatically loads the editor with the
2372 2372 (temporary) file where foo() was previously defined:
2373
2373
2374 2374 In [3]: ed foo
2375 2375 Editing... done. Executing edited code...
2376 2376
2377 2377 And if we call foo() again we get the modified version:
2378
2378
2379 2379 In [4]: foo()
2380 2380 foo() has now been changed!
2381 2381
@@ -2411,7 +2411,7 b' Currently the magic system has the following functions:\\n"""'
2411 2411 general instructions on how to set a new hook for use once you've
2412 2412 defined it."""
2413 2413 opts,args = self.parse_options(parameter_s,'prxn:')
2414
2414
2415 2415 try:
2416 2416 filename, lineno, is_temp = self._find_edit_target(args, opts, last_call)
2417 2417 except MacroToEdit as e:
@@ -2429,12 +2429,12 b' Currently the magic system has the following functions:\\n"""'
2429 2429 except TryNext:
2430 2430 warn('Could not open editor')
2431 2431 return
2432
2432
2433 2433 # XXX TODO: should this be generalized for all string vars?
2434 2434 # For now, this is special-cased to blocks created by cpaste
2435 2435 if args.strip() == 'pasted_block':
2436 2436 self.shell.user_ns['pasted_block'] = file_read(filename)
2437
2437
2438 2438 if 'x' in opts: # -x prevents actual execution
2439 2439 print
2440 2440 else:
@@ -2445,7 +2445,7 b' Currently the magic system has the following functions:\\n"""'
2445 2445 else:
2446 2446 self.shell.safe_execfile(filename,self.shell.user_ns,
2447 2447 self.shell.user_ns)
2448
2448
2449 2449 if is_temp:
2450 2450 try:
2451 2451 return open(filename).read()
@@ -2481,19 +2481,19 b' Currently the magic system has the following functions:\\n"""'
2481 2481 Currently implemented schemes: NoColor, Linux, LightBG.
2482 2482
2483 2483 Color scheme names are not case-sensitive.
2484
2484
2485 2485 Examples
2486 2486 --------
2487 2487 To get a plain black and white terminal::
2488
2488
2489 2489 %colors nocolor
2490 2490 """
2491 2491
2492 2492 def color_switch_err(name):
2493 2493 warn('Error changing %s color schemes.\n%s' %
2494 2494 (name,sys.exc_info()[1]))
2495
2496
2495
2496
2497 2497 new_scheme = parameter_s.strip()
2498 2498 if not new_scheme:
2499 2499 raise UsageError(
@@ -2517,11 +2517,11 b' http://starship.python.net/crew/theller/ctypes'
2517 2517 Defaulting color scheme to 'NoColor'"""
2518 2518 new_scheme = 'NoColor'
2519 2519 warn(msg)
2520
2520
2521 2521 # readline option is 0
2522 2522 if not shell.colors_force and not shell.has_readline:
2523 2523 new_scheme = 'NoColor'
2524
2524
2525 2525 # Set prompt colors
2526 2526 try:
2527 2527 shell.displayhook.set_colors(new_scheme)
@@ -2545,7 +2545,7 b' Defaulting color scheme to \'NoColor\'"""'
2545 2545 color_switch_err('object inspector')
2546 2546 else:
2547 2547 shell.inspector.set_active_scheme('NoColor')
2548
2548
2549 2549 def magic_pprint(self, parameter_s=''):
2550 2550 """Toggle pretty printing on/off."""
2551 2551 ptformatter = self.shell.display_formatter.formatters['text/plain']
@@ -2578,7 +2578,7 b' Defaulting color scheme to \'NoColor\'"""'
2578 2578
2579 2579 You can also define aliases with parameters using %s specifiers (one
2580 2580 per parameter):
2581
2581
2582 2582 In [1]: alias parts echo first %s second %s
2583 2583 In [2]: %parts A B
2584 2584 first A second B
@@ -2589,7 +2589,7 b' Defaulting color scheme to \'NoColor\'"""'
2589 2589 Note that %l and %s are mutually exclusive. You can only use one or
2590 2590 the other in your aliases.
2591 2591
2592 Aliases expand Python variables just like system calls using ! or !!
2592 Aliases expand Python variables just like system calls using ! or !!
2593 2593 do: all expressions prefixed with '$' get expanded. For details of
2594 2594 the semantic rules, see PEP-215:
2595 2595 http://www.python.org/peps/pep-0215.html. This is the library used by
@@ -2619,7 +2619,7 b' Defaulting color scheme to \'NoColor\'"""'
2619 2619 print "Total number of aliases:", len(aliases)
2620 2620 sys.stdout.flush()
2621 2621 return aliases
2622
2622
2623 2623 # Now try to define a new one
2624 2624 try:
2625 2625 alias,cmd = par.split(None, 1)
@@ -2649,7 +2649,7 b' Defaulting color scheme to \'NoColor\'"""'
2649 2649 Under Windows, it checks executability as a match agains a
2650 2650 '|'-separated string of extensions, stored in the IPython config
2651 2651 variable win_exec_ext. This defaults to 'exe|com|bat'.
2652
2652
2653 2653 This function also resets the root module cache of module completer,
2654 2654 used on slow filesystems.
2655 2655 """
@@ -2657,8 +2657,8 b' Defaulting color scheme to \'NoColor\'"""'
2657 2657
2658 2658 # for the benefit of module completer in ipy_completers.py
2659 2659 del self.db['rootmodules']
2660
2661 path = [os.path.abspath(os.path.expanduser(p)) for p in
2660
2661 path = [os.path.abspath(os.path.expanduser(p)) for p in
2662 2662 os.environ.get('PATH','').split(os.pathsep)]
2663 2663 path = filter(os.path.isdir,path)
2664 2664
@@ -2717,20 +2717,20 b' Defaulting color scheme to \'NoColor\'"""'
2717 2717 db['syscmdlist'] = syscmdlist
2718 2718 finally:
2719 2719 os.chdir(savedir)
2720
2721 @skip_doctest
2720
2721 @skip_doctest
2722 2722 def magic_pwd(self, parameter_s = ''):
2723 2723 """Return the current working directory path.
2724
2724
2725 2725 Examples
2726 2726 --------
2727 2727 ::
2728
2728
2729 2729 In [9]: pwd
2730 2730 Out[9]: '/home/tsuser/sprint/ipython'
2731 2731 """
2732 2732 return os.getcwdu()
2733
2733
2734 2734 @skip_doctest
2735 2735 def magic_cd(self, parameter_s=''):
2736 2736 """Change the current working directory.
@@ -2749,25 +2749,25 b' Defaulting color scheme to \'NoColor\'"""'
2749 2749 cd -<n>: changes to the n-th directory in the directory history.
2750 2750
2751 2751 cd --foo: change to directory that matches 'foo' in history
2752
2752
2753 2753 cd -b <bookmark_name>: jump to a bookmark set by %bookmark
2754 2754 (note: cd <bookmark_name> is enough if there is no
2755 2755 directory <bookmark_name>, but a bookmark with the name exists.)
2756 'cd -b <tab>' allows you to tab-complete bookmark names.
2756 'cd -b <tab>' allows you to tab-complete bookmark names.
2757 2757
2758 2758 Options:
2759 2759
2760 2760 -q: quiet. Do not print the working directory after the cd command is
2761 2761 executed. By default IPython's cd command does print this directory,
2762 2762 since the default prompts do not display path information.
2763
2763
2764 2764 Note that !cd doesn't work for this purpose because the shell where
2765 2765 !command runs is immediately discarded after executing 'command'.
2766
2766
2767 2767 Examples
2768 2768 --------
2769 2769 ::
2770
2770
2771 2771 In [10]: cd parent/child
2772 2772 /home/tsuser/parent/child
2773 2773 """
@@ -2797,25 +2797,25 b' Defaulting color scheme to \'NoColor\'"""'
2797 2797 if pat in os.path.basename(ent) and os.path.isdir(ent):
2798 2798 ps = ent
2799 2799 break
2800
2800
2801 2801 if fallback is None and pat in ent and os.path.isdir(ent):
2802 2802 fallback = ent
2803
2803
2804 2804 # if we have no last part match, pick the first full path match
2805 2805 if ps is None:
2806 2806 ps = fallback
2807
2807
2808 2808 if ps is None:
2809 2809 print "No matching entry in directory history"
2810 2810 return
2811 2811 else:
2812 2812 opts = {}
2813
2814
2813
2814
2815 2815 else:
2816 #turn all non-space-escaping backslashes to slashes,
2816 #turn all non-space-escaping backslashes to slashes,
2817 2817 # for c:\windows\directory\names\
2818 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
2818 parameter_s = re.sub(r'\\(?! )','/', parameter_s)
2819 2819 opts,ps = self.parse_options(parameter_s,'qb',mode='string')
2820 2820 # jump to previous
2821 2821 if ps == '-':
@@ -2827,7 +2827,7 b' Defaulting color scheme to \'NoColor\'"""'
2827 2827 else:
2828 2828 if not os.path.isdir(ps) or opts.has_key('b'):
2829 2829 bkms = self.db.get('bookmarks', {})
2830
2830
2831 2831 if bkms.has_key(ps):
2832 2832 target = bkms[ps]
2833 2833 print '(bookmark:%s) -> %s' % (ps,target)
@@ -2853,14 +2853,14 b' Defaulting color scheme to \'NoColor\'"""'
2853 2853 if oldcwd != cwd:
2854 2854 dhist.append(cwd)
2855 2855 self.db['dhist'] = compress_dhist(dhist)[-100:]
2856
2856
2857 2857 else:
2858 2858 os.chdir(self.shell.home_dir)
2859 2859 if hasattr(self.shell, 'term_title') and self.shell.term_title:
2860 2860 set_term_title('IPython: ' + '~')
2861 2861 cwd = os.getcwdu()
2862 2862 dhist = self.shell.user_ns['_dh']
2863
2863
2864 2864 if oldcwd != cwd:
2865 2865 dhist.append(cwd)
2866 2866 self.db['dhist'] = compress_dhist(dhist)[-100:]
@@ -2870,16 +2870,16 b' Defaulting color scheme to \'NoColor\'"""'
2870 2870
2871 2871 def magic_env(self, parameter_s=''):
2872 2872 """List environment variables."""
2873
2873
2874 2874 return os.environ.data
2875 2875
2876 2876 def magic_pushd(self, parameter_s=''):
2877 2877 """Place the current dir on stack and change directory.
2878
2878
2879 2879 Usage:\\
2880 2880 %pushd ['dirname']
2881 2881 """
2882
2882
2883 2883 dir_s = self.shell.dir_stack
2884 2884 tgt = os.path.expanduser(unquote_filename(parameter_s))
2885 2885 cwd = os.getcwdu().replace(self.home_dir,'~')
@@ -2912,10 +2912,10 b' Defaulting color scheme to \'NoColor\'"""'
2912 2912 This history is automatically maintained by the %cd command, and
2913 2913 always available as the global list variable _dh. You can use %cd -<n>
2914 2914 to go to directory number <n>.
2915
2915
2916 2916 Note that most of time, you should view directory history by entering
2917 2917 cd -<TAB>.
2918
2918
2919 2919 """
2920 2920
2921 2921 dh = self.shell.user_ns['_dh']
@@ -2943,13 +2943,13 b' Defaulting color scheme to \'NoColor\'"""'
2943 2943 """Shell capture - execute a shell command and capture its output.
2944 2944
2945 2945 DEPRECATED. Suboptimal, retained for backwards compatibility.
2946
2946
2947 2947 You should use the form 'var = !command' instead. Example:
2948
2948
2949 2949 "%sc -l myfiles = ls ~" should now be written as
2950
2950
2951 2951 "myfiles = !ls ~"
2952
2952
2953 2953 myfiles.s, myfiles.l and myfiles.n still apply as documented
2954 2954 below.
2955 2955
@@ -2963,7 +2963,7 b' Defaulting color scheme to \'NoColor\'"""'
2963 2963
2964 2964 The '=' sign in the syntax is mandatory, and the variable name you
2965 2965 supply must follow Python's standard conventions for valid names.
2966
2966
2967 2967 (A special format without variable name exists for internal use)
2968 2968
2969 2969 Options:
@@ -2983,7 +2983,7 b' Defaulting color scheme to \'NoColor\'"""'
2983 2983 For example:
2984 2984
2985 2985 # all-random
2986
2986
2987 2987 # Capture into variable a
2988 2988 In [1]: sc a=ls *py
2989 2989
@@ -3074,7 +3074,7 b' Defaulting color scheme to \'NoColor\'"""'
3074 3074 !!ls
3075 3075 is a shorthand equivalent to:
3076 3076 %sx ls
3077
3077
3078 3078 2) %sx differs from %sc in that %sx automatically splits into a list,
3079 3079 like '%sc -l'. The reason for this is to make it as easy as possible
3080 3080 to process line-oriented shell output via further python commands.
@@ -3093,7 +3093,7 b' Defaulting color scheme to \'NoColor\'"""'
3093 3093 if parameter_s:
3094 3094 return self.shell.getoutput(parameter_s)
3095 3095
3096
3096
3097 3097 def magic_bookmark(self, parameter_s=''):
3098 3098 """Manage IPython's bookmark system.
3099 3099
@@ -3116,7 +3116,7 b' Defaulting color scheme to \'NoColor\'"""'
3116 3116 raise UsageError("%bookmark: too many arguments")
3117 3117
3118 3118 bkms = self.db.get('bookmarks',{})
3119
3119
3120 3120 if opts.has_key('d'):
3121 3121 try:
3122 3122 todel = args[0]
@@ -3157,7 +3157,7 b' Defaulting color scheme to \'NoColor\'"""'
3157 3157
3158 3158 This magic is similar to the cat utility, but it will assume the file
3159 3159 to be Python source and will show it with syntax highlighting. """
3160
3160
3161 3161 try:
3162 3162 filename = get_py_filename(parameter_s)
3163 3163 cont = file_read(filename)
@@ -3205,13 +3205,13 b' Defaulting color scheme to \'NoColor\'"""'
3205 3205 ]
3206 3206
3207 3207 strip_from_start = map(re.compile,strip_re)
3208
3208
3209 3209 lines = []
3210 3210 for l in raw_lines:
3211 for pat in strip_from_start:
3211 for pat in strip_from_start:
3212 3212 l = pat.sub('',l)
3213 3213 lines.append(l)
3214
3214
3215 3215 block = "\n".join(lines) + '\n'
3216 3216 #print "block:\n",block
3217 3217 return block
@@ -3231,7 +3231,7 b' Defaulting color scheme to \'NoColor\'"""'
3231 3231 """ Show a quick reference sheet """
3232 3232 import IPython.core.usage
3233 3233 qr = IPython.core.usage.quick_reference + self.magic_magic('-brief')
3234
3234
3235 3235 page.page(qr)
3236 3236
3237 3237 def magic_doctest_mode(self,parameter_s=''):
@@ -3298,7 +3298,7 b' Defaulting color scheme to \'NoColor\'"""'
3298 3298
3299 3299 ptformatter.pprint = False
3300 3300 disp_formatter.plain_text_only = True
3301
3301
3302 3302 shell.magic_xmode('Plain')
3303 3303 else:
3304 3304 # turn off
@@ -3385,7 +3385,7 b' Defaulting color scheme to \'NoColor\'"""'
3385 3385 name = src.replace('profile_', '')
3386 3386 print " %s"%name
3387 3387 pd = ProfileDir.create_profile_dir_by_name(ipython_dir, name)
3388 pd.copy_config_file('ipython_config.py', path=src,
3388 pd.copy_config_file('ipython_config.py', path=src,
3389 3389 overwrite=overwrite)
3390 3390
3391 3391 @skip_doctest
@@ -3452,16 +3452,16 b' Defaulting color scheme to \'NoColor\'"""'
3452 3452 Backend in use: Qt4Agg
3453 3453 For more information, type 'help(pylab)'.
3454 3454 """
3455
3455
3456 3456 if Application.initialized():
3457 3457 app = Application.instance()
3458 3458 try:
3459 3459 import_all_status = app.pylab_import_all
3460 3460 except AttributeError:
3461 import_all_status = True
3461 import_all_status = True
3462 3462 else:
3463 3463 import_all_status = True
3464
3464
3465 3465 self.shell.enable_pylab(s,import_all=import_all_status)
3466 3466
3467 3467 def magic_tb(self, s):
@@ -3469,50 +3469,50 b' Defaulting color scheme to \'NoColor\'"""'
3469 3469
3470 3470 See %xmode for changing exception reporting modes."""
3471 3471 self.shell.showtraceback()
3472
3472
3473 3473 @skip_doctest
3474 3474 def magic_precision(self, s=''):
3475 3475 """Set floating point precision for pretty printing.
3476
3476
3477 3477 Can set either integer precision or a format string.
3478
3478
3479 3479 If numpy has been imported and precision is an int,
3480 3480 numpy display precision will also be set, via ``numpy.set_printoptions``.
3481
3481
3482 3482 If no argument is given, defaults will be restored.
3483
3483
3484 3484 Examples
3485 3485 --------
3486 3486 ::
3487
3487
3488 3488 In [1]: from math import pi
3489
3489
3490 3490 In [2]: %precision 3
3491 3491 Out[2]: u'%.3f'
3492
3492
3493 3493 In [3]: pi
3494 3494 Out[3]: 3.142
3495
3495
3496 3496 In [4]: %precision %i
3497 3497 Out[4]: u'%i'
3498
3498
3499 3499 In [5]: pi
3500 3500 Out[5]: 3
3501
3501
3502 3502 In [6]: %precision %e
3503 3503 Out[6]: u'%e'
3504
3504
3505 3505 In [7]: pi**10
3506 3506 Out[7]: 9.364805e+04
3507
3507
3508 3508 In [8]: %precision
3509 3509 Out[8]: u'%r'
3510
3510
3511 3511 In [9]: pi**10
3512 3512 Out[9]: 93648.047476082982
3513
3513
3514 3514 """
3515
3515
3516 3516 ptformatter = self.shell.display_formatter.formatters['text/plain']
3517 3517 ptformatter.float_precision = s
3518 3518 return ptformatter.float_format
@@ -3583,6 +3583,6 b' Defaulting color scheme to \'NoColor\'"""'
3583 3583 nb = current.reads(s, u'xml')
3584 3584 with open(new_fname, 'w') as f:
3585 3585 current.write(nb, f, new_format)
3586
3586
3587 3587
3588 3588 # end Magic
@@ -197,7 +197,7 b' def call_tip(oinfo, format_call=True):'
197 197 When format_call is True, the whole call information is formattted as a
198 198 single string. Otherwise, the object's name and its argspec dict are
199 199 returned. If no call information is available, None is returned.
200
200
201 201 docstring : str or None
202 202 The most relevant docstring for calling purposes is returned, if
203 203 available. The priority is: call docstring for callable instances, then
@@ -219,7 +219,7 b' def call_tip(oinfo, format_call=True):'
219 219 else:
220 220 if has_self:
221 221 argspec['args'] = argspec['args'][1:]
222
222
223 223 call_line = oinfo['name']+format_argspec(argspec)
224 224
225 225 # Now get docstring.
@@ -249,14 +249,14 b' class Inspector:'
249 249
250 250 If any exception is generated, None is returned instead and the
251 251 exception is suppressed."""
252
252
253 253 try:
254 254 # We need a plain string here, NOT unicode!
255 255 hdef = oname + inspect.formatargspec(*getargspec(obj))
256 256 return py3compat.unicode_to_str(hdef, 'ascii')
257 257 except:
258 258 return None
259
259
260 260 def __head(self,h):
261 261 """Return a header string with proper colors."""
262 262 return '%s%s%s' % (self.color_table.active_colors.header,h,
@@ -265,7 +265,7 b' class Inspector:'
265 265 def set_active_scheme(self,scheme):
266 266 self.color_table.set_active_scheme(scheme)
267 267 self.parser.color_table.set_active_scheme(scheme)
268
268
269 269 def noinfo(self,msg,oname):
270 270 """Generic message when no information is found."""
271 271 print 'No %s found' % msg,
@@ -273,7 +273,7 b' class Inspector:'
273 273 print 'for %s' % oname
274 274 else:
275 275 print
276
276
277 277 def pdef(self,obj,oname=''):
278 278 """Print the definition header for any callable object.
279 279
@@ -303,30 +303,30 b' class Inspector:'
303 303 Optional:
304 304 -formatter: a function to run the docstring through for specially
305 305 formatted docstrings.
306
306
307 307 Examples
308 308 --------
309
309
310 310 In [1]: class NoInit:
311 311 ...: pass
312
312
313 313 In [2]: class NoDoc:
314 314 ...: def __init__(self):
315 315 ...: pass
316
316
317 317 In [3]: %pdoc NoDoc
318 318 No documentation found for NoDoc
319
319
320 320 In [4]: %pdoc NoInit
321 321 No documentation found for NoInit
322 322
323 323 In [5]: obj = NoInit()
324
324
325 325 In [6]: %pdoc obj
326 326 No documentation found for obj
327 327
328 328 In [5]: obj2 = NoDoc()
329
329
330 330 In [6]: %pdoc obj2
331 331 No documentation found for obj2
332 332 """
@@ -355,14 +355,14 b' class Inspector:'
355 355 self.noinfo('documentation',oname)
356 356 else:
357 357 page.page('\n'.join(lines))
358
358
359 359 def psource(self,obj,oname=''):
360 360 """Print the source code for an object."""
361 361
362 362 # Flush the source cache because inspect can return out-of-date source
363 363 linecache.checkcache()
364 364 try:
365 src = getsource(obj)
365 src = getsource(obj)
366 366 except:
367 367 self.noinfo('source',oname)
368 368 else:
@@ -385,7 +385,7 b' class Inspector:'
385 385 return
386 386
387 387 # We only reach this point if object was successfully queried
388
388
389 389 # run contents of file through pager starting at line
390 390 # where the object is defined
391 391 ofile = inspect.getabsfile(obj)
@@ -399,10 +399,10 b' class Inspector:'
399 399 # getsourcelines returns lineno with 1-offset and page() uses
400 400 # 0-offset, so we must adjust.
401 401 page.page(self.format(open(ofile).read()),lineno-1)
402
402
403 403 def _format_fields(self, fields, title_width=12):
404 404 """Formats a list of fields for display.
405
405
406 406 Parameters
407 407 ----------
408 408 fields : list
@@ -428,17 +428,17 b' class Inspector:'
428 428 ("Length", "length"),
429 429 ("File", "file"),
430 430 ("Definition", "definition")]
431
431
432 432 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
433 433 ("Constructor Docstring","init_docstring"),
434 434 ("Call def", "call_def"),
435 435 ("Call docstring", "call_docstring")]
436
436
437 437 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
438 438 """Show detailed information about an object.
439 439
440 440 Optional arguments:
441
441
442 442 - oname: name of the variable pointing to the object.
443 443
444 444 - formatter: special formatter for docstrings (see pdoc)
@@ -455,14 +455,14 b' class Inspector:'
455 455 field = info[key]
456 456 if field is not None:
457 457 displayfields.append((title, field.rstrip()))
458
458
459 459 # Source or docstring, depending on detail level and whether
460 460 # source found.
461 461 if detail_level > 0 and info['source'] is not None:
462 462 displayfields.append(("Source", self.format(py3compat.unicode_to_str(info['source']))))
463 463 elif info['docstring'] is not None:
464 464 displayfields.append(("Docstring", info["docstring"]))
465
465
466 466 # Constructor info for classes
467 467 if info['isclass']:
468 468 if info['init_definition'] or info['init_docstring']:
@@ -473,14 +473,14 b' class Inspector:'
473 473 if info['init_docstring'] is not None:
474 474 displayfields.append((" Docstring",
475 475 indent(info['init_docstring'])))
476
476
477 477 # Info for objects:
478 478 else:
479 479 for title, key in self.pinfo_fields_obj:
480 480 field = info[key]
481 481 if field is not None:
482 482 displayfields.append((title, field.rstrip()))
483
483
484 484 # Finally send to printer/pager:
485 485 if displayfields:
486 486 page.page(self._format_fields(displayfields))
@@ -489,7 +489,7 b' class Inspector:'
489 489 """Compute a dict with detailed information about an object.
490 490
491 491 Optional arguments:
492
492
493 493 - oname: name of the variable pointing to the object.
494 494
495 495 - formatter: special formatter for docstrings (see pdoc)
@@ -532,7 +532,7 b' class Inspector:'
532 532
533 533 # store output in a dict, we initialize it here and fill it as we go
534 534 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
535
535
536 536 string_max = 200 # max size of strings to show (snipped if longer)
537 537 shalf = int((string_max -5)/2)
538 538
@@ -599,7 +599,7 b' class Inspector:'
599 599 # avoid repetitions). If source fails, we add them back, see below.
600 600 if ds and detail_level == 0:
601 601 out['docstring'] = ds
602
602
603 603 # Original source code for any callable
604 604 if detail_level:
605 605 # Flush the source cache because inspect can return out-of-date
@@ -616,10 +616,10 b' class Inspector:'
616 616 out['source'] = source.rstrip()
617 617 except Exception:
618 618 pass
619
619
620 620 if ds and source is None:
621 621 out['docstring'] = ds
622
622
623 623
624 624 # Constructor docstring for classes
625 625 if inspect.isclass(obj):
@@ -692,7 +692,7 b' class Inspector:'
692 692 # Compute the object's argspec as a callable. The key is to decide
693 693 # whether to pull it from the object itself, from its __init__ or
694 694 # from its __call__ method.
695
695
696 696 if inspect.isclass(obj):
697 697 # Old-style classes need not have an __init__
698 698 callable_obj = getattr(obj, "__init__", None)
@@ -727,7 +727,7 b' class Inspector:'
727 727 - ns_table: dict of name->namespaces for search.
728 728
729 729 Optional arguments:
730
730
731 731 - ns_search: list of namespace names to include in search.
732 732
733 733 - ignore_case(False): make the search case-insensitive.
@@ -736,7 +736,7 b' class Inspector:'
736 736 underscores.
737 737 """
738 738 #print 'ps pattern:<%r>' % pattern # dbg
739
739
740 740 # defaults
741 741 type_pattern = 'all'
742 742 filter = ''
@@ -100,7 +100,7 b' class PrefilterManager(Configurable):'
100 100 """Main prefilter component.
101 101
102 102 The IPython prefilter is run on all user input before it is run. The
103 prefilter consumes lines of input and produces transformed lines of
103 prefilter consumes lines of input and produces transformed lines of
104 104 input.
105 105
106 106 The iplementation consists of two phases:
@@ -119,12 +119,12 b' class PrefilterManager(Configurable):'
119 119
120 120 After all the transformers have been run, the line is fed to the checkers,
121 121 which are instances of :class:`PrefilterChecker`. The line is passed to
122 the :meth:`check` method, which either returns `None` or a
122 the :meth:`check` method, which either returns `None` or a
123 123 :class:`PrefilterHandler` instance. If `None` is returned, the other
124 124 checkers are tried. If an :class:`PrefilterHandler` instance is returned,
125 125 the line is passed to the :meth:`handle` method of the returned
126 126 handler and no further checkers are tried.
127
127
128 128 Both transformers and checkers have a `priority` attribute, that determines
129 129 the order in which they are called. Smaller priorities are tried first.
130 130
@@ -317,7 +317,7 b' class PrefilterManager(Configurable):'
317 317
318 318 # Now we compute line_info for the checkers and handlers
319 319 line_info = LineInfo(line, continue_prompt)
320
320
321 321 # the input history needs to track even empty lines
322 322 stripped = line.strip()
323 323
@@ -358,7 +358,7 b' class PrefilterManager(Configurable):'
358 358 for lnum, line in enumerate(llines) ])
359 359 else:
360 360 out = self.prefilter_line(llines[0], continue_prompt)
361
361
362 362 return out
363 363
364 364 #-----------------------------------------------------------------------------
@@ -522,9 +522,9 b' class ShellEscapeChecker(PrefilterChecker):'
522 522
523 523
524 524 class MacroChecker(PrefilterChecker):
525
525
526 526 priority = Int(250, config=True)
527
527
528 528 def check(self, line_info):
529 529 obj = self.shell.user_ns.get(line_info.ifun)
530 530 if isinstance(obj, Macro):
@@ -555,7 +555,7 b' class MultiLineMagicChecker(PrefilterChecker):'
555 555 "Allow ! and !! in multi-line statements if multi_line_specials is on"
556 556 # Note that this one of the only places we check the first character of
557 557 # ifun and *not* the pre_char. Also note that the below test matches
558 # both ! and !!.
558 # both ! and !!.
559 559 if line_info.continue_prompt \
560 560 and self.prefilter_manager.multi_line_specials:
561 561 if line_info.esc == ESC_MAGIC:
@@ -591,7 +591,7 b' class AssignmentChecker(PrefilterChecker):'
591 591 def check(self, line_info):
592 592 """Check to see if user is assigning to a var for the first time, in
593 593 which case we want to avoid any sort of automagic / autocall games.
594
594
595 595 This allows users to assign to either alias or magic names true python
596 596 variables (the magic/alias systems always take second seat to true
597 597 python code). E.g. ls='hi', or ls,that=1,2"""
@@ -669,7 +669,7 b' class AutocallChecker(PrefilterChecker):'
669 669 oinfo = line_info.ofind(self.shell) # This can mutate state via getattr
670 670 if not oinfo['found']:
671 671 return None
672
672
673 673 if callable(oinfo['obj']) \
674 674 and (not re_exclude_auto.match(line_info.the_rest)) \
675 675 and re_fun_name.match(line_info.ifun):
@@ -735,7 +735,7 b' class AliasHandler(PrefilterHandler):'
735 735 # aliases won't work in indented sections.
736 736 line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace,
737 737 make_quoted_expr(transformed))
738
738
739 739 return line_out
740 740
741 741
@@ -769,7 +769,7 b' class ShellEscapeHandler(PrefilterHandler):'
769 769
770 770 class MacroHandler(PrefilterHandler):
771 771 handler_name = Unicode("macro")
772
772
773 773 def handle(self, line_info):
774 774 obj = self.shell.user_ns.get(line_info.ifun)
775 775 pre_space = line_info.pre_whitespace
@@ -813,7 +813,7 b' class AutoHandler(PrefilterHandler):'
813 813
814 814 force_auto = isinstance(obj, IPyAutocall)
815 815 auto_rewrite = getattr(obj, 'rewrite', True)
816
816
817 817 if esc == ESC_QUOTE:
818 818 # Auto-quote splitting on whitespace
819 819 newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) )
@@ -848,7 +848,7 b' class AutoHandler(PrefilterHandler):'
848 848
849 849 if auto_rewrite:
850 850 self.shell.auto_rewrite_input(newcmd)
851
851
852 852 return newcmd
853 853
854 854
@@ -107,7 +107,7 b' class ProfileList(Application):'
107 107 )
108 108 ))
109 109
110 ipython_dir = Unicode(get_ipython_dir(), config=True,
110 ipython_dir = Unicode(get_ipython_dir(), config=True,
111 111 help="""
112 112 The name of the IPython directory. This directory is used for logging
113 113 configuration (through profiles), history storage, etc. The default
@@ -115,7 +115,7 b' class ProfileList(Application):'
115 115 the environment variable IPYTHON_DIR.
116 116 """
117 117 )
118
118
119 119 def list_profile_dirs(self):
120 120 # Find the search paths
121 121 paths = [os.getcwdu(), self.ipython_dir]
@@ -129,7 +129,7 b' class ProfileList(Application):'
129 129 profile = f.split('_',1)[-1]
130 130 start_cmd = 'ipython profile=%s' % profile
131 131 print start_cmd + " ==> " + full_path
132
132
133 133 def start(self):
134 134 self.list_profile_dirs()
135 135
@@ -150,15 +150,15 b' class ProfileCreate(BaseIPythonApplication):'
150 150 description = create_help
151 151 examples = _create_examples
152 152 auto_create = Bool(True, config=False)
153
153
154 154 def _copy_config_files_default(self):
155 155 return True
156
156
157 157 parallel = Bool(False, config=True,
158 158 help="whether to include parallel computing config files")
159 159 def _parallel_changed(self, name, old, new):
160 parallel_files = [ 'ipcontroller_config.py',
161 'ipengine_config.py',
160 parallel_files = [ 'ipcontroller_config.py',
161 'ipengine_config.py',
162 162 'ipcluster_config.py'
163 163 ]
164 164 if new:
@@ -168,17 +168,17 b' class ProfileCreate(BaseIPythonApplication):'
168 168 for cf in parallel_files:
169 169 if cf in self.config_files:
170 170 self.config_files.remove(cf)
171
171
172 172 def parse_command_line(self, argv):
173 173 super(ProfileCreate, self).parse_command_line(argv)
174 174 # accept positional arg as profile name
175 175 if self.extra_args:
176 176 self.profile = self.extra_args[0]
177
177
178 178 flags = Dict(create_flags)
179
179
180 180 classes = [ProfileDir]
181
181
182 182 def init_config_files(self):
183 183 super(ProfileCreate, self).init_config_files()
184 184 # use local imports, since these classes may import from here
@@ -223,7 +223,7 b' class ProfileCreate(BaseIPythonApplication):'
223 223 app.profile = self.profile
224 224 app.init_profile_dir()
225 225 app.init_config_files()
226
226
227 227 def stage_default_config_file(self):
228 228 pass
229 229
@@ -237,7 +237,7 b' class ProfileApp(Application):'
237 237 create = (ProfileCreate, "Create a new profile dir with default config files"),
238 238 list = (ProfileList, "List existing profiles")
239 239 ))
240
240
241 241 def start(self):
242 242 if self.subapp is None:
243 243 print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys())
@@ -42,7 +42,7 b' PromptColors.add_scheme(coloransi.ColorScheme('
42 42 in_number = InputColors.NoColor, # Input prompt number
43 43 in_prompt2 = InputColors.NoColor, # Continuation prompt
44 44 in_normal = InputColors.NoColor, # color off (usu. Colors.Normal)
45
45
46 46 out_prompt = Colors.NoColor, # Output prompt
47 47 out_number = Colors.NoColor, # Output prompt number
48 48
@@ -255,7 +255,7 b' class BasePrompt(object):'
255 255 # by all prompt classes through the cache. Nice OO spaghetti code!
256 256 self.cache = cache
257 257 self.sep = sep
258
258
259 259 # regexp to count the number of spaces at the end of a prompt
260 260 # expression, useful for prompt auto-rewriting
261 261 self.rspace = re.compile(r'(\s*)$')
@@ -281,7 +281,7 b' class BasePrompt(object):'
281 281 ('${self.sep}${self.col_p}',
282 282 multiple_replace(prompt_specials, self.p_template),
283 283 '${self.col_norm}'),self.cache.shell.user_ns,loc)
284
284
285 285 self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor,
286 286 self.p_template),
287 287 self.cache.shell.user_ns,loc)
@@ -369,8 +369,8 b' class Prompt1(BasePrompt):'
369 369 self.col_norm = Colors.in_normal
370 370 # We need a non-input version of these escapes for the '--->'
371 371 # auto-call prompts used in the auto_rewrite() method.
372 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
373 self.col_norm_ni = Colors.normal
372 self.col_p_ni = self.col_p.replace('\001','').replace('\002','')
373 self.col_norm_ni = Colors.normal
374 374
375 375 def __str__(self):
376 376 self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1]
@@ -405,7 +405,7 b' class PromptOut(BasePrompt):'
405 405
406 406 class Prompt2(BasePrompt):
407 407 """Interactive continuation prompt."""
408
408
409 409 def __init__(self, cache, prompt=' .\\D.: ', pad_left=True):
410 410 self.cache = cache
411 411 self.p_template = prompt
@@ -73,13 +73,13 b' The enhanced interactive Python shells have the following main features:'
73 73
74 74 * Easily embeddable in other Python programs and wxPython GUIs.
75 75
76 * Integrated access to the pdb debugger and the Python profiler.
76 * Integrated access to the pdb debugger and the Python profiler.
77 77
78 78 The parallel computing architecture has the following main features:
79 79
80 80 * Quickly parallelize Python code from an interactive Python/IPython session.
81 81
82 * A flexible and dynamic process model that be deployed on anything from
82 * A flexible and dynamic process model that be deployed on anything from
83 83 multicore workstations to supercomputers.
84 84
85 85 * An architecture that supports many different styles of parallelism, from
@@ -90,7 +90,7 b' The parallel computing architecture has the following main features:'
90 90 * High level APIs that enable many things to be parallelized in a few lines
91 91 of code.
92 92
93 * Share live parallel jobs with other users securely.
93 * Share live parallel jobs with other users securely.
94 94
95 95 * Dynamically load balanced task farming system.
96 96
@@ -37,7 +37,7 b' from IPython.utils import py3compat'
37 37
38 38 # Although it's not solely driven by the regex, note that:
39 39 # ,;/% only trigger if they are the first character on the line
40 # ! and !! trigger if they are first char(s) *or* follow an indent
40 # ! and !! trigger if they are first char(s) *or* follow an indent
41 41 # ? triggers as first or last char.
42 42
43 43 line_split = re.compile("""
@@ -54,7 +54,7 b' def split_user_input(line, pattern=None):'
54 54 """
55 55 # We need to ensure that the rest of this routine deals only with unicode
56 56 line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8')
57
57
58 58 if pattern is None:
59 59 pattern = line_split
60 60 match = pattern.match(line)
@@ -77,29 +77,29 b' def split_user_input(line, pattern=None):'
77 77 class LineInfo(object):
78 78 """A single line of input and associated info.
79 79
80 Includes the following as properties:
80 Includes the following as properties:
81 81
82 82 line
83 83 The original, raw line
84
84
85 85 continue_prompt
86 86 Is this line a continuation in a sequence of multiline input?
87
87
88 88 pre
89 89 Any leading whitespace.
90
90
91 91 esc
92 92 The escape character(s) in pre or the empty string if there isn't one.
93 93 Note that '!!' and '??' are possible values for esc. Otherwise it will
94 94 always be a single character.
95
95
96 96 ifun
97 97 The 'function part', which is basically the maximal initial sequence
98 98 of valid python identifiers and the '.' character. This is what is
99 99 checked for alias and magic transformations, used for auto-calling,
100 100 etc. In contrast to Python identifiers, it may start with "%" and contain
101 101 "*".
102
102
103 103 the_rest
104 104 Everything else on the line.
105 105 """
@@ -111,7 +111,7 b' class LineInfo(object):'
111 111 self.pre_char = self.pre.strip()
112 112 if self.pre_char:
113 113 self.pre_whitespace = '' # No whitespace allowd before esc chars
114 else:
114 else:
115 115 self.pre_whitespace = self.pre
116 116
117 117 self._oinfo = None
@@ -134,5 +134,5 b' class LineInfo(object):'
134 134 self._oinfo = ip.shell._ofind(self.ifun)
135 135 return self._oinfo
136 136
137 def __str__(self):
138 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
137 def __str__(self):
138 return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest)
@@ -81,7 +81,7 b' def test_handlers():'
81 81 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
82 82
83 83 # post-esc-char whitespace goes inside
84 ("! true", 'get_ipython().system(u" true")'),
84 ("! true", 'get_ipython().system(u" true")'),
85 85
86 86 # handle_help
87 87
@@ -111,32 +111,32 b' def test_handlers():'
111 111 ('if 1:\n !!true', 'if 1:\n get_ipython().magic(u"sx true")'),
112 112
113 113 # Even with m_l_s on, autocall is off even with special chars
114 ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
114 ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'),
115 115 ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'),
116 116 ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'),
117 117 ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'),
118 # What about !!
118 # What about !!
119 119 ])
120 120
121 121 # Objects which are instances of IPyAutocall are *always* autocalled
122 122 autocallable = Autocallable()
123 123 ip.user_ns['autocallable'] = autocallable
124 124
125 # auto
125 # auto
126 126 ip.magic('autocall 0')
127 127 # Only explicit escapes or instances of IPyAutocallable should get
128 128 # expanded
129 129 run([
130 ('len "abc"', 'len "abc"'),
131 ('autocallable', 'autocallable()'),
130 ('len "abc"', 'len "abc"'),
131 ('autocallable', 'autocallable()'),
132 132 (",list 1 2 3", 'list("1", "2", "3")'),
133 (";list 1 2 3", 'list("1 2 3")'),
133 (";list 1 2 3", 'list("1 2 3")'),
134 134 ("/len range(1,4)", 'len(range(1,4))'),
135 135 ])
136 136 ip.magic('autocall 1')
137 137 run([
138 138 (",list 1 2 3", 'list("1", "2", "3")'),
139 (";list 1 2 3", 'list("1 2 3")'),
139 (";list 1 2 3", 'list("1 2 3")'),
140 140 ("/len range(1,4)", 'len(range(1,4))'),
141 141 ('len "abc"', 'len("abc")'),
142 142 ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens
@@ -150,11 +150,11 b' def test_handlers():'
150 150 ip.magic('autocall 2')
151 151 run([
152 152 (",list 1 2 3", 'list("1", "2", "3")'),
153 (";list 1 2 3", 'list("1 2 3")'),
153 (";list 1 2 3", 'list("1 2 3")'),
154 154 ("/len range(1,4)", 'len(range(1,4))'),
155 155 ('len "abc"', 'len("abc")'),
156 156 ('len "abc";', 'len("abc");'),
157 ('len [1,2]', 'len([1,2])'),
157 ('len [1,2]', 'len([1,2])'),
158 158 ('call_idx [1]', 'call_idx [1]'),
159 159 ('call_idx 1', 'call_idx(1)'),
160 160 # This is what's different:
@@ -31,18 +31,18 b' def test_history():'
31 31 hist = ['a=1', 'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"]
32 32 for i, h in enumerate(hist, start=1):
33 33 ip.history_manager.store_inputs(i, h)
34
34
35 35 ip.history_manager.db_log_output = True
36 36 # Doesn't match the input, but we'll just check it's stored.
37 37 ip.history_manager.output_hist_reprs[3] = "spam"
38 38 ip.history_manager.store_output(3)
39
39
40 40 nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist)
41
42 # Check whether specifying a range beyond the end of the current
41
42 # Check whether specifying a range beyond the end of the current
43 43 # session results in an error (gh-804)
44 44 ip.magic('%hist 2-500')
45
45
46 46 # New session
47 47 ip.history_manager.reset()
48 48 newcmds = ["z=5","class X(object):\n pass", "k='p'"]
@@ -53,7 +53,7 b' def test_history():'
53 53 # Previous session:
54 54 gothist = ip.history_manager.get_range(-1, 1, 4)
55 55 nt.assert_equal(list(gothist), zip([1,1,1],[1,2,3], hist))
56
56
57 57 # Check get_hist_tail
58 58 gothist = ip.history_manager.get_tail(4, output=True,
59 59 include_latest=True)
@@ -62,25 +62,25 b' def test_history():'
62 62 (2, 2, (newcmds[1], None)),
63 63 (2, 3, (newcmds[2], None)),]
64 64 nt.assert_equal(list(gothist), expected)
65
65
66 66 gothist = ip.history_manager.get_tail(2)
67 67 expected = [(2, 1, newcmds[0]),
68 68 (2, 2, newcmds[1])]
69 69 nt.assert_equal(list(gothist), expected)
70
70
71 71 # Check get_hist_search
72 72 gothist = ip.history_manager.search("*test*")
73 73 nt.assert_equal(list(gothist), [(1,2,hist[1])] )
74 74 gothist = ip.history_manager.search("b*", output=True)
75 75 nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] )
76
76
77 77 # Cross testing: check that magic %save can get previous session.
78 78 testfilename = os.path.realpath(os.path.join(tmpdir, "test.py"))
79 79 ip.magic_save(testfilename + " ~1/1-3")
80 80 testfile = open(testfilename, "r")
81 81 nt.assert_equal(testfile.read().decode("utf-8"),
82 82 "# coding: utf-8\n" + "\n".join(hist))
83
83
84 84 # Duplicate line numbers - check that it doesn't crash, and
85 85 # gets a new session
86 86 ip.history_manager.store_inputs(1, "rogue")
@@ -102,7 +102,7 b' def test_extract_hist_ranges():'
102 102 (-7, 1, 6)]
103 103 actual = list(extract_hist_ranges(instr))
104 104 nt.assert_equal(actual, expected)
105
105
106 106 def test_magic_rerun():
107 107 """Simple test for %rerun (no args -> rerun last line)"""
108 108 ip = get_ipython()
@@ -41,7 +41,7 b' def mini_interactive_loop(input_func):'
41 41 raw_input that simulates interactive input."""
42 42
43 43 from IPython.core.inputsplitter import InputSplitter
44
44
45 45 isp = InputSplitter()
46 46 # In practice, this input loop would be wrapped in an outside loop to read
47 47 # input indefinitely, until some exit/quit command was issued. Here we
@@ -106,7 +106,7 b' def test_remove_comments():'
106 106 'line \nline\nline\nline \n\n'),
107 107 ]
108 108 tt.check_pairs(isp.remove_comments, tests)
109
109
110 110 def test_has_comment():
111 111 tests = [('text', False),
112 112 ('text #comment', True),
@@ -134,13 +134,13 b' class NoInputEncodingTestCase(unittest.TestCase):'
134 134 class X: pass
135 135 fake_stdin = X()
136 136 sys.stdin = fake_stdin
137
137
138 138 def test(self):
139 139 # Verify that if sys.stdin has no 'encoding' attribute we do the right
140 140 # thing
141 141 enc = isp.get_input_encoding()
142 142 self.assertEqual(enc, 'ascii')
143
143
144 144 def tearDown(self):
145 145 sys.stdin = self.old_stdin
146 146
@@ -167,7 +167,7 b' class InputSplitterTestCase(unittest.TestCase):'
167 167 self.assertEqual(self.isp.source_reset(), '1\n2\n')
168 168 self.assertEqual(self.isp._buffer, [])
169 169 self.assertEqual(self.isp.source, '')
170
170
171 171 def test_indent(self):
172 172 isp = self.isp # shorthand
173 173 isp.push('x=1')
@@ -200,7 +200,7 b' class InputSplitterTestCase(unittest.TestCase):'
200 200 isp.push("if 1:")
201 201 isp.push(" x = (1+\n 2)")
202 202 self.assertEqual(isp.indent_spaces, 4)
203
203
204 204 def test_indent4(self):
205 205 # In cell mode, inputs must be fed in whole blocks, so skip this test
206 206 if self.isp.input_mode == 'cell': return
@@ -261,13 +261,13 b' class InputSplitterTestCase(unittest.TestCase):'
261 261 self.assertFalse(isp.push('if 1:'))
262 262 for line in [' x=1', '# a comment', ' y=2']:
263 263 self.assertTrue(isp.push(line))
264
264
265 265 def test_push3(self):
266 266 isp = self.isp
267 267 isp.push('if True:')
268 268 isp.push(' a = 1')
269 269 self.assertFalse(isp.push('b = [1,'))
270
270
271 271 def test_replace_mode(self):
272 272 isp = self.isp
273 273 isp.input_mode = 'cell'
@@ -292,7 +292,7 b' class InputSplitterTestCase(unittest.TestCase):'
292 292 self.assertTrue(isp.push_accepts_more())
293 293 isp.push('')
294 294 self.assertFalse(isp.push_accepts_more())
295
295
296 296 def test_push_accepts_more3(self):
297 297 isp = self.isp
298 298 isp.push("x = (2+\n3)")
@@ -318,7 +318,7 b' class InputSplitterTestCase(unittest.TestCase):'
318 318 self.assertTrue(isp.push_accepts_more())
319 319 isp.push('')
320 320 self.assertFalse(isp.push_accepts_more())
321
321
322 322 def test_push_accepts_more5(self):
323 323 # In cell mode, inputs must be fed in whole blocks, so skip this test
324 324 if self.isp.input_mode == 'cell': return
@@ -368,7 +368,7 b' class InteractiveLoopTestCase(unittest.TestCase):'
368 368 # we can check that the given dict is *contained* in test_ns
369 369 for k,v in ns.iteritems():
370 370 self.assertEqual(test_ns[k], v)
371
371
372 372 def test_simple(self):
373 373 self.check_ns(['x=1'], dict(x=1))
374 374
@@ -380,10 +380,10 b' class InteractiveLoopTestCase(unittest.TestCase):'
380 380
381 381 def test_abc(self):
382 382 self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3))
383
383
384 384 def test_multi(self):
385 385 self.check_ns(['x =(1+','1+','2)'], dict(x=4))
386
386
387 387
388 388 def test_LineInfo():
389 389 """Simple test for LineInfo construction and str()"""
@@ -453,7 +453,7 b' syntax = \\'
453 453 ('?%hist', 'get_ipython().magic(u"pinfo %hist")'),
454 454 ('?abc = qwe', 'get_ipython().magic(u"pinfo abc")'),
455 455 ],
456
456
457 457 end_help =
458 458 [ ('x3?', 'get_ipython().magic(u"pinfo x3")'),
459 459 ('x4??', 'get_ipython().magic(u"pinfo2 x4")'),
@@ -473,7 +473,7 b' syntax = \\'
473 473 ('%cd /home', 'get_ipython().magic(u"cd /home")'),
474 474 (' %magic', ' get_ipython().magic(u"magic")'),
475 475 ],
476
476
477 477 # Quoting with separate arguments
478 478 escaped_quote =
479 479 [ (',f', 'f("")'),
@@ -481,23 +481,23 b' syntax = \\'
481 481 (' ,f y', ' f("y")'),
482 482 (',f a b', 'f("a", "b")'),
483 483 ],
484
484
485 485 # Quoting with single argument
486 escaped_quote2 =
486 escaped_quote2 =
487 487 [ (';f', 'f("")'),
488 488 (';f x', 'f("x")'),
489 489 (' ;f y', ' f("y")'),
490 490 (';f a b', 'f("a b")'),
491 491 ],
492
492
493 493 # Simply apply parens
494 escaped_paren =
494 escaped_paren =
495 495 [ ('/f', 'f()'),
496 496 ('/f x', 'f(x)'),
497 497 (' /f y', ' f(y)'),
498 498 ('/f a b', 'f(a, b)'),
499 499 ],
500
500
501 501 # Check that we transform prompts before other transforms
502 502 mixed =
503 503 [ ('In [1]: %lsmagic', 'get_ipython().magic(u"lsmagic")'),
@@ -532,7 +532,7 b' syntax_ml = \\'
532 532 def test_assign_system():
533 533 tt.check_pairs(isp.transform_assign_system, syntax['assign_system'])
534 534
535
535
536 536 def test_assign_magic():
537 537 tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic'])
538 538
@@ -541,7 +541,7 b' def test_classic_prompt():'
541 541 transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt)
542 542 for example in syntax_ml['classic_prompt']:
543 543 transform_checker(example, isp.transform_classic_prompt)
544
544
545 545
546 546 def test_ipy_prompt():
547 547 transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt)
@@ -599,7 +599,7 b' class IPythonInputTestCase(InputSplitterTestCase):'
599 599 for raw, out_t in example:
600 600 if raw.startswith(' '):
601 601 continue
602
602
603 603 isp.push(raw)
604 604 out, out_raw = isp.source_raw_reset()
605 605 self.assertEqual(out.rstrip(), out_t,
@@ -622,13 +622,13 b' class IPythonInputTestCase(InputSplitterTestCase):'
622 622 raw = '\n'.join(raw_parts).rstrip()
623 623 self.assertEqual(out.rstrip(), out_t)
624 624 self.assertEqual(out_raw.rstrip(), raw)
625
625
626 626
627 627 class BlockIPythonInputTestCase(IPythonInputTestCase):
628 628
629 629 # Deactivate tests that don't make sense for the block mode
630 630 test_push3 = test_split = lambda s: None
631
631
632 632 def setUp(self):
633 633 self.isp = isp.IPythonInputSplitter(input_mode='cell')
634 634
@@ -650,7 +650,7 b' class BlockIPythonInputTestCase(IPythonInputTestCase):'
650 650 # Match ignoring trailing whitespace
651 651 self.assertEqual(out.rstrip(), out_t.rstrip())
652 652 self.assertEqual(out_raw.rstrip(), raw.rstrip())
653
653
654 654
655 655 #-----------------------------------------------------------------------------
656 656 # Main - use as a script, mostly for developer experiments
@@ -667,7 +667,7 b" if __name__ == '__main__':"
667 667
668 668 autoindent = True
669 669 #autoindent = False
670
670
671 671 try:
672 672 while True:
673 673 prompt = start_prompt
@@ -45,7 +45,7 b' class Call(object):'
45 45
46 46 def method(self, x, z=2):
47 47 """Some method's docstring"""
48
48
49 49 class OldStyle:
50 50 """An old-style class for testing."""
51 51 pass
@@ -62,7 +62,7 b' def check_calltip(obj, name, call, docstring):'
62 62 info = inspector.info(obj, name)
63 63 call_line, ds = oinspect.call_tip(info)
64 64 nt.assert_equal(call_line, call)
65 nt.assert_equal(ds, docstring)
65 nt.assert_equal(ds, docstring)
66 66
67 67 #-----------------------------------------------------------------------------
68 68 # Tests
@@ -92,7 +92,7 b' def test_calltip_function2():'
92 92
93 93 def test_calltip_builtin():
94 94 check_calltip(sum, 'sum', None, sum.__doc__)
95
95
96 96 def test_info():
97 97 "Check that Inspector.info fills out various fields as expected."
98 98 i = inspector.info(Call, oname='Call')
@@ -112,11 +112,11 b' def test_info():'
112 112 nt.assert_true(i['isclass'])
113 113 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
114 114 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
115
115
116 116 i = inspector.info(Call, detail_level=1)
117 117 nt.assert_not_equal(i['source'], None)
118 118 nt.assert_equal(i['docstring'], None)
119
119
120 120 c = Call(1)
121 121 c.__doc__ = "Modified instance docstring"
122 122 i = inspector.info(c)
@@ -125,12 +125,12 b' def test_info():'
125 125 nt.assert_equal(i['class_docstring'], Call.__doc__)
126 126 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
127 127 nt.assert_equal(i['call_docstring'], c.__call__.__doc__)
128
128
129 129 # Test old-style classes, which for example may not have an __init__ method.
130 130 if not py3compat.PY3:
131 131 i = inspector.info(OldStyle)
132 132 nt.assert_equal(i['type_name'], 'classobj')
133
133
134 134 i = inspector.info(OldStyle())
135 135 nt.assert_equal(i['type_name'], 'instance')
136 136 nt.assert_equal(i['docstring'], OldStyle.__doc__)
@@ -32,7 +32,7 b' def doctest_refbug():'
32 32
33 33 In [1]: _ip.clear_main_mod_cache()
34 34 # random
35
35
36 36 In [2]: %run refbug
37 37
38 38 In [3]: call_f()
@@ -81,7 +81,7 b' def doctest_run_builtins():'
81 81 ....: os.unlink(fname)
82 82 ....: except:
83 83 ....: pass
84 ....:
84 ....:
85 85 """
86 86
87 87 def doctest_reset_del():
@@ -90,7 +90,7 b' def doctest_reset_del():'
90 90 In [2]: class A(object):
91 91 ...: def __del__(self):
92 92 ...: print str("Hi")
93 ...:
93 ...:
94 94
95 95 In [3]: a = A()
96 96
@@ -127,7 +127,7 b' class TestMagicRunPass(tt.TempFileMixin):'
127 127
128 128 def test_builtins_type(self):
129 129 """Check that the type of __builtins__ doesn't change with %run.
130
130
131 131 However, the above could pass if __builtins__ was already modified to
132 132 be a dict (it should be a module) by a previous use of %run. So we
133 133 also check explicitly that it really is a module:
@@ -168,8 +168,8 b' class TestMagicRunSimple(tt.TempFileMixin):'
168 168 "a = A()\n")
169 169 self.mktmp(src)
170 170 tt.ipexec_validate(self.fname, 'object A deleted')
171
172 @dec.skip_known_failure
171
172 @dec.skip_known_failure
173 173 def test_aggressive_namespace_cleanup(self):
174 174 """Test that namespace cleanup is not too aggressive GH-238
175 175
@@ -12,7 +12,7 b' Installation instructions for ColorTB:'
12 12 import sys,ultratb
13 13 sys.excepthook = ultratb.ColorTB()
14 14
15 * VerboseTB
15 * VerboseTB
16 16 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
17 17 of useful info when a traceback occurs. Ping originally had it spit out HTML
18 18 and intended it for CGI programmers, but why should they have all the fun? I
@@ -34,7 +34,7 b' Note:'
34 34 Verbose_novars mode instead of the regular Verbose, which avoids formatting
35 35 variables (but otherwise includes the information and context given by
36 36 Verbose).
37
37
38 38
39 39 Installation instructions for ColorTB:
40 40 import sys,ultratb
@@ -121,7 +121,7 b' def inspect_error():'
121 121 """Print a message about internal inspect errors.
122 122
123 123 These are unfortunately quite common."""
124
124
125 125 error('Internal Python error in the inspect module.\n'
126 126 'Below is the traceback from this internal error.\n')
127 127
@@ -197,7 +197,7 b' def findsource(object):'
197 197 while lnum > 0:
198 198 if pmatch(lines[lnum]): break
199 199 lnum -= 1
200
200
201 201 return lines, lnum
202 202 raise IOError('could not find code object')
203 203
@@ -262,7 +262,7 b' def _fixed_getinnerframes(etb, context=1,tb_offset=0):'
262 262 # (SyntaxErrors have to be treated specially because they have no traceback)
263 263
264 264 _parser = PyColorize.Parser()
265
265
266 266 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):
267 267 numbers_width = INDENT_SIZE - 1
268 268 res = []
@@ -285,10 +285,10 b' def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):'
285 285 # is unicode-safe. So for now this is rather an ugly hack, but
286 286 # necessary to at least have readable tracebacks. Improvements welcome!
287 287 line = py3compat.cast_bytes_py2(line, 'utf-8')
288
288
289 289 new_line, err = _line_format(line, 'str', scheme)
290 290 if not err: line = new_line
291
291
292 292 if i == lnum:
293 293 # This is the line with the error
294 294 pad = numbers_width - len(str(i))
@@ -301,11 +301,11 b' def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None):'
301 301 else:
302 302 marker = ''
303 303 num = marker + str(i)
304 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
304 line = '%s%s%s %s%s' %(Colors.linenoEm, num,
305 305 Colors.line, line, Colors.Normal)
306 306 else:
307 307 num = '%*s' % (numbers_width,i)
308 line = '%s%s%s %s' %(Colors.lineno, num,
308 line = '%s%s%s %s' %(Colors.lineno, num,
309 309 Colors.Normal, line)
310 310
311 311 res.append(line)
@@ -352,7 +352,7 b' class TBTools(object):'
352 352 """Output stream that exceptions are written to.
353 353
354 354 Valid values are:
355
355
356 356 - None: the default, which means that IPython will dynamically resolve
357 357 to io.stdout. This ensures compatibility with most tools, including
358 358 Windows (where plain stdout doesn't recognize ANSI escapes).
@@ -364,7 +364,7 b' class TBTools(object):'
364 364 def _set_ostream(self, val):
365 365 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
366 366 self._ostream = val
367
367
368 368 ostream = property(_get_ostream, _set_ostream)
369 369
370 370 def set_colors(self,*args,**kw):
@@ -380,7 +380,7 b' class TBTools(object):'
380 380
381 381 def color_toggle(self):
382 382 """Toggle between the currently active color scheme and NoColor."""
383
383
384 384 if self.color_scheme_table.active_scheme_name == 'NoColor':
385 385 self.color_scheme_table.set_active_scheme(self.old_scheme)
386 386 self.Colors = self.color_scheme_table.active_colors
@@ -414,7 +414,7 b' class TBTools(object):'
414 414 #---------------------------------------------------------------------------
415 415 class ListTB(TBTools):
416 416 """Print traceback information from a traceback list, with optional color.
417
417
418 418 Calling: requires 3 arguments:
419 419 (etype, evalue, elist)
420 420 as would be obtained by:
@@ -434,7 +434,7 b' class ListTB(TBTools):'
434 434 def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None):
435 435 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
436 436 ostream=ostream)
437
437
438 438 def __call__(self, etype, value, elist):
439 439 self.ostream.flush()
440 440 self.ostream.write(self.text(etype, value, elist))
@@ -458,7 +458,7 b' class ListTB(TBTools):'
458 458 tb_offset : int, optional
459 459 Number of frames in the traceback to skip. If not given, the
460 460 instance value is used (set in constructor).
461
461
462 462 context : int, optional
463 463 Number of lines of context information to print.
464 464
@@ -473,7 +473,7 b' class ListTB(TBTools):'
473 473
474 474 if tb_offset and len(elist) > tb_offset:
475 475 elist = elist[tb_offset:]
476
476
477 477 out_list.append('Traceback %s(most recent call last)%s:' %
478 478 (Colors.normalEm, Colors.Normal) + '\n')
479 479 out_list.extend(self._format_list(elist))
@@ -482,7 +482,7 b' class ListTB(TBTools):'
482 482 out_list.append(lines)
483 483
484 484 # Note: this code originally read:
485
485
486 486 ## for line in lines[:-1]:
487 487 ## out_list.append(" "+line)
488 488 ## out_list.append(lines[-1])
@@ -490,7 +490,7 b' class ListTB(TBTools):'
490 490 # This means it was indenting everything but the last line by a little
491 491 # bit. I've disabled this for now, but if we see ugliness somewhre we
492 492 # can restore it.
493
493
494 494 return out_list
495 495
496 496 def _format_list(self, extracted_list):
@@ -502,7 +502,7 b' class ListTB(TBTools):'
502 502 same index in the argument list. Each string ends in a newline;
503 503 the strings may contain internal newlines as well, for those items
504 504 whose source text line is not None.
505
505
506 506 Lifted almost verbatim from traceback.py
507 507 """
508 508
@@ -510,7 +510,7 b' class ListTB(TBTools):'
510 510 list = []
511 511 for filename, lineno, name, line in extracted_list[:-1]:
512 512 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
513 (Colors.filename, filename, Colors.Normal,
513 (Colors.filename, filename, Colors.Normal,
514 514 Colors.lineno, lineno, Colors.Normal,
515 515 Colors.name, name, Colors.Normal)
516 516 if line:
@@ -530,7 +530,7 b' class ListTB(TBTools):'
530 530 list.append(item)
531 531 #from pprint import pformat; print 'LISTTB', pformat(list) # dbg
532 532 return list
533
533
534 534 def _format_exception_only(self, etype, value):
535 535 """Format the exception part of a traceback.
536 536
@@ -541,7 +541,7 b' class ListTB(TBTools):'
541 541 printed) display detailed information about where the syntax error
542 542 occurred. The message indicating which exception occurred is the
543 543 always last string in the list.
544
544
545 545 Also lifted nearly verbatim from traceback.py
546 546 """
547 547
@@ -573,7 +573,7 b' class ListTB(TBTools):'
573 573 while i < len(line) and line[i].isspace():
574 574 i = i+1
575 575 list.append('%s %s%s\n' % (Colors.line,
576 line.strip(),
576 line.strip(),
577 577 Colors.Normal))
578 578 if offset is not None:
579 579 s = ' '
@@ -602,7 +602,7 b' class ListTB(TBTools):'
602 602
603 603 def get_exception_only(self, etype, value):
604 604 """Only print the exception type and message, without a traceback.
605
605
606 606 Parameters
607 607 ----------
608 608 etype : exception type
@@ -613,7 +613,7 b' class ListTB(TBTools):'
613 613
614 614 def show_exception_only(self, etype, evalue):
615 615 """Only print the exception type and message, without a traceback.
616
616
617 617 Parameters
618 618 ----------
619 619 etype : exception type
@@ -725,7 +725,7 b' class VerboseTB(TBTools):'
725 725 # Header with the exception type, python version, and date
726 726 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
727 727 date = time.ctime(time.time())
728
728
729 729 head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal,
730 730 exc, ' '*(75-len(str(etype))-len(pyver)),
731 731 pyver, date.rjust(75) )
@@ -797,7 +797,7 b' class VerboseTB(TBTools):'
797 797 inspect_error()
798 798 traceback.print_exc(file=self.ostream)
799 799 info("\nIPython's exception reporting continues...\n")
800
800
801 801 if func == '?':
802 802 call = ''
803 803 else:
@@ -838,7 +838,7 b' class VerboseTB(TBTools):'
838 838 there is no way to disambguate partial dotted structures until
839 839 the full list is known. The caller is responsible for pruning
840 840 the final list of duplicates before using it."""
841
841
842 842 # build composite names
843 843 if token == '.':
844 844 try:
@@ -887,7 +887,7 b' class VerboseTB(TBTools):'
887 887 "The following traceback may be corrupted or invalid\n"
888 888 "The error message is: %s\n" % msg)
889 889 error(_m)
890
890
891 891 # prune names list of duplicates, but keep the right order
892 892 unique_names = uniq_stable(names)
893 893
@@ -965,11 +965,11 b' class VerboseTB(TBTools):'
965 965 if ipinst is not None:
966 966 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
967 967 # vds: <<
968
968
969 969 # return all our info assembled as a single string
970 970 # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) )
971 971 return [head] + frames + [''.join(exception[0])]
972
972
973 973 def debugger(self,force=False):
974 974 """Call up the pdb debugger if desired, always clean up the tb
975 975 reference.
@@ -1048,9 +1048,9 b' class FormattedTB(VerboseTB, ListTB):'
1048 1048 one needs to remove a number of topmost frames from the traceback (such as
1049 1049 occurs with python programs that themselves execute other python code,
1050 1050 like Python shells). """
1051
1051
1052 1052 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1053 ostream=None,
1053 ostream=None,
1054 1054 tb_offset=0, long_header=False, include_vars=False,
1055 1055 check_cache=None):
1056 1056
@@ -1068,7 +1068,7 b' class FormattedTB(VerboseTB, ListTB):'
1068 1068 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1069 1069 # set_mode also sets the tb_join_char attribute
1070 1070 self.set_mode(mode)
1071
1071
1072 1072 def _extract_tb(self,tb):
1073 1073 if tb:
1074 1074 return traceback.extract_tb(tb)
@@ -1096,7 +1096,7 b' class FormattedTB(VerboseTB, ListTB):'
1096 1096 def stb2text(self, stb):
1097 1097 """Convert a structured traceback (a list) to a string."""
1098 1098 return self.tb_join_char.join(stb)
1099
1099
1100 1100
1101 1101 def set_mode(self,mode=None):
1102 1102 """Switch to the desired mode.
@@ -1134,14 +1134,14 b' class AutoFormattedTB(FormattedTB):'
1134 1134 It will find out about exceptions by itself.
1135 1135
1136 1136 A brief example:
1137
1137
1138 1138 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1139 1139 try:
1140 1140 ...
1141 1141 except:
1142 1142 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1143 1143 """
1144
1144
1145 1145 def __call__(self,etype=None,evalue=None,etb=None,
1146 1146 out=None,tb_offset=None):
1147 1147 """Print out a formatted exception traceback.
@@ -1153,7 +1153,7 b' class AutoFormattedTB(FormattedTB):'
1153 1153 per-call basis (this overrides temporarily the instance's tb_offset
1154 1154 given at initialization time. """
1155 1155
1156
1156
1157 1157 if out is None:
1158 1158 out = self.ostream
1159 1159 out.flush()
@@ -1230,7 +1230,7 b' if __name__ == "__main__":'
1230 1230 except:
1231 1231 traceback.print_exc()
1232 1232 print ''
1233
1233
1234 1234 handler = ColorTB()
1235 1235 print '*** ColorTB ***'
1236 1236 try:
@@ -1238,7 +1238,7 b' if __name__ == "__main__":'
1238 1238 except:
1239 1239 apply(handler, sys.exc_info() )
1240 1240 print ''
1241
1241
1242 1242 handler = VerboseTB()
1243 1243 print '*** VerboseTB ***'
1244 1244 try:
@@ -1246,4 +1246,4 b' if __name__ == "__main__":'
1246 1246 except:
1247 1247 apply(handler, sys.exc_info() )
1248 1248 print ''
1249
1249
@@ -36,7 +36,7 b' Usage'
36 36
37 37 Almost all configuration in IPython is available via the command-line. Do
38 38 `ipython --help-all` to see all available options. For persistent
39 configuration, look into your `ipython_config.py` configuration file for
39 configuration, look into your `ipython_config.py` configuration file for
40 40 details.
41 41
42 42 This file is typically installed in the `IPYTHON_DIR` directory, and there
@@ -45,11 +45,11 b' Usage'
45 45 IPYTHON_DIR defaults to `$HOME/.config/ipython`, and for other Unix systems
46 46 to `$HOME/.ipython`. For Windows users, $HOME resolves to C:\\Documents
47 47 and Settings\\YourUserName in most instances.
48
48
49 49 To initialize a profile with the default configuration file, do::
50
50
51 51 $> ipython profile create
52
52
53 53 and start editing `IPYTHON_DIR/profile_default/ipython_config.py`
54 54
55 55 In IPython's documentation, we will refer to this directory as
@@ -129,7 +129,7 b' MAIN FEATURES'
129 129 * Persistent command history across sessions.
130 130
131 131 * Logging of input with the ability to save and restore a working session.
132
132
133 133 * System escape with !. Typing !ls will run 'ls' in the current directory.
134 134
135 135 * The reload command does a 'deep' reload of a module: changes made to the
@@ -201,7 +201,7 b' MAIN FEATURES'
201 201 Note that the '/' MUST be the first character on the line! This
202 202 won't work:
203 203 >>> print /globals # syntax error
204
204
205 205 In most cases the automatic algorithm should work, so you should
206 206 rarely need to explicitly invoke /. One notable exception is if you
207 207 are trying to call a function with a list of tuples as arguments (the
@@ -210,12 +210,12 b' MAIN FEATURES'
210 210 but this will work:
211 211 In [2]: /zip (1,2,3),(4,5,6)
212 212 ------> zip ((1,2,3),(4,5,6))
213 Out[2]= [(1, 4), (2, 5), (3, 6)]
213 Out[2]= [(1, 4), (2, 5), (3, 6)]
214 214
215 215 IPython tells you that it has altered your command line by
216 216 displaying the new command line preceded by -->. e.g.:
217 217 In [18]: callable list
218 -------> callable (list)
218 -------> callable (list)
219 219
220 220 2. Auto-Quoting
221 221 You can force auto-quoting of a function's arguments by using ',' as
@@ -255,7 +255,7 b' obj?, obj?? : Get help, or more help for object (also works as'
255 255
256 256 Magic functions are prefixed by %, and typically take their arguments without
257 257 parentheses, quotes or even commas for convenience.
258
258
259 259 Example magic function calls:
260 260
261 261 %alias d ls -F : 'd' is now an alias for 'ls -F'
@@ -265,7 +265,7 b' cd /usr/share : Obvious. cd -<tab> to choose from visited dirs.'
265 265 %cd?? : See help AND source for magic %cd
266 266
267 267 System commands:
268
268
269 269 !cp a.txt b/ : System command escape, calls os.system()
270 270 cp a.txt b/ : after %rehashx, most system commands work without !
271 271 cp ${f}.txt $bar : Variable expansion in magics and system commands
@@ -277,7 +277,7 b' History:'
277 277 _i, _ii, _iii : Previous, next previous, next next previous input
278 278 _i4, _ih[2:5] : Input history line 4, lines 2-4
279 279 exec _i81 : Execute input history line #81 again
280 %rep 81 : Edit input history line #81
280 %rep 81 : Edit input history line #81
281 281 _, __, ___ : previous, next previous, next next previous output
282 282 _dh : Directory history
283 283 _oh : Output history
@@ -327,10 +327,10 b' blocks are evaluated once a single blank line is entered::'
327 327
328 328 In [1]: print "Hello IPython!" # Enter was pressed at the end of the line
329 329 Hello IPython!
330
330
331 331 In [2]: for i in range(10):
332 332 ...: print i,
333 ...:
333 ...:
334 334 0 1 2 3 4 5 6 7 8 9
335 335
336 336 If you want to enter more than one expression in a single input block
@@ -348,7 +348,7 b' cell is executed as if it was a script. An example should clarify this::'
348 348 ...: z=3
349 349 ...: x**2 # This does *not* produce an Out[] value
350 350 ...: x+y+z # Only the last expression does
351 ...:
351 ...:
352 352 Out[3]: 6
353 353
354 354 The behavior where an extra blank line forces execution is only active if you
@@ -150,13 +150,13 b' def zip_items(items,titles=None):'
150 150 with their index. Leave other plot items alone."""
151 151
152 152 class StandaloneItem(Exception): pass
153
153
154 154 def get_titles(titles):
155 155 """Return the next title and the input titles array.
156 156
157 157 The input array may be changed to None when no titles are left to
158 158 prevent extra unnecessary calls to this function."""
159
159
160 160 try:
161 161 title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope
162 162 except IndexError:
@@ -258,33 +258,33 b' class Gnuplot(Gnuplot_ori.Gnuplot):'
258 258 explicit '' argument must be given as the limit to be kept.
259 259
260 260 Similar functions exist for [y{2}z{2}rtuv]range."""
261
261
262 262 self('set xrange [%s:%s]' % (min,max))
263
263
264 264 def yrange(self,min='*',max='*'):
265 265 self('set yrange [%s:%s]' % (min,max))
266
266
267 267 def zrange(self,min='*',max='*'):
268 268 self('set zrange [%s:%s]' % (min,max))
269
269
270 270 def x2range(self,min='*',max='*'):
271 271 self('set xrange [%s:%s]' % (min,max))
272
272
273 273 def y2range(self,min='*',max='*'):
274 274 self('set yrange [%s:%s]' % (min,max))
275
275
276 276 def z2range(self,min='*',max='*'):
277 277 self('set zrange [%s:%s]' % (min,max))
278
278
279 279 def rrange(self,min='*',max='*'):
280 280 self('set rrange [%s:%s]' % (min,max))
281
281
282 282 def trange(self,min='*',max='*'):
283 283 self('set trange [%s:%s]' % (min,max))
284
284
285 285 def urange(self,min='*',max='*'):
286 286 self('set urange [%s:%s]' % (min,max))
287
287
288 288 def vrange(self,min='*',max='*'):
289 289 self('set vrange [%s:%s]' % (min,max))
290 290
@@ -319,7 +319,7 b' class Gnuplot(Gnuplot_ori.Gnuplot):'
319 319 # Filter out other options the original plot doesn't know
320 320 hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None)
321 321 titles = popkey(keyw,'titles',0)
322
322
323 323 # the filename keyword should control hardcopy generation, this is an
324 324 # override switch only which needs to be explicitly set to zero
325 325 if hardcopy:
@@ -410,7 +410,7 b' class Gnuplot(Gnuplot_ori.Gnuplot):'
410 410
411 411 - filename: a string, typically ending in .eps. If given, the plot is
412 412 sent to this file in PostScript format.
413
413
414 414 - hardcopy: this can be set to 0 to override 'filename'. It does not
415 415 need to be given to produce PostScript, its purpose is to allow
416 416 switching PostScript output off globally in scripts without having to
@@ -421,7 +421,7 b' class Gnuplot(Gnuplot_ori.Gnuplot):'
421 421 PostScript.
422 422
423 423 For example:
424
424
425 425 In [1]: x=frange(0,2*pi,npts=100)
426 426
427 427 Generate a plot in file 'sin.eps':
@@ -439,16 +439,16 b' class Gnuplot(Gnuplot_ori.Gnuplot):'
439 439 PostScript generation through plot() is useful mainly for scripting
440 440 uses where you are not interested in interactive plotting. For
441 441 interactive use, the hardcopy() function is typically more convenient:
442
442
443 443 In [5]: plot(x,sin(x))
444 444
445 445 In [6]: hardcopy('sin.eps') """
446
446
447 447 self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw)
448
448
449 449 def plot2(self,arg,**kw):
450 """Plot the entries of a dictionary or a list/tuple of arrays.
451
450 """Plot the entries of a dictionary or a list/tuple of arrays.
451
452 452 This simple utility calls plot() with a list of Gnuplot.Data objects
453 453 constructed either from the values of the input dictionary, or the entries
454 454 in it if it is a tuple or list. Each item gets labeled with the key/index
@@ -493,7 +493,7 b' class Gnuplot(Gnuplot_ori.Gnuplot):'
493 493 Gnuplot.py, this version has several enhancements, listed in the
494 494 plot() documentation.
495 495 """
496
496
497 497 self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw)
498 498
499 499 def replot(self, *items, **keyw):
@@ -508,7 +508,7 b' class Gnuplot(Gnuplot_ori.Gnuplot):'
508 508 'filename' keyword argument in each call to replot. The Gnuplot python
509 509 interface has no way of knowing that your previous call to
510 510 Gnuplot.plot() was meant for PostScript output."""
511
511
512 512 self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw)
513 513
514 514 # The original hardcopy has a bug. See fix at the end. The rest of the code
@@ -38,13 +38,13 b' class _Helper(object):'
38 38 def __repr__(self):
39 39 return "Type help() for interactive help, " \
40 40 "or help(object) for help about object."
41
41
42 42 def __call__(self, *args, **kwds):
43 43 class DummyWriter(object):
44 '''Dumy class to handle help output'''
44 '''Dumy class to handle help output'''
45 45 def __init__(self, pager):
46 46 self._pager = pager
47
47
48 48 def write(self, data):
49 49 '''hook to fill self._pager'''
50 50 self._pager(data)
@@ -52,17 +52,17 b' class _Helper(object):'
52 52 import pydoc
53 53 pydoc.help.output = DummyWriter(self._pager)
54 54 pydoc.help.interact = lambda :1
55
55
56 56 return pydoc.help(*args, **kwds)
57 57
58
58
59 59 ##############################################################################
60 60 class _CodeExecutor(ThreadEx):
61 61 ''' Thread that execute ipython code '''
62 62 def __init__(self, instance):
63 63 ThreadEx.__init__(self)
64 64 self.instance = instance
65
65
66 66 def run(self):
67 67 '''Thread main loop'''
68 68 try:
@@ -70,17 +70,17 b' class _CodeExecutor(ThreadEx):'
70 70 self.instance._help_text = None
71 71 self.instance._execute()
72 72 # used for uper class to generate event after execution
73 self.instance._after_execute()
74
73 self.instance._after_execute()
74
75 75 except KeyboardInterrupt:
76 76 pass
77
77
78 78
79 79 ##############################################################################
80 80 class NonBlockingIPShell(object):
81 81 '''
82 82 Create an IPython instance, running the commands in a separate,
83 non-blocking thread.
83 non-blocking thread.
84 84 This allows embedding in any GUI without blockage.
85 85
86 86 Note: The ThreadEx class supports asynchroneous function call
@@ -111,7 +111,7 b' class NonBlockingIPShell(object):'
111 111 self.init_ipython0(user_ns, user_global_ns,
112 112 cin, cout, cerr,
113 113 ask_exit_handler)
114
114
115 115 #vars used by _execute
116 116 self._iter_more = 0
117 117 self._history_level = 0
@@ -121,7 +121,7 b' class NonBlockingIPShell(object):'
121 121 #thread working vars
122 122 self._line_to_execute = ''
123 123 self._threading = True
124
124
125 125 #vars that will be checked by GUI loop to handle thread states...
126 126 #will be replaced later by PostEvent GUI funtions...
127 127 self._doc_text = None
@@ -132,7 +132,7 b' class NonBlockingIPShell(object):'
132 132 cin=None, cout=None, cerr=None,
133 133 ask_exit_handler=None):
134 134 ''' Initialize an ipython0 instance '''
135
135
136 136 #first we redefine in/out/error functions of IPython
137 137 #BUG: we've got a limitation form ipython0 there
138 138 #only one instance can be instanciated else tehre will be
@@ -143,7 +143,7 b' class NonBlockingIPShell(object):'
143 143 Term.cout = cout
144 144 if cerr:
145 145 Term.cerr = cerr
146
146
147 147 excepthook = sys.excepthook
148 148
149 149 #Hack to save sys.displayhook, because ipython seems to overwrite it...
@@ -165,11 +165,11 b' class NonBlockingIPShell(object):'
165 165 self._IP.stdin_encoding = loc
166 166 #we replace the ipython default pager by our pager
167 167 self._IP.set_hook('show_in_pager', self._pager)
168
169 #we replace the ipython default shell command caller
168
169 #we replace the ipython default shell command caller
170 170 #by our shell handler
171 171 self._IP.set_hook('shell_hook', self._shell)
172
172
173 173 #we replace the ipython default input command caller by our method
174 174 iplib.raw_input_original = self._raw_input_original
175 175 #we replace the ipython default exit command by our method
@@ -184,10 +184,10 b' class NonBlockingIPShell(object):'
184 184
185 185 import __builtin__
186 186 __builtin__.raw_input = self._raw_input
187
187
188 188 sys.excepthook = excepthook
189 189
190 #----------------------- Thread management section ----------------------
190 #----------------------- Thread management section ----------------------
191 191 def do_execute(self, line):
192 192 """
193 193 Tell the thread to process the 'line' command
@@ -196,8 +196,8 b' class NonBlockingIPShell(object):'
196 196 self._line_to_execute = line
197 197
198 198 if self._threading:
199 #we launch the ipython line execution in a thread to make it
200 #interruptible with include it in self namespace to be able
199 #we launch the ipython line execution in a thread to make it
200 #interruptible with include it in self namespace to be able
201 201 #to call ce.raise_exc(KeyboardInterrupt)
202 202 self.ce = _CodeExecutor(self)
203 203 self.ce.start()
@@ -207,8 +207,8 b' class NonBlockingIPShell(object):'
207 207 self._help_text = None
208 208 self._execute()
209 209 # used for uper class to generate event after execution
210 self._after_execute()
211
210 self._after_execute()
211
212 212 except KeyboardInterrupt:
213 213 pass
214 214
@@ -225,7 +225,7 b' class NonBlockingIPShell(object):'
225 225 @rtype: bool
226 226 """
227 227 return self._threading
228
228
229 229 def set_threading(self, state):
230 230 """
231 231 Sets threading state, if set to True, then each command sent to
@@ -247,7 +247,7 b' class NonBlockingIPShell(object):'
247 247 @rtype: string
248 248 """
249 249 return self._doc_text
250
250
251 251 def get_help_text(self):
252 252 """
253 253 Returns the output of the processing that need to be paged via help pager(if any)
@@ -265,7 +265,7 b' class NonBlockingIPShell(object):'
265 265 @rtype: string
266 266 """
267 267 return self._IP.banner
268
268
269 269 def get_prompt_count(self):
270 270 """
271 271 Returns the prompt number.
@@ -295,7 +295,7 b' class NonBlockingIPShell(object):'
295 295 @rtype: int
296 296 """
297 297 return self._IP.indent_current_nsp
298
298
299 299 def update_namespace(self, ns_dict):
300 300 '''
301 301 Add the current dictionary to the shell namespace.
@@ -354,7 +354,7 b' class NonBlockingIPShell(object):'
354 354 while((history == '' or history == '\n') and self._history_level >0):
355 355 if self._history_level >= 1:
356 356 self._history_level -= 1
357 history = self._get_history()
357 history = self._get_history()
358 358 return history
359 359
360 360 def history_forward(self):
@@ -406,7 +406,7 b' class NonBlockingIPShell(object):'
406 406 @rtype: int
407 407 '''
408 408 return len(self._IP.input_hist_raw)-1
409
409
410 410 def _get_history(self):
411 411 '''
412 412 Get's the command string of the current history level.
@@ -428,7 +428,7 b' class NonBlockingIPShell(object):'
428 428 self._help_text = text
429 429 else:
430 430 self._help_text += text
431
431
432 432 def _pager(self, IP, text):
433 433 '''
434 434 This function is used as a callback replacment to IPython pager function
@@ -437,7 +437,7 b' class NonBlockingIPShell(object):'
437 437 get_doc_text function.
438 438 '''
439 439 self._doc_text = text
440
440
441 441 def _raw_input_original(self, prompt=''):
442 442 '''
443 443 Custom raw_input() replacement. Get's current line from console buffer.
@@ -454,7 +454,7 b' class NonBlockingIPShell(object):'
454 454 """ A replacement from python's raw_input.
455 455 """
456 456 raise NotImplementedError
457
457
458 458 def _execute(self):
459 459 '''
460 460 Executes the current line provided by the shell object.
@@ -464,7 +464,7 b' class NonBlockingIPShell(object):'
464 464 sys.stdout = Term.cout
465 465 #self.sys_displayhook_ori = sys.displayhook
466 466 #sys.displayhook = self.displayhook
467
467
468 468 try:
469 469 line = self._IP.raw_input(None, self._iter_more)
470 470 if self._IP.autoindent:
@@ -497,7 +497,7 b' class NonBlockingIPShell(object):'
497 497
498 498 sys.stdout = orig_stdout
499 499 #sys.displayhook = self.sys_displayhook_ori
500
500
501 501 def _shell(self, ip, cmd):
502 502 '''
503 503 Replacement method to allow shell commands without them blocking.
@@ -16,12 +16,12 b' class IPythonHistoryPanel(wx.Panel):'
16 16
17 17 def __init__(self, parent,flt_empty=True,
18 18 flt_doc=True,flt_cmd=True,flt_magic=True):
19
19
20 20 wx.Panel.__init__(self,parent,-1)
21 21 #text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
22 22 text_ctrl = PythonSTC(self, -1)
23
24
23
24
25 25 st_filt = wx.StaticText(self, -1, " Filter:")
26 26
27 27 self.filter_empty = wx.CheckBox(self, -1, "Empty commands")
@@ -52,12 +52,12 b' class IPythonHistoryPanel(wx.Panel):'
52 52 self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter)
53 53 self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter)
54 54 self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter)
55
55
56 56 #self.filter_empty.SetValue(flt_empty)
57 57 #self.filter_doc.SetValue(flt_doc)
58 58 #self.filter_cmd.SetValue(flt_cmd)
59 59 #self.filter_magic.SetValue(flt_magic)
60
60
61 61 sizer = wx.BoxSizer(wx.VERTICAL)
62 62
63 63 sizer.Add(text_ctrl, 1, wx.EXPAND)
@@ -83,7 +83,7 b' class IPythonHistoryPanel(wx.Panel):'
83 83 text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER)
84 84 text_ctrl.SetMarginWidth(1, 15)
85 85
86
86
87 87 def write(self,history_line):
88 88 add = True
89 89 if self.filter_empty.GetValue() == True and history_line == '':
@@ -106,10 +106,10 b' class IPythonHistoryPanel(wx.Panel):'
106 106 self.options[name]['value']='False'
107 107 self.updateOptionTracker(name,
108 108 self.options[name]['value'])
109
109
110 110 def evtCheckEmptyFilter(self, event):
111 111 self.processOptionCheckedEvt(event, 'filter_empty')
112
112
113 113 def evtCheckDocFilter(self, event):
114 114 self.processOptionCheckedEvt(event, 'filter_doc')
115 115
@@ -118,10 +118,10 b' class IPythonHistoryPanel(wx.Panel):'
118 118
119 119 def evtCheckMagicFilter(self, event):
120 120 self.processOptionCheckedEvt(event, 'filter_magic')
121
121
122 122 def getOptions(self):
123 123 return self.options
124
124
125 125 def reloadOptions(self,options):
126 126 self.options = options
127 127 for key in self.options.keys():
@@ -135,14 +135,14 b' class IPythonHistoryPanel(wx.Panel):'
135 135 Default history tracker (does nothing)
136 136 '''
137 137 pass
138
138
139 139 def setOptionTrackerHook(self,func):
140 140 '''
141 141 Define a new history tracker
142 142 '''
143 143 self.updateOptionTracker = func
144 144
145
145
146 146 #----------------------------------------------------------------------
147 147 # Font definition for Styled Text Control
148 148
@@ -177,7 +177,7 b' else:'
177 177 class PythonSTC(stc.StyledTextCtrl):
178 178
179 179 fold_symbols = 3
180
180
181 181 def __init__(self, parent, ID,
182 182 pos=wx.DefaultPosition, size=wx.DefaultSize,
183 183 style=0):
@@ -197,14 +197,14 b' class PythonSTC(stc.StyledTextCtrl):'
197 197 #self.SetViewEOL(True)
198 198 self.SetEOLMode(stc.STC_EOL_CRLF)
199 199 #self.SetUseAntiAliasing(True)
200
200
201 201 self.SetEdgeMode(stc.STC_EDGE_LINE)
202 202 self.SetEdgeColumn(80)
203 203 self.SetEdgeColour(wx.LIGHT_GREY)
204 204 self.SetLayoutCache(stc.STC_CACHE_PAGE)
205 205
206 206 # Setup a margin to hold fold markers
207 #self.SetFoldFlags(16)
207 #self.SetFoldFlags(16)
208 208 ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
209 209 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
210 210 self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
@@ -212,7 +212,7 b' class PythonSTC(stc.StyledTextCtrl):'
212 212 self.SetMarginWidth(2, 12)
213 213
214 214 if self.fold_symbols == 0:
215 # Arrow pointing right for contracted folders,
215 # Arrow pointing right for contracted folders,
216 216 # arrow pointing down for expanded
217 217 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
218 218 stc.STC_MARK_ARROWDOWN, "black", "black")
@@ -228,7 +228,7 b' class PythonSTC(stc.StyledTextCtrl):'
228 228 stc.STC_MARK_EMPTY, "white", "black")
229 229 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
230 230 stc.STC_MARK_EMPTY, "white", "black")
231
231
232 232 elif self.fold_symbols == 1:
233 233 # Plus for contracted folders, minus for expanded
234 234 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
@@ -301,7 +301,7 b' class PythonSTC(stc.StyledTextCtrl):'
301 301 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
302 302
303 303 # Python styles
304 # Default
304 # Default
305 305 self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
306 306 # Comments
307 307 self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
@@ -335,9 +335,9 b' class PythonSTC(stc.StyledTextCtrl):'
335 335
336 336 # register some images for use in the AutoComplete box.
337 337 #self.RegisterImage(1, images.getSmilesBitmap())
338 #self.RegisterImage(2,
338 #self.RegisterImage(2,
339 339 # wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
340 #self.RegisterImage(3,
340 #self.RegisterImage(3,
341 341 # wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
342 342
343 343
@@ -365,7 +365,7 b' class PythonSTC(stc.StyledTextCtrl):'
365 365 #self.AutoCompShow(0, st)
366 366
367 367 kw = keyword.kwlist[:]
368
368
369 369 kw.sort() # Python sorts are case sensitive
370 370 self.AutoCompSetIgnoreCase(False) # so this needs to match
371 371
@@ -398,7 +398,7 b' class PythonSTC(stc.StyledTextCtrl):'
398 398 if braceAtCaret < 0:
399 399 charAfter = self.GetCharAt(caretPos)
400 400 styleAfter = self.GetStyleAt(caretPos)
401
401
402 402 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
403 403 braceAtCaret = caretPos
404 404
@@ -53,11 +53,11 b' class WxNonBlockingIPShell(NonBlockingIPShell):'
53 53 '''
54 54 An NonBlockingIPShell Thread that is WX dependent.
55 55 '''
56 def __init__(self, parent,
56 def __init__(self, parent,
57 57 argv=[],user_ns={},user_global_ns=None,
58 58 cin=None, cout=None, cerr=None,
59 59 ask_exit_handler=None):
60
60
61 61 NonBlockingIPShell.__init__(self, argv, user_ns, user_global_ns,
62 62 cin, cout, cerr,
63 63 ask_exit_handler)
@@ -68,22 +68,22 b' class WxNonBlockingIPShell(NonBlockingIPShell):'
68 68 self._IP.exit = self._ask_exit
69 69
70 70 def addGUIShortcut(self, text, func):
71 wx.CallAfter(self.parent.add_button_handler,
72 button_info={ 'text':text,
71 wx.CallAfter(self.parent.add_button_handler,
72 button_info={ 'text':text,
73 73 'func':self.parent.doExecuteLine(func)})
74 74
75 75 def _raw_input(self, prompt=''):
76 76 """ A replacement from python's raw_input.
77 77 """
78 78 self.answer = None
79 if(self._threading == True):
79 if(self._threading == True):
80 80 wx.CallAfter(self._yesNoBox, prompt)
81 81 while self.answer is None:
82 82 time.sleep(.1)
83 83 else:
84 84 self._yesNoBox(prompt)
85 85 return self.answer
86
86
87 87 def _yesNoBox(self, prompt):
88 88 """ yes/no box managed with wx.CallAfter jsut in case caler is executed in a thread"""
89 89 dlg = wx.TextEntryDialog(
@@ -94,21 +94,21 b' class WxNonBlockingIPShell(NonBlockingIPShell):'
94 94 answer = ''
95 95 if dlg.ShowModal() == wx.ID_OK:
96 96 answer = dlg.GetValue()
97
97
98 98 dlg.Destroy()
99 99 self.answer = answer
100
100
101 101 def _ask_exit(self):
102 102 wx.CallAfter(self.ask_exit_callback, ())
103 103
104 104 def _after_execute(self):
105 105 wx.CallAfter(self.parent.evtStateExecuteDone, ())
106 106
107
107
108 108 class WxConsoleView(stc.StyledTextCtrl):
109 109 '''
110 110 Specialized styled text control view for console-like workflow.
111 We use here a scintilla frontend thus it can be reused in any GUI that
111 We use here a scintilla frontend thus it can be reused in any GUI that
112 112 supports scintilla with less work.
113 113
114 114 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
@@ -128,7 +128,7 b' class WxConsoleView(stc.StyledTextCtrl):'
128 128 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
129 129 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
130 130 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
131 '1;34': [12, 'LIGHT BLUE'], '1;35':
131 '1;34': [12, 'LIGHT BLUE'], '1;35':
132 132 [13, 'MEDIUM VIOLET RED'],
133 133 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
134 134
@@ -163,8 +163,8 b' class WxConsoleView(stc.StyledTextCtrl):'
163 163 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
164 164
165 165 ####### Scintilla configuration ###################################
166
167 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
166
167 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
168 168 # the widget
169 169 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
170 170 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
@@ -188,7 +188,7 b' class WxConsoleView(stc.StyledTextCtrl):'
188 188 self.SetTabWidth(4)
189 189
190 190 self.EnsureCaretVisible()
191
191
192 192 self.SetMargins(3, 3) #text is moved away from border with 3px
193 193 # Suppressing Scintilla margins
194 194 self.SetMarginWidth(0, 0)
@@ -197,19 +197,19 b' class WxConsoleView(stc.StyledTextCtrl):'
197 197
198 198 self.background_color = background_color
199 199 self.buildStyles()
200
200
201 201 self.indent = 0
202 202 self.prompt_count = 0
203 203 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
204
204
205 205 self.write(intro)
206 206 self.setPrompt(prompt)
207 207 self.showPrompt()
208 208
209 209 self.autocomplete_mode = autocomplete_mode
210
210
211 211 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress)
212
212
213 213 def buildStyles(self):
214 214 #we define platform specific fonts
215 215 if wx.Platform == '__WXMSW__':
@@ -246,29 +246,29 b' class WxConsoleView(stc.StyledTextCtrl):'
246 246 self.SetCaretForeground("WHITE")
247 247 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
248 248
249 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
250 "fore:%s,back:%s,size:%d,face:%s"
249 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
250 "fore:%s,back:%s,size:%d,face:%s"
251 251 % (self.ANSI_STYLES['0;30'][1],
252 252 self.background_color,
253 253 faces['size'], faces['mono']))
254 254 self.StyleClearAll()
255 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
255 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
256 256 "fore:#FF0000,back:#0000FF,bold")
257 257 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
258 258 "fore:#000000,back:#FF0000,bold")
259 259
260 260 for style in self.ANSI_STYLES.values():
261 261 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
262
262
263 263 #######################################################################
264
264
265 265 def setBackgroundColor(self, color):
266 266 self.background_color = color
267 267 self.buildStyles()
268 268
269 269 def getBackgroundColor(self, color):
270 270 return self.background_color
271
271
272 272 def asyncWrite(self, text):
273 273 '''
274 274 Write given text to buffer in an asynchroneous way.
@@ -278,16 +278,16 b' class WxConsoleView(stc.StyledTextCtrl):'
278 278 '''
279 279 try:
280 280 wx.MutexGuiEnter()
281
281
282 282 #be sure not to be interrutpted before the MutexGuiLeave!
283 283 self.write(text)
284
284
285 285 except KeyboardInterrupt:
286 286 wx.MutexGuiLeave()
287 287 raise KeyboardInterrupt
288 288 wx.MutexGuiLeave()
289
290
289
290
291 291 def write(self, text):
292 292 '''
293 293 Write given text to buffer.
@@ -299,7 +299,7 b' class WxConsoleView(stc.StyledTextCtrl):'
299 299 segment = segments.pop(0)
300 300 self.StartStyling(self.getCurrentLineEnd(), 0xFF)
301 301 self.AppendText(segment)
302
302
303 303 if segments:
304 304 ansi_tags = self.color_pat.findall(text)
305 305
@@ -312,9 +312,9 b' class WxConsoleView(stc.StyledTextCtrl):'
312 312 self.SetStyling(len(segments[i+1]), self.ANSI_STYLES[tag][0])
313 313
314 314 segments.pop(i)
315
315
316 316 self.moveCursor(self.getCurrentLineEnd())
317
317
318 318 def getPromptLen(self):
319 319 '''
320 320 Return the length of current prompt
@@ -326,10 +326,10 b' class WxConsoleView(stc.StyledTextCtrl):'
326 326
327 327 def setIndentation(self, indentation):
328 328 self.indent = indentation
329
329
330 330 def setPromptCount(self, count):
331 331 self.prompt_count = count
332
332
333 333 def showPrompt(self):
334 334 '''
335 335 Prints prompt at start of line.
@@ -340,11 +340,11 b' class WxConsoleView(stc.StyledTextCtrl):'
340 340 self.write(self.prompt)
341 341 #now we update the position of end of prompt
342 342 self.current_start = self.getCurrentLineEnd()
343
343
344 344 autoindent = self.indent*' '
345 345 autoindent = autoindent.replace(' ','\t')
346 346 self.write(autoindent)
347
347
348 348 def changeLine(self, text):
349 349 '''
350 350 Replace currently entered command line with given text.
@@ -379,15 +379,15 b' class WxConsoleView(stc.StyledTextCtrl):'
379 379 #If cursor is at wrong position put it at last line...
380 380 if self.GetCurrentPos() < self.getCurrentPromptStart():
381 381 self.GotoPos(self.getCurrentPromptStart())
382
382
383 383 def removeFromTo(self, from_pos, to_pos):
384 384 if from_pos < to_pos:
385 385 self.SetSelection(from_pos, to_pos)
386 386 self.DeleteBack()
387
387
388 388 def removeCurrentLine(self):
389 389 self.LineDelete()
390
390
391 391 def moveCursor(self, position):
392 392 self.GotoPos(position)
393 393
@@ -397,7 +397,7 b' class WxConsoleView(stc.StyledTextCtrl):'
397 397 def selectFromTo(self, from_pos, to_pos):
398 398 self.SetSelectionStart(from_pos)
399 399 self.SetSelectionEnd(to_pos)
400
400
401 401 def writeHistory(self, history):
402 402 self.removeFromTo(self.getCurrentPromptStart(), self.getCurrentLineEnd())
403 403 self.changeLine(history)
@@ -410,19 +410,19 b' class WxConsoleView(stc.StyledTextCtrl):'
410 410
411 411 def getCompletionMethod(self, completion):
412 412 return self.autocomplete_mode
413
413
414 414 def writeCompletion(self, possibilities):
415 415 if self.autocomplete_mode == 'IPYTHON':
416 416 max_len = len(max(possibilities, key=len))
417 417 max_symbol = ' '*max_len
418
418
419 419 #now we check how much symbol we can put on a line...
420 420 test_buffer = max_symbol + ' '*4
421
421
422 422 allowed_symbols = 80/len(test_buffer)
423 423 if allowed_symbols == 0:
424 424 allowed_symbols = 1
425
425
426 426 pos = 1
427 427 buf = ''
428 428 for symbol in possibilities:
@@ -445,7 +445,7 b' class WxConsoleView(stc.StyledTextCtrl):'
445 445 for breaker in splitter:
446 446 last_word = last_word.split(breaker)[-1]
447 447 self.AutoCompShow(len(last_word), " ".join(possibilities))
448
448
449 449 def _onKeypress(self, event, skip=True):
450 450 '''
451 451 Key press callback used for correcting behavior for console-like
@@ -476,7 +476,7 b' class WxConsoleView(stc.StyledTextCtrl):'
476 476 elif event.GetKeyCode() == wx.WXK_LEFT:
477 477 if event.Modifiers == wx.MOD_NONE:
478 478 self.moveCursorOnNewValidKey()
479
479
480 480 self.moveCursor(self.getCursorPos()-1)
481 481 if self.getCursorPos() < self.getCurrentPromptStart():
482 482 self.moveCursor(self.getCurrentPromptStart())
@@ -487,18 +487,18 b' class WxConsoleView(stc.StyledTextCtrl):'
487 487 if self.getCursorPos() > self.getCurrentPromptStart():
488 488 event.Skip()
489 489 return True
490
490
491 491 if skip:
492 492 if event.GetKeyCode() not in [wx.WXK_PAGEUP, wx.WXK_PAGEDOWN]\
493 493 and event.Modifiers == wx.MOD_NONE:
494 494 self.moveCursorOnNewValidKey()
495
495
496 496 event.Skip()
497 497 return True
498 498 return False
499 499 else:
500 500 event.Skip()
501
501
502 502 def OnUpdateUI(self, evt):
503 503 # check for matching braces
504 504 braceAtCaret = -1
@@ -533,19 +533,19 b' class WxConsoleView(stc.StyledTextCtrl):'
533 533 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
534 534 #print pt
535 535 #self.Refresh(False)
536
536
537 537 class IPShellWidget(wx.Panel):
538 538 '''
539 539 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
540 If you want to port this to any other GUI toolkit, just replace the
541 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
542 from whatever container you want. I've choosed to derivate from a wx.Panel
540 If you want to port this to any other GUI toolkit, just replace the
541 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
542 from whatever container you want. I've choosed to derivate from a wx.Panel
543 543 because it seems to be more useful
544 544 Any idea to make it more 'generic' welcomed.
545 545 '''
546 546
547 547 def __init__(self, parent, intro=None,
548 background_color="BLACK", add_button_handler=None,
548 background_color="BLACK", add_button_handler=None,
549 549 wx_ip_shell=None, user_ns={},user_global_ns=None,
550 550 ):
551 551 '''
@@ -570,7 +570,7 b' class IPShellWidget(wx.Panel):'
570 570
571 571 ### IPython wx console view instanciation ###
572 572 #If user didn't defined an intro text, we create one for him
573 #If you really wnat an empty intro just call wxIPythonViewPanel
573 #If you really wnat an empty intro just call wxIPythonViewPanel
574 574 #with intro=''
575 575 if intro is None:
576 576 welcome_text = "Welcome to WxIPython Shell.\n\n"
@@ -598,7 +598,7 b' class IPShellWidget(wx.Panel):'
598 598 self.threading_option.SetToolTip(wx.ToolTip(
599 599 "Use threading: infinite loop don't freeze the GUI and commands can be breaked\nNo threading: maximum compatibility"))
600 600 #self.threading_option.SetValue(False)
601
601
602 602 self.options={'completion':{'value':'IPYTHON',
603 603 'checkbox':self.completion_option,'STC':True,'IPYTHON':False,
604 604 'setfunc':self.text_ctrl.setCompletionMethod},
@@ -614,12 +614,12 b' class IPShellWidget(wx.Panel):'
614 614 self.cout.write = self.text_ctrl.asyncWrite
615 615 #we reloard options
616 616 self.reloadOptions(self.options)
617
617
618 618 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress)
619 619 self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion)
620 620 self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor)
621 621 self.threading_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionThreading)
622
622
623 623 ### making the layout of the panel ###
624 624 sizer = wx.BoxSizer(wx.VERTICAL)
625 625 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
@@ -648,7 +648,7 b' class IPShellWidget(wx.Panel):'
648 648
649 649 def askExitCallback(self, event):
650 650 self.askExitHandler(event)
651
651
652 652 #---------------------- IPython Thread Management ------------------------
653 653 def stateDoExecuteLine(self):
654 654 lines=self.text_ctrl.getCurrentLine()
@@ -660,7 +660,7 b' class IPShellWidget(wx.Panel):'
660 660 if(self.text_ctrl.getCursorPos()!=0):
661 661 self.text_ctrl.removeCurrentLine()
662 662 self.setCurrentState('WAIT_END_OF_EXECUTION')
663
663
664 664 def evtStateExecuteDone(self,evt):
665 665 self.doc = self.IP.get_doc_text()
666 666 self.help = self.IP.get_help_text()
@@ -673,7 +673,7 b' class IPShellWidget(wx.Panel):'
673 673 self.pager_lines = self.help.split('\n')
674 674 self.pager_state = 'INIT'
675 675 self.setCurrentState('SHOW_DOC')
676 self.pager(self.help)
676 self.pager(self.help)
677 677 else:
678 678 if(self.text_ctrl.getCursorPos()!=0):
679 679 self.text_ctrl.removeCurrentLine()
@@ -714,7 +714,7 b' class IPShellWidget(wx.Panel):'
714 714 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
715 715 else:
716 716 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
717
717
718 718 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
719 719 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
720 720 self.pager_index += 10
@@ -730,7 +730,7 b' class IPShellWidget(wx.Panel):'
730 730 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
731 731 else:
732 732 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
733
733
734 734 self.pager_index += 1
735 735 self.pager_nb_lines -= 1
736 736 if self.pager_nb_lines > 0:
@@ -739,7 +739,7 b' class IPShellWidget(wx.Panel):'
739 739 self.pager_nb_lines = 0
740 740 self.pager_state = 'DONE'
741 741 self.stateShowPrompt()
742
742
743 743 #------------------------ Key Handler ------------------------------------
744 744 def keyPress(self, event):
745 745 '''
@@ -752,7 +752,7 b' class IPShellWidget(wx.Panel):'
752 752 #we raise an exception inside the IPython thread container
753 753 self.IP.ce.raise_exc(KeyboardInterrupt)
754 754 return
755
755
756 756 #let this before 'wx.WXK_RETURN' because we have to put 'IDLE'
757 757 #mode if AutoComp has been set as inactive
758 758 if self.cur_state == 'COMPLETING':
@@ -772,13 +772,13 b' class IPShellWidget(wx.Panel):'
772 772 self.pager_state = 'PROCESS_LINES'
773 773 self.pager(self.doc)
774 774 return
775
775
776 776 if self.cur_state == 'WAITING_USER_INPUT':
777 777 line=self.text_ctrl.getCurrentLine()
778 778 self.text_ctrl.write('\n')
779 779 self.setCurrentState('WAIT_END_OF_EXECUTION')
780 780 return
781
781
782 782 if event.GetKeyCode() in [ord('q'),ord('Q')]:
783 783 if self.pager_state == 'WAITING':
784 784 self.pager_state = 'DONE'
@@ -787,8 +787,8 b' class IPShellWidget(wx.Panel):'
787 787 return
788 788
789 789 if self.cur_state == 'WAITING_USER_INPUT':
790 event.Skip()
791
790 event.Skip()
791
792 792 if self.cur_state == 'IDLE':
793 793 if event.KeyCode == wx.WXK_UP:
794 794 history = self.IP.history_back()
@@ -805,7 +805,7 b' class IPShellWidget(wx.Panel):'
805 805 return
806 806 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
807 807 if len(possibilities) > 1:
808 if self.text_ctrl.autocomplete_mode == 'IPYTHON':
808 if self.text_ctrl.autocomplete_mode == 'IPYTHON':
809 809 cur_slice = self.text_ctrl.getCurrentLine()
810 810 self.text_ctrl.write('\n')
811 811 self.text_ctrl.writeCompletion(possibilities)
@@ -855,31 +855,31 b' class IPShellWidget(wx.Panel):'
855 855 self.updateOptionTracker('threading',
856 856 self.options['threading']['value'])
857 857 self.text_ctrl.SetFocus()
858
858
859 859 def getOptions(self):
860 860 return self.options
861
861
862 862 def reloadOptions(self,options):
863 863 self.options = options
864 864 for key in self.options.keys():
865 865 value = self.options[key]['value']
866 866 self.options[key]['checkbox'].SetValue(self.options[key][value])
867 867 self.options[key]['setfunc'](value)
868
868
869 869 if self.options['threading']['value']=='True':
870 870 self.IP.set_threading(True)
871 871 self.cout.write = self.text_ctrl.asyncWrite
872 872 else:
873 873 self.IP.set_threading(False)
874 874 self.cout.write = self.text_ctrl.write
875
875
876 876 #------------------------ Hook Section -----------------------------------
877 877 def updateOptionTracker(self,name,value):
878 878 '''
879 879 Default history tracker (does nothing)
880 880 '''
881 881 pass
882
882
883 883 def setOptionTrackerHook(self,func):
884 884 '''
885 885 Define a new history tracker
@@ -891,7 +891,7 b' class IPShellWidget(wx.Panel):'
891 891 Default history tracker (does nothing)
892 892 '''
893 893 pass
894
894
895 895 def setHistoryTrackerHook(self,func):
896 896 '''
897 897 Define a new history tracker
@@ -903,7 +903,7 b' class IPShellWidget(wx.Panel):'
903 903 Default status tracker (does nothing)
904 904 '''
905 905 pass
906
906
907 907 def setStatusTrackerHook(self,func):
908 908 '''
909 909 Define a new status tracker
@@ -6,8 +6,8 b' raise_exc.'
6 6 import threading
7 7 import inspect
8 8 import ctypes
9
10
9
10
11 11 def _async_raise(tid, exctype):
12 12 """raises the exception, performs cleanup if needed"""
13 13 if not inspect.isclass(exctype):
@@ -16,35 +16,35 b' def _async_raise(tid, exctype):'
16 16 if res == 0:
17 17 raise ValueError("invalid thread id")
18 18 elif res != 1:
19 # """if it returns a number greater than one, you're in trouble,
19 # """if it returns a number greater than one, you're in trouble,
20 20 # and you should call it again with exc=NULL to revert the effect"""
21 21 ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
22 22 raise SystemError("PyThreadState_SetAsyncExc failed")
23
24
23
24
25 25 class ThreadEx(threading.Thread):
26 26 def _get_my_tid(self):
27 27 """determines this (self's) thread id"""
28 28 if not self.isAlive():
29 29 raise threading.ThreadError("the thread is not active")
30
30
31 31 # do we have it cached?
32 32 if hasattr(self, "_thread_id"):
33 33 return self._thread_id
34
34
35 35 # no, look for it in the _active dict
36 36 for tid, tobj in threading._active.items():
37 37 if tobj is self:
38 38 self._thread_id = tid
39 39 return tid
40
40
41 41 raise AssertionError("could not determine the thread's id")
42
42
43 43 def raise_exc(self, exctype):
44 44 """raises the given exception type in the context of this thread"""
45 45 _async_raise(self._get_my_tid(), exctype)
46
46
47 47 def kill(self):
48 """raises SystemExit in the context of the given thread, which should
48 """raises SystemExit in the context of the given thread, which should
49 49 cause the thread to exit silently (unless caught)"""
50 50 self.raise_exc(SystemExit)
@@ -27,26 +27,26 b' __email__ = "laurent.dufrechou _at_ gmail.com"'
27 27 __license__ = "BSD"
28 28
29 29 #-----------------------------------------
30 # Creating one main frame for our
30 # Creating one main frame for our
31 31 # application with movables windows
32 32 #-----------------------------------------
33 33 class MyFrame(wx.Frame):
34 """Creating one main frame for our
34 """Creating one main frame for our
35 35 application with movables windows"""
36 def __init__(self, parent=None, id=-1, title="WxIPython",
36 def __init__(self, parent=None, id=-1, title="WxIPython",
37 37 pos=wx.DefaultPosition,
38 38 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE, sync_ok=False):
39 39 wx.Frame.__init__(self, parent, id, title, pos, size, style)
40 40 self._mgr = wx.aui.AuiManager()
41
41
42 42 # notify PyAUI which frame to use
43 43 self._mgr.SetManagedWindow(self)
44
45 #create differents panels and make them persistant
44
45 #create differents panels and make them persistant
46 46 self.history_panel = IPythonHistoryPanel(self)
47 47
48 48 self.history_panel.setOptionTrackerHook(self.optionSave)
49
49
50 50 self.ipython_panel = IPShellWidget(self,background_color = "BLACK")
51 51 #self.ipython_panel = IPShellWidget(self,background_color = "WHITE")
52 52 if(sync_ok):
@@ -60,12 +60,12 b' class MyFrame(wx.Frame):'
60 60
61 61 #Create a notebook to display different IPython shell implementations
62 62 self.nb = wx.aui.AuiNotebook(self)
63
63
64 64 self.optionLoad()
65
65
66 66 self.statusbar = self.createStatus()
67 67 self.createMenu()
68
68
69 69 ########################################################################
70 70 ### add the panes to the manager
71 71 # main panels
@@ -75,12 +75,12 b' class MyFrame(wx.Frame):'
75 75 self.nb.AddPage(self.ipython_panel2, "IPython1 Synchroneous Shell")
76 76
77 77 self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history")
78
78
79 79 # now we specify some panel characteristics
80 80 self._mgr.GetPane(self.ipython_panel).CaptionVisible(True);
81 81 self._mgr.GetPane(self.history_panel).CaptionVisible(True);
82 82 self._mgr.GetPane(self.history_panel).MinSize((200,400));
83
83
84 84 # tell the manager to "commit" all the changes just made
85 85 self._mgr.Update()
86 86
@@ -91,14 +91,14 b' class MyFrame(wx.Frame):'
91 91 self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2)
92 92 self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3)
93 93 self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6)
94
94
95 95 warn_text = 'Hello from IPython and wxPython.\n'
96 96 warn_text +='Please Note that this work is still EXPERIMENTAL\n'
97 97 warn_text +='It does NOT emulate currently all the IPython functions.\n'
98 98 warn_text +="\nIf you use MATPLOTLIB with show() you'll need to deactivate the THREADING option.\n"
99 99 if(not sync_ok):
100 100 warn_text +="\n->No twisted package detected, IPython1 example deactivated."
101
101
102 102 dlg = wx.MessageDialog(self,
103 103 warn_text,
104 104 'Warning Box',
@@ -120,9 +120,9 b' class MyFrame(wx.Frame):'
120 120 opt.write(key + '=' + options_ipython_panel[key]['value']+'\n')
121 121 for key in options_history_panel.keys():
122 122 opt.write(key + '=' + options_history_panel[key]['value']+'\n')
123 finally:
123 finally:
124 124 opt.close()
125
125
126 126 def optionLoad(self):
127 127 try:
128 128 ip = get()
@@ -130,10 +130,10 b' class MyFrame(wx.Frame):'
130 130 opt = open(path + '/options.conf','r')
131 131 lines = opt.readlines()
132 132 opt.close()
133
133
134 134 options_ipython_panel = self.ipython_panel.getOptions()
135 135 options_history_panel = self.history_panel.getOptions()
136
136
137 137 for line in lines:
138 138 key = line.split('=')[0]
139 139 value = line.split('=')[1].replace('\n','').replace('\r','')
@@ -145,25 +145,25 b' class MyFrame(wx.Frame):'
145 145 print >>sys.__stdout__,"Warning: key ",key,"not found in widget options. Check Options.conf"
146 146 self.ipython_panel.reloadOptions(options_ipython_panel)
147 147 self.history_panel.reloadOptions(options_history_panel)
148
148
149 149 except IOError:
150 150 print >>sys.__stdout__,"Could not open Options.conf, defaulting to default values."
151
152
151
152
153 153 def createMenu(self):
154 154 """local method used to create one menu bar"""
155
155
156 156 mb = wx.MenuBar()
157 157
158 158 file_menu = wx.Menu()
159 159 file_menu.Append(wx.ID_EXIT, "Exit")
160
160
161 161 view_menu = wx.Menu()
162 162 view_menu.Append(wx.ID_HIGHEST+1, "Show IPython Panel")
163 163 view_menu.Append(wx.ID_HIGHEST+2, "Show History Panel")
164 164 view_menu.AppendSeparator()
165 165 view_menu.Append(wx.ID_HIGHEST+6, "Show All")
166
166
167 167 about_menu = wx.Menu()
168 168 about_menu.Append(wx.ID_HIGHEST+3, "About")
169 169
@@ -171,7 +171,7 b' class MyFrame(wx.Frame):'
171 171 mb.Append(view_menu, "View")
172 172 mb.Append(about_menu, "About")
173 173 #mb.Append(options_menu, "Options")
174
174
175 175 self.SetMenuBar(mb)
176 176
177 177 def createStatus(self):
@@ -189,14 +189,14 b' class MyFrame(wx.Frame):'
189 189 'SHOW_DOC':'Showing doc',
190 190 'SHOW_PROMPT':'Showing prompt'}
191 191 self.statusbar.SetStatusText(states[text], 0)
192
192
193 193 def OnClose(self, event):
194 194 """#event used to close program """
195 195 # deinitialize the frame manager
196 196 self._mgr.UnInit()
197 self.Destroy()
197 self.Destroy()
198 198 event.Skip()
199
199
200 200 def OnExitDlg(self, event):
201 201 dlg = wx.MessageDialog(self, 'Are you sure you want to quit WxIPython',
202 202 'WxIPython exit',
@@ -208,17 +208,17 b' class MyFrame(wx.Frame):'
208 208 self._mgr.UnInit()
209 209 self.Destroy()
210 210 dlg.Destroy()
211
212 #event to display IPython pannel
211
212 #event to display IPython pannel
213 213 def OnShowIPythonPanel(self,event):
214 214 """ #event to display Boxpannel """
215 215 self._mgr.GetPane(self.ipython_panel).Show(True)
216 self._mgr.Update()
217 #event to display History pannel
216 self._mgr.Update()
217 #event to display History pannel
218 218 def OnShowHistoryPanel(self,event):
219 219 self._mgr.GetPane(self.history_panel).Show(True)
220 self._mgr.Update()
221
220 self._mgr.Update()
221
222 222 def OnShowAllPanel(self,event):
223 223 """#event to display all Pannels"""
224 224 self._mgr.GetPane(self.ipython_panel).Show(True)
@@ -240,22 +240,22 b' class MyFrame(wx.Frame):'
240 240 info.License = wordwrap(licenseText, 500, wx.ClientDC(self))
241 241
242 242 # Then we call wx.AboutBox giving it that info object
243 wx.AboutBox(info)
244
243 wx.AboutBox(info)
244
245 245 #-----------------------------------------
246 246 #Creating our application
247 #-----------------------------------------
247 #-----------------------------------------
248 248 class MyApp(wx.PySimpleApp):
249 249 """Creating our application"""
250 250 def __init__(self, sync_ok=False):
251 251 wx.PySimpleApp.__init__(self)
252
252
253 253 self.frame = MyFrame(sync_ok=sync_ok)
254 254 self.frame.Show()
255
255
256 256 #-----------------------------------------
257 257 #Main loop
258 #-----------------------------------------
258 #-----------------------------------------
259 259 def main():
260 260 app = MyApp(is_sync_frontend_ok)
261 261 app.SetTopWindow(app.frame)
@@ -3,18 +3,18 b''
3 3
4 4 Definition of Fundamental Physical Constants, CODATA Recommended Values
5 5
6 Source, Peter J. Mohr and Barry N. Taylor,
6 Source, Peter J. Mohr and Barry N. Taylor,
7 7 CODATA Recommended Values of the Fundamental
8 Physical Constants, 1998
9
10 Website: physics.nist.gov/constants
8 Physical Constants, 1998
9
10 Website: physics.nist.gov/constants
11 11 """
12 12 # License: BSD-like
13 13 # Copyright: Gael Varoquaux (gael.varoquaux@normalesup.org)
14 14
15 15 # inspired by maxima's physconst.mac by Cliff Yapp
16 16
17 #from math import * # math MUST be imported BEFORE PhysicalQInteractive
17 #from math import * # math MUST be imported BEFORE PhysicalQInteractive
18 18 from IPython.extensions.PhysicalQInteractive import PhysicalQuantityInteractive
19 19
20 20 # Math constants:
@@ -111,7 +111,7 b' ueVT_N.__doc__ = """nuclear magneton in eV T-1 """'
111 111 # Atomic and Nuclear Constants
112 112 # General
113 113 #-------------------------------------------------------------------------
114 # fine-structure constant
114 # fine-structure constant
115 115 alpha = 7.297352533E-3
116 116
117 117
@@ -163,19 +163,19 b' me_MeV.__doc__ = """electron mass - energy equivalent in MeV"""'
163 163 # electron-muon mass ratio
164 164 memu = 4.83633210E-3
165 165
166 # electron-tau mass ratio
166 # electron-tau mass ratio
167 167 metau = 2.87555E-4
168 168
169 # electron-proton mass ratio
169 # electron-proton mass ratio
170 170 memp = 5.446170232E-4
171 171
172 # electron-neutron mass ratio
172 # electron-neutron mass ratio
173 173 memn = 5.438673462E-4
174 174
175 # electron-deuteron mass ratio
175 # electron-deuteron mass ratio
176 176 memd = 2.7244371170E-4
177 177
178 # electron to alpha particle mass ratio
178 # electron to alpha particle mass ratio
179 179 memalpha = 1.3709335611E-4
180 180
181 181
@@ -202,31 +202,31 b' sigma_e.__doc__ = """Thomson cross section """'
202 202 u_e = PhysicalQuantityInteractive(-928.476362E-26 , 'J/T')
203 203 u_e.__doc__ = """electron magnetic moment """
204 204
205 # electron magnetic moment to Bohr magneton ratio
205 # electron magnetic moment to Bohr magneton ratio
206 206 ueuB = -1.0011596521869
207 207
208 # electron magnetic moment to nuclear magneton ratio
208 # electron magnetic moment to nuclear magneton ratio
209 209 ueuN = -1838.2819660
210 210
211 # electron magnetic moment anomaly |ue|/uB - 1
211 # electron magnetic moment anomaly |ue|/uB - 1
212 212 a_e = 1.1596521869E-3
213 213
214 # electron g-factor
214 # electron g-factor
215 215 g_e = -2.0023193043737
216 216
217 # electron-muon magnetic moment ratio
217 # electron-muon magnetic moment ratio
218 218 ueuu = 206.7669720
219 219
220 # electron-proton magnetic moment ratio
220 # electron-proton magnetic moment ratio
221 221 ueup = -658.2106875
222 222
223 223 # electron to shielded proton magnetic moment ratio (H2O, sphere, 25 C)
224 224 ueusp = -658.2275954
225 225
226 # electron-neutron magnetic moment ratio
226 # electron-neutron magnetic moment ratio
227 227 ueun = 960.92050
228 228
229 # electron-deuteron magnetic moment ratio
229 # electron-deuteron magnetic moment ratio
230 230 ueud = -2143.923498
231 231
232 232 # electron to shielded helione magnetic moment ratio (gas, sphere, 25 C)
@@ -252,7 +252,7 b' muc2_J.__doc__ = """energy equivalent """'
252 252 muc2_MeV = PhysicalQuantityInteractive(105.6583568 , 'MeV')
253 253 muc2_MeV.__doc__ = """energy equivalent in MeV """
254 254
255 # muon-electron mass ratio
255 # muon-electron mass ratio
256 256 mume = 206.7682657
257 257
258 258 # muon-tau mass ratio
@@ -261,7 +261,7 b' mum = 5.94572E-2'
261 261 # muon-proton mass ratio
262 262 mump = 0.1126095173
263 263
264 # muon-neutron mass ratio
264 # muon-neutron mass ratio
265 265 mumn = 0.1124545079
266 266
267 267
@@ -276,19 +276,19 b' lambda_C_u.__doc__ = """muon Compton wavelength """'
276 276 uu = PhysicalQuantityInteractive(-4.49044813E-26 , 'J/T')
277 277 uu.__doc__ = """muon magnetic moment """
278 278
279 # ratio of muon magnetic moment to Bohr magneton ratio
279 # ratio of muon magnetic moment to Bohr magneton ratio
280 280 uuuB = -4.84197085E-3
281 281
282 # ratio of muon magnetic moment to nuclear magneton ratio
282 # ratio of muon magnetic moment to nuclear magneton ratio
283 283 uuuN = -8.89059770
284 284
285 # muon magnetic moment anomaly |uu|/(e /2mu) - 1
285 # muon magnetic moment anomaly |uu|/(e /2mu) - 1
286 286 a_u = 1.16591602E-3
287 287
288 288 # muon g-factor -2(1 + au)
289 289 g_u = -2.0023318320
290 290
291 # muon-proton magnetic moment ratio
291 # muon-proton magnetic moment ratio
292 292 uuup = -3.18334539
293 293
294 294 # Tau, tau-
@@ -308,16 +308,16 b' mtauc2_J.__doc__ = """tau mass energy equivalent """'
308 308 mtauc2_MeV = PhysicalQuantityInteractive(1777.05 , 'MeV')
309 309 mtauc2_MeV.__doc__ = """tau mass energy equivalent in MeV """
310 310
311 # tau-electron mass ratio
311 # tau-electron mass ratio
312 312 mtaume = 3477.60
313 313
314 # tau-muon mass ratio
314 # tau-muon mass ratio
315 315 mtaumu = 16.8188
316 316
317 # tau-proton mass ratio
317 # tau-proton mass ratio
318 318 mtaump = 1.89396
319 319
320 # tau-neutron mass ratio
320 # tau-neutron mass ratio
321 321 mtaumn = 1.89135
322 322
323 323
@@ -344,16 +344,16 b' mpc2_J.__doc__ = """energy equivalent """'
344 344 mpc2_MeV = PhysicalQuantityInteractive(938.271998 , 'MeV')
345 345 mpc2_MeV.__doc__ = """energy equivalent in MeV """
346 346
347 # proton-electron mass ratio
347 # proton-electron mass ratio
348 348 mpme = 1836.1526675
349 349
350 350 # proton-muon mass ratio
351 351 mpmu = 8.88024408
352 352
353 # proton-tau mass ratio
353 # proton-tau mass ratio
354 354 mpmtau = 0.527994
355 355
356 # proton-neutron mass ratio
356 # proton-neutron mass ratio
357 357 mpmn = 0.99862347855
358 358
359 359
@@ -372,26 +372,26 b' lambda_C_p.__doc__ = """proton Compton wavelength h/mpc """'
372 372 up = PhysicalQuantityInteractive(1.410606633E-26 , 'J/T')
373 373 up.__doc__ = """proton magnetic moment """
374 374
375 # proton magnetic moment to Bohr magneton ratio
375 # proton magnetic moment to Bohr magneton ratio
376 376 upuB = 1.521032203E-3
377 377
378 # proton magnetic moment to nuclear magneton ratio
378 # proton magnetic moment to nuclear magneton ratio
379 379 upuN = 2.792847337
380 380
381 # proton g-factor 2up/uN
381 # proton g-factor 2up/uN
382 382 g_p = 5.585694675
383 383
384 # proton-neutron magnetic moment ratio
384 # proton-neutron magnetic moment ratio
385 385 upun = -1.45989805
386 386
387 387
388 388 usp = PhysicalQuantityInteractive(1.410570399E-26 , 'J/T')
389 389 usp.__doc__ = """shielded proton magnetic moment (H2O, sphere, 25 C)"""
390 390
391 # shielded proton magnetic moment to Bohr magneton ratio
391 # shielded proton magnetic moment to Bohr magneton ratio
392 392 uspuB = 1.520993132E-3
393 393
394 # shielded proton magnetic moment to nuclear magneton ratio
394 # shielded proton magnetic moment to nuclear magneton ratio
395 395 uspuN = 2.792775597
396 396
397 397 # proton magnetic shielding correction 1 - u p/up (H2O, sphere, 25 C)
@@ -422,16 +422,16 b' mnc2_J.__doc__ = """neutron mass energy equivalent """'
422 422 mnc2_MeV = PhysicalQuantityInteractive(939.565330 , 'MeV')
423 423 mnc2_MeV.__doc__ = """neutron mass energy equivalent in MeV """
424 424
425 # neutron-electron mass ratio
425 # neutron-electron mass ratio
426 426 mnme = 1838.6836550
427 427
428 # neutron-muon mass ratio
428 # neutron-muon mass ratio
429 429 mnmu = 8.89248478
430 430
431 # neutron-tau mass ratio
431 # neutron-tau mass ratio
432 432 mnm = 0.528722
433 433
434 # neutron-proton mass ratio
434 # neutron-proton mass ratio
435 435 mnmp = 1.00137841887
436 436
437 437
@@ -446,19 +446,19 b' lambda_C_n.__doc__ = """neutron Compton wavelength"""'
446 446 un = PhysicalQuantityInteractive(-0.96623640E-26 , 'J/T')
447 447 un.__doc__ = """neutron magnetic moment """
448 448
449 # neutron magnetic moment to Bohr magneton ratio
449 # neutron magnetic moment to Bohr magneton ratio
450 450 unuB = -1.04187563E-3
451 451
452 # neutron magnetic moment to nuclear magneton ratio
452 # neutron magnetic moment to nuclear magneton ratio
453 453 unuN = -1.91304272
454 454
455 # neutron g-factor
455 # neutron g-factor
456 456 g_n = -3.82608545
457 457
458 # neutron-electron magnetic moment ratio
458 # neutron-electron magnetic moment ratio
459 459 unue = 1.04066882E-3
460 460
461 # neutron-proton magnetic moment ratio
461 # neutron-proton magnetic moment ratio
462 462 unup = -0.68497934
463 463
464 464 # neutron to shielded proton magnetic moment ratio (H2O, sphere, 25 C)
@@ -486,10 +486,10 b' mdc2_J.__doc__ = """deuteron mass energy equivalent """'
486 486 mdc2_eV = PhysicalQuantityInteractive(1875.612762 , 'MeV')
487 487 mdc2_eV.__doc__ = """deuteron mass energy equivalent in MeV """
488 488
489 # deuteron-electron mass ratio
489 # deuteron-electron mass ratio
490 490 mdme = 3670.4829550
491 491
492 # deuteron-proton mass ratio
492 # deuteron-proton mass ratio
493 493 mdmp = 1.99900750083
494 494
495 495
@@ -500,19 +500,19 b' Molar_d.__doc__ = """deuteron molar mass """'
500 500 ud = PhysicalQuantityInteractive(0.433073457E-26 , 'J/T')
501 501 ud.__doc__ = """deuteron magnetic moment """
502 502
503 # deuteron magnetic moment to Bohr magneton ratio
503 # deuteron magnetic moment to Bohr magneton ratio
504 504 uduB = 0.4669754556E-3
505 505
506 # deuteron magnetic moment to nuclear magneton ratio
506 # deuteron magnetic moment to nuclear magneton ratio
507 507 uduN = 0.8574382284
508 508
509 # deuteron-electron magnetic moment ratio
509 # deuteron-electron magnetic moment ratio
510 510 udue = -4.664345537E-4
511 511
512 # deuteron-proton magnetic moment ratio
512 # deuteron-proton magnetic moment ratio
513 513 udup = 0.3070122083
514 514
515 # deuteron-neutron magnetic moment ratio
515 # deuteron-neutron magnetic moment ratio
516 516 udun = -0.44820652
517 517
518 518 # Helion, h
@@ -532,10 +532,10 b' mhc2_J.__doc__ = """helion mass energy equivalent """'
532 532 mhc2_MeV = PhysicalQuantityInteractive(2808.39132 , 'MeV')
533 533 mhc2_MeV.__doc__ = """helion mass energy equivalent in MeV """
534 534
535 # helion-electron mass ratio
535 # helion-electron mass ratio
536 536 mhme = 5495.885238
537 537
538 # helion-proton mass ratio
538 # helion-proton mass ratio
539 539 mhmp = 2.99315265850
540 540
541 541
@@ -546,10 +546,10 b' Molar_h.__doc__ = """helion molar mass """'
546 546 ush = PhysicalQuantityInteractive(-1.074552967E-26 , 'J/T')
547 547 ush.__doc__ = """shielded helion magnetic moment (gas, sphere, 25 C)"""
548 548
549 # shielded helion magnetic moment to Bohr magneton ratio
549 # shielded helion magnetic moment to Bohr magneton ratio
550 550 ushuB = -1.158671474E-3
551 551
552 # shielded helion magnetic moment to nuclear magneton ratio
552 # shielded helion magnetic moment to nuclear magneton ratio
553 553 ushuN = -2.127497718
554 554
555 555 # shielded helion to proton magnetic moment ratio (gas, sphere, 25 C)
@@ -562,7 +562,7 b' ushusp = -0.7617861313'
562 562 gamma_h = PhysicalQuantityInteractive(2.037894764E8 , '1/(s*T)')
563 563 gamma_h.__doc__ = """shielded helion gyromagnetic (gas, sphere, 25 C) """
564 564
565 # Alpha particle,
565 # Alpha particle,
566 566 #-------------------------------------------------------------------------
567 567
568 568 m_alpha = PhysicalQuantityInteractive(6.64465598E-27 , 'kg')
@@ -579,10 +579,10 b' malphac2_J.__doc__ = """alpha particle mass energy equivalent """'
579 579 malphac2_MeV = PhysicalQuantityInteractive(3727.37904 , 'MeV')
580 580 malphac2_MeV.__doc__ = """alpha particle mass energy equivalent in MeV """
581 581
582 # alpha particle to electron mass ratio
582 # alpha particle to electron mass ratio
583 583 malphame = 7294.299508
584 584
585 # alpha particle to proton mass ratio
585 # alpha particle to proton mass ratio
586 586 malphamp = 3.9725996846
587 587
588 588
@@ -642,9 +642,9 b" Vm_2 = PhysicalQuantityInteractive(22.710981E-3 , 'm**3/mol')"
642 642 Vm_2.__doc__ = """molar volume of ideal gas RT/p T = 273.15 K, p = 100 kPa """
643 643
644 644 # Sackur-Tetrode constant (absolute entropy constant) 52 + ln_(2 mukT1/h2)3/2kT1/p0
645 # T1 = 1 K, p0 = 100 kPa
645 # T1 = 1 K, p0 = 100 kPa
646 646 S_0R_1 = -1.1517048
647 # T1 = 1 K, p0 = 101.325 kPa
647 # T1 = 1 K, p0 = 101.325 kPa
648 648 S_0R_2 = -1.1648678
649 649
650 650
@@ -1,10 +1,10 b''
1 """ Set default options for IPython.
1 """ Set default options for IPython.
2 2
3 3 Just import this module to get reasonable defaults for everything.
4 4
5 These configurations used to be performed in ipythonrc (or ipythonrc.ini).
5 These configurations used to be performed in ipythonrc (or ipythonrc.ini).
6 6 Therefore importing this in your config files makes ipython basically
7 ignore your ipythonrc. This is *not* imported by default, you need to import
7 ignore your ipythonrc. This is *not* imported by default, you need to import
8 8 this manually in one of your config files.
9 9
10 10 You can further override these defaults in e.g. your ipy_user_config.py,
@@ -58,5 +58,5 b' set show-all-if-ambiguous on'
58 58 if readline.have_readline:
59 59 for cmd in rlopts.split('\n'):
60 60 readline.parse_and_bind(cmd)
61
62
61
62
@@ -2,7 +2,7 b''
2 2
3 3 Start ipython in shell mode by invoking "ipython -p sh"
4 4
5 (the old version, "ipython -p pysh" still works but this is the more "modern"
5 (the old version, "ipython -p pysh" still works but this is the more "modern"
6 6 shell mode and is recommended for users who don't care about pysh-mode
7 7 compatibility)
8 8 """
@@ -16,29 +16,29 b' import os,re,textwrap'
16 16
17 17 import ipy_defaults
18 18
19 def main():
19 def main():
20 20 ip = ipapi.get()
21 21 o = ip.options
22 22 # autocall to "full" mode (smart mode is default, I like full mode)
23
23
24 24 o.autocall = 2
25
25
26 26 # Jason Orendorff's path class is handy to have in user namespace
27 27 # if you are doing shell-like stuff
28 28 try:
29 29 ip.ex("from IPython.external.path import path" )
30 30 except ImportError:
31 31 pass
32
32
33 33 # beefed up %env is handy in shell mode
34 34 import envpersist
35
36 # To see where mycmd resides (in path/aliases), do %which mycmd
35
36 # To see where mycmd resides (in path/aliases), do %which mycmd
37 37 import ipy_which
38
38
39 39 # tab completers for hg, svn, ...
40 40 import ipy_app_completers
41
41
42 42 # To make executables foo and bar in mybin usable without PATH change, do:
43 43 # %rehashdir c:/mybin
44 44 # %store foo
@@ -47,45 +47,45 b' def main():'
47 47
48 48 # does not work without subprocess module!
49 49 #import ipy_signals
50
50
51 51 ip.ex('import os')
52 52 ip.ex("def up(): os.chdir('..')")
53 ip.user_ns['LA'] = LastArgFinder()
54
55 # You can assign to _prompt_title variable
53 ip.user_ns['LA'] = LastArgFinder()
54
55 # You can assign to _prompt_title variable
56 56 # to provide some extra information for prompt
57 57 # (e.g. the current mode, host/username...)
58 58
59 59 ip.user_ns['_prompt_title'] = ''
60
60
61 61 # Nice prompt
62 62 o.prompt_in1= r'\C_Green${_prompt_title}\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> '
63 63 o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green> '
64 64 o.prompt_out= '<\#> '
65
65
66 66 from IPython.core import release
67 67
68 68 import sys
69 69 # Non-chatty banner
70 70 o.banner = "IPython %s [on Py %s]\n" % (release.version,sys.version.split(None,1)[0])
71
72
71
72
73 73 ip.default_option('cd','-q')
74 74 ip.default_option('macro', '-r')
75 # If you only rarely want to execute the things you %edit...
75 # If you only rarely want to execute the things you %edit...
76 76 #ip.default_option('edit','-x')
77
77
78 78
79 79 o.prompts_pad_left="1"
80 80 # Remove all blank lines in between prompts, like a normal shell.
81 81 o.separate_in="0"
82 82 o.separate_out="0"
83 83 o.separate_out2="0"
84
84
85 85 # now alias all syscommands
86
86
87 87 db = ip.db
88
88
89 89 syscmds = db.get("syscmdlist",[] )
90 90 if not syscmds:
91 91 print textwrap.dedent("""
@@ -95,47 +95,47 b' def main():'
95 95 """)
96 96 ip.magic('rehashx')
97 97 syscmds = db.get("syscmdlist")
98
98
99 99 # lowcase aliases on win32 only
100 100 if os.name == 'posix':
101 101 mapper = lambda s:s
102 102 else:
103 103 def mapper(s): return s.lower()
104
104
105 105 for cmd in syscmds:
106 106 # print "sys",cmd #dbg
107 107 noext, ext = os.path.splitext(cmd)
108 108 if ext.lower() == '.exe':
109 109 cmd = noext
110
110
111 111 key = mapper(cmd)
112 112 if key not in ip.alias_manager.alias_table:
113 113 # Dots will be removed from alias names, since ipython
114 114 # assumes names with dots to be python code
115
115
116 116 ip.define_alias(key.replace('.',''), cmd)
117 117
118 118 # mglob combines 'find', recursion, exclusion... '%mglob?' to learn more
119 ip.load("IPython.external.mglob")
119 ip.load("IPython.external.mglob")
120 120
121 121 # win32 is crippled w/o cygwin, try to help it a little bit
122 122 if sys.platform == 'win32':
123 if 'cygwin' in os.environ['PATH'].lower():
123 if 'cygwin' in os.environ['PATH'].lower():
124 124 # use the colors of cygwin ls (recommended)
125 125 ip.define_alias('d', 'ls -F --color=auto')
126 126 else:
127 127 # get icp, imv, imkdir, igrep, irm,...
128 128 ip.load('ipy_fsops')
129
129
130 130 # and the next best thing to real 'ls -F'
131 131 ip.define_alias('d','dir /w /og /on')
132
132
133 133 ip.set_hook('input_prefilter', slash_prefilter_f)
134 134 extend_shell_behavior(ip)
135 135
136 136 class LastArgFinder:
137 137 """ Allow $LA to work as "last argument of previous command", like $! in bash
138
138
139 139 To call this in normal IPython code, do LA()
140 140 """
141 141 def __call__(self, hist_idx = None):
@@ -144,7 +144,7 b' class LastArgFinder:'
144 144 return str(self)
145 145 return ip.input_hist_raw[hist_idx].strip().split()[-1]
146 146 def __str__(self):
147 ip = ipapi.get()
147 ip = ipapi.get()
148 148 for cmd in reversed(ip.input_hist_raw):
149 149 parts = cmd.strip().split()
150 150 if len(parts) < 2 or parts[-1] in ['$LA', 'LA()']:
@@ -154,7 +154,7 b' class LastArgFinder:'
154 154
155 155 def slash_prefilter_f(self,line):
156 156 """ ./foo, ~/foo and /bin/foo now run foo as system command
157
157
158 158 Removes the need for doing !./foo, !~/foo or !/bin/foo
159 159 """
160 160 from IPython.utils import genutils
@@ -253,7 +253,7 b' def extend_shell_behavior(ip):'
253 253 if command or more:
254 254 # push to raw history, so hist line numbers stay in sync
255 255 ip.input_hist_raw.append("# " + command + "\n")
256
256
257 257 more = ip.push_line(ip.prefilter(command,more))
258 258 command = ''
259 259 # IPython's runsource returns None if there was an error
@@ -186,7 +186,7 b' class ZopeDebug(object):'
186 186 query = {}
187 187 if indexes.get('path'):
188 188 from string import join
189 path = join(obj.getPhysicalPath(), '/')
189 path = join(obj.getPhysicalPath(), '/')
190 190 query.update({'path': path})
191 191 if indexes.get('getID'):
192 192 query.update({'getID': obj.id, })
@@ -288,7 +288,7 b' def main():'
288 288 ip = ipapi.get()
289 289 o = ip.options
290 290 # autocall to "full" mode (smart mode is default, I like full mode)
291
291
292 292 SOFTWARE_HOME = os.environ.get( "SOFTWARE_HOME" )
293 293 sys.path.append( SOFTWARE_HOME )
294 294 print "SOFTWARE_HOME=%s\n" % SOFTWARE_HOME
@@ -310,7 +310,7 b' def main():'
310 310 app
311 311 portal
312 312 utils.{ %s }
313
313
314 314 Uses the $SOFTWARE_HOME and $CONFIG_FILE environment
315 315 variables.
316 316 """ % ( ",".join([ x for x in dir(zope_debug.utils) if not x.startswith("_") ] ) ) )
@@ -1,10 +1,10 b''
1 1 """ Integration with gvim, by Erich Heine
2 2
3 Provides a %vim magic command, and reuses the same vim session. Uses
4 unix domain sockets for communication between vim and IPython. ipy.vim is
3 Provides a %vim magic command, and reuses the same vim session. Uses
4 unix domain sockets for communication between vim and IPython. ipy.vim is
5 5 available in doc/examples of the IPython distribution.
6 6
7 Slightly touched up email announcement (and description how to use it) by
7 Slightly touched up email announcement (and description how to use it) by
8 8 Erich Heine is here:
9 9
10 10 Ive recently been playing with ipython, and like it quite a bit. I did
@@ -22,7 +22,7 b' for having gvim and ipython work very nicely together. Ive attached'
22 22 both to this email (hoping of course that the mailing list allows such
23 23 things).
24 24
25 There are 2 files:
25 There are 2 files:
26 26
27 27 ipy_vimserver.py -- this file contains the ipython stuff
28 28 ipy.vim -- this file contains the gvim stuff
@@ -40,7 +40,7 b' from Numeric import *'
40 40 inf = infty = Infinity = (array([1])/0.0)[0]
41 41
42 42 #****************************************************************************
43 # function definitions
43 # function definitions
44 44 exp_safe_MIN = math.log(2.2250738585072014e-308)
45 45 exp_safe_MAX = 1.7976931348623157e+308
46 46
@@ -140,12 +140,12 b' def norm(a,p=2):'
140 140
141 141 Ref: http://mathworld.wolfram.com/VectorNorm.html
142 142 http://mathworld.wolfram.com/L-Infinity-Norm.html"""
143
143
144 144 if p in ('inf','Infinity'):
145 145 return max(absolute(a).flat)
146 146 else:
147 return (sum_flat(absolute(a)**p))**(1.0/p)
148
147 return (sum_flat(absolute(a)**p))**(1.0/p)
148
149 149 def frange(xini,xfin=None,delta=None,**kw):
150 150 """frange([start,] stop[, step, keywords]) -> array of floats
151 151
@@ -183,14 +183,14 b' def frange(xini,xfin=None,delta=None,**kw):'
183 183 #defaults
184 184 kw.setdefault('closed',1)
185 185 endpoint = kw['closed'] != 0
186
186
187 187 # funny logic to allow the *first* argument to be optional (like range())
188 188 # This was modified with a simpler version from a similar frange() found
189 189 # at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66472
190 190 if xfin == None:
191 191 xfin = xini + 0.0
192 192 xini = 0.0
193
193
194 194 if delta == None:
195 195 delta = 1.0
196 196
@@ -223,7 +223,7 b" def identity(n,rank=2,typecode='l'):"
223 223
224 224 Since rank defaults to 2, this function behaves in the default case (when
225 225 only n is given) like the Numeric identity function."""
226
226
227 227 iden = zeros((n,)*rank,typecode=typecode)
228 228 for i in range(n):
229 229 idx = (i,)*rank
@@ -250,7 +250,7 b' def binary_repr(number, max_length = 1025):'
250 250 Increase the value of max_length for very large numbers. Note that on
251 251 32-bit machines, 2**1023 is the largest integer power of 2 which can be
252 252 converted to a Python float."""
253
253
254 254 assert number < 2L << max_length
255 255 shifts = map (operator.rshift, max_length * [number], \
256 256 range (max_length - 1, -1, -1))
@@ -261,7 +261,7 b' def binary_repr(number, max_length = 1025):'
261 261
262 262 def log2(x,ln2 = math.log(2.0)):
263 263 """Return the log(x) in base 2.
264
264
265 265 This is a _slow_ function but which is guaranteed to return the correct
266 266 integer value if the input is an ineger exact power of 2."""
267 267
@@ -288,7 +288,7 b' def ispower2(n):'
288 288
289 289 def fromfunction_kw(function, dimensions, **kwargs):
290 290 """Drop-in replacement for fromfunction() from Numerical Python.
291
291
292 292 Allows passing keyword arguments to the desired function.
293 293
294 294 Call it as (keywords are optional):
@@ -38,10 +38,10 b' class AsyncFrontEndBase(FrontEndBase):'
38 38 Overrides FrontEndBase to wrap execute in a deferred result.
39 39 All callbacks are made as callbacks on the deferred result.
40 40 """
41
41
42 42 implements(IFrontEnd)
43 43 classProvides(IFrontEndFactory)
44
44
45 45 def __init__(self, engine=None, history=None):
46 46 assert(engine==None or IEngineCore.providedBy(engine))
47 47 self.engine = IEngineCore(engine)
@@ -49,26 +49,26 b' class AsyncFrontEndBase(FrontEndBase):'
49 49 self.history = FrontEndHistory(input_cache=[''])
50 50 else:
51 51 self.history = history
52
52
53 53 def execute(self, block, blockID=None):
54 54 """Execute the block and return the deferred result.
55
55
56 56 Parameters:
57 57 block : {str, AST}
58 58 blockID : any
59 Caller may provide an ID to identify this block.
59 Caller may provide an ID to identify this block.
60 60 result['blockID'] := blockID
61
61
62 62 Result:
63 63 Deferred result of self.interpreter.execute
64 64 """
65
65
66 66 if(not self.is_complete(block)):
67 67 return Failure(Exception("Block is not compilable"))
68
68
69 69 if(blockID == None):
70 blockID = guid.generate()
71
70 blockID = guid.generate()
71
72 72 d = self.engine.execute(block)
73 73 d.addCallback(self._add_history, block=block)
74 74 d.addCallbacks(self._add_block_id_for_result,
@@ -76,7 +76,7 b' class AsyncFrontEndBase(FrontEndBase):'
76 76 callbackArgs=(blockID,),
77 77 errbackArgs=(blockID,))
78 78 d.addBoth(self.update_cell_prompt, blockID=blockID)
79 d.addCallbacks(self.render_result,
79 d.addCallbacks(self.render_result,
80 80 errback=self.render_error)
81
81
82 82 return d
@@ -1,10 +1,10 b''
1 1 # encoding: utf-8
2 2 # -*- test-case-name: IPython.frontend.cocoa.tests.test_cocoa_frontend -*-
3 3
4 """PyObjC classes to provide a Cocoa frontend to the
4 """PyObjC classes to provide a Cocoa frontend to the
5 5 IPython.kernel.engineservice.IEngineBase.
6 6
7 To add an IPython interpreter to a cocoa app, instantiate an
7 To add an IPython interpreter to a cocoa app, instantiate an
8 8 IPythonCocoaController in a XIB and connect its textView outlet to an
9 9 NSTextView instance in your UI. That's it.
10 10
@@ -32,7 +32,7 b' from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\\'
32 32 NSLog, NSNotificationCenter, NSMakeRange,\
33 33 NSLocalizedString, NSIntersectionRange,\
34 34 NSString, NSAutoreleasePool
35
35
36 36 from AppKit import NSApplicationWillTerminateNotification, NSBeep,\
37 37 NSTextView, NSRulerView, NSVerticalRuler
38 38
@@ -49,14 +49,14 b' from twisted.python.failure import Failure'
49 49 # Classes to implement the Cocoa frontend
50 50 #-----------------------------------------------------------------------------
51 51
52 # TODO:
53 # 1. use MultiEngineClient and out-of-process engine rather than
52 # TODO:
53 # 1. use MultiEngineClient and out-of-process engine rather than
54 54 # ThreadedEngineService?
55 55 # 2. integrate Xgrid launching of engines
56
56
57 57 class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):
58 58 """Wrap all blocks in an NSAutoreleasePool"""
59
59
60 60 def wrapped_execute(self, msg, lines):
61 61 """wrapped_execute"""
62 62 try:
@@ -65,9 +65,9 b' class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService):'
65 65 self).wrapped_execute(msg, lines)
66 66 finally:
67 67 p.drain()
68
68
69 69 return result
70
70
71 71
72 72
73 73 class Cell(NSObject):
@@ -75,20 +75,20 b' class Cell(NSObject):'
75 75 Representation of the prompts, input and output of a cell in the
76 76 frontend
77 77 """
78
78
79 79 blockNumber = objc.ivar().unsigned_long()
80 80 blockID = objc.ivar()
81 81 inputBlock = objc.ivar()
82 82 output = objc.ivar()
83
84 83
85
84
85
86 86 class CellBlock(object):
87 87 """
88 88 Storage for information about text ranges relating to a single cell
89 89 """
90 90
91
91
92 92 def __init__(self, inputPromptRange, inputRange=None, outputPromptRange=None,
93 93 outputRange=None):
94 94 super(CellBlock, self).__init__()
@@ -96,10 +96,10 b' class CellBlock(object):'
96 96 self.inputRange = inputRange
97 97 self.outputPromptRange = outputPromptRange
98 98 self.outputRange = outputRange
99
99
100 100 def update_ranges_for_insertion(self, text, textRange):
101 101 """Update ranges for text insertion at textRange"""
102
102
103 103 for r in [self.inputPromptRange,self.inputRange,
104 104 self.outputPromptRange, self.outputRange]:
105 105 if(r == None):
@@ -117,11 +117,11 b' class CellBlock(object):'
117 117 r.length += len(text) - intersection.length
118 118 else:
119 119 r.length -= intersection.length
120
121
120
121
122 122 def update_ranges_for_deletion(self, textRange):
123 123 """Update ranges for text deletion at textRange"""
124
124
125 125 for r in [self.inputPromptRange,self.inputRange,
126 126 self.outputPromptRange, self.outputRange]:
127 127 if(r==None):
@@ -139,52 +139,52 b' class CellBlock(object):'
139 139 r.length += intersection.length
140 140 else:
141 141 r.length -= intersection.length
142
142
143 143 def __repr__(self):
144 144 return 'CellBlock('+ str((self.inputPromptRange,
145 145 self.inputRange,
146 146 self.outputPromptRange,
147 147 self.outputRange)) + ')'
148
149 148
150 149
151
150
151
152 152 class IPythonCocoaController(NSObject, AsyncFrontEndBase):
153 153 userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value))
154 154 waitingForEngine = objc.ivar().bool()
155 155 textView = objc.IBOutlet()
156
156
157 157 def init(self):
158 158 self = super(IPythonCocoaController, self).init()
159 159 AsyncFrontEndBase.__init__(self,
160 160 engine=AutoreleasePoolWrappedThreadedEngineService())
161 161 if(self != None):
162 162 self._common_init()
163
163
164 164 return self
165
165
166 166 def _common_init(self):
167 167 """_common_init"""
168
168
169 169 self.userNS = NSMutableDictionary.dictionary()
170 170 self.waitingForEngine = False
171
171
172 172 self.lines = {}
173 173 self.tabSpaces = 4
174 174 self.tabUsesSpaces = True
175 175 self.currentBlockID = self.next_block_ID()
176 176 self.blockRanges = {} # blockID=>CellBlock
177
178
177
178
179 179 def awakeFromNib(self):
180 180 """awakeFromNib"""
181
181
182 182 self._common_init()
183
183
184 184 # Start the IPython engine
185 185 self.engine.startService()
186 186 NSLog('IPython engine started')
187
187
188 188 # Register for app termination
189 189 nc = NSNotificationCenter.defaultCenter()
190 190 nc.addObserver_selector_name_object_(
@@ -192,7 +192,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
192 192 'appWillTerminate:',
193 193 NSApplicationWillTerminateNotification,
194 194 None)
195
195
196 196 self.textView.setDelegate_(self)
197 197 self.textView.enclosingScrollView().setHasVerticalRuler_(True)
198 198 r = NSRulerView.alloc().initWithScrollView_orientation_(
@@ -202,30 +202,30 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
202 202 self.verticalRulerView.setClientView_(self.textView)
203 203 self._start_cli_banner()
204 204 self.start_new_block()
205
206
205
206
207 207 def appWillTerminate_(self, notification):
208 208 """appWillTerminate"""
209
209
210 210 self.engine.stopService()
211
212
211
212
213 213 def complete(self, token):
214 214 """Complete token in engine's user_ns
215
215
216 216 Parameters
217 217 ----------
218 218 token : string
219
219
220 220 Result
221 221 ------
222 Deferred result of
222 Deferred result of
223 223 IPython.kernel.engineservice.IEngineBase.complete
224 224 """
225
225
226 226 return self.engine.complete(token)
227
228
227
228
229 229 def execute(self, block, blockID=None):
230 230 self.waitingForEngine = True
231 231 self.willChangeValueForKey_('commandHistory')
@@ -233,87 +233,87 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
233 233 blockID)
234 234 d.addBoth(self._engine_done)
235 235 d.addCallback(self._update_user_ns)
236
236
237 237 return d
238
239
238
239
240 240 def push_(self, namespace):
241 241 """Push dictionary of key=>values to python namespace"""
242
242
243 243 self.waitingForEngine = True
244 244 self.willChangeValueForKey_('commandHistory')
245 245 d = self.engine.push(namespace)
246 246 d.addBoth(self._engine_done)
247 247 d.addCallback(self._update_user_ns)
248
249
248
249
250 250 def pull_(self, keys):
251 251 """Pull keys from python namespace"""
252
252
253 253 self.waitingForEngine = True
254 254 result = blockingCallFromThread(self.engine.pull, keys)
255 255 self.waitingForEngine = False
256
256
257 257 @objc.signature('v@:@I')
258 258 def executeFileAtPath_encoding_(self, path, encoding):
259 259 """Execute file at path in an empty namespace. Update the engine
260 260 user_ns with the resulting locals."""
261
261
262 262 lines,err = NSString.stringWithContentsOfFile_encoding_error_(
263 263 path,
264 264 encoding,
265 265 None)
266 266 self.engine.execute(lines)
267
268
267
268
269 269 def _engine_done(self, x):
270 270 self.waitingForEngine = False
271 271 self.didChangeValueForKey_('commandHistory')
272 272 return x
273
273
274 274 def _update_user_ns(self, result):
275 275 """Update self.userNS from self.engine's namespace"""
276 276 d = self.engine.keys()
277 277 d.addCallback(self._get_engine_namespace_values_for_keys)
278
278
279 279 return result
280
281
280
281
282 282 def _get_engine_namespace_values_for_keys(self, keys):
283 283 d = self.engine.pull(keys)
284 284 d.addCallback(self._store_engine_namespace_values, keys=keys)
285
286
285
286
287 287 def _store_engine_namespace_values(self, values, keys=[]):
288 288 assert(len(values) == len(keys))
289 289 self.willChangeValueForKey_('userNS')
290 290 for (k,v) in zip(keys,values):
291 291 self.userNS[k] = saferepr(v)
292 292 self.didChangeValueForKey_('userNS')
293
294
293
294
295 295 def update_cell_prompt(self, result, blockID=None):
296 296 print self.blockRanges
297 297 if(isinstance(result, Failure)):
298 298 prompt = self.input_prompt()
299
299
300 300 else:
301 301 prompt = self.input_prompt(number=result['number'])
302
302
303 303 r = self.blockRanges[blockID].inputPromptRange
304 304 self.insert_text(prompt,
305 305 textRange=r,
306 306 scrollToVisible=False
307 307 )
308
308
309 309 return result
310
311
310
311
312 312 def render_result(self, result):
313 313 blockID = result['blockID']
314 314 inputRange = self.blockRanges[blockID].inputRange
315 315 del self.blockRanges[blockID]
316
316
317 317 #print inputRange,self.current_block_range()
318 318 self.insert_text('\n' +
319 319 self.output_prompt(number=result['number']) +
@@ -322,8 +322,8 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
322 322 textRange=NSMakeRange(inputRange.location+inputRange.length,
323 323 0))
324 324 return result
325
326
325
326
327 327 def render_error(self, failure):
328 328 print failure
329 329 blockID = failure.blockID
@@ -338,82 +338,82 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
338 338 0))
339 339 self.start_new_block()
340 340 return failure
341
342
341
342
343 343 def _start_cli_banner(self):
344 344 """Print banner"""
345
345
346 346 banner = """IPython1 %s -- An enhanced Interactive Python.""" % \
347 347 IPython.__version__
348
348
349 349 self.insert_text(banner + '\n\n')
350
351
350
351
352 352 def start_new_block(self):
353 353 """"""
354
354
355 355 self.currentBlockID = self.next_block_ID()
356 356 self.blockRanges[self.currentBlockID] = self.new_cell_block()
357 self.insert_text(self.input_prompt(),
357 self.insert_text(self.input_prompt(),
358 358 textRange=self.current_block_range().inputPromptRange)
359
360
361
359
360
361
362 362 def next_block_ID(self):
363
364 return guid.generate()
365
363
364 return guid.generate()
365
366 366 def new_cell_block(self):
367 367 """A new CellBlock at the end of self.textView.textStorage()"""
368
369 return CellBlock(NSMakeRange(self.textView.textStorage().length(),
368
369 return CellBlock(NSMakeRange(self.textView.textStorage().length(),
370 370 0), #len(self.input_prompt())),
371 371 NSMakeRange(self.textView.textStorage().length(),# + len(self.input_prompt()),
372 372 0))
373
374
373
374
375 375 def current_block_range(self):
376 return self.blockRanges.get(self.currentBlockID,
376 return self.blockRanges.get(self.currentBlockID,
377 377 self.new_cell_block())
378
378
379 379 def current_block(self):
380 380 """The current block's text"""
381
381
382 382 return self.text_for_range(self.current_block_range().inputRange)
383
383
384 384 def text_for_range(self, textRange):
385 385 """text_for_range"""
386
386
387 387 ts = self.textView.textStorage()
388 388 return ts.string().substringWithRange_(textRange)
389
389
390 390 def current_line(self):
391 391 block = self.text_for_range(self.current_block_range().inputRange)
392 392 block = block.split('\n')
393 393 return block[-1]
394
395
394
395
396 396 def insert_text(self, string=None, textRange=None, scrollToVisible=True):
397 """Insert text into textView at textRange, updating blockRanges
397 """Insert text into textView at textRange, updating blockRanges
398 398 as necessary
399 399 """
400 400 if(textRange == None):
401 401 #range for end of text
402 textRange = NSMakeRange(self.textView.textStorage().length(), 0)
403
404
402 textRange = NSMakeRange(self.textView.textStorage().length(), 0)
403
404
405 405 self.textView.replaceCharactersInRange_withString_(
406 406 textRange, string)
407
407
408 408 for r in self.blockRanges.itervalues():
409 409 r.update_ranges_for_insertion(string, textRange)
410
410
411 411 self.textView.setSelectedRange_(textRange)
412 412 if(scrollToVisible):
413 413 self.textView.scrollRangeToVisible_(textRange)
414
415
416
414
415
416
417 417 def replace_current_block_with_string(self, textView, string):
418 418 textView.replaceCharactersInRange_withString_(
419 419 self.current_block_range().inputRange,
@@ -422,53 +422,53 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
422 422 r = NSMakeRange(textView.textStorage().length(), 0)
423 423 textView.scrollRangeToVisible_(r)
424 424 textView.setSelectedRange_(r)
425
426
425
426
427 427 def current_indent_string(self):
428 428 """returns string for indent or None if no indent"""
429
429
430 430 return self._indent_for_block(self.current_block())
431
432
431
432
433 433 def _indent_for_block(self, block):
434 434 lines = block.split('\n')
435 435 if(len(lines) > 1):
436 436 currentIndent = len(lines[-1]) - len(lines[-1].lstrip())
437 437 if(currentIndent == 0):
438 438 currentIndent = self.tabSpaces
439
439
440 440 if(self.tabUsesSpaces):
441 441 result = ' ' * currentIndent
442 442 else:
443 443 result = '\t' * (currentIndent/self.tabSpaces)
444 444 else:
445 445 result = None
446
446
447 447 return result
448
449
448
449
450 450 # NSTextView delegate methods...
451 451 def textView_doCommandBySelector_(self, textView, selector):
452 452 assert(textView == self.textView)
453 453 NSLog("textView_doCommandBySelector_: "+selector)
454
455
454
455
456 456 if(selector == 'insertNewline:'):
457 457 indent = self.current_indent_string()
458 458 if(indent):
459 459 line = indent + self.current_line()
460 460 else:
461 461 line = self.current_line()
462
462
463 463 if(self.is_complete(self.current_block())):
464 464 self.execute(self.current_block(),
465 465 blockID=self.currentBlockID)
466 466 self.start_new_block()
467
467
468 468 return True
469
469
470 470 return False
471
471
472 472 elif(selector == 'moveUp:'):
473 473 prevBlock = self.get_history_previous(self.current_block())
474 474 if(prevBlock != None):
@@ -476,7 +476,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
476 476 else:
477 477 NSBeep()
478 478 return True
479
479
480 480 elif(selector == 'moveDown:'):
481 481 nextBlock = self.get_history_next()
482 482 if(nextBlock != None):
@@ -484,10 +484,10 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
484 484 else:
485 485 NSBeep()
486 486 return True
487
487
488 488 elif(selector == 'moveToBeginningOfParagraph:'):
489 489 textView.setSelectedRange_(NSMakeRange(
490 self.current_block_range().inputRange.location,
490 self.current_block_range().inputRange.location,
491 491 0))
492 492 return True
493 493 elif(selector == 'moveToEndOfParagraph:'):
@@ -499,16 +499,16 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
499 499 if(textView.selectedRange().location <= \
500 500 self.current_block_range().location):
501 501 raise NotImplemented()
502
502
503 503 return False # don't actually handle the delete
504
504
505 505 elif(selector == 'insertTab:'):
506 506 if(len(self.current_line().strip()) == 0): #only white space
507 507 return False
508 508 else:
509 509 self.textView.complete_(self)
510 510 return True
511
511
512 512 elif(selector == 'deleteBackward:'):
513 513 #if we're at the beginning of the current block, ignore
514 514 if(textView.selectedRange().location == \
@@ -523,17 +523,17 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
523 523 r.update_ranges_for_deletion(deleteRange)
524 524 return False
525 525 return False
526
527
528 def textView_shouldChangeTextInRanges_replacementStrings_(self,
526
527
528 def textView_shouldChangeTextInRanges_replacementStrings_(self,
529 529 textView, ranges, replacementStrings):
530 530 """
531 531 Delegate method for NSTextView.
532
533 Refuse change text in ranges not at end, but make those changes at
532
533 Refuse change text in ranges not at end, but make those changes at
534 534 end.
535 535 """
536
536
537 537 assert(len(ranges) == len(replacementStrings))
538 538 allow = True
539 539 for r,s in zip(ranges, replacementStrings):
@@ -542,10 +542,10 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
542 542 r.location < self.current_block_range().inputRange.location):
543 543 self.insert_text(s)
544 544 allow = False
545
545
546 546 return allow
547
548 def textView_completions_forPartialWordRange_indexOfSelectedItem_(self,
547
548 def textView_completions_forPartialWordRange_indexOfSelectedItem_(self,
549 549 textView, words, charRange, index):
550 550 try:
551 551 ts = textView.textStorage()
@@ -554,7 +554,7 b' class IPythonCocoaController(NSObject, AsyncFrontEndBase):'
554 554 except:
555 555 completions = objc.nil
556 556 NSBeep()
557
557
558 558 return (completions,0)
559
559
560 560
@@ -2,7 +2,7 b''
2 2 """
3 3 setup.py
4 4
5 Setuptools installer script for generating a Cocoa plugin for the
5 Setuptools installer script for generating a Cocoa plugin for the
6 6 IPython cocoa frontend
7 7
8 8 Author: Barry Wark
@@ -1,18 +1,18 b''
1 1 # encoding: utf-8
2 """This file contains unittests for the
2 """This file contains unittests for the
3 3 IPython.frontend.cocoa.cocoa_frontend module.
4 4 """
5 5 __docformat__ = "restructuredtext en"
6
6
7 7 #---------------------------------------------------------------------------
8 # Copyright (C) 2005 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
8 # Copyright (C) 2005 The IPython Development Team
9 #
10 # Distributed under the terms of the BSD License. The full license is in
11 # the file COPYING, distributed as part of this software.
12 12 #---------------------------------------------------------------------------
13
13
14 14 #---------------------------------------------------------------------------
15 # Imports
15 # Imports
16 16 #---------------------------------------------------------------------------
17 17
18 18 # Tell nose to skip this module
@@ -84,14 +84,14 b' class TestIPythonCocoaControler(unittest.TestCase):'
84 84 """test that current_indent_string returns current indent or None.
85 85 Uses _indent_for_block for direct unit testing.
86 86 """
87
87
88 88 self.controller.tabUsesSpaces = True
89 89 self.assert_(self.controller._indent_for_block("""a=3""") == None)
90 90 self.assert_(self.controller._indent_for_block("") == None)
91 91 block = """def test():\n a=3"""
92 92 self.assert_(self.controller._indent_for_block(block) == \
93 93 ' ' * self.controller.tabSpaces)
94
94
95 95 block = """if(True):\n%sif(False):\n%spass""" % \
96 96 (' '*self.controller.tabSpaces,
97 97 2*' '*self.controller.tabSpaces)
@@ -1,10 +1,10 b''
1 1 # encoding: utf-8
2 2 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*-
3 3 """
4 frontendbase provides an interface and base class for GUI frontends for
4 frontendbase provides an interface and base class for GUI frontends for
5 5 IPython.kernel/IPython.kernel.core.
6 6
7 Frontend implementations will likely want to subclass FrontEndBase.
7 Frontend implementations will likely want to subclass FrontEndBase.
8 8
9 9 Author: Barry Wark
10 10 """
@@ -26,8 +26,8 b' from IPython.external import guid'
26 26
27 27
28 28 from IPython.frontend.zopeinterface import (
29 Interface,
30 Attribute,
29 Interface,
30 Attribute,
31 31 )
32 32 from IPython.kernel.core.history import FrontEndHistory
33 33 from IPython.kernel.core.util import Bunch
@@ -47,103 +47,103 b" rc.prompt_out = r'Out [$number]: '"
47 47
48 48 class IFrontEndFactory(Interface):
49 49 """Factory interface for frontends."""
50
50
51 51 def __call__(engine=None, history=None):
52 52 """
53 53 Parameters:
54 54 interpreter : IPython.kernel.engineservice.IEngineCore
55 55 """
56
56
57 57 pass
58 58
59 59
60 60 class IFrontEnd(Interface):
61 61 """Interface for frontends. All methods return t.i.d.Deferred"""
62
62
63 63 Attribute("input_prompt_template", "string.Template instance\
64 64 substituteable with execute result.")
65 65 Attribute("output_prompt_template", "string.Template instance\
66 66 substituteable with execute result.")
67 67 Attribute("continuation_prompt_template", "string.Template instance\
68 68 substituteable with execute result.")
69
69
70 70 def update_cell_prompt(result, blockID=None):
71 """Subclass may override to update the input prompt for a block.
71 """Subclass may override to update the input prompt for a block.
72 72
73 73 In asynchronous frontends, this method will be called as a
74 74 twisted.internet.defer.Deferred's callback/errback.
75 75 Implementations should thus return result when finished.
76
76
77 77 Result is a result dict in case of success, and a
78 78 twisted.python.util.failure.Failure in case of an error
79 79 """
80
80
81 81 pass
82
82
83 83 def render_result(result):
84 84 """Render the result of an execute call. Implementors may choose the
85 85 method of rendering.
86 For example, a notebook-style frontend might render a Chaco plot
86 For example, a notebook-style frontend might render a Chaco plot
87 87 inline.
88
88
89 89 Parameters:
90 90 result : dict (result of IEngineBase.execute )
91 91 blockID = result['blockID']
92
92
93 93 Result:
94 94 Output of frontend rendering
95 95 """
96
96
97 97 pass
98
98
99 99 def render_error(failure):
100 """Subclasses must override to render the failure.
101
100 """Subclasses must override to render the failure.
101
102 102 In asynchronous frontend, since this method will be called as a
103 103 twisted.internet.defer.Deferred's callback. Implementations
104 104 should thus return result when finished.
105
105
106 106 blockID = failure.blockID
107 107 """
108
108
109 109 pass
110
110
111 111 def input_prompt(number=''):
112 """Returns the input prompt by subsituting into
112 """Returns the input prompt by subsituting into
113 113 self.input_prompt_template
114 114 """
115 115 pass
116
116
117 117 def output_prompt(number=''):
118 """Returns the output prompt by subsituting into
118 """Returns the output prompt by subsituting into
119 119 self.output_prompt_template
120 120 """
121
121
122 122 pass
123
123
124 124 def continuation_prompt():
125 """Returns the continuation prompt by subsituting into
125 """Returns the continuation prompt by subsituting into
126 126 self.continuation_prompt_template
127 127 """
128
128
129 129 pass
130
130
131 131 def is_complete(block):
132 132 """Returns True if block is complete, False otherwise."""
133
133
134 134 pass
135
136
135
136
137 137 def get_history_previous(current_block):
138 138 """Returns the block previous in the history. Saves currentBlock if
139 139 the history_cursor is currently at the end of the input history"""
140 140 pass
141
141
142 142 def get_history_next():
143 143 """Returns the next block in the history."""
144
144
145 145 pass
146
146
147 147 def complete(self, line):
148 148 """Returns the list of possible completions, and the completed
149 149 line.
@@ -156,7 +156,7 b' class IFrontEnd(Interface):'
156 156
157 157
158 158 ##############################################################################
159 # Base class for all the frontends.
159 # Base class for all the frontends.
160 160 ##############################################################################
161 161
162 162 class FrontEndBase(object):
@@ -164,86 +164,86 b' class FrontEndBase(object):'
164 164 FrontEndBase manages the state tasks for a CLI frontend:
165 165 - Input and output history management
166 166 - Input/continuation and output prompt generation
167
167
168 168 Some issues (due to possibly unavailable engine):
169 169 - How do we get the current cell number for the engine?
170 170 - How do we handle completions?
171 171 """
172
172
173 173 history_cursor = 0
174
174
175 175 input_prompt_template = string.Template(rc.prompt_in1)
176 176 output_prompt_template = string.Template(rc.prompt_out)
177 177 continuation_prompt_template = string.Template(rc.prompt_in2)
178
178
179 179 def __init__(self, shell=None, history=None):
180 180 self.shell = shell
181 181 if history is None:
182 182 self.history = FrontEndHistory(input_cache=[''])
183 183 else:
184 184 self.history = history
185
186
185
186
187 187 def input_prompt(self, number=''):
188 188 """Returns the current input prompt
189
189
190 190 It would be great to use ipython1.core.prompts.Prompt1 here
191 191 """
192 192 return self.input_prompt_template.safe_substitute({'number':number})
193
194
193
194
195 195 def continuation_prompt(self):
196 196 """Returns the current continuation prompt"""
197
197
198 198 return self.continuation_prompt_template.safe_substitute()
199
199
200 200 def output_prompt(self, number=''):
201 201 """Returns the output prompt for result"""
202
202
203 203 return self.output_prompt_template.safe_substitute({'number':number})
204
205
204
205
206 206 def is_complete(self, block):
207 207 """Determine if block is complete.
208
208
209 209 Parameters
210 210 block : string
211
212 Result
211
212 Result
213 213 True if block can be sent to the engine without compile errors.
214 214 False otherwise.
215 215 """
216
216
217 217 try:
218 218 is_complete = codeop.compile_command(block.rstrip() + '\n\n',
219 "<string>", "exec")
219 "<string>", "exec")
220 220 except:
221 221 return False
222
222
223 223 lines = block.split('\n')
224 return ((is_complete is not None)
224 return ((is_complete is not None)
225 225 and (len(lines)==1 or str(lines[-1])==''))
226
227
226
227
228 228 def execute(self, block, blockID=None):
229 229 """Execute the block and return the result.
230
230
231 231 Parameters:
232 232 block : {str, AST}
233 233 blockID : any
234 Caller may provide an ID to identify this block.
234 Caller may provide an ID to identify this block.
235 235 result['blockID'] := blockID
236
236
237 237 Result:
238 238 Deferred result of self.interpreter.execute
239 239 """
240
240
241 241 if(not self.is_complete(block)):
242 242 raise Exception("Block is not compilable")
243
243
244 244 if(blockID == None):
245 245 blockID = guid.generate()
246
246
247 247 try:
248 248 result = self.shell.execute(block)
249 249 except Exception,e:
@@ -254,90 +254,90 b' class FrontEndBase(object):'
254 254 result = self._add_block_id_for_result(result, blockID=blockID)
255 255 result = self.update_cell_prompt(result, blockID=blockID)
256 256 result = self.render_result(result)
257
257
258 258 return result
259
260
259
260
261 261 def _add_block_id_for_result(self, result, blockID):
262 """Add the blockID to result or failure. Unfortunatley, we have to
262 """Add the blockID to result or failure. Unfortunatley, we have to
263 263 treat failures differently than result dicts.
264 264 """
265
265
266 266 result['blockID'] = blockID
267
267
268 268 return result
269
269
270 270 def _add_block_id_for_failure(self, failure, blockID):
271 271 """_add_block_id_for_failure"""
272 272 failure.blockID = blockID
273 273 return failure
274
275
274
275
276 276 def _add_history(self, result, block=None):
277 277 """Add block to the history"""
278
278
279 279 assert(block != None)
280 280 self.history.add_items([block])
281 281 self.history_cursor += 1
282
282
283 283 return result
284
285
284
285
286 286 def get_history_previous(self, current_block):
287 287 """ Returns previous history string and decrement history cursor.
288 288 """
289 289 command = self.history.get_history_item(self.history_cursor - 1)
290
290
291 291 if command is not None:
292 292 if(self.history_cursor+1 == len(self.history.input_cache)):
293 293 self.history.input_cache[self.history_cursor] = current_block
294 294 self.history_cursor -= 1
295 295 return command
296
297
296
297
298 298 def get_history_next(self):
299 299 """ Returns next history string and increment history cursor.
300 300 """
301 301 command = self.history.get_history_item(self.history_cursor+1)
302
302
303 303 if command is not None:
304 304 self.history_cursor += 1
305 305 return command
306
306
307 307 ###
308 308 # Subclasses probably want to override these methods...
309 309 ###
310
310
311 311 def update_cell_prompt(self, result, blockID=None):
312 """Subclass may override to update the input prompt for a block.
312 """Subclass may override to update the input prompt for a block.
313 313
314 314 This method only really makes sens in asyncrhonous frontend.
315 Since this method will be called as a
316 twisted.internet.defer.Deferred's callback, implementations should
315 Since this method will be called as a
316 twisted.internet.defer.Deferred's callback, implementations should
317 317 return result when finished.
318 318 """
319
319
320 320 raise NotImplementedError
321
322
321
322
323 323 def render_result(self, result):
324 """Subclasses must override to render result.
325
324 """Subclasses must override to render result.
325
326 326 In asynchronous frontends, this method will be called as a
327 327 twisted.internet.defer.Deferred's callback. Implementations
328 328 should thus return result when finished.
329 329 """
330
330
331 331 raise NotImplementedError
332
333
332
333
334 334 def render_error(self, failure):
335 """Subclasses must override to render the failure.
336
335 """Subclasses must override to render the failure.
336
337 337 In asynchronous frontends, this method will be called as a
338 338 twisted.internet.defer.Deferred's callback. Implementations
339 339 should thus return result when finished.
340 340 """
341
341
342 342 raise NotImplementedError
343 343
@@ -48,13 +48,13 b' class LineFrontEndBase(FrontEndBase):'
48 48 to be the base class behind all the frontend that are line-oriented,
49 49 rather than block-oriented.
50 50 """
51
51
52 52 # We need to keep the prompt number, to be able to increment
53 53 # it when there is an exception.
54 54 prompt_number = 1
55 55
56 56 # We keep a reference to the last result: it helps testing and
57 # programatic control of the frontend.
57 # programatic control of the frontend.
58 58 last_result = dict(number=0)
59 59
60 60 # The last prompt displayed. Useful for continuation prompts.
@@ -93,11 +93,11 b' class LineFrontEndBase(FrontEndBase):'
93 93
94 94 def complete(self, line):
95 95 """Complete line in engine's user_ns
96
96
97 97 Parameters
98 98 ----------
99 99 line : string
100
100
101 101 Returns
102 102 -------
103 103 The replacement for the line and the list of possible completions.
@@ -105,11 +105,11 b' class LineFrontEndBase(FrontEndBase):'
105 105 completions = self.shell.complete(line)
106 106 complete_sep = re.compile('[\s\{\}\[\]\(\)\=]')
107 107 if completions:
108 prefix = common_prefix(completions)
108 prefix = common_prefix(completions)
109 109 residual = complete_sep.split(line)[:-1]
110 110 line = line[:-len(residual)] + prefix
111 return line, completions
112
111 return line, completions
112
113 113
114 114 def render_result(self, result):
115 115 """ Frontend-specific rendering of the result of a calculation
@@ -118,15 +118,15 b' class LineFrontEndBase(FrontEndBase):'
118 118 if 'stdout' in result and result['stdout']:
119 119 self.write('\n' + result['stdout'])
120 120 if 'display' in result and result['display']:
121 self.write("%s%s\n" % (
121 self.write("%s%s\n" % (
122 122 self.output_prompt_template.substitute(
123 123 number=result['number']),
124 124 result['display']['pprint']
125 125 ) )
126
126
127 127
128 128 def render_error(self, failure):
129 """ Frontend-specific rendering of error.
129 """ Frontend-specific rendering of error.
130 130 """
131 131 self.write('\n\n'+str(failure)+'\n\n')
132 132 return failure
@@ -146,7 +146,7 b' class LineFrontEndBase(FrontEndBase):'
146 146 # thus want to consider an empty string as a complete
147 147 # statement.
148 148 return True
149 elif ( len(self.input_buffer.split('\n'))>2
149 elif ( len(self.input_buffer.split('\n'))>2
150 150 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)):
151 151 return False
152 152 else:
@@ -157,7 +157,7 b' class LineFrontEndBase(FrontEndBase):'
157 157 # This should probably be done in a different place (like
158 158 # maybe 'prefilter_input' method? For now, this works.
159 159 clean_string = string.rstrip('\n')
160 if not clean_string.endswith('\\'): clean_string +='\n\n'
160 if not clean_string.endswith('\\'): clean_string +='\n\n'
161 161 is_complete = codeop.compile_command(clean_string,
162 162 "<string>", "exec")
163 163 self.release_output()
@@ -228,10 +228,10 b' class LineFrontEndBase(FrontEndBase):'
228 228
229 229
230 230 def complete_current_input(self):
231 """ Do code completion on current line.
231 """ Do code completion on current line.
232 232 """
233 233 if self.debug:
234 print >>sys.__stdout__, "complete_current_input",
234 print >>sys.__stdout__, "complete_current_input",
235 235 line = self.input_buffer
236 236 new_line, completions = self.complete(line)
237 237 if len(completions)>1:
@@ -241,7 +241,7 b' class LineFrontEndBase(FrontEndBase):'
241 241 if self.debug:
242 242 print >>sys.__stdout__, 'line', line
243 243 print >>sys.__stdout__, 'new_line', new_line
244 print >>sys.__stdout__, completions
244 print >>sys.__stdout__, completions
245 245
246 246
247 247 def get_line_width(self):
@@ -259,10 +259,10 b' class LineFrontEndBase(FrontEndBase):'
259 259 """
260 260 if new_line is None:
261 261 new_line = self.input_buffer
262
262
263 263 self.write('\n')
264 264 max_len = len(max(possibilities, key=len)) + 1
265
265
266 266 # Now we check how much symbol we can put on a line...
267 267 chars_per_line = self.get_line_width()
268 268 symbols_per_line = max(1, chars_per_line/max_len)
@@ -283,7 +283,7 b' class LineFrontEndBase(FrontEndBase):'
283 283
284 284
285 285 def new_prompt(self, prompt):
286 """ Prints a prompt and starts a new editing buffer.
286 """ Prints a prompt and starts a new editing buffer.
287 287
288 288 Subclasses should use this method to make sure that the
289 289 terminal is put in a state favorable for a new line
@@ -297,7 +297,7 b' class LineFrontEndBase(FrontEndBase):'
297 297 """Returns the current continuation prompt.
298 298 """
299 299 return ("."*(len(self.last_prompt)-2) + ': ')
300
300
301 301
302 302 def execute_command(self, command, hidden=False):
303 303 """ Execute a command, not only in the model, but also in the
@@ -308,7 +308,7 b' class LineFrontEndBase(FrontEndBase):'
308 308 #--------------------------------------------------------------------------
309 309 # Private API
310 310 #--------------------------------------------------------------------------
311
311
312 312 def _on_enter(self, new_line_pos=0):
313 313 """ Called when the return key is pressed in a line editing
314 314 buffer.
@@ -339,7 +339,7 b' class LineFrontEndBase(FrontEndBase):'
339 339 new_line_pos = -new_line_pos
340 340 lines = current_buffer.split('\n')[:-1]
341 341 prompt_less_lines = prompt_less_buffer.split('\n')
342 # Create the new line, with the continuation prompt, and the
342 # Create the new line, with the continuation prompt, and the
343 343 # same amount of indent than the line above it.
344 344 new_line = self.continuation_prompt() + \
345 345 self._get_indent_string('\n'.join(
@@ -356,7 +356,7 b' class LineFrontEndBase(FrontEndBase):'
356 356 else:
357 357 lines.insert(new_line_pos, new_line)
358 358 self.input_buffer = '\n'.join(lines)
359
359
360 360
361 361 def _get_indent_string(self, string):
362 362 """ Return the string of whitespace that prefixes a line. Used to
@@ -369,5 +369,5 b' class LineFrontEndBase(FrontEndBase):'
369 369 ' '*(indent_chars % 4)
370 370
371 371 return indent_string
372
373
372
373
@@ -51,7 +51,7 b' def mk_system_call(system_call_function, command):'
51 51 return my_system_call
52 52
53 53 #-----------------------------------------------------------------------------
54 # Frontend class using ipython0 to do the prefiltering.
54 # Frontend class using ipython0 to do the prefiltering.
55 55 #-----------------------------------------------------------------------------
56 56
57 57 class PrefilterFrontEnd(LineFrontEndBase):
@@ -65,7 +65,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
65 65 """
66 66
67 67 debug = False
68
68
69 69 def __init__(self, ipython0=None, *args, **kwargs):
70 70 """ Parameters
71 71 ----------
@@ -99,7 +99,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
99 99 __builtin__.raw_input = old_rawinput
100 100 self.ipython0 = ipython0
101 101 # Set the pager:
102 self.ipython0.set_hook('show_in_pager',
102 self.ipython0.set_hook('show_in_pager',
103 103 lambda s, string: self.write("\n" + string))
104 104 self.ipython0.write = self.write
105 105 self._ip = _ip = self.ipython0
@@ -109,7 +109,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
109 109 # XXX: Muck around with magics so that they work better
110 110 # in our environment
111 111 if not sys.platform.startswith('win'):
112 self.ipython0.magic_ls = mk_system_call(self.system_call,
112 self.ipython0.magic_ls = mk_system_call(self.system_call,
113 113 'ls -CF')
114 114 # And now clean up the mess created by ipython0
115 115 self.release_output()
@@ -122,7 +122,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
122 122 self.start()
123 123
124 124 #--------------------------------------------------------------------------
125 # FrontEndBase interface
125 # FrontEndBase interface
126 126 #--------------------------------------------------------------------------
127 127
128 128 def show_traceback(self):
@@ -147,8 +147,8 b' class PrefilterFrontEnd(LineFrontEndBase):'
147 147
148 148 def save_output_hooks(self):
149 149 """ Store all the output hooks we can think of, to be able to
150 restore them.
151
150 restore them.
151
152 152 We need to do this early, as starting the ipython0 instance will
153 153 screw ouput hooks.
154 154 """
@@ -178,8 +178,8 b' class PrefilterFrontEnd(LineFrontEndBase):'
178 178 Term.cerr.write = self.__old_cerr_write
179 179 sys.stdout = self.__old_stdout
180 180 sys.stderr = self.__old_stderr
181 pydoc.help.output = self.__old_help_output
182 sys.displayhook = self.__old_display_hook
181 pydoc.help.output = self.__old_help_output
182 sys.displayhook = self.__old_display_hook
183 183
184 184
185 185 def complete(self, line):
@@ -191,12 +191,12 b' class PrefilterFrontEnd(LineFrontEndBase):'
191 191 key = lambda x: x.replace('_', '')
192 192 completions.sort(key=key)
193 193 if completions:
194 prefix = common_prefix(completions)
194 prefix = common_prefix(completions)
195 195 line = line[:-len(word)] + prefix
196 196 return line, completions
197
197
198 198 #--------------------------------------------------------------------------
199 # LineFrontEndBase interface
199 # LineFrontEndBase interface
200 200 #--------------------------------------------------------------------------
201 201
202 202 def prefilter_input(self, input_string):
@@ -209,7 +209,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
209 209 # capture it.
210 210 self.capture_output()
211 211 self.last_result = dict(number=self.prompt_number)
212
212
213 213 try:
214 214 try:
215 215 for line in input_string.split('\n'):
@@ -227,9 +227,9 b' class PrefilterFrontEnd(LineFrontEndBase):'
227 227 return filtered_string
228 228
229 229 #--------------------------------------------------------------------------
230 # PrefilterFrontEnd interface
230 # PrefilterFrontEnd interface
231 231 #--------------------------------------------------------------------------
232
232
233 233 def system_call(self, command_string):
234 234 """ Allows for frontend to define their own system call, to be
235 235 able capture output and redirect input.
@@ -250,7 +250,7 b' class PrefilterFrontEnd(LineFrontEndBase):'
250 250 # that in the 'pyreadline' module (modes/basemode.py) where we break at
251 251 # each delimiter and try to complete the residual line, until we get a
252 252 # successful list of completions.
253 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
253 expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})'
254 254 complete_sep = re.compile(expression)
255 255 text = complete_sep.split(line)[-1]
256 256 return text
@@ -1,4 +1,4 b''
1 # Addapted from killableprocess.py.
1 # Addapted from killableprocess.py.
2 2 #______________________________________________________________________________
3 3 #
4 4 # killableprocess - subprocesses which can be reliably killed
@@ -118,10 +118,10 b' else:'
118 118
119 119 if startupinfo is None:
120 120 startupinfo = winprocess.STARTUPINFO()
121
121
122 122 if None not in (p2cread, c2pwrite, errwrite):
123 123 startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
124
124
125 125 startupinfo.hStdInput = int(p2cread)
126 126 startupinfo.hStdOutput = int(c2pwrite)
127 127 startupinfo.hStdError = int(errwrite)
@@ -132,7 +132,7 b' else:'
132 132 args = comspec + " /c " + args
133 133
134 134 # We create a new job for this process, so that we can kill
135 # the process and any sub-processes
135 # the process and any sub-processes
136 136 self._job = winprocess.CreateJobObject()
137 137
138 138 creationflags |= winprocess.CREATE_SUSPENDED
@@ -145,7 +145,7 b' else:'
145 145 creationflags,
146 146 winprocess.EnvironmentBlock(env),
147 147 cwd, startupinfo)
148
148
149 149 self._child_created = True
150 150 self._handle = hp
151 151 self._thread = ht
@@ -173,7 +173,7 b' else:'
173 173 winprocess.TerminateJobObject(self._job, 127)
174 174 else:
175 175 winprocess.TerminateProcess(self._handle, 127)
176 self.returncode = 127
176 self.returncode = 127
177 177 else:
178 178 if group:
179 179 os.killpg(self.pid, signal.SIGKILL)
@@ -1,6 +1,6 b''
1 1 # encoding: utf-8
2 2 """
3 Object for encapsulating process execution by using callbacks for stdout,
3 Object for encapsulating process execution by using callbacks for stdout,
4 4 stderr and stdin.
5 5 """
6 6 __docformat__ = "restructuredtext en"
@@ -26,10 +26,10 b' class PipedProcess(Thread):'
26 26 killing it.
27 27 """
28 28
29 def __init__(self, command_string, out_callback,
29 def __init__(self, command_string, out_callback,
30 30 end_callback=None,):
31 31 """ command_string: the command line executed to start the
32 process.
32 process.
33 33
34 34 out_callback: the python callable called on stdout/stderr.
35 35
@@ -43,7 +43,7 b' class PipedProcess(Thread):'
43 43 self.out_callback = out_callback
44 44 self.end_callback = end_callback
45 45 Thread.__init__(self)
46
46
47 47
48 48 def run(self):
49 49 """ Start the process and hook up the callbacks.
@@ -70,5 +70,5 b' class PipedProcess(Thread):'
70 70
71 71 if self.end_callback is not None:
72 72 self.end_callback()
73
73
74 74
@@ -2,20 +2,20 b''
2 2 """This file contains unittests for the asyncfrontendbase module."""
3 3
4 4 #---------------------------------------------------------------------------
5 # Copyright (C) 2008-2009 The IPython Development Team
6 #
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
5 # Copyright (C) 2008-2009 The IPython Development Team
6 #
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
9 9 #---------------------------------------------------------------------------
10 10
11 11 #---------------------------------------------------------------------------
12 # Imports
12 # Imports
13 13 #---------------------------------------------------------------------------
14 14
15 15 from twisted.trial import unittest
16
16
17 17 from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase
18 from IPython.frontend import frontendbase
18 from IPython.frontend import frontendbase
19 19 from IPython.kernel.engineservice import EngineService
20 20 from IPython.testing.parametric import Parametric, parametric
21 21
@@ -26,20 +26,20 b' from IPython.testing.parametric import Parametric, parametric'
26 26 class FrontEndCallbackChecker(AsyncFrontEndBase):
27 27 """FrontEndBase subclass for checking callbacks"""
28 28 def __init__(self, engine=None, history=None):
29 super(FrontEndCallbackChecker, self).__init__(engine=engine,
29 super(FrontEndCallbackChecker, self).__init__(engine=engine,
30 30 history=history)
31 31 self.updateCalled = False
32 32 self.renderResultCalled = False
33 33 self.renderErrorCalled = False
34
34
35 35 def update_cell_prompt(self, result, blockID=None):
36 36 self.updateCalled = True
37 37 return result
38
38
39 39 def render_result(self, result):
40 40 self.renderResultCalled = True
41 41 return result
42
42
43 43 def render_error(self, failure):
44 44 self.renderErrorCalled = True
45 45 return failure
@@ -48,50 +48,50 b' class FrontEndCallbackChecker(AsyncFrontEndBase):'
48 48 class TestAsyncFrontendBase(unittest.TestCase):
49 49 def setUp(self):
50 50 """Setup the EngineService and FrontEndBase"""
51
51
52 52 self.fb = FrontEndCallbackChecker(engine=EngineService())
53
53
54 54 def test_implements_IFrontEnd(self):
55 55 self.assert_(frontendbase.IFrontEnd.implementedBy(
56 56 AsyncFrontEndBase))
57
57
58 58 def test_is_complete_returns_False_for_incomplete_block(self):
59 59 block = """def test(a):"""
60 60 self.assert_(self.fb.is_complete(block) == False)
61
61
62 62 def test_is_complete_returns_True_for_complete_block(self):
63 63 block = """def test(a): pass"""
64 64 self.assert_(self.fb.is_complete(block))
65 65 block = """a=3"""
66 66 self.assert_(self.fb.is_complete(block))
67
67
68 68 def test_blockID_added_to_result(self):
69 69 block = """3+3"""
70 70 d = self.fb.execute(block, blockID='TEST_ID')
71 71 d.addCallback(lambda r: self.assert_(r['blockID']=='TEST_ID'))
72 72 return d
73
73
74 74 def test_blockID_added_to_failure(self):
75 75 block = "raise Exception()"
76 76 d = self.fb.execute(block,blockID='TEST_ID')
77 77 d.addErrback(lambda f: self.assert_(f.blockID=='TEST_ID'))
78 78 return d
79
79
80 80 def test_callbacks_added_to_execute(self):
81 81 d = self.fb.execute("10+10")
82 82 d.addCallback(lambda r: self.assert_(self.fb.updateCalled and self.fb.renderResultCalled))
83 83 return d
84
84
85 85 def test_error_callback_added_to_execute(self):
86 86 """Test that render_error called on execution error."""
87
87
88 88 d = self.fb.execute("raise Exception()")
89 89 d.addErrback(lambda f: self.assert_(self.fb.renderErrorCalled))
90 90 return d
91
91
92 92 def test_history_returns_expected_block(self):
93 93 """Make sure history browsing doesn't fail."""
94
94
95 95 blocks = ["a=1","a=2","a=3"]
96 96 d = self.fb.execute(blocks[0])
97 97 d.addCallback(lambda _: self.fb.execute(blocks[1]))
@@ -100,7 +100,7 b' class TestAsyncFrontendBase(unittest.TestCase):'
100 100 d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-3]))
101 101 d.addCallback(lambda _: self.assert_(self.fb.get_history_next()==blocks[-2]))
102 102 return d
103
104 def test_history_returns_none_at_startup(self):
103
104 def test_history_returns_none_at_startup(self):
105 105 self.assert_(self.fb.get_history_previous("")==None)
106 106 self.assert_(self.fb.get_history_next()==None)
@@ -1,6 +1,6 b''
1 1 # encoding: utf-8
2 2 """
3 Test the basic functionality of frontendbase.
3 Test the basic functionality of frontendbase.
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
@@ -15,7 +15,7 b' __docformat__ = "restructuredtext en"'
15 15 from IPython.frontend.frontendbase import FrontEndBase
16 16
17 17 def test_iscomplete():
18 """ Check that is_complete works.
18 """ Check that is_complete works.
19 19 """
20 20 f = FrontEndBase()
21 21 assert f.is_complete('(a + a)')
@@ -1,6 +1,6 b''
1 1 # encoding: utf-8
2 2 """
3 Test the LineFrontEnd
3 Test the LineFrontEnd
4 4 """
5 5
6 6 __docformat__ = "restructuredtext en"
@@ -27,7 +27,7 b' from IPython.testing.globalipapp import get_ipython'
27 27 #-----------------------------------------------------------------------------
28 28
29 29 class TestPrefilterFrontEnd(PrefilterFrontEnd):
30
30
31 31 input_prompt_template = string.Template('')
32 32 output_prompt_template = string.Template('')
33 33 banner = ''
@@ -42,7 +42,7 b' class TestPrefilterFrontEnd(PrefilterFrontEnd):'
42 42 self.out.truncate()
43 43
44 44 def write(self, string, *args, **kwargs):
45 self.out.write(string)
45 self.out.write(string)
46 46
47 47 def _on_enter(self):
48 48 self.input_buffer += '\n'
@@ -151,11 +151,11 b' def test_capture():'
151 151 out_value = f.out.getvalue()
152 152 yield assert_equal, out_value, '1'
153 153
154
154
155 155 @isolate_ipython0
156 156 def test_magic():
157 157 """ Test the magic expansion and history.
158
158
159 159 This test is fairly fragile and will break when magics change.
160 160 """
161 161 f = TestPrefilterFrontEnd()
@@ -188,7 +188,7 b' def test_help():'
188 188 assert 'traceback' not in f.last_result
189 189 ## XXX: ipython doctest magic breaks this. I have no clue why
190 190 #out_value = f.out.getvalue()
191 #assert out_value.split()[-1] == 'foobar'
191 #assert out_value.split()[-1] == 'foobar'
192 192
193 193
194 194 @isolate_ipython0
@@ -35,7 +35,7 b' def test_io():'
35 35 """ Checks that we can send characters on stdin to the process.
36 36 """
37 37 s = StringIO()
38 p = PipedProcess(sys.executable + ' -c "a = raw_input(); print a"',
38 p = PipedProcess(sys.executable + ' -c "a = raw_input(); print a"',
39 39 out_callback=s.write, )
40 40 p.start()
41 41 test_string = '12345\n'
@@ -52,12 +52,12 b' def test_kill():'
52 52 """ Check that we can kill a process, and its subprocess.
53 53 """
54 54 s = StringIO()
55 p = PipedProcess(sys.executable + ' -c "a = raw_input();"',
55 p = PipedProcess(sys.executable + ' -c "a = raw_input();"',
56 56 out_callback=s.write, )
57 57 p.start()
58 58 while not hasattr(p, 'process'):
59 59 sleep(0.1)
60 p.process.kill()
60 p.process.kill()
61 61 assert p.process.poll() is not None
62 62
63 63
@@ -36,7 +36,7 b' import re'
36 36 # FIXME: Need to provide an API for non user-generated display on the
37 37 # screen: this should not be editable by the user.
38 38 #-------------------------------------------------------------------------------
39 # Constants
39 # Constants
40 40 #-------------------------------------------------------------------------------
41 41 _COMPLETE_BUFFER_MARKER = 31
42 42 _ERROR_MARKER = 30
@@ -75,7 +75,7 b' _DEFAULT_STYLE = {'
75 75 # Default scintilla settings
76 76 'antialiasing' : True,
77 77 'carret_color' : 'BLACK',
78 'background_color' :'WHITE',
78 'background_color' :'WHITE',
79 79
80 80 #prompt definition
81 81 'prompt_in1' : \
@@ -94,14 +94,14 b' _TRACE_STYLE = 17'
94 94 # system colors
95 95 #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
96 96
97 # Translation table from ANSI escape sequences to color.
97 # Translation table from ANSI escape sequences to color.
98 98 ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'],
99 99 '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'],
100 100 '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'],
101 101 '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'],
102 102 '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'],
103 103 '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'],
104 '1;34': [12, 'LIGHT BLUE'], '1;35':
104 '1;34': [12, 'LIGHT BLUE'], '1;35':
105 105 [13, 'MEDIUM VIOLET RED'],
106 106 '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']}
107 107
@@ -133,7 +133,7 b' else:'
133 133 'size' : 10,
134 134 'size2': 8,
135 135 }
136
136
137 137
138 138 #-----------------------------------------------------------------------------
139 139 # The console widget class
@@ -174,36 +174,36 b' class ConsoleWidget(editwindow.EditWindow):'
174 174 # Translation table from ANSI escape sequences to color. Override
175 175 # this to specify your colors.
176 176 ANSI_STYLES = ANSI_STYLES.copy()
177
177
178 178 # Font faces
179 179 faces = FACES.copy()
180
180
181 181 # Store the last time a refresh was done
182 182 _last_refresh_time = 0
183 183
184 184 #--------------------------------------------------------------------------
185 185 # Public API
186 186 #--------------------------------------------------------------------------
187
188 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
187
188 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
189 189 size=wx.DefaultSize, style=wx.WANTS_CHARS, ):
190 190 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
191 191 self.configure_scintilla()
192 192 # Track if 'enter' key as ever been processed
193 193 # This variable will only be reallowed until key goes up
194 self.enter_catched = False
194 self.enter_catched = False
195 195 self.current_prompt_pos = 0
196 196
197 197 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)
198 198 self.Bind(wx.EVT_KEY_UP, self._on_key_up)
199
199
200 200
201 201 def write(self, text, refresh=True):
202 202 """ Write given text to buffer, while translating the ansi escape
203 203 sequences.
204 204 """
205 # XXX: do not put print statements to sys.stdout/sys.stderr in
206 # this method, the print statements will call this method, as
205 # XXX: do not put print statements to sys.stdout/sys.stderr in
206 # this method, the print statements will call this method, as
207 207 # you will end up with an infinit loop
208 208 title = self.title_pat.split(text)
209 209 if len(title)>1:
@@ -219,7 +219,7 b' class ConsoleWidget(editwindow.EditWindow):'
219 219 except UnicodeDecodeError:
220 220 # XXX: Do I really want to skip the exception?
221 221 pass
222
222
223 223 if segments:
224 224 for ansi_tag, text in zip(segments[::2], segments[1::2]):
225 225 self.StartStyling(self.GetLength(), 0xFF)
@@ -234,8 +234,8 b' class ConsoleWidget(editwindow.EditWindow):'
234 234 else:
235 235 style = self.ANSI_STYLES[ansi_tag][0]
236 236
237 self.SetStyling(len(text), style)
238
237 self.SetStyling(len(text), style)
238
239 239 self.GotoPos(self.GetLength())
240 240 if refresh:
241 241 current_time = time.time()
@@ -245,9 +245,9 b' class ConsoleWidget(editwindow.EditWindow):'
245 245 else:
246 246 wx.Yield()
247 247 # self.ProcessEvent(wx.PaintEvent())
248 self._last_refresh_time = current_time
248 self._last_refresh_time = current_time
249
249 250
250
251 251 def new_prompt(self, prompt):
252 252 """ Prints a prompt at start of line, and move the start of the
253 253 current block there.
@@ -270,7 +270,7 b' class ConsoleWidget(editwindow.EditWindow):'
270 270 # ASCII-less prompt
271 271 ascii_less = ''.join(self.color_pat.split(self.last_prompt)[2::2])
272 272 return "."*(len(ascii_less)-2) + ': '
273
273
274 274
275 275 def scroll_to_bottom(self):
276 276 maxrange = self.GetScrollRange(wx.VERTICAL)
@@ -299,7 +299,7 b' class ConsoleWidget(editwindow.EditWindow):'
299 299 widget.
300 300 """
301 301 p = self.style.copy()
302
302
303 303 # Marker for complete buffer.
304 304 self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND,
305 305 background=p['trace'])
@@ -313,14 +313,14 b' class ConsoleWidget(editwindow.EditWindow):'
313 313
314 314 self.SetEOLMode(stc.STC_EOL_LF)
315 315
316 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
316 # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside
317 317 # the widget
318 318 self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
319 319 self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
320 # Also allow Ctrl Shift "=" for poor non US keyboard users.
321 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
320 # Also allow Ctrl Shift "=" for poor non US keyboard users.
321 self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT,
322 322 stc.STC_CMD_ZOOMIN)
323
323
324 324 # Keys: we need to clear some of the keys the that don't play
325 325 # well with a console.
326 326 self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL)
@@ -341,7 +341,7 b' class ConsoleWidget(editwindow.EditWindow):'
341 341 self.SetIndent(4)
342 342 self.SetTabWidth(4)
343 343
344 # we don't want scintilla's autocompletion to choose
344 # we don't want scintilla's autocompletion to choose
345 345 # automaticaly out of a single choice list, as we pop it up
346 346 # automaticaly
347 347 self.AutoCompSetChooseSingle(False)
@@ -360,11 +360,11 b' class ConsoleWidget(editwindow.EditWindow):'
360 360 self.title_pat = re.compile('\x1b]0;(.*?)\x07')
361 361
362 362 # styles
363
363
364 364 self.SetCaretForeground(p['carret_color'])
365
365
366 366 background_color = p['background_color']
367
367
368 368 if 'default' in p:
369 369 if 'back' not in p['default']:
370 370 p['default'] += ',back:%s' % background_color
@@ -372,20 +372,20 b' class ConsoleWidget(editwindow.EditWindow):'
372 372 p['default'] += ',size:%s' % self.faces['size']
373 373 if 'face' not in p['default']:
374 374 p['default'] += ',face:%s' % self.faces['mono']
375
375
376 376 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default'])
377 377 else:
378 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
379 "fore:%s,back:%s,size:%d,face:%s"
380 % (self.ANSI_STYLES['0;30'][1],
378 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
379 "fore:%s,back:%s,size:%d,face:%s"
380 % (self.ANSI_STYLES['0;30'][1],
381 381 background_color,
382 382 self.faces['size'], self.faces['mono']))
383
383
384 384 self.StyleClearAll()
385
386 # XXX: two lines below are usefull if not using the lexer
385
386 # XXX: two lines below are usefull if not using the lexer
387 387 #for style in self.ANSI_STYLES.values():
388 # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
388 # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
389 389
390 390 # prompt definition
391 391 self.prompt_in1 = p['prompt_in1']
@@ -417,25 +417,25 b' class ConsoleWidget(editwindow.EditWindow):'
417 417 #we add a vertical line to console widget
418 418 self.SetEdgeMode(stc.STC_EDGE_LINE)
419 419 self.SetEdgeColumn(edge_column)
420
421
420
421
422 422 #--------------------------------------------------------------------------
423 423 # EditWindow API
424 424 #--------------------------------------------------------------------------
425 425
426 426 def OnUpdateUI(self, event):
427 """ Override the OnUpdateUI of the EditWindow class, to prevent
427 """ Override the OnUpdateUI of the EditWindow class, to prevent
428 428 syntax highlighting both for faster redraw, and for more
429 429 consistent look and feel.
430 430 """
431 431
432
432
433 433 #--------------------------------------------------------------------------
434 434 # Private API
435 435 #--------------------------------------------------------------------------
436
436
437 437 def _on_key_down(self, event, skip=True):
438 """ Key press callback used for correcting behavior for
438 """ Key press callback used for correcting behavior for
439 439 console-like interfaces: the cursor is constraint to be after
440 440 the last prompt.
441 441
@@ -487,7 +487,7 b' class ConsoleWidget(editwindow.EditWindow):'
487 487 if event.ShiftDown():
488 488 # Try to force execution
489 489 self.GotoPos(self.GetLength())
490 self.write('\n' + self.continuation_prompt(),
490 self.write('\n' + self.continuation_prompt(),
491 491 refresh=False)
492 492 self._on_enter()
493 493 else:
@@ -501,7 +501,7 b' class ConsoleWidget(editwindow.EditWindow):'
501 501 else:
502 502 # FIXME: This behavior is not ideal: if the selection
503 503 # is already started, it will jump.
504 self.SetSelectionStart(self.current_prompt_pos)
504 self.SetSelectionStart(self.current_prompt_pos)
505 505 self.SetSelectionEnd(self.GetCurrentPos())
506 506 catched = True
507 507
@@ -591,15 +591,15 b' class ConsoleWidget(editwindow.EditWindow):'
591 591 # Jump back up
592 592 self.GotoPos(self.GetLineEndPosition(line_num-1))
593 593 return True
594 elif ( current_pos > self.GetLineEndPosition(line_num)
595 and not current_pos == self.GetLength()):
594 elif ( current_pos > self.GetLineEndPosition(line_num)
595 and not current_pos == self.GetLength()):
596 596 # Jump to next line
597 597 self.GotoPos(current_pos + 1 +
598 598 len(continuation_prompt))
599 599 return True
600 600
601 601 # We re-allow enter event processing
602 self.enter_catched = False
602 self.enter_catched = False
603 603 return False
604 604
605 605
@@ -38,7 +38,7 b' class IPythonXController(WxController):'
38 38 self._input_state == 'readline':
39 39 wx.CallAfter(self.ask_exit)
40 40 else:
41 WxController._on_key_down(self, event, skip=skip)
41 WxController._on_key_down(self, event, skip=skip)
42 42
43 43
44 44 def ask_exit(self):
@@ -56,7 +56,7 b' class IPythonXController(WxController):'
56 56 else:
57 57 wx.CallAfter(wx.GetApp().Exit)
58 58 self.write('Exiting ...', refresh=False)
59
59
60 60
61 61 def do_exit(self):
62 62 """ Exits the interpreter, kills the windows.
@@ -81,10 +81,10 b' class IPythonX(wx.Frame):'
81 81 self.Show(True)
82 82 wx.EVT_CLOSE(self, self.on_close)
83 83
84
84
85 85 def on_close(self, event):
86 """ Called on closing the windows.
87
86 """ Called on closing the windows.
87
88 88 Stops the event loop, to close all the child windows.
89 89 """
90 90 wx.CallAfter(wx.Exit)
@@ -47,7 +47,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
47 47 This class inherits from ConsoleWidget, that provides a console-like
48 48 widget to provide a text-rendering widget suitable for a terminal.
49 49 """
50
50
51 51 # Print debug info on what is happening to the console.
52 52 debug = False
53 53
@@ -83,7 +83,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
83 83
84 84 # A flag governing the behavior of the input. Can be:
85 85 #
86 # 'readline' for readline-like behavior with a prompt
86 # 'readline' for readline-like behavior with a prompt
87 87 # and an edit buffer.
88 88 # 'raw_input' similar to readline, but triggered by a raw-input
89 89 # call. Can be used by subclasses to act differently.
@@ -111,7 +111,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
111 111 #--------------------------------------------------------------------------
112 112 # Public API
113 113 #--------------------------------------------------------------------------
114
114
115 115 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
116 116 size=wx.DefaultSize,
117 117 style=wx.CLIP_CHILDREN|wx.WANTS_CHARS,
@@ -129,7 +129,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
129 129 self.style = styledef
130 130 ConsoleWidget.__init__(self, parent, id, pos, size, style)
131 131 PrefilterFrontEnd.__init__(self, **kwds)
132
132
133 133 # Stick in our own raw_input:
134 134 self.ipython0.raw_input = self.raw_input
135 135
@@ -147,14 +147,14 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
147 147 self.shell.user_ns['self'] = self
148 148 # Inject our own raw_input in namespace
149 149 self.shell.user_ns['raw_input'] = self.raw_input
150
150
151 151 def raw_input(self, prompt=''):
152 152 """ A replacement from python's raw_input.
153 153 """
154 154 self.new_prompt(prompt)
155 155 self._input_state = 'raw_input'
156 156 if hasattr(self, '_cursor'):
157 del self._cursor
157 del self._cursor
158 158 self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
159 159 self.__old_on_enter = self._on_enter
160 160 event_loop = wx.EventLoop()
@@ -162,7 +162,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
162 162 event_loop.Exit()
163 163 self._on_enter = my_on_enter
164 164 # XXX: Running a separate event_loop. Ugly.
165 event_loop.Run()
165 event_loop.Run()
166 166 self._on_enter = self.__old_on_enter
167 167 self._input_state = 'buffering'
168 168 self._cursor = wx.BusyCursor()
@@ -177,12 +177,12 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
177 177 self._running_process = False
178 178 event_loop.Exit()
179 179
180 self._running_process = PipedProcess(command_string,
180 self._running_process = PipedProcess(command_string,
181 181 out_callback=self.buffered_write,
182 182 end_callback = _end_system_call)
183 183 self._running_process.start()
184 184 # XXX: Running a separate event_loop. Ugly.
185 event_loop.Run()
185 event_loop.Run()
186 186 # Be sure to flush the buffer.
187 187 self._buffer_flush(event=None)
188 188
@@ -191,7 +191,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
191 191 """ Analyse current and displays useful calltip for it.
192 192 """
193 193 if self.debug:
194 print >>sys.__stdout__, "do_calltip"
194 print >>sys.__stdout__, "do_calltip"
195 195 separators = re.compile('[\s\{\}\[\]\(\)\= ,:]')
196 196 symbol = self.input_buffer
197 197 symbol_string = separators.split(symbol)[-1]
@@ -217,11 +217,11 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
217 217
218 218
219 219 def _popup_completion(self, create=False):
220 """ Updates the popup completion menu if it exists. If create is
220 """ Updates the popup completion menu if it exists. If create is
221 221 true, open the menu.
222 222 """
223 223 if self.debug:
224 print >>sys.__stdout__, "_popup_completion"
224 print >>sys.__stdout__, "_popup_completion"
225 225 line = self.input_buffer
226 226 if (self.AutoCompActive() and line and not line[-1] == '.') \
227 227 or create==True:
@@ -230,7 +230,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
230 230 offset = len(self._get_completion_text(line))
231 231 self.pop_completion(completions, offset=offset)
232 232 if self.debug:
233 print >>sys.__stdout__, completions
233 print >>sys.__stdout__, completions
234 234
235 235
236 236 def buffered_write(self, text):
@@ -244,7 +244,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
244 244 self._out_buffer.append(text)
245 245 self._out_buffer_lock.release()
246 246 if not self._buffer_flush_timer.IsRunning():
247 wx.CallAfter(self._buffer_flush_timer.Start,
247 wx.CallAfter(self._buffer_flush_timer.Start,
248 248 milliseconds=100, oneShot=True)
249 249
250 250
@@ -257,9 +257,9 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
257 257
258 258
259 259 #--------------------------------------------------------------------------
260 # LineFrontEnd interface
260 # LineFrontEnd interface
261 261 #--------------------------------------------------------------------------
262
262
263 263 def execute(self, python_string, raw_string=None):
264 264 self._input_state = 'buffering'
265 265 self.CallTipCancel()
@@ -275,7 +275,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
275 275 # Use a callafter to update the display robustly under windows
276 276 def callback():
277 277 self.GotoPos(self.GetLength())
278 PrefilterFrontEnd.execute(self, python_string,
278 PrefilterFrontEnd.execute(self, python_string,
279 279 raw_string=raw_string)
280 280 wx.CallAfter(callback)
281 281
@@ -314,7 +314,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
314 314 return True
315 315
316 316
317 def save_output_hooks(self):
317 def save_output_hooks(self):
318 318 self.__old_raw_input = __builtin__.raw_input
319 319 PrefilterFrontEnd.save_output_hooks(self)
320 320
@@ -322,8 +322,8 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
322 322 self.SetLexer(stc.STC_LEX_NULL)
323 323 PrefilterFrontEnd.capture_output(self)
324 324 __builtin__.raw_input = self.raw_input
325
326
325
326
327 327 def release_output(self):
328 328 __builtin__.raw_input = self.__old_raw_input
329 329 PrefilterFrontEnd.release_output(self)
@@ -346,11 +346,11 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
346 346 for i in range(start_line, self.GetCurrentLine()):
347 347 self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER)
348 348
349
349
350 350 #--------------------------------------------------------------------------
351 # FrontEndBase interface
351 # FrontEndBase interface
352 352 #--------------------------------------------------------------------------
353
353
354 354 def render_error(self, e):
355 355 start_line = self.GetCurrentLine()
356 356 self.write('\n' + e + '\n')
@@ -359,7 +359,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
359 359
360 360
361 361 #--------------------------------------------------------------------------
362 # ConsoleWidget interface
362 # ConsoleWidget interface
363 363 #--------------------------------------------------------------------------
364 364
365 365 def new_prompt(self, prompt):
@@ -405,7 +405,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
405 405 # get back to a prompt.
406 406 elif self._input_state == 'subprocess' and (
407 407 ( key_code <256 and not event.ControlDown() )
408 or
408 or
409 409 ( key_code in (ord('d'), ord('D')) and
410 410 event.ControlDown())):
411 411 # We are running a process, we redirect keys.
@@ -426,7 +426,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
426 426 self.do_calltip()
427 427 elif self.AutoCompActive() and not key_code == ord('\t'):
428 428 event.Skip()
429 if key_code in (wx.WXK_BACK, wx.WXK_DELETE):
429 if key_code in (wx.WXK_BACK, wx.WXK_DELETE):
430 430 wx.CallAfter(self._popup_completion, create=True)
431 431 elif not key_code in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT,
432 432 wx.WXK_RIGHT, wx.WXK_ESCAPE):
@@ -455,7 +455,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
455 455 # Tab-completion
456 456 elif key_code == ord('\t'):
457 457 current_line, current_line_num = self.CurLine
458 if not re.match(r'^%s\s*$' % self.continuation_prompt(),
458 if not re.match(r'^%s\s*$' % self.continuation_prompt(),
459 459 current_line):
460 460 self.complete_current_input()
461 461 if self.AutoCompActive():
@@ -491,7 +491,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
491 491 ConsoleWidget._on_key_down(self, event, skip=skip)
492 492 else:
493 493 ConsoleWidget._on_key_down(self, event, skip=skip)
494
494
495 495
496 496
497 497 def _on_key_up(self, event, skip=True):
@@ -503,7 +503,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
503 503 wx.CallAfter(self._popup_completion, create=True)
504 504 else:
505 505 ConsoleWidget._on_key_up(self, event, skip=skip)
506 # Make sure the continuation_prompts are always followed by a
506 # Make sure the continuation_prompts are always followed by a
507 507 # whitespace
508 508 new_lines = []
509 509 if self._input_state == 'readline':
@@ -531,10 +531,10 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
531 531 if sys.platform == 'win32':
532 532 self.input_buffer = self.input_buffer
533 533 old_prompt_num = self.current_prompt_pos
534 has_executed = PrefilterFrontEnd._on_enter(self,
534 has_executed = PrefilterFrontEnd._on_enter(self,
535 535 new_line_pos=new_line_pos)
536 536 if old_prompt_num == self.current_prompt_pos:
537 # No execution has happened
537 # No execution has happened
538 538 self.GotoPos(self.GetLineEndPosition(current_line_num + 1))
539 539 return has_executed
540 540
@@ -544,7 +544,7 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
544 544 #--------------------------------------------------------------------------
545 545
546 546 def OnUpdateUI(self, event):
547 """ Override the OnUpdateUI of the EditWindow class, to prevent
547 """ Override the OnUpdateUI of the EditWindow class, to prevent
548 548 syntax highlighting both for faster redraw, and for more
549 549 consistent look and feel.
550 550 """
@@ -554,10 +554,10 b' class WxController(ConsoleWidget, PrefilterFrontEnd):'
554 554 #--------------------------------------------------------------------------
555 555 # Private API
556 556 #--------------------------------------------------------------------------
557
557
558 558 def _buffer_flush(self, event):
559 559 """ Called by the timer to flush the write buffer.
560
560
561 561 This is always called in the mainloop, by the wx timer.
562 562 """
563 563 self._out_buffer_lock.acquire()
@@ -4,7 +4,7 b''
4 4 zope.interface mock. If zope is installed, this module provides a zope
5 5 interface classes, if not it provides mocks for them.
6 6
7 Classes provided:
7 Classes provided:
8 8 Interface, Attribute, implements, classProvides
9 9 """
10 10 __docformat__ = "restructuredtext en"
@@ -23,7 +23,7 b' if len(sys.argv) > 1:'
23 23 if sys.argv[1] == '-v':
24 24 sys.argv = sys.argv[:-1] # IPython is confused by -v, apparently
25 25 verbose = True
26
26
27 27 IPython.Shell.start()
28 28
29 29 ip = IPython.ipapi.get()
@@ -41,7 +41,7 b' def install_mock_handler(name):'
41 41 handler func always returns '', which causes ipython to cease handling
42 42 the string immediately. That way, that it doesn't echo output, raise
43 43 exceptions, etc. But do note that testing multiline strings thus gets
44 a bit hard."""
44 a bit hard."""
45 45 def mock_handler(self, line, continue_prompt=None,
46 46 pre=None,iFun=None,theRest=None,
47 47 obj=None):
@@ -76,7 +76,7 b' def reset_esc_handlers():'
76 76 s.ESC_SH_CAP : s.handle_shell_escape,
77 77 }
78 78 reset_esc_handlers()
79
79
80 80 # This is so I don't have to quote over and over. Gotta be a better way.
81 81 handle_normal = 'handle_normal'
82 82 handle_auto = 'handle_auto'
@@ -96,18 +96,18 b' def check(assertion, failure_msg):'
96 96 if assertion:
97 97 if verbose:
98 98 sys.stdout.write('.')
99 sys.stdout.flush()
99 sys.stdout.flush()
100 100 else:
101 101 if verbose:
102 102 sys.stdout.write('F')
103 103 sys.stdout.flush()
104 104 failures.append(failure_msg)
105
105
106 106
107 107 def check_handler(expected_handler, line):
108 108 """Verify that the expected hander was called (for the given line,
109 109 passed in for failure reporting).
110
110
111 111 Pulled out to its own function so that tests which don't use
112 112 run_handler_tests can still take advantage of it."""
113 113 check(handler_called == expected_handler,
@@ -115,16 +115,16 b' def check_handler(expected_handler, line):'
115 115 "instead %s called" % (expected_handler,
116 116 repr(line),
117 117 handler_called))
118
118
119 119
120 120 def run_handler_tests(h_tests):
121 121 """Loop through a series of (input_line, handler_name) pairs, verifying
122 that, for each ip calls the given handler for the given line.
122 that, for each ip calls the given handler for the given line.
123 123
124 124 The verbose complaint includes the line passed in, so if that line can
125 125 include enough info to find the error, the tests are modestly
126 126 self-documenting.
127 """
127 """
128 128 for ln, expected_handler in h_tests:
129 129 global handler_called
130 130 handler_called = None
@@ -133,7 +133,7 b' def run_handler_tests(h_tests):'
133 133
134 134 def run_one_test(ln, expected_handler):
135 135 run_handler_tests([(ln, expected_handler)])
136
136
137 137
138 138 # =========================================
139 139 # Tests
@@ -153,12 +153,12 b' esc_handler_tests = ['
153 153 ( '%magic', handle_magic),
154 154 # XXX Possibly, add test for /,; once those are unhooked from %autocall
155 155 ( 'emacs_mode # PYTHON-MODE', handle_emacs ),
156 ( ' ', handle_normal),
156 ( ' ', handle_normal),
157 157
158 158 # Trailing qmark combos. Odd special cases abound
159 159
160 160 # ! always takes priority!
161 ( '!thing?', handle_shell_escape),
161 ( '!thing?', handle_shell_escape),
162 162 ( '!thing arg?', handle_shell_escape),
163 163 ( '!!thing?', handle_shell_escape),
164 164 ( '!!thing arg?', handle_shell_escape),
@@ -186,8 +186,8 b' run_handler_tests(esc_handler_tests)'
186 186 old_mls = ip.options.multi_line_specials
187 187 for ln in [ ' !ls $f multi_line_specials %s',
188 188 ' !!ls $f multi_line_specials %s', # !! escapes work on mls
189 # Trailing ? doesn't trigger help:
190 ' !ls $f multi_line_specials %s ?',
189 # Trailing ? doesn't trigger help:
190 ' !ls $f multi_line_specials %s ?',
191 191 ' !!ls $f multi_line_specials %s ?',
192 192 ]:
193 193 ip.options.multi_line_specials = 1
@@ -271,16 +271,16 b' class AttributeMutator(object):'
271 271 attr_mutator = AttributeMutator()
272 272 ip.to_user_ns('attr_mutator')
273 273
274 ip.options.autocall = 1
274 ip.options.autocall = 1
275 275
276 276 run_one_test('attr_mutator.foo should mutate', handle_normal)
277 277 check(attr_mutator.called, 'ofind should be called in absence of assign characters')
278 278
279 for c in list('!=()<>+*/%^&|'):
279 for c in list('!=()<>+*/%^&|'):
280 280 attr_mutator.called = False
281 281 run_one_test('attr_mutator.foo %s should *not* mutate' % c, handle_normal)
282 282 run_one_test('attr_mutator.foo%s should *not* mutate' % c, handle_normal)
283
283
284 284 check(not attr_mutator.called,
285 285 'ofind should not be called near character %s' % c)
286 286
@@ -302,7 +302,7 b' for ac_state in [0,1]:'
302 302 run_handler_tests([
303 303 ("alias_cmd", handle_alias),
304 304 # XXX See note above
305 #("alias_head.with_dot unshadowed, autocall=%s" % ac_state, handle_alias),
305 #("alias_head.with_dot unshadowed, autocall=%s" % ac_state, handle_alias),
306 306 ("alias_cmd.something aliases must match whole expr", handle_normal),
307 307 ("alias_cmd /", handle_alias),
308 308 ])
@@ -331,7 +331,7 b' import IPython.ipapi'
331 331 class Autocallable(IPython.ipapi.IPyAutocall):
332 332 def __call__(self):
333 333 return "called"
334
334
335 335 autocallable = Autocallable()
336 336 ip.to_user_ns('autocallable')
337 337
@@ -344,13 +344,13 b' run_handler_tests( ['
344 344 ( 'len autocall_0', handle_normal),
345 345 ( 'thing autocall_0', handle_normal),
346 346 ( 'autocallable', handle_auto),
347
347
348 348 # With explicit escapes, callable and non-callables both get expanded,
349 349 # regardless of the %autocall setting:
350 350 ( '/len autocall_0', handle_auto),
351 351 ( ',len autocall_0 b0', handle_auto),
352 352 ( ';len autocall_0 b0', handle_auto),
353
353
354 354 ( '/thing autocall_0', handle_auto),
355 355 ( ',thing autocall_0 b0', handle_auto),
356 356 ( ';thing autocall_0 b0', handle_auto),
@@ -370,7 +370,7 b' run_handler_tests( ['
370 370
371 371
372 372 # Now, with autocall in default, 'smart' mode
373 ip.options.autocall = 1
373 ip.options.autocall = 1
374 374 run_handler_tests( [
375 375 # Autocalls without escapes -- only expand if it's callable
376 376 ( 'len a1', handle_auto),
@@ -416,8 +416,8 b' for b in bin_ops:'
416 416 bin_tests.append((';len %s binop_autocall' % b, handle_auto))
417 417 bin_tests.append((',len %s binop_autocall' % b, handle_auto))
418 418 bin_tests.append(('/len %s binop_autocall' % b, handle_auto))
419
420 # Who loves auto-generating tests?
419
420 # Who loves auto-generating tests?
421 421 run_handler_tests(bin_tests)
422 422
423 423
@@ -431,7 +431,7 b' run_handler_tests(bin_tests)'
431 431 # ============
432 432 num_f = len(failures)
433 433 if verbose:
434 print
434 print
435 435 print "%s tests run, %s failure%s" % (num_tests,
436 436 num_f,
437 437 num_f != 1 and "s" or "")
@@ -10,7 +10,7 b' import sys'
10 10 from twisted.internet import reactor, threads
11 11
12 12 from IPython.core.ipmaker import make_IPython
13 from IPython.core.iplib import InteractiveShell
13 from IPython.core.iplib import InteractiveShell
14 14 from IPython.utils.ipstruct import Struct
15 15 import Queue,thread,threading,signal
16 16 from signal import signal, SIGINT
@@ -43,7 +43,7 b' def hijack_reactor():'
43 43 return getattr(orig_reactor, name)
44 44 def __setattr__(self, name, value):
45 45 return setattr(orig_reactor, name, value)
46
46
47 47 internet.reactor = DummyReactor()
48 48 return orig_reactor
49 49
@@ -62,12 +62,12 b' class TwistedInteractiveShell(InteractiveShell):'
62 62 def __init__(self,name,usage=None,rc=Struct(opts=None,args=None),
63 63 user_ns=None,user_global_ns=None,banner2='',**kw):
64 64 """Similar to the normal InteractiveShell, but with threading control"""
65
65
66 66 InteractiveShell.__init__(self,name,usage,rc,user_ns,
67 67 user_global_ns,banner2)
68 68
69 69
70 # A queue to hold the code to be executed.
70 # A queue to hold the code to be executed.
71 71 self.code_queue = Queue.Queue()
72 72
73 73 # Stuff to do at closing time
@@ -82,13 +82,13 b' class TwistedInteractiveShell(InteractiveShell):'
82 82 self.worker_ident = None
83 83 self.reactor_started = False
84 84 self.first_run = True
85
85
86 86 def runsource(self, source, filename="<input>", symbol="single"):
87 87 """Compile and run some source in the interpreter.
88 88
89 89 Modified version of code.py's runsource(), to handle threading issues.
90 90 See the original for full docstring details."""
91
91
92 92 # If Ctrl-C was typed, we reset the flag and return right away
93 93 if shellglobals.KBINT:
94 94 shellglobals.KBINT = False
@@ -97,7 +97,7 b' class TwistedInteractiveShell(InteractiveShell):'
97 97 if self._kill:
98 98 # can't queue new code if we are being killed
99 99 return True
100
100
101 101 try:
102 102 code = self.compile(source, filename, symbol)
103 103 except (OverflowError, SyntaxError, ValueError):
@@ -109,21 +109,21 b' class TwistedInteractiveShell(InteractiveShell):'
109 109 # Case 2
110 110 return True
111 111
112 # shortcut - if we are in worker thread, or the worker thread is not running,
113 # execute directly (to allow recursion and prevent deadlock if code is run early
112 # shortcut - if we are in worker thread, or the worker thread is not running,
113 # execute directly (to allow recursion and prevent deadlock if code is run early
114 114 # in IPython construction)
115
116 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
115
116 if (not self.reactor_started or (self.worker_ident is None and not self.first_run)
117 117 or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)):
118 118 InteractiveShell.runcode(self,code)
119 119 return
120 120
121 121 # Case 3
122 122 # Store code in queue, so the execution thread can handle it.
123
123
124 124 self.first_run = False
125 completed_ev, received_ev = threading.Event(), threading.Event()
126
125 completed_ev, received_ev = threading.Event(), threading.Event()
126
127 127 self.code_queue.put((code,completed_ev, received_ev))
128 128
129 129 reactor.callLater(0.0,self.runcode)
@@ -133,18 +133,18 b' class TwistedInteractiveShell(InteractiveShell):'
133 133 print "Warning: Timeout for mainloop thread exceeded"
134 134 print "switching to nonthreaded mode (until mainloop wakes up again)"
135 135 self.worker_ident = None
136 else:
136 else:
137 137 completed_ev.wait()
138
138
139 139 return False
140 140
141 141 def runcode(self):
142 142 """Execute a code object.
143 143
144 144 Multithreaded wrapper around IPython's runcode()."""
145
146
147 # we are in worker thread, stash out the id for runsource()
145
146
147 # we are in worker thread, stash out the id for runsource()
148 148 self.worker_ident = thread.get_ident()
149 149
150 150 if self._kill:
@@ -172,12 +172,12 b' class TwistedInteractiveShell(InteractiveShell):'
172 172 code_to_run = None
173 173 while 1:
174 174 try:
175 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
175 code_to_run, completed_ev, received_ev = self.code_queue.get_nowait()
176 176 except Queue.Empty:
177 177 break
178 178 received_ev.set()
179 179
180
180
181 181 # Exceptions need to be raised differently depending on which
182 182 # thread is active. This convoluted try/except is only there to
183 183 # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT
@@ -196,8 +196,8 b' class TwistedInteractiveShell(InteractiveShell):'
196 196 finally:
197 197 shellglobals.CODE_RUN = False
198 198 # allow runsource() return from wait
199 completed_ev.set()
200
199 completed_ev.set()
200
201 201 # This MUST return true for gtk threading to work
202 202 return True
203 203
@@ -237,7 +237,7 b' class IPShellTwisted:'
237 237 while True and not self.quitting:
238 238 reactorrun_orig()
239 239 self.reactor.run = reactorrun
240
240
241 241 self.IP = make_IPython(argv, user_ns=user_ns, debug=debug,
242 242 shell_class=shell_class,
243 243 on_kill=[mainquit])
@@ -258,8 +258,8 b' class IPShellTwisted:'
258 258 reactor.callWhenRunning(spawnMainloopThread)
259 259 self.IP.reactor_started = True
260 260 self.reactor.run()
261 print "mainloop ending...."
262
261 print "mainloop ending...."
262
263 263 exists = True
264 264
265 265
@@ -53,19 +53,19 b' class ParalleMagic(Plugin):'
53 53 def magic_result(self, ipself, parameter_s=''):
54 54 """Print the result of command i on all engines..
55 55
56 To use this a :class:`DirectView` instance must be created
56 To use this a :class:`DirectView` instance must be created
57 57 and then activated by calling its :meth:`activate` method.
58 58
59 59 Then you can do the following::
60 60
61 61 In [23]: %result
62 Out[23]:
62 Out[23]:
63 63 <Results List>
64 64 [0] In [6]: a = 10
65 65 [1] In [6]: a = 10
66
66
67 67 In [22]: %result 6
68 Out[22]:
68 Out[22]:
69 69 <Results List>
70 70 [0] In [6]: a = 10
71 71 [1] In [6]: a = 10
@@ -85,14 +85,14 b' class ParalleMagic(Plugin):'
85 85 def magic_px(self, ipself, parameter_s=''):
86 86 """Executes the given python command in parallel.
87 87
88 To use this a :class:`DirectView` instance must be created
88 To use this a :class:`DirectView` instance must be created
89 89 and then activated by calling its :meth:`activate` method.
90
90
91 91 Then you can do the following::
92 92
93 93 In [24]: %px a = 5
94 94 Parallel execution on engine(s): all
95 Out[24]:
95 Out[24]:
96 96 <Results List>
97 97 [0] In [7]: a = 5
98 98 [1] In [7]: a = 5
@@ -111,7 +111,7 b' class ParalleMagic(Plugin):'
111 111 def magic_autopx(self, ipself, parameter_s=''):
112 112 """Toggles auto parallel mode.
113 113
114 To use this a :class:`DirectView` instance must be created
114 To use this a :class:`DirectView` instance must be created
115 115 and then activated by calling its :meth:`activate` method. Once this
116 116 is called, all commands typed at the command line are send to
117 117 the engines to be executed in parallel. To control which engine
@@ -142,7 +142,7 b' class ParalleMagic(Plugin):'
142 142 self._enable_autopx()
143 143
144 144 def _enable_autopx(self):
145 """Enable %autopx mode by saving the original run_cell and installing
145 """Enable %autopx mode by saving the original run_cell and installing
146 146 pxrun_cell.
147 147 """
148 148 if self.active_view is None:
@@ -157,7 +157,7 b' class ParalleMagic(Plugin):'
157 157
158 158 self.autopx = True
159 159 print "%autopx enabled"
160
160
161 161 def _disable_autopx(self):
162 162 """Disable %autopx by restoring the original InteractiveShell.run_cell.
163 163 """
@@ -178,7 +178,7 b' class ParalleMagic(Plugin):'
178 178 stdouts = [result.stdout.rstrip()]
179 179 else:
180 180 stdouts = [s.rstrip() for s in result.stdout]
181
181
182 182 targets = self.active_view.targets
183 183 if isinstance(targets, int):
184 184 targets = [targets]
@@ -192,29 +192,29 b' class ParalleMagic(Plugin):'
192 192
193 193 def pxrun_cell(self, raw_cell, store_history=True):
194 194 """drop-in replacement for InteractiveShell.run_cell.
195
195
196 196 This executes code remotely, instead of in the local namespace.
197 197
198 198 See InteractiveShell.run_cell for details.
199 199 """
200
200
201 201 if (not raw_cell) or raw_cell.isspace():
202 202 return
203
203
204 204 ipself = self.shell
205
205
206 206 with ipself.builtin_trap:
207 207 cell = ipself.prefilter_manager.prefilter_lines(raw_cell)
208
208
209 209 # Store raw and processed history
210 210 if store_history:
211 ipself.history_manager.store_inputs(ipself.execution_count,
211 ipself.history_manager.store_inputs(ipself.execution_count,
212 212 cell, raw_cell)
213 213
214 214 # ipself.logger.log(cell, raw_cell)
215
215
216 216 cell_name = ipself.compile.cache(cell, ipself.execution_count)
217
217
218 218 try:
219 219 code_ast = ast.parse(cell, filename=cell_name)
220 220 except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError):
@@ -232,7 +232,7 b' class ParalleMagic(Plugin):'
232 232 ipself.history_manager.store_output(ipself.execution_count)
233 233 # Each cell is a *single* input, regardless of how many lines it has
234 234 ipself.execution_count += 1
235
235
236 236 if re.search(r'get_ipython\(\)\.magic\(u?"%?autopx', cell):
237 237 self._disable_autopx()
238 238 return False
@@ -94,7 +94,7 b' def matchorfail(text, pos):'
94 94
95 95 class Itpl:
96 96 """Class representing a string with interpolation abilities.
97
97
98 98 Upon creation, an instance works out what parts of the format
99 99 string are literal and what parts need to be evaluated. The
100 100 evaluation and substitution happens in the namespace of the
@@ -106,10 +106,10 b' class Itpl:'
106 106
107 107 The format string is parsed according to the following rules:
108 108
109 1. A dollar sign and a name, possibly followed by any of:
110 - an open-paren, and anything up to the matching paren
111 - an open-bracket, and anything up to the matching bracket
112 - a period and a name
109 1. A dollar sign and a name, possibly followed by any of:
110 - an open-paren, and anything up to the matching paren
111 - an open-bracket, and anything up to the matching bracket
112 - a period and a name
113 113 any number of times, is evaluated as a Python expression.
114 114
115 115 2. A dollar sign immediately followed by an open-brace, and
@@ -135,7 +135,7 b' class Itpl:'
135 135 self.format = format
136 136 self.codec = codec
137 137 self.encoding_errors = encoding_errors
138
138
139 139 namechars = "abcdefghijklmnopqrstuvwxyz" \
140 140 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
141 141 chunks = []
@@ -212,7 +212,7 b' class Itpl:'
212 212 loc, glob = frame.f_locals, frame.f_globals
213 213
214 214 return self._str(glob,loc)
215
215
216 216 class ItplNS(Itpl):
217 217 """Class representing a string with interpolation abilities.
218 218
@@ -221,7 +221,7 b' class ItplNS(Itpl):'
221 221 efficient, as no traceback needs to be extracte. It also allows the
222 222 caller to supply a different namespace for the interpolation to occur than
223 223 its own."""
224
224
225 225 def __init__(self, format,globals,locals=None,
226 226 codec='utf_8',encoding_errors='backslashreplace'):
227 227 """ItplNS(format,globals[,locals]) -> interpolating string instance.
@@ -236,7 +236,7 b' class ItplNS(Itpl):'
236 236 self.globals = globals
237 237 self.locals = locals
238 238 Itpl.__init__(self,format,codec,encoding_errors)
239
239
240 240 def __str__(self):
241 241 """Evaluate and substitute the appropriate parts of the string."""
242 242 return self._str(self.globals,self.locals)
@@ -260,7 +260,7 b' class ItplFile:'
260 260
261 261 def filter(file=sys.stdout):
262 262 """Return an ItplFile that filters writes to the given file object.
263
263
264 264 'file = filter(file)' replaces 'file' with a filtered object that
265 265 has a write() method. When called with no argument, this creates
266 266 a filter to sys.stdout."""
@@ -268,7 +268,7 b' def filter(file=sys.stdout):'
268 268
269 269 def unfilter(ifile=None):
270 270 """Return the original file that corresponds to the given ItplFile.
271
271
272 272 'file = unfilter(file)' undoes the effect of 'file = filter(file)'.
273 273 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'."""
274 274 return ifile and ifile.file or sys.stdout.file
@@ -3,12 +3,12 b''
3 3 ## Copyright (c) 2005, Michele Simionato
4 4 ## All rights reserved.
5 5 ##
6 ## Redistributions of source code must retain the above copyright
6 ## Redistributions of source code must retain the above copyright
7 7 ## notice, this list of conditions and the following disclaimer.
8 8 ## Redistributions in bytecode form must reproduce the above copyright
9 9 ## notice, this list of conditions and the following disclaimer in
10 10 ## the documentation and/or other materials provided with the
11 ## distribution.
11 ## distribution.
12 12
13 13 ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14 14 ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -39,7 +39,7 b' except ImportError: # for Python version < 2.5'
39 39 "A simple replacement of functools.partial"
40 40 def __init__(self, func, *args, **kw):
41 41 self.func = func
42 self.args = args
42 self.args = args
43 43 self.keywords = kw
44 44 def __call__(self, *otherargs, **otherkw):
45 45 kw = self.keywords.copy()
@@ -61,7 +61,7 b' class FunctionMaker(object):'
61 61 # func can be a class or a callable, but not an instance method
62 62 self.name = func.__name__
63 63 if self.name == '<lambda>': # small hack for lambda functions
64 self.name = '_lambda_'
64 self.name = '_lambda_'
65 65 self.doc = func.__doc__
66 66 self.module = func.__module__
67 67 if inspect.isfunction(func):
@@ -138,7 +138,7 b' class FunctionMaker(object):'
138 138 """
139 139 if isinstance(obj, str): # "name(signature)"
140 140 name, rest = obj.strip().split('(', 1)
141 signature = rest[:-1] #strip a right parens
141 signature = rest[:-1] #strip a right parens
142 142 func = None
143 143 else: # a function
144 144 name = None
@@ -146,9 +146,9 b' class FunctionMaker(object):'
146 146 func = obj
147 147 fun = cls(func, name, signature, defaults, doc, module)
148 148 ibody = '\n'.join(' ' + line for line in body.splitlines())
149 return fun.make('def %(name)s(%(signature)s):\n' + ibody,
149 return fun.make('def %(name)s(%(signature)s):\n' + ibody,
150 150 evaldict, addsource, **attrs)
151
151
152 152 def decorator(caller, func=None):
153 153 """
154 154 decorator(caller) converts a caller function into a decorator;
@@ -164,7 +164,7 b' def decorator(caller, func=None):'
164 164 # otherwise assume caller is a function
165 165 f = inspect.getargspec(caller)[0][0] # first arg
166 166 return FunctionMaker.create(
167 '%s(%s)' % (caller.__name__, f),
167 '%s(%s)' % (caller.__name__, f),
168 168 'return decorator(_call_, %s)' % f,
169 169 dict(_call_=caller, decorator=decorator), undecorated=caller,
170 170 doc=caller.__doc__, module=caller.__module__)
@@ -191,7 +191,7 b' def getinfo(func):'
191 191 - doc (the docstring : str)
192 192 - module (the module name : str)
193 193 - dict (the function __dict__ : str)
194
194
195 195 >>> def f(self, x=1, y=2, *args, **kw): pass
196 196
197 197 >>> info = getinfo(f)
@@ -200,7 +200,7 b' def getinfo(func):'
200 200 'f'
201 201 >>> info["argnames"]
202 202 ['self', 'x', 'y', 'args', 'kw']
203
203
204 204 >>> info["defaults"]
205 205 (1, 2)
206 206
@@ -237,7 +237,7 b' def update_wrapper(wrapper, model, infodict=None):'
237 237 def new_wrapper(wrapper, model):
238 238 """
239 239 An improvement over functools.update_wrapper. The wrapper is a generic
240 callable object. It works by generating a copy of the wrapper with the
240 callable object. It works by generating a copy of the wrapper with the
241 241 right signature and by updating the copy, not the original.
242 242 Moreovoer, 'model' can be a dictionary with keys 'name', 'doc', 'module',
243 243 'dict', 'defaults'.
@@ -138,9 +138,9 b' def skipif(skip_condition, msg=None):'
138 138
139 139 def get_msg(func,msg=None):
140 140 """Skip message with information about function being skipped."""
141 if msg is None:
141 if msg is None:
142 142 out = 'Test skipped due to test condition'
143 else:
143 else:
144 144 out = '\n'+msg
145 145
146 146 return "Skipping test: %s%s" % (func.__name__,out)
@@ -167,7 +167,7 b' def skipif(skip_condition, msg=None):'
167 167 skipper = skipper_gen
168 168 else:
169 169 skipper = skipper_func
170
170
171 171 return nose.tools.make_decorator(f)(skipper)
172 172
173 173 return skip_decorator
@@ -5,41 +5,41 b''
5 5 #
6 6 # Copyright (c) 2006 Conan C. Albrecht
7 7 #
8 # Permission is hereby granted, free of charge, to any person obtaining a copy
9 # of this software and associated documentation files (the "Software"), to deal
10 # in the Software without restriction, including without limitation the rights
11 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 # copies of the Software, and to permit persons to whom the Software is furnished
8 # Permission is hereby granted, free of charge, to any person obtaining a copy
9 # of this software and associated documentation files (the "Software"), to deal
10 # in the Software without restriction, including without limitation the rights
11 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 # copies of the Software, and to permit persons to whom the Software is furnished
13 13 # to do so, subject to the following conditions:
14 14 #
15 # The above copyright notice and this permission notice shall be included in all
15 # The above copyright notice and this permission notice shall be included in all
16 16 # copies or substantial portions of the Software.
17 17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
19 # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
20 # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
21 # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
19 # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
20 # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
21 # FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 23 # DEALINGS IN THE SOFTWARE.
24 24
25 25
26 26
27 27 ##################################################################################################
28 ### A globally-unique identifier made up of time and ip and 8 digits for a counter:
28 ### A globally-unique identifier made up of time and ip and 8 digits for a counter:
29 29 ### each GUID is 40 characters wide
30 30 ###
31 ### A globally unique identifier that combines ip, time, and a counter. Since the
32 ### time is listed first, you can sort records by guid. You can also extract the time
33 ### and ip if needed.
31 ### A globally unique identifier that combines ip, time, and a counter. Since the
32 ### time is listed first, you can sort records by guid. You can also extract the time
33 ### and ip if needed.
34 34 ###
35 ### Since the counter has eight hex characters, you can create up to
35 ### Since the counter has eight hex characters, you can create up to
36 36 ### 0xffffffff (4294967295) GUIDs every millisecond. If your processor
37 37 ### is somehow fast enough to create more than that in a millisecond (looking
38 38 ### toward the future, of course), the function will wait until the next
39 39 ### millisecond to return.
40 ###
41 ### GUIDs make wonderful database keys. They require no access to the
42 ### database (to get the max index number), they are extremely unique, and they sort
40 ###
41 ### GUIDs make wonderful database keys. They require no access to the
42 ### database (to get the max index number), they are extremely unique, and they sort
43 43 ### automatically by time. GUIDs prevent key clashes when merging
44 44 ### two databases together, combining data, or generating keys in distributed
45 45 ### systems.
@@ -57,9 +57,9 b''
57 57 # December 2, 2003 Fixed duplicating GUIDs. Sometimes they duplicate if multiples are created
58 58 # in the same millisecond (it checks the last 100 GUIDs now and has a larger random part)
59 59 # December 9, 2003 Fixed MAX_RANDOM, which was going over sys.maxint
60 # June 12, 2004 Allowed a custom IP address to be sent in rather than always using the
61 # local IP address.
62 # November 4, 2005 Changed the random part to a counter variable. Now GUIDs are totally
60 # June 12, 2004 Allowed a custom IP address to be sent in rather than always using the
61 # local IP address.
62 # November 4, 2005 Changed the random part to a counter variable. Now GUIDs are totally
63 63 # unique and more efficient, as long as they are created by only
64 64 # on runtime on a given machine. The counter part is after the time
65 65 # part so it sorts correctly.
@@ -87,7 +87,7 b' import threading'
87 87
88 88 #Makes a hex IP from a decimal dot-separated ip (eg: 127.0.0.1)
89 89 make_hexip = lambda ip: ''.join(["%04x" % long(i) for i in ip.split('.')]) # leave space for ip v6 (65K in each sub)
90
90
91 91 MAX_COUNTER = 0xfffffffe
92 92 counter = 0L
93 93 firstcounter = MAX_COUNTER
@@ -104,7 +104,7 b" except: # if we don't have an ip, default to someting in the 10.x.x.x private ra"
104 104 ip += '.' + str(rand.randrange(1, 0xffff)) # might as well use IPv6 range if we're making it up
105 105 hexip = make_hexip(ip)
106 106
107
107
108 108 #################################
109 109 ### Public module functions
110 110
@@ -121,7 +121,7 b' def generate(ip=None):'
121 121
122 122 # do we need to wait for the next millisecond (are we out of counters?)
123 123 now = long(time.time() * 1000)
124 while lasttime == now and counter == firstcounter:
124 while lasttime == now and counter == firstcounter:
125 125 time.sleep(.01)
126 126 now = long(time.time() * 1000)
127 127
@@ -136,7 +136,7 b' def generate(ip=None):'
136 136 if counter > MAX_COUNTER:
137 137 counter = 0
138 138 lasttime = now
139 parts.append("%08x" % (counter))
139 parts.append("%08x" % (counter))
140 140
141 141 # ip part
142 142 parts.append(hexip)
@@ -145,10 +145,10 b' def generate(ip=None):'
145 145 return ''.join(parts)
146 146 finally:
147 147 lock.release()
148
148
149 149
150 150 def extract_time(guid):
151 '''Extracts the time portion out of the guid and returns the
151 '''Extracts the time portion out of the guid and returns the
152 152 number of seconds since the epoch as a float'''
153 153 return float(long(guid[0:16], 16)) / 1000.0
154 154
@@ -1,26 +1,26 b''
1 1 r""" mglob - enhanced file list expansion module
2 2
3 Use as stand-alone utility (for xargs, `backticks` etc.),
4 or a globbing library for own python programs. Globbing the sys.argv is something
3 Use as stand-alone utility (for xargs, `backticks` etc.),
4 or a globbing library for own python programs. Globbing the sys.argv is something
5 5 that almost every Windows script has to perform manually, and this module is here
6 to help with that task. Also Unix users will benefit from enhanced modes
6 to help with that task. Also Unix users will benefit from enhanced modes
7 7 such as recursion, exclusion, directory omission...
8 8
9 Unlike glob.glob, directories are not included in the glob unless specified
9 Unlike glob.glob, directories are not included in the glob unless specified
10 10 with 'dir:'
11 11
12 12 'expand' is the function to use in python programs. Typical use
13 13 to expand argv (esp. in windows)::
14 14
15 15 try:
16 import mglob
16 import mglob
17 17 files = mglob.expand(sys.argv[1:])
18 18 except ImportError:
19 19 print "mglob not found; try 'easy_install mglob' for extra features"
20 files = sys.argv[1:]
20 files = sys.argv[1:]
21 21
22 22 Note that for unix, shell expands *normal* wildcards (*.cpp, etc.) in argv.
23 Therefore, you might want to use quotes with normal wildcards to prevent this
23 Therefore, you might want to use quotes with normal wildcards to prevent this
24 24 expansion, in order for mglob to see the wildcards and get the wanted behaviour.
25 25 Not quoting the wildcards is harmless and typically has equivalent results, though.
26 26
@@ -34,27 +34,27 b' License: MIT Open Source license'
34 34 globsyntax = """\
35 35 This program allows specifying filenames with "mglob" mechanism.
36 36 Supported syntax in globs (wilcard matching patterns)::
37
38 *.cpp ?ellowo*
37
38 *.cpp ?ellowo*
39 39 - obvious. Differs from normal glob in that dirs are not included.
40 40 Unix users might want to write this as: "*.cpp" "?ellowo*"
41 rec:/usr/share=*.txt,*.doc
42 - get all *.txt and *.doc under /usr/share,
41 rec:/usr/share=*.txt,*.doc
42 - get all *.txt and *.doc under /usr/share,
43 43 recursively
44 44 rec:/usr/share
45 45 - All files under /usr/share, recursively
46 46 rec:*.py
47 47 - All .py files under current working dir, recursively
48 foo
48 foo
49 49 - File or dir foo
50 !*.bak readme*
50 !*.bak readme*
51 51 - readme*, exclude files ending with .bak
52 52 !.svn/ !.hg/ !*_Data/ rec:.
53 53 - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse.
54 54 Trailing / is the key, \ does not work! Use !.*/ for all hidden.
55 dir:foo
55 dir:foo
56 56 - the directory foo if it exists (not files in foo)
57 dir:*
57 dir:*
58 58 - all directories in current folder
59 59 foo.py bar.* !h* rec:*.py
60 60 - Obvious. !h* exclusion only applies for rec:*.py.
@@ -71,16 +71,16 b' __version__ = "0.2"'
71 71
72 72
73 73 import os,glob,fnmatch,sys,re
74
74
75 75 def expand(flist,exp_dirs = False):
76 76 """ Expand the glob(s) in flist.
77
77
78 78 flist may be either a whitespace-separated list of globs/files
79 79 or an array of globs/files.
80
80
81 81 if exp_dirs is true, directory names in glob are expanded to the files
82 82 contained in them - otherwise, directory names are returned as is.
83
83
84 84 """
85 85 if isinstance(flist, basestring):
86 86 import shlex
@@ -89,7 +89,7 b' def expand(flist,exp_dirs = False):'
89 89 denied_set = set()
90 90 cont_set = set()
91 91 cur_rejected_dirs = set()
92
92
93 93 def recfind(p, pats = ["*"]):
94 94 denied_dirs = [os.path.dirname(d) for d in denied_set if d.endswith("/")]
95 95 for (dp,dnames,fnames) in os.walk(p):
@@ -103,7 +103,7 b' def expand(flist,exp_dirs = False):'
103 103 break
104 104 if deny:
105 105 continue
106
106
107 107
108 108 #print "dp",dp
109 109 bname = os.path.basename(dp)
@@ -115,7 +115,7 b' def expand(flist,exp_dirs = False):'
115 115 if deny:
116 116 continue
117 117
118
118
119 119 for f in fnames:
120 120 matched = False
121 121 for p in pats:
@@ -123,7 +123,7 b' def expand(flist,exp_dirs = False):'
123 123 matched = True
124 124 break
125 125 if matched:
126 yield os.path.join(dp,f)
126 yield os.path.join(dp,f)
127 127
128 128 def once_filter(seq):
129 129 for it in seq:
@@ -146,30 +146,30 b' def expand(flist,exp_dirs = False):'
146 146 if not re.search(pat,cont, re.IGNORECASE):
147 147 deny = True
148 148 break
149
149
150 150 if not deny:
151 151 yield it
152 152 return
153
153
154 154 res = []
155 155
156 156 for ent in flist:
157 157 ent = os.path.expanduser(os.path.expandvars(ent))
158 158 if ent.lower().startswith('rec:'):
159 fields = ent[4:].split('=')
159 fields = ent[4:].split('=')
160 160 if len(fields) == 2:
161 161 pth, patlist = fields
162 162 elif len(fields) == 1:
163 163 if os.path.isdir(fields[0]):
164 164 # single arg is dir
165 165 pth, patlist = fields[0], '*'
166 else:
166 else:
167 167 # single arg is pattern
168 168 pth, patlist = '.', fields[0]
169
169
170 170 elif len(fields) == 0:
171 171 pth, pathlist = '.','*'
172
172
173 173 pats = patlist.split(',')
174 174 res.extend(once_filter(recfind(pth, pats)))
175 175 # filelist
@@ -186,7 +186,7 b' def expand(flist,exp_dirs = False):'
186 186 # get all files in the specified dir
187 187 elif os.path.isdir(ent) and exp_dirs:
188 188 res.extend(once_filter(filter(os.path.isfile,glob.glob(ent + os.sep+"*"))))
189
189
190 190 # glob only files
191 191
192 192 elif '*' in ent or '?' in ent:
@@ -195,19 +195,19 b' def expand(flist,exp_dirs = False):'
195 195 else:
196 196 res.extend(once_filter([ent]))
197 197 return res
198
199
198
199
200 200 def test():
201 201 assert (
202 expand("*.py ~/.ipython/*.py rec:/usr/share/doc-base") ==
203 expand( ['*.py', '~/.ipython/*.py', 'rec:/usr/share/doc-base'] )
202 expand("*.py ~/.ipython/*.py rec:/usr/share/doc-base") ==
203 expand( ['*.py', '~/.ipython/*.py', 'rec:/usr/share/doc-base'] )
204 204 )
205
205
206 206 def main():
207 207 if len(sys.argv) < 2:
208 208 print globsyntax
209 209 return
210
210
211 211 print "\n".join(expand(sys.argv[1:])),
212 212
213 213 def mglob_f(self, arg):
@@ -220,8 +220,8 b' def mglob_f(self, arg):'
220 220 def init_ipython(ip):
221 221 """ register %mglob for IPython """
222 222 mglob_f.__doc__ = globsyntax
223 ip.define_magic("mglob",mglob_f)
224
223 ip.define_magic("mglob",mglob_f)
224
225 225 # test()
226 226 if __name__ == "__main__":
227 227 main()
@@ -86,7 +86,7 b' __all__ = ['
86 86 'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno',
87 87 'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
88 88 'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
89 'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity',
89 'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity',
90 90 'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
91 91 'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
92 92 'indentedBlock', 'originalTextFor',
@@ -430,7 +430,7 b' class ParseResults(object):'
430 430 self[k] = v
431 431 if isinstance(v[0],ParseResults):
432 432 v[0].__parent = wkref(self)
433
433
434 434 self.__toklist += other.__toklist
435 435 self.__accumNames.update( other.__accumNames )
436 436 del other
@@ -3269,12 +3269,12 b' def originalTextFor(expr, asString=True):'
3269 3269 restore the parsed fields of an HTML start tag into the raw tag text itself, or to
3270 3270 revert separate tokens with intervening whitespace back to the original matching
3271 3271 input text. Simpler to use than the parse action keepOriginalText, and does not
3272 require the inspect module to chase up the call stack. By default, returns a
3273 string containing the original parsed text.
3274
3275 If the optional asString argument is passed as False, then the return value is a
3276 ParseResults containing any results names that were originally matched, and a
3277 single token containing the original matched text from the input string. So if
3272 require the inspect module to chase up the call stack. By default, returns a
3273 string containing the original parsed text.
3274
3275 If the optional asString argument is passed as False, then the return value is a
3276 ParseResults containing any results names that were originally matched, and a
3277 single token containing the original matched text from the input string. So if
3278 3278 the expression passed to originalTextFor contains expressions with defined
3279 3279 results names, you must set asString to False if you want to preserve those
3280 3280 results name values."""
@@ -3290,7 +3290,7 b' def originalTextFor(expr, asString=True):'
3290 3290 del t["_original_end"]
3291 3291 matchExpr.setParseAction(extractText)
3292 3292 return matchExpr
3293
3293
3294 3294 # convenience constants for positional expressions
3295 3295 empty = Empty().setName("empty")
3296 3296 lineStart = LineStart().setName("lineStart")
@@ -3570,7 +3570,7 b' def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString):'
3570 3570 ).setParseAction(lambda t:t[0].strip()))
3571 3571 else:
3572 3572 if ignoreExpr is not None:
3573 content = (Combine(OneOrMore(~ignoreExpr +
3573 content = (Combine(OneOrMore(~ignoreExpr +
3574 3574 ~Literal(opener) + ~Literal(closer) +
3575 3575 CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
3576 3576 ).setParseAction(lambda t:t[0].strip()))
@@ -40,7 +40,7 b' if QT_API is None:'
40 40 QT_API = QT_API_PYQT
41 41 except ImportError:
42 42 raise ImportError('Cannot import PySide >= 1.0.3 or PyQt4 >= 4.7')
43
43
44 44 elif QT_API == QT_API_PYQT:
45 45 # Note: This must be called *before* PyQt4 is imported.
46 46 prepare_pyqt4()
@@ -62,5 +62,5 b' elif QT_API == QT_API_PYSIDE:'
62 62 from PySide import QtCore, QtGui, QtSvg
63 63
64 64 else:
65 raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' %
65 raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' %
66 66 (QT_API, QT_API_PYQT, QT_API_PYSIDE))
@@ -75,7 +75,7 b' def try_passwordless_ssh(server, keyfile, paramiko=None):'
75 75 """Attempt to make an ssh connection without a password.
76 76 This is mainly used for requiring password input only once
77 77 when many tunnels may be connected to the same server.
78
78
79 79 If paramiko is None, the default for the platform is chosen.
80 80 """
81 81 if paramiko is None:
@@ -130,12 +130,12 b' def _try_passwordless_paramiko(server, keyfile):'
130 130
131 131 def tunnel_connection(socket, addr, server, keyfile=None, password=None, paramiko=None, timeout=60):
132 132 """Connect a socket to an address via an ssh tunnel.
133
133
134 134 This is a wrapper for socket.connect(addr), when addr is not accessible
135 135 from the local machine. It simply creates an ssh tunnel using the remaining args,
136 136 and calls socket.connect('tcp://localhost:lport') where lport is the randomly
137 137 selected local port of the tunnel.
138
138
139 139 """
140 140 new_url, tunnel = open_tunnel(addr, server, keyfile=keyfile, password=password, paramiko=paramiko, timeout=timeout)
141 141 socket.connect(new_url)
@@ -144,15 +144,15 b' def tunnel_connection(socket, addr, server, keyfile=None, password=None, paramik'
144 144
145 145 def open_tunnel(addr, server, keyfile=None, password=None, paramiko=None, timeout=60):
146 146 """Open a tunneled connection from a 0MQ url.
147
147
148 148 For use inside tunnel_connection.
149
149
150 150 Returns
151 151 -------
152
152
153 153 (url, tunnel): The 0MQ url that has been forwarded, and the tunnel object
154 154 """
155
155
156 156 lport = select_random_ports(1)[0]
157 157 transport, addr = addr.split('://')
158 158 ip,rport = addr.split(':')
@@ -163,7 +163,7 b' def open_tunnel(addr, server, keyfile=None, password=None, paramiko=None, timeou'
163 163 tunnelf = paramiko_tunnel
164 164 else:
165 165 tunnelf = openssh_tunnel
166
166
167 167 tunnel = tunnelf(lport, rport, server, remoteip=ip, keyfile=keyfile, password=password, timeout=timeout)
168 168 return 'tcp://127.0.0.1:%i'%lport, tunnel
169 169
@@ -172,15 +172,15 b" def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pas"
172 172 on this machine to localhost:rport on server. The tunnel
173 173 will automatically close when not in use, remaining open
174 174 for a minimum of timeout seconds for an initial connection.
175
175
176 176 This creates a tunnel redirecting `localhost:lport` to `remoteip:rport`,
177 177 as seen from `server`.
178
178
179 179 keyfile and password may be specified, but ssh config is checked for defaults.
180
180
181 181 Parameters
182 182 ----------
183
183
184 184 lport : int
185 185 local port for connecting to the tunnel from this machine.
186 186 rport : int
@@ -192,11 +192,11 b" def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pas"
192 192 The remote ip, specifying the destination of the tunnel.
193 193 Default is localhost, which means that the tunnel would redirect
194 194 localhost:lport on this machine to localhost:rport on the *server*.
195
195
196 196 keyfile : str; path to public key file
197 197 This specifies a key to be used in ssh login, default None.
198 198 Regular default ssh keys will be used without specifying this argument.
199 password : str;
199 password : str;
200 200 Your ssh password to the ssh server. Note that if this is left None,
201 201 you will be prompted for it if passwordless key based login is unavailable.
202 202 timeout : int [default: 60]
@@ -207,7 +207,7 b" def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pas"
207 207 raise ImportError("pexpect unavailable, use paramiko_tunnel")
208 208 ssh="ssh "
209 209 if keyfile:
210 ssh += "-i " + keyfile
210 ssh += "-i " + keyfile
211 211 cmd = ssh + " -f -L 127.0.0.1:%i:%s:%i %s sleep %i"%(lport, remoteip, rport, server, timeout)
212 212 tunnel = pexpect.spawn(cmd)
213 213 failed = False
@@ -232,7 +232,7 b" def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pas"
232 232 password = getpass("%s's password: "%(server))
233 233 tunnel.sendline(password)
234 234 failed = True
235
235
236 236 def _split_server(server):
237 237 if '@' in server:
238 238 username,server = server.split('@', 1)
@@ -248,20 +248,20 b' def _split_server(server):'
248 248 def paramiko_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, password=None, timeout=60):
249 249 """launch a tunner with paramiko in a subprocess. This should only be used
250 250 when shell ssh is unavailable (e.g. Windows).
251
251
252 252 This creates a tunnel redirecting `localhost:lport` to `remoteip:rport`,
253 253 as seen from `server`.
254
254
255 255 If you are familiar with ssh tunnels, this creates the tunnel:
256
256
257 257 ssh server -L localhost:lport:remoteip:rport
258
258
259 259 keyfile and password may be specified, but ssh config is checked for defaults.
260
261
260
261
262 262 Parameters
263 263 ----------
264
264
265 265 lport : int
266 266 local port for connecting to the tunnel from this machine.
267 267 rport : int
@@ -273,33 +273,33 b" def paramiko_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pa"
273 273 The remote ip, specifying the destination of the tunnel.
274 274 Default is localhost, which means that the tunnel would redirect
275 275 localhost:lport on this machine to localhost:rport on the *server*.
276
276
277 277 keyfile : str; path to public key file
278 278 This specifies a key to be used in ssh login, default None.
279 279 Regular default ssh keys will be used without specifying this argument.
280 password : str;
280 password : str;
281 281 Your ssh password to the ssh server. Note that if this is left None,
282 282 you will be prompted for it if passwordless key based login is unavailable.
283 283 timeout : int [default: 60]
284 284 The time (in seconds) after which no activity will result in the tunnel
285 285 closing. This prevents orphaned tunnels from running forever.
286
286
287 287 """
288 288 if paramiko is None:
289 289 raise ImportError("Paramiko not available")
290
290
291 291 if password is None:
292 292 if not _try_passwordless_paramiko(server, keyfile):
293 293 password = getpass("%s's password: "%(server))
294 294
295 p = Process(target=_paramiko_tunnel,
296 args=(lport, rport, server, remoteip),
295 p = Process(target=_paramiko_tunnel,
296 args=(lport, rport, server, remoteip),
297 297 kwargs=dict(keyfile=keyfile, password=password))
298 298 p.daemon=False
299 299 p.start()
300 300 atexit.register(_shutdown_process, p)
301 301 return p
302
302
303 303 def _shutdown_process(p):
304 304 if p.isalive():
305 305 p.terminate()
@@ -342,7 +342,7 b" if sys.platform == 'win32':"
342 342 else:
343 343 ssh_tunnel = openssh_tunnel
344 344
345
345
346 346 __all__ = ['tunnel_connection', 'ssh_tunnel', 'openssh_tunnel', 'paramiko_tunnel', 'try_passwordless_ssh']
347 347
348 348
@@ -50,7 +50,7 b' class AuthenticatedHandler(web.RequestHandler):'
50 50 if not self.application.password:
51 51 user_id = 'anonymous'
52 52 return user_id
53
53
54 54
55 55 class NBBrowserHandler(AuthenticatedHandler):
56 56 @web.authenticated
@@ -176,13 +176,13 b' class AuthenticatedZMQStreamHandler(ZMQStreamHandler):'
176 176 self.session = Session()
177 177 self.save_on_message = self.on_message
178 178 self.on_message = self.on_first_message
179
179
180 180 def get_current_user(self):
181 181 user_id = self.get_secure_cookie("user")
182 182 if user_id == '' or (user_id is None and not self.application.password):
183 183 user_id = 'anonymous'
184 184 return user_id
185
185
186 186 def _inject_cookie_message(self, msg):
187 187 """Inject the first message, which is the document cookie,
188 188 for authentication."""
@@ -193,14 +193,14 b' class AuthenticatedZMQStreamHandler(ZMQStreamHandler):'
193 193 self._cookies = Cookie.SimpleCookie(msg)
194 194 except:
195 195 logging.warn("couldn't parse cookie string: %s",msg, exc_info=True)
196
196
197 197 def on_first_message(self, msg):
198 198 self._inject_cookie_message(msg)
199 199 if self.get_current_user() is None:
200 200 logging.warn("Couldn't authenticate WebSocket connection")
201 201 raise web.HTTPError(403)
202 202 self.on_message = self.save_on_message
203
203
204 204
205 205 class IOPubHandler(AuthenticatedZMQStreamHandler):
206 206
@@ -209,7 +209,7 b' class IOPubHandler(AuthenticatedZMQStreamHandler):'
209 209 self._beating = False
210 210 self.iopub_stream = None
211 211 self.hb_stream = None
212
212
213 213 def on_first_message(self, msg):
214 214 try:
215 215 super(IOPubHandler, self).on_first_message(msg)
@@ -231,12 +231,12 b' class IOPubHandler(AuthenticatedZMQStreamHandler):'
231 231 else:
232 232 self.iopub_stream.on_recv(self._on_zmq_reply)
233 233 self.start_hb(self.kernel_died)
234
234
235 235 def on_message(self, msg):
236 236 pass
237 237
238 238 def on_close(self):
239 # This method can be called twice, once by self.kernel_died and once
239 # This method can be called twice, once by self.kernel_died and once
240 240 # from the WebSocket close event. If the WebSocket connection is
241 241 # closed before the ZMQ streams are setup, they could be None.
242 242 self.stop_hb()
@@ -245,7 +245,7 b' class IOPubHandler(AuthenticatedZMQStreamHandler):'
245 245 self.iopub_stream.close()
246 246 if self.hb_stream is not None and not self.hb_stream.closed():
247 247 self.hb_stream.close()
248
248
249 249 def start_hb(self, callback):
250 250 """Start the heartbeating and call the callback if the kernel dies."""
251 251 if not self._beating:
@@ -12,7 +12,7 b' class BaseFrontendMixin(object):'
12 12 #---------------------------------------------------------------------------
13 13 # 'BaseFrontendMixin' concrete interface
14 14 #---------------------------------------------------------------------------
15
15
16 16 def _get_kernel_manager(self):
17 17 """ Returns the current kernel manager.
18 18 """
@@ -34,7 +34,7 b' class BaseFrontendMixin(object):'
34 34 old_manager.stdin_channel.message_received.disconnect(self._dispatch)
35 35 old_manager.hb_channel.kernel_died.disconnect(
36 36 self._handle_kernel_died)
37
37
38 38 # Handle the case where the old kernel manager is still listening.
39 39 if old_manager.channels_running:
40 40 self._stopped_channels()
@@ -77,9 +77,9 b' class BaseFrontendMixin(object):'
77 77 since_last_heartbeat : float
78 78 The time since the heartbeat was last received.
79 79 """
80
80
81 81 def _started_channels(self):
82 """ Called when the KernelManager channels have started listening or
82 """ Called when the KernelManager channels have started listening or
83 83 when the frontend is assigned an already listening KernelManager.
84 84 """
85 85
@@ -93,7 +93,7 b' class BaseFrontendMixin(object):'
93 93 #---------------------------------------------------------------------------
94 94
95 95 def _dispatch(self, msg):
96 """ Calls the frontend handler associated with the message type of the
96 """ Calls the frontend handler associated with the message type of the
97 97 given message.
98 98 """
99 99 msg_type = msg['header']['msg_type']
@@ -112,7 +112,7 b' class AnsiCodeProcessor(object):'
112 112 ----------
113 113 command : str
114 114 The code identifier, i.e. the final character in the sequence.
115
115
116 116 params : sequence of integers, optional
117 117 The parameter codes for the command.
118 118 """
@@ -143,7 +143,7 b' class AnsiCodeProcessor(object):'
143 143
144 144 def set_osc_code(self, params):
145 145 """ Set attributes based on OSC (Operating System Command) parameters.
146
146
147 147 Parameters
148 148 ----------
149 149 params : sequence of str
@@ -162,7 +162,7 b' class AnsiCodeProcessor(object):'
162 162 self.color_map[color] = self._parse_xterm_color_spec(spec)
163 163 except (IndexError, ValueError):
164 164 pass
165
165
166 166 def set_sgr_code(self, params):
167 167 """ Set attributes based on SGR (Select Graphic Rendition) codes.
168 168
@@ -200,7 +200,7 b' class AnsiCodeProcessor(object):'
200 200 self.underline = False
201 201 elif code >= 30 and code <= 37:
202 202 self.foreground_color = code - 30
203 elif code == 38 and params and params.pop(0) == 5:
203 elif code == 38 and params and params.pop(0) == 5:
204 204 # xterm-specific: 256 color support.
205 205 if params:
206 206 self.foreground_color = params.pop(0)
@@ -226,7 +226,7 b' class AnsiCodeProcessor(object):'
226 226 if spec.startswith('rgb:'):
227 227 return tuple(map(lambda x: int(x, 16), spec[4:].split('/')))
228 228 elif spec.startswith('rgbi:'):
229 return tuple(map(lambda x: int(float(x) * 255),
229 return tuple(map(lambda x: int(float(x) * 255),
230 230 spec[5:].split('/')))
231 231 elif spec == '?':
232 232 raise ValueError('Unsupported xterm color spec')
@@ -237,7 +237,7 b' class AnsiCodeProcessor(object):'
237 237 if special == '\f':
238 238 self.actions.append(ScrollAction('scroll', 'down', 'page', 1))
239 239 return ''
240
240
241 241
242 242 class QtAnsiCodeProcessor(AnsiCodeProcessor):
243 243 """ Translates ANSI escape codes into QTextCharFormats.
@@ -288,7 +288,7 b' class QtAnsiCodeProcessor(AnsiCodeProcessor):'
288 288 return QtGui.QColor(*constructor)
289 289
290 290 return None
291
291
292 292 def get_format(self):
293 293 """ Returns a QTextCharFormat that encodes the current style attributes.
294 294 """
@@ -322,7 +322,7 b' class QtAnsiCodeProcessor(AnsiCodeProcessor):'
322 322 self.default_color_map = self.darkbg_color_map.copy()
323 323
324 324 if color.value() >= 127:
325 # Colors appropriate for a terminal with a light background. For
325 # Colors appropriate for a terminal with a light background. For
326 326 # now, only use non-bright colors...
327 327 for i in xrange(8):
328 328 self.default_color_map[i + 8] = self.default_color_map[i]
@@ -9,7 +9,7 b' class BracketMatcher(QtCore.QObject):'
9 9 """ Matches square brackets, braces, and parentheses based on cursor
10 10 position.
11 11 """
12
12
13 13 # Protected class variables.
14 14 _opening_map = { '(':')', '{':'}', '[':']' }
15 15 _closing_map = { ')':'(', '}':'{', ']':'[' }
@@ -75,7 +75,7 b' class BracketMatcher(QtCore.QObject):'
75 75 selection = QtGui.QTextEdit.ExtraSelection()
76 76 cursor = self._text_edit.textCursor()
77 77 cursor.setPosition(position)
78 cursor.movePosition(QtGui.QTextCursor.NextCharacter,
78 cursor.movePosition(QtGui.QTextCursor.NextCharacter,
79 79 QtGui.QTextCursor.KeepAnchor)
80 80 selection.cursor = cursor
81 81 selection.format = self.format
@@ -134,7 +134,7 b' class CallTipWidget(QtGui.QLabel):'
134 134 doc = doc[:match.end()] + '\n[Documentation continues...]'
135 135 else:
136 136 doc = ''
137
137
138 138 if call_line:
139 139 doc = '\n\n'.join([call_line, doc])
140 140 return self.show_tip(doc)
@@ -147,7 +147,7 b' class CallTipWidget(QtGui.QLabel):'
147 147 document = text_edit.document()
148 148 cursor = text_edit.textCursor()
149 149 search_pos = cursor.position() - 1
150 self._start_position, _ = self._find_parenthesis(search_pos,
150 self._start_position, _ = self._find_parenthesis(search_pos,
151 151 forward=False)
152 152 if self._start_position == -1:
153 153 return False
@@ -155,7 +155,7 b' class CallTipWidget(QtGui.QLabel):'
155 155 # Set the text and resize the widget accordingly.
156 156 self.setText(tip)
157 157 self.resize(self.sizeHint())
158
158
159 159 # Locate and show the widget. Place the tip below the current line
160 160 # unless it would be off the screen. In that case, place it above
161 161 # the current line.
@@ -171,7 +171,7 b' class CallTipWidget(QtGui.QLabel):'
171 171 self.move(point)
172 172 self.show()
173 173 return True
174
174
175 175 #--------------------------------------------------------------------------
176 176 # Protected interface
177 177 #--------------------------------------------------------------------------
@@ -3,7 +3,7 b' from pygments.token import Token, is_token_subtype'
3 3
4 4
5 5 class CompletionLexer(object):
6 """ Uses Pygments and some auxillary information to lex code snippets for
6 """ Uses Pygments and some auxillary information to lex code snippets for
7 7 symbol contexts.
8 8 """
9 9
@@ -30,7 +30,7 b' class CompletionLexer(object):'
30 30 if reversed_tokens and reversed_tokens[0][1].endswith('\n') and \
31 31 not string.endswith('\n'):
32 32 reversed_tokens.pop(0)
33
33
34 34 current_op = ''
35 35 for token, text in reversed_tokens:
36 36
@@ -71,4 +71,4 b' class CompletionLexer(object):'
71 71 self._name_separators = list(name_separators)
72 72
73 73 lexer = property(get_lexer, set_lexer)
74
74
@@ -39,15 +39,15 b' class CompletionWidget(QtGui.QListWidget):'
39 39
40 40 if etype == QtCore.QEvent.KeyPress:
41 41 key, text = event.key(), event.text()
42 if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter,
42 if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter,
43 43 QtCore.Qt.Key_Tab):
44 44 self._complete_current()
45 45 return True
46 46 elif key == QtCore.Qt.Key_Escape:
47 47 self.hide()
48 48 return True
49 elif key in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down,
50 QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown,
49 elif key in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down,
50 QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown,
51 51 QtCore.Qt.Key_Home, QtCore.Qt.Key_End):
52 52 self.keyPressEvent(event)
53 53 return True
@@ -114,16 +114,16 b' class CompletionWidget(QtGui.QListWidget):'
114 114 """
115 115 cursor = self._text_edit.textCursor()
116 116 if cursor.position() >= self._start_position:
117 cursor.setPosition(self._start_position,
117 cursor.setPosition(self._start_position,
118 118 QtGui.QTextCursor.KeepAnchor)
119 119 return cursor
120
120
121 121 def _update_current(self):
122 122 """ Updates the current item based on the current text.
123 123 """
124 124 prefix = self._current_text_cursor().selection().toPlainText()
125 125 if prefix:
126 items = self.findItems(prefix, (QtCore.Qt.MatchStartsWith |
126 items = self.findItems(prefix, (QtCore.Qt.MatchStartsWith |
127 127 QtCore.Qt.MatchCaseSensitive))
128 128 if items:
129 129 self.setCurrentItem(items[0])
@@ -40,11 +40,11 b' def is_letter_or_number(char):'
40 40 #-----------------------------------------------------------------------------
41 41
42 42 class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):
43 """ An abstract base class for console-type widgets. This class has
43 """ An abstract base class for console-type widgets. This class has
44 44 functionality for:
45 45
46 46 * Maintaining a prompt and editing region
47 * Providing the traditional Unix-style console keyboard shortcuts
47 * Providing the traditional Unix-style console keyboard shortcuts
48 48 * Performing tab completion
49 49 * Paging text
50 50 * Handling ANSI escape codes
@@ -79,11 +79,11 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
79 79 """
80 80 )
81 81 # NOTE: this value can only be specified during initialization.
82 paging = Enum(['inside', 'hsplit', 'vsplit', 'custom', 'none'],
82 paging = Enum(['inside', 'hsplit', 'vsplit', 'custom', 'none'],
83 83 default_value='inside', config=True,
84 84 help="""
85 85 The type of paging to use. Valid values are:
86
86
87 87 'inside' : The widget pages like a traditional terminal.
88 88 'hsplit' : When paging is requested, the widget is split
89 89 horizontally. The top pane contains the console, and the
@@ -264,7 +264,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
264 264 key = event.key()
265 265 if self._control_key_down(event.modifiers()) and \
266 266 key in self._ctrl_down_remap:
267 new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress,
267 new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress,
268 268 self._ctrl_down_remap[key],
269 269 QtCore.Qt.NoModifier)
270 270 QtGui.qApp.sendEvent(obj, new_event)
@@ -378,10 +378,10 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
378 378 """ Returns whether text can be cut to the clipboard.
379 379 """
380 380 cursor = self._control.textCursor()
381 return (cursor.hasSelection() and
382 self._in_buffer(cursor.anchor()) and
381 return (cursor.hasSelection() and
382 self._in_buffer(cursor.anchor()) and
383 383 self._in_buffer(cursor.position()))
384
384
385 385 def can_paste(self):
386 386 """ Returns whether text can be pasted from the clipboard.
387 387 """
@@ -390,7 +390,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
390 390 return False
391 391
392 392 def clear(self, keep_input=True):
393 """ Clear the console.
393 """ Clear the console.
394 394
395 395 Parameters:
396 396 -----------
@@ -425,7 +425,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
425 425 input.
426 426
427 427 Parameters:
428 -----------
428 -----------
429 429 source : str, optional
430 430
431 431 The source to execute. If not specified, the input buffer will be
@@ -467,7 +467,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
467 467 source += '\n'
468 468 elif not hidden:
469 469 self.input_buffer = source
470
470
471 471 # Execute the source or show a continuation prompt if it is incomplete.
472 472 complete = self._is_complete(source, interactive)
473 473 if hidden:
@@ -475,7 +475,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
475 475 self._execute(source, hidden)
476 476 else:
477 477 error = 'Incomplete noninteractive input: "%s"'
478 raise RuntimeError(error % source)
478 raise RuntimeError(error % source)
479 479 else:
480 480 if complete:
481 481 self._append_plain_text('\n')
@@ -494,7 +494,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
494 494
495 495 # Perform actual execution.
496 496 self._execute(source, hidden)
497
497
498 498 else:
499 499 # Do this inside an edit block so continuation prompts are
500 500 # removed seamlessly via undo/redo.
@@ -505,7 +505,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
505 505 cursor.endEditBlock()
506 506
507 507 # Do not do this inside the edit block. It works as expected
508 # when using a QPlainTextEdit control, but does not have an
508 # when using a QPlainTextEdit control, but does not have an
509 509 # effect when using a QTextEdit. I believe this is a Qt bug.
510 510 self._control.moveCursor(QtGui.QTextCursor.End)
511 511
@@ -617,7 +617,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
617 617 if self._get_cursor().blockNumber() < prompt_cursor.blockNumber():
618 618 self._set_cursor(prompt_cursor)
619 619 self._set_top_cursor(prompt_cursor)
620
620
621 621 def redo(self):
622 622 """ Redo the last operation. If there is no operation to redo, nothing
623 623 happens.
@@ -729,7 +729,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
729 729
730 730 def _append_custom(self, insert, input, before_prompt=False):
731 731 """ A low-level method for appending content to the end of the buffer.
732
732
733 733 If 'before_prompt' is enabled, the content will be inserted before the
734 734 current prompt, if there is one.
735 735 """
@@ -750,7 +750,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
750 750 diff = cursor.position() - start_pos
751 751 self._append_before_prompt_pos += diff
752 752 self._prompt_pos += diff
753
753
754 754 return result
755 755
756 756 def _append_html(self, html, before_prompt=False):
@@ -811,7 +811,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
811 811 self._cancel_text_completion()
812 812
813 813 if len(items) == 1:
814 cursor.setPosition(self._control.textCursor().position(),
814 cursor.setPosition(self._control.textCursor().position(),
815 815 QtGui.QTextCursor.KeepAnchor)
816 816 cursor.insertText(items[0])
817 817
@@ -825,7 +825,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
825 825
826 826 if self.gui_completion:
827 827 cursor.movePosition(QtGui.QTextCursor.Left, n=len(prefix))
828 self._completion_widget.show_items(cursor, items)
828 self._completion_widget.show_items(cursor, items)
829 829 else:
830 830 cursor.beginEditBlock()
831 831 self._append_plain_text('\n')
@@ -963,7 +963,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
963 963
964 964 elif key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
965 965 intercepted = True
966
966
967 967 # Special handling when tab completing in text mode.
968 968 self._cancel_text_completion()
969 969
@@ -1076,7 +1076,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1076 1076 if key == QtCore.Qt.Key_B:
1077 1077 self._set_cursor(self._get_word_start_cursor(position))
1078 1078 intercepted = True
1079
1079
1080 1080 elif key == QtCore.Qt.Key_F:
1081 1081 self._set_cursor(self._get_word_end_cursor(position))
1082 1082 intercepted = True
@@ -1103,7 +1103,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1103 1103 elif key == QtCore.Qt.Key_Greater:
1104 1104 self._control.moveCursor(QtGui.QTextCursor.End)
1105 1105 intercepted = True
1106
1106
1107 1107 elif key == QtCore.Qt.Key_Less:
1108 1108 self._control.setTextCursor(self._get_prompt_cursor())
1109 1109 intercepted = True
@@ -1115,7 +1115,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1115 1115 anchormode = QtGui.QTextCursor.KeepAnchor
1116 1116 else:
1117 1117 anchormode = QtGui.QTextCursor.MoveAnchor
1118
1118
1119 1119 if key == QtCore.Qt.Key_Escape:
1120 1120 self._keyboard_quit()
1121 1121 intercepted = True
@@ -1144,19 +1144,19 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1144 1144 line, col = cursor.blockNumber(), cursor.columnNumber()
1145 1145 if line > self._get_prompt_cursor().blockNumber() and \
1146 1146 col == len(self._continuation_prompt):
1147 self._control.moveCursor(QtGui.QTextCursor.PreviousBlock,
1147 self._control.moveCursor(QtGui.QTextCursor.PreviousBlock,
1148 1148 mode=anchormode)
1149 self._control.moveCursor(QtGui.QTextCursor.EndOfBlock,
1149 self._control.moveCursor(QtGui.QTextCursor.EndOfBlock,
1150 1150 mode=anchormode)
1151 1151 intercepted = True
1152 1152
1153 1153 # Regular left movement
1154 1154 else:
1155 1155 intercepted = not self._in_buffer(position - 1)
1156
1156
1157 1157 elif key == QtCore.Qt.Key_Right:
1158 1158 original_block_number = cursor.blockNumber()
1159 cursor.movePosition(QtGui.QTextCursor.Right,
1159 cursor.movePosition(QtGui.QTextCursor.Right,
1160 1160 mode=anchormode)
1161 1161 if cursor.blockNumber() != original_block_number:
1162 1162 cursor.movePosition(QtGui.QTextCursor.Right,
@@ -1237,7 +1237,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1237 1237 return intercepted
1238 1238
1239 1239 def _event_filter_page_keypress(self, event):
1240 """ Filter key events for the paging widget to create console-like
1240 """ Filter key events for the paging widget to create console-like
1241 1241 interface.
1242 1242 """
1243 1243 key = event.key()
@@ -1253,7 +1253,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1253 1253 if key == QtCore.Qt.Key_Greater:
1254 1254 self._page_control.moveCursor(QtGui.QTextCursor.End)
1255 1255 intercepted = True
1256
1256
1257 1257 elif key == QtCore.Qt.Key_Less:
1258 1258 self._page_control.moveCursor(QtGui.QTextCursor.Start)
1259 1259 intercepted = True
@@ -1266,15 +1266,15 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1266 1266 return True
1267 1267
1268 1268 elif key in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
1269 new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress,
1270 QtCore.Qt.Key_PageDown,
1269 new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress,
1270 QtCore.Qt.Key_PageDown,
1271 1271 QtCore.Qt.NoModifier)
1272 1272 QtGui.qApp.sendEvent(self._page_control, new_event)
1273 1273 return True
1274 1274
1275 1275 elif key == QtCore.Qt.Key_Backspace:
1276 1276 new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress,
1277 QtCore.Qt.Key_PageUp,
1277 QtCore.Qt.Key_PageUp,
1278 1278 QtCore.Qt.NoModifier)
1279 1279 QtGui.qApp.sendEvent(self._page_control, new_event)
1280 1280 return True
@@ -1300,7 +1300,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1300 1300 width = self._control.viewport().width()
1301 1301 char_width = QtGui.QFontMetrics(self.font).width(' ')
1302 1302 displaywidth = max(10, (width / char_width) - 1)
1303
1303
1304 1304 return columnize(items, separator, displaywidth)
1305 1305
1306 1306 def _get_block_plain_text(self, block):
@@ -1308,7 +1308,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1308 1308 """
1309 1309 cursor = QtGui.QTextCursor(block)
1310 1310 cursor.movePosition(QtGui.QTextCursor.StartOfBlock)
1311 cursor.movePosition(QtGui.QTextCursor.EndOfBlock,
1311 cursor.movePosition(QtGui.QTextCursor.EndOfBlock,
1312 1312 QtGui.QTextCursor.KeepAnchor)
1313 1313 return cursor.selection().toPlainText()
1314 1314
@@ -1316,7 +1316,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1316 1316 """ Convenience method that returns a cursor for the current position.
1317 1317 """
1318 1318 return self._control.textCursor()
1319
1319
1320 1320 def _get_end_cursor(self):
1321 1321 """ Convenience method that returns a cursor for the last character.
1322 1322 """
@@ -1482,7 +1482,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1482 1482 self._set_top_cursor(cursor)
1483 1483 cursor.joinPreviousEditBlock()
1484 1484 cursor.deletePreviousChar()
1485
1485
1486 1486 format = self._ansi_processor.get_format()
1487 1487 cursor.insertText(substring, format)
1488 1488 else:
@@ -1545,7 +1545,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1545 1545 self._cancel_text_completion()
1546 1546 else:
1547 1547 self.input_buffer = ''
1548
1548
1549 1549 def _page(self, text, html=False):
1550 1550 """ Displays text using the pager if it exceeds the height of the
1551 1551 viewport.
@@ -1591,7 +1591,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1591 1591 def _prompt_started(self):
1592 1592 """ Called immediately after a new prompt is displayed.
1593 1593 """
1594 # Temporarily disable the maximum block count to permit undo/redo and
1594 # Temporarily disable the maximum block count to permit undo/redo and
1595 1595 # to ensure that the prompt position does not change due to truncation.
1596 1596 self._control.document().setMaximumBlockCount(0)
1597 1597 self._control.setUndoRedoEnabled(True)
@@ -1613,7 +1613,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1613 1613 self._control.moveCursor(QtGui.QTextCursor.End)
1614 1614
1615 1615 def _readline(self, prompt='', callback=None):
1616 """ Reads one line of input from the user.
1616 """ Reads one line of input from the user.
1617 1617
1618 1618 Parameters
1619 1619 ----------
@@ -1669,7 +1669,7 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1669 1669 else:
1670 1670 self._continuation_prompt = prompt
1671 1671 self._continuation_prompt_html = None
1672
1672
1673 1673 def _set_cursor(self, cursor):
1674 1674 """ Convenience method to set the current cursor.
1675 1675 """
@@ -1699,16 +1699,16 b' class ConsoleWidget(LoggingConfigurable, QtGui.QWidget):'
1699 1699 as plain text, though ANSI color codes will be handled.
1700 1700
1701 1701 newline : bool, optional (default True)
1702 If set, a new line will be written before showing the prompt if
1702 If set, a new line will be written before showing the prompt if
1703 1703 there is not already a newline at the end of the buffer.
1704 1704 """
1705 1705 # Save the current end position to support _append*(before_prompt=True).
1706 1706 cursor = self._get_end_cursor()
1707 1707 self._append_before_prompt_pos = cursor.position()
1708
1708
1709 1709 # Insert a preliminary newline, if necessary.
1710 1710 if newline and cursor.position() > 0:
1711 cursor.movePosition(QtGui.QTextCursor.Left,
1711 cursor.movePosition(QtGui.QTextCursor.Left,
1712 1712 QtGui.QTextCursor.KeepAnchor)
1713 1713 if cursor.selection().toPlainText() != '\n':
1714 1714 self._append_plain_text('\n')
@@ -103,7 +103,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
103 103
104 104 # Emitted when an exit request has been received from the kernel.
105 105 exit_requested = QtCore.Signal()
106
106
107 107 # Protected class variables.
108 108 _CallTipRequest = namedtuple('_CallTipRequest', ['id', 'pos'])
109 109 _CompletionRequest = namedtuple('_CompletionRequest', ['id', 'pos'])
@@ -115,7 +115,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
115 115 #---------------------------------------------------------------------------
116 116 # 'object' interface
117 117 #---------------------------------------------------------------------------
118
118
119 119 def __init__(self, *args, **kw):
120 120 super(FrontendWidget, self).__init__(*args, **kw)
121 121
@@ -151,9 +151,9 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
151 151 # Connect signal handlers.
152 152 document = self._control.document()
153 153 document.contentsChange.connect(self._document_contents_change)
154
154
155 155 # Set flag for whether we are connected via localhost.
156 self._local_kernel = kw.get('local_kernel',
156 self._local_kernel = kw.get('local_kernel',
157 157 FrontendWidget._local_kernel)
158 158
159 159 #---------------------------------------------------------------------------
@@ -193,7 +193,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
193 193 self._hidden = hidden
194 194 if not hidden:
195 195 self.executing.emit(source)
196
196
197 197 def _prompt_started_hook(self):
198 198 """ Called immediately after a new prompt is displayed.
199 199 """
@@ -394,7 +394,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
394 394 # to spaces so that output looks as expected regardless of this
395 395 # widget's tab width.
396 396 text = msg['content']['data'].expandtabs(8)
397
397
398 398 self._append_plain_text(text, before_prompt=True)
399 399 self._control.moveCursor(QtGui.QTextCursor.End)
400 400
@@ -432,7 +432,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
432 432 self.reset()
433 433
434 434 def _started_channels(self):
435 """ Called when the KernelManager channels have started listening or
435 """ Called when the KernelManager channels have started listening or
436 436 when the frontend is assigned an already listening KernelManager.
437 437 """
438 438 self.reset()
@@ -467,7 +467,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
467 467 def reset(self):
468 468 """ Resets the widget to its initial state. Similar to ``clear``, but
469 469 also re-writes the banner and aborts execution if necessary.
470 """
470 """
471 471 if self._executing:
472 472 self._executing = False
473 473 self._request_info['execute'] = None
@@ -550,7 +550,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
550 550 '.'.join(context), # text
551 551 self._get_input_buffer_cursor_line(), # line
552 552 self._get_input_buffer_cursor_column(), # cursor_pos
553 self.input_buffer) # block
553 self.input_buffer) # block
554 554 pos = self._get_cursor().position()
555 555 info = self._CompletionRequest(msg_id, pos)
556 556 self._request_info['complete'] = info
@@ -561,7 +561,7 b' class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin):'
561 561 """
562 562 if cursor is None:
563 563 cursor = self._get_cursor()
564 cursor.movePosition(QtGui.QTextCursor.StartOfBlock,
564 cursor.movePosition(QtGui.QTextCursor.StartOfBlock,
565 565 QtGui.QTextCursor.KeepAnchor)
566 566 text = cursor.selection().toPlainText()
567 567 return self._completion_lexer.get_context(text)
@@ -17,7 +17,7 b' class HistoryConsoleWidget(ConsoleWidget):'
17 17 # an edit is made to a multi-line input buffer. To override the lock, use
18 18 # Shift in conjunction with the standard history cycling keys.
19 19 history_lock = Bool(False, config=True)
20
20
21 21 #---------------------------------------------------------------------------
22 22 # 'object' interface
23 23 #---------------------------------------------------------------------------
@@ -45,7 +45,7 b' class HistoryConsoleWidget(ConsoleWidget):'
45 45 source, hidden, interactive)
46 46
47 47 if executed and not hidden:
48 # Save the command unless it was an empty string or was identical
48 # Save the command unless it was an empty string or was identical
49 49 # to the previous command.
50 50 history = history.rstrip()
51 51 if history and (not self._history or self._history[-1] != history):
@@ -90,7 +90,7 b' class HistoryConsoleWidget(ConsoleWidget):'
90 90 # search.
91 91 cursor = self._get_prompt_cursor()
92 92 if self._history_prefix:
93 cursor.movePosition(QtGui.QTextCursor.Right,
93 cursor.movePosition(QtGui.QTextCursor.Right,
94 94 n=len(self._history_prefix))
95 95 else:
96 96 cursor.movePosition(QtGui.QTextCursor.EndOfLine)
@@ -111,7 +111,7 b' class HistoryConsoleWidget(ConsoleWidget):'
111 111 return False
112 112
113 113 # Perform the search.
114 replaced = self.history_next(self._history_prefix,
114 replaced = self.history_next(self._history_prefix,
115 115 as_prefix=not shift_modifier)
116 116
117 117 # Emulate readline: keep the cursor position fixed for a prefix
@@ -120,7 +120,7 b' class HistoryConsoleWidget(ConsoleWidget):'
120 120 # input buffer is set.)
121 121 if self._history_prefix and replaced:
122 122 cursor = self._get_prompt_cursor()
123 cursor.movePosition(QtGui.QTextCursor.Right,
123 cursor.movePosition(QtGui.QTextCursor.Right,
124 124 n=len(self._history_prefix))
125 125 self._set_cursor(cursor)
126 126
@@ -155,7 +155,7 b' class HistoryConsoleWidget(ConsoleWidget):'
155 155 or (not as_prefix and substring in history):
156 156 replace = True
157 157 break
158
158
159 159 if replace:
160 160 self._store_edits()
161 161 self._history_index = index
@@ -186,7 +186,7 b' class HistoryConsoleWidget(ConsoleWidget):'
186 186 or (not as_prefix and substring in history):
187 187 replace = True
188 188 break
189
189
190 190 if replace:
191 191 self._store_edits()
192 192 self._history_index = index
@@ -203,7 +203,7 b' class HistoryConsoleWidget(ConsoleWidget):'
203 203 The (maximum) number of history items to get.
204 204 """
205 205 return self._history[-n:]
206
206
207 207 #---------------------------------------------------------------------------
208 208 # 'HistoryConsoleWidget' protected interface
209 209 #---------------------------------------------------------------------------
@@ -211,8 +211,8 b' class HistoryConsoleWidget(ConsoleWidget):'
211 211 def _history_locked(self):
212 212 """ Returns whether history movement is locked.
213 213 """
214 return (self.history_lock and
215 (self._get_edited_history(self._history_index) !=
214 return (self.history_lock and
215 (self._get_edited_history(self._history_index) !=
216 216 self.input_buffer) and
217 217 (self._get_prompt_cursor().blockNumber() !=
218 218 self._get_end_cursor().blockNumber()))
@@ -81,7 +81,7 b' class IPythonWidget(FrontendWidget):'
81 81 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter)
82 82 3. IPython: .error, .in-prompt, .out-prompt, etc
83 83 """)
84
84
85 85 syntax_style = Unicode(config=True,
86 86 help="""
87 87 If not empty, use this Pygments style for syntax highlighting.
@@ -110,12 +110,12 b' class IPythonWidget(FrontendWidget):'
110 110 #---------------------------------------------------------------------------
111 111 # 'object' interface
112 112 #---------------------------------------------------------------------------
113
113
114 114 def __init__(self, *args, **kw):
115 115 super(IPythonWidget, self).__init__(*args, **kw)
116 116
117 117 # IPythonWidget protected variables.
118 self._payload_handlers = {
118 self._payload_handlers = {
119 119 self._payload_source_edit : self._handle_payload_edit,
120 120 self._payload_source_exit : self._handle_payload_exit,
121 121 self._payload_source_page : self._handle_payload_page,
@@ -151,7 +151,7 b' class IPythonWidget(FrontendWidget):'
151 151 # but the last component and then suitably decreasing the offset
152 152 # between the current cursor position and the start of completion.
153 153 if len(matches) > 1 and matches[0][:offset] == text:
154 parts = re.split(r'[./\\]', text)
154 parts = re.split(r'[./\\]', text)
155 155 sep_count = len(parts) - 1
156 156 if sep_count:
157 157 chop_length = sum(map(len, parts[:sep_count])) + sep_count
@@ -228,7 +228,7 b' class IPythonWidget(FrontendWidget):'
228 228 """ The base handler for the ``display_data`` message.
229 229 """
230 230 self.log.debug("display: %s", msg.get('content', ''))
231 # For now, we don't display data from other frontends, but we
231 # For now, we don't display data from other frontends, but we
232 232 # eventually will as this allows all frontends to monitor the display
233 233 # data. But we need to figure out how to handle this in the GUI.
234 234 if not self._hidden and self._is_from_this_session(msg):
@@ -302,13 +302,13 b' class IPythonWidget(FrontendWidget):'
302 302 # text field. Readline-based frontends do get a real text field which
303 303 # they can use.
304 304 text = ''
305
305
306 306 # Send the completion request to the kernel
307 307 msg_id = self.kernel_manager.shell_channel.complete(
308 308 text, # text
309 309 self._get_input_buffer_cursor_line(), # line
310 310 self._get_input_buffer_cursor_column(), # cursor_pos
311 self.input_buffer) # block
311 self.input_buffer) # block
312 312 pos = self._get_cursor().position()
313 313 info = self._CompletionRequest(msg_id, pos)
314 314 self._request_info['complete'] = info
@@ -332,7 +332,7 b' class IPythonWidget(FrontendWidget):'
332 332 self._append_html(traceback)
333 333 else:
334 334 # This is the fallback for now, using plain text with ansi escapes
335 self._append_plain_text(traceback)
335 self._append_plain_text(traceback)
336 336
337 337 def _process_execute_payload(self, item):
338 338 """ Reimplemented to dispatch payloads to handler methods.
@@ -344,7 +344,7 b' class IPythonWidget(FrontendWidget):'
344 344 else:
345 345 handler(item)
346 346 return True
347
347
348 348 def _show_interpreter_prompt(self, number=None):
349 349 """ Reimplemented for IPython-style prompts.
350 350 """
@@ -383,7 +383,7 b' class IPythonWidget(FrontendWidget):'
383 383 # Remove the old prompt and insert a new prompt.
384 384 cursor = QtGui.QTextCursor(block)
385 385 cursor.movePosition(QtGui.QTextCursor.Right,
386 QtGui.QTextCursor.KeepAnchor,
386 QtGui.QTextCursor.KeepAnchor,
387 387 self._previous_prompt_obj.length)
388 388 prompt = self._make_in_prompt(previous_prompt_number)
389 389 self._prompt = self._insert_html_fetching_plain_text(
@@ -485,7 +485,7 b' class IPythonWidget(FrontendWidget):'
485 485 space_count = len(prompt.lstrip('\n')) - len(end_chars)
486 486 body = '&nbsp;' * space_count + end_chars
487 487 return '<span class="in-prompt">%s</span>' % body
488
488
489 489 def _make_out_prompt(self, number):
490 490 """ Given a prompt number, returns an HTML Out prompt.
491 491 """
@@ -14,7 +14,7 b' from IPython.external.qt import QtCore, QtGui'
14 14 class KillRing(object):
15 15 """ A generic Emacs-style kill ring.
16 16 """
17
17
18 18 def __init__(self):
19 19 self.clear()
20 20
@@ -41,7 +41,7 b' class KillRing(object):'
41 41
42 42 def rotate(self):
43 43 """ Rotate the kill ring, then yank back the new top.
44
44
45 45 Returns:
46 46 --------
47 47 A text string or None.
@@ -50,7 +50,7 b' class KillRing(object):'
50 50 if self._index >= 0:
51 51 return self._ring[self._index]
52 52 return None
53
53
54 54 class QtKillRing(QtCore.QObject):
55 55 """ A kill ring attached to Q[Plain]TextEdit.
56 56 """
@@ -109,12 +109,12 b' class QtKillRing(QtCore.QObject):'
109 109 if text:
110 110 self._skip_cursor = True
111 111 cursor = self._text_edit.textCursor()
112 cursor.movePosition(QtGui.QTextCursor.Left,
113 QtGui.QTextCursor.KeepAnchor,
112 cursor.movePosition(QtGui.QTextCursor.Left,
113 QtGui.QTextCursor.KeepAnchor,
114 114 n = len(self._prev_yank))
115 115 cursor.insertText(text)
116 116 self._prev_yank = text
117
117
118 118 #--------------------------------------------------------------------------
119 119 # Protected interface
120 120 #--------------------------------------------------------------------------
@@ -79,7 +79,7 b' class PygmentsBlockUserData(QtGui.QTextBlockUserData):'
79 79
80 80 def __repr__(self):
81 81 attrs = ['syntax_stack']
82 kwds = ', '.join([ '%s=%r' % (attr, getattr(self, attr))
82 kwds = ', '.join([ '%s=%r' % (attr, getattr(self, attr))
83 83 for attr in attrs ])
84 84 return 'PygmentsBlockUserData(%s)' % kwds
85 85
@@ -172,7 +172,7 b' class PygmentsHighlighter(QtGui.QSyntaxHighlighter):'
172 172 return result
173 173
174 174 def _get_format_from_document(self, token, document):
175 """ Returns a QTextCharFormat for token by
175 """ Returns a QTextCharFormat for token by
176 176 """
177 177 code, html = self._formatter._format_lines([(token, 'dummy')]).next()
178 178 self._document.setHtml(html)
@@ -56,7 +56,7 b' class RichIPythonWidget(IPythonWidget):'
56 56 if svg is not None:
57 57 menu.addSeparator()
58 58 menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg))
59 menu.addAction('Save SVG As...',
59 menu.addAction('Save SVG As...',
60 60 lambda: save_svg(svg, self._control))
61 61 else:
62 62 menu = super(RichIPythonWidget, self)._context_menu_make(pos)
@@ -209,7 +209,7 b' class RichIPythonWidget(IPythonWidget):'
209 209 # Chop stand-alone header from matplotlib SVG
210 210 offset = svg.find("<svg")
211 211 assert(offset > -1)
212
212
213 213 return svg[offset:]
214 214
215 215 else:
@@ -51,20 +51,20 b' class QtShellSocketChannel(SocketChannelQObject, ShellSocketChannel):'
51 51 # Emitted when the first reply comes back.
52 52 first_reply = QtCore.Signal()
53 53
54 # Used by the first_reply signal logic to determine if a reply is the
54 # Used by the first_reply signal logic to determine if a reply is the
55 55 # first.
56 56 _handlers_called = False
57 57
58 58 #---------------------------------------------------------------------------
59 59 # 'ShellSocketChannel' interface
60 60 #---------------------------------------------------------------------------
61
61
62 62 def call_handlers(self, msg):
63 63 """ Reimplemented to emit signals instead of making callbacks.
64 64 """
65 65 # Emit the generic signal.
66 66 self.message_received.emit(msg)
67
67
68 68 # Emit signals for specialized message types.
69 69 msg_type = msg['header']['msg_type']
70 70 signal = getattr(self, msg_type, None)
@@ -115,7 +115,7 b' class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel):'
115 115 #---------------------------------------------------------------------------
116 116 # 'SubSocketChannel' interface
117 117 #---------------------------------------------------------------------------
118
118
119 119 def call_handlers(self, msg):
120 120 """ Reimplemented to emit signals instead of making callbacks.
121 121 """
@@ -153,7 +153,7 b' class QtStdInSocketChannel(SocketChannelQObject, StdInSocketChannel):'
153 153 """
154 154 # Emit the generic signal.
155 155 self.message_received.emit(msg)
156
156
157 157 # Emit signals for specialized message types.
158 158 msg_type = msg['header']['msg_type']
159 159 if msg_type == 'input_request':
@@ -208,7 +208,7 b' class QtKernelManager(KernelManager, SuperQObject):'
208 208 super(QtKernelManager, self).start_kernel(*args, **kw)
209 209
210 210 #------ Channel management -------------------------------------------------
211
211
212 212 def start_channels(self, *args, **kw):
213 213 """ Reimplemented to emit signal.
214 214 """
@@ -217,7 +217,7 b' class QtKernelManager(KernelManager, SuperQObject):'
217 217
218 218 def stop_channels(self):
219 219 """ Reimplemented to emit signal.
220 """
220 """
221 221 super(QtKernelManager, self).stop_channels()
222 222 self.stopped_channels.emit()
223 223
@@ -233,7 +233,7 b' class QtKernelManager(KernelManager, SuperQObject):'
233 233 #---------------------------------------------------------------------------
234 234 # Protected interface
235 235 #---------------------------------------------------------------------------
236
236
237 237 def _first_reply(self):
238 238 """ Unpauses the heartbeat channel when the first reply is received on
239 239 the execute channel. Note that this will *not* start the heartbeat
@@ -87,7 +87,7 b' class HtmlExporter(object):'
87 87 ib.setShortcut('I')
88 88 eb = QtGui.QPushButton("&External")
89 89 eb.setShortcut('E')
90 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
90 box = QtGui.QMessageBox(QtGui.QMessageBox.Question,
91 91 dialog.windowTitle(), msg)
92 92 box.setInformativeText(info)
93 93 box.addButton(ib, QtGui.QMessageBox.NoRole)
@@ -190,12 +190,12 b' def default_image_tag(match, path = None, format = "png"):'
190 190 """ Return (X)HTML mark-up for the image-tag given by match.
191 191
192 192 This default implementation merely removes the image, and exists mostly
193 for documentation purposes. More information than is present in the Qt
193 for documentation purposes. More information than is present in the Qt
194 194 HTML is required to supply the images.
195 195
196 196 Parameters
197 197 ----------
198 match : re.SRE_Match
198 match : re.SRE_Match
199 199 A match to an HTML image tag as exported by Qt, with match.group("Name")
200 200 containing the matched image ID.
201 201
@@ -212,7 +212,7 b' def default_image_tag(match, path = None, format = "png"):'
212 212
213 213 def fix_html(html):
214 214 """ Transforms a Qt-generated HTML string into a standards-compliant one.
215
215
216 216 Parameters:
217 217 -----------
218 218 html : str,
@@ -53,7 +53,7 b" def kill_embedded(self,parameter_s=''):"
53 53 figured out what you needed from it, you may then kill it and the program
54 54 will then continue to run without the interactive shell interfering again.
55 55 """
56
56
57 57 kill = ask_yes_no("Are you sure you want to kill this embedded instance "
58 58 "(y/n)? [y/N] ",'n')
59 59 if kill:
@@ -206,7 +206,7 b' class InteractiveShellEmbed(TerminalInteractiveShell):'
206 206
207 207 with nested(self.builtin_trap, self.display_trap):
208 208 self.interact(display_banner=display_banner)
209
209
210 210 # now, purge out the user namespace from anything we might have added
211 211 # from the caller's local namespace
212 212 delvar = self.user_ns.pop
@@ -234,7 +234,7 b' def embed(**kwargs):'
234 234 d = 40
235 235 embed
236 236
237 Full customization can be done by passing a :class:`Struct` in as the
237 Full customization can be done by passing a :class:`Struct` in as the
238 238 config argument.
239 239 """
240 240 config = kwargs.get('config')
@@ -117,7 +117,7 b' class TerminalInteractiveShell(InteractiveShell):'
117 117 self.system = self.system_piped
118 118 else:
119 119 self.system = self.system_raw
120
120
121 121 self.init_term_title()
122 122 self.init_usage(usage)
123 123 self.init_banner(banner1, banner2, display_banner)
@@ -214,13 +214,13 b' class TerminalInteractiveShell(InteractiveShell):'
214 214 If an optional banner argument is given, it will override the
215 215 internally created default banner.
216 216 """
217
217
218 218 with nested(self.builtin_trap, self.display_trap):
219 219
220 220 while 1:
221 221 try:
222 222 self.interact(display_banner=display_banner)
223 #self.interact_with_readline()
223 #self.interact_with_readline()
224 224 # XXX for testing of a readline-decoupled repl loop, call
225 225 # interact_with_readline above
226 226 break
@@ -232,23 +232,23 b' class TerminalInteractiveShell(InteractiveShell):'
232 232 def interact(self, display_banner=None):
233 233 """Closely emulate the interactive Python console."""
234 234
235 # batch run -> do not interact
235 # batch run -> do not interact
236 236 if self.exit_now:
237 237 return
238 238
239 239 if display_banner is None:
240 240 display_banner = self.display_banner
241
241
242 242 if isinstance(display_banner, basestring):
243 243 self.show_banner(display_banner)
244 244 elif display_banner:
245 245 self.show_banner()
246 246
247 247 more = False
248
248
249 249 # Mark activity in the builtins
250 250 __builtin__.__dict__['__IPYTHON__active'] += 1
251
251
252 252 if self.has_readline:
253 253 self.readline_startup_hook(self.pre_readline)
254 254 # exit_now is set by a call to %Exit or %Quit, through the
@@ -263,7 +263,7 b' class TerminalInteractiveShell(InteractiveShell):'
263 263 self.showtraceback()
264 264 if self.autoindent:
265 265 self.rl_do_indent = True
266
266
267 267 else:
268 268 try:
269 269 prompt = self.hooks.generate_prompt(False)
@@ -276,7 +276,7 b' class TerminalInteractiveShell(InteractiveShell):'
276 276 break
277 277 if self.autoindent:
278 278 self.rl_do_indent = False
279
279
280 280 except KeyboardInterrupt:
281 281 #double-guard against keyboardinterrupts during kbdint handling
282 282 try:
@@ -310,7 +310,7 b' class TerminalInteractiveShell(InteractiveShell):'
310 310 if not more:
311 311 source_raw = self.input_splitter.source_raw_reset()[1]
312 312 self.run_cell(source_raw)
313
313
314 314 # We are off again...
315 315 __builtin__.__dict__['__IPYTHON__active'] -= 1
316 316
@@ -335,7 +335,7 b' class TerminalInteractiveShell(InteractiveShell):'
335 335
336 336 if self.has_readline:
337 337 self.set_readline_completer()
338
338
339 339 try:
340 340 line = py3compat.str_to_unicode(self.raw_input_original(prompt))
341 341 except ValueError:
@@ -351,7 +351,7 b' class TerminalInteractiveShell(InteractiveShell):'
351 351 if num_ini_spaces(line) > self.indent_current_nsp:
352 352 line = line[self.indent_current_nsp:]
353 353 self.indent_current_nsp = 0
354
354
355 355 return line
356 356
357 357 #-------------------------------------------------------------------------
@@ -378,7 +378,7 b' class TerminalInteractiveShell(InteractiveShell):'
378 378 try:
379 379 f = file(err.filename)
380 380 try:
381 # This should be inside a display_trap block and I
381 # This should be inside a display_trap block and I
382 382 # think it is.
383 383 sys.displayhook(f.read())
384 384 finally:
@@ -392,10 +392,10 b' class TerminalInteractiveShell(InteractiveShell):'
392 392 if e.filename in ('<ipython console>','<input>','<string>',
393 393 '<console>','<BackgroundJob compilation>',
394 394 None):
395
395
396 396 return False
397 397 try:
398 if (self.autoedit_syntax and
398 if (self.autoedit_syntax and
399 399 not self.ask_yes_no('Return to editor to correct syntax error? '
400 400 '[Y/n] ','y')):
401 401 return False
@@ -468,7 +468,7 b' class TerminalInteractiveShell(InteractiveShell):'
468 468 self.ask_exit()
469 469 else:
470 470 self.ask_exit()
471
471
472 472 #------------------------------------------------------------------------
473 473 # Magic overrides
474 474 #------------------------------------------------------------------------
@@ -486,38 +486,38 b' class TerminalInteractiveShell(InteractiveShell):'
486 486 @skip_doctest
487 487 def magic_cpaste(self, parameter_s=''):
488 488 """Paste & execute a pre-formatted code block from clipboard.
489
489
490 490 You must terminate the block with '--' (two minus-signs) alone on the
491 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
491 line. You can also provide your own sentinel with '%paste -s %%' ('%%'
492 492 is the new sentinel for this operation)
493
493
494 494 The block is dedented prior to execution to enable execution of method
495 495 definitions. '>' and '+' characters at the beginning of a line are
496 496 ignored, to allow pasting directly from e-mails, diff files and
497 497 doctests (the '...' continuation prompt is also stripped). The
498 498 executed block is also assigned to variable named 'pasted_block' for
499 499 later editing with '%edit pasted_block'.
500
500
501 501 You can also pass a variable name as an argument, e.g. '%cpaste foo'.
502 This assigns the pasted block to variable 'foo' as string, without
502 This assigns the pasted block to variable 'foo' as string, without
503 503 dedenting or executing it (preceding >>> and + is still stripped)
504
504
505 505 '%cpaste -r' re-executes the block previously entered by cpaste.
506
507 Do not be alarmed by garbled output on Windows (it's a readline bug).
508 Just press enter and type -- (and press enter again) and the block
506
507 Do not be alarmed by garbled output on Windows (it's a readline bug).
508 Just press enter and type -- (and press enter again) and the block
509 509 will be what was just pasted.
510
510
511 511 IPython statements (magics, shell escapes) are not supported (yet).
512 512
513 513 See also
514 514 --------
515 515 paste: automatically pull code from clipboard.
516
516
517 517 Examples
518 518 --------
519 519 ::
520
520
521 521 In [8]: %cpaste
522 522 Pasting code; enter '--' alone on the line to stop.
523 523 :>>> a = ["world!", "Hello"]
@@ -525,13 +525,13 b' class TerminalInteractiveShell(InteractiveShell):'
525 525 :--
526 526 Hello world!
527 527 """
528
528
529 529 opts,args = self.parse_options(parameter_s,'rs:',mode='string')
530 530 par = args.strip()
531 531 if opts.has_key('r'):
532 532 self._rerun_pasted()
533 533 return
534
534
535 535 sentinel = opts.get('s','--')
536 536
537 537 block = self._strip_pasted_lines_for_code(
@@ -541,7 +541,7 b' class TerminalInteractiveShell(InteractiveShell):'
541 541
542 542 def magic_paste(self, parameter_s=''):
543 543 """Paste & execute a pre-formatted code block from clipboard.
544
544
545 545 The text is pulled directly from the clipboard without user
546 546 intervention and printed back on the screen before execution (unless
547 547 the -q flag is given to force quiet mode).
@@ -552,18 +552,18 b' class TerminalInteractiveShell(InteractiveShell):'
552 552 doctests (the '...' continuation prompt is also stripped). The
553 553 executed block is also assigned to variable named 'pasted_block' for
554 554 later editing with '%edit pasted_block'.
555
555
556 556 You can also pass a variable name as an argument, e.g. '%paste foo'.
557 This assigns the pasted block to variable 'foo' as string, without
557 This assigns the pasted block to variable 'foo' as string, without
558 558 dedenting or executing it (preceding >>> and + is still stripped)
559 559
560 560 Options
561 561 -------
562
562
563 563 -r: re-executes the block previously entered by cpaste.
564 564
565 565 -q: quiet mode: do not echo the pasted text back to the terminal.
566
566
567 567 IPython statements (magics, shell escapes) are not supported (yet).
568 568
569 569 See also
@@ -586,9 +586,9 b' class TerminalInteractiveShell(InteractiveShell):'
586 586 if not block.endswith('\n'):
587 587 write('\n')
588 588 write("## -- End pasted text --\n")
589
589
590 590 self._execute_block(block, par)
591
591
592 592 def showindentationerror(self):
593 593 super(TerminalInteractiveShell, self).showindentationerror()
594 594 print("If you want to paste code into IPython, try the %paste magic function.")
@@ -201,7 +201,7 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
201 201 PlainTextFormatter,
202 202 Completer,
203 203 ]
204
204
205 205 subcommands = Dict(dict(
206 206 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
207 207 """Launch the IPython Qt Console."""
@@ -216,7 +216,7 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
216 216 "Start a kernel without an attached frontend."
217 217 ),
218 218 ))
219
219
220 220 # *do* autocreate requested profile, but don't create the config file.
221 221 auto_create=Bool(True)
222 222 # configurables
@@ -253,7 +253,7 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
253 253 def _force_interact_changed(self, name, old, new):
254 254 if new:
255 255 self.interact = True
256
256
257 257 def _file_to_run_changed(self, name, old, new):
258 258 if new and not self.force_interact:
259 259 self.interact = False
@@ -283,7 +283,7 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
283 283 sub = '--pylab='+gui
284 284 argv.pop(idx+1)
285 285 argv[idx] = sub
286
286
287 287 return super(TerminalIPythonApp, self).parse_command_line(argv)
288 288
289 289 def initialize(self, argv=None):
@@ -313,7 +313,7 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):'
313 313 sys.path.insert(0, '')
314 314
315 315 # Create an InteractiveShell instance.
316 # shell.display_banner should always be False for the terminal
316 # shell.display_banner should always be False for the terminal
317 317 # based app, because we call shell.show_banner() by hand below
318 318 # so the banner shows *before* all extension loading stuff.
319 319 self.shell = TerminalInteractiveShell.instance(config=self.config,
@@ -18,10 +18,10 b' def win32_clipboard_get():'
18 18 message = ("Getting text from the clipboard requires the pywin32 "
19 19 "extensions: http://sourceforge.net/projects/pywin32/")
20 20 raise TryNext(message)
21 win32clipboard.OpenClipboard()
22 text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
21 win32clipboard.OpenClipboard()
22 text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
23 23 # FIXME: convert \r\n to \n?
24 win32clipboard.CloseClipboard()
24 win32clipboard.CloseClipboard()
25 25 return text
26 26
27 27 def osx_clipboard_get():
@@ -9,11 +9,11 b' To enable it type::'
9 9 You can then disable it with::
10 10
11 11 __builtin__.reload = deepreload.original_reload
12
12
13 13 Alternatively, you can add a dreload builtin alongside normal reload with::
14 14
15 15 __builtin__.dreload = deepreload.reload
16
16
17 17 This code is almost entirely based on knee.py from the standard library.
18 18 """
19 19
@@ -30,7 +30,7 b' import sys'
30 30
31 31 # Replacement for __import__()
32 32 def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1):
33 # For now level is ignored, it's just there to prevent crash
33 # For now level is ignored, it's just there to prevent crash
34 34 # with from __future__ import absolute_import
35 35 parent = determine_parent(globals)
36 36 q, tail = find_head_package(parent, name)
@@ -94,7 +94,7 b' def load_tail(q, tail):'
94 94 # to:
95 95 mname = m.__name__
96 96 # This needs more testing!!! (I don't understand this module too well)
97
97
98 98 #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg
99 99 m = import_module(head, mname, m)
100 100 if not m:
@@ -125,25 +125,25 b' def import_module(partname, fqname, parent):'
125 125 global found_now
126 126 if found_now.has_key(fqname):
127 127 try:
128 return sys.modules[fqname]
128 return sys.modules[fqname]
129 129 except KeyError:
130 130 pass
131
131
132 132 print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \
133 133 #sys.displayhook is sys.__displayhook__
134
134
135 135 found_now[fqname] = 1
136 136 try:
137 137 fp, pathname, stuff = imp.find_module(partname,
138 138 parent and parent.__path__)
139 139 except ImportError:
140 140 return None
141
141
142 142 try:
143 143 m = imp.load_module(fqname, fp, pathname, stuff)
144 144 finally:
145 145 if fp: fp.close()
146
146
147 147 if parent:
148 148 setattr(parent, partname, m)
149 149
@@ -168,14 +168,14 b' except AttributeError:'
168 168 def reload(module, exclude=['sys', '__builtin__', '__main__']):
169 169 """Recursively reload all modules used in the given module. Optionally
170 170 takes a list of modules to exclude from reloading. The default exclude
171 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
171 list contains sys, __main__, and __builtin__, to prevent, e.g., resetting
172 172 display, exception, and io hooks.
173 173 """
174 174 global found_now
175 175 for i in exclude:
176 176 found_now[i] = 1
177 177 original_import = __builtin__.__import__
178 __builtin__.__import__ = deep_import_hook
178 __builtin__.__import__ = deep_import_hook
179 179 try:
180 180 ret = deep_reload_hook(module)
181 181 finally:
@@ -44,7 +44,7 b' subclassing more convenient. Their docstrings below have some more details:'
44 44
45 45 - post_cmd(): run right after the execution of each block. If the block
46 46 raises an exception, this is NOT called.
47
47
48 48
49 49 Operation
50 50 =========
@@ -72,14 +72,14 b' The supported tags are:'
72 72 word 'stop', to help visually distinguish the blocks in a text editor:
73 73
74 74 # <demo> --- stop ---
75
75
76 76
77 77 # <demo> silent
78 78
79 79 Make a block execute silently (and hence automatically). Typically used in
80 80 cases where you have some boilerplate or initialization code which you need
81 81 executed but do not want to be seen in the demo.
82
82
83 83 # <demo> auto
84 84
85 85 Make a block execute automatically, but still being printed. Useful for
@@ -116,7 +116,7 b' been added to the "docs/examples/core" directory. Just cd to this directory in'
116 116 an IPython session, and type::
117 117
118 118 %run demo-exercizer.py
119
119
120 120 and then follow the directions.
121 121
122 122 Example
@@ -200,14 +200,14 b' class Demo(object):'
200 200 IPython.Demo? in IPython to see it).
201 201
202 202 Inputs:
203
203
204 204 - src is either a file, or file-like object, or a
205 205 string that can be resolved to a filename.
206 206
207 207 Optional inputs:
208
208
209 209 - title: a string to use as the demo name. Of most use when the demo
210 you are making comes from an object that has no filename, or if you
210 you are making comes from an object that has no filename, or if you
211 211 want an alternate denotation distinct from the filename.
212 212
213 213 - arg_str(''): a string of arguments, internally converted to a list
@@ -238,7 +238,7 b' class Demo(object):'
238 238 self.sys_argv = [src] + shlex.split(arg_str)
239 239 self.auto_all = auto_all
240 240 self.src = src
241
241
242 242 # get a few things from ipython. While it's a bit ugly design-wise,
243 243 # it ensures that things like color scheme and the like are always in
244 244 # sync with the ipython mode being used. This class is only meant to
@@ -268,7 +268,7 b' class Demo(object):'
268 268 def reload(self):
269 269 """Reload source from disk and initialize state."""
270 270 self.fload()
271
271
272 272 self.src = self.fobj.read()
273 273 src_b = [b.strip() for b in self.re_stop.split(self.src) if b]
274 274 self._silent = [bool(self.re_silent.findall(b)) for b in src_b]
@@ -315,7 +315,7 b' class Demo(object):'
315 315 """Get the current block index, validating and checking status.
316 316
317 317 Returns None if the demo is finished"""
318
318
319 319 if index is None:
320 320 if self.finished:
321 321 print >>io.stdout, 'Demo finished. Use <demo_name>.reset() if you want to rerun it.'
@@ -369,7 +369,7 b' class Demo(object):'
369 369 # that the default demo.edit() call opens up the sblock we've last run
370 370 if index>0:
371 371 index -= 1
372
372
373 373 filename = self.shell.mktempfile(self.src_blocks[index])
374 374 self.shell.hooks.editor(filename,1)
375 375 new_block = file_read(filename)
@@ -379,7 +379,7 b' class Demo(object):'
379 379 self.block_index = index
380 380 # call to run with the newly edited index
381 381 self()
382
382
383 383 def show(self,index=None):
384 384 """Show a single block on screen"""
385 385
@@ -414,7 +414,7 b' class Demo(object):'
414 414 """Execute a string with one or more lines of code"""
415 415
416 416 exec source in self.user_ns
417
417
418 418 def __call__(self,index=None):
419 419 """run a block of the demo.
420 420
@@ -452,7 +452,7 b' class Demo(object):'
452 452 self.post_cmd()
453 453 finally:
454 454 sys.argv = save_argv
455
455
456 456 except:
457 457 self.ip_showtb(filename=self.fname)
458 458 else:
@@ -499,7 +499,7 b' class IPythonDemo(Demo):'
499 499 """Execute a string with one or more lines of code"""
500 500
501 501 self.shell.run_cell(source)
502
502
503 503 class LineDemo(Demo):
504 504 """Demo where each line is executed as a separate block.
505 505
@@ -513,7 +513,7 b' class LineDemo(Demo):'
513 513 Note: the input can not have *any* indentation, which means that only
514 514 single-lines of input are accepted, not even function definitions are
515 515 valid."""
516
516
517 517 def reload(self):
518 518 """Reload source from disk and initialize state."""
519 519 # read data and parse into blocks
@@ -542,26 +542,26 b' class IPythonLineDemo(IPythonDemo,LineDemo):'
542 542
543 543 class ClearMixin(object):
544 544 """Use this mixin to make Demo classes with less visual clutter.
545
545
546 546 Demos using this mixin will clear the screen before every block and use
547 547 blank marquees.
548
548
549 549 Note that in order for the methods defined here to actually override those
550 550 of the classes it's mixed with, it must go /first/ in the inheritance
551 551 tree. For example:
552
552
553 553 class ClearIPDemo(ClearMixin,IPythonDemo): pass
554
554
555 555 will provide an IPythonDemo class with the mixin's features.
556 556 """
557
557
558 558 def marquee(self,txt='',width=78,mark='*'):
559 559 """Blank marquee that returns '' no matter what the input."""
560 560 return ''
561
561
562 562 def pre_cmd(self):
563 563 """Method called before executing each block.
564
564
565 565 This one simply clears the screen."""
566 566 from IPython.utils.terminal import term_clear
567 567 term_clear()
@@ -5,30 +5,30 b' Authors : MinRK'
5 5
6 6 class YouTubeVideo(object):
7 7 """Class for embedding a YouTube Video in an IPython session, based on its video id.
8
8
9 9 e.g. to embed the video on this page:
10
10
11 11 http://www.youtube.com/watch?v=foo
12
12
13 13 you would do:
14
14
15 15 vid = YouTubeVideo("foo")
16 16 display(vid)
17 17 """
18
18
19 19 def __init__(self, id, width=400, height=300):
20 20 self.id = id
21 21 self.width = width
22 22 self.height = height
23
23
24 24 def _repr_html_(self):
25 25 """return YouTube embed iframe for this video id"""
26 26 return """
27 <iframe
28 width="%i"
29 height="%i"
30 src="http://www.youtube.com/embed/%s"
31 frameborder="0"
27 <iframe
28 width="%i"
29 height="%i"
30 src="http://www.youtube.com/embed/%s"
31 frameborder="0"
32 32 allowfullscreen
33 33 ></iframe>
34 34 """%(self.width, self.height, self.id)
@@ -8,11 +8,11 b' session. IPython has two different types of GUI integration:'
8 8 1. The terminal based IPython supports GUI event loops through Python's
9 9 PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically
10 10 whenever raw_input is waiting for a user to type code. We implement GUI
11 support in the terminal by setting PyOS_InputHook to a function that
11 support in the terminal by setting PyOS_InputHook to a function that
12 12 iterates the event loop for a short while. It is important to note that
13 13 in this situation, the real GUI event loop is NOT run in the normal
14 14 manner, so you can't use the normal means to detect that it is running.
15 2. In the two process IPython kernel/frontend, the GUI event loop is run in
15 2. In the two process IPython kernel/frontend, the GUI event loop is run in
16 16 the kernel. In this case, the event loop is run in the normal manner by
17 17 calling the function or method of the GUI toolkit that starts the event
18 18 loop.
@@ -47,7 +47,7 b' we proposed the following informal protocol:'
47 47 *must* use its value. If it has not been set, you can query the toolkit
48 48 in the normal manner.
49 49 * If you want GUI support and no one else has created an application or
50 started the event loop you *must* do this. We don't want projects to
50 started the event loop you *must* do this. We don't want projects to
51 51 attempt to defer these things to someone else if they themselves need it.
52 52
53 53 The functions below implement this logic for each GUI toolkit. If you need
@@ -45,7 +45,7 b' from timeit import default_timer as clock'
45 45 # Frame per second : 60
46 46 # Should probably be an IPython option
47 47 glut_fps = 60
48
48
49 49
50 50 # Display mode : double buffeed + rgba + depth
51 51 # Should probably be an IPython option
@@ -56,10 +56,10 b' glut_display_mode = (glut.GLUT_DOUBLE |'
56 56 glutMainLoopEvent = None
57 57 if sys.platform == 'darwin':
58 58 try:
59 glutCheckLoop = platform.createBaseFunction(
60 'glutCheckLoop', dll=platform.GLUT, resultType=None,
59 glutCheckLoop = platform.createBaseFunction(
60 'glutCheckLoop', dll=platform.GLUT, resultType=None,
61 61 argTypes=[],
62 doc='glutCheckLoop( ) -> None',
62 doc='glutCheckLoop( ) -> None',
63 63 argNames=(),
64 64 )
65 65 except AttributeError:
@@ -125,7 +125,7 b' def glut_int_handler(signum, frame):'
125 125 #-----------------------------------------------------------------------------
126 126 def inputhook_glut():
127 127 """Run the pyglet event loop by processing pending events only.
128
128
129 129 This keeps processing pending events until stdin is ready. After
130 130 processing all pending events, a call to time.sleep is inserted. This is
131 131 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
@@ -148,7 +148,7 b' def inputhook_glut():'
148 148 while not stdin_ready():
149 149 glutMainLoopEvent()
150 150 # We need to sleep at this point to keep the idle CPU load
151 # low. However, if sleep to long, GUI response is poor. As
151 # low. However, if sleep to long, GUI response is poor. As
152 152 # a compromise, we watch how often GUI events are being processed
153 153 # and switch between a short and long sleep time. Here are some
154 154 # stats useful in helping to tune this.
@@ -68,7 +68,7 b' else:'
68 68
69 69 def inputhook_pyglet():
70 70 """Run the pyglet event loop by processing pending events only.
71
71
72 72 This keeps processing pending events until stdin is ready. After
73 73 processing all pending events, a call to time.sleep is inserted. This is
74 74 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
@@ -87,7 +87,7 b' def inputhook_pyglet():'
87 87 flip(window)
88 88
89 89 # We need to sleep at this point to keep the idle CPU load
90 # low. However, if sleep to long, GUI response is poor. As
90 # low. However, if sleep to long, GUI response is poor. As
91 91 # a compromise, we watch how often GUI events are being processed
92 92 # and switch between a short and long sleep time. Here are some
93 93 # stats useful in helping to tune this.
@@ -46,8 +46,8 b' def stdin_ready():'
46 46
47 47 def inputhook_wx1():
48 48 """Run the wx event loop by processing pending events only.
49
50 This approach seems to work, but its performance is not great as it
49
50 This approach seems to work, but its performance is not great as it
51 51 relies on having PyOS_InputHook called regularly.
52 52 """
53 53 try:
@@ -92,16 +92,16 b' class EventLoopRunner(object):'
92 92
93 93 def inputhook_wx2():
94 94 """Run the wx event loop, polling for stdin.
95
95
96 96 This version runs the wx eventloop for an undetermined amount of time,
97 97 during which it periodically checks to see if anything is ready on
98 98 stdin. If anything is ready on stdin, the event loop exits.
99
99
100 100 The argument to elr.Run controls how often the event loop looks at stdin.
101 101 This determines the responsiveness at the keyboard. A setting of 1000
102 102 enables a user to type at most 1 char per second. I have found that a
103 setting of 10 gives good keyboard response. We can shorten it further,
104 but eventually performance would suffer from calling select/kbhit too
103 setting of 10 gives good keyboard response. We can shorten it further,
104 but eventually performance would suffer from calling select/kbhit too
105 105 often.
106 106 """
107 107 try:
@@ -118,9 +118,9 b' def inputhook_wx2():'
118 118
119 119 def inputhook_wx3():
120 120 """Run the wx event loop by processing pending events only.
121
121
122 122 This is like inputhook_wx1, but it keeps processing pending events
123 until stdin is ready. After processing all pending events, a call to
123 until stdin is ready. After processing all pending events, a call to
124 124 time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%.
125 125 This sleep time should be tuned though for best performance.
126 126 """
@@ -146,7 +146,7 b' def inputhook_wx3():'
146 146 evtloop.Dispatch()
147 147 app.ProcessIdle()
148 148 # We need to sleep at this point to keep the idle CPU load
149 # low. However, if sleep to long, GUI response is poor. As
149 # low. However, if sleep to long, GUI response is poor. As
150 150 # a compromise, we watch how often GUI events are being processed
151 151 # and switch between a short and long sleep time. Here are some
152 152 # stats useful in helping to tune this.
@@ -59,11 +59,11 b' def pexpect_monkeypatch():'
59 59 self.close() will trigger an exception because it tries to call os.close(),
60 60 and os is now None.
61 61 """
62
62
63 63 if pexpect.__version__[:3] >= '2.2':
64 64 # No need to patch, fix is already the upstream version.
65 65 return
66
66
67 67 def __del__(self):
68 68 """This makes sure that no system resources are left open.
69 69 Python only garbage collects Python objects. OS file descriptors
@@ -84,7 +84,7 b' pexpect_monkeypatch()'
84 84 # The generic runner class
85 85 class InteractiveRunner(object):
86 86 """Class to run a sequence of commands through an interactive program."""
87
87
88 88 def __init__(self,program,prompts,args=None,out=sys.stdout,echo=True):
89 89 """Construct a runner.
90 90
@@ -121,7 +121,7 b' class InteractiveRunner(object):'
121 121 increase this value (it is measured in seconds). Note that this
122 122 variable is not honored at all by older versions of pexpect.
123 123 """
124
124
125 125 self.program = program
126 126 self.prompts = prompts
127 127 if args is None: args = []
@@ -201,7 +201,7 b' class InteractiveRunner(object):'
201 201 else:
202 202 # Quiet mode, all writes are no-ops
203 203 write = lambda s: None
204
204
205 205 c = self.child
206 206 prompts = c.compile_pattern_list(self.prompts)
207 207 prompt_idx = c.expect_list(prompts)
@@ -214,7 +214,7 b' class InteractiveRunner(object):'
214 214 if get_output:
215 215 output = []
216 216 store_output = output.append
217
217
218 218 for cmd in source:
219 219 # skip blank lines for all matches to the 'main' prompt, while the
220 220 # secondary prompts do not
@@ -233,7 +233,7 b' class InteractiveRunner(object):'
233 233 write(c.before)
234 234 end_normal = False
235 235 break
236
236
237 237 write(c.before)
238 238
239 239 # With an echoing process, the output we get in c.before contains
@@ -266,11 +266,11 b' class InteractiveRunner(object):'
266 266 # hangs on the second invocation.
267 267 if c.isalive():
268 268 c.send('\n')
269
269
270 270 # Return any requested output
271 271 if get_output:
272 272 return ''.join(output)
273
273
274 274 def main(self,argv=None):
275 275 """Run as a command-line script."""
276 276
@@ -301,7 +301,7 b' class IPythonRunner(InteractiveRunner):'
301 301 pexpect need to be matched to the actual prompts, so user-customized
302 302 prompts would break this.
303 303 """
304
304
305 305 def __init__(self,program = 'ipython',args=None,out=sys.stdout,echo=True):
306 306 """New runner, optionally passing the ipython command to use."""
307 307 args0 = ['--colors=NoColor',
@@ -327,10 +327,10 b' class PythonRunner(InteractiveRunner):'
327 327
328 328 class SAGERunner(InteractiveRunner):
329 329 """Interactive SAGE runner.
330
331 WARNING: this runner only works if you manually adjust your SAGE
330
331 WARNING: this runner only works if you manually adjust your SAGE
332 332 configuration so that the 'color' option in the configuration file is set to
333 'NoColor', because currently the prompt matching regexp does not identify
333 'NoColor', because currently the prompt matching regexp does not identify
334 334 color sequences."""
335 335
336 336 def __init__(self,program='sage',args=None,out=sys.stdout,echo=True):
@@ -354,7 +354,7 b' class RunnerFactory(object):'
354 354
355 355 def __init__(self,out=sys.stdout):
356 356 """Instantiate a code runner."""
357
357
358 358 self.out = out
359 359 self.runner = None
360 360 self.runnerClass = None
@@ -363,7 +363,7 b' class RunnerFactory(object):'
363 363 self.runnerClass = runnerClass
364 364 self.runner = runnerClass(out=self.out)
365 365 return self.runner
366
366
367 367 def __call__(self,fname):
368 368 """Return a runner for the given filename."""
369 369
@@ -1,5 +1,5 b''
1 1 """Test suite for pylab_import_all magic
2 Modified from the irunner module but using regex.
2 Modified from the irunner module but using regex.
3 3 """
4 4
5 5 # Global to make tests extra verbose and help debugging
@@ -24,7 +24,7 b' class RunnerTestCase(unittest.TestCase):'
24 24
25 25 def _test_runner(self,runner,source,output):
26 26 """Test that a given runner's input/output match."""
27
27
28 28 runner.run_source(source)
29 29 out = self.out.getvalue()
30 30 #out = ''
@@ -47,7 +47,7 b' def parse_filename(fname):'
47 47 format (json/py) and the notebook name. This logic can be
48 48 summarized as follows:
49 49
50 * notebook.ipynb -> (notebook.ipynb, notebook, json)
50 * notebook.ipynb -> (notebook.ipynb, notebook, json)
51 51 * notebook.json -> (notebook.json, notebook, json)
52 52 * notebook.py -> (notebook.py, notebook, py)
53 53 * notebook -> (notebook.ipynb, notebook, json)
@@ -61,8 +61,8 b' def parse_filename(fname):'
61 61
62 62 Returns
63 63 -------
64 (fname, name, format) : (unicode, unicode, unicode)
65 The filename, notebook name and format.
64 (fname, name, format) : (unicode, unicode, unicode)
65 The filename, notebook name and format.
66 66 """
67 67 if fname.endswith(u'.ipynb'):
68 68 format = u'json'
@@ -1,6 +1,6 b''
1 1 """The basic dict based notebook format.
2 2
3 The Python representation of a notebook is a nested structure of
3 The Python representation of a notebook is a nested structure of
4 4 dictionary subclasses that support attribute access
5 5 (IPython.utils.ipstruct.Struct). The functions in this module are merely
6 6 helpers to build the structs in the right form.
@@ -47,7 +47,7 b' def from_dict(d):'
47 47
48 48
49 49 def new_output(output_type=None, output_text=None, output_png=None,
50 output_html=None, output_svg=None, output_latex=None, output_json=None,
50 output_html=None, output_svg=None, output_latex=None, output_json=None,
51 51 output_javascript=None, output_jpeg=None, prompt_number=None,
52 52 etype=None, evalue=None, traceback=None):
53 53 """Create a new code cell with input and output"""
@@ -46,7 +46,7 b' class PyReader(NotebookReader):'
46 46 cells.append(cell)
47 47 state = u'codecell'
48 48 cell_lines = []
49 elif line.startswith(u'# <htmlcell>'):
49 elif line.startswith(u'# <htmlcell>'):
50 50 cell = self.new_cell(state, cell_lines)
51 51 if cell is not None:
52 52 cells.append(cell)
@@ -38,7 +38,7 b' from IPython.core.profiledir import ProfileDir'
38 38 from IPython.utils.daemonize import daemonize
39 39 from IPython.utils.importstring import import_item
40 40 from IPython.utils.sysinfo import num_cpus
41 from IPython.utils.traitlets import (Int, Unicode, Bool, CFloat, Dict, List,
41 from IPython.utils.traitlets import (Int, Unicode, Bool, CFloat, Dict, List,
42 42 DottedObjectName)
43 43
44 44 from IPython.parallel.apps.baseapp import (
@@ -114,7 +114,7 b' Start an ipython cluster by its profile name or cluster'
114 114 directory. Cluster directories contain configuration, log and
115 115 security related files and are named using the convention
116 116 'profile_<name>' and should be creating using the 'start'
117 subcommand of 'ipcluster'. If your cluster directory is in
117 subcommand of 'ipcluster'. If your cluster directory is in
118 118 the cwd or the ipython directory, you can simply refer to it
119 119 using its profile name, 'ipcluster start --n=4 --profile=<profile>`,
120 120 otherwise use the 'profile-dir' option.
@@ -123,7 +123,7 b' stop_help = """Stop a running IPython cluster'
123 123
124 124 Stop a running ipython cluster by its profile name or cluster
125 125 directory. Cluster directories are named using the convention
126 'profile_<name>'. If your cluster directory is in
126 'profile_<name>'. If your cluster directory is in
127 127 the cwd or the ipython directory, you can simply refer to it
128 128 using its profile name, 'ipcluster stop --profile=<profile>`, otherwise
129 129 use the '--profile-dir' option.
@@ -135,7 +135,7 b' by profile name or cluster directory.'
135 135 Cluster directories contain configuration, log and
136 136 security related files and are named using the convention
137 137 'profile_<name>' and should be creating using the 'start'
138 subcommand of 'ipcluster'. If your cluster directory is in
138 subcommand of 'ipcluster'. If your cluster directory is in
139 139 the cwd or the ipython directory, you can simply refer to it
140 140 using its profile name, 'ipcluster engines --n=4 --profile=<profile>`,
141 141 otherwise use the 'profile-dir' option.
@@ -150,12 +150,12 b' class IPClusterStop(BaseParallelApplication):'
150 150 description = stop_help
151 151 examples = _stop_examples
152 152 config_file_name = Unicode(default_config_file_name)
153
153
154 154 signal = Int(signal.SIGINT, config=True,
155 155 help="signal to use for stopping processes.")
156
156
157 157 aliases = Dict(stop_aliases)
158
158
159 159 def start(self):
160 160 """Start the app for the stop subcommand."""
161 161 try:
@@ -168,7 +168,7 b' class IPClusterStop(BaseParallelApplication):'
168 168 # can watch for to learn how I existed.
169 169 self.remove_pid_file()
170 170 self.exit(ALREADY_STOPPED)
171
171
172 172 if not self.check_pid(pid):
173 173 self.log.critical(
174 174 'Cluster [pid=%r] is not running.' % pid
@@ -177,7 +177,7 b' class IPClusterStop(BaseParallelApplication):'
177 177 # Here I exit with a unusual exit status that other processes
178 178 # can watch for to learn how I existed.
179 179 self.exit(ALREADY_STOPPED)
180
180
181 181 elif os.name=='posix':
182 182 sig = self.signal
183 183 self.log.info(
@@ -197,7 +197,7 b' class IPClusterStop(BaseParallelApplication):'
197 197 self.log.error("Stopping cluster failed, assuming already dead.",
198 198 exc_info=True)
199 199 self.remove_pid_file()
200
200
201 201 engine_aliases = {}
202 202 engine_aliases.update(base_aliases)
203 203 engine_aliases.update(dict(
@@ -228,7 +228,7 b' class IPClusterEngines(BaseParallelApplication):'
228 228 launchers = launcher.all_launchers
229 229 eslaunchers = [ l for l in launchers if 'EngineSet' in l.__name__]
230 230 return [ProfileDir]+eslaunchers
231
231
232 232 n = Int(num_cpus(), config=True,
233 233 help="""The number of engines to start. The default is to use one for each
234 234 CPU on your machine""")
@@ -239,12 +239,12 b' class IPClusterEngines(BaseParallelApplication):'
239 239 to use various batch systems to launch your engines, such as PBS,SGE,MPIExec,etc.
240 240 Each launcher class has its own set of configuration options, for making sure
241 241 it will work in your environment.
242
242
243 243 You can also write your own launcher, and specify it's absolute import path,
244 244 as in 'mymodule.launcher.FTLEnginesLauncher`.
245
245
246 246 Examples include:
247
247
248 248 LocalEngineSetLauncher : start engines locally as subprocesses [default]
249 249 MPIExecEngineSetLauncher : use mpiexec to launch in an MPI environment
250 250 PBSEngineSetLauncher : use PBS (qsub) to submit engines to a batch queue
@@ -273,15 +273,15 b' class IPClusterEngines(BaseParallelApplication):'
273 273 super(IPClusterEngines, self).initialize(argv)
274 274 self.init_signal()
275 275 self.init_launchers()
276
276
277 277 def init_launchers(self):
278 278 self.engine_launcher = self.build_launcher(self.engine_launcher_class, 'EngineSet')
279 279 self.engine_launcher.on_stop(lambda r: self.loop.stop())
280
280
281 281 def init_signal(self):
282 282 # Setup signals
283 283 signal.signal(signal.SIGINT, self.sigint_handler)
284
284
285 285 def build_launcher(self, clsname, kind=None):
286 286 """import and instantiate a Launcher based on importstring"""
287 287 if '.' not in clsname:
@@ -302,7 +302,7 b' class IPClusterEngines(BaseParallelApplication):'
302 302 profile_dir=self.profile_dir.location, cluster_id=self.cluster_id,
303 303 )
304 304 return launcher
305
305
306 306 def start_engines(self):
307 307 self.log.info("Starting %i engines"%self.n)
308 308 self.engine_launcher.start(self.n)
@@ -327,7 +327,7 b' class IPClusterEngines(BaseParallelApplication):'
327 327 def sigint_handler(self, signum, frame):
328 328 self.log.debug("SIGINT received, stopping launchers...")
329 329 self.stop_launchers()
330
330
331 331 def start_logging(self):
332 332 # Remove old log files of the controller and engine
333 333 if self.clean_logs:
@@ -342,7 +342,7 b' class IPClusterEngines(BaseParallelApplication):'
342 342 """Start the app for the engines subcommand."""
343 343 self.log.info("IPython cluster: started")
344 344 # First see if the cluster is already running
345
345
346 346 # Now log and daemonize
347 347 self.log.info(
348 348 'Starting engines with [daemon=%r]' % self.daemonize
@@ -392,8 +392,8 b' class IPClusterStart(IPClusterEngines):'
392 392 def _classes_default(self,):
393 393 from IPython.parallel.apps import launcher
394 394 return [ProfileDir] + [IPClusterEngines] + launcher.all_launchers
395
396 clean_logs = Bool(True, config=True,
395
396 clean_logs = Bool(True, config=True,
397 397 help="whether to cleanup old logs before starting")
398 398
399 399 delay = CFloat(1., config=True,
@@ -403,12 +403,12 b' class IPClusterStart(IPClusterEngines):'
403 403 config=True,
404 404 helep="""The class for launching a Controller. Change this value if you want
405 405 your controller to also be launched by a batch system, such as PBS,SGE,MPIExec,etc.
406
406
407 407 Each launcher class has its own set of configuration options, for making sure
408 408 it will work in your environment.
409
409
410 410 Examples include:
411
411
412 412 LocalControllerLauncher : start engines locally as subprocesses
413 413 MPIExecControllerLauncher : use mpiexec to launch engines in an MPI universe
414 414 PBSControllerLauncher : use PBS (qsub) to submit engines to a batch queue
@@ -420,7 +420,7 b' class IPClusterStart(IPClusterEngines):'
420 420 reset = Bool(False, config=True,
421 421 help="Whether to reset config files as part of '--create'."
422 422 )
423
423
424 424 # flags = Dict(flags)
425 425 aliases = Dict(start_aliases)
426 426
@@ -428,10 +428,10 b' class IPClusterStart(IPClusterEngines):'
428 428 self.controller_launcher = self.build_launcher(self.controller_launcher_class, 'Controller')
429 429 self.engine_launcher = self.build_launcher(self.engine_launcher_class, 'EngineSet')
430 430 self.controller_launcher.on_stop(self.stop_launchers)
431
431
432 432 def start_controller(self):
433 433 self.controller_launcher.start()
434
434
435 435 def stop_controller(self):
436 436 # self.log.info("In stop_controller")
437 437 if self.controller_launcher and self.controller_launcher.running:
@@ -460,7 +460,7 b' class IPClusterStart(IPClusterEngines):'
460 460 self.exit(ALREADY_STARTED)
461 461 else:
462 462 self.remove_pid_file()
463
463
464 464
465 465 # Now log and daemonize
466 466 self.log.info(
@@ -501,11 +501,11 b' class IPClusterApp(Application):'
501 501 'stop' : (base+'Stop', stop_help),
502 502 'engines' : (base+'Engines', engines_help),
503 503 }
504
504
505 505 # no aliases or flags for parent App
506 506 aliases = Dict()
507 507 flags = Dict()
508
508
509 509 def start(self):
510 510 if self.subapp is None:
511 511 print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys())
@@ -115,10 +115,10 b' class BaseLauncher(LoggingConfigurable):'
115 115 # the work_dir option.
116 116 work_dir = Unicode(u'.')
117 117 loop = Instance('zmq.eventloop.ioloop.IOLoop')
118
118
119 119 start_data = Any()
120 120 stop_data = Any()
121
121
122 122 def _loop_default(self):
123 123 return ioloop.IOLoop.instance()
124 124
@@ -255,7 +255,7 b' class LocalProcessLauncher(BaseLauncher):'
255 255 ``self.work_dir``.
256 256 """
257 257
258 # This is used to to construct self.args, which is passed to
258 # This is used to to construct self.args, which is passed to
259 259 # spawnProcess.
260 260 cmd_and_args = List([])
261 261 poll_frequency = Int(100) # in ms
@@ -314,7 +314,7 b' class LocalProcessLauncher(BaseLauncher):'
314 314 self.killer.start()
315 315
316 316 # callbacks, etc:
317
317
318 318 def handle_stdout(self, fd, events):
319 319 if WINDOWS:
320 320 line = self.stdout.recv()
@@ -325,7 +325,7 b' class LocalProcessLauncher(BaseLauncher):'
325 325 self.log.info(line[:-1])
326 326 else:
327 327 self.poll()
328
328
329 329 def handle_stderr(self, fd, events):
330 330 if WINDOWS:
331 331 line = self.stderr.recv()
@@ -336,7 +336,7 b' class LocalProcessLauncher(BaseLauncher):'
336 336 self.log.error(line[:-1])
337 337 else:
338 338 self.poll()
339
339
340 340 def poll(self):
341 341 status = self.process.poll()
342 342 if status is not None:
@@ -373,13 +373,13 b' class LocalEngineSetLauncher(LocalEngineLauncher):'
373 373 This can help force the engines to get their ids in order, or limit
374 374 process flood when starting many engines."""
375 375 )
376
376
377 377 # launcher class
378 378 launcher_class = LocalEngineLauncher
379
379
380 380 launchers = Dict()
381 381 stop_data = Dict()
382
382
383 383 def __init__(self, work_dir=u'.', config=None, **kwargs):
384 384 super(LocalEngineSetLauncher, self).__init__(
385 385 work_dir=work_dir, config=config, **kwargs
@@ -395,7 +395,7 b' class LocalEngineSetLauncher(LocalEngineLauncher):'
395 395 el = self.launcher_class(work_dir=self.work_dir, config=self.config, log=self.log,
396 396 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
397 397 )
398
398
399 399 # Copy the engine args over to each engine launcher.
400 400 el.engine_cmd = copy.deepcopy(self.engine_cmd)
401 401 el.engine_args = copy.deepcopy(self.engine_args)
@@ -427,7 +427,7 b' class LocalEngineSetLauncher(LocalEngineLauncher):'
427 427
428 428 def stop(self):
429 429 return self.interrupt_then_kill()
430
430
431 431 def _notice_engine_stopped(self, data):
432 432 pid = data['pid']
433 433 for idx,el in self.launchers.iteritems():
@@ -480,7 +480,7 b' class MPIExecControllerLauncher(MPIExecLauncher, ControllerMixin):'
480 480 @property
481 481 def program(self):
482 482 return self.controller_cmd
483
483
484 484 @property
485 485 def program_args(self):
486 486 return self.cluster_args + self.controller_args
@@ -500,7 +500,7 b' class MPIExecEngineSetLauncher(MPIExecLauncher, EngineMixin):'
500 500 @property
501 501 def program(self):
502 502 return self.engine_cmd
503
503
504 504 @property
505 505 def program_args(self):
506 506 return self.cluster_args + self.engine_args
@@ -558,15 +558,15 b' class SSHLauncher(LocalProcessLauncher):'
558 558 self.hostname = hostname
559 559 if user is not None:
560 560 self.user = user
561
561
562 562 return super(SSHLauncher, self).start()
563
563
564 564 def signal(self, sig):
565 565 if self.state == 'running':
566 566 # send escaped ssh connection-closer
567 567 self.process.stdin.write('~.')
568 568 self.process.stdin.flush()
569
569
570 570
571 571
572 572 class SSHControllerLauncher(SSHLauncher, ControllerMixin):
@@ -577,7 +577,7 b' class SSHControllerLauncher(SSHLauncher, ControllerMixin):'
577 577 @property
578 578 def program(self):
579 579 return self.controller_cmd
580
580
581 581 @property
582 582 def program_args(self):
583 583 return self.cluster_args + self.controller_args
@@ -591,30 +591,30 b' class SSHEngineLauncher(SSHLauncher, EngineMixin):'
591 591 @property
592 592 def program(self):
593 593 return self.engine_cmd
594
594
595 595 @property
596 596 def program_args(self):
597 597 return self.cluster_args + self.engine_args
598
599
598
599
600 600 class SSHEngineSetLauncher(LocalEngineSetLauncher):
601 601 launcher_class = SSHEngineLauncher
602 602 engines = Dict(config=True,
603 603 help="""dict of engines to launch. This is a dict by hostname of ints,
604 604 corresponding to the number of engines to start on that host.""")
605
605
606 606 def start(self, n):
607 607 """Start engines by profile or profile_dir.
608 608 `n` is ignored, and the `engines` config property is used instead.
609 609 """
610
610
611 611 dlist = []
612 612 for host, n in self.engines.iteritems():
613 613 if isinstance(n, (tuple, list)):
614 614 n, args = n
615 615 else:
616 616 args = copy.deepcopy(self.engine_args)
617
617
618 618 if '@' in host:
619 619 user,host = host.split('@',1)
620 620 else:
@@ -625,7 +625,7 b' class SSHEngineSetLauncher(LocalEngineSetLauncher):'
625 625 el = self.launcher_class(work_dir=self.work_dir, config=self.config, log=self.log,
626 626 profile_dir=self.profile_dir, cluster_id=self.cluster_id,
627 627 )
628
628
629 629 # Copy the engine args over to each engine launcher.
630 630 el.engine_cmd = self.engine_cmd
631 631 el.engine_args = args
@@ -637,7 +637,7 b' class SSHEngineSetLauncher(LocalEngineSetLauncher):'
637 637 dlist.append(d)
638 638 self.notify_start(dlist)
639 639 return dlist
640
640
641 641
642 642
643 643 #-----------------------------------------------------------------------------
@@ -687,7 +687,7 b' class WindowsHPCLauncher(BaseLauncher):'
687 687
688 688 def find_args(self):
689 689 return [u'job.exe']
690
690
691 691 def parse_job_id(self, output):
692 692 """Take the output of the submit command and return the job id."""
693 693 m = re.search(self.job_id_regexp, output)
@@ -748,7 +748,7 b' class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin):'
748 748 job = IPControllerJob(config=self.config)
749 749
750 750 t = IPControllerTask(config=self.config)
751 # The tasks work directory is *not* the actual work directory of
751 # The tasks work directory is *not* the actual work directory of
752 752 # the controller. It is used as the base path for the stdout/stderr
753 753 # files that the scheduler redirects to.
754 754 t.work_directory = self.profile_dir
@@ -781,7 +781,7 b' class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin):'
781 781
782 782 for i in range(n):
783 783 t = IPEngineTask(config=self.config)
784 # The tasks work directory is *not* the actual work directory of
784 # The tasks work directory is *not* the actual work directory of
785 785 # the engine. It is used as the base path for the stdout/stderr
786 786 # files that the scheduler redirects to.
787 787 t.work_directory = self.profile_dir
@@ -850,13 +850,13 b' class BatchSystemLauncher(BaseLauncher):'
850 850 help="The filename of the instantiated batch script.")
851 851 queue = Unicode(u'', config=True,
852 852 help="The PBS Queue.")
853
853
854 854 def _queue_changed(self, name, old, new):
855 855 self.context[name] = new
856
856
857 857 n = Int(1)
858 858 _n_changed = _queue_changed
859
859
860 860 # not configurable, override in subclasses
861 861 # PBS Job Array regex
862 862 job_array_regexp = Unicode('')
@@ -873,10 +873,10 b' class BatchSystemLauncher(BaseLauncher):'
873 873 # the Formatter instance for rendering the templates:
874 874 formatter = Instance(EvalFormatter, (), {})
875 875
876
876
877 877 def find_args(self):
878 878 return self.submit_command + [self.batch_file]
879
879
880 880 def __init__(self, work_dir=u'.', config=None, **kwargs):
881 881 super(BatchSystemLauncher, self).__init__(
882 882 work_dir=work_dir, config=config, **kwargs
@@ -905,7 +905,7 b' class BatchSystemLauncher(BaseLauncher):'
905 905 if not self.batch_template:
906 906 # third (last) priority is default_template
907 907 self.batch_template = self.default_template
908
908
909 909 # add jobarray or queue lines to user-specified template
910 910 # note that this is *only* when user did not specify a template.
911 911 regex = re.compile(self.job_array_regexp)
@@ -914,17 +914,17 b' class BatchSystemLauncher(BaseLauncher):'
914 914 self.log.info("adding job array settings to batch script")
915 915 firstline, rest = self.batch_template.split('\n',1)
916 916 self.batch_template = u'\n'.join([firstline, self.job_array_template, rest])
917
917
918 918 regex = re.compile(self.queue_regexp)
919 919 # print regex.search(self.batch_template)
920 920 if self.queue and not regex.search(self.batch_template):
921 921 self.log.info("adding PBS queue settings to batch script")
922 922 firstline, rest = self.batch_template.split('\n',1)
923 923 self.batch_template = u'\n'.join([firstline, self.queue_template, rest])
924
924
925 925 script_as_string = self.formatter.format(self.batch_template, **self.context)
926 926 self.log.info('Writing instantiated batch script: %s' % self.batch_file)
927
927
928 928 with open(self.batch_file, 'w') as f:
929 929 f.write(script_as_string)
930 930 os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
@@ -935,7 +935,7 b' class BatchSystemLauncher(BaseLauncher):'
935 935 # can be used in the batch script template as {profile_dir}
936 936 self.write_batch_script(n)
937 937 output = check_output(self.args, env=os.environ)
938
938
939 939 job_id = self.parse_job_id(output)
940 940 self.notify_start(job_id)
941 941 return job_id
@@ -955,7 +955,7 b' class PBSLauncher(BatchSystemLauncher):'
955 955 help="The PBS delete command ['qsub']")
956 956 job_id_regexp = Unicode(r'\d+', config=True,
957 957 help="Regular expresion for identifying the job ID [r'\d+']")
958
958
959 959 batch_file = Unicode(u'')
960 960 job_array_regexp = Unicode('#PBS\W+-t\W+[\w\d\-\$]+')
961 961 job_array_template = Unicode('#PBS -t 1-{n}')
@@ -974,7 +974,7 b' class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin):'
974 974 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
975 975 """%(' '.join(ipcontroller_cmd_argv)))
976 976
977
977
978 978 def start(self):
979 979 """Start the controller by profile or profile_dir."""
980 980 self.log.info("Starting PBSControllerLauncher: %r" % self.args)
@@ -1041,20 +1041,20 b' class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin):'
1041 1041
1042 1042 class LSFLauncher(BatchSystemLauncher):
1043 1043 """A BatchSystemLauncher subclass for LSF."""
1044
1044
1045 1045 submit_command = List(['bsub'], config=True,
1046 1046 help="The PBS submit command ['bsub']")
1047 1047 delete_command = List(['bkill'], config=True,
1048 1048 help="The PBS delete command ['bkill']")
1049 1049 job_id_regexp = Unicode(r'\d+', config=True,
1050 1050 help="Regular expresion for identifying the job ID [r'\d+']")
1051
1051
1052 1052 batch_file = Unicode(u'')
1053 1053 job_array_regexp = Unicode('#BSUB[ \t]-J+\w+\[\d+-\d+\]')
1054 1054 job_array_template = Unicode('#BSUB -J ipengine[1-{n}]')
1055 1055 queue_regexp = Unicode('#BSUB[ \t]+-q[ \t]+\w+')
1056 1056 queue_template = Unicode('#BSUB -q {queue}')
1057
1057
1058 1058 def start(self, n):
1059 1059 """Start n copies of the process using LSF batch system.
1060 1060 This cant inherit from the base class because bsub expects
@@ -1075,16 +1075,16 b' class LSFLauncher(BatchSystemLauncher):'
1075 1075
1076 1076 class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin):
1077 1077 """Launch a controller using LSF."""
1078
1078
1079 1079 batch_file_name = Unicode(u'lsf_controller', config=True,
1080 1080 help="batch file name for the controller job.")
1081 1081 default_template= Unicode("""#!/bin/sh
1082 1082 #BSUB -J ipcontroller
1083 #BSUB -oo ipcontroller.o.%%J
1084 #BSUB -eo ipcontroller.e.%%J
1083 #BSUB -oo ipcontroller.o.%%J
1084 #BSUB -eo ipcontroller.e.%%J
1085 1085 %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1086 1086 """%(' '.join(ipcontroller_cmd_argv)))
1087
1087
1088 1088 def start(self):
1089 1089 """Start the controller by profile or profile_dir."""
1090 1090 self.log.info("Starting LSFControllerLauncher: %r" % self.args)
@@ -1096,11 +1096,11 b' class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin):'
1096 1096 batch_file_name = Unicode(u'lsf_engines', config=True,
1097 1097 help="batch file name for the engine(s) job.")
1098 1098 default_template= Unicode(u"""#!/bin/sh
1099 #BSUB -oo ipengine.o.%%J
1100 #BSUB -eo ipengine.e.%%J
1099 #BSUB -oo ipengine.o.%%J
1100 #BSUB -eo ipengine.e.%%J
1101 1101 %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}"
1102 1102 """%(' '.join(ipengine_cmd_argv)))
1103
1103
1104 1104 def start(self, n):
1105 1105 """Start n engines by profile or profile_dir."""
1106 1106 self.log.info('Starting %i engines with LSFEngineSetLauncher: %r' % (n, self.args))
@@ -1,6 +1,6 b''
1 1 # encoding: utf-8
2 2 """
3 Job and task components for writing .xml files that the Windows HPC Server
3 Job and task components for writing .xml files that the Windows HPC Server
4 4 2008 can use to start jobs.
5 5
6 6 Authors:
@@ -297,7 +297,7 b' class IPEngineTask(WinHPCTask):'
297 297 the_uuid = uuid.uuid1()
298 298 self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid)
299 299 self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid)
300
300
301 301 @property
302 302 def command_line(self):
303 303 return ' '.join(self.engine_cmd + self.engine_args)
@@ -307,7 +307,7 b' class IPEngineTask(WinHPCTask):'
307 307 # j.job_name = 'IPCluster'
308 308 # j.username = 'GNET\\bgranger'
309 309 # j.requested_nodes = 'GREEN'
310 #
310 #
311 311 # t = WinHPCTask(None)
312 312 # t.task_name = 'Controller'
313 313 # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10"
@@ -39,15 +39,15 b' def check_ready(f, self, *args, **kwargs):'
39 39
40 40 class AsyncResult(object):
41 41 """Class for representing results of non-blocking calls.
42
42
43 43 Provides the same interface as :py:class:`multiprocessing.pool.AsyncResult`.
44 44 """
45
45
46 46 msg_ids = None
47 47 _targets = None
48 48 _tracker = None
49 49 _single_result = False
50
50
51 51 def __init__(self, client, msg_ids, fname='unknown', targets=None, tracker=None):
52 52 if isinstance(msg_ids, basestring):
53 53 # always a list
@@ -66,17 +66,17 b' class AsyncResult(object):'
66 66 self._single_result = not isinstance(targets, (list, tuple))
67 67 else:
68 68 self._single_result = False
69
69
70 70 def __repr__(self):
71 71 if self._ready:
72 72 return "<%s: finished>"%(self.__class__.__name__)
73 73 else:
74 74 return "<%s: %s>"%(self.__class__.__name__,self._fname)
75
76
75
76
77 77 def _reconstruct_result(self, res):
78 78 """Reconstruct our result from actual result list (always a list)
79
79
80 80 Override me in subclasses for turning a list of results
81 81 into the expected form.
82 82 """
@@ -84,10 +84,10 b' class AsyncResult(object):'
84 84 return res[0]
85 85 else:
86 86 return res
87
87
88 88 def get(self, timeout=-1):
89 """Return the result when it arrives.
90
89 """Return the result when it arrives.
90
91 91 If `timeout` is not ``None`` and the result does not arrive within
92 92 `timeout` seconds then ``TimeoutError`` is raised. If the
93 93 remote call raised an exception then that exception will be reraised
@@ -95,7 +95,7 b' class AsyncResult(object):'
95 95 """
96 96 if not self.ready():
97 97 self.wait(timeout)
98
98
99 99 if self._ready:
100 100 if self._success:
101 101 return self._result
@@ -103,16 +103,16 b' class AsyncResult(object):'
103 103 raise self._exception
104 104 else:
105 105 raise error.TimeoutError("Result not ready.")
106
106
107 107 def ready(self):
108 108 """Return whether the call has completed."""
109 109 if not self._ready:
110 110 self.wait(0)
111 111 return self._ready
112
112
113 113 def wait(self, timeout=-1):
114 114 """Wait until the result is available or until `timeout` seconds pass.
115
115
116 116 This method always returns None.
117 117 """
118 118 if self._ready:
@@ -136,26 +136,26 b' class AsyncResult(object):'
136 136 self._success = True
137 137 finally:
138 138 self._metadata = map(self._client.metadata.get, self.msg_ids)
139
140
139
140
141 141 def successful(self):
142 """Return whether the call completed without raising an exception.
143
142 """Return whether the call completed without raising an exception.
143
144 144 Will raise ``AssertionError`` if the result is not ready.
145 145 """
146 146 assert self.ready()
147 147 return self._success
148
148
149 149 #----------------------------------------------------------------
150 150 # Extra methods not in mp.pool.AsyncResult
151 151 #----------------------------------------------------------------
152
152
153 153 def get_dict(self, timeout=-1):
154 154 """Get the results as a dict, keyed by engine_id.
155
155
156 156 timeout behavior is described in `get()`.
157 157 """
158
158
159 159 results = self.get(timeout)
160 160 engine_ids = [ md['engine_id'] for md in self._metadata ]
161 161 bycount = sorted(engine_ids, key=lambda k: engine_ids.count(k))
@@ -163,17 +163,17 b' class AsyncResult(object):'
163 163 if maxcount > 1:
164 164 raise ValueError("Cannot build dict, %i jobs ran on engine #%i"%(
165 165 maxcount, bycount[-1]))
166
166
167 167 return dict(zip(engine_ids,results))
168
168
169 169 @property
170 170 def result(self):
171 171 """result property wrapper for `get(timeout=0)`."""
172 172 return self.get()
173
173
174 174 # abbreviated alias:
175 175 r = result
176
176
177 177 @property
178 178 @check_ready
179 179 def metadata(self):
@@ -182,15 +182,15 b' class AsyncResult(object):'
182 182 return self._metadata[0]
183 183 else:
184 184 return self._metadata
185
185
186 186 @property
187 187 def result_dict(self):
188 188 """result property as a dict."""
189 189 return self.get_dict()
190
190
191 191 def __dict__(self):
192 192 return self.get_dict(0)
193
193
194 194 def abort(self):
195 195 """abort my tasks."""
196 196 assert not self.ready(), "Can't abort, I am already done!"
@@ -200,10 +200,10 b' class AsyncResult(object):'
200 200 def sent(self):
201 201 """check whether my messages have been sent."""
202 202 return self._tracker.done
203
203
204 204 def wait_for_send(self, timeout=-1):
205 205 """wait for pyzmq send to complete.
206
206
207 207 This is necessary when sending arrays that you intend to edit in-place.
208 208 `timeout` is in seconds, and will raise TimeoutError if it is reached
209 209 before the send completes.
@@ -213,7 +213,7 b' class AsyncResult(object):'
213 213 #-------------------------------------
214 214 # dict-access
215 215 #-------------------------------------
216
216
217 217 @check_ready
218 218 def __getitem__(self, key):
219 219 """getitem returns result value(s) if keyed by int/slice, or metadata if key is str.
@@ -230,7 +230,7 b' class AsyncResult(object):'
230 230 return values
231 231 else:
232 232 raise TypeError("Invalid key type %r, must be 'int','slice', or 'str'"%type(key))
233
233
234 234 @check_ready
235 235 def __getattr__(self, key):
236 236 """getattr maps to getitem for convenient attr access to metadata."""
@@ -238,7 +238,7 b' class AsyncResult(object):'
238 238 raise AttributeError("%r object has no attribute %r"%(
239 239 self.__class__.__name__, key))
240 240 return self.__getitem__(key)
241
241
242 242 # asynchronous iterator:
243 243 def __iter__(self):
244 244 if self._single_result:
@@ -256,22 +256,22 b' class AsyncResult(object):'
256 256 yield r
257 257
258 258
259
259
260 260 class AsyncMapResult(AsyncResult):
261 261 """Class for representing results of non-blocking gathers.
262
262
263 263 This will properly reconstruct the gather.
264 264 """
265
265
266 266 def __init__(self, client, msg_ids, mapObject, fname=''):
267 267 AsyncResult.__init__(self, client, msg_ids, fname=fname)
268 268 self._mapObject = mapObject
269 269 self._single_result = False
270
270
271 271 def _reconstruct_result(self, res):
272 272 """Perform the gather on the actual results."""
273 273 return self._mapObject.joinPartitions(res)
274
274
275 275 # asynchronous iterator:
276 276 def __iter__(self):
277 277 try:
@@ -297,11 +297,11 b' class AsyncMapResult(AsyncResult):'
297 297
298 298 class AsyncHubResult(AsyncResult):
299 299 """Class to wrap pending results that must be requested from the Hub.
300
300
301 301 Note that waiting/polling on these objects requires polling the Hubover the network,
302 302 so use `AsyncHubResult.wait()` sparingly.
303 303 """
304
304
305 305 def wait(self, timeout=-1):
306 306 """wait for result to complete."""
307 307 start = time.time()
@@ -341,5 +341,5 b' class AsyncHubResult(AsyncResult):'
341 341 self._success = True
342 342 finally:
343 343 self._metadata = map(self._client.metadata.get, self.msg_ids)
344
344
345 345 __all__ = ['AsyncResult', 'AsyncMapResult', 'AsyncHubResult'] No newline at end of file
@@ -71,9 +71,9 b' def spin_first(f, self, *args, **kwargs):'
71 71
72 72 class Metadata(dict):
73 73 """Subclass of dict for initializing metadata values.
74
74
75 75 Attribute access works on keys.
76
76
77 77 These objects have a strict set of keys - errors will raise if you try
78 78 to add new keys.
79 79 """
@@ -98,7 +98,7 b' class Metadata(dict):'
98 98 }
99 99 self.update(md)
100 100 self.update(dict(*args, **kwargs))
101
101
102 102 def __getattr__(self, key):
103 103 """getattr aliased to getitem"""
104 104 if key in self.iterkeys():
@@ -112,21 +112,21 b' class Metadata(dict):'
112 112 self[key] = value
113 113 else:
114 114 raise AttributeError(key)
115
115
116 116 def __setitem__(self, key, value):
117 117 """strict static key enforcement"""
118 118 if key in self.iterkeys():
119 119 dict.__setitem__(self, key, value)
120 120 else:
121 121 raise KeyError(key)
122
122
123 123
124 124 class Client(HasTraits):
125 125 """A semi-synchronous client to the IPython ZMQ cluster
126
126
127 127 Parameters
128 128 ----------
129
129
130 130 url_or_file : bytes or unicode; zmq url or path to ipcontroller-client.json
131 131 Connection information for the Hub's registration. If a json connector
132 132 file is given, then likely no further configuration is necessary.
@@ -139,12 +139,12 b' class Client(HasTraits):'
139 139 Pass an existing zmq.Context instance, otherwise the client will create its own.
140 140 debug : bool
141 141 flag for lots of message printing for debug purposes
142 timeout : int/float
142 timeout : int/float
143 143 time (in seconds) to wait for connection replies from the Hub
144 144 [Default: 10]
145
145
146 146 #-------------- session related args ----------------
147
147
148 148 config : Config object
149 149 If specified, this will be relayed to the Session for configuration
150 150 username : str
@@ -157,16 +157,16 b' class Client(HasTraits):'
157 157 unpacker : str (import_string) or callable
158 158 The inverse of packer. Only necessary if packer is specified as *not* one
159 159 of 'json' or 'pickle'.
160
160
161 161 #-------------- ssh related args ----------------
162 162 # These are args for configuring the ssh tunnel to be used
163 163 # credentials are used to forward connections over ssh to the Controller
164 164 # Note that the ip given in `addr` needs to be relative to sshserver
165 165 # The most basic case is to leave addr as pointing to localhost (127.0.0.1),
166 # and set sshserver as the same machine the Controller is on. However,
166 # and set sshserver as the same machine the Controller is on. However,
167 167 # the only requirement is that sshserver is able to see the Controller
168 168 # (i.e. is within the same trusted network).
169
169
170 170 sshserver : str
171 171 A string of the form passed to ssh, i.e. 'server.tld' or 'user@server.tld:port'
172 172 If keyfile or password is specified, and this is not, it will default to
@@ -174,81 +174,81 b' class Client(HasTraits):'
174 174 sshkey : str; path to ssh private key file
175 175 This specifies a key to be used in ssh login, default None.
176 176 Regular default ssh keys will be used without specifying this argument.
177 password : str
177 password : str
178 178 Your ssh password to sshserver. Note that if this is left None,
179 179 you will be prompted for it if passwordless key based login is unavailable.
180 180 paramiko : bool
181 181 flag for whether to use paramiko instead of shell ssh for tunneling.
182 182 [default: True on win32, False else]
183
183
184 184 ------- exec authentication args -------
185 185 If even localhost is untrusted, you can have some protection against
186 unauthorized execution by signing messages with HMAC digests.
187 Messages are still sent as cleartext, so if someone can snoop your
186 unauthorized execution by signing messages with HMAC digests.
187 Messages are still sent as cleartext, so if someone can snoop your
188 188 loopback traffic this will not protect your privacy, but will prevent
189 189 unauthorized execution.
190
190
191 191 exec_key : str
192 192 an authentication key or file containing a key
193 193 default: None
194
195
194
195
196 196 Attributes
197 197 ----------
198
198
199 199 ids : list of int engine IDs
200 200 requesting the ids attribute always synchronizes
201 201 the registration state. To request ids without synchronization,
202 202 use semi-private _ids attributes.
203
203
204 204 history : list of msg_ids
205 205 a list of msg_ids, keeping track of all the execution
206 206 messages you have submitted in order.
207
207
208 208 outstanding : set of msg_ids
209 209 a set of msg_ids that have been submitted, but whose
210 210 results have not yet been received.
211
211
212 212 results : dict
213 213 a dict of all our results, keyed by msg_id
214
214
215 215 block : bool
216 216 determines default behavior when block not specified
217 217 in execution methods
218
218
219 219 Methods
220 220 -------
221
221
222 222 spin
223 223 flushes incoming results and registration state changes
224 224 control methods spin, and requesting `ids` also ensures up to date
225
225
226 226 wait
227 227 wait on one or more msg_ids
228
228
229 229 execution methods
230 230 apply
231 231 legacy: execute, run
232
232
233 233 data movement
234 234 push, pull, scatter, gather
235
235
236 236 query methods
237 237 queue_status, get_result, purge, result_status
238
238
239 239 control methods
240 240 abort, shutdown
241
241
242 242 """
243
244
243
244
245 245 block = Bool(False)
246 246 outstanding = Set()
247 247 results = Instance('collections.defaultdict', (dict,))
248 248 metadata = Instance('collections.defaultdict', (Metadata,))
249 249 history = List()
250 250 debug = Bool(False)
251
251
252 252 profile=Unicode()
253 253 def _profile_default(self):
254 254 if BaseIPythonApplication.initialized():
@@ -261,8 +261,8 b' class Client(HasTraits):'
261 261 return u'default'
262 262 else:
263 263 return u'default'
264
265
264
265
266 266 _outstanding_dict = Instance('collections.defaultdict', (set,))
267 267 _ids = List()
268 268 _connected=Bool(False)
@@ -281,11 +281,11 b' class Client(HasTraits):'
281 281 _closed = False
282 282 _ignored_control_replies=Int(0)
283 283 _ignored_hub_replies=Int(0)
284
284
285 285 def __new__(self, *args, **kw):
286 286 # don't raise on positional args
287 287 return HasTraits.__new__(self, **kw)
288
288
289 289 def __init__(self, url_or_file=None, profile=None, profile_dir=None, ipython_dir=None,
290 290 context=None, debug=False, exec_key=None,
291 291 sshserver=None, sshkey=None, password=None, paramiko=None,
@@ -298,14 +298,14 b' class Client(HasTraits):'
298 298 if context is None:
299 299 context = zmq.Context.instance()
300 300 self._context = context
301
301
302 302 self._setup_profile_dir(self.profile, profile_dir, ipython_dir)
303 303 if self._cd is not None:
304 304 if url_or_file is None:
305 305 url_or_file = pjoin(self._cd.security_dir, 'ipcontroller-client.json')
306 306 assert url_or_file is not None, "I can't find enough information to connect to a hub!"\
307 307 " Please specify at least one of url_or_file or profile."
308
308
309 309 try:
310 310 util.validate_url(url_or_file)
311 311 except AssertionError:
@@ -317,7 +317,7 b' class Client(HasTraits):'
317 317 cfg = json.loads(f.read())
318 318 else:
319 319 cfg = {'url':url_or_file}
320
320
321 321 # sync defaults from args, json:
322 322 if sshserver:
323 323 cfg['ssh'] = sshserver
@@ -346,9 +346,9 b' class Client(HasTraits):'
346 346 elif not sshserver:
347 347 # otherwise sync with cfg
348 348 sshserver = cfg['ssh']
349
349
350 350 self._config = cfg
351
351
352 352 self._ssh = bool(sshserver or sshkey or password)
353 353 if self._ssh and sshserver is None:
354 354 # default to ssh via localhost
@@ -359,7 +359,7 b' class Client(HasTraits):'
359 359 else:
360 360 password = getpass("SSH Password for %s: "%sshserver)
361 361 ssh_kwargs = dict(keyfile=sshkey, password=password, paramiko=paramiko)
362
362
363 363 # configure and construct the session
364 364 if exec_key is not None:
365 365 if os.path.isfile(exec_key):
@@ -368,16 +368,16 b' class Client(HasTraits):'
368 368 exec_key = util.asbytes(exec_key)
369 369 extra_args['key'] = exec_key
370 370 self.session = Session(**extra_args)
371
371
372 372 self._query_socket = self._context.socket(zmq.DEALER)
373 373 self._query_socket.setsockopt(zmq.IDENTITY, self.session.bsession)
374 374 if self._ssh:
375 375 tunnel.tunnel_connection(self._query_socket, url, sshserver, **ssh_kwargs)
376 376 else:
377 377 self._query_socket.connect(url)
378
378
379 379 self.session.debug = self.debug
380
380
381 381 self._notification_handlers = {'registration_notification' : self._register_engine,
382 382 'unregistration_notification' : self._unregister_engine,
383 383 'shutdown_notification' : lambda msg: self.close(),
@@ -385,11 +385,11 b' class Client(HasTraits):'
385 385 self._queue_handlers = {'execute_reply' : self._handle_execute_reply,
386 386 'apply_reply' : self._handle_apply_reply}
387 387 self._connect(sshserver, ssh_kwargs, timeout)
388
388
389 389 def __del__(self):
390 390 """cleanup sockets, but _not_ context."""
391 391 self.close()
392
392
393 393 def _setup_profile_dir(self, profile, profile_dir, ipython_dir):
394 394 if ipython_dir is None:
395 395 ipython_dir = get_ipython_dir()
@@ -407,7 +407,7 b' class Client(HasTraits):'
407 407 except ProfileDirError:
408 408 pass
409 409 self._cd = None
410
410
411 411 def _update_engines(self, engines):
412 412 """Update our engines dict and _ids from a dict of the form: {id:uuid}."""
413 413 for k,v in engines.iteritems():
@@ -418,7 +418,7 b' class Client(HasTraits):'
418 418 if sorted(self._engines.keys()) != range(len(self._engines)) and \
419 419 self._task_scheme == 'pure' and self._task_socket:
420 420 self._stop_scheduling_tasks()
421
421
422 422 def _stop_scheduling_tasks(self):
423 423 """Stop scheduling tasks because an engine has been unregistered
424 424 from a pure ZMQ scheduler.
@@ -431,7 +431,7 b' class Client(HasTraits):'
431 431 msg += " If you were running tasks when this happened, " +\
432 432 "some `outstanding` msg_ids may never resolve."
433 433 warnings.warn(msg, RuntimeWarning)
434
434
435 435 def _build_targets(self, targets):
436 436 """Turn valid target IDs or 'all' into two lists:
437 437 (int_ids, uuids).
@@ -440,7 +440,7 b' class Client(HasTraits):'
440 440 # flush notification socket if no engines yet, just in case
441 441 if not self.ids:
442 442 raise error.NoEnginesRegistered("Can't build targets without any engines")
443
443
444 444 if targets is None:
445 445 targets = self._ids
446 446 elif isinstance(targets, basestring):
@@ -454,21 +454,21 b' class Client(HasTraits):'
454 454 if targets not in self._ids:
455 455 raise IndexError("No such engine: %i"%targets)
456 456 targets = [targets]
457
457
458 458 if isinstance(targets, slice):
459 459 indices = range(len(self._ids))[targets]
460 460 ids = self.ids
461 461 targets = [ ids[i] for i in indices ]
462
462
463 463 if not isinstance(targets, (tuple, list, xrange)):
464 464 raise TypeError("targets by int/slice/collection of ints only, not %s"%(type(targets)))
465
465
466 466 return [util.asbytes(self._engines[t]) for t in targets], list(targets)
467
467
468 468 def _connect(self, sshserver, ssh_kwargs, timeout):
469 469 """setup all our socket connections to the cluster. This is called from
470 470 __init__."""
471
471
472 472 # Maybe allow reconnecting?
473 473 if self._connected:
474 474 return
@@ -480,7 +480,7 b' class Client(HasTraits):'
480 480 return tunnel.tunnel_connection(s, url, sshserver, **ssh_kwargs)
481 481 else:
482 482 return s.connect(url)
483
483
484 484 self.session.send(self._query_socket, 'connection_request')
485 485 # use Poller because zmq.select has wrong units in pyzmq 2.1.7
486 486 poller = zmq.Poller()
@@ -527,11 +527,11 b' class Client(HasTraits):'
527 527 else:
528 528 self._connected = False
529 529 raise Exception("Failed to connect!")
530
530
531 531 #--------------------------------------------------------------------------
532 532 # handlers and callbacks for incoming messages
533 533 #--------------------------------------------------------------------------
534
534
535 535 def _unwrap_exception(self, content):
536 536 """unwrap exception, and remap engine_id to int."""
537 537 e = error.unwrap_exception(content)
@@ -541,7 +541,7 b' class Client(HasTraits):'
541 541 eid = self._engines[e_uuid]
542 542 e.engine_info['engine_id'] = eid
543 543 return e
544
544
545 545 def _extract_metadata(self, header, parent, content):
546 546 md = {'msg_id' : parent['msg_id'],
547 547 'received' : datetime.now(),
@@ -550,10 +550,10 b' class Client(HasTraits):'
550 550 'after' : parent.get('after', []),
551 551 'status' : content['status'],
552 552 }
553
553
554 554 if md['engine_uuid'] is not None:
555 555 md['engine_id'] = self._engines.get(md['engine_uuid'], None)
556
556
557 557 if 'date' in parent:
558 558 md['submitted'] = parent['date']
559 559 if 'started' in header:
@@ -561,7 +561,7 b' class Client(HasTraits):'
561 561 if 'date' in header:
562 562 md['completed'] = header['date']
563 563 return md
564
564
565 565 def _register_engine(self, msg):
566 566 """Register a new engine, and update our connection info."""
567 567 content = msg['content']
@@ -576,25 +576,25 b' class Client(HasTraits):'
576 576 if eid in self._ids:
577 577 self._ids.remove(eid)
578 578 uuid = self._engines.pop(eid)
579
579
580 580 self._handle_stranded_msgs(eid, uuid)
581
581
582 582 if self._task_socket and self._task_scheme == 'pure':
583 583 self._stop_scheduling_tasks()
584
584
585 585 def _handle_stranded_msgs(self, eid, uuid):
586 586 """Handle messages known to be on an engine when the engine unregisters.
587
587
588 588 It is possible that this will fire prematurely - that is, an engine will
589 589 go down after completing a result, and the client will be notified
590 590 of the unregistration and later receive the successful result.
591 591 """
592
592
593 593 outstanding = self._outstanding_dict[uuid]
594
594
595 595 for msg_id in list(outstanding):
596 596 if msg_id in self.results:
597 # we already
597 # we already
598 598 continue
599 599 try:
600 600 raise error.EngineError("Engine %r died while running task %r"%(eid, msg_id))
@@ -608,13 +608,13 b' class Client(HasTraits):'
608 608 header['date'] = datetime.now()
609 609 msg = dict(parent_header=parent, header=header, content=content)
610 610 self._handle_apply_reply(msg)
611
611
612 612 def _handle_execute_reply(self, msg):
613 613 """Save the reply to an execute_request into our results.
614
614
615 615 execute messages are never actually used. apply is used instead.
616 616 """
617
617
618 618 parent = msg['parent_header']
619 619 msg_id = parent['msg_id']
620 620 if msg_id not in self.outstanding:
@@ -625,7 +625,7 b' class Client(HasTraits):'
625 625 else:
626 626 self.outstanding.remove(msg_id)
627 627 self.results[msg_id] = self._unwrap_exception(msg['content'])
628
628
629 629 def _handle_apply_reply(self, msg):
630 630 """Save the reply to an apply_request into our results."""
631 631 parent = msg['parent_header']
@@ -641,17 +641,17 b' class Client(HasTraits):'
641 641 self.outstanding.remove(msg_id)
642 642 content = msg['content']
643 643 header = msg['header']
644
644
645 645 # construct metadata:
646 646 md = self.metadata[msg_id]
647 647 md.update(self._extract_metadata(header, parent, content))
648 648 # is this redundant?
649 649 self.metadata[msg_id] = md
650
650
651 651 e_outstanding = self._outstanding_dict[md['engine_uuid']]
652 652 if msg_id in e_outstanding:
653 653 e_outstanding.remove(msg_id)
654
654
655 655 # construct result:
656 656 if content['status'] == 'ok':
657 657 self.results[msg_id] = util.unserialize_object(msg['buffers'])[0]
@@ -662,7 +662,7 b' class Client(HasTraits):'
662 662 pass
663 663 else:
664 664 self.results[msg_id] = self._unwrap_exception(content)
665
665
666 666 def _flush_notifications(self):
667 667 """Flush notifications of engine registrations waiting
668 668 in ZMQ queue."""
@@ -677,7 +677,7 b' class Client(HasTraits):'
677 677 else:
678 678 handler(msg)
679 679 idents,msg = self.session.recv(self._notification_socket, mode=zmq.NOBLOCK)
680
680
681 681 def _flush_results(self, sock):
682 682 """Flush task or queue results waiting in ZMQ queue."""
683 683 idents,msg = self.session.recv(sock, mode=zmq.NOBLOCK)
@@ -691,11 +691,11 b' class Client(HasTraits):'
691 691 else:
692 692 handler(msg)
693 693 idents,msg = self.session.recv(sock, mode=zmq.NOBLOCK)
694
694
695 695 def _flush_control(self, sock):
696 696 """Flush replies from the control channel waiting
697 697 in the ZMQ queue.
698
698
699 699 Currently: ignore them."""
700 700 if self._ignored_control_replies <= 0:
701 701 return
@@ -705,18 +705,18 b' class Client(HasTraits):'
705 705 if self.debug:
706 706 pprint(msg)
707 707 idents,msg = self.session.recv(sock, mode=zmq.NOBLOCK)
708
708
709 709 def _flush_ignored_control(self):
710 710 """flush ignored control replies"""
711 711 while self._ignored_control_replies > 0:
712 712 self.session.recv(self._control_socket)
713 713 self._ignored_control_replies -= 1
714
714
715 715 def _flush_ignored_hub_replies(self):
716 716 ident,msg = self.session.recv(self._query_socket, mode=zmq.NOBLOCK)
717 717 while msg is not None:
718 718 ident,msg = self.session.recv(self._query_socket, mode=zmq.NOBLOCK)
719
719
720 720 def _flush_iopub(self, sock):
721 721 """Flush replies from the iopub channel waiting
722 722 in the ZMQ queue.
@@ -730,10 +730,10 b' class Client(HasTraits):'
730 730 content = msg['content']
731 731 header = msg['header']
732 732 msg_type = msg['header']['msg_type']
733
733
734 734 # init metadata:
735 735 md = self.metadata[msg_id]
736
736
737 737 if msg_type == 'stream':
738 738 name = content['name']
739 739 s = md[name] or ''
@@ -744,40 +744,40 b' class Client(HasTraits):'
744 744 md.update({'pyin' : content['code']})
745 745 else:
746 746 md.update({msg_type : content.get('data', '')})
747
747
748 748 # reduntant?
749 749 self.metadata[msg_id] = md
750
750
751 751 idents,msg = self.session.recv(sock, mode=zmq.NOBLOCK)
752
752
753 753 #--------------------------------------------------------------------------
754 754 # len, getitem
755 755 #--------------------------------------------------------------------------
756
756
757 757 def __len__(self):
758 758 """len(client) returns # of engines."""
759 759 return len(self.ids)
760
760
761 761 def __getitem__(self, key):
762 762 """index access returns DirectView multiplexer objects
763
763
764 764 Must be int, slice, or list/tuple/xrange of ints"""
765 765 if not isinstance(key, (int, slice, tuple, list, xrange)):
766 766 raise TypeError("key by int/slice/iterable of ints only, not %s"%(type(key)))
767 767 else:
768 768 return self.direct_view(key)
769
769
770 770 #--------------------------------------------------------------------------
771 771 # Begin public methods
772 772 #--------------------------------------------------------------------------
773
773
774 774 @property
775 775 def ids(self):
776 776 """Always up-to-date ids property."""
777 777 self._flush_notifications()
778 778 # always copy:
779 779 return list(self._ids)
780
780
781 781 def close(self):
782 782 if self._closed:
783 783 return
@@ -786,7 +786,7 b' class Client(HasTraits):'
786 786 if isinstance(socket, zmq.Socket) and not socket.closed:
787 787 socket.close()
788 788 self._closed = True
789
789
790 790 def spin(self):
791 791 """Flush any registration notifications and execution results
792 792 waiting in the ZMQ queue.
@@ -803,13 +803,13 b' class Client(HasTraits):'
803 803 self._flush_iopub(self._iopub_socket)
804 804 if self._query_socket:
805 805 self._flush_ignored_hub_replies()
806
806
807 807 def wait(self, jobs=None, timeout=-1):
808 808 """waits on one or more `jobs`, for up to `timeout` seconds.
809
809
810 810 Parameters
811 811 ----------
812
812
813 813 jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects
814 814 ints are indices to self.history
815 815 strs are msg_ids
@@ -817,10 +817,10 b' class Client(HasTraits):'
817 817 timeout : float
818 818 a time in seconds, after which to give up.
819 819 default is -1, which means no timeout
820
820
821 821 Returns
822 822 -------
823
823
824 824 True : when all msg_ids are done
825 825 False : timeout reached, some msg_ids still outstanding
826 826 """
@@ -848,11 +848,11 b' class Client(HasTraits):'
848 848 time.sleep(1e-3)
849 849 self.spin()
850 850 return len(theids.intersection(self.outstanding)) == 0
851
851
852 852 #--------------------------------------------------------------------------
853 853 # Control methods
854 854 #--------------------------------------------------------------------------
855
855
856 856 @spin_first
857 857 def clear(self, targets=None, block=None):
858 858 """Clear the namespace in target(s)."""
@@ -873,22 +873,22 b' class Client(HasTraits):'
873 873 self._ignored_control_replies += len(targets)
874 874 if error:
875 875 raise error
876
877
876
877
878 878 @spin_first
879 879 def abort(self, jobs=None, targets=None, block=None):
880 880 """Abort specific jobs from the execution queues of target(s).
881
881
882 882 This is a mechanism to prevent jobs that have already been submitted
883 883 from executing.
884
884
885 885 Parameters
886 886 ----------
887
887
888 888 jobs : msg_id, list of msg_ids, or AsyncResult
889 889 The jobs to be aborted
890
891
890
891
892 892 """
893 893 block = self.block if block is None else block
894 894 targets = self._build_targets(targets)[0]
@@ -905,7 +905,7 b' class Client(HasTraits):'
905 905 msg_ids.append(j)
906 906 content = dict(msg_ids=msg_ids)
907 907 for t in targets:
908 self.session.send(self._control_socket, 'abort_request',
908 self.session.send(self._control_socket, 'abort_request',
909 909 content=content, ident=t)
910 910 error = False
911 911 if block:
@@ -920,7 +920,7 b' class Client(HasTraits):'
920 920 self._ignored_control_replies += len(targets)
921 921 if error:
922 922 raise error
923
923
924 924 @spin_first
925 925 def shutdown(self, targets=None, restart=False, hub=False, block=None):
926 926 """Terminates one or more engine processes, optionally including the hub."""
@@ -929,7 +929,7 b' class Client(HasTraits):'
929 929 targets = 'all'
930 930 targets = self._build_targets(targets)[0]
931 931 for t in targets:
932 self.session.send(self._control_socket, 'shutdown_request',
932 self.session.send(self._control_socket, 'shutdown_request',
933 933 content={'restart':restart},ident=t)
934 934 error = False
935 935 if block or hub:
@@ -942,7 +942,7 b' class Client(HasTraits):'
942 942 error = self._unwrap_exception(msg['content'])
943 943 else:
944 944 self._ignored_control_replies += len(targets)
945
945
946 946 if hub:
947 947 time.sleep(0.25)
948 948 self.session.send(self._query_socket, 'shutdown_request')
@@ -951,34 +951,34 b' class Client(HasTraits):'
951 951 pprint(msg)
952 952 if msg['content']['status'] != 'ok':
953 953 error = self._unwrap_exception(msg['content'])
954
954
955 955 if error:
956 956 raise error
957
957
958 958 #--------------------------------------------------------------------------
959 959 # Execution related methods
960 960 #--------------------------------------------------------------------------
961
961
962 962 def _maybe_raise(self, result):
963 963 """wrapper for maybe raising an exception if apply failed."""
964 964 if isinstance(result, error.RemoteError):
965 965 raise result
966
966
967 967 return result
968
968
969 969 def send_apply_message(self, socket, f, args=None, kwargs=None, subheader=None, track=False,
970 970 ident=None):
971 971 """construct and send an apply message via a socket.
972
972
973 973 This is the principal method with which all engine execution is performed by views.
974 974 """
975
975
976 976 assert not self._closed, "cannot use me anymore, I'm closed!"
977 977 # defaults:
978 978 args = args if args is not None else []
979 979 kwargs = kwargs if kwargs is not None else {}
980 980 subheader = subheader if subheader is not None else {}
981
981
982 982 # validate arguments
983 983 if not callable(f):
984 984 raise TypeError("f must be callable, not %s"%type(f))
@@ -988,12 +988,12 b' class Client(HasTraits):'
988 988 raise TypeError("kwargs must be dict, not %s"%type(kwargs))
989 989 if not isinstance(subheader, dict):
990 990 raise TypeError("subheader must be dict, not %s"%type(subheader))
991
991
992 992 bufs = util.pack_apply_message(f,args,kwargs)
993
993
994 994 msg = self.session.send(socket, "apply_request", buffers=bufs, ident=ident,
995 995 subheader=subheader, track=track)
996
996
997 997 msg_id = msg['header']['msg_id']
998 998 self.outstanding.add(msg_id)
999 999 if ident:
@@ -1005,22 +1005,22 b' class Client(HasTraits):'
1005 1005 self._outstanding_dict[ident].add(msg_id)
1006 1006 self.history.append(msg_id)
1007 1007 self.metadata[msg_id]['submitted'] = datetime.now()
1008
1008
1009 1009 return msg
1010 1010
1011 1011 #--------------------------------------------------------------------------
1012 1012 # construct a View object
1013 1013 #--------------------------------------------------------------------------
1014
1014
1015 1015 def load_balanced_view(self, targets=None):
1016 1016 """construct a DirectView object.
1017
1017
1018 1018 If no arguments are specified, create a LoadBalancedView
1019 1019 using all engines.
1020
1020
1021 1021 Parameters
1022 1022 ----------
1023
1023
1024 1024 targets: list,slice,int,etc. [default: use all engines]
1025 1025 The subset of engines across which to load-balance
1026 1026 """
@@ -1029,16 +1029,16 b' class Client(HasTraits):'
1029 1029 if targets is not None:
1030 1030 targets = self._build_targets(targets)[1]
1031 1031 return LoadBalancedView(client=self, socket=self._task_socket, targets=targets)
1032
1032
1033 1033 def direct_view(self, targets='all'):
1034 1034 """construct a DirectView object.
1035
1035
1036 1036 If no targets are specified, create a DirectView
1037 1037 using all engines.
1038
1038
1039 1039 Parameters
1040 1040 ----------
1041
1041
1042 1042 targets: list,slice,int,etc. [default: use all engines]
1043 1043 The engines to use for the View
1044 1044 """
@@ -1049,56 +1049,56 b' class Client(HasTraits):'
1049 1049 if single:
1050 1050 targets = targets[0]
1051 1051 return DirectView(client=self, socket=self._mux_socket, targets=targets)
1052
1052
1053 1053 #--------------------------------------------------------------------------
1054 1054 # Query methods
1055 1055 #--------------------------------------------------------------------------
1056
1056
1057 1057 @spin_first
1058 1058 def get_result(self, indices_or_msg_ids=None, block=None):
1059 1059 """Retrieve a result by msg_id or history index, wrapped in an AsyncResult object.
1060
1060
1061 1061 If the client already has the results, no request to the Hub will be made.
1062
1062
1063 1063 This is a convenient way to construct AsyncResult objects, which are wrappers
1064 1064 that include metadata about execution, and allow for awaiting results that
1065 1065 were not submitted by this Client.
1066
1066
1067 1067 It can also be a convenient way to retrieve the metadata associated with
1068 1068 blocking execution, since it always retrieves
1069
1069
1070 1070 Examples
1071 1071 --------
1072 1072 ::
1073
1073
1074 1074 In [10]: r = client.apply()
1075
1075
1076 1076 Parameters
1077 1077 ----------
1078
1078
1079 1079 indices_or_msg_ids : integer history index, str msg_id, or list of either
1080 1080 The indices or msg_ids of indices to be retrieved
1081
1081
1082 1082 block : bool
1083 1083 Whether to wait for the result to be done
1084
1084
1085 1085 Returns
1086 1086 -------
1087
1087
1088 1088 AsyncResult
1089 1089 A single AsyncResult object will always be returned.
1090
1090
1091 1091 AsyncHubResult
1092 1092 A subclass of AsyncResult that retrieves results from the Hub
1093
1093
1094 1094 """
1095 1095 block = self.block if block is None else block
1096 1096 if indices_or_msg_ids is None:
1097 1097 indices_or_msg_ids = -1
1098
1098
1099 1099 if not isinstance(indices_or_msg_ids, (list,tuple)):
1100 1100 indices_or_msg_ids = [indices_or_msg_ids]
1101
1101
1102 1102 theids = []
1103 1103 for id in indices_or_msg_ids:
1104 1104 if isinstance(id, int):
@@ -1106,18 +1106,18 b' class Client(HasTraits):'
1106 1106 if not isinstance(id, basestring):
1107 1107 raise TypeError("indices must be str or int, not %r"%id)
1108 1108 theids.append(id)
1109
1109
1110 1110 local_ids = filter(lambda msg_id: msg_id in self.history or msg_id in self.results, theids)
1111 1111 remote_ids = filter(lambda msg_id: msg_id not in local_ids, theids)
1112
1112
1113 1113 if remote_ids:
1114 1114 ar = AsyncHubResult(self, msg_ids=theids)
1115 1115 else:
1116 1116 ar = AsyncResult(self, msg_ids=theids)
1117
1117
1118 1118 if block:
1119 1119 ar.wait()
1120
1120
1121 1121 return ar
1122 1122
1123 1123 @spin_first
@@ -1181,27 +1181,27 b' class Client(HasTraits):'
1181 1181 ar.wait()
1182 1182
1183 1183 return ar
1184
1184
1185 1185 @spin_first
1186 1186 def result_status(self, msg_ids, status_only=True):
1187 1187 """Check on the status of the result(s) of the apply request with `msg_ids`.
1188
1188
1189 1189 If status_only is False, then the actual results will be retrieved, else
1190 1190 only the status of the results will be checked.
1191
1191
1192 1192 Parameters
1193 1193 ----------
1194
1194
1195 1195 msg_ids : list of msg_ids
1196 1196 if int:
1197 1197 Passed as index to self.history for convenience.
1198 1198 status_only : bool (default: True)
1199 1199 if False:
1200 1200 Retrieve the actual results of completed tasks.
1201
1201
1202 1202 Returns
1203 1203 -------
1204
1204
1205 1205 results : dict
1206 1206 There will always be the keys 'pending' and 'completed', which will
1207 1207 be lists of msg_ids that are incomplete or complete. If `status_only`
@@ -1209,7 +1209,7 b' class Client(HasTraits):'
1209 1209 """
1210 1210 if not isinstance(msg_ids, (list,tuple)):
1211 1211 msg_ids = [msg_ids]
1212
1212
1213 1213 theids = []
1214 1214 for msg_id in msg_ids:
1215 1215 if isinstance(msg_id, int):
@@ -1217,17 +1217,17 b' class Client(HasTraits):'
1217 1217 if not isinstance(msg_id, basestring):
1218 1218 raise TypeError("msg_ids must be str, not %r"%msg_id)
1219 1219 theids.append(msg_id)
1220
1220
1221 1221 completed = []
1222 1222 local_results = {}
1223
1223
1224 1224 # comment this block out to temporarily disable local shortcut:
1225 1225 for msg_id in theids:
1226 1226 if msg_id in self.results:
1227 1227 completed.append(msg_id)
1228 1228 local_results[msg_id] = self.results[msg_id]
1229 1229 theids.remove(msg_id)
1230
1230
1231 1231 if theids: # some not locally cached
1232 1232 content = dict(msg_ids=theids, status_only=status_only)
1233 1233 msg = self.session.send(self._query_socket, "result_request", content=content)
@@ -1241,16 +1241,16 b' class Client(HasTraits):'
1241 1241 buffers = msg['buffers']
1242 1242 else:
1243 1243 content = dict(completed=[],pending=[])
1244
1244
1245 1245 content['completed'].extend(completed)
1246
1246
1247 1247 if status_only:
1248 1248 return content
1249
1249
1250 1250 failures = []
1251 1251 # load cached results into result:
1252 1252 content.update(local_results)
1253
1253
1254 1254 # update cache with results:
1255 1255 for msg_id in sorted(theids):
1256 1256 if msg_id in content['completed']:
@@ -1261,34 +1261,34 b' class Client(HasTraits):'
1261 1261 iodict = rec['io']
1262 1262 if isinstance(rcontent, str):
1263 1263 rcontent = self.session.unpack(rcontent)
1264
1264
1265 1265 md = self.metadata[msg_id]
1266 1266 md.update(self._extract_metadata(header, parent, rcontent))
1267 1267 md.update(iodict)
1268
1268
1269 1269 if rcontent['status'] == 'ok':
1270 1270 res,buffers = util.unserialize_object(buffers)
1271 1271 else:
1272 1272 print rcontent
1273 1273 res = self._unwrap_exception(rcontent)
1274 1274 failures.append(res)
1275
1275
1276 1276 self.results[msg_id] = res
1277 1277 content[msg_id] = res
1278
1278
1279 1279 if len(theids) == 1 and failures:
1280 1280 raise failures[0]
1281
1281
1282 1282 error.collect_exceptions(failures, "result_status")
1283 1283 return content
1284 1284
1285 1285 @spin_first
1286 1286 def queue_status(self, targets='all', verbose=False):
1287 1287 """Fetch the status of engine queues.
1288
1288
1289 1289 Parameters
1290 1290 ----------
1291
1291
1292 1292 targets : int/str/list of ints/strs
1293 1293 the engines whose states are to be queried.
1294 1294 default : all
@@ -1310,31 +1310,31 b' class Client(HasTraits):'
1310 1310 return content[targets]
1311 1311 else:
1312 1312 return content
1313
1313
1314 1314 @spin_first
1315 1315 def purge_results(self, jobs=[], targets=[]):
1316 1316 """Tell the Hub to forget results.
1317
1317
1318 1318 Individual results can be purged by msg_id, or the entire
1319 1319 history of specific targets can be purged.
1320
1320
1321 1321 Use `purge_results('all')` to scrub everything from the Hub's db.
1322
1322
1323 1323 Parameters
1324 1324 ----------
1325
1325
1326 1326 jobs : str or list of str or AsyncResult objects
1327 1327 the msg_ids whose results should be forgotten.
1328 1328 targets : int/str/list of ints/strs
1329 1329 The targets, by int_id, whose entire history is to be purged.
1330
1330
1331 1331 default : None
1332 1332 """
1333 1333 if not targets and not jobs:
1334 1334 raise ValueError("Must specify at least one of `targets` and `jobs`")
1335 1335 if targets:
1336 1336 targets = self._build_targets(targets)[1]
1337
1337
1338 1338 # construct msg_ids from jobs
1339 1339 if jobs == 'all':
1340 1340 msg_ids = jobs
@@ -1363,23 +1363,23 b' class Client(HasTraits):'
1363 1363 @spin_first
1364 1364 def hub_history(self):
1365 1365 """Get the Hub's history
1366
1366
1367 1367 Just like the Client, the Hub has a history, which is a list of msg_ids.
1368 1368 This will contain the history of all clients, and, depending on configuration,
1369 1369 may contain history across multiple cluster sessions.
1370
1370
1371 1371 Any msg_id returned here is a valid argument to `get_result`.
1372
1372
1373 1373 Returns
1374 1374 -------
1375
1375
1376 1376 msg_ids : list of strs
1377 1377 list of all msg_ids, ordered by task submission time.
1378 1378 """
1379
1379
1380 1380 self.session.send(self._query_socket, "history_request", content={})
1381 1381 idents, msg = self.session.recv(self._query_socket, 0)
1382
1382
1383 1383 if self.debug:
1384 1384 pprint(msg)
1385 1385 content = msg['content']
@@ -1391,12 +1391,12 b' class Client(HasTraits):'
1391 1391 @spin_first
1392 1392 def db_query(self, query, keys=None):
1393 1393 """Query the Hub's TaskRecord database
1394
1394
1395 1395 This will return a list of task record dicts that match `query`
1396
1396
1397 1397 Parameters
1398 1398 ----------
1399
1399
1400 1400 query : mongodb query dict
1401 1401 The search dict. See mongodb query docs for details.
1402 1402 keys : list of strs [optional]
@@ -1413,9 +1413,9 b' class Client(HasTraits):'
1413 1413 content = msg['content']
1414 1414 if content['status'] != 'ok':
1415 1415 raise self._unwrap_exception(content)
1416
1416
1417 1417 records = content['records']
1418
1418
1419 1419 buffer_lens = content['buffer_lens']
1420 1420 result_buffer_lens = content['result_buffer_lens']
1421 1421 buffers = msg['buffers']
@@ -1429,7 +1429,7 b' class Client(HasTraits):'
1429 1429 if has_rbufs:
1430 1430 blen = result_buffer_lens[i]
1431 1431 rec['result_buffers'], buffers = buffers[:blen],buffers[blen:]
1432
1432
1433 1433 return records
1434 1434
1435 1435 __all__ = [ 'Client' ]
@@ -33,14 +33,14 b' from .asyncresult import AsyncMapResult'
33 33 @skip_doctest
34 34 def remote(view, block=None, **flags):
35 35 """Turn a function into a remote function.
36
36
37 37 This method can be used for map:
38
38
39 39 In [1]: @remote(view,block=True)
40 40 ...: def func(a):
41 41 ...: pass
42 42 """
43
43
44 44 def remote_function(f):
45 45 return RemoteFunction(view, f, block=block, **flags)
46 46 return remote_function
@@ -48,14 +48,14 b' def remote(view, block=None, **flags):'
48 48 @skip_doctest
49 49 def parallel(view, dist='b', block=None, **flags):
50 50 """Turn a function into a parallel remote function.
51
51
52 52 This method can be used for map:
53
53
54 54 In [1]: @parallel(view, block=True)
55 55 ...: def func(a):
56 56 ...: pass
57 57 """
58
58
59 59 def parallel_function(f):
60 60 return ParallelFunction(view, f, dist=dist, block=block, **flags)
61 61 return parallel_function
@@ -66,10 +66,10 b" def parallel(view, dist='b', block=None, **flags):"
66 66
67 67 class RemoteFunction(object):
68 68 """Turn an existing function into a remote function.
69
69
70 70 Parameters
71 71 ----------
72
72
73 73 view : View instance
74 74 The view to be used for execution
75 75 f : callable
@@ -77,37 +77,37 b' class RemoteFunction(object):'
77 77 block : bool [default: None]
78 78 Whether to wait for results or not. The default behavior is
79 79 to use the current `block` attribute of `view`
80
80
81 81 **flags : remaining kwargs are passed to View.temp_flags
82 82 """
83
83
84 84 view = None # the remote connection
85 85 func = None # the wrapped function
86 86 block = None # whether to block
87 87 flags = None # dict of extra kwargs for temp_flags
88
88
89 89 def __init__(self, view, f, block=None, **flags):
90 90 self.view = view
91 91 self.func = f
92 92 self.block=block
93 93 self.flags=flags
94
94
95 95 def __call__(self, *args, **kwargs):
96 96 block = self.view.block if self.block is None else self.block
97 97 with self.view.temp_flags(block=block, **self.flags):
98 98 return self.view.apply(self.func, *args, **kwargs)
99
99
100 100
101 101 class ParallelFunction(RemoteFunction):
102 102 """Class for mapping a function to sequences.
103
103
104 104 This will distribute the sequences according the a mapper, and call
105 105 the function on each sub-sequence. If called via map, then the function
106 106 will be called once on each element, rather that each sub-sequence.
107
107
108 108 Parameters
109 109 ----------
110
110
111 111 view : View instance
112 112 The view to be used for execution
113 113 f : callable
@@ -124,17 +124,17 b' class ParallelFunction(RemoteFunction):'
124 124 The size of chunk to use when breaking up sequences in a load-balanced manner
125 125 **flags : remaining kwargs are passed to View.temp_flags
126 126 """
127
127
128 128 chunksize=None
129 129 mapObject=None
130
130
131 131 def __init__(self, view, f, dist='b', block=None, chunksize=None, **flags):
132 132 super(ParallelFunction, self).__init__(view, f, block=block, **flags)
133 133 self.chunksize = chunksize
134
134
135 135 mapClass = Map.dists[dist]
136 136 self.mapObject = mapClass()
137
137
138 138 def __call__(self, *sequences):
139 139 # check that the length of sequences match
140 140 len_0 = len(sequences[0])
@@ -155,7 +155,7 b' class ParallelFunction(RemoteFunction):'
155 155 # multiplexed:
156 156 targets = self.view.targets
157 157 nparts = len(targets)
158
158
159 159 msg_ids = []
160 160 # my_f = lambda *a: map(self.func, *a)
161 161 client = self.view.client
@@ -169,7 +169,7 b' class ParallelFunction(RemoteFunction):'
169 169 args.append(part)
170 170 if not args:
171 171 continue
172
172
173 173 # print (args)
174 174 if hasattr(self, '_map'):
175 175 if sys.version_info[0] >= 3:
@@ -179,15 +179,15 b' class ParallelFunction(RemoteFunction):'
179 179 args = [self.func]+args
180 180 else:
181 181 f=self.func
182
182
183 183 view = self.view if balanced else client[t]
184 184 with view.temp_flags(block=False, **self.flags):
185 185 ar = view.apply(f, *args)
186
186
187 187 msg_ids.append(ar.msg_ids[0])
188
188
189 189 r = AsyncMapResult(self.view.client, msg_ids, self.mapObject, fname=self.func.__name__)
190
190
191 191 if self.block:
192 192 try:
193 193 return r.get()
@@ -195,9 +195,9 b' class ParallelFunction(RemoteFunction):'
195 195 return r
196 196 else:
197 197 return r
198
198
199 199 def map(self, *sequences):
200 """call a function on each element of a sequence remotely.
200 """call a function on each element of a sequence remotely.
201 201 This should behave very much like the builtin map, but return an AsyncMapResult
202 202 if self.block is False.
203 203 """
@@ -76,56 +76,56 b' def spin_after(f, self, *args, **kwargs):'
76 76 @skip_doctest
77 77 class View(HasTraits):
78 78 """Base View class for more convenint apply(f,*args,**kwargs) syntax via attributes.
79
79
80 80 Don't use this class, use subclasses.
81
81
82 82 Methods
83 83 -------
84
84
85 85 spin
86 86 flushes incoming results and registration state changes
87 87 control methods spin, and requesting `ids` also ensures up to date
88
88
89 89 wait
90 90 wait on one or more msg_ids
91
91
92 92 execution methods
93 93 apply
94 94 legacy: execute, run
95
95
96 96 data movement
97 97 push, pull, scatter, gather
98
98
99 99 query methods
100 100 get_result, queue_status, purge_results, result_status
101
101
102 102 control methods
103 103 abort, shutdown
104
104
105 105 """
106 106 # flags
107 107 block=Bool(False)
108 108 track=Bool(True)
109 109 targets = Any()
110
110
111 111 history=List()
112 112 outstanding = Set()
113 113 results = Dict()
114 114 client = Instance('IPython.parallel.Client')
115
115
116 116 _socket = Instance('zmq.Socket')
117 117 _flag_names = List(['targets', 'block', 'track'])
118 118 _targets = Any()
119 119 _idents = Any()
120
120
121 121 def __init__(self, client=None, socket=None, **flags):
122 122 super(View, self).__init__(client=client, _socket=socket)
123 123 self.block = client.block
124
124
125 125 self.set_flags(**flags)
126
126
127 127 assert not self.__class__ is View, "Don't use base View objects, use subclasses"
128
128
129 129
130 130 def __repr__(self):
131 131 strtargets = str(self.targets)
@@ -135,17 +135,17 b' class View(HasTraits):'
135 135
136 136 def set_flags(self, **kwargs):
137 137 """set my attribute flags by keyword.
138
138
139 139 Views determine behavior with a few attributes (`block`, `track`, etc.).
140 140 These attributes can be set all at once by name with this method.
141
141
142 142 Parameters
143 143 ----------
144
144
145 145 block : bool
146 146 whether to wait for results
147 147 track : bool
148 whether to create a MessageTracker to allow the user to
148 whether to create a MessageTracker to allow the user to
149 149 safely edit after arrays and buffers during non-copying
150 150 sends.
151 151 """
@@ -154,16 +154,16 b' class View(HasTraits):'
154 154 raise KeyError("Invalid name: %r"%name)
155 155 else:
156 156 setattr(self, name, value)
157
157
158 158 @contextmanager
159 159 def temp_flags(self, **kwargs):
160 160 """temporarily set flags, for use in `with` statements.
161
161
162 162 See set_flags for permanent setting of flags
163
163
164 164 Examples
165 165 --------
166
166
167 167 >>> view.track=False
168 168 ...
169 169 >>> with view.temp_flags(track=True):
@@ -171,7 +171,7 b' class View(HasTraits):'
171 171 ... ar.tracker.wait() # wait for send to finish
172 172 >>> view.track
173 173 False
174
174
175 175 """
176 176 # preflight: save flags, and set temporaries
177 177 saved_flags = {}
@@ -184,23 +184,23 b' class View(HasTraits):'
184 184 finally:
185 185 # postflight: restore saved flags
186 186 self.set_flags(**saved_flags)
187
188
187
188
189 189 #----------------------------------------------------------------
190 190 # apply
191 191 #----------------------------------------------------------------
192
192
193 193 @sync_results
194 194 @save_ids
195 195 def _really_apply(self, f, args, kwargs, block=None, **options):
196 196 """wrapper for client.send_apply_message"""
197 197 raise NotImplementedError("Implement in subclasses")
198
198
199 199 def apply(self, f, *args, **kwargs):
200 200 """calls f(*args, **kwargs) on remote engines, returning the result.
201
201
202 202 This method sets all apply flags via this View's attributes.
203
203
204 204 if self.block is False:
205 205 returns AsyncResult
206 206 else:
@@ -210,7 +210,7 b' class View(HasTraits):'
210 210
211 211 def apply_async(self, f, *args, **kwargs):
212 212 """calls f(*args, **kwargs) on remote engines in a nonblocking manner.
213
213
214 214 returns AsyncResult
215 215 """
216 216 return self._really_apply(f, args, kwargs, block=False)
@@ -219,7 +219,7 b' class View(HasTraits):'
219 219 def apply_sync(self, f, *args, **kwargs):
220 220 """calls f(*args, **kwargs) on remote engines in a blocking manner,
221 221 returning the result.
222
222
223 223 returns: actual result of f(*args, **kwargs)
224 224 """
225 225 return self._really_apply(f, args, kwargs, block=True)
@@ -231,14 +231,14 b' class View(HasTraits):'
231 231 def spin(self):
232 232 """spin the client, and sync"""
233 233 self.client.spin()
234
234
235 235 @sync_results
236 236 def wait(self, jobs=None, timeout=-1):
237 237 """waits on one or more `jobs`, for up to `timeout` seconds.
238
238
239 239 Parameters
240 240 ----------
241
241
242 242 jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects
243 243 ints are indices to self.history
244 244 strs are msg_ids
@@ -246,23 +246,23 b' class View(HasTraits):'
246 246 timeout : float
247 247 a time in seconds, after which to give up.
248 248 default is -1, which means no timeout
249
249
250 250 Returns
251 251 -------
252
252
253 253 True : when all msg_ids are done
254 254 False : timeout reached, some msg_ids still outstanding
255 255 """
256 256 if jobs is None:
257 257 jobs = self.history
258 258 return self.client.wait(jobs, timeout)
259
259
260 260 def abort(self, jobs=None, targets=None, block=None):
261 261 """Abort jobs on my engines.
262
262
263 263 Parameters
264 264 ----------
265
265
266 266 jobs : None, str, list of strs, optional
267 267 if None: abort all jobs.
268 268 else: abort specific msg_id(s).
@@ -275,13 +275,13 b' class View(HasTraits):'
275 275 """Fetch the Queue status of my engines"""
276 276 targets = targets if targets is not None else self.targets
277 277 return self.client.queue_status(targets=targets, verbose=verbose)
278
278
279 279 def purge_results(self, jobs=[], targets=[]):
280 280 """Instruct the controller to forget specific results."""
281 281 if targets is None or targets == 'all':
282 282 targets = self.targets
283 283 return self.client.purge_results(jobs=jobs, targets=targets)
284
284
285 285 def shutdown(self, targets=None, restart=False, hub=False, block=None):
286 286 """Terminates one or more engine processes, optionally including the hub.
287 287 """
@@ -289,15 +289,15 b' class View(HasTraits):'
289 289 if targets is None or targets == 'all':
290 290 targets = self.targets
291 291 return self.client.shutdown(targets=targets, restart=restart, hub=hub, block=block)
292
292
293 293 @spin_after
294 294 def get_result(self, indices_or_msg_ids=None):
295 295 """return one or more results, specified by history index or msg_id.
296
296
297 297 See client.get_result for details.
298
298
299 299 """
300
300
301 301 if indices_or_msg_ids is None:
302 302 indices_or_msg_ids = -1
303 303 if isinstance(indices_or_msg_ids, int):
@@ -308,57 +308,57 b' class View(HasTraits):'
308 308 if isinstance(index, int):
309 309 indices_or_msg_ids[i] = self.history[index]
310 310 return self.client.get_result(indices_or_msg_ids)
311
311
312 312 #-------------------------------------------------------------------
313 313 # Map
314 314 #-------------------------------------------------------------------
315
315
316 316 def map(self, f, *sequences, **kwargs):
317 317 """override in subclasses"""
318 318 raise NotImplementedError
319
319
320 320 def map_async(self, f, *sequences, **kwargs):
321 321 """Parallel version of builtin `map`, using this view's engines.
322
322
323 323 This is equivalent to map(...block=False)
324
324
325 325 See `self.map` for details.
326 326 """
327 327 if 'block' in kwargs:
328 328 raise TypeError("map_async doesn't take a `block` keyword argument.")
329 329 kwargs['block'] = False
330 330 return self.map(f,*sequences,**kwargs)
331
331
332 332 def map_sync(self, f, *sequences, **kwargs):
333 333 """Parallel version of builtin `map`, using this view's engines.
334
334
335 335 This is equivalent to map(...block=True)
336
336
337 337 See `self.map` for details.
338 338 """
339 339 if 'block' in kwargs:
340 340 raise TypeError("map_sync doesn't take a `block` keyword argument.")
341 341 kwargs['block'] = True
342 342 return self.map(f,*sequences,**kwargs)
343
343
344 344 def imap(self, f, *sequences, **kwargs):
345 345 """Parallel version of `itertools.imap`.
346
346
347 347 See `self.map` for details.
348
348
349 349 """
350
350
351 351 return iter(self.map_async(f,*sequences, **kwargs))
352
352
353 353 #-------------------------------------------------------------------
354 354 # Decorators
355 355 #-------------------------------------------------------------------
356
356
357 357 def remote(self, block=True, **flags):
358 358 """Decorator for making a RemoteFunction"""
359 359 block = self.block if block is None else block
360 360 return remote(self, block=block, **flags)
361
361
362 362 def parallel(self, dist='b', block=None, **flags):
363 363 """Decorator for making a ParallelFunction"""
364 364 block = self.block if block is None else block
@@ -367,45 +367,45 b' class View(HasTraits):'
367 367 @skip_doctest
368 368 class DirectView(View):
369 369 """Direct Multiplexer View of one or more engines.
370
370
371 371 These are created via indexed access to a client:
372
372
373 373 >>> dv_1 = client[1]
374 374 >>> dv_all = client[:]
375 375 >>> dv_even = client[::2]
376 376 >>> dv_some = client[1:3]
377
377
378 378 This object provides dictionary access to engine namespaces:
379
379
380 380 # push a=5:
381 >>> dv['a'] = 5
381 >>> dv['a'] = 5
382 382 # pull 'foo':
383 383 >>> db['foo']
384
384
385 385 """
386
386
387 387 def __init__(self, client=None, socket=None, targets=None):
388 388 super(DirectView, self).__init__(client=client, socket=socket, targets=targets)
389
389
390 390 @property
391 391 def importer(self):
392 392 """sync_imports(local=True) as a property.
393
393
394 394 See sync_imports for details.
395
395
396 396 """
397 397 return self.sync_imports(True)
398
398
399 399 @contextmanager
400 400 def sync_imports(self, local=True):
401 401 """Context Manager for performing simultaneous local and remote imports.
402
402
403 403 'import x as y' will *not* work. The 'as y' part will simply be ignored.
404
404
405 405 >>> with view.sync_imports():
406 406 ... from numpy import recarray
407 407 importing recarray from numpy on engine(s)
408
408
409 409 """
410 410 import __builtin__
411 411 local_import = __builtin__.__import__
@@ -424,7 +424,7 b' class DirectView(View):'
424 424 user_ns[key] = getattr(mod, key)
425 425 else:
426 426 user_ns[name] = sys.modules[name]
427
427
428 428 def view_import(name, globals={}, locals={}, fromlist=[], level=-1):
429 429 """the drop-in replacement for __import__, that optionally imports
430 430 locally as well.
@@ -432,19 +432,19 b' class DirectView(View):'
432 432 # don't override nested imports
433 433 save_import = __builtin__.__import__
434 434 __builtin__.__import__ = local_import
435
435
436 436 if imp.lock_held():
437 437 # this is a side-effect import, don't do it remotely, or even
438 438 # ignore the local effects
439 439 return local_import(name, globals, locals, fromlist, level)
440
440
441 441 imp.acquire_lock()
442 442 if local:
443 443 mod = local_import(name, globals, locals, fromlist, level)
444 444 else:
445 445 raise NotImplementedError("remote-only imports not yet implemented")
446 446 imp.release_lock()
447
447
448 448 key = name+':'+','.join(fromlist or [])
449 449 if level == -1 and key not in modules:
450 450 modules.add(key)
@@ -455,9 +455,9 b' class DirectView(View):'
455 455 results.append(self.apply_async(remote_import, name, fromlist, level))
456 456 # restore override
457 457 __builtin__.__import__ = save_import
458
458
459 459 return mod
460
460
461 461 # override __import__
462 462 __builtin__.__import__ = view_import
463 463 try:
@@ -470,38 +470,38 b' class DirectView(View):'
470 470 finally:
471 471 # always restore __import__
472 472 __builtin__.__import__ = local_import
473
473
474 474 for r in results:
475 475 # raise possible remote ImportErrors here
476 476 r.get()
477
478
477
478
479 479 @sync_results
480 480 @save_ids
481 481 def _really_apply(self, f, args=None, kwargs=None, targets=None, block=None, track=None):
482 482 """calls f(*args, **kwargs) on remote engines, returning the result.
483
483
484 484 This method sets all of `apply`'s flags via this View's attributes.
485
485
486 486 Parameters
487 487 ----------
488
488
489 489 f : callable
490
490
491 491 args : list [default: empty]
492
492
493 493 kwargs : dict [default: empty]
494
494
495 495 targets : target list [default: self.targets]
496 496 where to run
497 497 block : bool [default: self.block]
498 whether to block
498 whether to block
499 499 track : bool [default: self.track]
500 500 whether to ask zmq to track the message, for safe non-copying sends
501
501
502 502 Returns
503 503 -------
504
504
505 505 if self.block is False:
506 506 returns AsyncResult
507 507 else:
@@ -514,7 +514,7 b' class DirectView(View):'
514 514 block = self.block if block is None else block
515 515 track = self.track if track is None else track
516 516 targets = self.targets if targets is None else targets
517
517
518 518 _idents = self.client._build_targets(targets)[0]
519 519 msg_ids = []
520 520 trackers = []
@@ -532,31 +532,31 b' class DirectView(View):'
532 532 except KeyboardInterrupt:
533 533 pass
534 534 return ar
535
535
536 536 @spin_after
537 537 def map(self, f, *sequences, **kwargs):
538 538 """view.map(f, *sequences, block=self.block) => list|AsyncMapResult
539
539
540 540 Parallel version of builtin `map`, using this View's `targets`.
541
541
542 542 There will be one task per target, so work will be chunked
543 if the sequences are longer than `targets`.
544
543 if the sequences are longer than `targets`.
544
545 545 Results can be iterated as they are ready, but will become available in chunks.
546
546
547 547 Parameters
548 548 ----------
549
549
550 550 f : callable
551 551 function to be mapped
552 552 *sequences: one or more sequences of matching length
553 553 the sequences to be distributed and passed to `f`
554 554 block : bool
555 555 whether to wait for the result or not [default self.block]
556
556
557 557 Returns
558 558 -------
559
559
560 560 if block=False:
561 561 AsyncMapResult
562 562 An object like AsyncResult, but which reassembles the sequence of results
@@ -566,24 +566,24 b' class DirectView(View):'
566 566 list
567 567 the result of map(f,*sequences)
568 568 """
569
569
570 570 block = kwargs.pop('block', self.block)
571 571 for k in kwargs.keys():
572 572 if k not in ['block', 'track']:
573 573 raise TypeError("invalid keyword arg, %r"%k)
574
574
575 575 assert len(sequences) > 0, "must have some sequences to map onto!"
576 576 pf = ParallelFunction(self, f, block=block, **kwargs)
577 577 return pf.map(*sequences)
578
578
579 579 def execute(self, code, targets=None, block=None):
580 580 """Executes `code` on `targets` in blocking or nonblocking manner.
581
581
582 582 ``execute`` is always `bound` (affects engine namespace)
583
583
584 584 Parameters
585 585 ----------
586
586
587 587 code : str
588 588 the code string to be executed
589 589 block : bool
@@ -591,15 +591,15 b' class DirectView(View):'
591 591 default: self.block
592 592 """
593 593 return self._really_apply(util._execute, args=(code,), block=block, targets=targets)
594
594
595 595 def run(self, filename, targets=None, block=None):
596 """Execute contents of `filename` on my engine(s).
597
596 """Execute contents of `filename` on my engine(s).
597
598 598 This simply reads the contents of the file and calls `execute`.
599
599
600 600 Parameters
601 601 ----------
602
602
603 603 filename : str
604 604 The path to the file
605 605 targets : int/str/list of ints/strs
@@ -608,34 +608,34 b' class DirectView(View):'
608 608 block : bool
609 609 whether or not to wait until done
610 610 default: self.block
611
611
612 612 """
613 613 with open(filename, 'r') as f:
614 614 # add newline in case of trailing indented whitespace
615 615 # which will cause SyntaxError
616 616 code = f.read()+'\n'
617 617 return self.execute(code, block=block, targets=targets)
618
618
619 619 def update(self, ns):
620 620 """update remote namespace with dict `ns`
621
621
622 622 See `push` for details.
623 623 """
624 624 return self.push(ns, block=self.block, track=self.track)
625
625
626 626 def push(self, ns, targets=None, block=None, track=None):
627 627 """update remote namespace with dict `ns`
628
628
629 629 Parameters
630 630 ----------
631
631
632 632 ns : dict
633 633 dict of keys with which to update engine namespace(s)
634 634 block : bool [default : self.block]
635 635 whether to wait to be notified of engine receipt
636
636
637 637 """
638
638
639 639 block = block if block is not None else self.block
640 640 track = track if track is not None else self.track
641 641 targets = targets if targets is not None else self.targets
@@ -646,15 +646,15 b' class DirectView(View):'
646 646
647 647 def get(self, key_s):
648 648 """get object(s) by `key_s` from remote namespace
649
649
650 650 see `pull` for details.
651 651 """
652 652 # block = block if block is not None else self.block
653 653 return self.pull(key_s, block=True)
654
654
655 655 def pull(self, names, targets=None, block=None):
656 656 """get object(s) by `name` from remote namespace
657
657
658 658 will return one object if it is a key.
659 659 can also take a list of keys, in which case it will return a list of objects.
660 660 """
@@ -670,7 +670,7 b' class DirectView(View):'
670 670 else:
671 671 raise TypeError("names must be strs, not %r"%names)
672 672 return self._really_apply(util._pull, (names,), block=block, targets=targets)
673
673
674 674 def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None, track=None):
675 675 """
676 676 Partition a Python sequence and send the partitions to a set of engines.
@@ -678,7 +678,7 b' class DirectView(View):'
678 678 block = block if block is not None else self.block
679 679 track = track if track is not None else self.track
680 680 targets = targets if targets is not None else self.targets
681
681
682 682 mapObject = Map.dists[dist]()
683 683 nparts = len(targets)
684 684 msg_ids = []
@@ -693,18 +693,18 b' class DirectView(View):'
693 693 msg_ids.extend(r.msg_ids)
694 694 if track:
695 695 trackers.append(r._tracker)
696
696
697 697 if track:
698 698 tracker = zmq.MessageTracker(*trackers)
699 699 else:
700 700 tracker = None
701
701
702 702 r = AsyncResult(self.client, msg_ids, fname='scatter', targets=targets, tracker=tracker)
703 703 if block:
704 704 r.wait()
705 705 else:
706 706 return r
707
707
708 708 @sync_results
709 709 @save_ids
710 710 def gather(self, key, dist='b', targets=None, block=None):
@@ -715,53 +715,53 b' class DirectView(View):'
715 715 targets = targets if targets is not None else self.targets
716 716 mapObject = Map.dists[dist]()
717 717 msg_ids = []
718
718
719 719 for index, engineid in enumerate(targets):
720 720 msg_ids.extend(self.pull(key, block=False, targets=engineid).msg_ids)
721
721
722 722 r = AsyncMapResult(self.client, msg_ids, mapObject, fname='gather')
723
723
724 724 if block:
725 725 try:
726 726 return r.get()
727 727 except KeyboardInterrupt:
728 728 pass
729 729 return r
730
730
731 731 def __getitem__(self, key):
732 732 return self.get(key)
733
733
734 734 def __setitem__(self,key, value):
735 735 self.update({key:value})
736
736
737 737 def clear(self, targets=None, block=False):
738 738 """Clear the remote namespaces on my engines."""
739 739 block = block if block is not None else self.block
740 740 targets = targets if targets is not None else self.targets
741 741 return self.client.clear(targets=targets, block=block)
742
742
743 743 def kill(self, targets=None, block=True):
744 744 """Kill my engines."""
745 745 block = block if block is not None else self.block
746 746 targets = targets if targets is not None else self.targets
747 747 return self.client.kill(targets=targets, block=block)
748
748
749 749 #----------------------------------------
750 750 # activate for %px,%autopx magics
751 751 #----------------------------------------
752 752 def activate(self):
753 753 """Make this `View` active for parallel magic commands.
754
754
755 755 IPython has a magic command syntax to work with `MultiEngineClient` objects.
756 756 In a given IPython session there is a single active one. While
757 there can be many `Views` created and used by the user,
758 there is only one active one. The active `View` is used whenever
757 there can be many `Views` created and used by the user,
758 there is only one active one. The active `View` is used whenever
759 759 the magic commands %px and %autopx are used.
760
761 The activate() method is called on a given `View` to make it
760
761 The activate() method is called on a given `View` to make it
762 762 active. Once this has been done, the magic commands can be used.
763 763 """
764
764
765 765 try:
766 766 # This is injected into __builtins__.
767 767 ip = get_ipython()
@@ -779,34 +779,34 b' class DirectView(View):'
779 779 @skip_doctest
780 780 class LoadBalancedView(View):
781 781 """An load-balancing View that only executes via the Task scheduler.
782
782
783 783 Load-balanced views can be created with the client's `view` method:
784
784
785 785 >>> v = client.load_balanced_view()
786
786
787 787 or targets can be specified, to restrict the potential destinations:
788
788
789 789 >>> v = client.client.load_balanced_view(([1,3])
790
790
791 791 which would restrict loadbalancing to between engines 1 and 3.
792
792
793 793 """
794
794
795 795 follow=Any()
796 796 after=Any()
797 797 timeout=CFloat()
798 798 retries = CInt(0)
799
799
800 800 _task_scheme = Any()
801 801 _flag_names = List(['targets', 'block', 'track', 'follow', 'after', 'timeout', 'retries'])
802
802
803 803 def __init__(self, client=None, socket=None, **flags):
804 804 super(LoadBalancedView, self).__init__(client=client, socket=socket, **flags)
805 805 self._task_scheme=client._task_scheme
806
806
807 807 def _validate_dependency(self, dep):
808 808 """validate a dependency.
809
809
810 810 For use in `set_flags`.
811 811 """
812 812 if dep is None or isinstance(dep, (basestring, AsyncResult, Dependency)):
@@ -825,9 +825,9 b' class LoadBalancedView(View):'
825 825 return False
826 826 else:
827 827 return False
828
828
829 829 return True
830
830
831 831 def _render_dependency(self, dep):
832 832 """helper for building jsonable dependencies from various input forms."""
833 833 if isinstance(dep, Dependency):
@@ -842,18 +842,18 b' class LoadBalancedView(View):'
842 842
843 843 def set_flags(self, **kwargs):
844 844 """set my attribute flags by keyword.
845
845
846 846 A View is a wrapper for the Client's apply method, but with attributes
847 847 that specify keyword arguments, those attributes can be set by keyword
848 848 argument with this method.
849
849
850 850 Parameters
851 851 ----------
852
852
853 853 block : bool
854 854 whether to wait for results
855 855 track : bool
856 whether to create a MessageTracker to allow the user to
856 whether to create a MessageTracker to allow the user to
857 857 safely edit after arrays and buffers during non-copying
858 858 sends.
859 859
@@ -878,7 +878,7 b' class LoadBalancedView(View):'
878 878 retries : int
879 879 Number of times a task will be retried on failure.
880 880 """
881
881
882 882 super(LoadBalancedView, self).set_flags(**kwargs)
883 883 for name in ('follow', 'after'):
884 884 if name in kwargs:
@@ -895,35 +895,35 b' class LoadBalancedView(View):'
895 895 if t < 0:
896 896 raise ValueError("Invalid timeout: %s"%t)
897 897 self.timeout = t
898
898
899 899 @sync_results
900 900 @save_ids
901 901 def _really_apply(self, f, args=None, kwargs=None, block=None, track=None,
902 902 after=None, follow=None, timeout=None,
903 903 targets=None, retries=None):
904 904 """calls f(*args, **kwargs) on a remote engine, returning the result.
905
905
906 906 This method temporarily sets all of `apply`'s flags for a single call.
907
907
908 908 Parameters
909 909 ----------
910
910
911 911 f : callable
912
912
913 913 args : list [default: empty]
914
914
915 915 kwargs : dict [default: empty]
916
916
917 917 block : bool [default: self.block]
918 whether to block
918 whether to block
919 919 track : bool [default: self.track]
920 920 whether to ask zmq to track the message, for safe non-copying sends
921
921
922 922 !!!!!! TODO: THE REST HERE !!!!
923
923
924 924 Returns
925 925 -------
926
926
927 927 if self.block is False:
928 928 returns AsyncResult
929 929 else:
@@ -939,7 +939,7 b' class LoadBalancedView(View):'
939 939 msg += " because the pure ZMQ scheduler cannot handle"
940 940 msg += " disappearing engines."
941 941 raise RuntimeError(msg)
942
942
943 943 if self._task_scheme == 'pure':
944 944 # pure zmq scheme doesn't support extra features
945 945 msg = "Pure ZMQ scheduler doesn't support the following flags:"
@@ -950,7 +950,7 b' class LoadBalancedView(View):'
950 950 if isinstance(f, dependent):
951 951 # soft warn on functional dependencies
952 952 warnings.warn(msg, RuntimeWarning)
953
953
954 954 # build args
955 955 args = [] if args is None else args
956 956 kwargs = {} if kwargs is None else kwargs
@@ -961,7 +961,7 b' class LoadBalancedView(View):'
961 961 follow = self.follow if follow is None else follow
962 962 timeout = self.timeout if timeout is None else timeout
963 963 targets = self.targets if targets is None else targets
964
964
965 965 if not isinstance(retries, int):
966 966 raise TypeError('retries must be int, not %r'%type(retries))
967 967
@@ -971,40 +971,40 b' class LoadBalancedView(View):'
971 971 idents = self.client._build_targets(targets)[0]
972 972 # ensure *not* bytes
973 973 idents = [ ident.decode() for ident in idents ]
974
974
975 975 after = self._render_dependency(after)
976 976 follow = self._render_dependency(follow)
977 977 subheader = dict(after=after, follow=follow, timeout=timeout, targets=idents, retries=retries)
978
978
979 979 msg = self.client.send_apply_message(self._socket, f, args, kwargs, track=track,
980 980 subheader=subheader)
981 981 tracker = None if track is False else msg['tracker']
982
982
983 983 ar = AsyncResult(self.client, msg['header']['msg_id'], fname=f.__name__, targets=None, tracker=tracker)
984
984
985 985 if block:
986 986 try:
987 987 return ar.get()
988 988 except KeyboardInterrupt:
989 989 pass
990 990 return ar
991
991
992 992 @spin_after
993 993 @save_ids
994 994 def map(self, f, *sequences, **kwargs):
995 995 """view.map(f, *sequences, block=self.block, chunksize=1) => list|AsyncMapResult
996
996
997 997 Parallel version of builtin `map`, load-balanced by this View.
998
998
999 999 `block`, and `chunksize` can be specified by keyword only.
1000
1000
1001 1001 Each `chunksize` elements will be a separate task, and will be
1002 1002 load-balanced. This lets individual elements be available for iteration
1003 1003 as soon as they arrive.
1004
1004
1005 1005 Parameters
1006 1006 ----------
1007
1007
1008 1008 f : callable
1009 1009 function to be mapped
1010 1010 *sequences: one or more sequences of matching length
@@ -1012,15 +1012,15 b' class LoadBalancedView(View):'
1012 1012 block : bool
1013 1013 whether to wait for the result or not [default self.block]
1014 1014 track : bool
1015 whether to create a MessageTracker to allow the user to
1015 whether to create a MessageTracker to allow the user to
1016 1016 safely edit after arrays and buffers during non-copying
1017 1017 sends.
1018 1018 chunksize : int
1019 1019 how many elements should be in each task [default 1]
1020
1020
1021 1021 Returns
1022 1022 -------
1023
1023
1024 1024 if block=False:
1025 1025 AsyncMapResult
1026 1026 An object like AsyncResult, but which reassembles the sequence of results
@@ -1028,20 +1028,20 b' class LoadBalancedView(View):'
1028 1028 results are complete.
1029 1029 else:
1030 1030 the result of map(f,*sequences)
1031
1031
1032 1032 """
1033
1033
1034 1034 # default
1035 1035 block = kwargs.get('block', self.block)
1036 1036 chunksize = kwargs.get('chunksize', 1)
1037
1037
1038 1038 keyset = set(kwargs.keys())
1039 1039 extra_keys = keyset.difference_update(set(['block', 'chunksize']))
1040 1040 if extra_keys:
1041 1041 raise TypeError("Invalid kwargs: %s"%list(extra_keys))
1042
1042
1043 1043 assert len(sequences) > 0, "must have some sequences to map onto!"
1044
1044
1045 1045 pf = ParallelFunction(self, f, block=block, chunksize=chunksize)
1046 1046 return pf.map(*sequences)
1047 1047
@@ -1,4 +1,4 b''
1 """A Task logger that presents our DB interface,
1 """A Task logger that presents our DB interface,
2 2 but exists entirely in memory and implemented with dicts.
3 3
4 4 Authors:
@@ -70,7 +70,7 b' filters = {'
70 70
71 71 class CompositeFilter(object):
72 72 """Composite filter for matching multiple properties."""
73
73
74 74 def __init__(self, dikt):
75 75 self.tests = []
76 76 self.values = []
@@ -91,23 +91,23 b' class BaseDB(LoggingConfigurable):'
91 91
92 92 class DictDB(BaseDB):
93 93 """Basic in-memory dict-based object for saving Task Records.
94
94
95 95 This is the first object to present the DB interface
96 96 for logging tasks out of memory.
97
97
98 98 The interface is based on MongoDB, so adding a MongoDB
99 99 backend should be straightforward.
100 100 """
101
101
102 102 _records = Dict()
103
103
104 104 def _match_one(self, rec, tests):
105 105 """Check if a specific record matches tests."""
106 106 for key,test in tests.iteritems():
107 107 if not test(rec.get(key, None)):
108 108 return False
109 109 return True
110
110
111 111 def _match(self, check):
112 112 """Find all the matches for a check dict."""
113 113 matches = []
@@ -117,12 +117,12 b' class DictDB(BaseDB):'
117 117 tests[k] = CompositeFilter(v)
118 118 else:
119 119 tests[k] = lambda o: o==v
120
120
121 121 for rec in self._records.itervalues():
122 122 if self._match_one(rec, tests):
123 123 matches.append(rec)
124 124 return matches
125
125
126 126 def _extract_subdict(self, rec, keys):
127 127 """extract subdict of keys"""
128 128 d = {}
@@ -130,42 +130,42 b' class DictDB(BaseDB):'
130 130 for key in keys:
131 131 d[key] = rec[key]
132 132 return d
133
133
134 134 def add_record(self, msg_id, rec):
135 135 """Add a new Task Record, by msg_id."""
136 136 if self._records.has_key(msg_id):
137 137 raise KeyError("Already have msg_id %r"%(msg_id))
138 138 self._records[msg_id] = rec
139
139
140 140 def get_record(self, msg_id):
141 141 """Get a specific Task Record, by msg_id."""
142 142 if not self._records.has_key(msg_id):
143 143 raise KeyError("No such msg_id %r"%(msg_id))
144 144 return self._records[msg_id]
145
145
146 146 def update_record(self, msg_id, rec):
147 147 """Update the data in an existing record."""
148 148 self._records[msg_id].update(rec)
149
149
150 150 def drop_matching_records(self, check):
151 151 """Remove a record from the DB."""
152 152 matches = self._match(check)
153 153 for m in matches:
154 154 del self._records[m['msg_id']]
155
155
156 156 def drop_record(self, msg_id):
157 157 """Remove a record from the DB."""
158 158 del self._records[msg_id]
159
160
159
160
161 161 def find_records(self, check, keys=None):
162 162 """Find records matching a query dict, optionally extracting subset of keys.
163
163
164 164 Returns dict keyed by msg_id of matching records.
165
165
166 166 Parameters
167 167 ----------
168
168
169 169 check: dict
170 170 mongodb-style query argument
171 171 keys: list of strs [optional]
@@ -177,8 +177,8 b' class DictDB(BaseDB):'
177 177 return [ self._extract_subdict(rec, keys) for rec in matches ]
178 178 else:
179 179 return matches
180
181
180
181
182 182 def get_history(self):
183 183 """get all msg_ids, ordered by time submitted."""
184 184 msg_ids = self._records.keys()
@@ -31,10 +31,10 b' class Heart(object):'
31 31 """A basic heart object for responding to a HeartMonitor.
32 32 This is a simple wrapper with defaults for the most common
33 33 Device model for responding to heartbeats.
34
35 It simply builds a threadsafe zmq.FORWARDER Device, defaulting to using
34
35 It simply builds a threadsafe zmq.FORWARDER Device, defaulting to using
36 36 SUB/XREQ for in/out.
37
37
38 38 You can specify the XREQ's IDENTITY via the optional heart_id argument."""
39 39 device=None
40 40 id=None
@@ -49,27 +49,27 b' class Heart(object):'
49 49 heart_id = uuid.uuid4().bytes
50 50 self.device.setsockopt_out(zmq.IDENTITY, heart_id)
51 51 self.id = heart_id
52
52
53 53 def start(self):
54 54 return self.device.start()
55
55
56 56 class HeartMonitor(LoggingConfigurable):
57 57 """A basic HeartMonitor class
58 58 pingstream: a PUB stream
59 59 pongstream: an XREP stream
60 60 period: the period of the heartbeat in milliseconds"""
61
61
62 62 period=CFloat(1000, config=True,
63 63 help='The frequency at which the Hub pings the engines for heartbeats '
64 64 ' (in ms) [default: 100]',
65 65 )
66
66
67 67 pingstream=Instance('zmq.eventloop.zmqstream.ZMQStream')
68 68 pongstream=Instance('zmq.eventloop.zmqstream.ZMQStream')
69 69 loop = Instance('zmq.eventloop.ioloop.IOLoop')
70 70 def _loop_default(self):
71 71 return ioloop.IOLoop.instance()
72
72
73 73 # not settable:
74 74 hearts=Set()
75 75 responses=Set()
@@ -79,30 +79,30 b' class HeartMonitor(LoggingConfigurable):'
79 79 _failure_handlers = Set()
80 80 lifetime = CFloat(0)
81 81 tic = CFloat(0)
82
82
83 83 def __init__(self, **kwargs):
84 84 super(HeartMonitor, self).__init__(**kwargs)
85
85
86 86 self.pongstream.on_recv(self.handle_pong)
87
87
88 88 def start(self):
89 89 self.caller = ioloop.PeriodicCallback(self.beat, self.period, self.loop)
90 90 self.caller.start()
91
91
92 92 def add_new_heart_handler(self, handler):
93 93 """add a new handler for new hearts"""
94 94 self.log.debug("heartbeat::new_heart_handler: %s"%handler)
95 95 self._new_handlers.add(handler)
96
96
97 97 def add_heart_failure_handler(self, handler):
98 98 """add a new handler for heart failure"""
99 99 self.log.debug("heartbeat::new heart failure handler: %s"%handler)
100 100 self._failure_handlers.add(handler)
101
101
102 102 def beat(self):
103 self.pongstream.flush()
103 self.pongstream.flush()
104 104 self.last_ping = self.lifetime
105
105
106 106 toc = time.time()
107 107 self.lifetime += toc-self.tic
108 108 self.tic = toc
@@ -118,7 +118,7 b' class HeartMonitor(LoggingConfigurable):'
118 118 # print self.on_probation, self.hearts
119 119 # self.log.debug("heartbeat::beat %.3f, %i beating hearts"%(self.lifetime, len(self.hearts)))
120 120 self.pingstream.send(asbytes(str(self.lifetime)))
121
121
122 122 def handle_new_heart(self, heart):
123 123 if self._new_handlers:
124 124 for handler in self._new_handlers:
@@ -126,7 +126,7 b' class HeartMonitor(LoggingConfigurable):'
126 126 else:
127 127 self.log.info("heartbeat::yay, got new heart %s!"%heart)
128 128 self.hearts.add(heart)
129
129
130 130 def handle_heart_failure(self, heart):
131 131 if self._failure_handlers:
132 132 for handler in self._failure_handlers:
@@ -138,8 +138,8 b' class HeartMonitor(LoggingConfigurable):'
138 138 else:
139 139 self.log.info("heartbeat::Heart %s failed :("%heart)
140 140 self.hearts.remove(heart)
141
142
141
142
143 143 def handle_pong(self, msg):
144 144 "a heart just beat"
145 145 current = asbytes(str(self.lifetime))
@@ -164,10 +164,10 b" if __name__ == '__main__':"
164 164 pub.bind('tcp://127.0.0.1:5555')
165 165 xrep = context.socket(zmq.ROUTER)
166 166 xrep.bind('tcp://127.0.0.1:5556')
167
167
168 168 outstream = zmqstream.ZMQStream(pub, loop)
169 169 instream = zmqstream.ZMQStream(xrep, loop)
170
170
171 171 hb = HeartMonitor(loop, outstream, instream)
172
172
173 173 loop.start()
@@ -73,7 +73,7 b' def empty_record():'
73 73 'stdout': '',
74 74 'stderr': '',
75 75 }
76
76
77 77 def init_record(msg):
78 78 """Initialize a TaskRecord based on a request."""
79 79 header = msg['header']
@@ -118,7 +118,7 b' class EngineConnector(HasTraits):'
118 118
119 119 class HubFactory(RegistrationFactory):
120 120 """The Configurable for setting up a Hub."""
121
121
122 122 # port-pairs for monitoredqueues:
123 123 hb = Tuple(Int,Int,config=True,
124 124 help="""XREQ/SUB Port pair for Engine heartbeats""")
@@ -127,10 +127,10 b' class HubFactory(RegistrationFactory):'
127 127
128 128 mux = Tuple(Int,Int,config=True,
129 129 help="""Engine/Client Port pair for MUX queue""")
130
130
131 131 def _mux_default(self):
132 132 return tuple(util.select_random_ports(2))
133
133
134 134 task = Tuple(Int,Int,config=True,
135 135 help="""Engine/Client Port pair for Task queue""")
136 136 def _task_default(self):
@@ -138,88 +138,88 b' class HubFactory(RegistrationFactory):'
138 138
139 139 control = Tuple(Int,Int,config=True,
140 140 help="""Engine/Client Port pair for Control queue""")
141
141
142 142 def _control_default(self):
143 143 return tuple(util.select_random_ports(2))
144 144
145 145 iopub = Tuple(Int,Int,config=True,
146 146 help="""Engine/Client Port pair for IOPub relay""")
147
147
148 148 def _iopub_default(self):
149 149 return tuple(util.select_random_ports(2))
150
150
151 151 # single ports:
152 152 mon_port = Int(config=True,
153 153 help="""Monitor (SUB) port for queue traffic""")
154 154
155 155 def _mon_port_default(self):
156 156 return util.select_random_ports(1)[0]
157
157
158 158 notifier_port = Int(config=True,
159 159 help="""PUB port for sending engine status notifications""")
160 160
161 161 def _notifier_port_default(self):
162 162 return util.select_random_ports(1)[0]
163
163
164 164 engine_ip = Unicode('127.0.0.1', config=True,
165 165 help="IP on which to listen for engine connections. [default: loopback]")
166 166 engine_transport = Unicode('tcp', config=True,
167 167 help="0MQ transport for engine connections. [default: tcp]")
168
168
169 169 client_ip = Unicode('127.0.0.1', config=True,
170 170 help="IP on which to listen for client connections. [default: loopback]")
171 171 client_transport = Unicode('tcp', config=True,
172 172 help="0MQ transport for client connections. [default : tcp]")
173
173
174 174 monitor_ip = Unicode('127.0.0.1', config=True,
175 175 help="IP on which to listen for monitor messages. [default: loopback]")
176 176 monitor_transport = Unicode('tcp', config=True,
177 177 help="0MQ transport for monitor messages. [default : tcp]")
178
178
179 179 monitor_url = Unicode('')
180
180
181 181 db_class = DottedObjectName('IPython.parallel.controller.dictdb.DictDB',
182 182 config=True, help="""The class to use for the DB backend""")
183
183
184 184 # not configurable
185 185 db = Instance('IPython.parallel.controller.dictdb.BaseDB')
186 186 heartmonitor = Instance('IPython.parallel.controller.heartmonitor.HeartMonitor')
187
187
188 188 def _ip_changed(self, name, old, new):
189 189 self.engine_ip = new
190 190 self.client_ip = new
191 191 self.monitor_ip = new
192 192 self._update_monitor_url()
193
193
194 194 def _update_monitor_url(self):
195 195 self.monitor_url = "%s://%s:%i"%(self.monitor_transport, self.monitor_ip, self.mon_port)
196
196
197 197 def _transport_changed(self, name, old, new):
198 198 self.engine_transport = new
199 199 self.client_transport = new
200 200 self.monitor_transport = new
201 201 self._update_monitor_url()
202
202
203 203 def __init__(self, **kwargs):
204 204 super(HubFactory, self).__init__(**kwargs)
205 205 self._update_monitor_url()
206
207
206
207
208 208 def construct(self):
209 209 self.init_hub()
210
210
211 211 def start(self):
212 212 self.heartmonitor.start()
213 213 self.log.info("Heartmonitor started")
214
214
215 215 def init_hub(self):
216 216 """construct"""
217 217 client_iface = "%s://%s:"%(self.client_transport, self.client_ip) + "%i"
218 218 engine_iface = "%s://%s:"%(self.engine_transport, self.engine_ip) + "%i"
219
219
220 220 ctx = self.context
221 221 loop = self.loop
222
222
223 223 # Registrar socket
224 224 q = ZMQStream(ctx.socket(zmq.ROUTER), loop)
225 225 q.bind(client_iface % self.regport)
@@ -227,7 +227,7 b' class HubFactory(RegistrationFactory):'
227 227 if self.client_ip != self.engine_ip:
228 228 q.bind(engine_iface % self.regport)
229 229 self.log.info("Hub listening on %s for registration."%(engine_iface%self.regport))
230
230
231 231 ### Engine connections ###
232 232
233 233 # heartbeat
@@ -253,11 +253,11 b' class HubFactory(RegistrationFactory):'
253 253 sub.bind(self.monitor_url)
254 254 sub.bind('inproc://monitor')
255 255 sub = ZMQStream(sub, loop)
256
256
257 257 # connect the db
258 258 self.log.info('Hub using DB backend: %r'%(self.db_class.split()[-1]))
259 259 # cdir = self.config.Global.cluster_dir
260 self.db = import_item(str(self.db_class))(session=self.session.session,
260 self.db = import_item(str(self.db_class))(session=self.session.session,
261 261 config=self.config, log=self.log)
262 262 time.sleep(.25)
263 263 try:
@@ -295,11 +295,11 b' class HubFactory(RegistrationFactory):'
295 295 query=q, notifier=n, resubmit=r, db=self.db,
296 296 engine_info=self.engine_info, client_info=self.client_info,
297 297 log=self.log)
298
298
299 299
300 300 class Hub(SessionFactory):
301 301 """The IPython Controller Hub with 0MQ connections
302
302
303 303 Parameters
304 304 ==========
305 305 loop: zmq IOLoop instance
@@ -333,7 +333,7 b' class Hub(SessionFactory):'
333 333 incoming_registrations=Dict()
334 334 registration_timeout=Int()
335 335 _idcounter=Int(0)
336
336
337 337 # objects from constructor:
338 338 query=Instance(ZMQStream)
339 339 monitor=Instance(ZMQStream)
@@ -343,8 +343,8 b' class Hub(SessionFactory):'
343 343 db=Instance(object)
344 344 client_info=Dict()
345 345 engine_info=Dict()
346
347
346
347
348 348 def __init__(self, **kwargs):
349 349 """
350 350 # universal:
@@ -359,10 +359,10 b' class Hub(SessionFactory):'
359 359 engine_info: zmq address/protocol dict for engine connections
360 360 client_info: zmq address/protocol dict for client connections
361 361 """
362
362
363 363 super(Hub, self).__init__(**kwargs)
364 364 self.registration_timeout = max(5000, 2*self.heartmonitor.period)
365
365
366 366 # validate connection dicts:
367 367 for k,v in self.client_info.iteritems():
368 368 if k == 'task':
@@ -371,14 +371,14 b' class Hub(SessionFactory):'
371 371 util.validate_url_container(v)
372 372 # util.validate_url_container(self.client_info)
373 373 util.validate_url_container(self.engine_info)
374
374
375 375 # register our callbacks
376 376 self.query.on_recv(self.dispatch_query)
377 377 self.monitor.on_recv(self.dispatch_monitor_traffic)
378
378
379 379 self.heartmonitor.add_heart_failure_handler(self.handle_heart_failure)
380 380 self.heartmonitor.add_new_heart_handler(self.handle_new_heart)
381
381
382 382 self.monitor_handlers = {b'in' : self.save_queue_request,
383 383 b'out': self.save_queue_result,
384 384 b'intask': self.save_task_request,
@@ -388,7 +388,7 b' class Hub(SessionFactory):'
388 388 b'outcontrol': _passer,
389 389 b'iopub': self.save_iopub_message,
390 390 }
391
391
392 392 self.query_handlers = {'queue_request': self.queue_status,
393 393 'result_request': self.get_results,
394 394 'history_request': self.get_history,
@@ -401,16 +401,16 b' class Hub(SessionFactory):'
401 401 'unregistration_request' : self.unregister_engine,
402 402 'connection_request': self.connection_request,
403 403 }
404
404
405 405 # ignore resubmit replies
406 406 self.resubmit.on_recv(lambda msg: None, copy=False)
407 407
408 408 self.log.info("hub::created hub")
409
409
410 410 @property
411 411 def _next_id(self):
412 412 """gemerate a new ID.
413
413
414 414 No longer reuse old ids, just count from 0."""
415 415 newid = self._idcounter
416 416 self._idcounter += 1
@@ -421,17 +421,17 b' class Hub(SessionFactory):'
421 421 # while newid in self.ids or newid in incoming:
422 422 # newid += 1
423 423 # return newid
424
424
425 425 #-----------------------------------------------------------------------------
426 426 # message validation
427 427 #-----------------------------------------------------------------------------
428
428
429 429 def _validate_targets(self, targets):
430 430 """turn any valid targets argument into a list of integer ids"""
431 431 if targets is None:
432 432 # default to all
433 433 targets = self.ids
434
434
435 435 if isinstance(targets, (int,str,unicode)):
436 436 # only one target specified
437 437 targets = [targets]
@@ -448,12 +448,12 b' class Hub(SessionFactory):'
448 448 if not targets:
449 449 raise IndexError("No Engines Registered")
450 450 return targets
451
451
452 452 #-----------------------------------------------------------------------------
453 453 # dispatch methods (1 per stream)
454 454 #-----------------------------------------------------------------------------
455
456
455
456
457 457 def dispatch_monitor_traffic(self, msg):
458 458 """all ME and Task queue messages come through here, as well as
459 459 IOPub traffic."""
@@ -471,8 +471,8 b' class Hub(SessionFactory):'
471 471 handler(idents, msg)
472 472 else:
473 473 self.log.error("Invalid monitor topic: %r"%switch)
474
475
474
475
476 476 def dispatch_query(self, msg):
477 477 """Route registration requests and queries from clients."""
478 478 try:
@@ -488,7 +488,7 b' class Hub(SessionFactory):'
488 488 except Exception:
489 489 content = error.wrap_exception()
490 490 self.log.error("Bad Query Message: %r"%msg, exc_info=True)
491 self.session.send(self.query, "hub_error", ident=client_id,
491 self.session.send(self.query, "hub_error", ident=client_id,
492 492 content=content)
493 493 return
494 494 # print client_id, header, parent, content
@@ -501,23 +501,23 b' class Hub(SessionFactory):'
501 501 except:
502 502 content = error.wrap_exception()
503 503 self.log.error("Bad Message Type: %r"%msg_type, exc_info=True)
504 self.session.send(self.query, "hub_error", ident=client_id,
504 self.session.send(self.query, "hub_error", ident=client_id,
505 505 content=content)
506 506 return
507 507
508 508 else:
509 509 handler(idents, msg)
510
510
511 511 def dispatch_db(self, msg):
512 512 """"""
513 513 raise NotImplementedError
514
514
515 515 #---------------------------------------------------------------------------
516 516 # handler methods (1 per event)
517 517 #---------------------------------------------------------------------------
518
518
519 519 #----------------------- Heartbeat --------------------------------------
520
520
521 521 def handle_new_heart(self, heart):
522 522 """handler to attach to heartbeater.
523 523 Called when a new heart starts to beat.
@@ -527,8 +527,8 b' class Hub(SessionFactory):'
527 527 self.log.info("heartbeat::ignoring new heart: %r"%heart)
528 528 else:
529 529 self.finish_registration(heart)
530
531
530
531
532 532 def handle_heart_failure(self, heart):
533 533 """handler to attach to heartbeater.
534 534 called when a previously registered heart fails to respond to beat request.
@@ -540,9 +540,9 b' class Hub(SessionFactory):'
540 540 self.log.info("heartbeat::ignoring heart failure %r"%heart)
541 541 else:
542 542 self.unregister_engine(heart, dict(content=dict(id=eid, queue=queue)))
543
543
544 544 #----------------------- MUX Queue Traffic ------------------------------
545
545
546 546 def save_queue_request(self, idents, msg):
547 547 if len(idents) < 2:
548 548 self.log.error("invalid identity prefix: %r"%idents)
@@ -553,7 +553,7 b' class Hub(SessionFactory):'
553 553 except Exception:
554 554 self.log.error("queue::client %r sent invalid message to %r: %r"%(client_id, queue_id, msg), exc_info=True)
555 555 return
556
556
557 557 eid = self.by_ident.get(queue_id, None)
558 558 if eid is None:
559 559 self.log.error("queue::target %r not registered"%queue_id)
@@ -584,16 +584,16 b' class Hub(SessionFactory):'
584 584 self.db.add_record(msg_id, record)
585 585 except Exception:
586 586 self.log.error("DB Error adding record %r"%msg_id, exc_info=True)
587
588
587
588
589 589 self.pending.add(msg_id)
590 590 self.queues[eid].append(msg_id)
591
591
592 592 def save_queue_result(self, idents, msg):
593 593 if len(idents) < 2:
594 594 self.log.error("invalid identity prefix: %r"%idents)
595 595 return
596
596
597 597 client_id, queue_id = idents[:2]
598 598 try:
599 599 msg = self.session.unserialize(msg)
@@ -601,12 +601,12 b' class Hub(SessionFactory):'
601 601 self.log.error("queue::engine %r sent invalid message to %r: %r"%(
602 602 queue_id,client_id, msg), exc_info=True)
603 603 return
604
604
605 605 eid = self.by_ident.get(queue_id, None)
606 606 if eid is None:
607 607 self.log.error("queue::unknown engine %r is sending a reply: "%queue_id)
608 608 return
609
609
610 610 parent = msg['parent_header']
611 611 if not parent:
612 612 return
@@ -637,14 +637,14 b' class Hub(SessionFactory):'
637 637 self.db.update_record(msg_id, result)
638 638 except Exception:
639 639 self.log.error("DB Error updating record %r"%msg_id, exc_info=True)
640
641
640
641
642 642 #--------------------- Task Queue Traffic ------------------------------
643
643
644 644 def save_task_request(self, idents, msg):
645 645 """Save the submission of a task."""
646 646 client_id = idents[0]
647
647
648 648 try:
649 649 msg = self.session.unserialize(msg)
650 650 except Exception:
@@ -691,7 +691,7 b' class Hub(SessionFactory):'
691 691 self.log.error("DB Error adding record %r"%msg_id, exc_info=True)
692 692 except Exception:
693 693 self.log.error("DB Error saving task request %r"%msg_id, exc_info=True)
694
694
695 695 def save_task_result(self, idents, msg):
696 696 """save the result of a completed task."""
697 697 client_id = idents[0]
@@ -701,7 +701,7 b' class Hub(SessionFactory):'
701 701 self.log.error("task::invalid task result message send to %r: %r"%(
702 702 client_id, msg), exc_info=True)
703 703 return
704
704
705 705 parent = msg['parent_header']
706 706 if not parent:
707 707 # print msg
@@ -710,11 +710,11 b' class Hub(SessionFactory):'
710 710 msg_id = parent['msg_id']
711 711 if msg_id in self.unassigned:
712 712 self.unassigned.remove(msg_id)
713
713
714 714 header = msg['header']
715 715 engine_uuid = header.get('engine', None)
716 716 eid = self.by_ident.get(engine_uuid, None)
717
717
718 718 if msg_id in self.pending:
719 719 self.pending.remove(msg_id)
720 720 self.all_completed.add(msg_id)
@@ -737,10 +737,10 b' class Hub(SessionFactory):'
737 737 self.db.update_record(msg_id, result)
738 738 except Exception:
739 739 self.log.error("DB Error saving task request %r"%msg_id, exc_info=True)
740
740
741 741 else:
742 742 self.log.debug("task::unknown task %r finished"%msg_id)
743
743
744 744 def save_task_destination(self, idents, msg):
745 745 try:
746 746 msg = self.session.unserialize(msg, content=True)
@@ -752,30 +752,30 b' class Hub(SessionFactory):'
752 752 msg_id = content['msg_id']
753 753 engine_uuid = content['engine_id']
754 754 eid = self.by_ident[util.asbytes(engine_uuid)]
755
755
756 756 self.log.info("task::task %r arrived on %r"%(msg_id, eid))
757 757 if msg_id in self.unassigned:
758 758 self.unassigned.remove(msg_id)
759 759 # else:
760 760 # self.log.debug("task::task %r not listed as MIA?!"%(msg_id))
761
761
762 762 self.tasks[eid].append(msg_id)
763 763 # self.pending[msg_id][1].update(received=datetime.now(),engine=(eid,engine_uuid))
764 764 try:
765 765 self.db.update_record(msg_id, dict(engine_uuid=engine_uuid))
766 766 except Exception:
767 767 self.log.error("DB Error saving task destination %r"%msg_id, exc_info=True)
768
769
768
769
770 770 def mia_task_request(self, idents, msg):
771 771 raise NotImplementedError
772 772 client_id = idents[0]
773 773 # content = dict(mia=self.mia,status='ok')
774 774 # self.session.send('mia_reply', content=content, idents=client_id)
775
776
775
776
777 777 #--------------------- IOPub Traffic ------------------------------
778
778
779 779 def save_iopub_message(self, topics, msg):
780 780 """save an iopub message into the db"""
781 781 # print (topics)
@@ -784,7 +784,7 b' class Hub(SessionFactory):'
784 784 except Exception:
785 785 self.log.error("iopub::invalid IOPub message", exc_info=True)
786 786 return
787
787
788 788 parent = msg['parent_header']
789 789 if not parent:
790 790 self.log.error("iopub::invalid IOPub message: %r"%msg)
@@ -792,7 +792,7 b' class Hub(SessionFactory):'
792 792 msg_id = parent['msg_id']
793 793 msg_type = msg['header']['msg_type']
794 794 content = msg['content']
795
795
796 796 # ensure msg_id is in db
797 797 try:
798 798 rec = self.db.get_record(msg_id)
@@ -806,25 +806,25 b' class Hub(SessionFactory):'
806 806 name = content['name']
807 807 s = rec[name] or ''
808 808 d[name] = s + content['data']
809
809
810 810 elif msg_type == 'pyerr':
811 811 d['pyerr'] = content
812 812 elif msg_type == 'pyin':
813 813 d['pyin'] = content['code']
814 814 else:
815 815 d[msg_type] = content.get('data', '')
816
816
817 817 try:
818 818 self.db.update_record(msg_id, d)
819 819 except Exception:
820 820 self.log.error("DB Error saving iopub message %r"%msg_id, exc_info=True)
821
822
823
821
822
823
824 824 #-------------------------------------------------------------------------
825 825 # Registration requests
826 826 #-------------------------------------------------------------------------
827
827
828 828 def connection_request(self, client_id, msg):
829 829 """Reply with connection addresses for clients."""
830 830 self.log.info("client::client %r connected"%client_id)
@@ -836,7 +836,7 b' class Hub(SessionFactory):'
836 836 jsonable[str(k)] = v.decode('ascii')
837 837 content['engines'] = jsonable
838 838 self.session.send(self.query, 'connection_reply', content, parent=msg, ident=client_id)
839
839
840 840 def register_engine(self, reg, msg):
841 841 """Register a new engine."""
842 842 content = msg['content']
@@ -851,9 +851,9 b' class Hub(SessionFactory):'
851 851 """register a new engine, and create the socket(s) necessary"""
852 852 eid = self._next_id
853 853 # print (eid, queue, reg, heart)
854
854
855 855 self.log.debug("registration::register_engine(%i, %r, %r, %r)"%(eid, queue, reg, heart))
856
856
857 857 content = dict(id=eid,status='ok')
858 858 content.update(self.engine_info)
859 859 # check if requesting available IDs:
@@ -885,11 +885,11 b' class Hub(SessionFactory):'
885 885 self.log.error("queue_id %r in use"%queue, exc_info=True)
886 886 content = error.wrap_exception()
887 887 break
888
889 msg = self.session.send(self.query, "registration_reply",
890 content=content,
888
889 msg = self.session.send(self.query, "registration_reply",
890 content=content,
891 891 ident=reg)
892
892
893 893 if content['status'] == 'ok':
894 894 if heart in self.heartmonitor.hearts:
895 895 # already beating
@@ -903,7 +903,7 b' class Hub(SessionFactory):'
903 903 else:
904 904 self.log.error("registration::registration %i failed: %r"%(eid, content['evalue']))
905 905 return eid
906
906
907 907 def unregister_engine(self, ident, msg):
908 908 """Unregister an engine that explicitly requested to leave."""
909 909 try:
@@ -918,7 +918,7 b' class Hub(SessionFactory):'
918 918 self.dead_engines.add(uuid)
919 919 # self.ids.remove(eid)
920 920 # uuid = self.keytable.pop(eid)
921 #
921 #
922 922 # ec = self.engines.pop(eid)
923 923 # self.hearts.pop(ec.heartbeat)
924 924 # self.by_ident.pop(ec.queue)
@@ -927,20 +927,20 b' class Hub(SessionFactory):'
927 927 dc = ioloop.DelayedCallback(handleit, self.registration_timeout, self.loop)
928 928 dc.start()
929 929 ############## TODO: HANDLE IT ################
930
930
931 931 if self.notifier:
932 932 self.session.send(self.notifier, "unregistration_notification", content=content)
933
933
934 934 def _handle_stranded_msgs(self, eid, uuid):
935 935 """Handle messages known to be on an engine when the engine unregisters.
936
936
937 937 It is possible that this will fire prematurely - that is, an engine will
938 938 go down after completing a result, and the client will be notified
939 939 that the result failed and later receive the actual result.
940 940 """
941
941
942 942 outstanding = self.queues[eid]
943
943
944 944 for msg_id in outstanding:
945 945 self.pending.remove(msg_id)
946 946 self.all_completed.add(msg_id)
@@ -959,12 +959,12 b' class Hub(SessionFactory):'
959 959 self.db.update_record(msg_id, rec)
960 960 except Exception:
961 961 self.log.error("DB Error handling stranded msg %r"%msg_id, exc_info=True)
962
963
962
963
964 964 def finish_registration(self, heart):
965 965 """Second half of engine registration, called after our HeartMonitor
966 966 has received a beat from the Engine's Heart."""
967 try:
967 try:
968 968 (eid,queue,reg,purge) = self.incoming_registrations.pop(heart)
969 969 except KeyError:
970 970 self.log.error("registration::tried to finish nonexistant registration", exc_info=True)
@@ -975,7 +975,7 b' class Hub(SessionFactory):'
975 975 control = queue
976 976 self.ids.add(eid)
977 977 self.keytable[eid] = queue
978 self.engines[eid] = EngineConnector(id=eid, queue=queue, registration=reg,
978 self.engines[eid] = EngineConnector(id=eid, queue=queue, registration=reg,
979 979 control=control, heartbeat=heart)
980 980 self.by_ident[queue] = eid
981 981 self.queues[eid] = list()
@@ -986,18 +986,18 b' class Hub(SessionFactory):'
986 986 if self.notifier:
987 987 self.session.send(self.notifier, "registration_notification", content=content)
988 988 self.log.info("engine::Engine Connected: %i"%eid)
989
989
990 990 def _purge_stalled_registration(self, heart):
991 991 if heart in self.incoming_registrations:
992 992 eid = self.incoming_registrations.pop(heart)[0]
993 993 self.log.info("registration::purging stalled registration: %i"%eid)
994 994 else:
995 995 pass
996
996
997 997 #-------------------------------------------------------------------------
998 998 # Client Requests
999 999 #-------------------------------------------------------------------------
1000
1000
1001 1001 def shutdown_request(self, client_id, msg):
1002 1002 """handle shutdown request."""
1003 1003 self.session.send(self.query, 'shutdown_reply', content={'status': 'ok'}, ident=client_id)
@@ -1005,13 +1005,13 b' class Hub(SessionFactory):'
1005 1005 self.session.send(self.notifier, 'shutdown_notice', content={'status': 'ok'})
1006 1006 dc = ioloop.DelayedCallback(lambda : self._shutdown(), 1000, self.loop)
1007 1007 dc.start()
1008
1008
1009 1009 def _shutdown(self):
1010 1010 self.log.info("hub::hub shutting down.")
1011 1011 time.sleep(0.1)
1012 1012 sys.exit(0)
1013
1014
1013
1014
1015 1015 def check_load(self, client_id, msg):
1016 1016 content = msg['content']
1017 1017 try:
@@ -1019,17 +1019,17 b' class Hub(SessionFactory):'
1019 1019 targets = self._validate_targets(targets)
1020 1020 except:
1021 1021 content = error.wrap_exception()
1022 self.session.send(self.query, "hub_error",
1022 self.session.send(self.query, "hub_error",
1023 1023 content=content, ident=client_id)
1024 1024 return
1025
1025
1026 1026 content = dict(status='ok')
1027 1027 # loads = {}
1028 1028 for t in targets:
1029 1029 content[bytes(t)] = len(self.queues[t])+len(self.tasks[t])
1030 1030 self.session.send(self.query, "load_reply", content=content, ident=client_id)
1031
1032
1031
1032
1033 1033 def queue_status(self, client_id, msg):
1034 1034 """Return the Queue status of one or more targets.
1035 1035 if verbose: return the msg_ids
@@ -1043,7 +1043,7 b' class Hub(SessionFactory):'
1043 1043 targets = self._validate_targets(targets)
1044 1044 except:
1045 1045 content = error.wrap_exception()
1046 self.session.send(self.query, "hub_error",
1046 self.session.send(self.query, "hub_error",
1047 1047 content=content, ident=client_id)
1048 1048 return
1049 1049 verbose = content.get('verbose', False)
@@ -1060,7 +1060,7 b' class Hub(SessionFactory):'
1060 1060 content['unassigned'] = list(self.unassigned) if verbose else len(self.unassigned)
1061 1061 # print (content)
1062 1062 self.session.send(self.query, "queue_reply", content=content, ident=client_id)
1063
1063
1064 1064 def purge_results(self, client_id, msg):
1065 1065 """Purge results from memory. This method is more valuable before we move
1066 1066 to a DB based message storage mechanism."""
@@ -1101,9 +1101,9 b' class Hub(SessionFactory):'
1101 1101 except Exception:
1102 1102 reply = error.wrap_exception()
1103 1103 break
1104
1104
1105 1105 self.session.send(self.query, 'purge_reply', content=reply, ident=client_id)
1106
1106
1107 1107 def resubmit_task(self, client_id, msg):
1108 1108 """Resubmit one or more tasks."""
1109 1109 def finish(reply):
@@ -1169,7 +1169,7 b' class Hub(SessionFactory):'
1169 1169
1170 1170 finish(dict(status='ok'))
1171 1171
1172
1172
1173 1173 def _extract_record(self, rec):
1174 1174 """decompose a TaskRecord dict into subsection of reply for get_result"""
1175 1175 io_dict = {}
@@ -1184,9 +1184,9 b' class Hub(SessionFactory):'
1184 1184 buffers = map(bytes, rec['result_buffers'])
1185 1185 else:
1186 1186 buffers = []
1187
1187
1188 1188 return content, buffers
1189
1189
1190 1190 def get_results(self, client_id, msg):
1191 1191 """Get the result of 1 or more messages."""
1192 1192 content = msg['content']
@@ -1207,7 +1207,7 b' class Hub(SessionFactory):'
1207 1207 records[rec['msg_id']] = rec
1208 1208 except Exception:
1209 1209 content = error.wrap_exception()
1210 self.session.send(self.query, "result_reply", content=content,
1210 self.session.send(self.query, "result_reply", content=content,
1211 1211 parent=msg, ident=client_id)
1212 1212 return
1213 1213 else:
@@ -1235,7 +1235,7 b' class Hub(SessionFactory):'
1235 1235 except:
1236 1236 content = error.wrap_exception()
1237 1237 break
1238 self.session.send(self.query, "result_reply", content=content,
1238 self.session.send(self.query, "result_reply", content=content,
1239 1239 parent=msg, ident=client_id,
1240 1240 buffers=buffers)
1241 1241
@@ -1247,8 +1247,8 b' class Hub(SessionFactory):'
1247 1247 content = error.wrap_exception()
1248 1248 else:
1249 1249 content = dict(status='ok', history=msg_ids)
1250
1251 self.session.send(self.query, "history_reply", content=content,
1250
1251 self.session.send(self.query, "history_reply", content=content,
1252 1252 parent=msg, ident=client_id)
1253 1253
1254 1254 def db_query(self, client_id, msg):
@@ -1270,7 +1270,7 b' class Hub(SessionFactory):'
1270 1270 else:
1271 1271 buffer_lens = []
1272 1272 result_buffer_lens = []
1273
1273
1274 1274 for rec in records:
1275 1275 # buffers may be None, so double check
1276 1276 if buffer_lens is not None:
@@ -1284,7 +1284,7 b' class Hub(SessionFactory):'
1284 1284 content = dict(status='ok', records=records, buffer_lens=buffer_lens,
1285 1285 result_buffer_lens=result_buffer_lens)
1286 1286 # self.log.debug (content)
1287 self.session.send(self.query, "db_reply", content=content,
1287 self.session.send(self.query, "db_reply", content=content,
1288 1288 parent=msg, ident=client_id,
1289 1289 buffers=buffers)
1290 1290
@@ -66,18 +66,18 b' def plainrandom(loads):'
66 66
67 67 def lru(loads):
68 68 """Always pick the front of the line.
69
69
70 70 The content of `loads` is ignored.
71
71
72 72 Assumes LRU ordering of loads, with oldest first.
73 73 """
74 74 return 0
75 75
76 76 def twobin(loads):
77 77 """Pick two at random, use the LRU of the two.
78
78
79 79 The content of loads is ignored.
80
80
81 81 Assumes LRU ordering of loads, with oldest first.
82 82 """
83 83 n = len(loads)
@@ -87,7 +87,7 b' def twobin(loads):'
87 87
88 88 def weighted(loads):
89 89 """Pick two at random using inverse load as weight.
90
90
91 91 Return the less loaded of the two.
92 92 """
93 93 # weight 0 a million times more than 1:
@@ -109,7 +109,7 b' def weighted(loads):'
109 109
110 110 def leastload(loads):
111 111 """Always choose the lowest load.
112
112
113 113 If the lowest load occurs more than once, the first
114 114 occurance will be used. If loads has LRU ordering, this means
115 115 the LRU of those with the lowest load is chosen.
@@ -124,13 +124,13 b' MET = Dependency([])'
124 124
125 125 class TaskScheduler(SessionFactory):
126 126 """Python TaskScheduler object.
127
127
128 128 This is the simplest object that supports msg_id based
129 129 DAG dependencies. *Only* task msg_ids are checked, not
130 130 msg_ids of jobs submitted via the MUX queue.
131
131
132 132 """
133
133
134 134 hwm = Int(0, config=True, shortname='hwm',
135 135 help="""specify the High Water Mark (HWM) for the downstream
136 136 socket in the Task scheduler. This is the maximum number
@@ -144,7 +144,7 b' class TaskScheduler(SessionFactory):'
144 144 def _scheme_name_changed(self, old, new):
145 145 self.log.debug("Using scheme %r"%new)
146 146 self.scheme = globals()[new]
147
147
148 148 # input arguments:
149 149 scheme = Instance(FunctionType) # function for determining the destination
150 150 def _scheme_default(self):
@@ -153,7 +153,7 b' class TaskScheduler(SessionFactory):'
153 153 engine_stream = Instance(zmqstream.ZMQStream) # engine-facing stream
154 154 notifier_stream = Instance(zmqstream.ZMQStream) # hub-facing sub stream
155 155 mon_stream = Instance(zmqstream.ZMQStream) # hub-facing pub stream
156
156
157 157 # internals:
158 158 graph = Dict() # dict by msg_id of [ msg_ids that depend on key ]
159 159 retries = Dict() # dict by msg_id of retries remaining (non-neg ints)
@@ -173,12 +173,12 b' class TaskScheduler(SessionFactory):'
173 173 all_ids = Set() # set of all submitted task IDs
174 174 blacklist = Dict() # dict by msg_id of locations where a job has encountered UnmetDependency
175 175 auditor = Instance('zmq.eventloop.ioloop.PeriodicCallback')
176
176
177 177 ident = CBytes() # ZMQ identity. This should just be self.session.session
178 178 # but ensure Bytes
179 179 def _ident_default(self):
180 180 return self.session.bsession
181
181
182 182 def start(self):
183 183 self.engine_stream.on_recv(self.dispatch_result, copy=False)
184 184 self._notification_handlers = dict(
@@ -189,20 +189,20 b' class TaskScheduler(SessionFactory):'
189 189 self.auditor = ioloop.PeriodicCallback(self.audit_timeouts, 2e3, self.loop) # 1 Hz
190 190 self.auditor.start()
191 191 self.log.info("Scheduler started [%s]"%self.scheme_name)
192
192
193 193 def resume_receiving(self):
194 194 """Resume accepting jobs."""
195 195 self.client_stream.on_recv(self.dispatch_submission, copy=False)
196
196
197 197 def stop_receiving(self):
198 198 """Stop accepting jobs while there are no engines.
199 199 Leave them in the ZMQ queue."""
200 200 self.client_stream.on_recv(None)
201
201
202 202 #-----------------------------------------------------------------------
203 203 # [Un]Registration Handling
204 204 #-----------------------------------------------------------------------
205
205
206 206 def dispatch_notification(self, msg):
207 207 """dispatch register/unregister events."""
208 208 try:
@@ -215,9 +215,9 b' class TaskScheduler(SessionFactory):'
215 215 except ValueError:
216 216 self.log.warn("task::Unauthorized message from: %r"%idents)
217 217 return
218
218
219 219 msg_type = msg['header']['msg_type']
220
220
221 221 handler = self._notification_handlers.get(msg_type, None)
222 222 if handler is None:
223 223 self.log.error("Unhandled message type: %r"%msg_type)
@@ -226,7 +226,7 b' class TaskScheduler(SessionFactory):'
226 226 handler(asbytes(msg['content']['queue']))
227 227 except Exception:
228 228 self.log.error("task::Invalid notification msg: %r",msg)
229
229
230 230 def _register_engine(self, uid):
231 231 """New engine with ident `uid` became available."""
232 232 # head of the line:
@@ -247,10 +247,10 b' class TaskScheduler(SessionFactory):'
247 247 if len(self.targets) == 1:
248 248 # this was our only engine
249 249 self.stop_receiving()
250
250
251 251 # handle any potentially finished tasks:
252 252 self.engine_stream.flush()
253
253
254 254 # don't pop destinations, because they might be used later
255 255 # map(self.destinations.pop, self.completed.pop(uid))
256 256 # map(self.destinations.pop, self.failed.pop(uid))
@@ -259,7 +259,7 b' class TaskScheduler(SessionFactory):'
259 259 idx = self.targets.index(uid)
260 260 self.targets.pop(idx)
261 261 self.loads.pop(idx)
262
262
263 263 # wait 5 seconds before cleaning up pending jobs, since the results might
264 264 # still be incoming
265 265 if self.pending[uid]:
@@ -269,7 +269,7 b' class TaskScheduler(SessionFactory):'
269 269 self.completed.pop(uid)
270 270 self.failed.pop(uid)
271 271
272
272
273 273 def handle_stranded_tasks(self, engine):
274 274 """Deal with jobs resident in an engine that died."""
275 275 lost = self.pending[engine]
@@ -296,8 +296,8 b' class TaskScheduler(SessionFactory):'
296 296 # finally scrub completed/failed lists
297 297 self.completed.pop(engine)
298 298 self.failed.pop(engine)
299
300
299
300
301 301 #-----------------------------------------------------------------------
302 302 # Job Submission
303 303 #-----------------------------------------------------------------------
@@ -311,24 +311,24 b' class TaskScheduler(SessionFactory):'
311 311 except Exception:
312 312 self.log.error("task::Invaid task msg: %r"%raw_msg, exc_info=True)
313 313 return
314
315
314
315
316 316 # send to monitor
317 317 self.mon_stream.send_multipart([b'intask']+raw_msg, copy=False)
318
318
319 319 header = msg['header']
320 320 msg_id = header['msg_id']
321 321 self.all_ids.add(msg_id)
322
322
323 323 # get targets as a set of bytes objects
324 324 # from a list of unicode objects
325 325 targets = header.get('targets', [])
326 326 targets = map(asbytes, targets)
327 327 targets = set(targets)
328
328
329 329 retries = header.get('retries', 0)
330 330 self.retries[msg_id] = retries
331
331
332 332 # time dependencies
333 333 after = header.get('after', None)
334 334 if after:
@@ -352,17 +352,17 b' class TaskScheduler(SessionFactory):'
352 352 after = MET
353 353 else:
354 354 after = MET
355
355
356 356 # location dependencies
357 357 follow = Dependency(header.get('follow', []))
358
358
359 359 # turn timeouts into datetime objects:
360 360 timeout = header.get('timeout', None)
361 361 if timeout:
362 362 timeout = datetime.now() + timedelta(0,timeout,0)
363
363
364 364 args = [raw_msg, targets, after, follow, timeout]
365
365
366 366 # validate and reduce dependencies:
367 367 for dep in after,follow:
368 368 if not dep: # empty dependency
@@ -375,7 +375,7 b' class TaskScheduler(SessionFactory):'
375 375 if dep.unreachable(self.all_completed, self.all_failed):
376 376 self.depending[msg_id] = args
377 377 return self.fail_unreachable(msg_id)
378
378
379 379 if after.check(self.all_completed, self.all_failed):
380 380 # time deps already met, try to run
381 381 if not self.maybe_run(msg_id, *args):
@@ -385,7 +385,7 b' class TaskScheduler(SessionFactory):'
385 385 self.save_unmet(msg_id, *args)
386 386 else:
387 387 self.save_unmet(msg_id, *args)
388
388
389 389 def audit_timeouts(self):
390 390 """Audit all waiting tasks for expired timeouts."""
391 391 now = datetime.now()
@@ -395,7 +395,7 b' class TaskScheduler(SessionFactory):'
395 395 raw,after,targets,follow,timeout = self.depending[msg_id]
396 396 if timeout and timeout < now:
397 397 self.fail_unreachable(msg_id, error.TaskTimeout)
398
398
399 399 def fail_unreachable(self, msg_id, why=error.ImpossibleDependency):
400 400 """a task has become unreachable, send a reply with an ImpossibleDependency
401 401 error."""
@@ -406,25 +406,25 b' class TaskScheduler(SessionFactory):'
406 406 for mid in follow.union(after):
407 407 if mid in self.graph:
408 408 self.graph[mid].remove(msg_id)
409
409
410 410 # FIXME: unpacking a message I've already unpacked, but didn't save:
411 411 idents,msg = self.session.feed_identities(raw_msg, copy=False)
412 412 header = self.session.unpack(msg[1].bytes)
413
413
414 414 try:
415 415 raise why()
416 416 except:
417 417 content = error.wrap_exception()
418
418
419 419 self.all_done.add(msg_id)
420 420 self.all_failed.add(msg_id)
421
422 msg = self.session.send(self.client_stream, 'apply_reply', content,
421
422 msg = self.session.send(self.client_stream, 'apply_reply', content,
423 423 parent=header, ident=idents)
424 424 self.session.send(self.mon_stream, msg, ident=[b'outtask']+idents)
425
425
426 426 self.update_graph(msg_id, success=False)
427
427
428 428 def maybe_run(self, msg_id, raw_msg, targets, after, follow, timeout):
429 429 """check location dependencies, and run if they are met."""
430 430 blacklist = self.blacklist.setdefault(msg_id, set())
@@ -443,7 +443,7 b' class TaskScheduler(SessionFactory):'
443 443 return False
444 444 # check follow
445 445 return follow.check(self.completed[target], self.failed[target])
446
446
447 447 indices = filter(can_run, range(len(self.targets)))
448 448
449 449 if not indices:
@@ -472,10 +472,10 b' class TaskScheduler(SessionFactory):'
472 472 return False
473 473 else:
474 474 indices = None
475
475
476 476 self.submit_task(msg_id, raw_msg, targets, follow, timeout, indices)
477 477 return True
478
478
479 479 def save_unmet(self, msg_id, raw_msg, targets, after, follow, timeout):
480 480 """Save a message for later submission when its dependencies are met."""
481 481 self.depending[msg_id] = [raw_msg,targets,after,follow,timeout]
@@ -484,7 +484,7 b' class TaskScheduler(SessionFactory):'
484 484 if dep_id not in self.graph:
485 485 self.graph[dep_id] = set()
486 486 self.graph[dep_id].add(msg_id)
487
487
488 488 def submit_task(self, msg_id, raw_msg, targets, follow, timeout, indices=None):
489 489 """Submit a task to any of a subset of our targets."""
490 490 if indices:
@@ -504,10 +504,10 b' class TaskScheduler(SessionFactory):'
504 504 self.pending[target][msg_id] = (raw_msg, targets, MET, follow, timeout)
505 505 # notify Hub
506 506 content = dict(msg_id=msg_id, engine_id=target.decode('ascii'))
507 self.session.send(self.mon_stream, 'task_destination', content=content,
507 self.session.send(self.mon_stream, 'task_destination', content=content,
508 508 ident=[b'tracktask',self.ident])
509
510
509
510
511 511 #-----------------------------------------------------------------------
512 512 # Result Handling
513 513 #-----------------------------------------------------------------------
@@ -545,7 +545,7 b' class TaskScheduler(SessionFactory):'
545 545 self.mon_stream.send_multipart([b'outtask']+raw_msg, copy=False)
546 546 else:
547 547 self.handle_unmet_dependency(idents, parent)
548
548
549 549 def handle_result(self, idents, parent, raw_msg, success=True):
550 550 """handle a real task result, either success or failure"""
551 551 # first, relay result to client
@@ -567,21 +567,21 b' class TaskScheduler(SessionFactory):'
567 567 self.all_failed.add(msg_id)
568 568 self.all_done.add(msg_id)
569 569 self.destinations[msg_id] = engine
570
570
571 571 self.update_graph(msg_id, success)
572
572
573 573 def handle_unmet_dependency(self, idents, parent):
574 574 """handle an unmet dependency"""
575 575 engine = idents[0]
576 576 msg_id = parent['msg_id']
577
577
578 578 if msg_id not in self.blacklist:
579 579 self.blacklist[msg_id] = set()
580 580 self.blacklist[msg_id].add(engine)
581
581
582 582 args = self.pending[engine].pop(msg_id)
583 583 raw,targets,after,follow,timeout = args
584
584
585 585 if self.blacklist[msg_id] == targets:
586 586 self.depending[msg_id] = args
587 587 self.fail_unreachable(msg_id)
@@ -590,7 +590,7 b' class TaskScheduler(SessionFactory):'
590 590 if msg_id not in self.all_failed:
591 591 # put it back in our dependency tree
592 592 self.save_unmet(msg_id, *args)
593
593
594 594 if self.hwm:
595 595 try:
596 596 idx = self.targets.index(engine)
@@ -599,13 +599,13 b' class TaskScheduler(SessionFactory):'
599 599 else:
600 600 if self.loads[idx] == self.hwm-1:
601 601 self.update_graph(None)
602
603
604
602
603
604
605 605 def update_graph(self, dep_id=None, success=True):
606 606 """dep_id just finished. Update our dependency
607 607 graph and submit any jobs that just became runable.
608
608
609 609 Called with dep_id=None to update entire graph for hwm, but without finishing
610 610 a task.
611 611 """
@@ -624,26 +624,26 b' class TaskScheduler(SessionFactory):'
624 624 # or b) dep_id was given as None
625 625 if dep_id is None or self.hwm and any( [ load==self.hwm-1 for load in self.loads ]):
626 626 jobs = self.depending.keys()
627
627
628 628 for msg_id in jobs:
629 629 raw_msg, targets, after, follow, timeout = self.depending[msg_id]
630
630
631 631 if after.unreachable(self.all_completed, self.all_failed)\
632 632 or follow.unreachable(self.all_completed, self.all_failed):
633 633 self.fail_unreachable(msg_id)
634
634
635 635 elif after.check(self.all_completed, self.all_failed): # time deps met, maybe run
636 636 if self.maybe_run(msg_id, raw_msg, targets, MET, follow, timeout):
637
637
638 638 self.depending.pop(msg_id)
639 639 for mid in follow.union(after):
640 640 if mid in self.graph:
641 641 self.graph[mid].remove(msg_id)
642
642
643 643 #----------------------------------------------------------------------
644 644 # methods to be overridden by subclasses
645 645 #----------------------------------------------------------------------
646
646
647 647 def add_job(self, idx):
648 648 """Called after self.targets[idx] just got the job with header.
649 649 Override with subclasses. The default ordering is simple LRU.
@@ -651,21 +651,21 b' class TaskScheduler(SessionFactory):'
651 651 self.loads[idx] += 1
652 652 for lis in (self.targets, self.loads):
653 653 lis.append(lis.pop(idx))
654
655
654
655
656 656 def finish_job(self, idx):
657 657 """Called after self.targets[idx] just finished a job.
658 658 Override with subclasses."""
659 659 self.loads[idx] -= 1
660
660
661 661
662 662
663 663 def launch_scheduler(in_addr, out_addr, mon_addr, not_addr, config=None,
664 664 logname='root', log_url=None, loglevel=logging.DEBUG,
665 665 identity=b'task', in_thread=False):
666
666
667 667 ZMQStream = zmqstream.ZMQStream
668
668
669 669 if config:
670 670 # unwrap dict back into Config
671 671 config = Config(config)
@@ -675,14 +675,14 b' def launch_scheduler(in_addr, out_addr, mon_addr, not_addr, config=None,'
675 675 ctx = zmq.Context.instance()
676 676 loop = ioloop.IOLoop.instance()
677 677 else:
678 # in a process, don't use instance()
678 # in a process, don't use instance()
679 679 # for safety with multiprocessing
680 680 ctx = zmq.Context()
681 681 loop = ioloop.IOLoop()
682 682 ins = ZMQStream(ctx.socket(zmq.ROUTER),loop)
683 683 ins.setsockopt(zmq.IDENTITY, identity)
684 684 ins.bind(in_addr)
685
685
686 686 outs = ZMQStream(ctx.socket(zmq.ROUTER),loop)
687 687 outs.setsockopt(zmq.IDENTITY, identity)
688 688 outs.bind(out_addr)
@@ -691,7 +691,7 b' def launch_scheduler(in_addr, out_addr, mon_addr, not_addr, config=None,'
691 691 nots = zmqstream.ZMQStream(ctx.socket(zmq.SUB),loop)
692 692 nots.setsockopt(zmq.SUBSCRIBE, b'')
693 693 nots.connect(not_addr)
694
694
695 695 # setup logging.
696 696 if in_thread:
697 697 log = Application.instance().log
@@ -700,7 +700,7 b' def launch_scheduler(in_addr, out_addr, mon_addr, not_addr, config=None,'
700 700 log = connect_logger(logname, ctx, log_url, root="scheduler", loglevel=loglevel)
701 701 else:
702 702 log = local_logger(logname, loglevel)
703
703
704 704 scheduler = TaskScheduler(client_stream=ins, engine_stream=outs,
705 705 mon_stream=mons, notifier_stream=nots,
706 706 loop=loop, log=log,
@@ -87,7 +87,7 b' def _convert_bufs(bs):'
87 87
88 88 class SQLiteDB(BaseDB):
89 89 """SQLite3 TaskRecord backend."""
90
90
91 91 filename = Unicode('tasks.db', config=True,
92 92 help="""The filename of the sqlite task database. [default: 'tasks.db']""")
93 93 location = Unicode('', config=True,
@@ -98,7 +98,7 b' class SQLiteDB(BaseDB):'
98 98 a new table will be created with the Hub's IDENT. Specifying the table will result
99 99 in tasks from previous sessions being available via Clients' db_query and
100 100 get_result methods.""")
101
101
102 102 _db = Instance('sqlite3.Connection')
103 103 # the ordered list of column names
104 104 _keys = List(['msg_id' ,
@@ -142,7 +142,7 b' class SQLiteDB(BaseDB):'
142 142 'stdout' : 'text',
143 143 'stderr' : 'text',
144 144 })
145
145
146 146 def __init__(self, **kwargs):
147 147 super(SQLiteDB, self).__init__(**kwargs)
148 148 if not self.table:
@@ -160,14 +160,14 b' class SQLiteDB(BaseDB):'
160 160 else:
161 161 self.location = u'.'
162 162 self._init_db()
163
163
164 164 # register db commit as 2s periodic callback
165 165 # to prevent clogging pipes
166 166 # assumes we are being run in a zmq ioloop app
167 167 loop = ioloop.IOLoop.instance()
168 168 pc = ioloop.PeriodicCallback(self._db.commit, 2000, loop)
169 169 pc.start()
170
170
171 171 def _defaults(self, keys=None):
172 172 """create an empty record"""
173 173 d = {}
@@ -175,10 +175,10 b' class SQLiteDB(BaseDB):'
175 175 for key in keys:
176 176 d[key] = None
177 177 return d
178
178
179 179 def _check_table(self):
180 180 """Ensure that an incorrect table doesn't exist
181
181
182 182 If a bad (old) table does exist, return False
183 183 """
184 184 cursor = self._db.execute("PRAGMA table_info(%s)"%self.table)
@@ -202,7 +202,7 b' class SQLiteDB(BaseDB):'
202 202 )
203 203 return False
204 204 return True
205
205
206 206 def _init_db(self):
207 207 """Connect to the database and get new session number."""
208 208 # register adapters
@@ -212,7 +212,7 b' class SQLiteDB(BaseDB):'
212 212 sqlite3.register_converter('bufs', _convert_bufs)
213 213 # connect to the db
214 214 dbfile = os.path.join(self.location, self.filename)
215 self._db = sqlite3.connect(dbfile, detect_types=sqlite3.PARSE_DECLTYPES,
215 self._db = sqlite3.connect(dbfile, detect_types=sqlite3.PARSE_DECLTYPES,
216 216 # isolation_level = None)#,
217 217 cached_statements=64)
218 218 # print dir(self._db)
@@ -225,8 +225,8 b' class SQLiteDB(BaseDB):'
225 225 "Table %s exists and doesn't match db format, trying %s"%
226 226 (first_table,self.table)
227 227 )
228
229 self._db.execute("""CREATE TABLE IF NOT EXISTS %s
228
229 self._db.execute("""CREATE TABLE IF NOT EXISTS %s
230 230 (msg_id text PRIMARY KEY,
231 231 header dict text,
232 232 content dict text,
@@ -248,32 +248,32 b' class SQLiteDB(BaseDB):'
248 248 stderr text)
249 249 """%self.table)
250 250 self._db.commit()
251
251
252 252 def _dict_to_list(self, d):
253 253 """turn a mongodb-style record dict into a list."""
254
254
255 255 return [ d[key] for key in self._keys ]
256
256
257 257 def _list_to_dict(self, line, keys=None):
258 258 """Inverse of dict_to_list"""
259 259 keys = self._keys if keys is None else keys
260 260 d = self._defaults(keys)
261 261 for key,value in zip(keys, line):
262 262 d[key] = value
263
263
264 264 return d
265
265
266 266 def _render_expression(self, check):
267 267 """Turn a mongodb-style search dict into an SQL query."""
268 268 expressions = []
269 269 args = []
270
270
271 271 skeys = set(check.keys())
272 272 skeys.difference_update(set(self._keys))
273 273 skeys.difference_update(set(['buffers', 'result_buffers']))
274 274 if skeys:
275 275 raise KeyError("Illegal testing key(s): %s"%skeys)
276
276
277 277 for name,sub_check in check.iteritems():
278 278 if isinstance(sub_check, dict):
279 279 for test,value in sub_check.iteritems():
@@ -283,7 +283,7 b' class SQLiteDB(BaseDB):'
283 283 raise KeyError("Unsupported operator: %r"%test)
284 284 if isinstance(op, tuple):
285 285 op, join = op
286
286
287 287 if value is None and op in null_operators:
288 288 expr = "%s %s"%null_operators[op]
289 289 else:
@@ -304,10 +304,10 b' class SQLiteDB(BaseDB):'
304 304 else:
305 305 expressions.append("%s = ?"%name)
306 306 args.append(sub_check)
307
307
308 308 expr = " AND ".join(expressions)
309 309 return expr, args
310
310
311 311 def add_record(self, msg_id, rec):
312 312 """Add a new Task Record, by msg_id."""
313 313 d = self._defaults()
@@ -317,7 +317,7 b' class SQLiteDB(BaseDB):'
317 317 tups = '(%s)'%(','.join(['?']*len(line)))
318 318 self._db.execute("INSERT INTO %s VALUES %s"%(self.table, tups), line)
319 319 # self._db.commit()
320
320
321 321 def get_record(self, msg_id):
322 322 """Get a specific Task Record, by msg_id."""
323 323 cursor = self._db.execute("""SELECT * FROM %s WHERE msg_id==?"""%self.table, (msg_id,))
@@ -325,7 +325,7 b' class SQLiteDB(BaseDB):'
325 325 if line is None:
326 326 raise KeyError("No such msg: %r"%msg_id)
327 327 return self._list_to_dict(line)
328
328
329 329 def update_record(self, msg_id, rec):
330 330 """Update the data in an existing record."""
331 331 query = "UPDATE %s SET "%self.table
@@ -340,27 +340,27 b' class SQLiteDB(BaseDB):'
340 340 values.append(msg_id)
341 341 self._db.execute(query, values)
342 342 # self._db.commit()
343
343
344 344 def drop_record(self, msg_id):
345 345 """Remove a record from the DB."""
346 346 self._db.execute("""DELETE FROM %s WHERE msg_id==?"""%self.table, (msg_id,))
347 347 # self._db.commit()
348
348
349 349 def drop_matching_records(self, check):
350 350 """Remove a record from the DB."""
351 351 expr,args = self._render_expression(check)
352 352 query = "DELETE FROM %s WHERE %s"%(self.table, expr)
353 353 self._db.execute(query,args)
354 354 # self._db.commit()
355
355
356 356 def find_records(self, check, keys=None):
357 357 """Find records matching a query dict, optionally extracting subset of keys.
358
358
359 359 Returns list of matching records.
360
360
361 361 Parameters
362 362 ----------
363
363
364 364 check: dict
365 365 mongodb-style query argument
366 366 keys: list of strs [optional]
@@ -371,7 +371,7 b' class SQLiteDB(BaseDB):'
371 371 bad_keys = [ key for key in keys if key not in self._keys ]
372 372 if bad_keys:
373 373 raise KeyError("Bad record key(s): %s"%bad_keys)
374
374
375 375 if keys:
376 376 # ensure msg_id is present and first:
377 377 if 'msg_id' in keys:
@@ -389,7 +389,7 b' class SQLiteDB(BaseDB):'
389 389 rec = self._list_to_dict(line, keys)
390 390 records.append(rec)
391 391 return records
392
392
393 393 def get_history(self):
394 394 """get all msg_ids, ordered by time submitted."""
395 395 query = """SELECT msg_id FROM %s ORDER by submitted ASC"""%self.table
@@ -27,7 +27,7 b' from IPython.external.ssh import tunnel'
27 27 from IPython.utils.traitlets import (
28 28 Instance, Dict, Int, Type, CFloat, Unicode, CBytes, Bool
29 29 )
30 # from IPython.utils.localinterfaces import LOCALHOST
30 # from IPython.utils.localinterfaces import LOCALHOST
31 31
32 32 from IPython.parallel.controller.heartmonitor import Heart
33 33 from IPython.parallel.factory import RegistrationFactory
@@ -39,7 +39,7 b' from .streamkernel import Kernel'
39 39
40 40 class EngineFactory(RegistrationFactory):
41 41 """IPython engine"""
42
42
43 43 # configurables:
44 44 out_stream_factory=Type('IPython.zmq.iostream.OutStream', config=True,
45 45 help="""The OutStream for handling stdout/err.
@@ -60,32 +60,32 b' class EngineFactory(RegistrationFactory):'
60 60 help="""The SSH private key file to use when tunneling connections to the Controller.""")
61 61 paramiko=Bool(sys.platform == 'win32', config=True,
62 62 help="""Whether to use paramiko instead of openssh for tunnels.""")
63
63
64 64 # not configurable:
65 65 user_ns=Dict()
66 66 id=Int(allow_none=True)
67 67 registrar=Instance('zmq.eventloop.zmqstream.ZMQStream')
68 68 kernel=Instance(Kernel)
69
69
70 70 bident = CBytes()
71 71 ident = Unicode()
72 72 def _ident_changed(self, name, old, new):
73 73 self.bident = asbytes(new)
74 74 using_ssh=Bool(False)
75
76
75
76
77 77 def __init__(self, **kwargs):
78 78 super(EngineFactory, self).__init__(**kwargs)
79 79 self.ident = self.session.session
80
80
81 81 def init_connector(self):
82 82 """construct connection function, which handles tunnels."""
83 83 self.using_ssh = bool(self.sshkey or self.sshserver)
84
84
85 85 if self.sshkey and not self.sshserver:
86 86 # We are using ssh directly to the controller, tunneling localhost to localhost
87 87 self.sshserver = self.url.split('://')[1].split(':')[0]
88
88
89 89 if self.using_ssh:
90 90 if tunnel.try_passwordless_ssh(self.sshserver, self.sshkey, self.paramiko):
91 91 password=False
@@ -93,7 +93,7 b' class EngineFactory(RegistrationFactory):'
93 93 password = getpass("SSH Password for %s: "%self.sshserver)
94 94 else:
95 95 password = False
96
96
97 97 def connect(s, url):
98 98 url = disambiguate_url(url, self.location)
99 99 if self.using_ssh:
@@ -104,7 +104,7 b' class EngineFactory(RegistrationFactory):'
104 104 )
105 105 else:
106 106 return s.connect(url)
107
107
108 108 def maybe_tunnel(url):
109 109 """like connect, but don't complete the connection (for use by heartbeat)"""
110 110 url = disambiguate_url(url, self.location)
@@ -116,10 +116,10 b' class EngineFactory(RegistrationFactory):'
116 116 )
117 117 return url
118 118 return connect, maybe_tunnel
119
119
120 120 def register(self):
121 121 """send the registration_request"""
122
122
123 123 self.log.info("Registering with controller at %s"%self.url)
124 124 ctx = self.context
125 125 connect,maybe_tunnel = self.init_connector()
@@ -127,13 +127,13 b' class EngineFactory(RegistrationFactory):'
127 127 reg.setsockopt(zmq.IDENTITY, self.bident)
128 128 connect(reg, self.url)
129 129 self.registrar = zmqstream.ZMQStream(reg, self.loop)
130
131
130
131
132 132 content = dict(queue=self.ident, heartbeat=self.ident, control=self.ident)
133 133 self.registrar.on_recv(lambda msg: self.complete_registration(msg, connect, maybe_tunnel))
134 134 # print (self.session.key)
135 135 self.session.send(self.registrar, "registration_request",content=content)
136
136
137 137 def complete_registration(self, msg, connect, maybe_tunnel):
138 138 # print msg
139 139 self._abort_dc.stop()
@@ -142,25 +142,25 b' class EngineFactory(RegistrationFactory):'
142 142 identity = self.bident
143 143 idents,msg = self.session.feed_identities(msg)
144 144 msg = Message(self.session.unserialize(msg))
145
145
146 146 if msg.content.status == 'ok':
147 147 self.id = int(msg.content.id)
148
148
149 149 # launch heartbeat
150 150 hb_addrs = msg.content.heartbeat
151
151
152 152 # possibly forward hb ports with tunnels
153 153 hb_addrs = [ maybe_tunnel(addr) for addr in hb_addrs ]
154 154 heart = Heart(*map(str, hb_addrs), heart_id=identity)
155 155 heart.start()
156
156
157 157 # create Shell Streams (MUX, Task, etc.):
158 158 queue_addr = msg.content.mux
159 159 shell_addrs = [ str(queue_addr) ]
160 160 task_addr = msg.content.task
161 161 if task_addr:
162 162 shell_addrs.append(str(task_addr))
163
163
164 164 # Uncomment this to go back to two-socket model
165 165 # shell_streams = []
166 166 # for addr in shell_addrs:
@@ -168,7 +168,7 b' class EngineFactory(RegistrationFactory):'
168 168 # stream.setsockopt(zmq.IDENTITY, identity)
169 169 # stream.connect(disambiguate_url(addr, self.location))
170 170 # shell_streams.append(stream)
171
171
172 172 # Now use only one shell stream for mux and tasks
173 173 stream = zmqstream.ZMQStream(ctx.socket(zmq.ROUTER), loop)
174 174 stream.setsockopt(zmq.IDENTITY, identity)
@@ -176,19 +176,19 b' class EngineFactory(RegistrationFactory):'
176 176 for addr in shell_addrs:
177 177 connect(stream, addr)
178 178 # end single stream-socket
179
179
180 180 # control stream:
181 181 control_addr = str(msg.content.control)
182 182 control_stream = zmqstream.ZMQStream(ctx.socket(zmq.ROUTER), loop)
183 183 control_stream.setsockopt(zmq.IDENTITY, identity)
184 184 connect(control_stream, control_addr)
185
185
186 186 # create iopub stream:
187 187 iopub_addr = msg.content.iopub
188 188 iopub_stream = zmqstream.ZMQStream(ctx.socket(zmq.PUB), loop)
189 189 iopub_stream.setsockopt(zmq.IDENTITY, identity)
190 190 connect(iopub_stream, iopub_addr)
191
191
192 192 # # Redirect input streams and set a display hook.
193 193 if self.out_stream_factory:
194 194 sys.stdout = self.out_stream_factory(self.session, iopub_stream, u'stdout')
@@ -199,25 +199,25 b' class EngineFactory(RegistrationFactory):'
199 199 sys.displayhook = self.display_hook_factory(self.session, iopub_stream)
200 200 sys.displayhook.topic = 'engine.%i.pyout'%self.id
201 201
202 self.kernel = Kernel(config=self.config, int_id=self.id, ident=self.ident, session=self.session,
203 control_stream=control_stream, shell_streams=shell_streams, iopub_stream=iopub_stream,
202 self.kernel = Kernel(config=self.config, int_id=self.id, ident=self.ident, session=self.session,
203 control_stream=control_stream, shell_streams=shell_streams, iopub_stream=iopub_stream,
204 204 loop=loop, user_ns = self.user_ns, log=self.log)
205 205 self.kernel.start()
206
207
206
207
208 208 else:
209 209 self.log.fatal("Registration Failed: %s"%msg)
210 210 raise Exception("Registration Failed: %s"%msg)
211
211
212 212 self.log.info("Completed registration with id %i"%self.id)
213
214
213
214
215 215 def abort(self):
216 216 self.log.fatal("Registration timed out after %.1f seconds"%self.timeout)
217 217 self.session.send(self.registrar, "unregistration_request", content=dict(id=self.id))
218 218 time.sleep(1)
219 219 sys.exit(255)
220
220
221 221 def start(self):
222 222 dc = ioloop.DelayedCallback(self.register, 0, self.loop)
223 223 dc.start()
@@ -47,17 +47,17 b' def printer(*args):'
47 47
48 48 class _Passer(zmqstream.ZMQStream):
49 49 """Empty class that implements `send()` that does nothing.
50
50
51 51 Subclass ZMQStream for Session typechecking
52
52
53 53 """
54 54 def __init__(self, *args, **kwargs):
55 55 pass
56
56
57 57 def send(self, *args, **kwargs):
58 58 pass
59 59 send_multipart = send
60
60
61 61
62 62 #-----------------------------------------------------------------------------
63 63 # Main kernel class
@@ -68,63 +68,63 b' class Kernel(SessionFactory):'
68 68 #---------------------------------------------------------------------------
69 69 # Kernel interface
70 70 #---------------------------------------------------------------------------
71
71
72 72 # kwargs:
73 73 exec_lines = List(Unicode, config=True,
74 74 help="List of lines to execute")
75
75
76 76 # identities:
77 77 int_id = Int(-1)
78 78 bident = CBytes()
79 79 ident = Unicode()
80 80 def _ident_changed(self, name, old, new):
81 81 self.bident = asbytes(new)
82
82
83 83 user_ns = Dict(config=True, help="""Set the user's namespace of the Kernel""")
84
84
85 85 control_stream = Instance(zmqstream.ZMQStream)
86 86 task_stream = Instance(zmqstream.ZMQStream)
87 87 iopub_stream = Instance(zmqstream.ZMQStream)
88 88 client = Instance('IPython.parallel.Client')
89
89
90 90 # internals
91 91 shell_streams = List()
92 92 compiler = Instance(CommandCompiler, (), {})
93 93 completer = Instance(KernelCompleter)
94
94
95 95 aborted = Set()
96 96 shell_handlers = Dict()
97 97 control_handlers = Dict()
98
98
99 99 def _set_prefix(self):
100 100 self.prefix = "engine.%s"%self.int_id
101
101
102 102 def _connect_completer(self):
103 103 self.completer = KernelCompleter(self.user_ns)
104
104
105 105 def __init__(self, **kwargs):
106 106 super(Kernel, self).__init__(**kwargs)
107 107 self._set_prefix()
108 108 self._connect_completer()
109
109
110 110 self.on_trait_change(self._set_prefix, 'id')
111 111 self.on_trait_change(self._connect_completer, 'user_ns')
112
112
113 113 # Build dict of handlers for message types
114 for msg_type in ['execute_request', 'complete_request', 'apply_request',
114 for msg_type in ['execute_request', 'complete_request', 'apply_request',
115 115 'clear_request']:
116 116 self.shell_handlers[msg_type] = getattr(self, msg_type)
117
117
118 118 for msg_type in ['shutdown_request', 'abort_request']+self.shell_handlers.keys():
119 119 self.control_handlers[msg_type] = getattr(self, msg_type)
120
120
121 121 self._initial_exec_lines()
122
122
123 123 def _wrap_exception(self, method=None):
124 124 e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method)
125 125 content=wrap_exception(e_info)
126 126 return content
127
127
128 128 def _initial_exec_lines(self):
129 129 s = _Passer()
130 130 content = dict(silent=True, user_variable=[],user_expressions=[])
@@ -133,20 +133,20 b' class Kernel(SessionFactory):'
133 133 content.update({'code':line})
134 134 msg = self.session.msg('execute_request', content)
135 135 self.execute_request(s, [], msg)
136
137
136
137
138 138 #-------------------- control handlers -----------------------------
139 139 def abort_queues(self):
140 140 for stream in self.shell_streams:
141 141 if stream:
142 142 self.abort_queue(stream)
143
143
144 144 def abort_queue(self, stream):
145 145 while True:
146 146 idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True)
147 147 if msg is None:
148 148 return
149
149
150 150 self.log.info("Aborting:")
151 151 self.log.info(str(msg))
152 152 msg_type = msg['header']['msg_type']
@@ -154,13 +154,13 b' class Kernel(SessionFactory):'
154 154 # reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg)
155 155 # self.reply_socket.send(ident,zmq.SNDMORE)
156 156 # self.reply_socket.send_json(reply_msg)
157 reply_msg = self.session.send(stream, reply_type,
157 reply_msg = self.session.send(stream, reply_type,
158 158 content={'status' : 'aborted'}, parent=msg, ident=idents)
159 159 self.log.debug(str(reply_msg))
160 160 # We need to wait a bit for requests to come in. This can probably
161 161 # be set shorter for true asynchronous clients.
162 162 time.sleep(0.05)
163
163
164 164 def abort_request(self, stream, ident, parent):
165 165 """abort a specifig msg by id"""
166 166 msg_ids = parent['content'].get('msg_ids', None)
@@ -170,12 +170,12 b' class Kernel(SessionFactory):'
170 170 self.abort_queues()
171 171 for mid in msg_ids:
172 172 self.aborted.add(str(mid))
173
173
174 174 content = dict(status='ok')
175 reply_msg = self.session.send(stream, 'abort_reply', content=content,
175 reply_msg = self.session.send(stream, 'abort_reply', content=content,
176 176 parent=parent, ident=ident)
177 177 self.log.debug(str(reply_msg))
178
178
179 179 def shutdown_request(self, stream, ident, parent):
180 180 """kill ourself. This should really be handled in an external process"""
181 181 try:
@@ -190,7 +190,7 b' class Kernel(SessionFactory):'
190 190 self.log.debug(str(msg))
191 191 dc = ioloop.DelayedCallback(lambda : sys.exit(0), 1000, self.loop)
192 192 dc.start()
193
193
194 194 def dispatch_control(self, msg):
195 195 idents,msg = self.session.feed_identities(msg, copy=False)
196 196 try:
@@ -200,7 +200,7 b' class Kernel(SessionFactory):'
200 200 return
201 201 else:
202 202 self.log.debug("Control received, %s", msg)
203
203
204 204 header = msg['header']
205 205 msg_id = header['msg_id']
206 206 msg_type = header['msg_type']
@@ -210,10 +210,10 b' class Kernel(SessionFactory):'
210 210 self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r"%msg_type)
211 211 else:
212 212 handler(self.control_stream, idents, msg)
213
213
214 214
215 215 #-------------------- queue helpers ------------------------------
216
216
217 217 def check_dependencies(self, dependencies):
218 218 if not dependencies:
219 219 return True
@@ -225,28 +225,28 b' class Kernel(SessionFactory):'
225 225 results = self.client.get_results(dependencies,status_only=True)
226 226 if results['status'] != 'ok':
227 227 return False
228
228
229 229 if anyorall == 'any':
230 230 if not results['completed']:
231 231 return False
232 232 else:
233 233 if results['pending']:
234 234 return False
235
235
236 236 return True
237
237
238 238 def check_aborted(self, msg_id):
239 239 return msg_id in self.aborted
240
240
241 241 #-------------------- queue handlers -----------------------------
242
242
243 243 def clear_request(self, stream, idents, parent):
244 244 """Clear our namespace."""
245 245 self.user_ns = {}
246 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
246 msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent,
247 247 content = dict(status='ok'))
248 248 self._initial_exec_lines()
249
249
250 250 def execute_request(self, stream, ident, parent):
251 251 self.log.debug('execute request %s'%parent)
252 252 try:
@@ -273,8 +273,8 b' class Kernel(SessionFactory):'
273 273 reply_content = exc_content
274 274 else:
275 275 reply_content = {'status' : 'ok'}
276
277 reply_msg = self.session.send(stream, u'execute_reply', reply_content, parent=parent,
276
277 reply_msg = self.session.send(stream, u'execute_reply', reply_content, parent=parent,
278 278 ident=ident, subheader = dict(started=started))
279 279 self.log.debug(str(reply_msg))
280 280 if reply_msg['content']['status'] == u'error':
@@ -289,7 +289,7 b' class Kernel(SessionFactory):'
289 289
290 290 def complete(self, msg):
291 291 return self.completer.complete(msg.content.line, msg.content.text)
292
292
293 293 def apply_request(self, stream, ident, parent):
294 294 # flush previous reply, so this request won't block it
295 295 stream.flush(zmq.POLLOUT)
@@ -314,21 +314,21 b' class Kernel(SessionFactory):'
314 314 sys.stderr.set_parent(parent)
315 315 # exec "f(*args,**kwargs)" in self.user_ns, self.user_ns
316 316 working = self.user_ns
317 # suffix =
317 # suffix =
318 318 prefix = "_"+str(msg_id).replace("-","")+"_"
319
319
320 320 f,args,kwargs = unpack_apply_message(bufs, working, copy=False)
321 321 # if bound:
322 322 # bound_ns = Namespace(working)
323 323 # args = [bound_ns]+list(args)
324 324
325 325 fname = getattr(f, '__name__', 'f')
326
326
327 327 fname = prefix+"f"
328 328 argname = prefix+"args"
329 329 kwargname = prefix+"kwargs"
330 330 resultname = prefix+"result"
331
331
332 332 ns = { fname : f, argname : args, kwargname : kwargs , resultname : None }
333 333 # print ns
334 334 working.update(ns)
@@ -341,7 +341,7 b' class Kernel(SessionFactory):'
341 341 working.pop(key)
342 342 # if bound:
343 343 # working.update(bound_ns)
344
344
345 345 packed_result,buf = serialize_object(result)
346 346 result_buf = [packed_result]+buf
347 347 except:
@@ -351,24 +351,24 b' class Kernel(SessionFactory):'
351 351 ident=asbytes('%s.pyerr'%self.prefix))
352 352 reply_content = exc_content
353 353 result_buf = []
354
354
355 355 if exc_content['ename'] == 'UnmetDependency':
356 356 sub['dependencies_met'] = False
357 357 else:
358 358 reply_content = {'status' : 'ok'}
359
359
360 360 # put 'ok'/'error' status in header, for scheduler introspection:
361 361 sub['status'] = reply_content['status']
362
363 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
362
363 reply_msg = self.session.send(stream, u'apply_reply', reply_content,
364 364 parent=parent, ident=ident,buffers=result_buf, subheader=sub)
365
365
366 366 # flush i/o
367 # should this be before reply_msg is sent, like in the single-kernel code,
367 # should this be before reply_msg is sent, like in the single-kernel code,
368 368 # or should nothing get in the way of real results?
369 369 sys.stdout.flush()
370 370 sys.stderr.flush()
371
371
372 372 def dispatch_queue(self, stream, msg):
373 373 self.control_stream.flush()
374 374 idents,msg = self.session.feed_identities(msg, copy=False)
@@ -379,8 +379,8 b' class Kernel(SessionFactory):'
379 379 return
380 380 else:
381 381 self.log.debug("Message received, %s", msg)
382
383
382
383
384 384 header = msg['header']
385 385 msg_id = header['msg_id']
386 386 msg_type = msg['header']['msg_type']
@@ -397,25 +397,25 b' class Kernel(SessionFactory):'
397 397 self.log.error("UNKNOWN MESSAGE TYPE: %r"%msg_type)
398 398 else:
399 399 handler(stream, idents, msg)
400
400
401 401 def start(self):
402 402 #### stream mode:
403 403 if self.control_stream:
404 404 self.control_stream.on_recv(self.dispatch_control, copy=False)
405 405 self.control_stream.on_err(printer)
406
406
407 407 def make_dispatcher(stream):
408 408 def dispatcher(msg):
409 409 return self.dispatch_queue(stream, msg)
410 410 return dispatcher
411
411
412 412 for s in self.shell_streams:
413 413 s.on_recv(make_dispatcher(s), copy=False)
414 414 s.on_err(printer)
415
415
416 416 if self.iopub_stream:
417 417 self.iopub_stream.on_err(printer)
418
418
419 419 #### while True mode:
420 420 # while True:
421 421 # idle = True
@@ -428,7 +428,7 b' class Kernel(SessionFactory):'
428 428 # else:
429 429 # idle=False
430 430 # self.dispatch_queue(self.shell_stream, msg)
431 #
431 #
432 432 # if not self.task_stream.empty():
433 433 # idle=False
434 434 # msg = self.task_stream.recv_multipart()
@@ -56,7 +56,7 b' class NotDefined(KernelError):'
56 56
57 57 def __repr__(self):
58 58 return '<NotDefined: %s>' % self.name
59
59
60 60 __str__ = __repr__
61 61
62 62
@@ -175,35 +175,35 b' class RemoteError(KernelError):'
175 175 evalue=None
176 176 traceback=None
177 177 engine_info=None
178
178
179 179 def __init__(self, ename, evalue, traceback, engine_info=None):
180 180 self.ename=ename
181 181 self.evalue=evalue
182 182 self.traceback=traceback
183 183 self.engine_info=engine_info or {}
184 184 self.args=(ename, evalue)
185
185
186 186 def __repr__(self):
187 187 engineid = self.engine_info.get('engine_id', ' ')
188 188 return "<Remote[%s]:%s(%s)>"%(engineid, self.ename, self.evalue)
189
189
190 190 def __str__(self):
191 191 sig = "%s(%s)"%(self.ename, self.evalue)
192 192 if self.traceback:
193 193 return sig + '\n' + self.traceback
194 194 else:
195 195 return sig
196
196
197 197
198 198 class TaskRejectError(KernelError):
199 199 """Exception to raise when a task should be rejected by an engine.
200
200
201 201 This exception can be used to allow a task running on an engine to test
202 202 if the engine (or the user's namespace on the engine) has the needed
203 203 task dependencies. If not, the task should raise this exception. For
204 204 the task to be retried on another engine, the task should be created
205 205 with the `retries` argument > 1.
206
206
207 207 The advantage of this approach over our older properties system is that
208 208 tasks have full access to the user's namespace on the engines and the
209 209 properties don't have to be managed or tested by the controller.
@@ -240,7 +240,7 b' class CompositeError(RemoteError):'
240 240 engine_str = self._get_engine_str(ei)
241 241 s = s + '\n' + engine_str + en + ': ' + str(ev)
242 242 return s
243
243
244 244 def __repr__(self):
245 245 return "CompositeError(%i)"%len(self.elist)
246 246
@@ -258,7 +258,7 b' class CompositeError(RemoteError):'
258 258 else:
259 259 print (self._get_engine_str(ei))
260 260 print (etb or 'No traceback available')
261
261
262 262 def raise_exception(self, excid=0):
263 263 try:
264 264 en,ev,etb,ei = self.elist[excid]
@@ -280,7 +280,7 b" def collect_exceptions(rdict_or_list, method='unspecified'):"
280 280 if isinstance(r, RemoteError):
281 281 en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info
282 282 # Sometimes we could have CompositeError in our list. Just take
283 # the errors out of them and put them in our new list. This
283 # the errors out of them and put them in our new list. This
284 284 # has the effect of flattening lists of CompositeErrors into one
285 285 # CompositeError
286 286 if en=='CompositeError':
@@ -312,7 +312,7 b' def wrap_exception(engine_info={}):'
312 312 return exc_content
313 313
314 314 def unwrap_exception(content):
315 err = RemoteError(content['ename'], content['evalue'],
315 err = RemoteError(content['ename'], content['evalue'],
316 316 ''.join(content['traceback']),
317 317 content.get('engine_info', {}))
318 318 return err
@@ -61,7 +61,7 b' def pysh():'
61 61 """Pysh is a set of modules and extensions to IPython which make shell-like
62 62 usage with Python syntax more convenient. Keep in mind that pysh is NOT a
63 63 full-blown shell, so don't try to make it your /etc/passwd entry!
64
64
65 65 In particular, it has no job control, so if you type Ctrl-Z (under Unix),
66 66 you'll suspend pysh itself, not the process you just started.
67 67
@@ -72,7 +72,7 b' def pysh():'
72 72 ALIASES
73 73 -------
74 74 All of your $PATH has been loaded as IPython aliases, so you should be
75 able to type any normal system command and have it executed. See %alias?
75 able to type any normal system command and have it executed. See %alias?
76 76 and %unalias? for details on the alias facilities.
77 77
78 78 SPECIAL SYNTAX
@@ -139,7 +139,7 b' def pysh():'
139 139 sys.platform is: linux2
140 140
141 141 IPython's input history handling is still active, which allows you to
142 rerun a single block of multi-line input by simply using exec:
142 rerun a single block of multi-line input by simply using exec:
143 143 fperez[~/test]|14> $$alist = ls *.eps
144 144 fperez[~/test]|15> exec _i11
145 145 file image2.eps 921 image2.eps
@@ -155,7 +155,7 b' def pysh():'
155 155 automatically loaded. Some additional functions, useful for shell usage,
156 156 are listed below. You can request more help about them with '?'.
157 157
158 shell - execute a command in the underlying system shell
158 shell - execute a command in the underlying system shell
159 159 system - like shell(), but return the exit status of the command
160 160 sout - capture the output of a command as a string
161 161 lout - capture the output of a command as a list (split on '\\n')
@@ -180,7 +180,7 b' def pysh():'
180 180
181 181 PROMPT CUSTOMIZATION
182 182 --------------------
183
183
184 184 The supplied ipythonrc-pysh profile comes with an example of a very
185 185 colored and detailed prompt, mainly to serve as an illustration. The
186 186 valid escape sequences, besides color names, are:
@@ -7,14 +7,14 b' ip = ipapi.get()'
7 7
8 8 def clear_f(self,arg):
9 9 """ Clear various data (e.g. stored history data)
10
10
11 11 %clear in - clear input history
12 12 %clear out - clear output history
13 13 %clear shadow_compress - Compresses shadow history (to speed up ipython)
14 14 %clear shadow_nuke - permanently erase all entries in shadow history
15 15 %clear dhist - clear dir history
16 16 %clear array - clear only variables that are NumPy arrays
17
17
18 18 Examples:
19 19
20 20 In [1]: clear in
@@ -29,11 +29,11 b' def clear_f(self,arg):'
29 29 In [4]: clear dhist
30 30 Clearing directory history
31 31 """
32
32
33 33 api = self.getapi()
34 34 user_ns = self.user_ns # local lookup, heavily used
35
36
35
36
37 37 for target in arg.split():
38 38
39 39 if target == 'out':
@@ -50,7 +50,7 b' def clear_f(self,arg):'
50 50 del user_ns[key]
51 51 except: pass
52 52 # must be done in-place
53 self.history_manager.input_hist_parsed[:] = ['\n'] * pc
53 self.history_manager.input_hist_parsed[:] = ['\n'] * pc
54 54 self.history_manager.input_hist_raw[:] = ['\n'] * pc
55 55
56 56 elif target == 'array':
@@ -68,7 +68,7 b' def clear_f(self,arg):'
68 68 elif target == 'shadow_compress':
69 69 print "Compressing shadow history"
70 70 api.db.hcompress('shadowhist')
71
71
72 72 elif target == 'shadow_nuke':
73 73 print "Erased all keys from shadow history "
74 74 for k in ip.db.keys('shadowhist/*'):
@@ -78,7 +78,7 b' def clear_f(self,arg):'
78 78 print "Clearing directory history"
79 79 del user_ns['_dh'][:]
80 80
81 gc.collect()
81 gc.collect()
82 82
83 83 # Activate the extension
84 84 ip.define_magic("clear",clear_f)
@@ -9,7 +9,7 b' ip = ipapi.get()'
9 9
10 10 import os,sys
11 11
12 def restore_env(self):
12 def restore_env(self):
13 13 ip = self.getapi()
14 14 env = ip.db.get('stored_env', {'set' : {}, 'add' : [], 'pre' : []})
15 15 for k,v in env['set'].items():
@@ -19,51 +19,51 b' def restore_env(self):'
19 19 for k,v in env['pre']:
20 20 os.environ[k] = v + os.environ.get(k,"")
21 21 raise TryNext
22
22
23 23 ip.set_hook('late_startup_hook', restore_env)
24 24
25 25 def persist_env(self, parameter_s=''):
26 26 """ Store environment variables persistently
27
28 IPython remembers the values across sessions, which is handy to avoid
27
28 IPython remembers the values across sessions, which is handy to avoid
29 29 editing startup files.
30
30
31 31 %env - Show all environment variables
32 32 %env VISUAL=jed - set VISUAL to jed
33 33 %env PATH+=;/foo - append ;foo to PATH
34 34 %env PATH+=;/bar - also append ;bar to PATH
35 35 %env PATH-=/wbin; - prepend /wbin; to PATH
36 36 %env -d VISUAL - forget VISUAL persistent val
37 %env -p - print all persistent env modifications
37 %env -p - print all persistent env modifications
38 38 """
39
39
40 40 if not parameter_s.strip():
41 41 return os.environ.data
42
42
43 43 ip = self.getapi()
44 44 db = ip.db
45 45 env = ip.db.get('stored_env', {'set' : {}, 'add' : [], 'pre' : []})
46 46
47 47 if parameter_s.startswith('-p'):
48 48 return env
49
49
50 50 elif parameter_s.startswith('-d'):
51 51 parts = (parameter_s.split()[1], '<del>')
52
52
53 53 else:
54 parts = parameter_s.strip().split('=')
55
54 parts = parameter_s.strip().split('=')
55
56 56 if len(parts) == 2:
57 57 k,v = [p.strip() for p in parts]
58
58
59 59 if v == '<del>':
60 60 if k in env['set']:
61 61 del env['set'][k]
62 62 env['add'] = [el for el in env['add'] if el[0] != k]
63 63 env['pre'] = [el for el in env['pre'] if el[0] != k]
64
64
65 65 print "Forgot '%s' (for next session)" % k
66
66
67 67 elif k.endswith('+'):
68 68 k = k[:-1]
69 69 env['add'].append((k,v))
@@ -74,13 +74,13 b" def persist_env(self, parameter_s=''):"
74 74 env['pre'].append((k,v))
75 75 os.environ[k] = v + os.environ.get(k,"")
76 76 print k,"after prepend =",os.environ[k]
77
78
77
78
79 79 else:
80 80 env['set'][k] = v
81 81 print "Setting",k,"to",v
82 82 os.environ[k] = v
83
83
84 84 db['stored_env'] = env
85 85
86 86 def env_completer(self,event):
@@ -1,7 +1,7 b''
1 1 # -*- coding: utf-8 -*-
2 """ IPython extension: new prefilters for output grabbing
2 """ IPython extension: new prefilters for output grabbing
3 3
4 Provides
4 Provides
5 5
6 6 var = %magic blah blah
7 7
@@ -41,7 +41,7 b' def init_handlers():'
41 41 install_re_handler('(?P<varname>[\w\.]+)\s*=\s*%(?P<cmd>.*)',
42 42 hnd_magic
43 43 )
44
44
45 45 install_re_handler('(?P<varname>[\w\.]+)\s*=\s*!(?P<cmd>.*)',
46 46 hnd_syscmd
47 47 )
@@ -53,7 +53,7 b' def regex_prefilter_f(self,line):'
53 53 mo = pat.match(line)
54 54 if mo:
55 55 return handler(line,mo)
56
56
57 57 raise TryNext
58 58
59 ip.set_hook('input_prefilter', regex_prefilter_f)
59 ip.set_hook('input_prefilter', regex_prefilter_f)
@@ -82,7 +82,7 b' def bzr_commands():'
82 82 return __bzr_commands
83 83 out = os.popen('bzr help commands')
84 84 __bzr_commands = [l.split()[0] for l in out]
85 return __bzr_commands
85 return __bzr_commands
86 86
87 87 def bzr_completer(self,event):
88 88 """ Completer for bazaar commands """
@@ -113,8 +113,8 b' def apt_get_packages(prefix):'
113 113 for p in out:
114 114 if p.startswith(prefix):
115 115 yield p.rstrip()
116
117
116
117
118 118 apt_commands = """\
119 119 update upgrade install remove purge source build-dep dist-upgrade
120 120 dselect-upgrade clean autoclean check"""
@@ -18,15 +18,15 b" def indent(s, ind= ' '):"
18 18
19 19 class ExtUtil:
20 20 """ IPython extensios (ipy_* etc.) management utilities """
21
21
22 22 def describe(self):
23 23 for n,mod in self._active():
24 24 doc = inspect.getdoc(mod)
25 25 if doc:
26 26 print '== %s ==' % n
27 27 print indent(doc)
28
29
28
29
30 30 def ls(self):
31 31 """ Show list of installed extensions. """
32 32 for n,m in self._active():
@@ -37,8 +37,8 b' class ExtUtil:'
37 37 o = getattr(m, 'ip', None)
38 38 if isinstance(o, InteractiveShell):
39 39 act.append((mname,m))
40 act.sort()
40 act.sort()
41 41 return act
42 42
43 extutil = ExtUtil()
43 extutil = ExtUtil()
44 44 ip.push('extutil')
@@ -27,30 +27,30 b' import IPython.utils.generics'
27 27
28 28 def parse_args(args):
29 29 """ Given arg string 'CMD files... target', return ([files], target) """
30
30
31 31 tup = args.split(None, 1)
32 32 if len(tup) == 1:
33 33 raise UsageError("Expected arguments for " + tup[0])
34
34
35 35 tup2 = shlex.split(tup[1])
36
36
37 37 flist, trg = mglob.expand(tup2[0:-1]), tup2[-1]
38 38 if not flist:
39 39 raise UsageError("No files found:" + str(tup2[0:-1]))
40 40 return flist, trg
41
41
42 42 def icp(ip,arg):
43 43 """ icp files... targetdir
44
44
45 45 Copy all files to target, creating dirs for target if necessary
46
46
47 47 icp srcdir dstdir
48
48
49 49 Copy srcdir to distdir
50
50
51 51 """
52 52 import distutils.dir_util
53
53
54 54 fs, targetdir = parse_args(arg)
55 55 if not os.path.isdir(targetdir) and len(fs) > 1:
56 56 distutils.dir_util.mkpath(targetdir,verbose =1)
@@ -64,21 +64,21 b' ip.define_alias("icp",icp)'
64 64
65 65 def imv(ip,arg):
66 66 """ imv src tgt
67
67
68 68 Move source to target.
69 69 """
70
70
71 71 fs, target = parse_args(arg)
72 72 if len(fs) > 1:
73 73 assert os.path.isdir(target)
74 for f in fs:
74 for f in fs:
75 75 shutil.move(f, target)
76 76 return fs
77 ip.define_alias("imv",imv)
77 ip.define_alias("imv",imv)
78 78
79 79 def irm(ip,arg):
80 80 """ irm path[s]...
81
81
82 82 Remove file[s] or dir[s] path. Dirs are deleted recursively.
83 83 """
84 84 try:
@@ -97,24 +97,24 b' ip.define_alias("irm",irm)'
97 97
98 98 def imkdir(ip,arg):
99 99 """ imkdir path
100
100
101 101 Creates dir path, and all dirs on the road
102 102 """
103 103 import distutils.dir_util
104 104 targetdir = arg.split(None,1)[1]
105 distutils.dir_util.mkpath(targetdir,verbose =1)
105 distutils.dir_util.mkpath(targetdir,verbose =1)
106 106
107 ip.define_alias("imkdir",imkdir)
107 ip.define_alias("imkdir",imkdir)
108 108
109 109 def igrep(ip,arg):
110 110 """ igrep PAT files...
111
111
112 112 Very dumb file scan, case-insensitive.
113
113
114 114 e.g.
115
115
116 116 igrep "test this" rec:*.py
117
117
118 118 """
119 119 elems = shlex.split(arg)
120 120 dummy, pat, fs = elems[0], elems[1], mglob.expand(elems[2:])
@@ -130,19 +130,19 b' def igrep(ip,arg):'
130 130 print l.rstrip()
131 131 return res
132 132
133 ip.define_alias("igrep",igrep)
133 ip.define_alias("igrep",igrep)
134 134
135 135 def collect(ip,arg):
136 136 """ collect foo/a.txt rec:bar=*.py
137
137
138 138 Copies foo/a.txt to ~/_ipython/collect/foo/a.txt and *.py from bar,
139 139 likewise
140
140
141 141 Without args, try to open ~/_ipython/collect dir (in win32 at least).
142 142 """
143 143 from IPython.external.path import path
144 144 basedir = path(ip.ipython_dir + '/collect')
145 try:
145 try:
146 146 fs = mglob.expand(arg.split(None,1)[1])
147 147 except IndexError:
148 148 os.startfile(basedir)
@@ -160,23 +160,23 b' def collect(ip,arg):'
160 160 print f,"=>",trg
161 161 shutil.copy2(f,trg)
162 162
163 ip.define_alias("collect",collect)
163 ip.define_alias("collect",collect)
164 164
165 165 def inote(ip,arg):
166 166 """ inote Hello world
167
167
168 168 Adds timestamp and Hello world to ~/_ipython/notes.txt
169
169
170 170 Without args, opens notes.txt for editing.
171 171 """
172 172 import time
173 173 fname = ip.ipython_dir + '/notes.txt'
174
174
175 175 try:
176 176 entry = " === " + time.asctime() + ': ===\n' + arg.split(None,1)[1] + '\n'
177 f= open(fname, 'a').write(entry)
177 f= open(fname, 'a').write(entry)
178 178 except IndexError:
179 ip.hooks.editor(fname)
179 ip.hooks.editor(fname)
180 180
181 181 ip.define_alias("inote",inote)
182 182
@@ -186,7 +186,7 b' def pathobj_unmangle(s):'
186 186 return s.replace('__',' ').replace('DOT','.')
187 187
188 188
189
189
190 190 class PathObj(path):
191 191 def __init__(self,p):
192 192 self.path = p
@@ -205,7 +205,7 b' class PathObj(path):'
205 205 sep = ''
206 206 else:
207 207 sep = '/'
208
208
209 209 tgt = self.path + sep + pathobj_unmangle(name)
210 210 #print "tgt",tgt
211 211 if os.path.isdir(tgt):
@@ -216,15 +216,15 b' class PathObj(path):'
216 216 raise AttributeError, name # <<< DON'T FORGET THIS LINE !!
217 217 def __str__(self):
218 218 return self.path
219
219
220 220 def __repr__(self):
221 221 return "<PathObj to %s>" % self.path
222
222
223 223 def __call__(self):
224 224 print "cd:",self.path
225 225 os.chdir(self.path)
226
227 def complete_pathobj(obj, prev_completions):
226
227 def complete_pathobj(obj, prev_completions):
228 228 if hasattr(obj,'__complete__'):
229 229 res = obj.__complete__()
230 230 if res:
@@ -242,5 +242,5 b' def test_pathobj():'
242 242 startmenu = PathObj("d:/Documents and Settings/All Users/Start Menu/Programs")
243 243 cwd = PathObj('.')
244 244 ip.push("rootdir startmenu cwd")
245
245
246 246 #test_pathobj() No newline at end of file
@@ -7,7 +7,7 b' Stores variables in Struct with some notes in PicleShare database'
7 7
8 8 """
9 9
10 from datetime import datetime
10 from datetime import datetime
11 11 from IPython.core import ipapi
12 12 ip = ipapi.get()
13 13
@@ -15,7 +15,7 b' import pickleshare'
15 15
16 16 import inspect,pickle,os,sys,textwrap
17 17 from IPython.core.fakemodule import FakeModule
18 from IPython.utils.ipstruct import Struct
18 from IPython.utils.ipstruct import Struct
19 19 from IPython.utils.warn import error
20 20
21 21
@@ -43,7 +43,7 b' def refresh_variables(ip, key=None):'
43 43 print "Restored", justkey
44 44 else:
45 45 ip.user_ns[origname] = obj['val']
46 print "Restored", origname
46 print "Restored", origname
47 47
48 48 def read_variables(ip, key=None):
49 49 db = ip.db
@@ -54,7 +54,7 b' def read_variables(ip, key=None):'
54 54 for key in keys:
55 55 # strip autorestore
56 56 justkey = os.path.basename(key)
57 print "restoring from ", justkey
57 print "restoring from ", justkey
58 58 try:
59 59 obj = db[key]
60 60 except KeyError:
@@ -66,7 +66,7 b' def read_variables(ip, key=None):'
66 66
67 67 def detail_variables(ip, key=None):
68 68 db, get = ip.db, ip.db.get
69
69
70 70 if key is None:
71 71 keys = db.keys('jot/*')
72 72 else:
@@ -82,7 +82,7 b' def detail_variables(ip, key=None):'
82 82 for key in keys:
83 83 v = get(key,'<unavailable>')
84 84 justkey = os.path.basename(key)
85 try:
85 try:
86 86 print fmthead % (justkey, datetime.ctime(v.get('time','<unavailable>')))
87 87 print fmtbody % (v.get('comment','<unavailable>'))
88 88 d = v.get('val','unavailable')
@@ -105,7 +105,7 b" def jot_obj(self, obj, name, comment=''):"
105 105 write obj data to the note database, with whatever that should be noted.
106 106 """
107 107 had = self.db.keys('jot/'+name+'*')
108 # if it the same name but a later version, we stupidly add a number to the
108 # if it the same name but a later version, we stupidly add a number to the
109 109 # so the name doesn't collide. Any better idea?
110 110 suffix = ''
111 111 if len(had)>0:
@@ -116,47 +116,47 b" def jot_obj(self, obj, name, comment=''):"
116 116
117 117 uname = 'jot/'+name+suffix
118 118
119 # which one works better?
119 # which one works better?
120 120 #all = ip.shadowhist.all()
121 121 all = ip.shell.history_manager.input_hist_parsed
122 122
123 123 # We may actually want to make snapshot of files that are run-ned.
124 124
125 # get the comment
125 # get the comment
126 126 try:
127 127 comment = ip.magic_edit('-x').strip()
128 128 except:
129 129 print "No comment is recorded."
130 130 comment = ''
131 131
132 self.db[uname] = Struct({'val':obj,
133 'time' : datetime.now(),
132 self.db[uname] = Struct({'val':obj,
133 'time' : datetime.now(),
134 134 'hist' : all,
135 135 'name' : name,
136 136 'comment' : comment,})
137 137
138 138 print "Jotted down notes for '%s' (%s)" % (uname, obj.__class__.__name__)
139 139
140
140
141 141
142 142 def magic_jot(self, parameter_s=''):
143 143 """Lightweight persistence for python variables.
144 144
145 145 Example:
146
146
147 147 ville@badger[~]|1> A = ['hello',10,'world']\\
148 148 ville@badger[~]|2> %jot A\\
149 149 ville@badger[~]|3> Exit
150
150
151 151 (IPython session is closed and started again...)
152
152
153 153 ville@badger:~$ ipython -p pysh\\
154 154 ville@badger[~]|1> print A
155
155
156 156 ['hello', 10, 'world']
157
157
158 158 Usage:
159
159
160 160 %jot - Show list of all variables and their current values\\
161 161 %jot -l - Show list of all variables and their current values in detail\\
162 162 %jot -l <var> - Show one variable and its current values in detail\\
@@ -165,16 +165,16 b" def magic_jot(self, parameter_s=''):"
165 165 %jot -z - Remove all variables from storage (disabled)\\
166 166 %jot -r <var> - Refresh/Load variable from jot (delete current vals)\\
167 167 %jot foo >a.txt - Store value of foo to new file a.txt\\
168 %jot foo >>a.txt - Append value of foo to file a.txt\\
169
168 %jot foo >>a.txt - Append value of foo to file a.txt\\
169
170 170 It should be noted that if you change the value of a variable, you
171 171 need to %note it again if you want to persist the new value.
172
172
173 173 Note also that the variables will need to be pickleable; most basic
174 174 python types can be safely %stored.
175
175
176 176 """
177
177
178 178 opts,argsl = self.parse_options(parameter_s,'drzl',mode='string')
179 179 args = argsl.split(None,1)
180 180 ip = self.getapi()
@@ -214,30 +214,30 b" def magic_jot(self, parameter_s=''):"
214 214 else:
215 215 print "Details for", tolist, ":"
216 216 detail_variables(ip, tolist)
217
218 # run without arguments -> list noted variables & notes
217
218 # run without arguments -> list noted variables & notes
219 219 elif not args:
220 220 vars = self.db.keys('jot/*')
221 vars.sort()
221 vars.sort()
222 222 if vars:
223 size = max(map(len,vars)) - 4
223 size = max(map(len,vars)) - 4
224 224 else:
225 225 size = 0
226
226
227 227 print 'Variables and their in-db values:'
228 228 fmt = '%-'+str(size)+'s [%s] -> %s'
229 229 get = db.get
230 230 for var in vars:
231 231 justkey = os.path.basename(var)
232 232 v = get(var,'<unavailable>')
233 try:
233 try:
234 234 print fmt % (justkey,\
235 235 datetime.ctime(v.get('time','<unavailable>')),\
236 236 v.get('comment','<unavailable>')[:70].replace('\n',' '),)
237 237 except AttributeError:
238 238 print fmt % (justkey, '<unavailable>', '<unavailable>', repr(v)[:50])
239 239
240
240
241 241 # default action - store the variable
242 242 else:
243 243 # %store foo >file.txt or >>file.txt
@@ -251,7 +251,7 b" def magic_jot(self, parameter_s=''):"
251 251 print "Writing '%s' (%s) to file '%s'." % (args[0],
252 252 obj.__class__.__name__, fnam)
253 253
254
254
255 255 if not isinstance (obj,basestring):
256 256 from pprint import pprint
257 257 pprint(obj,fil)
@@ -259,10 +259,10 b" def magic_jot(self, parameter_s=''):"
259 259 fil.write(obj)
260 260 if not obj.endswith('\n'):
261 261 fil.write('\n')
262
262
263 263 fil.close()
264 264 return
265
265
266 266 # %note foo
267 267 try:
268 268 obj = ip.user_ns[args[0]]
@@ -270,18 +270,18 b" def magic_jot(self, parameter_s=''):"
270 270 # this should not be alias, for aliases, use %store
271 271 print
272 272 print "Error: %s doesn't exist." % args[0]
273 print
273 print
274 274 print "Use %note -r <var> to retrieve variables. This should not be used " +\
275 "to store alias, for saving aliases, use %store"
275 "to store alias, for saving aliases, use %store"
276 276 return
277 277 else:
278 278 if isinstance(inspect.getmodule(obj), FakeModule):
279 279 print textwrap.dedent("""\
280 Warning:%s is %s
280 Warning:%s is %s
281 281 Proper storage of interactively declared classes (or instances
282 282 of those classes) is not possible! Only instances
283 283 of classes in real modules on file system can be %%store'd.
284 """ % (args[0], obj) )
284 """ % (args[0], obj) )
285 285 return
286 286 #pickled = pickle.dumps(obj)
287 287 #self.db[ 'jot/' + args[0] ] = obj
@@ -289,11 +289,11 b" def magic_jot(self, parameter_s=''):"
289 289
290 290
291 291 def magic_read(self, parameter_s=''):
292 """
292 """
293 293 %read <var> - Load variable from data that is jotted down.\\
294
294
295 295 """
296
296
297 297 opts,argsl = self.parse_options(parameter_s,'drzl',mode='string')
298 298 args = argsl.split(None,1)
299 299 ip = self.getapi()
@@ -45,7 +45,7 b' def lookfor(what, modules=None, import_modules=True, regenerate=False):'
45 45 cache.update(c)
46 46 except ImportError:
47 47 pass
48
48
49 49 # Search
50 50 # XXX: maybe using a real stemming search engine would be better?
51 51 found = []
@@ -53,7 +53,7 b' def lookfor(what, modules=None, import_modules=True, regenerate=False):'
53 53 if not whats: return
54 54
55 55 for name, (docstring, kind, index) in cache.iteritems():
56 if kind in ('module', 'object'):
56 if kind in ('module', 'object'):
57 57 # don't show modules or objects
58 58 continue
59 59 ok = True
@@ -69,7 +69,7 b' def lookfor(what, modules=None, import_modules=True, regenerate=False):'
69 69 # XXX: this is full Harrison-Stetson heuristics now,
70 70 # XXX: it probably could be improved
71 71
72 kind_relevance = {'func': 1000, 'class': 1000,
72 kind_relevance = {'func': 1000, 'class': 1000,
73 73 'module': -1000, 'object': -1000}
74 74
75 75 def relevance(name, docstr, kind, index):
@@ -138,7 +138,7 b' def _lookfor_generate_cache(module, import_modules, regenerate):'
138 138 cache : dict {obj_full_name: (docstring, kind, index), ...}
139 139 Docstring cache for the module, either cached one (regenerate=False)
140 140 or newly generated.
141
141
142 142 """
143 143 global _lookfor_caches
144 144
@@ -164,7 +164,7 b' def _lookfor_generate_cache(module, import_modules, regenerate):'
164 164
165 165 index += 1
166 166 kind = "object"
167
167
168 168 if inspect.ismodule(item):
169 169 kind = "module"
170 170 try:
@@ -190,7 +190,7 b' def _lookfor_generate_cache(module, import_modules, regenerate):'
190 190 stack.append(("%s.%s" % (name, n), v))
191 191 elif callable(item):
192 192 kind = "func"
193
193
194 194 doc = inspect.getdoc(item)
195 195 if doc is not None:
196 196 cache[name] = (doc, kind, index)
@@ -4,9 +4,9 b''
4 4 Usage:
5 5
6 6 %rehashdir c:/bin c:/tools
7 - Add all executables under c:/bin and c:/tools to alias table, in
7 - Add all executables under c:/bin and c:/tools to alias table, in
8 8 order to make them directly executable from any directory.
9
9
10 10 This also serves as an example on how to extend ipython
11 11 with new magic functions.
12 12
@@ -23,27 +23,27 b' import os,re,fnmatch,sys'
23 23
24 24 def selflaunch(ip,line):
25 25 """ Launch python script with 'this' interpreter
26
26
27 27 e.g. d:\foo\ipykit.exe a.py
28
28
29 29 """
30
30
31 31 tup = line.split(None,1)
32 32 if len(tup) == 1:
33 33 print "Launching nested ipython session"
34 34 os.system(sys.executable)
35 35 return
36
36
37 37 cmd = sys.executable + ' ' + tup[1]
38 38 print ">",cmd
39 39 os.system(cmd)
40 40
41 41 class PyLauncher:
42 42 """ Invoke selflanucher on the specified script
43
43
44 44 This is mostly useful for associating with scripts using::
45 45 _ip.define_alias('foo',PyLauncher('foo_script.py'))
46
46
47 47 """
48 48 def __init__(self,script):
49 49 self.script = os.path.abspath(script)
@@ -57,22 +57,22 b' class PyLauncher:'
57 57 tail = ' ' + tup[1]
58 58 else:
59 59 tail = ''
60
60
61 61 selflaunch(ip,"py " + self.script + tail)
62 62 def __repr__(self):
63 63 return 'PyLauncher("%s")' % self.script
64 64
65 65 def rehashdir_f(self,arg):
66 66 """ Add executables in all specified dirs to alias table
67
67
68 68 Usage:
69 69
70 70 %rehashdir c:/bin;c:/tools
71 - Add all executables under c:/bin and c:/tools to alias table, in
71 - Add all executables under c:/bin and c:/tools to alias table, in
72 72 order to make them directly executable from any directory.
73
73
74 74 Without arguments, add all executables in current directory.
75
75
76 76 """
77 77
78 78 # most of the code copied from Magic.magic_rehashx
@@ -83,13 +83,13 b' def rehashdir_f(self,arg):'
83 83 if fnmatch.fnmatch(fname, j):
84 84 return True
85 85 return False
86
86
87 87 created = []
88 88 if not arg:
89 89 arg = '.'
90 90 path = map(os.path.abspath,arg.split(';'))
91 91 alias_table = self.shell.alias_manager.alias_table
92
92
93 93 if os.name == 'posix':
94 94 isexec = lambda fname:os.path.isfile(fname) and \
95 95 os.access(fname,os.X_OK)
@@ -101,7 +101,7 b' def rehashdir_f(self,arg):'
101 101 winext = 'exe|com|bat|py'
102 102 if 'py' not in winext:
103 103 winext += '|py'
104
104
105 105 execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE)
106 106 isexec = lambda fname:os.path.isfile(fname) and execre.match(fname)
107 107 savedir = os.getcwdu()
@@ -117,7 +117,7 b' def rehashdir_f(self,arg):'
117 117 # where N is the number of positional arguments of the
118 118 # alias.
119 119 src,tgt = os.path.splitext(ff)[0], os.path.abspath(ff)
120 created.append(src)
120 created.append(src)
121 121 alias_table[src] = (0,tgt)
122 122 else:
123 123 for pdir in path:
@@ -126,7 +126,7 b' def rehashdir_f(self,arg):'
126 126 if isexec(ff) and not isjunk(ff):
127 127 src, tgt = execre.sub(r'\1',ff), os.path.abspath(ff)
128 128 src = src.lower()
129 created.append(src)
129 created.append(src)
130 130 alias_table[src] = (0,tgt)
131 131 # Make sure the alias table doesn't contain keywords or builtins
132 132 self.shell.alias_table_validate()
@@ -11,7 +11,7 b' from IPython.external.Itpl import itplns'
11 11
12 12 def toclip_w32(s):
13 13 """ Places contents of s to clipboard
14
14
15 15 Needs pyvin32 to work:
16 16 http://sourceforge.net/projects/pywin32/
17 17 """
@@ -23,29 +23,29 b' def toclip_w32(s):'
23 23 cl.CloseClipboard()
24 24
25 25 try:
26 import win32clipboard
26 import win32clipboard
27 27 toclip = toclip_w32
28 28 except ImportError:
29 29 def toclip(s): pass
30
30
31 31
32 32 def render(tmpl):
33 33 """ Render a template (Itpl format) from ipython variables
34 34
35 35 Example:
36
36
37 37 $ import ipy_render
38 38 $ my_name = 'Bob' # %store this for convenience
39 39 $ t_submission_form = "Submission report, author: $my_name" # %store also
40 40 $ render t_submission_form
41
41
42 42 => returns "Submission report, author: Bob" and copies to clipboard on win32
43 43
44 44 # if template exist as a file, read it. Note: ;f hei vaan => f("hei vaan")
45 $ ;render c:/templates/greeting.txt
46
45 $ ;render c:/templates/greeting.txt
46
47 47 Template examples (Ka-Ping Yee's Itpl library):
48
48
49 49 Here is a $string.
50 50 Here is a $module.member.
51 51 Here is an $object.member.
@@ -54,10 +54,10 b' def render(tmpl):'
54 54 Here is an $array[3] member.
55 55 Here is a $dictionary['member'].
56 56 """
57
57
58 58 if os.path.isfile(tmpl):
59 59 tmpl = open(tmpl).read()
60
60
61 61 res = itplns(tmpl, ip.user_ns)
62 62 toclip(res)
63 63 return res
@@ -6,7 +6,7 b' import ipy_server'
6 6 ipy_server.serve_thread(16455)
7 7
8 8 Now, to execute the statements in this ipython instance, open a TCP socket
9 (port 16455), write out the statements, and close the socket.
9 (port 16455), write out the statements, and close the socket.
10 10 You can use e.g. "telnet localhost 16455" or a script to do this.
11 11
12 12 This is a bit like 'M-x server-start" or gnuserv in the emacs world.
@@ -17,27 +17,27 b' ip = ipapi.get()'
17 17
18 18 def new_ipsystem_posix(cmd):
19 19 """ ctrl+c ignoring replacement for system() command in iplib.
20
21 Ignore ctrl + c in IPython process during the command execution.
20
21 Ignore ctrl + c in IPython process during the command execution.
22 22 The subprocess will still get the ctrl + c signal.
23
23
24 24 posix implementation
25 25 """
26
26
27 27 p = subprocess.Popen(cmd, shell = True)
28
28
29 29 old_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
30 30 pid,status = os.waitpid(p.pid,0)
31 31 signal.signal(signal.SIGINT, old_handler)
32 32 if status and ip.options.verbose:
33 33 print "[exit status: %d]" % status
34
35 def new_ipsystem_win32(cmd):
34
35 def new_ipsystem_win32(cmd):
36 36 """ ctrl+c ignoring replacement for system() command in iplib.
37
38 Ignore ctrl + c in IPython process during the command execution.
37
38 Ignore ctrl + c in IPython process during the command execution.
39 39 The subprocess will still get the ctrl + c signal.
40
40
41 41 win32 implementation
42 42 """
43 43 old_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
@@ -45,8 +45,8 b' def new_ipsystem_win32(cmd):'
45 45 signal.signal(signal.SIGINT, old_handler)
46 46 if status and ip.options.verbose:
47 47 print "[exit status: %d]" % status
48
49
48
49
50 50 def init():
51 51 o = ip.options
52 52 try:
@@ -54,9 +54,8 b' def init():'
54 54 except AttributeError:
55 55 o.allow_new_attr (True )
56 56 o.verbose = 0
57
58 ip.system = (sys.platform == 'win32' and new_ipsystem_win32 or
57
58 ip.system = (sys.platform == 'win32' and new_ipsystem_win32 or
59 59 new_ipsystem_posix)
60
60
61 61 init()
62 No newline at end of file
@@ -3,7 +3,7 b''
3 3 This will be imported by ipython for all users.
4 4
5 5 After this ipy_user_conf.py is imported, user specific configuration
6 should reside there.
6 should reside there.
7 7
8 8 """
9 9
@@ -11,7 +11,7 b' from IPython.core import ipapi'
11 11 ip = ipapi.get()
12 12
13 13 # add system wide configuration information, import extensions etc. here.
14 # nothing here is essential
14 # nothing here is essential
15 15
16 16 import sys
17 17
@@ -3,8 +3,8 b''
3 3 Usage:
4 4
5 5 %wdb test.py
6 run test.py, with a winpdb breakpoint at start of the file
7
6 run test.py, with a winpdb breakpoint at start of the file
7
8 8 %wdb pass
9 9 Change the password (e.g. if you have forgotten the old one)
10 10
@@ -31,16 +31,16 b' rpdb_started = False'
31 31
32 32 def wdb_f(self, arg):
33 33 """ Debug a script (like %run -d) in IPython process, Using WinPdb
34
34
35 35 Usage:
36
36
37 37 %wdb test.py
38 run test.py, with a winpdb breakpoint at start of the file
39
38 run test.py, with a winpdb breakpoint at start of the file
39
40 40 %wdb pass
41 41 Change the password (e.g. if you have forgotten the old one)
42
43 Note that after the script has been run, you need to do "Go" (f5)
42
43 Note that after the script has been run, you need to do "Go" (f5)
44 44 in WinPdb to resume normal IPython operation.
45 45 """
46 46
@@ -48,15 +48,15 b' def wdb_f(self, arg):'
48 48 if not arg.strip():
49 49 print __doc__
50 50 return
51
51
52 52 if arg.strip() == 'pass':
53 53 passwd = raw_input('Enter new winpdb session password: ')
54 54 ip.db['winpdb_pass'] = passwd
55 55 print "Winpdb password changed"
56 56 if rpdb_started:
57 57 print "You need to restart IPython to use the new password"
58 return
59
58 return
59
60 60 path = os.path.abspath(arg)
61 61 if not os.path.isfile(path):
62 62 raise UsageError("%%wdb: file %s does not exist" % path)
@@ -66,19 +66,19 b' def wdb_f(self, arg):'
66 66 import textwrap
67 67 print textwrap.dedent("""\
68 68 Winpdb sessions need a password that you use for attaching the external
69 winpdb session. IPython will remember this. You can change the password later
69 winpdb session. IPython will remember this. You can change the password later
70 70 by '%wpdb pass'
71 71 """)
72 72 passwd = raw_input('Enter new winpdb session password: ')
73 73 ip.db['winpdb_pass'] = passwd
74
74
75 75 print "Starting rpdb2 in IPython process"
76 76 rpdb2.start_embedded_debugger(passwd, timeout = 0)
77 77 rpdb_started = True
78
78
79 79 rpdb2.set_temp_breakpoint(path)
80 80 print 'It is time to attach with WinPdb (launch WinPdb if needed, File -> Attach)'
81 81 ip.magic('%run ' + arg)
82
82
83 83
84 84 ip.define_magic('wdb', wdb_f)
@@ -5,14 +5,14 b' import os, subprocess'
5 5
6 6 workdir = None
7 7 def workdir_f(ip,line):
8 """ Exceute commands residing in cwd elsewhere
9
8 """ Exceute commands residing in cwd elsewhere
9
10 10 Example::
11
11
12 12 workdir /myfiles
13 13 cd bin
14 workdir myscript.py
15
14 workdir myscript.py
15
16 16 executes myscript.py (stored in bin, but not in path) in /myfiles
17 17 """
18 18 global workdir
@@ -1,4 +1,4 b''
1 """ Preliminary "job control" extensions for IPython
1 """ Preliminary "job control" extensions for IPython
2 2
3 3 requires python 2.4 (or separate 'subprocess' module
4 4
@@ -39,7 +39,7 b' Now launch a new IPython prompt and kill the process:'
39 39 [Q:/ipython]|4>
40 40
41 41 (you don't need to specify PID for %kill if only one task is running)
42 """
42 """
43 43
44 44 from subprocess import *
45 45 import os,shlex,sys,time
@@ -55,8 +55,8 b" if os.name == 'nt':"
55 55 else:
56 56 def kill_process(pid):
57 57 os.system('kill -9 %d' % pid)
58
59
58
59
60 60
61 61 class IpyPopen(Popen):
62 62 def go(self):
@@ -66,7 +66,7 b' class IpyPopen(Popen):'
66 66
67 67 def kill(self):
68 68 kill_process(self.pid)
69
69
70 70 def startjob(job):
71 71 p = IpyPopen(shlex.split(job), stdout=PIPE, shell = False)
72 72 p.line = job
@@ -85,7 +85,7 b' class AsyncJobQ(threading.Thread):'
85 85 self.output.append("** Discarding: '%s' - %s" % (cmd,cwd))
86 86 continue
87 87 self.output.append("** Task started: '%s' - %s" % (cmd,cwd))
88
88
89 89 p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd = cwd)
90 90 out = p.stdout.read()
91 91 self.output.append("** Task complete: '%s'\n" % cmd)
@@ -93,16 +93,16 b' class AsyncJobQ(threading.Thread):'
93 93
94 94 def add(self,cmd):
95 95 self.q.put_nowait((cmd, os.getcwdu()))
96
96
97 97 def dumpoutput(self):
98 98 while self.output:
99 99 item = self.output.pop(0)
100 print item
100 print item
101 101
102 102 _jobq = None
103 103
104 104 def jobqueue_f(self, line):
105
105
106 106 global _jobq
107 107 if not _jobq:
108 108 print "Starting jobqueue - do '&some_long_lasting_system_command' to enqueue"
@@ -118,11 +118,11 b' def jobqueue_f(self, line):'
118 118 if line.strip() == 'start':
119 119 _jobq.stop = False
120 120 return
121
122 def jobctrl_prefilter_f(self,line):
121
122 def jobctrl_prefilter_f(self,line):
123 123 if line.startswith('&'):
124 124 pre,fn,rest = self.split_user_input(line[1:])
125
125
126 126 line = ip.expand_aliases(fn,rest)
127 127 if not _jobq:
128 128 return 'get_ipython().startjob(%s)' % make_quoted_expr(line)
@@ -147,7 +147,7 b' def magic_tasks(self,line):'
147 147
148 148 A 'task' is a process that has been started in IPython when 'jobctrl' extension is enabled.
149 149 Tasks can be killed with %kill.
150
150
151 151 '%tasks clear' clears the task list (from stale tasks)
152 152 """
153 153 ip = self.getapi()
@@ -156,7 +156,7 b' def magic_tasks(self,line):'
156 156 print "Clearing",ip.db[k]
157 157 del ip.db[k]
158 158 return
159
159
160 160 ents = job_list(ip)
161 161 if not ents:
162 162 print "No tasks running"
@@ -181,19 +181,19 b' def magic_kill(self,line):'
181 181 else:
182 182 magic_tasks(self,line)
183 183 return
184
184
185 185 try:
186 186 pid = int(line)
187 187 kill_process(pid)
188 188 except ValueError:
189 189 magic_tasks(self,line)
190
190
191 191 if sys.platform == 'win32':
192 192 shell_internal_commands = 'break chcp cls copy ctty date del erase dir md mkdir path prompt rd rmdir start time type ver vol'.split()
193 193 PopenExc = WindowsError
194 194 else:
195 195 # todo linux commands
196 shell_internal_commands = []
196 shell_internal_commands = []
197 197 PopenExc = OSError
198 198
199 199
@@ -218,10 +218,10 b' def jobctrl_shellcmd(ip,cmd):'
218 218 else:
219 219 # have to go via shell, sucks
220 220 p = Popen(cmd,shell = True)
221
221
222 222 jobentry = 'tasks/t' + str(p.pid)
223 223 ip.db[jobentry] = (p.pid,cmd,os.getcwdu(),time.time())
224 p.communicate()
224 p.communicate()
225 225
226 226 finally:
227 227 if jobentry:
@@ -238,5 +238,5 b' def install():'
238 238 ip.define_magic('kill',magic_kill)
239 239 ip.define_magic('tasks',magic_tasks)
240 240 ip.define_magic('jobqueue',jobqueue_f)
241 ip.set_hook('pre_prompt_hook', jobq_output_hook)
241 ip.set_hook('pre_prompt_hook', jobq_output_hook)
242 242 install()
@@ -1,9 +1,9 b''
1 """ Fun magic line editor for ipython
1 """ Fun magic line editor for ipython
2 2
3 Use this to easily edit lists of strings gradually without crafting long
3 Use this to easily edit lists of strings gradually without crafting long
4 4 list comprehensions.
5 5
6 'l' is the magic variable name for every line (array element). Save the current
6 'l' is the magic variable name for every line (array element). Save the current
7 7 result (or more exactly, retrieve the last ipython computation result into
8 8 %led work area) by running '%led s'. Just run '%led' to show the current work
9 9 area data.
@@ -51,9 +51,9 b' curdata = []'
51 51
52 52 def line_edit_f(self, cmd ):
53 53 global curdata
54
54
55 55 if not cmd:
56
56
57 57 print "Magic line editor (for lists of strings)"
58 58 if curdata:
59 59 print "current data is:"
@@ -62,12 +62,12 b' def line_edit_f(self, cmd ):'
62 62 print "No current data, you should set it by running '%led s'"
63 63 print "When you have your data in _ (result of last computation)."
64 64 return
65
65
66 66 if cmd == 's':
67 67 curdata = ip.ev('_')
68 68 print "Data set from last result (_)"
69 69 newlines = curdata
70
70
71 71 else:
72 72 # simple method call, e.g. upper
73 73 if cmd.isalpha():
@@ -83,16 +83,16 b' def line_edit_f(self, cmd ):'
83 83 continue
84 84 newlines.append(l2)
85 85
86
86
87 87 return newlines
88 88
89 89 def line_edit_complete_f(self,event):
90 90 """ Show all string methods in completions """
91 91 if event.symbol.startswith('l.'):
92 92 return ['l.' + func for func in dir('')]
93
93
94 94 return dir('') + ['l.' + func for func in dir('')]
95 95
96 96 ip.set_hook('complete_command', line_edit_complete_f , str_key = '%led')
97
97
98 98 ip.define_magic('led', line_edit_f) No newline at end of file
@@ -36,56 +36,56 b' def refresh_variables(ip):'
36 36 else:
37 37 #print "restored",justkey,"=",obj #dbg
38 38 ip.user_ns[justkey] = obj
39
39
40 40
41 41 def restore_dhist(ip):
42 42 db = ip.db
43 43 ip.user_ns['_dh'] = db.get('dhist',[])
44
44
45 45 def restore_data(self):
46 46 ip = self.getapi()
47 47 refresh_variables(ip)
48 48 restore_aliases(self)
49 49 restore_dhist(self)
50 50 raise TryNext
51
51
52 52 ip.set_hook('late_startup_hook', restore_data)
53 53
54 54 def magic_store(self, parameter_s=''):
55 55 """Lightweight persistence for python variables.
56 56
57 57 Example:
58
58
59 59 ville@badger[~]|1> A = ['hello',10,'world']\\
60 60 ville@badger[~]|2> %store A\\
61 61 ville@badger[~]|3> Exit
62
62
63 63 (IPython session is closed and started again...)
64
64
65 65 ville@badger:~$ ipython -p pysh\\
66 66 ville@badger[~]|1> print A
67
67
68 68 ['hello', 10, 'world']
69
69
70 70 Usage:
71
71
72 72 %store - Show list of all variables and their current values\\
73 73 %store <var> - Store the *current* value of the variable to disk\\
74 74 %store -d <var> - Remove the variable and its value from storage\\
75 75 %store -z - Remove all variables from storage\\
76 76 %store -r - Refresh all variables from store (delete current vals)\\
77 77 %store foo >a.txt - Store value of foo to new file a.txt\\
78 %store foo >>a.txt - Append value of foo to file a.txt\\
79
78 %store foo >>a.txt - Append value of foo to file a.txt\\
79
80 80 It should be noted that if you change the value of a variable, you
81 81 need to %store it again if you want to persist the new value.
82
82
83 83 Note also that the variables will need to be pickleable; most basic
84 84 python types can be safely %stored.
85
85
86 86 Also aliases can be %store'd across sessions.
87 87 """
88
88
89 89 opts,argsl = self.parse_options(parameter_s,'drz',mode='string')
90 90 args = argsl.split(None,1)
91 91 ip = self.getapi()
@@ -109,16 +109,16 b" def magic_store(self, parameter_s=''):"
109 109 elif opts.has_key('r'):
110 110 refresh_variables(ip)
111 111
112
112
113 113 # run without arguments -> list variables & values
114 114 elif not args:
115 115 vars = self.db.keys('autorestore/*')
116 vars.sort()
116 vars.sort()
117 117 if vars:
118 118 size = max(map(len,vars))
119 119 else:
120 120 size = 0
121
121
122 122 print 'Stored variables and their in-db values:'
123 123 fmt = '%-'+str(size)+'s -> %s'
124 124 get = db.get
@@ -126,7 +126,7 b" def magic_store(self, parameter_s=''):"
126 126 justkey = os.path.basename(var)
127 127 # print 30 first characters from every var
128 128 print fmt % (justkey,repr(get(var,'<unavailable>'))[:50])
129
129
130 130 # default action - store the variable
131 131 else:
132 132 # %store foo >file.txt or >>file.txt
@@ -140,7 +140,7 b" def magic_store(self, parameter_s=''):"
140 140 print "Writing '%s' (%s) to file '%s'." % (args[0],
141 141 obj.__class__.__name__, fnam)
142 142
143
143
144 144 if not isinstance (obj,basestring):
145 145 from pprint import pprint
146 146 pprint(obj,fil)
@@ -148,10 +148,10 b" def magic_store(self, parameter_s=''):"
148 148 fil.write(obj)
149 149 if not obj.endswith('\n'):
150 150 fil.write('\n')
151
151
152 152 fil.close()
153 153 return
154
154
155 155 # %store foo
156 156 try:
157 157 obj = ip.user_ns[args[0]]
@@ -161,20 +161,20 b" def magic_store(self, parameter_s=''):"
161 161 if args[0] in self.alias_table:
162 162 staliases = db.get('stored_aliases',{})
163 163 staliases[ args[0] ] = self.alias_table[ args[0] ]
164 db['stored_aliases'] = staliases
164 db['stored_aliases'] = staliases
165 165 print "Alias stored:", args[0], self.alias_table[ args[0] ]
166 166 return
167 167 else:
168 168 raise UsageError("Unknown variable '%s'" % args[0])
169
169
170 170 else:
171 171 if isinstance(inspect.getmodule(obj), FakeModule):
172 172 print textwrap.dedent("""\
173 Warning:%s is %s
173 Warning:%s is %s
174 174 Proper storage of interactively declared classes (or instances
175 175 of those classes) is not possible! Only instances
176 176 of classes in real modules on file system can be %%store'd.
177 """ % (args[0], obj) )
177 """ % (args[0], obj) )
178 178 return
179 179 #pickled = pickle.dumps(obj)
180 180 self.db[ 'autorestore/' + args[0] ] = obj
@@ -11,12 +11,12 b" def clip_f( self, parameter_s = '' ):"
11 11 This function uses the same syntax as %macro for line extraction, but
12 12 instead of creating a macro it saves the resulting string to the
13 13 clipboard.
14
15 When used without arguments, this returns the text contents of the clipboard.
14
15 When used without arguments, this returns the text contents of the clipboard.
16 16 E.g.
17
17
18 18 mytext = %clip
19
19
20 20 """
21 21
22 22 import win32clipboard as cl
@@ -28,7 +28,7 b" def clip_f( self, parameter_s = '' ):"
28 28 cl.CloseClipboard()
29 29 return data
30 30 api = self.getapi()
31
31
32 32 if parameter_s.lstrip().startswith('='):
33 33 rest = parameter_s[parameter_s.index('=')+1:].strip()
34 34 val = str(api.ev(rest))
@@ -41,5 +41,5 b" def clip_f( self, parameter_s = '' ):"
41 41 cl.CloseClipboard()
42 42 print 'The following text was written to the clipboard'
43 43 print val
44
44
45 45 ip.define_magic( "clip", clip_f )
@@ -150,7 +150,7 b' def make_label_dec(label,ds=None):'
150 150 labels = [label]
151 151 else:
152 152 labels = label
153
153
154 154 # Validate that the given label(s) are OK for use in setattr() by doing a
155 155 # dry run on a dummy function.
156 156 tmp = lambda : None
@@ -162,12 +162,12 b' def make_label_dec(label,ds=None):'
162 162 for label in labels:
163 163 setattr(f,label,True)
164 164 return f
165
165
166 166 # Apply the user's docstring, or autogenerate a basic one
167 167 if ds is None:
168 168 ds = "Labels a test as %r." % label
169 169 decor.__doc__ = ds
170
170
171 171 return decor
172 172
173 173
@@ -179,11 +179,11 b' def skipif(skip_condition, msg=None):'
179 179
180 180 Parameters
181 181 ----------
182 skip_condition : bool or callable.
183 Flag to determine whether to skip test. If the condition is a
184 callable, it is used at runtime to dynamically make the decision. This
185 is useful for tests that may require costly imports, to delay the cost
186 until the test suite is actually executed.
182 skip_condition : bool or callable.
183 Flag to determine whether to skip test. If the condition is a
184 callable, it is used at runtime to dynamically make the decision. This
185 is useful for tests that may require costly imports, to delay the cost
186 until the test suite is actually executed.
187 187 msg : string
188 188 Message to give on raising a SkipTest exception
189 189
@@ -202,8 +202,8 b' def skipif(skip_condition, msg=None):'
202 202 '''
203 203
204 204 def skip_decorator(f):
205 # Local import to avoid a hard nose dependency and only incur the
206 # import time overhead at actual test-time.
205 # Local import to avoid a hard nose dependency and only incur the
206 # import time overhead at actual test-time.
207 207 import nose
208 208
209 209 # Allow for both boolean or callable skip conditions.
@@ -225,7 +225,7 b' def skipif(skip_condition, msg=None):'
225 225 if skip_val():
226 226 raise nose.SkipTest(get_msg(f,msg))
227 227 else:
228 return f(*args, **kwargs)
228 return f(*args, **kwargs)
229 229
230 230 def skipper_gen(*args, **kwargs):
231 231 """Skipper for test generators."""
@@ -240,7 +240,7 b' def skipif(skip_condition, msg=None):'
240 240 skipper = skipper_gen
241 241 else:
242 242 skipper = skipper_func
243
243
244 244 return nose.tools.make_decorator(f)(skipper)
245 245
246 246 return skip_decorator
@@ -38,20 +38,20 b' from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell'
38 38 class StreamProxy(io.IOStream):
39 39 """Proxy for sys.stdout/err. This will request the stream *at call time*
40 40 allowing for nose's Capture plugin's redirection of sys.stdout/err.
41
41
42 42 Parameters
43 43 ----------
44 44 name : str
45 45 The name of the stream. This will be requested anew at every call
46 46 """
47
47
48 48 def __init__(self, name):
49 49 self.name=name
50
50
51 51 @property
52 52 def stream(self):
53 53 return getattr(sys, self.name)
54
54
55 55 def flush(self):
56 56 self.stream.flush()
57 57
@@ -62,7 +62,7 b' class StreamProxy(io.IOStream):'
62 62 class py_file_finder(object):
63 63 def __init__(self,test_filename):
64 64 self.test_filename = test_filename
65
65
66 66 def __call__(self,name,win32=False):
67 67 from IPython.utils.path import get_py_filename
68 68 try:
@@ -71,7 +71,7 b' class py_file_finder(object):'
71 71 test_dir = os.path.dirname(self.test_filename)
72 72 new_path = os.path.join(test_dir,name)
73 73 return get_py_filename(new_path,win32=win32)
74
74
75 75
76 76 def _run_ns_sync(self,arg_s,runner=None):
77 77 """Modified version of %run that syncs testing namespaces.
@@ -94,7 +94,7 b' class ipnsdict(dict):'
94 94 which is needed because of how Python's doctest machinery operates with
95 95 '_'. See constructor and :meth:`update` for details.
96 96 """
97
97
98 98 def __init__(self,*a):
99 99 dict.__init__(self,*a)
100 100 self._savedict = {}
@@ -102,11 +102,11 b' class ipnsdict(dict):'
102 102 # remove a key named '_'. This is so that such a dict can be used as a
103 103 # namespace in doctests that call '_'.
104 104 self.protect_underscore = False
105
105
106 106 def clear(self):
107 107 dict.clear(self)
108 108 self.update(self._savedict)
109
109
110 110 def _checkpoint(self):
111 111 self._savedict.clear()
112 112 self._savedict.update(self)
@@ -132,7 +132,7 b' class ipnsdict(dict):'
132 132 # correct for that ourselves, to ensure consitency with the 'real'
133 133 # ipython.
134 134 self['__builtins__'] = builtin_mod
135
135
136 136 def __delitem__(self, key):
137 137 """Part of the test suite checks that we can release all
138 138 references to an object. So we need to make sure that we're not
@@ -177,7 +177,7 b' def start_ipython():'
177 177 if hasattr(start_ipython, 'already_called'):
178 178 return
179 179 start_ipython.already_called = True
180
180
181 181 # Store certain global objects that IPython modifies
182 182 _displayhook = sys.displayhook
183 183 _excepthook = sys.excepthook
@@ -187,16 +187,16 b' def start_ipython():'
187 187 config = tools.default_config()
188 188
189 189 # Create and initialize our test-friendly IPython instance.
190 shell = TerminalInteractiveShell.instance(config=config,
190 shell = TerminalInteractiveShell.instance(config=config,
191 191 user_ns=ipnsdict(),
192 192 user_global_ns={}
193 193 )
194 194
195 195 # A few more tweaks needed for playing nicely with doctests...
196
196
197 197 # remove history file
198 198 shell.tempfiles.append(config.HistoryManager.hist_file)
199
199
200 200 # These traps are normally only active for interactive use, set them
201 201 # permanently since we'll be mocking interactive sessions.
202 202 shell.builtin_trap.activate()
@@ -205,12 +205,12 b' def start_ipython():'
205 205 # can capture subcommands and print them to Python's stdout, otherwise the
206 206 # doctest machinery would miss them.
207 207 shell.system = py3compat.MethodType(xsys, shell)
208
208
209 209
210 210 shell._showtraceback = py3compat.MethodType(_showtraceback, shell)
211 211
212 212 # IPython is ready, now clean up some global state...
213
213
214 214 # Deactivate the various python system hooks added by ipython for
215 215 # interactive convenience so we don't confuse the doctest system
216 216 sys.modules['__main__'] = _main
@@ -224,7 +224,7 b' def start_ipython():'
224 224 get_ipython = _ip.get_ipython
225 225 builtin_mod._ip = _ip
226 226 builtin_mod.get_ipython = get_ipython
227
227
228 228 # To avoid extra IPython messages during testing, suppress io.stdout/stderr
229 229 io.stdout = StreamProxy('stdout')
230 230 io.stderr = StreamProxy('stderr')
@@ -88,18 +88,18 b' def extract_version(mod):'
88 88 def test_for(item, min_version=None, callback=extract_version):
89 89 """Test to see if item is importable, and optionally check against a minimum
90 90 version.
91
91
92 92 If min_version is given, the default behavior is to check against the
93 93 `__version__` attribute of the item, but specifying `callback` allows you to
94 94 extract the value you are interested in. e.g::
95
95
96 96 In [1]: import sys
97
97
98 98 In [2]: from IPython.testing.iptest import test_for
99
99
100 100 In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info)
101 101 Out[3]: True
102
102
103 103 """
104 104 try:
105 105 check = import_item(item)
@@ -112,7 +112,7 b' def test_for(item, min_version=None, callback=extract_version):'
112 112 if callback:
113 113 # extra processing step to get version to compare
114 114 check = callback(check)
115
115
116 116 return check >= min_version
117 117 else:
118 118 return True
@@ -156,7 +156,7 b' def report():'
156 156
157 157 avail = []
158 158 not_avail = []
159
159
160 160 for k, is_avail in have.items():
161 161 if is_avail:
162 162 avail.append(k)
@@ -172,7 +172,7 b' def report():'
172 172 out.append('\nTools and libraries NOT available at test time:\n')
173 173 not_avail.sort()
174 174 out.append(' ' + ' '.join(not_avail)+'\n')
175
175
176 176 return ''.join(out)
177 177
178 178
@@ -188,7 +188,7 b' def make_exclude():'
188 188 # Simple utility to make IPython paths more readably, we need a lot of
189 189 # these below
190 190 ipjoin = lambda *paths: pjoin('IPython', *paths)
191
191
192 192 exclusions = [ipjoin('external'),
193 193 pjoin('IPython_doctest_plugin'),
194 194 ipjoin('quarantine'),
@@ -207,7 +207,7 b' def make_exclude():'
207 207
208 208 if not have['wx']:
209 209 exclusions.append(ipjoin('lib', 'inputhookwx'))
210
210
211 211 # We do this unconditionally, so that the test suite doesn't import
212 212 # gtk, changing the default encoding and masking some unicode bugs.
213 213 exclusions.append(ipjoin('lib', 'inputhookgtk'))
@@ -229,7 +229,7 b' def make_exclude():'
229 229 exclusions.append(ipjoin('parallel'))
230 230 elif not have['qt']:
231 231 exclusions.append(ipjoin('frontend', 'qt'))
232
232
233 233 if not have['pymongo']:
234 234 exclusions.append(ipjoin('parallel', 'controller', 'mongodb'))
235 235 exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb'))
@@ -259,7 +259,7 b' class IPTester(object):'
259 259 call_args = None
260 260 #: list, process ids of subprocesses we start (for cleanup)
261 261 pids = None
262
262
263 263 def __init__(self, runner='iptest', params=None):
264 264 """Create new test runner."""
265 265 p = os.path
@@ -303,7 +303,7 b' class IPTester(object):'
303 303 retcode = subp.wait()
304 304 self.pids.pop()
305 305 return retcode
306
306
307 307 def run(self):
308 308 """Run the stored commands"""
309 309 try:
@@ -318,7 +318,7 b' class IPTester(object):'
318 318
319 319 if not hasattr(os, 'kill'):
320 320 return
321
321
322 322 for pid in self.pids:
323 323 try:
324 324 print 'Cleaning stale PID:', pid
@@ -326,7 +326,7 b' class IPTester(object):'
326 326 except OSError:
327 327 # This is just a best effort, if we fail or the process was
328 328 # really gone, ignore it.
329 pass
329 pass
330 330
331 331
332 332 def make_runners():
@@ -336,10 +336,10 b' def make_runners():'
336 336 # Packages to be tested via nose, that only depend on the stdlib
337 337 nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib',
338 338 'scripts', 'testing', 'utils', 'nbformat' ]
339
339
340 340 if have['zmq']:
341 341 nose_pkg_names.append('parallel')
342
342
343 343 # For debugging this code, only load quick stuff
344 344 #nose_pkg_names = ['core', 'extensions'] # dbg
345 345
@@ -348,29 +348,29 b' def make_runners():'
348 348
349 349 # Make runners
350 350 runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ]
351
351
352 352 return runners
353 353
354 354
355 355 def run_iptest():
356 356 """Run the IPython test suite using nose.
357
357
358 358 This function is called when this script is **not** called with the form
359 359 `iptest all`. It simply calls nose with appropriate command line flags
360 360 and accepts all of the standard nose arguments.
361 361 """
362 362
363 warnings.filterwarnings('ignore',
363 warnings.filterwarnings('ignore',
364 364 'This will be removed soon. Use IPython.testing.util instead')
365 365
366 366 argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks
367
367
368 368 # Loading ipdoctest causes problems with Twisted, but
369 369 # our test suite runner now separates things and runs
370 370 # all Twisted tests with trial.
371 371 '--with-ipdoctest',
372 372 '--ipdoctest-tests','--ipdoctest-extension=txt',
373
373
374 374 # We add --exe because of setuptools' imbecility (it
375 375 # blindly does chmod +x on ALL files). Nose does the
376 376 # right thing and it tries to avoid executables,
@@ -402,7 +402,7 b' def run_iptest():'
402 402
403 403 def run_iptestall():
404 404 """Run the entire IPython test suite by calling nose and trial.
405
405
406 406 This function constructs :class:`IPTester` instances for all IPython
407 407 modules and package and then runs each of them. This causes the modules
408 408 and packages of IPython to be tested each in their own subprocess using
@@ -45,7 +45,7 b' class IndentOut(object):'
45 45
46 46 Instances of this class trap output to a given stream and first reformat it
47 47 to indent every input line."""
48
48
49 49 def __init__(self,out=sys.stdout,indent=4):
50 50 """Create an indented writer.
51 51
@@ -57,7 +57,7 b' class IndentOut(object):'
57 57 - `indent` : int
58 58 Number of spaces to indent every input line by.
59 59 """
60
60
61 61 self.indent_text = ' '*indent
62 62 self.indent = re.compile('^',re.MULTILINE).sub
63 63 self.out = out
@@ -77,7 +77,7 b' class IndentOut(object):'
77 77 data = ''.join(self.buffer)
78 78 self.buffer[:] = []
79 79 self._write(self.indent(self.indent_text,data))
80
80
81 81 def close(self):
82 82 self.flush()
83 83 self._closed = True
@@ -96,7 +96,7 b' class RunnerFactory(object):'
96 96
97 97 def __init__(self,out=sys.stdout):
98 98 """Instantiate a code runner."""
99
99
100 100 self.out = out
101 101 self.runner = None
102 102 self.runnerClass = None
@@ -105,7 +105,7 b' class RunnerFactory(object):'
105 105 self.runnerClass = runnerClass
106 106 self.runner = runnerClass(out=self.out)
107 107 return self.runner
108
108
109 109 def __call__(self,fname):
110 110 """Return a runner for the given filename."""
111 111
@@ -199,7 +199,7 b' def main():'
199 199 outfile = open(outfname,'w')
200 200
201 201
202 # all output from included files will be indented
202 # all output from included files will be indented
203 203 indentOut = IndentOut(outfile,4)
204 204 getRunner = RunnerFactory(indentOut)
205 205
@@ -3,10 +3,10 b''
3 3 Limitations:
4 4
5 5 - When generating examples for use as doctests, make sure that you have
6 pretty-printing OFF. This can be done either by setting the
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
6 pretty-printing OFF. This can be done either by setting the
7 ``PlainTextFormatter.pprint`` option in your configuration file to False, or
8 8 by interactively disabling it with %Pprint. This is required so that IPython
9 output matches that of normal Python, which is used by doctest for internal
9 output matches that of normal Python, which is used by doctest for internal
10 10 execution.
11 11
12 12 - Do not rely on specific prompt numbers for results (such as using
@@ -68,7 +68,7 b' def is_extension_module(filename):'
68 68
69 69 class DocTestSkip(object):
70 70 """Object wrapper for doctests to be skipped."""
71
71
72 72 ds_skip = """Doctest to skip.
73 73 >>> 1 #doctest: +SKIP
74 74 """
@@ -166,13 +166,13 b' class DocTestFinder(doctest.DocTestFinder):'
166 166
167 167 class IPDoctestOutputChecker(doctest.OutputChecker):
168 168 """Second-chance checker with support for random tests.
169
169
170 170 If the default comparison doesn't pass, this checker looks in the expected
171 171 output string for flags that tell us to ignore the output.
172 172 """
173 173
174 174 random_re = re.compile(r'#\s*random\s+')
175
175
176 176 def check_output(self, want, got, optionflags):
177 177 """Check output, accepting special markers embedded in the output.
178 178
@@ -236,7 +236,7 b' class DocTestCase(doctests.DocTestCase):'
236 236 def runTest(self):
237 237 test = self._dt_test
238 238 runner = self._dt_runner
239
239
240 240 old = sys.stdout
241 241 new = StringIO()
242 242 optionflags = self._dt_optionflags
@@ -289,7 +289,7 b' class DocTestCase(doctests.DocTestCase):'
289 289 # Restore the behavior of the '_' key in the user namespace to
290 290 # normal after each doctest, so that unittests behave normally
291 291 _ip.user_ns.protect_underscore = False
292
292
293 293 # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but
294 294 # it does look like one to me: its tearDown method tries to run
295 295 #
@@ -376,7 +376,7 b' class IPDocTestParser(doctest.DocTestParser):'
376 376
377 377 # Mark tests to be executed in an external process - currently unsupported.
378 378 _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL')
379
379
380 380 def ip2py(self,source):
381 381 """Convert input IPython source into valid Python."""
382 382 out = []
@@ -459,7 +459,7 b' class IPDocTestParser(doctest.DocTestParser):'
459 459 # Append the random-output marker (it defaults to empty in most
460 460 # cases, it's only non-empty for 'all-random' tests):
461 461 want += random_marker
462
462
463 463 if Example is IPExternalExample:
464 464 options[doctest.NORMALIZE_WHITESPACE] = True
465 465 want += '\n'
@@ -569,7 +569,7 b" SKIP = doctest.register_optionflag('SKIP')"
569 569 class IPDocTestRunner(doctest.DocTestRunner,object):
570 570 """Test runner that synchronizes the IPython namespace with test globals.
571 571 """
572
572
573 573 def run(self, test, compileflags=None, out=None, clear_globs=True):
574 574
575 575 # Hack: ipython needs access to the execution context of the example,
@@ -582,7 +582,7 b' class IPDocTestRunner(doctest.DocTestRunner,object):'
582 582 #_ip._ipdoctest_test_filename = test.filename
583 583
584 584 test.globs.update(_ip.user_ns)
585
585
586 586 return super(IPDocTestRunner,self).run(test,
587 587 compileflags,out,clear_globs)
588 588
@@ -669,7 +669,7 b' class ExtensionDoctest(doctests.Doctest):'
669 669
670 670 def loadTestsFromModule(self, module):
671 671 #print '*** ipdoctest - lTM',module # dbg
672
672
673 673 if not self.matches(module.__name__):
674 674 log.debug("Doctest doesn't want module %s", module)
675 675 return
@@ -691,7 +691,7 b' class ExtensionDoctest(doctests.Doctest):'
691 691 continue
692 692 if not test.filename:
693 693 test.filename = module_file
694
694
695 695 yield DocTestCase(test,
696 696 optionflags=optionflags,
697 697 checker=self.checker)
@@ -26,7 +26,7 b' Notes:'
26 26 - running this script with python (it has a __main__ section at the end) misses
27 27 one docstring test, the one embedded in the Foo object method. Since our
28 28 approach relies on using decorators that create standalone TestCase
29 instances, it can only be used for functions, not for methods of objects.
29 instances, it can only be used for functions, not for methods of objects.
30 30 Authors
31 31 -------
32 32
@@ -66,8 +66,8 b' In [20]: print 1'
66 66
67 67 In [26]: for i in range(10):
68 68 ....: print i,
69 ....:
70 ....:
69 ....:
70 ....:
71 71 0 1 2 3 4 5 6 7 8 9
72 72
73 73 In [27]: 3+4
@@ -83,8 +83,8 b' def ipdt_indented_test():'
83 83
84 84 In [26]: for i in range(10):
85 85 ....: print i,
86 ....:
87 ....:
86 ....:
87 ....:
88 88 0 1 2 3 4 5 6 7 8 9
89 89
90 90 In [27]: 3+4
@@ -107,8 +107,8 b' class Foo(object):'
107 107
108 108 In [26]: for i in range(10):
109 109 ....: print i,
110 ....:
111 ....:
110 ....:
111 ....:
112 112 0 1 2 3 4 5 6 7 8 9
113 113
114 114 In [27]: 3+4
@@ -134,7 +134,7 b' def parse_test_output(txt):'
134 134 nerr = int(err_m.group(1))
135 135 nfail = 0
136 136 return nerr, nfail
137
137
138 138 fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE)
139 139 if fail_m:
140 140 nerr = 0
@@ -147,7 +147,7 b' def parse_test_output(txt):'
147 147 nerr = int(both_m.group(1))
148 148 nfail = int(both_m.group(2))
149 149 return nerr, nfail
150
150
151 151 # If the input didn't match any of these forms, assume no error/failures
152 152 return 0, 0
153 153
@@ -197,15 +197,15 b' def ipexec(fname, options=None):'
197 197 (stdout, stderr) of ipython subprocess.
198 198 """
199 199 if options is None: options = []
200
200
201 201 # For these subprocess calls, eliminate all prompt printing so we only see
202 202 # output from script execution
203 prompt_opts = [ '--InteractiveShell.prompt_in1=""',
204 '--InteractiveShell.prompt_in2=""',
203 prompt_opts = [ '--InteractiveShell.prompt_in1=""',
204 '--InteractiveShell.prompt_in2=""',
205 205 '--InteractiveShell.prompt_out=""'
206 206 ]
207 207 cmdargs = ' '.join(default_argv() + prompt_opts + options)
208
208
209 209 _ip = get_ipython()
210 210 test_dir = os.path.dirname(__file__)
211 211
@@ -256,7 +256,7 b" def ipexec_validate(fname, expected_out, expected_err='',"
256 256 """
257 257
258 258 import nose.tools as nt
259
259
260 260 out, err = ipexec(fname)
261 261 #print 'OUT', out # dbg
262 262 #print 'ERR', err # dbg
@@ -276,7 +276,7 b' class TempFileMixin(object):'
276 276 """Utility class to create temporary Python/IPython files.
277 277
278 278 Meant as a mixin class for test cases."""
279
279
280 280 def mktmp(self, src, ext='.py'):
281 281 """Make a valid python temp file."""
282 282 fname, f = temp_pyfile(src, ext)
@@ -303,16 +303,16 b' pair_fail_msg = ("Testing {0}\\n\\n"'
303 303 "Got:\n"
304 304 " {3!r}\n")
305 305 def check_pairs(func, pairs):
306 """Utility function for the common case of checking a function with a
306 """Utility function for the common case of checking a function with a
307 307 sequence of input/output pairs.
308
308
309 309 Parameters
310 310 ----------
311 311 func : callable
312 312 The function to be tested. Should accept a single argument.
313 313 pairs : iterable
314 314 A list of (input, expected_output) tuples.
315
315
316 316 Returns
317 317 -------
318 318 None. Raises an AssertionError if any output does not match the expected
@@ -20,7 +20,7 b' Hettinger. http://users.rcn.com/python/download/Descriptor.htm'
20 20
21 21 Notes
22 22 -----
23 This module is taken from the NiPy project
23 This module is taken from the NiPy project
24 24 (http://neuroimaging.scipy.org/site/index.html), and is BSD licensed.
25 25
26 26 Authors
@@ -57,7 +57,7 b' class ResetMixin(object):'
57 57 ... def y(self):
58 58 ... print '*** y computation executed ***'
59 59 ... return self.x / 2.0
60 ...
60 ...
61 61
62 62 >>> a = A(10)
63 63
@@ -70,7 +70,7 b' class ResetMixin(object):'
70 70
71 71 Changing x
72 72 >>> a.x = 20
73
73
74 74 a.y doesn't change to 10, since it is a static attribute:
75 75 >>> a.y
76 76 5.0
@@ -111,7 +111,7 b' class OneTimeProperty(object):'
111 111 Parameters
112 112 ----------
113 113 func : method
114
114
115 115 The method that will be called the first time to compute a value.
116 116 Afterwards, the method's name will be a standard attribute holding
117 117 the value of this computation.
@@ -150,7 +150,7 b' def auto_attr(func):'
150 150 ... @auto_attr
151 151 ... def a(self):
152 152 ... return 99
153 ...
153 ...
154 154 >>> x = MagicProp()
155 155 >>> 'a' in x.__dict__
156 156 False
@@ -3,7 +3,7 b''
3 3 """Utilities to enable code objects to be pickled.
4 4
5 5 Any process that import this module will be able to pickle code objects. This
6 includes the func_code attribute of any function. Once unpickled, new
6 includes the func_code attribute of any function. Once unpickled, new
7 7 functions can be built using new.function(code, globals()). Eventually
8 8 we need to automate all of this so that functions themselves can be pickled.
9 9
@@ -28,7 +28,7 b' import types, copy_reg'
28 28
29 29 def code_ctor(*args):
30 30 return types.CodeType(*args)
31
31
32 32 def reduce_code(co):
33 33 if co.co_freevars or co.co_cellvars:
34 34 raise ValueError("Sorry, cannot pickle code objects with closures")
@@ -19,7 +19,7 b' def make_color_table(in_class):'
19 19 """Build a set of color attributes in a class.
20 20
21 21 Helper function for building the *TermColors classes."""
22
22
23 23 color_templates = (
24 24 # Dark colors
25 25 ("Black" , "0;30"),
@@ -38,7 +38,7 b' def make_color_table(in_class):'
38 38 ("LightBlue" , "1;34"),
39 39 ("LightPurple" , "1;35"),
40 40 ("LightCyan" , "1;36"),
41 ("White" , "1;37"),
41 ("White" , "1;37"),
42 42 # Blinking colors. Probably should not be used in anything serious.
43 43 ("BlinkBlack" , "5;30"),
44 44 ("BlinkRed" , "5;31"),
@@ -56,13 +56,13 b' def make_color_table(in_class):'
56 56 class TermColors:
57 57 """Color escape sequences.
58 58
59 This class defines the escape sequences for all the standard (ANSI?)
59 This class defines the escape sequences for all the standard (ANSI?)
60 60 colors in terminals. Also defines a NoColor escape which is just the null
61 61 string, suitable for defining 'dummy' color schemes in terminals which get
62 62 confused by color escapes.
63 63
64 64 This class should be used as a mixin for building color schemes."""
65
65
66 66 NoColor = '' # for color schemes in color-less terminals.
67 67 Normal = '\033[0m' # Reset normal coloring
68 68 _base = '\033[%sm' # Template for all other colors
@@ -78,13 +78,13 b' class InputTermColors:'
78 78 can wrap lines accordingly. Use this class for any colored text which
79 79 needs to be used in input prompts, such as in calls to raw_input().
80 80
81 This class defines the escape sequences for all the standard (ANSI?)
81 This class defines the escape sequences for all the standard (ANSI?)
82 82 colors in terminals. Also defines a NoColor escape which is just the null
83 83 string, suitable for defining 'dummy' color schemes in terminals which get
84 84 confused by color escapes.
85 85
86 86 This class should be used as a mixin for building color schemes."""
87
87
88 88 NoColor = '' # for color schemes in color-less terminals.
89 89
90 90 if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs':
@@ -112,13 +112,13 b' class ColorScheme:'
112 112 if name is None:
113 113 name = self.name
114 114 return ColorScheme(name, self.colors.dict())
115
115
116 116 class ColorSchemeTable(dict):
117 117 """General class to handle tables of color schemes.
118 118
119 119 It's basically a dict of color schemes with a couple of shorthand
120 120 attributes and some convenient methods.
121
121
122 122 active_scheme_name -> obvious
123 123 active_colors -> actual color table of the active scheme"""
124 124
@@ -129,11 +129,11 b' class ColorSchemeTable(dict):'
129 129 created with a list of valid color schemes AND the specification for
130 130 the default active scheme.
131 131 """
132
132
133 133 # create object attributes to be set later
134 134 self.active_scheme_name = ''
135 135 self.active_colors = None
136
136
137 137 if scheme_list:
138 138 if default_scheme == '':
139 139 raise ValueError,'you must specify the default color scheme'
@@ -150,7 +150,7 b' class ColorSchemeTable(dict):'
150 150 if not isinstance(new_scheme,ColorScheme):
151 151 raise ValueError,'ColorSchemeTable only accepts ColorScheme instances'
152 152 self[new_scheme.name] = new_scheme
153
153
154 154 def set_active_scheme(self,scheme,case_sensitive=0):
155 155 """Set the currently active scheme.
156 156
@@ -41,7 +41,7 b' def complete_object(obj, prev_completions):'
41 41 List of attributes discovered so far.
42 42
43 43 This should return the list of attributes in obj. If you only wish to
44 add to the attributes already discovered normally, return
44 add to the attributes already discovered normally, return
45 45 own_attrs + prev_completions.
46 46 """
47 47 raise TryNext
@@ -34,7 +34,7 b' class Notifier(object):'
34 34
35 35 def _notify(self, title, msg):
36 36 if self.g_notifier is not None:
37 self.g_notifier.notify('core', title, msg)
37 self.g_notifier.notify('core', title, msg)
38 38
39 39 def notify(self, title, msg):
40 40 self._notify(title, msg)
@@ -32,13 +32,13 b' class IOStream:'
32 32 raise ValueError("fallback required, but not specified")
33 33 self.stream = stream
34 34 self._swrite = stream.write
35
35
36 36 # clone all methods not overridden:
37 37 def clone(meth):
38 38 return not hasattr(self, meth) and not meth.startswith('_')
39 39 for meth in filter(clone, dir(stream)):
40 40 setattr(self, meth, getattr(stream, meth))
41
41
42 42 def write(self,data):
43 43 try:
44 44 self._swrite(data)
@@ -52,7 +52,7 b' class IOStream:'
52 52 # if we get here, something is seriously broken.
53 53 print('ERROR - failed to write data to stream:', self.stream,
54 54 file=sys.stderr)
55
55
56 56 def writelines(self, lines):
57 57 if isinstance(lines, basestring):
58 58 lines = [lines]
@@ -66,7 +66,7 b' class IOStream:'
66 66 @property
67 67 def closed(self):
68 68 return self.stream.closed
69
69
70 70 def close(self):
71 71 pass
72 72
@@ -114,11 +114,11 b' class Tee(object):'
114 114 mode : optional, valid mode for open().
115 115 If a filename was give, open with this mode.
116 116
117 channel : str, one of ['stdout', 'stderr']
117 channel : str, one of ['stdout', 'stderr']
118 118 """
119 119 if channel not in ['stdout', 'stderr']:
120 120 raise ValueError('Invalid channel spec %s' % channel)
121
121
122 122 if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'):
123 123 self.file = file_or_name
124 124 else:
@@ -302,7 +302,7 b" def temp_pyfile(src, ext='.py'):"
302 302
303 303 def raw_print(*args, **kw):
304 304 """Raw print to sys.__stdout__, otherwise identical interface to print()."""
305
305
306 306 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
307 307 file=sys.__stdout__)
308 308 sys.__stdout__.flush()
@@ -310,7 +310,7 b' def raw_print(*args, **kw):'
310 310
311 311 def raw_print_err(*args, **kw):
312 312 """Raw print to sys.__stderr__, otherwise identical interface to print()."""
313
313
314 314 print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'),
315 315 file=sys.__stderr__)
316 316 sys.__stderr__.flush()
@@ -1,7 +1,7 b''
1 1 # encoding: utf-8
2 2 """A dict subclass that supports attribute style access.
3 3
4 Authors:
4 Authors:
5 5
6 6 * Fernando Perez (original)
7 7 * Brian Granger (refactoring to a dict subclass)
@@ -81,7 +81,7 b' class Struct(dict):'
81 81 ... s['b'] = 20
82 82 ... except KeyError:
83 83 ... print 'this is not allowed'
84 ...
84 ...
85 85 this is not allowed
86 86 """
87 87 if not self._allownew and not self.has_key(key):
@@ -92,7 +92,7 b' class Struct(dict):'
92 92 def __setattr__(self, key, value):
93 93 """Set an attr with protection of class members.
94 94
95 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
95 This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to
96 96 :exc:`AttributeError`.
97 97
98 98 Examples
@@ -106,13 +106,13 b' class Struct(dict):'
106 106 ... s.get = 10
107 107 ... except AttributeError:
108 108 ... print "you can't set a class member"
109 ...
109 ...
110 110 you can't set a class member
111 111 """
112 112 # If key is an str it might be a class member or instance var
113 113 if isinstance(key, str):
114 114 # I can't simply call hasattr here because it calls getattr, which
115 # calls self.__getattr__, which returns True for keys in
115 # calls self.__getattr__, which returns True for keys in
116 116 # self._data. But I only want keys in the class and in
117 117 # self.__dict__
118 118 if key in self.__dict__ or hasattr(Struct, key):
@@ -127,7 +127,7 b' class Struct(dict):'
127 127 def __getattr__(self, key):
128 128 """Get an attr by calling :meth:`dict.__getitem__`.
129 129
130 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
130 Like :meth:`__setattr__`, this method converts :exc:`KeyError` to
131 131 :exc:`AttributeError`.
132 132
133 133 Examples
@@ -142,7 +142,7 b' class Struct(dict):'
142 142 ... s.b
143 143 ... except AttributeError:
144 144 ... print "I don't have that key"
145 ...
145 ...
146 146 I don't have that key
147 147 """
148 148 try:
@@ -154,10 +154,10 b' class Struct(dict):'
154 154
155 155 def __iadd__(self, other):
156 156 """s += s2 is a shorthand for s.merge(s2).
157
157
158 158 Examples
159 159 --------
160
160
161 161 >>> s = Struct(a=10,b=30)
162 162 >>> s2 = Struct(a=20,c=40)
163 163 >>> s += s2
@@ -169,10 +169,10 b' class Struct(dict):'
169 169
170 170 def __add__(self,other):
171 171 """s + s2 -> New Struct made from s.merge(s2).
172
172
173 173 Examples
174 174 --------
175
175
176 176 >>> s1 = Struct(a=10,b=30)
177 177 >>> s2 = Struct(a=20,c=40)
178 178 >>> s = s1 + s2
@@ -185,10 +185,10 b' class Struct(dict):'
185 185
186 186 def __sub__(self,other):
187 187 """s1 - s2 -> remove keys in s2 from s1.
188
188
189 189 Examples
190 190 --------
191
191
192 192 >>> s1 = Struct(a=10,b=30)
193 193 >>> s2 = Struct(a=40)
194 194 >>> s = s1 - s2
@@ -201,10 +201,10 b' class Struct(dict):'
201 201
202 202 def __isub__(self,other):
203 203 """Inplace remove keys from self that are in other.
204
204
205 205 Examples
206 206 --------
207
207
208 208 >>> s1 = Struct(a=10,b=30)
209 209 >>> s2 = Struct(a=40)
210 210 >>> s1 -= s2
@@ -217,9 +217,9 b' class Struct(dict):'
217 217 return self
218 218
219 219 def __dict_invert(self, data):
220 """Helper function for merge.
220 """Helper function for merge.
221 221
222 Takes a dictionary whose values are lists and returns a dict with
222 Takes a dictionary whose values are lists and returns a dict with
223 223 the elements of each list as keys and the original keys as values.
224 224 """
225 225 outdict = {}
@@ -235,10 +235,10 b' class Struct(dict):'
235 235
236 236 def copy(self):
237 237 """Return a copy as a Struct.
238
238
239 239 Examples
240 240 --------
241
241
242 242 >>> s = Struct(a=10,b=30)
243 243 >>> s2 = s.copy()
244 244 >>> s2
@@ -304,14 +304,14 b' class Struct(dict):'
304 304
305 305 The `__conflict_solve` dict is a dictionary of binary functions which will be used to
306 306 solve key conflicts. Here is an example::
307
307
308 308 __conflict_solve = dict(
309 309 func1=['a','b','c'],
310 310 func2=['d','e']
311 311 )
312
312
313 313 In this case, the function :func:`func1` will be used to resolve
314 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
314 keys 'a', 'b' and 'c' and the function :func:`func2` will be used for
315 315 keys 'd' and 'e'. This could also be written as::
316 316
317 317 __conflict_solve = dict(func1='a b c',func2='d e')
@@ -344,15 +344,15 b' class Struct(dict):'
344 344 --------
345 345
346 346 This show the default policy:
347
347
348 348 >>> s = Struct(a=10,b=30)
349 349 >>> s2 = Struct(a=20,c=40)
350 350 >>> s.merge(s2)
351 351 >>> s
352 352 {'a': 10, 'c': 40, 'b': 30}
353
353
354 354 Now, show how to specify a conflict dict:
355
355
356 356 >>> s = Struct(a=10,b=30)
357 357 >>> s2 = Struct(a=20,b=40)
358 358 >>> conflict = {'update':'a','add':'b'}
@@ -1,7 +1,7 b''
1 1 """Simple utility for building a list of local IPs using the socket module.
2 2 This module defines two constants:
3 3
4 LOCALHOST : The loopback interface, or the first interface that points to this
4 LOCALHOST : The loopback interface, or the first interface that points to this
5 5 machine. It will *almost* always be '127.0.0.1'
6 6
7 7 LOCAL_IPS : A list of IP addresses, loopback first, that point to this machine.
@@ -29,7 +29,7 b' class NotificationError(Exception):'
29 29
30 30 class NotificationCenter(object):
31 31 """Synchronous notification center.
32
32
33 33 Examples
34 34 --------
35 35 Here is a simple example of how to use this::
@@ -83,9 +83,9 b' class NotificationCenter(object):'
83 83 "Notification type and sender are required.")
84 84
85 85 # If there are no registered observers for the type/sender pair
86 if((ntype not in self.registered_types and
86 if((ntype not in self.registered_types and
87 87 None not in self.registered_types) or
88 (sender not in self.registered_senders and
88 (sender not in self.registered_senders and
89 89 None not in self.registered_senders)):
90 90 return
91 91
@@ -110,11 +110,11 b' class NotificationCenter(object):'
110 110
111 111 def add_observer(self, callback, ntype, sender):
112 112 """Add an observer callback to this notification center.
113
113
114 114 The given callback will be called upon posting of notifications of
115 115 the given type/sender and will receive any additional arguments passed
116 116 to post_notification.
117
117
118 118 Parameters
119 119 ----------
120 120 callback : callable
@@ -131,12 +131,12 b' class NotificationCenter(object):'
131 131 self.registered_types.add(ntype)
132 132 self.registered_senders.add(sender)
133 133 self.observers.setdefault((ntype,sender), set()).add(callback)
134
134
135 135 def remove_all_observers(self):
136 136 """Removes all observers from this notification center"""
137
137
138 138 self._init_observers()
139
139
140 140
141 141
142 142 shared_center = NotificationCenter()
@@ -89,7 +89,7 b' def get_py_filename(name, force_win32=None):'
89 89
90 90 If the given name is not a file, it adds '.py' and searches again.
91 91 Raises IOError with an informative message if the file isn't found.
92
92
93 93 On Windows, apply Windows semantics to the filename. In particular, remove
94 94 any quoting that has been applied to it. This option can be forced for
95 95 testing purposes.
@@ -125,7 +125,7 b' def filefind(filename, path_dirs=None):'
125 125
126 126 Will find the file in the users home directory. This function does not
127 127 automatically try any paths, such as the cwd or the user's home directory.
128
128
129 129 Parameters
130 130 ----------
131 131 filename : str
@@ -136,30 +136,30 b' def filefind(filename, path_dirs=None):'
136 136 put into a sequence and the searched. If a sequence, walk through
137 137 each element and join with ``filename``, calling :func:`expandvars`
138 138 and :func:`expanduser` before testing for existence.
139
139
140 140 Returns
141 141 -------
142 142 Raises :exc:`IOError` or returns absolute path to file.
143 143 """
144
144
145 145 # If paths are quoted, abspath gets confused, strip them...
146 146 filename = filename.strip('"').strip("'")
147 147 # If the input is an absolute path, just check it exists
148 148 if os.path.isabs(filename) and os.path.isfile(filename):
149 149 return filename
150
150
151 151 if path_dirs is None:
152 152 path_dirs = ("",)
153 153 elif isinstance(path_dirs, basestring):
154 154 path_dirs = (path_dirs,)
155
155
156 156 for path in path_dirs:
157 157 if path == '.': path = os.getcwdu()
158 158 testname = expand_path(os.path.join(path, filename))
159 159 if os.path.isfile(testname):
160 160 return os.path.abspath(testname)
161
162 raise IOError("File %r does not exist in any of the search paths: %r" %
161
162 raise IOError("File %r does not exist in any of the search paths: %r" %
163 163 (filename, path_dirs) )
164 164
165 165
@@ -178,7 +178,7 b' def get_home_dir():'
178 178 - Registry hack for My Documents
179 179 - %HOME%: rare, but some people with unix-like setups may have defined it
180 180 * On Dos C:\
181
181
182 182 Currently only Posix and NT are implemented, a HomeDirError exception is
183 183 raised for all other OSes.
184 184 """
@@ -191,7 +191,7 b' def get_home_dir():'
191 191 if hasattr(sys, "frozen"): #Is frozen by py2exe
192 192 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
193 193 root, rest = IPython.__file__.lower().split('library.zip')
194 else:
194 else:
195 195 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
196 196 root=os.path.abspath(root).rstrip('\\')
197 197 if _writable_dir(os.path.join(root, '_ipython')):
@@ -208,7 +208,7 b' def get_home_dir():'
208 208 # still knows it - reported once as:
209 209 # https://github.com/ipython/ipython/issues/154
210 210 from subprocess import Popen, PIPE
211 homedir = Popen('echo $HOME', shell=True,
211 homedir = Popen('echo $HOME', shell=True,
212 212 stdout=PIPE).communicate()[0].strip()
213 213 if homedir:
214 214 return py3compat.cast_unicode(homedir, fs_encoding)
@@ -221,7 +221,7 b' def get_home_dir():'
221 221 # For some strange reason all of these return 'nt' for os.name.
222 222 # First look for a network home directory. This will return the UNC
223 223 # path (\\server\\Users\%username%) not the mapped path (Z:\). This
224 # is needed when running IPython on cluster where all paths have to
224 # is needed when running IPython on cluster where all paths have to
225 225 # be UNC.
226 226 try:
227 227 homedir = env['HOMESHARE']
@@ -284,36 +284,36 b' def get_home_dir():'
284 284
285 285 def get_xdg_dir():
286 286 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
287
287
288 288 This is only for posix (Linux,Unix,OS X, etc) systems.
289 289 """
290 290
291 291 env = os.environ
292
292
293 293 if os.name == 'posix':
294 294 # Linux, Unix, AIX, OS X
295 295 # use ~/.config if not set OR empty
296 296 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
297 297 if xdg and _writable_dir(xdg):
298 298 return py3compat.cast_unicode(xdg, fs_encoding)
299
299
300 300 return None
301
301
302 302
303 303 def get_ipython_dir():
304 304 """Get the IPython directory for this platform and user.
305
305
306 306 This uses the logic in `get_home_dir` to find the home directory
307 307 and then adds .ipython to the end of the path.
308 308 """
309
309
310 310 env = os.environ
311 311 pjoin = os.path.join
312
313
312
313
314 314 ipdir_def = '.ipython'
315 315 xdg_def = 'ipython'
316
316
317 317 home_dir = get_home_dir()
318 318 xdg_dir = get_xdg_dir()
319 319 # import pdb; pdb.set_trace() # dbg
@@ -324,18 +324,18 b' def get_ipython_dir():'
324 324 if xdg_dir:
325 325 # use XDG, as long as the user isn't already
326 326 # using $HOME/.ipython and *not* XDG/ipython
327
327
328 328 xdg_ipdir = pjoin(xdg_dir, xdg_def)
329
329
330 330 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
331 331 ipdir = xdg_ipdir
332
332
333 333 if ipdir is None:
334 334 # not using XDG
335 335 ipdir = home_ipdir
336 336
337 337 ipdir = os.path.normpath(os.path.expanduser(ipdir))
338
338
339 339 if os.path.exists(ipdir) and not _writable_dir(ipdir):
340 340 # ipdir exists, but is not writable
341 341 warn.warn("IPython dir '%s' is not a writable location,"
@@ -377,7 +377,7 b' def expand_path(s):'
377 377 """Expand $VARS and ~names in a string, like a shell
378 378
379 379 :Examples:
380
380
381 381 In [2]: os.environ['FOO']='test'
382 382
383 383 In [3]: expand_path('variable FOO is $FOO')
@@ -464,7 +464,7 b' def check_for_old_config(ipython_dir=None):'
464 464 else:
465 465 warn.warn("Found old IPython config file %r (modified by user)"%f)
466 466 warned = True
467
467
468 468 if warned:
469 469 warn.info("""
470 470 The IPython configuration system has changed as of 0.11, and these files will
@@ -2,16 +2,16 b''
2 2
3 3 """ PickleShare - a small 'shelve' like datastore with concurrency support
4 4
5 Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
6 shelve, many processes can access the database simultaneously. Changing a
7 value in database is immediately visible to other processes accessing the
5 Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike
6 shelve, many processes can access the database simultaneously. Changing a
7 value in database is immediately visible to other processes accessing the
8 8 same database.
9 9
10 10 Concurrency is possible because the values are stored in separate files. Hence
11 11 the "database" is a directory where *all* files are governed by PickleShare.
12 12
13 13 Example usage::
14
14
15 15 from pickleshare import *
16 16 db = PickleShareDB('~/testpickleshare')
17 17 db.clear()
@@ -22,8 +22,8 b' Example usage::'
22 22 print db.keys()
23 23 del db['aku ankka']
24 24
25 This module is certainly not ZODB, but can be used for low-load
26 (non-mission-critical) situations where tiny code size trumps the
25 This module is certainly not ZODB, but can be used for low-load
26 (non-mission-critical) situations where tiny code size trumps the
27 27 advanced features of a "real" object database.
28 28
29 29 Installation guide: easy_install pickleshare
@@ -53,7 +53,7 b' class PickleShareDB(collections.MutableMapping):'
53 53 self.root.makedirs()
54 54 # cache has { 'key' : (obj, orig_mod_time) }
55 55 self.cache = {}
56
56
57 57
58 58 def __getitem__(self,key):
59 59 """ db['key'] reading """
@@ -70,10 +70,10 b' class PickleShareDB(collections.MutableMapping):'
70 70 obj = pickle.load(fil.open())
71 71 except:
72 72 raise KeyError(key)
73
73
74 74 self.cache[fil] = (obj,mtime)
75 75 return obj
76
76
77 77 def __setitem__(self,key,value):
78 78 """ db['key'] = 5 """
79 79 fil = self.root / key
@@ -86,7 +86,7 b' class PickleShareDB(collections.MutableMapping):'
86 86 except OSError,e:
87 87 if e.errno != 2:
88 88 raise
89
89
90 90 def hset(self, hashroot, key, value):
91 91 """ hashed set """
92 92 hroot = self.root / hashroot
@@ -95,27 +95,27 b' class PickleShareDB(collections.MutableMapping):'
95 95 hfile = hroot / gethashfile(key)
96 96 d = self.get(hfile, {})
97 97 d.update( {key : value})
98 self[hfile] = d
98 self[hfile] = d
99
100
99 101
100
101
102 102 def hget(self, hashroot, key, default = _sentinel, fast_only = True):
103 103 """ hashed get """
104 104 hroot = self.root / hashroot
105 105 hfile = hroot / gethashfile(key)
106
106
107 107 d = self.get(hfile, _sentinel )
108 108 #print "got dict",d,"from",hfile
109 109 if d is _sentinel:
110 110 if fast_only:
111 111 if default is _sentinel:
112 112 raise KeyError(key)
113
113
114 114 return default
115
115
116 116 # slow mode ok, works even after hcompress()
117 117 d = self.hdict(hashroot)
118
118
119 119 return d.get(key, default)
120 120
121 121 def hdict(self, hashroot):
@@ -126,9 +126,9 b' class PickleShareDB(collections.MutableMapping):'
126 126 if last.endswith('xx'):
127 127 # print "using xx"
128 128 hfiles = [last] + hfiles[:-1]
129
129
130 130 all = {}
131
131
132 132 for f in hfiles:
133 133 # print "using",f
134 134 try:
@@ -136,17 +136,17 b' class PickleShareDB(collections.MutableMapping):'
136 136 except KeyError:
137 137 print "Corrupt",f,"deleted - hset is not threadsafe!"
138 138 del self[f]
139
139
140 140 self.uncache(f)
141
141
142 142 return all
143
143
144 144 def hcompress(self, hashroot):
145 145 """ Compress category 'hashroot', so hset is fast again
146
146
147 147 hget will fail if fast_only is True for compressed items (that were
148 148 hset before hcompress).
149
149
150 150 """
151 151 hfiles = self.keys(hashroot + "/*")
152 152 all = {}
@@ -154,16 +154,16 b' class PickleShareDB(collections.MutableMapping):'
154 154 # print "using",f
155 155 all.update(self[f])
156 156 self.uncache(f)
157
157
158 158 self[hashroot + '/xx'] = all
159 159 for f in hfiles:
160 160 p = self.root / f
161 161 if p.basename() == 'xx':
162 162 continue
163 163 p.remove()
164
165
166
164
165
166
167 167 def __delitem__(self,key):
168 168 """ del db["key"] """
169 169 fil = self.root / key
@@ -174,53 +174,53 b' class PickleShareDB(collections.MutableMapping):'
174 174 # notfound and permission denied are ok - we
175 175 # lost, the other process wins the conflict
176 176 pass
177
177
178 178 def _normalized(self, p):
179 179 """ Make a key suitable for user's eyes """
180 180 return str(self.root.relpathto(p)).replace('\\','/')
181
181
182 182 def keys(self, globpat = None):
183 183 """ All keys in DB, or all keys matching a glob"""
184
184
185 185 if globpat is None:
186 186 files = self.root.walkfiles()
187 187 else:
188 188 files = [Path(p) for p in glob.glob(self.root/globpat)]
189 189 return [self._normalized(p) for p in files if p.isfile()]
190
190
191 191 def __iter__(self):
192 192 return iter(keys)
193
193
194 194 def __len__(self):
195 195 return len(keys)
196 196
197 197 def uncache(self,*items):
198 198 """ Removes all, or specified items from cache
199
199
200 200 Use this after reading a large amount of large objects
201 201 to free up memory, when you won't be needing the objects
202 202 for a while.
203
203
204 204 """
205 205 if not items:
206 206 self.cache = {}
207 207 for it in items:
208 208 self.cache.pop(it,None)
209
209
210 210 def waitget(self,key, maxwaittime = 60 ):
211 211 """ Wait (poll) for a key to get a value
212
212
213 213 Will wait for `maxwaittime` seconds before raising a KeyError.
214 214 The call exits normally if the `key` field in db gets a value
215 215 within the timeout period.
216
216
217 217 Use this for synchronizing different processes or for ensuring
218 that an unfortunately timed "db['key'] = newvalue" operation
219 in another process (which causes all 'get' operation to cause a
220 KeyError for the duration of pickling) won't screw up your program
221 logic.
218 that an unfortunately timed "db['key'] = newvalue" operation
219 in another process (which causes all 'get' operation to cause a
220 KeyError for the duration of pickling) won't screw up your program
221 logic.
222 222 """
223
223
224 224 wtimes = [0.2] * 3 + [0.5] * 2 + [1]
225 225 tries = 0
226 226 waited = 0
@@ -230,24 +230,24 b' class PickleShareDB(collections.MutableMapping):'
230 230 return val
231 231 except KeyError:
232 232 pass
233
233
234 234 if waited > maxwaittime:
235 235 raise KeyError(key)
236
236
237 237 time.sleep(wtimes[tries])
238 238 waited+=wtimes[tries]
239 239 if tries < len(wtimes) -1:
240 240 tries+=1
241
241
242 242 def getlink(self,folder):
243 243 """ Get a convenient link for accessing items """
244 244 return PickleShareLink(self, folder)
245
245
246 246 def __repr__(self):
247 247 return "PickleShareDB('%s')" % self.root
248
249
250
248
249
250
251 251 class PickleShareLink:
252 252 """ A shortdand for accessing nested PickleShare data conveniently.
253 253
@@ -256,11 +256,11 b' class PickleShareLink:'
256 256 lnk = db.getlink('myobjects/test')
257 257 lnk.foo = 2
258 258 lnk.bar = lnk.foo + 5
259
259
260 260 """
261 def __init__(self, db, keydir ):
261 def __init__(self, db, keydir ):
262 262 self.__dict__.update(locals())
263
263
264 264 def __getattr__(self,key):
265 265 return self.__dict__['db'][self.__dict__['keydir']+'/' + key]
266 266 def __setattr__(self,key,val):
@@ -271,8 +271,8 b' class PickleShareLink:'
271 271 return "<PickleShareLink '%s': %s>" % (
272 272 self.__dict__['keydir'],
273 273 ";".join([Path(k).basename() for k in keys]))
274
275
274
275
276 276 def test():
277 277 db = PickleShareDB('~/testpickleshare')
278 278 db.clear()
@@ -308,22 +308,22 b' def stress():'
308 308
309 309 if j%33 == 0:
310 310 time.sleep(0.02)
311
311
312 312 db[str(j)] = db.get(str(j), []) + [(i,j,"proc %d" % os.getpid())]
313 313 db.hset('hash',j, db.hget('hash',j,15) + 1 )
314
314
315 315 print i,
316 316 sys.stdout.flush()
317 317 if i % 10 == 0:
318 318 db.uncache()
319
319
320 320 def main():
321 321 import textwrap
322 322 usage = textwrap.dedent("""\
323 pickleshare - manage PickleShare databases
324
323 pickleshare - manage PickleShare databases
324
325 325 Usage:
326
326
327 327 pickleshare dump /path/to/db > dump.txt
328 328 pickleshare load /path/to/db < dump.txt
329 329 pickleshare test /path/to/db
@@ -333,7 +333,7 b' def main():'
333 333 if len(sys.argv) < 2:
334 334 print usage
335 335 return
336
336
337 337 cmd = sys.argv[1]
338 338 args = sys.argv[2:]
339 339 if cmd == 'dump':
@@ -355,8 +355,8 b' def main():'
355 355 elif cmd == 'test':
356 356 test()
357 357 stress()
358
358
359 359 if __name__== "__main__":
360 360 main()
361
362
361
362
@@ -32,8 +32,8 b' class CannedObject(object):'
32 32 self.obj = copy.copy(obj)
33 33 for key in keys:
34 34 setattr(self.obj, key, can(getattr(obj, key)))
35
36
35
36
37 37 def getObject(self, g=None):
38 38 if g is None:
39 39 g = globals()
@@ -47,10 +47,10 b' class Reference(CannedObject):'
47 47 if not isinstance(name, basestring):
48 48 raise TypeError("illegal name: %r"%name)
49 49 self.name = name
50
50
51 51 def __repr__(self):
52 52 return "<Reference: %r>"%self.name
53
53
54 54 def getObject(self, g=None):
55 55 if g is None:
56 56 g = globals()
@@ -58,20 +58,20 b' class Reference(CannedObject):'
58 58 return g[self.name]
59 59 except KeyError:
60 60 raise NameError("name %r is not defined"%self.name)
61
61
62 62
63 63 class CannedFunction(CannedObject):
64
64
65 65 def __init__(self, f):
66 self._checkType(f)
66 self._checkType(f)
67 67 self.code = f.func_code
68 68 self.defaults = f.func_defaults
69 69 self.module = f.__module__ or '__main__'
70 70 self.__name__ = f.__name__
71
71
72 72 def _checkType(self, obj):
73 73 assert isinstance(obj, FunctionType), "Not a function type"
74
74
75 75 def getObject(self, g=None):
76 76 # try to load function back into its module:
77 77 if not self.module.startswith('__'):
@@ -81,7 +81,7 b' class CannedFunction(CannedObject):'
81 81 pass
82 82 else:
83 83 g = sys.modules[self.module].__dict__
84
84
85 85 if g is None:
86 86 g = globals()
87 87 newFunc = FunctionType(self.code, g, self.__name__, self.defaults)
@@ -40,7 +40,7 b' class FindCmdError(Exception):'
40 40
41 41 def find_cmd(cmd):
42 42 """Find absolute path to executable cmd in a cross platform manner.
43
43
44 44 This function tries to determine the full path to a command line program
45 45 using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the
46 46 time it will use the version that is first on the users `PATH`. If
@@ -49,7 +49,7 b' def find_cmd(cmd):'
49 49 Warning, don't use this to find IPython command line programs as there
50 50 is a risk you will find the wrong one. Instead find those using the
51 51 following code and looking for the application itself::
52
52
53 53 from IPython.utils.path import get_ipython_module_path
54 54 from IPython.utils.process import pycmd2argv
55 55 argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp'))
@@ -79,7 +79,7 b' def pycmd2argv(cmd):'
79 79 sure the right version is used.
80 80
81 81 For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe,
82 .com or .bat, and [, cmd] otherwise.
82 .com or .bat, and [, cmd] otherwise.
83 83
84 84 Parameters
85 85 ----------
@@ -97,7 +97,7 b' def pycmd2argv(cmd):'
97 97 if sys.platform == 'win32':
98 98 # The -u option here turns on unbuffered output, which is required
99 99 # on Win32 to prevent wierd conflict and problems with Twisted.
100 # Also, use sys.executable to make sure we are picking up the
100 # Also, use sys.executable to make sure we are picking up the
101 101 # right python exe.
102 102 return [sys.executable, '-u', cmd]
103 103 else:
@@ -20,21 +20,21 b' class StrDispatch(object):'
20 20 >>> print list(dis.flat_matches('hei'))
21 21 [123, 34, 686]
22 22 """
23
23
24 24 def __init__(self):
25 25 self.strs = {}
26 26 self.regexs = {}
27 27
28 28 def add_s(self, s, obj, priority= 0 ):
29 29 """ Adds a target 'string' for dispatching """
30
30
31 31 chain = self.strs.get(s, CommandChainDispatcher())
32 32 chain.add(obj,priority)
33 33 self.strs[s] = chain
34 34
35 35 def add_re(self, regex, obj, priority= 0 ):
36 36 """ Adds a target regexp for dispatching """
37
37
38 38 chain = self.regexs.get(regex, CommandChainDispatcher())
39 39 chain.add(obj,priority)
40 40 self.regexs[regex] = chain
@@ -43,23 +43,23 b' class StrDispatch(object):'
43 43 """ Get a seq of Commandchain objects that match key """
44 44 if key in self.strs:
45 45 yield self.strs[key]
46
46
47 47 for r, obj in self.regexs.items():
48 48 if re.match(r, key):
49 49 yield obj
50 else:
50 else:
51 51 #print "nomatch",key # dbg
52 52 pass
53 53
54 54 def __repr__(self):
55 55 return "<Strdispatch %s, %s>" % (self.strs, self.regexs)
56
56
57 57 def s_matches(self, key):
58 58 if key not in self.strs:
59 59 return
60 60 for el in self.strs[key]:
61 61 yield el[1]
62
62
63 63 def flat_matches(self, key):
64 64 """ Yield all 'value' targets, without priority """
65 65 for val in self.dispatch(key):
@@ -24,7 +24,7 b' from IPython.utils.notification import shared_center'
24 24
25 25 class Observer(object):
26 26
27 def __init__(self, expected_ntype, expected_sender,
27 def __init__(self, expected_ntype, expected_sender,
28 28 center=shared_center, *args, **kwargs):
29 29 super(Observer, self).__init__()
30 30 self.expected_ntype = expected_ntype
@@ -32,10 +32,10 b' class Observer(object):'
32 32 self.expected_args = args
33 33 self.expected_kwargs = kwargs
34 34 self.recieved = False
35 center.add_observer(self.callback,
36 self.expected_ntype,
35 center.add_observer(self.callback,
36 self.expected_ntype,
37 37 self.expected_sender)
38
38
39 39 def callback(self, ntype, sender, *args, **kwargs):
40 40 assert(ntype == self.expected_ntype or
41 41 self.expected_ntype == None)
@@ -44,10 +44,10 b' class Observer(object):'
44 44 assert(args == self.expected_args)
45 45 assert(kwargs == self.expected_kwargs)
46 46 self.recieved = True
47
47
48 48 def verify(self):
49 49 assert(self.recieved)
50
50
51 51 def reset(self):
52 52 self.recieved = False
53 53
@@ -74,7 +74,7 b' class NotificationTests(unittest.TestCase):'
74 74
75 75 def tearDown(self):
76 76 shared_center.remove_all_observers()
77
77
78 78 def test_notification_delivered(self):
79 79 """Test that notifications are delivered"""
80 80
@@ -100,7 +100,7 b' class NotificationTests(unittest.TestCase):'
100 100
101 101 def test_sender_specificity(self):
102 102 """Test that observers are registered by sender"""
103
103
104 104 expected_ntype = "EXPECTED_TYPE"
105 105 sender1 = Notifier(expected_ntype)
106 106 sender2 = Notifier(expected_ntype)
@@ -117,7 +117,7 b' class NotificationTests(unittest.TestCase):'
117 117 for i in xrange(10):
118 118 Observer('TYPE', None, center=shared_center)
119 119
120 self.assert_(len(shared_center.observers[('TYPE',None)]) >= 10,
120 self.assert_(len(shared_center.observers[('TYPE',None)]) >= 10,
121 121 "observers registered")
122 122
123 123 shared_center.remove_all_observers()
@@ -139,7 +139,7 b' class NotificationTests(unittest.TestCase):'
139 139 def test_post_performance(self):
140 140 """Test that post_notification, even with many registered irrelevant
141 141 observers is fast"""
142
142
143 143 for i in xrange(10):
144 144 Observer("UNRELATED_TYPE", None)
145 145
@@ -44,7 +44,7 b' except ImportError:'
44 44 import _winreg as wreg
45 45 #Add entries that needs to be stubbed by the testing code
46 46 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
47
47
48 48 try:
49 49 reload
50 50 except NameError: # Python 3
@@ -65,7 +65,7 b" IP_TEST_DIR = join(HOME_TEST_DIR,'.ipython')"
65 65
66 66 def setup():
67 67 """Setup testenvironment for the module:
68
68
69 69 - Adds dummy home dir tree
70 70 """
71 71 # Do not mask exceptions here. In particular, catching WindowsError is a
@@ -76,7 +76,7 b' def setup():'
76 76
77 77 def teardown():
78 78 """Teardown testenvironment for the module:
79
79
80 80 - Remove dummy home dir tree
81 81 """
82 82 # Note: we remove the parent test dir, which is the root of all test
@@ -86,10 +86,10 b' def teardown():'
86 86
87 87
88 88 def setup_environment():
89 """Setup testenvironment for some functions that are tested
89 """Setup testenvironment for some functions that are tested
90 90 in this module. In particular this functions stores attributes
91 91 and other things that we need to stub in some test functions.
92 This needs to be done on a function level and not module level because
92 This needs to be done on a function level and not module level because
93 93 each testfunction needs a pristine environment.
94 94 """
95 95 global oldstuff, platformstuff
@@ -105,7 +105,7 b' def teardown_environment():'
105 105 (oldenv, os.name, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
106 106 os.chdir(old_wd)
107 107 reload(path)
108
108
109 109 for key in env.keys():
110 110 if key not in oldenv:
111 111 del env[key]
@@ -125,10 +125,10 b' def test_get_home_dir_1():'
125 125 """Testcase for py2exe logic, un-compressed lib
126 126 """
127 127 sys.frozen = True
128
128
129 129 #fake filename for IPython.__init__
130 130 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
131
131
132 132 home_dir = path.get_home_dir()
133 133 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
134 134
@@ -141,7 +141,7 b' def test_get_home_dir_2():'
141 141 sys.frozen = True
142 142 #fake filename for IPython.__init__
143 143 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
144
144
145 145 home_dir = path.get_home_dir()
146 146 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())
147 147
@@ -158,9 +158,9 b' def test_get_home_dir_3():'
158 158 @with_environment
159 159 @skip_win32
160 160 def test_get_home_dir_4():
161 """Testcase $HOME is not set, os=='posix'.
161 """Testcase $HOME is not set, os=='posix'.
162 162 This should fail with HomeDirError"""
163
163
164 164 os.name = 'posix'
165 165 if 'HOME' in env: del env['HOME']
166 166 nt.assert_raises(path.HomeDirError, path.get_home_dir)
@@ -208,13 +208,13 b' def test_get_home_dir_7():'
208 208 home_dir = path.get_home_dir()
209 209 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
210 210
211
211
212 212 # Should we stub wreg fully so we can run the test on all platforms?
213 213 @skip_if_not_win32
214 214 @with_environment
215 215 def test_get_home_dir_8():
216 216 """Using registry hack for 'My Documents', os=='nt'
217
217
218 218 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
219 219 """
220 220 os.name = 'nt'
@@ -333,7 +333,7 b' def test_get_xdg_dir_1():'
333 333 env.pop('IPYTHON_DIR', None)
334 334 env.pop('IPYTHONDIR', None)
335 335 env.pop('XDG_CONFIG_HOME', None)
336
336
337 337 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
338 338
339 339
@@ -359,7 +359,7 b' def test_get_xdg_dir_2():'
359 359 env.pop('XDG_CONFIG_HOME', None)
360 360 cfgdir=os.path.join(path.get_home_dir(), '.config')
361 361 os.makedirs(cfgdir)
362
362
363 363 nt.assert_equal(path.get_xdg_dir(), cfgdir)
364 364
365 365 def test_filefind():
@@ -384,7 +384,7 b' def test_get_ipython_module_path():'
384 384 @dec.skip_if_not_win32
385 385 def test_get_long_path_name_win32():
386 386 p = path.get_long_path_name('c:\\docume~1')
387 nt.assert_equals(p,u'c:\\Documents and Settings')
387 nt.assert_equals(p,u'c:\\Documents and Settings')
388 388
389 389
390 390 @dec.skip_win32
@@ -75,7 +75,7 b' class TestTraitType(TestCase):'
75 75 return -1
76 76 class A(HasTraitsStub):
77 77 tt = MyTT
78
78
79 79 a = A()
80 80 a.tt = 10
81 81 self.assertEquals(a.tt, -1)
@@ -393,7 +393,7 b' class TestHasTraits(TestCase):'
393 393 traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
394 394 self.assertEquals(traits, dict(i=A.i))
395 395
396 # This passes, but it shouldn't because I am replicating a bug in
396 # This passes, but it shouldn't because I am replicating a bug in
397 397 # traits.
398 398 traits = a.traits(config_key=lambda v: True)
399 399 self.assertEquals(traits, dict(i=A.i, f=A.f, j=A.j))
@@ -432,7 +432,7 b' class TestType(TestCase):'
432 432 class C(object): pass
433 433 class A(HasTraits):
434 434 klass = Type(B)
435
435
436 436 a = A()
437 437 self.assertEquals(a.klass, B)
438 438 self.assertRaises(TraitError, setattr, a, 'klass', C)
@@ -486,7 +486,7 b' class TestType(TestCase):'
486 486 a = A()
487 487 a.klass = Struct
488 488 self.assertEquals(a.klass, Struct)
489
489
490 490 self.assertRaises(TraitError, setattr, a, 'klass', 10)
491 491
492 492 class TestInstance(TestCase):
@@ -495,7 +495,7 b' class TestInstance(TestCase):'
495 495 class Foo(object): pass
496 496 class Bar(Foo): pass
497 497 class Bah(object): pass
498
498
499 499 class A(HasTraits):
500 500 inst = Instance(Foo)
501 501
@@ -547,7 +547,7 b' class TestInstance(TestCase):'
547 547
548 548 class A(HasTraits):
549 549 inst = Instance(Foo, allow_none=False)
550
550
551 551 self.assertRaises(TraitError, A)
552 552
553 553 def test_instance(self):
@@ -556,7 +556,7 b' class TestInstance(TestCase):'
556 556 def inner():
557 557 class A(HasTraits):
558 558 inst = Instance(Foo())
559
559
560 560 self.assertRaises(TraitError, inner)
561 561
562 562
@@ -576,7 +576,7 b' class TestThis(TestCase):'
576 576 def test_this_inst(self):
577 577 class Foo(HasTraits):
578 578 this = This()
579
579
580 580 f = Foo()
581 581 f.this = Foo()
582 582 self.assert_(isinstance(f.this, Foo))
@@ -696,7 +696,7 b' class TestComplex(TraitTestBase):'
696 696 obj = ComplexTrait()
697 697
698 698 _default_value = 99.0-99.0j
699 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
699 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
700 700 10.1j, 10.1+10.1j, 10.1-10.1j]
701 701 _bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
702 702
@@ -725,7 +725,7 b' class TestUnicode(TraitTestBase):'
725 725 obj = UnicodeTrait()
726 726
727 727 _default_value = u'unicode'
728 _good_values = ['10', '-10', '10L', '-10L', '10.1',
728 _good_values = ['10', '-10', '10L', '-10L', '10.1',
729 729 '-10.1', '', u'', 'string', u'string', u"€"]
730 730 _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
731 731 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
@@ -733,10 +733,10 b' class TestUnicode(TraitTestBase):'
733 733
734 734 class ObjectNameTrait(HasTraits):
735 735 value = ObjectName("abc")
736
736
737 737 class TestObjectName(TraitTestBase):
738 738 obj = ObjectNameTrait()
739
739
740 740 _default_value = "abc"
741 741 _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"]
742 742 _bad_values = [1, "", u"€", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]",
@@ -752,7 +752,7 b' class DottedObjectNameTrait(HasTraits):'
752 752
753 753 class TestDottedObjectName(TraitTestBase):
754 754 obj = DottedObjectNameTrait()
755
755
756 756 _default_value = "a.b"
757 757 _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"]
758 758 _bad_values = [1, u"abc.€", "_.@", ".", ".abc", "abc.", ".abc."]
@@ -39,7 +39,7 b' from IPython.utils.data import flatten'
39 39 # won't need to make changes all over IPython.
40 40 def getdefaultencoding():
41 41 """Return IPython's guess for the default encoding for bytes as text.
42
42
43 43 Asks for stdin.encoding first, to match the calling Terminal, but that
44 44 is often None for subprocesses. Fall back on locale.getpreferredencoding()
45 45 which should be a sensible platform default (that respects LANG environment),
@@ -124,8 +124,8 b' class LSString(str):'
124 124 # """ Prettier (non-repr-like) and more informative printer for LSString """
125 125 # print "LSString (.p, .n, .l, .s available). Value:"
126 126 # print arg
127 #
128 #
127 #
128 #
129 129 # print_lsstring = result_display.when_type(LSString)(print_lsstring)
130 130
131 131
@@ -283,9 +283,9 b' class SList(list):'
283 283 # if hasattr(arg, 'hideonce') and arg.hideonce:
284 284 # arg.hideonce = False
285 285 # return
286 #
286 #
287 287 # nlprint(arg)
288 #
288 #
289 289 # print_slist = result_display.when_type(SList)(print_slist)
290 290
291 291
@@ -421,10 +421,10 b' def indent(instr,nspaces=4, ntabs=0, flatten=False):'
421 421 """Indent a string a given number of spaces or tabstops.
422 422
423 423 indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces.
424
424
425 425 Parameters
426 426 ----------
427
427
428 428 instr : basestring
429 429 The string to be indented.
430 430 nspaces : int (default: 4)
@@ -435,12 +435,12 b' def indent(instr,nspaces=4, ntabs=0, flatten=False):'
435 435 Whether to scrub existing indentation. If True, all lines will be
436 436 aligned to the same indentation. If False, existing indentation will
437 437 be strictly increased.
438
438
439 439 Returns
440 440 -------
441
441
442 442 str|unicode : string indented by ntabs and nspaces.
443
443
444 444 """
445 445 if instr is None:
446 446 return
@@ -547,25 +547,25 b' def format_screen(strng):'
547 547
548 548 def dedent(text):
549 549 """Equivalent of textwrap.dedent that ignores unindented first line.
550
550
551 551 This means it will still dedent strings like:
552 552 '''foo
553 553 is a bar
554 554 '''
555
555
556 556 For use in wrap_paragraphs.
557 557 """
558
558
559 559 if text.startswith('\n'):
560 560 # text starts with blank line, don't ignore the first line
561 561 return textwrap.dedent(text)
562
562
563 563 # split first line
564 564 splits = text.split('\n',1)
565 565 if len(splits) == 1:
566 566 # only one line
567 567 return textwrap.dedent(text)
568
568
569 569 first, rest = splits
570 570 # dedent everything but the first line
571 571 rest = textwrap.dedent(rest)
@@ -573,13 +573,13 b' def dedent(text):'
573 573
574 574 def wrap_paragraphs(text, ncols=80):
575 575 """Wrap multiple paragraphs to fit a specified width.
576
576
577 577 This is equivalent to textwrap.wrap, but with support for multiple
578 578 paragraphs, as separated by empty lines.
579
579
580 580 Returns
581 581 -------
582
582
583 583 list of complete paragraphs, wrapped to fill `ncols` columns.
584 584 """
585 585 paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE)
@@ -588,42 +588,42 b' def wrap_paragraphs(text, ncols=80):'
588 588 out_ps = []
589 589 indent_re = re.compile(r'\n\s+', re.MULTILINE)
590 590 for p in paragraphs:
591 # presume indentation that survives dedent is meaningful formatting,
591 # presume indentation that survives dedent is meaningful formatting,
592 592 # so don't fill unless text is flush.
593 593 if indent_re.search(p) is None:
594 594 # wrap paragraph
595 595 p = textwrap.fill(p, ncols)
596 596 out_ps.append(p)
597 597 return out_ps
598
598
599 599
600 600
601 601 class EvalFormatter(Formatter):
602 602 """A String Formatter that allows evaluation of simple expressions.
603
603
604 604 Any time a format key is not found in the kwargs,
605 605 it will be tried as an expression in the kwargs namespace.
606
606
607 607 This is to be used in templating cases, such as the parallel batch
608 608 script templates, where simple arithmetic on arguments is useful.
609
609
610 610 Examples
611 611 --------
612
612
613 613 In [1]: f = EvalFormatter()
614 614 In [2]: f.format('{n//4}', n=8)
615 615 Out[2]: '2'
616
616
617 617 In [3]: f.format('{list(range(3))}')
618 618 Out[3]: '[0, 1, 2]'
619 619
620 620 In [4]: f.format('{3*2}')
621 621 Out[4]: '6'
622 622 """
623
623
624 624 # should we allow slicing by disabling the format_spec feature?
625 625 allow_slicing = True
626
626
627 627 # copied from Formatter._vformat with minor changes to allow eval
628 628 # and replace the format_spec code with slicing
629 629 def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
@@ -677,7 +677,7 b" def columnize(items, separator=' ', displaywidth=80):"
677 677
678 678 displaywidth : int, optional [default is 80]
679 679 Width of the display in number of characters.
680
680
681 681 Returns
682 682 -------
683 683 The formatted string.
@@ -687,7 +687,7 b" def columnize(items, separator=' ', displaywidth=80):"
687 687
688 688 # Some degenerate cases.
689 689 size = len(items)
690 if size == 0:
690 if size == 0:
691 691 return '\n'
692 692 elif size == 1:
693 693 return '%s\n' % items[0]
@@ -715,9 +715,9 b" def columnize(items, separator=' ', displaywidth=80):"
715 715 colwidth = max(colwidth, len_x)
716 716 colwidths.append(colwidth)
717 717 totwidth += colwidth + len(separator)
718 if totwidth > displaywidth:
718 if totwidth > displaywidth:
719 719 break
720 if totwidth <= displaywidth:
720 if totwidth <= displaywidth:
721 721 break
722 722
723 723 # The smallest number of rows computed and the max widths for each
@@ -58,7 +58,7 b' try:'
58 58 ClassTypes = (ClassType, type)
59 59 except:
60 60 ClassTypes = (type,)
61
61
62 62 from .importstring import import_item
63 63 from IPython.utils import py3compat
64 64
@@ -119,10 +119,10 b' def repr_type(obj):'
119 119
120 120 def parse_notifier_name(name):
121 121 """Convert the name argument to a list of names.
122
122
123 123 Examples
124 124 --------
125
125
126 126 >>> parse_notifier_name('a')
127 127 ['a']
128 128 >>> parse_notifier_name(['a','b'])
@@ -153,7 +153,7 b' class _SimpleTest:'
153 153 def getmembers(object, predicate=None):
154 154 """A safe version of inspect.getmembers that handles missing attributes.
155 155
156 This is useful when there are descriptor based attributes that for
156 This is useful when there are descriptor based attributes that for
157 157 some reason raise AttributeError even though they exist. This happens
158 158 in zope.inteface with the __provides__ attribute.
159 159 """
@@ -192,7 +192,7 b' class TraitType(object):'
192 192 This is used by the :class:`This` trait to allow subclasses to
193 193 accept superclasses for :class:`This` values.
194 194 """
195
195
196 196
197 197 metadata = {}
198 198 default_value = Undefined
@@ -231,7 +231,7 b' class TraitType(object):'
231 231 created.
232 232
233 233 This method trigger the creation and validation of default values
234 and also things like the resolution of str given class names in
234 and also things like the resolution of str given class names in
235 235 :class:`Type` and :class`Instance`.
236 236
237 237 Parameters
@@ -246,7 +246,7 b' class TraitType(object):'
246 246 """Set the default value on a per instance basis.
247 247
248 248 This method is called by :meth:`instance_init` to create and
249 validate the default value. The creation and validation of
249 validate the default value. The creation and validation of
250 250 default values must be delayed until the parent :class:`HasTraits`
251 251 class has been instantiated.
252 252 """
@@ -270,7 +270,7 b' class TraitType(object):'
270 270 """Get the value of the trait by self.name for the instance.
271 271
272 272 Default values are instantiated when :meth:`HasTraits.__new__`
273 is called. Thus by the time this method gets called either the
273 is called. Thus by the time this method gets called either the
274 274 default value or a user defined value (they called :meth:`__set__`)
275 275 is in the :class:`HasTraits` instance.
276 276 """
@@ -347,14 +347,14 b' class TraitType(object):'
347 347
348 348 class MetaHasTraits(type):
349 349 """A metaclass for HasTraits.
350
350
351 351 This metaclass makes sure that any TraitType class attributes are
352 352 instantiated and sets their name attribute.
353 353 """
354
354
355 355 def __new__(mcls, name, bases, classdict):
356 356 """Create the HasTraits class.
357
357
358 358 This instantiates all TraitTypes in the class dict and sets their
359 359 :attr:`name` attribute.
360 360 """
@@ -373,7 +373,7 b' class MetaHasTraits(type):'
373 373
374 374 def __init__(cls, name, bases, classdict):
375 375 """Finish initializing the HasTraits class.
376
376
377 377 This sets the :attr:`this_class` attribute of each TraitType in the
378 378 class dict to the newly created class ``cls``.
379 379 """
@@ -398,7 +398,7 b' class HasTraits(object):'
398 398 inst._trait_notifiers = {}
399 399 inst._trait_dyn_inits = {}
400 400 # Here we tell all the TraitType instances to set their default
401 # values on the instance.
401 # values on the instance.
402 402 for key in dir(cls):
403 403 # Some descriptors raise AttributeError like zope.interface's
404 404 # __provides__ attributes even though they exist. This causes
@@ -462,7 +462,7 b' class HasTraits(object):'
462 462 else:
463 463 raise TraitError('a trait changed callback '
464 464 'must be callable.')
465
465
466 466
467 467 def _add_notifiers(self, handler, name):
468 468 if not self._trait_notifiers.has_key(name):
@@ -487,17 +487,17 b' class HasTraits(object):'
487 487 """Setup a handler to be called when a trait changes.
488 488
489 489 This is used to setup dynamic notifications of trait changes.
490
490
491 491 Static handlers can be created by creating methods on a HasTraits
492 492 subclass with the naming convention '_[traitname]_changed'. Thus,
493 493 to create static handler for the trait 'a', create the method
494 494 _a_changed(self, name, old, new) (fewer arguments can be used, see
495 495 below).
496
496
497 497 Parameters
498 498 ----------
499 499 handler : callable
500 A callable that is called when a trait changes. Its
500 A callable that is called when a trait changes. Its
501 501 signature can be handler(), handler(name), handler(name, new)
502 502 or handler(name, old, new).
503 503 name : list, str, None
@@ -651,12 +651,12 b' class Type(ClassBasedTraitType):'
651 651 default_value : class, str or None
652 652 The default value must be a subclass of klass. If an str,
653 653 the str must be a fully specified class name, like 'foo.bar.Bah'.
654 The string is resolved into real class, when the parent
654 The string is resolved into real class, when the parent
655 655 :class:`HasTraits` class is instantiated.
656 656 klass : class, str, None
657 657 Values of this trait must be a subclass of klass. The klass
658 658 may be specified in a string like: 'foo.bar.MyClass'.
659 The string is resolved into real class, when the parent
659 The string is resolved into real class, when the parent
660 660 :class:`HasTraits` class is instantiated.
661 661 allow_none : boolean
662 662 Indicates whether None is allowed as an assignable value. Even if
@@ -725,11 +725,11 b' class DefaultValueGenerator(object):'
725 725
726 726 class Instance(ClassBasedTraitType):
727 727 """A trait whose value must be an instance of a specified class.
728
728
729 729 The value can also be an instance of a subclass of the specified class.
730 730 """
731 731
732 def __init__(self, klass=None, args=None, kw=None,
732 def __init__(self, klass=None, args=None, kw=None,
733 733 allow_none=True, **metadata ):
734 734 """Construct an Instance trait.
735 735
@@ -754,7 +754,7 b' class Instance(ClassBasedTraitType):'
754 754 -------------
755 755 If both ``args`` and ``kw`` are None, then the default value is None.
756 756 If ``args`` is a tuple and ``kw`` is a dict, then the default is
757 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
757 created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is
758 758 not (but not both), None is replace by ``()`` or ``{}``.
759 759 """
760 760
@@ -764,7 +764,7 b' class Instance(ClassBasedTraitType):'
764 764 raise TraitError('The klass argument must be a class'
765 765 ' you gave: %r' % klass)
766 766 self.klass = klass
767
767
768 768 # self.klass is a class, so handle default_value
769 769 if args is None and kw is None:
770 770 default_value = None
@@ -775,12 +775,12 b' class Instance(ClassBasedTraitType):'
775 775 elif kw is None:
776 776 # args is not None
777 777 kw = {}
778
778
779 779 if not isinstance(kw, dict):
780 780 raise TraitError("The 'kw' argument must be a dict or None.")
781 781 if not isinstance(args, tuple):
782 782 raise TraitError("The 'args' argument must be a tuple or None.")
783
783
784 784 default_value = DefaultValueGenerator(*args, **kw)
785 785
786 786 super(Instance, self).__init__(default_value, **metadata)
@@ -817,7 +817,7 b' class Instance(ClassBasedTraitType):'
817 817
818 818 def get_default_value(self):
819 819 """Instantiate a default value instance.
820
820
821 821 This is called when the containing HasTraits classes'
822 822 :meth:`__new__` method is called to ensure that a unique instance
823 823 is created for each HasTraits instance.
@@ -833,7 +833,7 b' class This(ClassBasedTraitType):'
833 833 """A trait for instances of the class containing this trait.
834 834
835 835 Because how how and when class bodies are executed, the ``This``
836 trait can only have a default value of None. This, and because we
836 trait can only have a default value of None. This, and because we
837 837 always validate default values, ``allow_none`` is *always* true.
838 838 """
839 839
@@ -1002,18 +1002,18 b' class CUnicode(Unicode):'
1002 1002 return unicode(value)
1003 1003 except:
1004 1004 self.error(obj, value)
1005
1006
1005
1006
1007 1007 class ObjectName(TraitType):
1008 1008 """A string holding a valid object name in this version of Python.
1009
1009
1010 1010 This does not check that the name exists in any scope."""
1011 1011 info_text = "a valid object identifier in Python"
1012 1012
1013 1013 if py3compat.PY3:
1014 1014 # Python 3:
1015 1015 coerce_str = staticmethod(lambda _,s: s)
1016
1016
1017 1017 else:
1018 1018 # Python 2:
1019 1019 def coerce_str(self, obj, value):
@@ -1024,10 +1024,10 b' class ObjectName(TraitType):'
1024 1024 except UnicodeEncodeError:
1025 1025 self.error(obj, value)
1026 1026 return value
1027
1027
1028 1028 def validate(self, obj, value):
1029 1029 value = self.coerce_str(obj, value)
1030
1030
1031 1031 if isinstance(value, str) and py3compat.isidentifier(value):
1032 1032 return value
1033 1033 self.error(obj, value)
@@ -1036,7 +1036,7 b' class DottedObjectName(ObjectName):'
1036 1036 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1037 1037 def validate(self, obj, value):
1038 1038 value = self.coerce_str(obj, value)
1039
1039
1040 1040 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
1041 1041 return value
1042 1042 self.error(obj, value)
@@ -1360,7 +1360,7 b' class Dict(Instance):'
1360 1360 def __init__(self, default_value=None, allow_none=True, **metadata):
1361 1361 """Create a dict trait type from a dict.
1362 1362
1363 The default value is created by doing ``dict(default_value)``,
1363 The default value is created by doing ``dict(default_value)``,
1364 1364 which creates a copy of the ``default_value``.
1365 1365 """
1366 1366 if default_value is None:
@@ -1372,7 +1372,7 b' class Dict(Instance):'
1372 1372 else:
1373 1373 raise TypeError('default value of Dict was %s' % default_value)
1374 1374
1375 super(Dict,self).__init__(klass=dict, args=args,
1375 super(Dict,self).__init__(klass=dict, args=args,
1376 1376 allow_none=allow_none, **metadata)
1377 1377
1378 1378 class TCPAddress(TraitType):
@@ -24,7 +24,7 b' def create_typestr2type_dicts(dont_include_in_type2typestr=["lambda"]):'
24 24 objects from the types package, and vice versa."""
25 25 typenamelist = [tname for tname in dir(types) if tname.endswith("Type")]
26 26 typestr2type, type2typestr = {}, {}
27
27
28 28 for tname in typenamelist:
29 29 name = tname[:-4].lower() # Cut 'Type' off the end of the name
30 30 obj = getattr(types, tname)
@@ -36,10 +36,10 b' def create_typestr2type_dicts(dont_include_in_type2typestr=["lambda"]):'
36 36 typestr2type, type2typestr = create_typestr2type_dicts()
37 37
38 38 def is_type(obj, typestr_or_type):
39 """is_type(obj, typestr_or_type) verifies if obj is of a certain type. It
39 """is_type(obj, typestr_or_type) verifies if obj is of a certain type. It
40 40 can take strings or actual python types for the second argument, i.e.
41 41 'tuple'<->TupleType. 'all' matches all types.
42
42
43 43 TODO: Should be extended for choosing more than one type."""
44 44 if typestr_or_type == "all":
45 45 return True
@@ -71,7 +71,7 b' def dict_dir(obj):'
71 71 except AttributeError:
72 72 pass
73 73 return ns
74
74
75 75 def filter_ns(ns, name_pattern="*", type_pattern="all", ignore_case=True,
76 76 show_all=True):
77 77 """Filter a namespace dictionary by name pattern and item type."""
@@ -80,7 +80,7 b' def filter_ns(ns, name_pattern="*", type_pattern="all", ignore_case=True,'
80 80 reg = re.compile(pattern+"$", re.I)
81 81 else:
82 82 reg = re.compile(pattern+"$")
83
83
84 84 # Check each one matches regex; shouldn't be hidden; of correct type.
85 85 return dict((key,obj) for key, obj in ns.iteritems() if reg.match(key) \
86 86 and show_hidden(key, show_all) \
@@ -103,7 +103,7 b' def list_namespace(namespace, type_pattern, filter, ignore_case=False, show_all='
103 103 ignore_case=ignore_case, show_all=show_all)
104 104 results = {}
105 105 for name, obj in filtered.iteritems():
106 ns = list_namespace(dict_dir(obj), type_pattern,
106 ns = list_namespace(dict_dir(obj), type_pattern,
107 107 ".".join(pattern_list[1:]),
108 108 ignore_case=ignore_case, show_all=show_all)
109 109 for inner_name, inner_obj in ns.iteritems():
@@ -44,7 +44,7 b' def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0'
44 44 executable : str, optional (default sys.executable)
45 45 The Python executable to use for the kernel process.
46 46
47 independent : bool, optional (default False)
47 independent : bool, optional (default False)
48 48 If set, the kernel process is guaranteed to survive if this process
49 49 dies. If not set, an effort is made to ensure that the kernel is killed
50 50 when this process dies. Note that in this case it is still good practice
@@ -104,11 +104,11 b' def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0'
104 104 # If this process in running on pythonw, we know that stdin, stdout, and
105 105 # stderr are all invalid.
106 106 redirect_out = sys.executable.endswith('pythonw.exe')
107 if redirect_out:
107 if redirect_out:
108 108 _stdout = PIPE if stdout is None else stdout
109 109 _stderr = PIPE if stderr is None else stderr
110 110 else:
111 _stdout, _stderr = stdout, stderr
111 _stdout, _stderr = stdout, stderr
112 112
113 113 # Spawn a kernel.
114 114 if sys.platform == 'win32':
@@ -130,14 +130,14 b' def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0'
130 130
131 131 # Launch the kernel process.
132 132 if independent:
133 proc = Popen(arguments,
133 proc = Popen(arguments,
134 134 creationflags=512, # CREATE_NEW_PROCESS_GROUP
135 135 stdin=_stdin, stdout=_stdout, stderr=_stderr)
136 136 else:
137 137 from _subprocess import DuplicateHandle, GetCurrentProcess, \
138 138 DUPLICATE_SAME_ACCESS
139 139 pid = GetCurrentProcess()
140 handle = DuplicateHandle(pid, pid, pid, 0,
140 handle = DuplicateHandle(pid, pid, pid, 0,
141 141 True, # Inheritable by new processes.
142 142 DUPLICATE_SAME_ACCESS)
143 143 proc = Popen(arguments + ['--parent=%i'%int(handle)],
@@ -163,5 +163,5 b' def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0'
163 163 proc.stdout.close()
164 164 if stderr is None:
165 165 proc.stderr.close()
166
166
167 167 return proc, shell_port, iopub_port, stdin_port, hb_port
@@ -69,14 +69,14 b' class Console(code.InteractiveConsole):'
69 69
70 70 def print_pyerr(self, err):
71 71 print >> sys.stderr, err.etype,':', err.evalue
72 print >> sys.stderr, ''.join(err.traceback)
72 print >> sys.stderr, ''.join(err.traceback)
73 73
74 74 def handle_pyerr(self, omsg):
75 75 if omsg.parent_header.session == self.session.session:
76 76 return
77 77 print >> sys.stderr, '[ERR from %s]' % omsg.parent_header.username
78 78 self.print_pyerr(omsg.content)
79
79
80 80 def handle_stream(self, omsg):
81 81 if omsg.content.name == 'stdout':
82 82 outstream = sys.stdout
@@ -104,7 +104,7 b' class Console(code.InteractiveConsole):'
104 104 if rep is None:
105 105 return
106 106 if rep.content.status == 'error':
107 self.print_pyerr(rep.content)
107 self.print_pyerr(rep.content)
108 108 elif rep.content.status == 'aborted':
109 109 print >> sys.stderr, "ERROR: ABORTED"
110 110 ab = self.messages[rep.parent_header.msg_id].content
@@ -137,7 +137,7 b' class Console(code.InteractiveConsole):'
137 137 omsg = self.session.send(self.request_socket,
138 138 'execute_request', dict(code=src))
139 139 self.messages[omsg.header.msg_id] = omsg
140
140
141 141 # Fake asynchronicity by letting the user put ';' at the end of the line
142 142 if src.endswith(';'):
143 143 self.backgrounded += 1
@@ -162,7 +162,7 b' class InteractiveClient(object):'
162 162 self.sub_socket = sub_socket
163 163 self.console = Console(None, '<zmq-console>',
164 164 session, request_socket, sub_socket)
165
165
166 166 def interact(self):
167 167 self.console.interact()
168 168
@@ -176,12 +176,12 b' def main():'
176 176 connection = ('tcp://%s' % ip) + ':%i'
177 177 req_conn = connection % port_base
178 178 sub_conn = connection % (port_base+1)
179
179
180 180 # Create initial sockets
181 181 c = zmq.Context()
182 182 request_socket = c.socket(zmq.DEALER)
183 183 request_socket.connect(req_conn)
184
184
185 185 sub_socket = c.socket(zmq.SUB)
186 186 sub_socket.connect(sub_conn)
187 187 sub_socket.setsockopt(zmq.SUBSCRIBE, '')
@@ -111,7 +111,7 b' class Kernel(Configurable):'
111 111 self.shell._reply_content = None
112 112
113 113 # Build dict of handlers for message types
114 msg_types = [ 'execute_request', 'complete_request',
114 msg_types = [ 'execute_request', 'complete_request',
115 115 'object_info_request', 'history_request',
116 116 'connect_request', 'shutdown_request']
117 117 self.handlers = {}
@@ -135,7 +135,7 b' class Kernel(Configurable):'
135 135 # We now require 2.0.8 or above, so we can uncomment for safety.
136 136 # print(ident,msg, file=sys.__stdout__)
137 137 assert ident is not None, "Missing message part."
138
138
139 139 # Print some info about this message and leave a '--->' marker, so it's
140 140 # easier to trace visually the message chain when debugging. Each
141 141 # handler prints its message at the end.
@@ -148,7 +148,7 b' class Kernel(Configurable):'
148 148 self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg))
149 149 else:
150 150 handler(ident, msg)
151
151
152 152 # Check whether we should exit, in case the incoming message set the
153 153 # exit flag on
154 154 if self.shell.exit_now:
@@ -169,7 +169,7 b' class Kernel(Configurable):'
169 169 # reason for this to be anything less than ~ 0.1s
170 170 # since it is a real poller and will respond
171 171 # to events immediately
172
172
173 173 # double nested try/except, to properly catch KeyboardInterrupt
174 174 # due to pyzmq Issue #130
175 175 try:
@@ -199,17 +199,17 b' class Kernel(Configurable):'
199 199 pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent)
200 200
201 201 def execute_request(self, ident, parent):
202
202
203 203 status_msg = self.session.send(self.iopub_socket,
204 204 u'status',
205 205 {u'execution_state':u'busy'},
206 206 parent=parent
207 207 )
208
208
209 209 try:
210 210 content = parent[u'content']
211 211 code = content[u'code']
212 silent = content[u'silent']
212 silent = content[u'silent']
213 213 except:
214 214 self.log.error("Got bad msg: ")
215 215 self.log.error(str(Message(parent)))
@@ -217,7 +217,7 b' class Kernel(Configurable):'
217 217
218 218 shell = self.shell # we'll need this a lot here
219 219
220 # Replace raw_input. Note that is not sufficient to replace
220 # Replace raw_input. Note that is not sufficient to replace
221 221 # raw_input in the user namespace.
222 222 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
223 223 if py3compat.PY3:
@@ -261,7 +261,7 b' class Kernel(Configurable):'
261 261 status = u'ok'
262 262
263 263 reply_content[u'status'] = status
264
264
265 265 # Return the execution counter so clients can display prompts
266 266 reply_content['execution_count'] = shell.execution_count -1
267 267
@@ -301,7 +301,7 b' class Kernel(Configurable):'
301 301 # to better understand what's going on.
302 302 if self._execute_sleep:
303 303 time.sleep(self._execute_sleep)
304
304
305 305 # Send the reply.
306 306 reply_content = json_clean(reply_content)
307 307 reply_msg = self.session.send(self.shell_socket, u'execute_reply',
@@ -345,18 +345,18 b' class Kernel(Configurable):'
345 345 n = parent['content']['n']
346 346 hist = self.shell.history_manager.get_tail(n, raw=raw, output=output,
347 347 include_latest=True)
348
348
349 349 elif hist_access_type == 'range':
350 350 session = parent['content']['session']
351 351 start = parent['content']['start']
352 352 stop = parent['content']['stop']
353 353 hist = self.shell.history_manager.get_range(session, start, stop,
354 354 raw=raw, output=output)
355
355
356 356 elif hist_access_type == 'search':
357 357 pattern = parent['content']['pattern']
358 358 hist = self.shell.history_manager.search(pattern, raw=raw, output=output)
359
359
360 360 else:
361 361 hist = []
362 362 content = {'history' : list(hist)}
@@ -430,7 +430,7 b' class Kernel(Configurable):'
430 430 self.log.error(str(Message(parent)))
431 431 value = ''
432 432 return value
433
433
434 434 def _complete(self, msg):
435 435 c = msg['content']
436 436 try:
@@ -562,11 +562,11 b' class TkKernel(Kernel):'
562 562 self.app = Tkinter.Tk()
563 563 self.app.withdraw()
564 564 self.func = func
565
565
566 566 def on_timer(self):
567 567 self.func()
568 568 self.app.after(poll_interval, self.on_timer)
569
569
570 570 def start(self):
571 571 self.on_timer() # Call it once to get things going.
572 572 self.app.mainloop()
@@ -577,11 +577,11 b' class TkKernel(Kernel):'
577 577
578 578 class GTKKernel(Kernel):
579 579 """A Kernel subclass with GTK support."""
580
580
581 581 def start(self):
582 582 """Start the kernel, coordinating with the GTK event loop"""
583 583 from .gui.gtkembed import GTKEmbed
584
584
585 585 gtk_kernel = GTKEmbed(self)
586 586 gtk_kernel.start()
587 587
@@ -666,7 +666,7 b' class IPKernelApp(KernelApp, InteractiveShellApp):'
666 666 import_all = self.pylab_import_all
667 667 pylabtools.import_pylab(kernel.shell.user_ns, backend, import_all,
668 668 shell=kernel.shell)
669
669
670 670 def init_shell(self):
671 671 self.shell = self.kernel.shell
672 672
@@ -122,12 +122,12 b' class ZMQSocketChannel(Thread):'
122 122 raise
123 123 else:
124 124 break
125
125
126 126 def stop(self):
127 127 """Stop the channel's activity.
128 128
129 129 This calls :method:`Thread.join` and returns when the thread
130 terminates. :class:`RuntimeError` will be raised if
130 terminates. :class:`RuntimeError` will be raised if
131 131 :method:`self.start` is called again.
132 132 """
133 133 self.join()
@@ -135,7 +135,7 b' class ZMQSocketChannel(Thread):'
135 135 @property
136 136 def address(self):
137 137 """Get the channel's address as an (ip, port) tuple.
138
138
139 139 By the default, the address is (localhost, 0), where 0 means a random
140 140 port.
141 141 """
@@ -191,7 +191,7 b' class ShellSocketChannel(ZMQSocketChannel):'
191 191 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
192 192 self.socket.connect('tcp://%s:%i' % self.address)
193 193 self.iostate = POLLERR|POLLIN
194 self.ioloop.add_handler(self.socket, self._handle_events,
194 self.ioloop.add_handler(self.socket, self._handle_events,
195 195 self.iostate)
196 196 self._run_loop()
197 197
@@ -217,7 +217,7 b' class ShellSocketChannel(ZMQSocketChannel):'
217 217 ----------
218 218 code : str
219 219 A string of Python code.
220
220
221 221 silent : bool, optional (default False)
222 222 If set, the kernel will execute the code as quietly possible.
223 223
@@ -225,7 +225,7 b' class ShellSocketChannel(ZMQSocketChannel):'
225 225 A list of variable names to pull from the user's namespace. They
226 226 will come back as a dict with these names as keys and their
227 227 :func:`repr` as values.
228
228
229 229 user_expressions : dict, optional
230 230 A dict with string keys and to pull from the user's
231 231 namespace. They will come back as a dict with these names as keys
@@ -239,7 +239,7 b' class ShellSocketChannel(ZMQSocketChannel):'
239 239 user_variables = []
240 240 if user_expressions is None:
241 241 user_expressions = {}
242
242
243 243 # Don't waste network traffic if inputs are invalid
244 244 if not isinstance(code, basestring):
245 245 raise ValueError('code %r must be a string' % code)
@@ -263,7 +263,7 b' class ShellSocketChannel(ZMQSocketChannel):'
263 263 text : str
264 264 The text to complete.
265 265 line : str
266 The full line of text that is the surrounding context for the
266 The full line of text that is the surrounding context for the
267 267 text to complete.
268 268 cursor_pos : int
269 269 The position of the cursor in the line where the completion was
@@ -287,7 +287,7 b' class ShellSocketChannel(ZMQSocketChannel):'
287 287 ----------
288 288 oname : str
289 289 A string specifying the object name.
290
290
291 291 Returns
292 292 -------
293 293 The msg_id of the message sent.
@@ -309,7 +309,7 b' class ShellSocketChannel(ZMQSocketChannel):'
309 309 hist_access_type : str
310 310 'range' (fill in session, start and stop params), 'tail' (fill in n)
311 311 or 'search' (fill in pattern param).
312
312
313 313 session : int
314 314 For a range request, the session from which to get lines. Session
315 315 numbers are positive integers; negative ones count back from the
@@ -318,10 +318,10 b' class ShellSocketChannel(ZMQSocketChannel):'
318 318 The first line number of a history range.
319 319 stop : int
320 320 The final (excluded) line number of a history range.
321
321
322 322 n : int
323 323 The number of lines of history to get for a tail request.
324
324
325 325 pattern : str
326 326 The glob-syntax pattern for a search request.
327 327
@@ -398,7 +398,7 b' class SubSocketChannel(ZMQSocketChannel):'
398 398 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
399 399 self.socket.connect('tcp://%s:%i' % self.address)
400 400 self.iostate = POLLIN|POLLERR
401 self.ioloop.add_handler(self.socket, self._handle_events,
401 self.ioloop.add_handler(self.socket, self._handle_events,
402 402 self.iostate)
403 403 self._run_loop()
404 404
@@ -486,7 +486,7 b' class StdInSocketChannel(ZMQSocketChannel):'
486 486 self.socket.setsockopt(zmq.IDENTITY, self.session.bsession)
487 487 self.socket.connect('tcp://%s:%i' % self.address)
488 488 self.iostate = POLLERR|POLLIN
489 self.ioloop.add_handler(self.socket, self._handle_events,
489 self.ioloop.add_handler(self.socket, self._handle_events,
490 490 self.iostate)
491 491 self._run_loop()
492 492
@@ -616,7 +616,7 b' class HBSocketChannel(ZMQSocketChannel):'
616 616 raise
617 617 else:
618 618 break
619
619
620 620 since_last_heartbeat = time.time()-request_time
621 621 if since_last_heartbeat > self.time_to_dead:
622 622 self.call_handlers(since_last_heartbeat)
@@ -671,15 +671,15 b' class KernelManager(HasTraits):'
671 671
672 672 The SUB channel is for the frontend to receive messages published by the
673 673 kernel.
674
674
675 675 The REQ channel is for the frontend to make requests of the kernel.
676
676
677 677 The REP channel is for the kernel to request stdin (raw_input) from the
678 678 frontend.
679 679 """
680 680 # config object for passing to child configurables
681 681 config = Instance(Config)
682
682
683 683 # The PyZMQ Context to use for communication with the kernel.
684 684 context = Instance(zmq.Context)
685 685 def _context_default(self):
@@ -691,7 +691,7 b' class KernelManager(HasTraits):'
691 691 # The kernel process with which the KernelManager is communicating.
692 692 kernel = Instance(Popen)
693 693
694 # The addresses for the communication channels.
694 # The addresses for the communication channels.
695 695 shell_address = TCPAddress((LOCALHOST, 0))
696 696 sub_address = TCPAddress((LOCALHOST, 0))
697 697 stdin_address = TCPAddress((LOCALHOST, 0))
@@ -788,7 +788,7 b' class KernelManager(HasTraits):'
788 788 "configured properly. "
789 789 "Currently valid addresses are: %s"%LOCAL_IPS
790 790 )
791
791
792 792 self._launch_args = kw.copy()
793 793 launch_kernel = kw.pop('launcher', None)
794 794 if launch_kernel is None:
@@ -830,10 +830,10 b' class KernelManager(HasTraits):'
830 830 # OK, we've waited long enough.
831 831 if self.has_kernel:
832 832 self.kill_kernel()
833
833
834 834 def restart_kernel(self, now=False, **kw):
835 835 """Restarts a kernel with the arguments that were used to launch it.
836
836
837 837 If the old kernel was launched with random ports, the same ports will be
838 838 used for the new kernel.
839 839
@@ -977,7 +977,7 b' class KernelManager(HasTraits):'
977 977 """Get the heartbeat socket channel object to check that the
978 978 kernel is alive."""
979 979 if self._hb_channel is None:
980 self._hb_channel = self.hb_channel_class(self.context,
980 self._hb_channel = self.hb_channel_class(self.context,
981 981 self.session,
982 982 self.hb_address)
983 983 return self._hb_channel
@@ -10,14 +10,14 b' from IPython.utils.warn import warn'
10 10
11 11
12 12 class ParentPollerUnix(Thread):
13 """ A Unix-specific daemon thread that terminates the program immediately
13 """ A Unix-specific daemon thread that terminates the program immediately
14 14 when the parent process no longer exists.
15 15 """
16 16
17 17 def __init__(self):
18 18 super(ParentPollerUnix, self).__init__()
19 19 self.daemon = True
20
20
21 21 def run(self):
22 22 # We cannot use os.waitpid because it works only for child processes.
23 23 from errno import EINTR
@@ -37,7 +37,7 b' class ParentPollerWindows(Thread):'
37 37 signals an interrupt and, optionally, terminates the program immediately
38 38 when the parent process no longer exists.
39 39 """
40
40
41 41 def __init__(self, interrupt_handle=None, parent_handle=None):
42 42 """ Create the poller. At least one of the optional parameters must be
43 43 provided.
@@ -49,7 +49,7 b' class ParentPollerWindows(Thread):'
49 49 handle is signaled.
50 50
51 51 parent_handle : HANDLE (int), optional
52 If provided, the program will terminate immediately when this
52 If provided, the program will terminate immediately when this
53 53 handle is signaled.
54 54 """
55 55 assert(interrupt_handle or parent_handle)
@@ -71,8 +71,8 b' class ParentPollerWindows(Thread):'
71 71 # handle by new processes.
72 72 # FIXME: We can clean up this mess by requiring pywin32 for IPython.
73 73 class SECURITY_ATTRIBUTES(ctypes.Structure):
74 _fields_ = [ ("nLength", ctypes.c_int),
75 ("lpSecurityDescriptor", ctypes.c_void_p),
74 _fields_ = [ ("nLength", ctypes.c_int),
75 ("lpSecurityDescriptor", ctypes.c_void_p),
76 76 ("bInheritHandle", ctypes.c_int) ]
77 77 sa = SECURITY_ATTRIBUTES()
78 78 sa_p = ctypes.pointer(sa)
@@ -71,7 +71,7 b' class Kernel(HasTraits):'
71 71 self.completer = KernelCompleter(self.user_ns)
72 72
73 73 # Build dict of handlers for message types
74 msg_types = [ 'execute_request', 'complete_request',
74 msg_types = [ 'execute_request', 'complete_request',
75 75 'object_info_request', 'shutdown_request' ]
76 76 self.handlers = {}
77 77 for msg_type in msg_types:
@@ -114,7 +114,7 b' class Kernel(HasTraits):'
114 114 try:
115 115 comp_code = self.compiler(code, '<zmq-kernel>')
116 116
117 # Replace raw_input. Note that is not sufficient to replace
117 # Replace raw_input. Note that is not sufficient to replace
118 118 # raw_input in the user namespace.
119 119 raw_input = lambda prompt='': self._raw_input(prompt, ident, parent)
120 120 if py3compat.PY3:
@@ -141,7 +141,7 b' class Kernel(HasTraits):'
141 141 reply_content = exc_content
142 142 else:
143 143 reply_content = { 'status' : 'ok', 'payload' : {} }
144
144
145 145 # Flush output before sending the reply.
146 146 sys.stderr.flush()
147 147 sys.stdout.flush()
@@ -259,7 +259,7 b' class Kernel(HasTraits):'
259 259
260 260 def launch_kernel(*args, **kwargs):
261 261 """ Launches a simple Python kernel, binding to the specified ports.
262
262
263 263 This function simply calls entry_point.base_launch_kernel with the right first
264 264 command to start a pykernel. See base_launch_kernel for arguments.
265 265
@@ -92,36 +92,36 b' class SessionFactory(LoggingConfigurable):'
92 92 """The Base class for configurables that have a Session, Context, logger,
93 93 and IOLoop.
94 94 """
95
95
96 96 logname = Unicode('')
97 97 def _logname_changed(self, name, old, new):
98 98 self.log = logging.getLogger(new)
99
99
100 100 # not configurable:
101 101 context = Instance('zmq.Context')
102 102 def _context_default(self):
103 103 return zmq.Context.instance()
104
104
105 105 session = Instance('IPython.zmq.session.Session')
106
106
107 107 loop = Instance('zmq.eventloop.ioloop.IOLoop', allow_none=False)
108 108 def _loop_default(self):
109 109 return IOLoop.instance()
110
110
111 111 def __init__(self, **kwargs):
112 112 super(SessionFactory, self).__init__(**kwargs)
113
113
114 114 if self.session is None:
115 115 # construct the session
116 116 self.session = Session(**kwargs)
117
117
118 118
119 119 class Message(object):
120 120 """A simple message object that maps dict keys to attributes.
121 121
122 122 A Message can be created from a dict and a dict from a Message instance
123 123 simply by calling dict(msg_obj)."""
124
124
125 125 def __init__(self, msg_dict):
126 126 dct = self.__dict__
127 127 for k, v in dict(msg_dict).iteritems():
@@ -132,7 +132,7 b' class Message(object):'
132 132 # Having this iterator lets dict(msg_obj) work out of the box.
133 133 def __iter__(self):
134 134 return iter(self.__dict__.iteritems())
135
135
136 136 def __repr__(self):
137 137 return repr(self.__dict__)
138 138
@@ -171,28 +171,28 b' def extract_header(msg_or_header):'
171 171
172 172 class Session(Configurable):
173 173 """Object for handling serialization and sending of messages.
174
174
175 175 The Session object handles building messages and sending them
176 176 with ZMQ sockets or ZMQStream objects. Objects can communicate with each
177 177 other over the network via Session objects, and only need to work with the
178 dict-based IPython message spec. The Session will handle
178 dict-based IPython message spec. The Session will handle
179 179 serialization/deserialization, security, and metadata.
180
180
181 181 Sessions support configurable serialiization via packer/unpacker traits,
182 182 and signing with HMAC digests via the key/keyfile traits.
183
183
184 184 Parameters
185 185 ----------
186
186
187 187 debug : bool
188 188 whether to trigger extra debugging statements
189 189 packer/unpacker : str : 'json', 'pickle' or import_string
190 190 importstrings for methods to serialize message parts. If just
191 191 'json' or 'pickle', predefined JSON and pickle packers will be used.
192 192 Otherwise, the entire importstring must be used.
193
193
194 194 The functions must accept at least valid JSON input, and output *bytes*.
195
195
196 196 For example, to use msgpack:
197 197 packer = 'msgpack.packb', unpacker='msgpack.unpackb'
198 198 pack/unpack : callables
@@ -207,11 +207,11 b' class Session(Configurable):'
207 207 keyfile : filepath
208 208 The file containing a key. If this is set, `key` will be initialized
209 209 to the contents of the file.
210
210
211 211 """
212
212
213 213 debug=Bool(False, config=True, help="""Debug output in the Session""")
214
214
215 215 packer = DottedObjectName('json',config=True,
216 216 help="""The name of the packer for serializing messages.
217 217 Should be one of 'json', 'pickle', or an import name
@@ -238,23 +238,23 b' class Session(Configurable):'
238 238 self.unpack = pickle_unpacker
239 239 else:
240 240 self.unpack = import_item(str(new))
241
241
242 242 session = CUnicode(u'', config=True,
243 243 help="""The UUID identifying this session.""")
244 244 def _session_default(self):
245 245 u = unicode(uuid.uuid4())
246 246 self.bsession = u.encode('ascii')
247 247 return u
248
248
249 249 def _session_changed(self, name, old, new):
250 250 self.bsession = self.session.encode('ascii')
251
251
252 252 # bsession is the session as bytes
253 253 bsession = CBytes(b'')
254
254
255 255 username = Unicode(os.environ.get('USER',u'username'), config=True,
256 256 help="""Username for the Session. Default is your system username.""")
257
257
258 258 # message signature related traits:
259 259 key = CBytes(b'', config=True,
260 260 help="""execution key, for extra authentication.""")
@@ -265,7 +265,7 b' class Session(Configurable):'
265 265 self.auth = None
266 266 auth = Instance(hmac.HMAC)
267 267 digest_history = Set()
268
268
269 269 keyfile = Unicode('', config=True,
270 270 help="""path to file containing execution key.""")
271 271 def _keyfile_changed(self, name, old, new):
@@ -276,16 +276,16 b' class Session(Configurable):'
276 276 def _pack_changed(self, name, old, new):
277 277 if not callable(new):
278 278 raise TypeError("packer must be callable, not %s"%type(new))
279
279
280 280 unpack = Any(default_unpacker) # the actual packer function
281 281 def _unpack_changed(self, name, old, new):
282 # unpacker is not checked - it is assumed to be
282 # unpacker is not checked - it is assumed to be
283 283 if not callable(new):
284 284 raise TypeError("unpacker must be callable, not %s"%type(new))
285 285
286 286 def __init__(self, **kwargs):
287 287 """create a Session object
288
288
289 289 Parameters
290 290 ----------
291 291
@@ -305,7 +305,7 b' class Session(Configurable):'
305 305 You can also set the pack/unpack callables for serialization
306 306 directly.
307 307 session : unicode (must be ascii)
308 the ID of this Session object. The default is to generate a new
308 the ID of this Session object. The default is to generate a new
309 309 UUID.
310 310 bsession : bytes
311 311 The session as bytes
@@ -315,7 +315,7 b' class Session(Configurable):'
315 315 The key used to initialize an HMAC signature. If unset, messages
316 316 will not be signed or checked.
317 317 keyfile : filepath
318 The file containing a key. If this is set, `key` will be
318 The file containing a key. If this is set, `key` will be
319 319 initialized to the contents of the file.
320 320 """
321 321 super(Session, self).__init__(**kwargs)
@@ -333,24 +333,24 b' class Session(Configurable):'
333 333 """check packers for binary data and datetime support."""
334 334 pack = self.pack
335 335 unpack = self.unpack
336
336
337 337 # check simple serialization
338 338 msg = dict(a=[1,'hi'])
339 339 try:
340 340 packed = pack(msg)
341 341 except Exception:
342 342 raise ValueError("packer could not serialize a simple message")
343
343
344 344 # ensure packed message is bytes
345 345 if not isinstance(packed, bytes):
346 346 raise ValueError("message packed to %r, but bytes are required"%type(packed))
347
347
348 348 # check that unpack is pack's inverse
349 349 try:
350 350 unpacked = unpack(packed)
351 351 except Exception:
352 352 raise ValueError("unpacker could not handle the packer's output")
353
353
354 354 # check datetime support
355 355 msg = dict(t=datetime.now())
356 356 try:
@@ -358,7 +358,7 b' class Session(Configurable):'
358 358 except Exception:
359 359 self.pack = lambda o: pack(squash_dates(o))
360 360 self.unpack = lambda s: extract_dates(unpack(s))
361
361
362 362 def msg_header(self, msg_type):
363 363 return msg_header(self.msg_id, msg_type, self.username, self.session)
364 364
@@ -386,7 +386,7 b' class Session(Configurable):'
386 386 Parameters
387 387 ----------
388 388 msg_list : list
389 The [p_header,p_parent,p_content] part of the message list.
389 The [p_header,p_parent,p_content] part of the message list.
390 390 """
391 391 if self.auth is None:
392 392 return b''
@@ -394,7 +394,7 b' class Session(Configurable):'
394 394 for m in msg_list:
395 395 h.update(m)
396 396 return str_to_bytes(h.hexdigest())
397
397
398 398 def serialize(self, msg, ident=None):
399 399 """Serialize the message components to bytes.
400 400
@@ -429,12 +429,12 b' class Session(Configurable):'
429 429 content = content.encode('utf8')
430 430 else:
431 431 raise TypeError("Content incorrect type: %s"%type(content))
432
433 real_message = [self.pack(msg['header']),
434 self.pack(msg['parent_header']),
432
433 real_message = [self.pack(msg['header']),
434 self.pack(msg['parent_header']),
435 435 content
436 436 ]
437
437
438 438 to_send = []
439 439
440 440 if isinstance(ident, list):
@@ -443,14 +443,14 b' class Session(Configurable):'
443 443 elif ident is not None:
444 444 to_send.append(ident)
445 445 to_send.append(DELIM)
446
446
447 447 signature = self.sign(real_message)
448 448 to_send.append(signature)
449
449
450 450 to_send.extend(real_message)
451 451
452 452 return to_send
453
453
454 454 def send(self, stream, msg_or_type, content=None, parent=None, ident=None,
455 455 buffers=None, subheader=None, track=False, header=None):
456 456 """Build and send a message via stream or socket.
@@ -458,21 +458,21 b' class Session(Configurable):'
458 458 The message format used by this function internally is as follows:
459 459
460 460 [ident1,ident2,...,DELIM,HMAC,p_header,p_parent,p_content,
461 buffer1,buffer2,...]
461 buffer1,buffer2,...]
462 462
463 463 The serialize/unserialize methods convert the nested message dict into this
464 464 format.
465 465
466 466 Parameters
467 467 ----------
468
468
469 469 stream : zmq.Socket or ZMQStream
470 470 The socket-like object used to send the data.
471 471 msg_or_type : str or Message/dict
472 Normally, msg_or_type will be a msg_type unless a message is being
472 Normally, msg_or_type will be a msg_type unless a message is being
473 473 sent more than once. If a header is supplied, this can be set to
474 474 None and the msg_type will be pulled from the header.
475
475
476 476 content : dict or None
477 477 The content of the message (ignored if msg_or_type is a message).
478 478 header : dict or None
@@ -490,29 +490,29 b' class Session(Configurable):'
490 490 track : bool
491 491 Whether to track. Only for use with Sockets, because ZMQStream
492 492 objects cannot track messages.
493
493
494 494 Returns
495 495 -------
496 496 msg : dict
497 497 The constructed message.
498 498 (msg,tracker) : (dict, MessageTracker)
499 if track=True, then a 2-tuple will be returned,
499 if track=True, then a 2-tuple will be returned,
500 500 the first element being the constructed
501 501 message, and the second being the MessageTracker
502
502
503 503 """
504 504
505 505 if not isinstance(stream, (zmq.Socket, ZMQStream)):
506 506 raise TypeError("stream must be Socket or ZMQStream, not %r"%type(stream))
507 507 elif track and isinstance(stream, ZMQStream):
508 508 raise TypeError("ZMQStream cannot track messages")
509
509
510 510 if isinstance(msg_or_type, (Message, dict)):
511 511 # We got a Message or message dict, not a msg_type so don't
512 512 # build a new Message.
513 513 msg = msg_or_type
514 514 else:
515 msg = self.msg(msg_or_type, content=content, parent=parent,
515 msg = self.msg(msg_or_type, content=content, parent=parent,
516 516 subheader=subheader, header=header)
517 517
518 518 buffers = [] if buffers is None else buffers
@@ -540,9 +540,9 b' class Session(Configurable):'
540 540 pprint.pprint(msg)
541 541 pprint.pprint(to_send)
542 542 pprint.pprint(buffers)
543
543
544 544 msg['tracker'] = tracker
545
545
546 546 return msg
547 547
548 548 def send_raw(self, stream, msg_list, flags=0, copy=True, ident=None):
@@ -571,7 +571,7 b' class Session(Configurable):'
571 571 to_send.append(self.sign(msg_list))
572 572 to_send.extend(msg_list)
573 573 stream.send_multipart(msg_list, flags, copy=copy)
574
574
575 575 def recv(self, socket, mode=zmq.NOBLOCK, content=True, copy=True):
576 576 """Receive and unpack a message.
577 577
@@ -605,21 +605,21 b' class Session(Configurable):'
605 605 except Exception as e:
606 606 # TODO: handle it
607 607 raise e
608
608
609 609 def feed_identities(self, msg_list, copy=True):
610 610 """Split the identities from the rest of the message.
611 611
612 612 Feed until DELIM is reached, then return the prefix as idents and
613 613 remainder as msg_list. This is easily broken by setting an IDENT to DELIM,
614 614 but that would be silly.
615
615
616 616 Parameters
617 617 ----------
618 618 msg_list : a list of Message or bytes objects
619 619 The message to be split.
620 620 copy : bool
621 621 flag determining whether the arguments are bytes or Messages
622
622
623 623 Returns
624 624 -------
625 625 (idents, msg_list) : two lists
@@ -642,7 +642,7 b' class Session(Configurable):'
642 642 raise ValueError("DELIM not in msg_list")
643 643 idents, msg_list = msg_list[:idx], msg_list[idx+1:]
644 644 return [m.bytes for m in idents], msg_list
645
645
646 646 def unserialize(self, msg_list, content=True, copy=True):
647 647 """Unserialize a msg_list to a nested message dict.
648 648
@@ -694,7 +694,7 b' class Session(Configurable):'
694 694 message['content'] = self.unpack(msg_list[3])
695 695 else:
696 696 message['content'] = msg_list[3]
697
697
698 698 message['buffers'] = msg_list[4:]
699 699 return message
700 700
@@ -706,10 +706,10 b' def test_msg2obj():'
706 706 am['y'] = dict(z=1)
707 707 ao = Message(am)
708 708 assert ao.y.z == am['y']['z']
709
709
710 710 k1, k2 = 'y', 'z'
711 711 assert ao[k1][k2] == am[k1][k2]
712
712
713 713 am2 = dict(ao)
714 714 assert am['x'] == am2['x']
715 715 assert am['y']['z'] == am2['y']['z']
@@ -21,7 +21,7 b' from zmq.eventloop.zmqstream import ZMQStream'
21 21 from IPython.zmq import session as ss
22 22
23 23 class SessionTestCase(BaseZMQTestCase):
24
24
25 25 def setUp(self):
26 26 BaseZMQTestCase.setUp(self)
27 27 self.session = ss.Session()
@@ -43,7 +43,7 b' class MockSocket(zmq.Socket):'
43 43 return self.data
44 44
45 45 class TestSession(SessionTestCase):
46
46
47 47 def test_msg(self):
48 48 """message format"""
49 49 msg = self.session.msg('execute')
@@ -82,7 +82,7 b' class TestSession(SessionTestCase):'
82 82 self.assertEquals(new_msg['msg_type'],msg['msg_type'])
83 83 self.assertEquals(new_msg['header'],msg['header'])
84 84 self.assertEquals(new_msg['content'],msg['content'])
85 self.assertEquals(new_msg['parent_header'],msg['parent_header'])
85 self.assertEquals(new_msg['parent_header'],msg['parent_header'])
86 86 self.assertEquals(new_msg['buffers'],[b'bar'])
87 87
88 88 socket.data = []
@@ -100,7 +100,7 b' class TestSession(SessionTestCase):'
100 100 self.assertEquals(new_msg['msg_type'],msg['msg_type'])
101 101 self.assertEquals(new_msg['header'],msg['header'])
102 102 self.assertEquals(new_msg['content'],msg['content'])
103 self.assertEquals(new_msg['parent_header'],msg['parent_header'])
103 self.assertEquals(new_msg['parent_header'],msg['parent_header'])
104 104 self.assertEquals(new_msg['buffers'],[b'bar'])
105 105
106 106 socket.data = []
@@ -112,7 +112,7 b' class TestSession(SessionTestCase):'
112 112 self.assertEquals(new_msg['msg_type'],msg['msg_type'])
113 113 self.assertEquals(new_msg['header'],msg['header'])
114 114 self.assertEquals(new_msg['content'],msg['content'])
115 self.assertEquals(new_msg['parent_header'],msg['parent_header'])
115 self.assertEquals(new_msg['parent_header'],msg['parent_header'])
116 116 self.assertEquals(new_msg['buffers'],[b'bar'])
117 117
118 118 socket.close()
@@ -123,17 +123,17 b' class TestSession(SessionTestCase):'
123 123 self.assertTrue(s.pack is ss.default_packer)
124 124 self.assertTrue(s.unpack is ss.default_unpacker)
125 125 self.assertEquals(s.username, os.environ.get('USER', u'username'))
126
126
127 127 s = ss.Session()
128 128 self.assertEquals(s.username, os.environ.get('USER', u'username'))
129
129
130 130 self.assertRaises(TypeError, ss.Session, pack='hi')
131 131 self.assertRaises(TypeError, ss.Session, unpack='hi')
132 132 u = str(uuid.uuid4())
133 133 s = ss.Session(username=u'carrot', session=u)
134 134 self.assertEquals(s.session, u)
135 135 self.assertEquals(s.username, u'carrot')
136
136
137 137 def test_tracking(self):
138 138 """test tracking messages"""
139 139 a,b = self.create_bound_pair(zmq.PAIR, zmq.PAIR)
@@ -150,26 +150,26 b' class TestSession(SessionTestCase):'
150 150 self.assertRaises(zmq.NotDone, t.wait, .1)
151 151 del M
152 152 t.wait(1) # this will raise
153
154
153
154
155 155 # def test_rekey(self):
156 156 # """rekeying dict around json str keys"""
157 157 # d = {'0': uuid.uuid4(), 0:uuid.uuid4()}
158 158 # self.assertRaises(KeyError, ss.rekey, d)
159 #
159 #
160 160 # d = {'0': uuid.uuid4(), 1:uuid.uuid4(), 'asdf':uuid.uuid4()}
161 161 # d2 = {0:d['0'],1:d[1],'asdf':d['asdf']}
162 162 # rd = ss.rekey(d)
163 163 # self.assertEquals(d2,rd)
164 #
164 #
165 165 # d = {'1.5':uuid.uuid4(),'1':uuid.uuid4()}
166 166 # d2 = {1.5:d['1.5'],1:d['1']}
167 167 # rd = ss.rekey(d)
168 168 # self.assertEquals(d2,rd)
169 #
169 #
170 170 # d = {'1.0':uuid.uuid4(),'1':uuid.uuid4()}
171 171 # self.assertRaises(KeyError, ss.rekey, d)
172 #
172 #
173 173 def test_unique_msg_ids(self):
174 174 """test that messages receive unique ids"""
175 175 ids = set()
@@ -178,14 +178,14 b' class TestSession(SessionTestCase):'
178 178 msg_id = h['msg_id']
179 179 self.assertTrue(msg_id not in ids)
180 180 ids.add(msg_id)
181
181
182 182 def test_feed_identities(self):
183 183 """scrub the front for zmq IDENTITIES"""
184 184 theids = "engine client other".split()
185 185 content = dict(code='whoda',stuff=object())
186 186 themsg = self.session.msg('execute',content=content)
187 187 pmsg = theids
188
188
189 189 def test_session_id(self):
190 190 session = ss.Session()
191 191 # get bs before us
@@ -206,5 +206,5 b' class TestSession(SessionTestCase):'
206 206 # get us before bs
207 207 self.assertEquals(session.bsession, session.session.encode('ascii'))
208 208 self.assertEquals(b'stuff', session.bsession)
209
209
210 210
@@ -80,7 +80,7 b' class ZMQInteractiveShell(InteractiveShell):'
80 80
81 81 displayhook_class = Type(ZMQShellDisplayHook)
82 82 display_pub_class = Type(ZMQDisplayPublisher)
83
83
84 84 # Override the traitlet in the parent class, because there's no point using
85 85 # readline for the kernel. Can be removed when the readline code is moved
86 86 # to the terminal frontend.
@@ -89,7 +89,7 b' class ZMQInteractiveShell(InteractiveShell):'
89 89 # autoindent has no meaning in a zmqshell, and attempting to enable it
90 90 # will print a warning in the absence of readline.
91 91 autoindent = CBool(False)
92
92
93 93 exiter = Instance(ZMQExitAutocall)
94 94 def _exiter_default(self):
95 95 return ZMQExitAutocall(self)
@@ -122,7 +122,7 b' class ZMQInteractiveShell(InteractiveShell):'
122 122 transformed_input=new,
123 123 )
124 124 self.payload_manager.write_payload(payload)
125
125
126 126 def ask_exit(self):
127 127 """Engage the exit actions."""
128 128 payload = dict(
@@ -153,7 +153,7 b' class ZMQInteractiveShell(InteractiveShell):'
153 153 exc_content[u'status'] = u'error'
154 154 self._reply_content = exc_content
155 155 # /FIXME
156
156
157 157 return exc_content
158 158
159 159 #------------------------------------------------------------------------
@@ -205,7 +205,7 b' class ZMQInteractiveShell(InteractiveShell):'
205 205 save_dstore('rc_pprint', ptformatter.pprint)
206 206 save_dstore('rc_plain_text_only',disp_formatter.plain_text_only)
207 207 save_dstore('xmode', shell.InteractiveTB.mode)
208
208
209 209 if mode == False:
210 210 # turn on
211 211 ptformatter.pprint = False
@@ -221,7 +221,7 b' class ZMQInteractiveShell(InteractiveShell):'
221 221 dstore.mode = bool(1-int(mode))
222 222 mode_label = ['OFF','ON'][dstore.mode]
223 223 print('Doctest mode is:', mode_label)
224
224
225 225 # Send the payload back so that clients can modify their prompt display
226 226 payload = dict(
227 227 source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode',
@@ -240,7 +240,7 b' class ZMQInteractiveShell(InteractiveShell):'
240 240
241 241 This command allows you to conveniently edit multi-line code right in
242 242 your IPython session.
243
243
244 244 If called without arguments, %edit opens up an empty editor with a
245 245 temporary file and will execute the contents of this file when you
246 246 close it (don't forget to save it!).
@@ -253,7 +253,7 b' class ZMQInteractiveShell(InteractiveShell):'
253 253 you can configure this by providing your own modified hook if your
254 254 favorite editor supports line-number specifications with a different
255 255 syntax.
256
256
257 257 -p: this will call the editor with the same data as the previous time
258 258 it was used, regardless of how long ago (in your current session) it
259 259 was.
@@ -264,7 +264,7 b' class ZMQInteractiveShell(InteractiveShell):'
264 264 this option is given, the raw input as typed as the command line is
265 265 used instead. When you exit the editor, it will be executed by
266 266 IPython's own processor.
267
267
268 268 -x: do not execute the edited code immediately upon exit. This is
269 269 mainly useful if you are editing programs which need to be called with
270 270 command line arguments, which you can then do using %run.
@@ -319,18 +319,18 b' class ZMQInteractiveShell(InteractiveShell):'
319 319 Out[1]: 'def foo():n print "foo() was defined in an editing session"n'
320 320
321 321 We can then call the function foo():
322
322
323 323 In [2]: foo()
324 324 foo() was defined in an editing session
325 325
326 326 Now we edit foo. IPython automatically loads the editor with the
327 327 (temporary) file where foo() was previously defined:
328
328
329 329 In [3]: ed foo
330 330 Editing... done. Executing edited code...
331 331
332 332 And if we call foo() again we get the modified version:
333
333
334 334 In [4]: foo()
335 335 foo() has now been changed!
336 336
@@ -356,9 +356,9 b' class ZMQInteractiveShell(InteractiveShell):'
356 356 hello again
357 357 Out[7]: "print 'hello again'n"
358 358 """
359
359
360 360 opts,args = self.parse_options(parameter_s,'prn:')
361
361
362 362 try:
363 363 filename, lineno, _ = self._find_edit_target(args, opts, last_call)
364 364 except MacroToEdit as e:
@@ -400,7 +400,7 b' class ZMQInteractiveShell(InteractiveShell):'
400 400 magic_cls = magic_clear
401 401
402 402 # Terminal pagers won't work over pexpect, but we do have our own pager
403
403
404 404 def magic_less(self, arg_s):
405 405 """Show a file through the pager.
406 406
@@ -427,12 +427,12 b' class ZMQInteractiveShell(InteractiveShell):'
427 427 """Show a basic reference about the GUI console."""
428 428 from IPython.core.usage import gui_reference
429 429 page.page(gui_reference, auto_html=True)
430
430
431 431 def set_next_input(self, text):
432 432 """Send the specified text to the frontend to be presented at the next
433 433 input cell."""
434 434 payload = dict(
435 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
435 source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input',
436 436 text=text
437 437 )
438 438 self.payload_manager.write_payload(payload)
@@ -14,7 +14,7 b' In [6]: %run gui-wx.py'
14 14
15 15 Ref: Modified from wxPython source code wxPython/samples/simple/simple.py
16 16
17 This example can only be run once in a given IPython session because when
17 This example can only be run once in a given IPython session because when
18 18 the frame is closed, wx goes through its shutdown sequence, killing further
19 19 attempts. I am sure someone who knows wx can fix this issue.
20 20
@@ -42,7 +42,7 b' class MyFrame(wx.Frame):'
42 42 # Create the menubar
43 43 menuBar = wx.MenuBar()
44 44
45 # and a menu
45 # and a menu
46 46 menu = wx.Menu()
47 47
48 48 # add an item to the menu, using \tKeyName automatically
@@ -4,7 +4,7 b' Ken Kinder <ken@kenkinder.com>'
4 4
5 5 Updated for newparallel by Min Ragan-Kelley <benjaminrk@gmail.com>
6 6
7 This module gives an example of how the task interface to the
7 This module gives an example of how the task interface to the
8 8 IPython controller works. Before running this script start the IPython controller
9 9 and some engines using something like::
10 10
@@ -34,42 +34,42 b' def fetchAndParse(url, data=None):'
34 34 return links
35 35
36 36 class DistributedSpider(object):
37
37
38 38 # Time to wait between polling for task results.
39 39 pollingDelay = 0.5
40
40
41 41 def __init__(self, site):
42 42 self.client = Client()
43 43 self.view = self.client.load_balanced_view()
44 44 self.mux = self.client[:]
45
45
46 46 self.allLinks = []
47 47 self.linksWorking = {}
48 48 self.linksDone = {}
49
49
50 50 self.site = site
51
51
52 52 def visitLink(self, url):
53 53 if url not in self.allLinks:
54 54 self.allLinks.append(url)
55 55 if url.startswith(self.site):
56 56 print ' ', url
57 57 self.linksWorking[url] = self.view.apply(fetchAndParse, url)
58
58
59 59 def onVisitDone(self, links, url):
60 60 print url, ':'
61 61 self.linksDone[url] = None
62 62 del self.linksWorking[url]
63 63 for link in links:
64 64 self.visitLink(link)
65
65
66 66 def run(self):
67 67 self.visitLink(self.site)
68 68 while self.linksWorking:
69 69 print len(self.linksWorking), 'pending...'
70 70 self.synchronize()
71 71 time.sleep(self.pollingDelay)
72
72
73 73 def synchronize(self):
74 74 for url, ar in self.linksWorking.items():
75 75 # Calling get_task_result with block=False will return None if the
@@ -196,7 +196,7 b' except error.CompositeError:'
196 196 try:
197 197 ar.r
198 198 except error.CompositeError:
199 print "Caught ZeroDivisionError OK."
199 print "Caught ZeroDivisionError OK."
200 200
201 201 # push/pull
202 202
@@ -50,7 +50,7 b' c = Client(profile=cluster_profile)'
50 50
51 51 # <markdowncell>
52 52
53 # A LoadBalancedView is an interface to the engines that provides dynamic load
53 # A LoadBalancedView is an interface to the engines that provides dynamic load
54 54 # balancing at the expense of not knowing which engine will execute the code.
55 55
56 56 # <codecell>
@@ -115,7 +115,7 b' prices = np.empty(n_strikes*n_sigmas,'
115 115
116 116 for i, price in enumerate(results):
117 117 prices[i] = tuple(price)
118
118
119 119 prices.shape = (n_strikes, n_sigmas)
120 120 strike_mesh, sigma_mesh = np.meshgrid(strike_vals, sigma_vals)
121 121
@@ -12,9 +12,9 b' variable below.'
12 12 The dataset we have been using for this is the 200 million digit one here:
13 13 ftp://pi.super-computing.org/.2/pi200m/
14 14
15 and the files used will be downloaded if they are not in the working directory
15 and the files used will be downloaded if they are not in the working directory
16 16 of the IPython engines.
17 """
17 """
18 18
19 19 from IPython.parallel import Client
20 20 from matplotlib import pyplot as plt
@@ -1,7 +1,7 b''
1 1 """Compute statistics on the digits of pi.
2 2
3 3 This uses precomputed digits of pi from the website
4 of Professor Yasumasa Kanada at the University of
4 of Professor Yasumasa Kanada at the University of
5 5 Tokoyo: http://www.super-computing.org/
6 6
7 7 Currently, there are only functions to read the
@@ -70,7 +70,7 b' def compute_n_digit_freqs(filename, n):'
70 70 return freqs
71 71
72 72 # Read digits from a txt file
73
73
74 74 def txt_file_to_digits(filename, the_type=str):
75 75 """
76 76 Yield the digits of pi read from a .txt file.
@@ -81,7 +81,7 b' def txt_file_to_digits(filename, the_type=str):'
81 81 if c != '\n' and c!= ' ':
82 82 yield the_type(c)
83 83
84 # Actual counting functions
84 # Actual counting functions
85 85
86 86 def one_digit_freqs(digits, normalize=False):
87 87 """
@@ -93,7 +93,7 b' def one_digit_freqs(digits, normalize=False):'
93 93 if normalize:
94 94 freqs = freqs/freqs.sum()
95 95 return freqs
96
96
97 97 def two_digit_freqs(digits, normalize=False):
98 98 """
99 99 Consume digits of pi and compute 2 digits freq. counts.
@@ -2,15 +2,15 b''
2 2
3 3 The two files plotting_frontend.py and plotting_backend.py go together.
4 4
5 This file (plotting_backend.py) performs the actual computation. For this
5 This file (plotting_backend.py) performs the actual computation. For this
6 6 example, the computation just generates a set of random numbers that
7 look like a distribution of particles with 2D position (x,y) and
7 look like a distribution of particles with 2D position (x,y) and
8 8 momentum (px,py). In a real situation, this file would do some time
9 9 consuming and complicated calculation, and could possibly make calls
10 10 to MPI.
11 11
12 12 One important feature is that this script can also be run standalone without
13 IPython. This is nice as it allows it to be run in more traditional
13 IPython. This is nice as it allows it to be run in more traditional
14 14 settings where IPython isn't being used.
15 15
16 16 When used with IPython.parallel, this code is run on the engines. Because this
@@ -6,7 +6,7 b''
6 6
7 7 # <markdowncell>
8 8
9 # The eigenvalues of random matrices obey certain statistical laws. Here we construct random matrices
9 # The eigenvalues of random matrices obey certain statistical laws. Here we construct random matrices
10 10 # from the Gaussian Orthogonal Ensemble (GOE), find their eigenvalues and then investigate the nearest
11 11 # neighbor eigenvalue distribution $\rho(s)$.
12 12
@@ -24,7 +24,7 b' from IPython.parallel import Client'
24 24
25 25 # The Wigner distribution gives the theoretical result for the nearest neighbor eigenvalue distribution
26 26 # for the GOE:
27 #
27 #
28 28 # $$\rho(s) = \frac{\pi s}{2} \exp(-\pi s^2/4)$$
29 29
30 30 # <codecell>
@@ -3,7 +3,7 b''
3 3
4 4 This script submits a set of tasks via a LoadBalancedView. The tasks
5 5 are basically just a time.sleep(t), where t is a random number between
6 two limits that can be configured at the command line. To run
6 two limits that can be configured at the command line. To run
7 7 the script there must first be an IPython controller and engines running::
8 8
9 9 ipclusterz start -n 16
@@ -12,7 +12,7 b' A good test to run with 16 engines is::'
12 12
13 13 python task_profiler.py -n 128 -t 0.01 -T 1.0
14 14
15 This should show a speedup of 13-14x. The limitation here is that the
15 This should show a speedup of 13-14x. The limitation here is that the
16 16 overhead of a single task is about 0.001-0.01 seconds.
17 17 """
18 18 import random, sys
@@ -27,19 +27,19 b' def main():'
27 27 parser.set_defaults(tmin=1e-3)
28 28 parser.set_defaults(tmax=1)
29 29 parser.set_defaults(profile='default')
30
30
31 31 parser.add_option("-n", type='int', dest='n',
32 32 help='the number of tasks to run')
33 parser.add_option("-t", type='float', dest='tmin',
33 parser.add_option("-t", type='float', dest='tmin',
34 34 help='the minimum task length in seconds')
35 35 parser.add_option("-T", type='float', dest='tmax',
36 36 help='the maximum task length in seconds')
37 37 parser.add_option("-p", '--profile', type='str', dest='profile',
38 38 help="the cluster profile [default: 'default']")
39
39
40 40 (opts, args) = parser.parse_args()
41 41 assert opts.tmax >= opts.tmin, "tmax must not be smaller than tmin"
42
42
43 43 rc = Client()
44 44 view = rc.load_balanced_view()
45 45 print view
@@ -51,7 +51,7 b' def main():'
51 51 # the jobs should take a random time within a range
52 52 times = [random.random()*(opts.tmax-opts.tmin)+opts.tmin for i in range(opts.n)]
53 53 stime = sum(times)
54
54
55 55 print "executing %i tasks, totalling %.1f secs on %i engines"%(opts.n, stime, nengines)
56 56 time.sleep(1)
57 57 start = time.time()
@@ -61,7 +61,7 b' def main():'
61 61
62 62 ptime = stop-start
63 63 scale = stime/ptime
64
64
65 65 print "executed %.1f secs in %.1f secs"%(stime, ptime)
66 66 print "%.3fx parallel performance on %i engines"%(scale, nengines)
67 67 print "%.1f%% of theoretical max"%(100*scale/nengines)
@@ -11,7 +11,7 b' An example of running the program is (8 processors, 4x2 partition,'
11 11 $ ipclusterz start --profile mpi -n 8 # start 8 engines (assuming mpi profile has been configured)
12 12 $ ./parallelwave-mpi.py --grid 400 100 --partition 4 2 --profile mpi
13 13
14 See also parallelwave-mpi, which runs the same program, but uses MPI
14 See also parallelwave-mpi, which runs the same program, but uses MPI
15 15 (via mpi4py) for the inter-engine communication.
16 16
17 17 Authors
@@ -50,11 +50,11 b' def wave_saver(u, x, y, t):'
50 50 global t_hist
51 51 t_hist.append(t)
52 52 u_hist.append(1.0*u)
53
53
54 54
55 55 # main program:
56 56 if __name__ == '__main__':
57
57
58 58 parser = argparse.ArgumentParser()
59 59 paa = parser.add_argument
60 60 paa('--grid', '-g',
@@ -75,16 +75,16 b" if __name__ == '__main__':"
75 75 paa('-t', '--tstop',
76 76 type=float, default=1.,
77 77 help="Time units to run")
78 paa('--profile',
78 paa('--profile',
79 79 type=unicode, default=u'default',
80 80 help="Specify the ipcluster profile for the client to connect to.")
81 paa('--save',
81 paa('--save',
82 82 action='store_true',
83 83 help="Add this flag to save the time/wave history during the run.")
84 paa('--scalar',
84 paa('--scalar',
85 85 action='store_true',
86 86 help="Also run with scalar interior implementation, to see vector speedup.")
87
87
88 88 ns = parser.parse_args()
89 89 # set up arguments
90 90 grid = ns.grid
@@ -97,22 +97,22 b" if __name__ == '__main__':"
97 97 user_action = wave_saver
98 98 else:
99 99 user_action = None
100
100
101 101 num_cells = 1.0*(grid[0]-1)*(grid[1]-1)
102 102 final_test = True
103
103
104 104 # create the Client
105 105 rc = Client(profile=ns.profile)
106 106 num_procs = len(rc.ids)
107
107
108 108 if partition is None:
109 109 partition = [1,num_procs]
110
110
111 111 assert partition[0]*partition[1] == num_procs, "can't map partition %s to %i engines"%(partition, num_procs)
112
112
113 113 view = rc[:]
114 114 print "Running %s system on %s processes until %f"%(grid, partition, tstop)
115
115
116 116 # functions defining initial/boundary/source conditions
117 117 def I(x,y):
118 118 from numpy import exp
@@ -123,28 +123,28 b" if __name__ == '__main__':"
123 123 # return 10*exp(-(x - sin(100*t))**2)
124 124 def bc(x,y,t):
125 125 return 0.0
126
126
127 127 # initial imports, setup rank
128 128 view.execute('\n'.join([
129 129 "from mpi4py import MPI",
130 130 "import numpy",
131 131 "mpi = MPI.COMM_WORLD",
132 132 "my_id = MPI.COMM_WORLD.Get_rank()"]), block=True)
133
133
134 134 # initialize t_hist/u_hist for saving the state at each step (optional)
135 135 view['t_hist'] = []
136 136 view['u_hist'] = []
137
137
138 138 # set vector/scalar implementation details
139 139 impl = {}
140 140 impl['ic'] = 'vectorized'
141 141 impl['inner'] = 'scalar'
142 142 impl['bc'] = 'vectorized'
143
143
144 144 # execute some files so that the classes we need will be defined on the engines:
145 145 view.run('RectPartitioner.py')
146 146 view.run('wavesolver.py')
147
147
148 148 # setup remote partitioner
149 149 # note that Reference means that the argument passed to setup_partitioner will be the
150 150 # object named 'my_id' in the engine's namespace
@@ -156,7 +156,7 b" if __name__ == '__main__':"
156 156
157 157 # lambda for calling solver.solve:
158 158 _solve = lambda *args, **kwargs: solver.solve(*args, **kwargs)
159
159
160 160 if ns.scalar:
161 161 impl['inner'] = 'scalar'
162 162 # run first with element-wise Python operations for each cell
@@ -171,12 +171,12 b" if __name__ == '__main__':"
171 171 norm = -1
172 172 t1 = time.time()
173 173 print 'scalar inner-version, Wtime=%g, norm=%g'%(t1-t0, norm)
174
174
175 175 impl['inner'] = 'vectorized'
176 176 # setup new solvers
177 177 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl)
178 178 view.execute('mpi.barrier()')
179
179
180 180 # run again with numpy vectorized inner-implementation
181 181 t0 = time.time()
182 182 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test)#, user_action=wave_saver)
@@ -189,7 +189,7 b" if __name__ == '__main__':"
189 189 norm = -1
190 190 t1 = time.time()
191 191 print 'vector inner-version, Wtime=%g, norm=%g'%(t1-t0, norm)
192
192
193 193 # if ns.save is True, then u_hist stores the history of u as a list
194 194 # If the partion scheme is Nx1, then u can be reconstructed via 'gather':
195 195 if ns.save and partition[-1] == 1:
@@ -11,7 +11,7 b' An example of running the program is (8 processors, 4x2 partition,'
11 11 $ ipclusterz start -n 8 # start 8 engines
12 12 $ ./parallelwave.py --grid 200 200 --partition 4 2
13 13
14 See also parallelwave-mpi, which runs the same program, but uses MPI
14 See also parallelwave-mpi, which runs the same program, but uses MPI
15 15 (via mpi4py) for the inter-engine communication.
16 16
17 17 Authors
@@ -50,11 +50,11 b' def wave_saver(u, x, y, t):'
50 50 global t_hist
51 51 t_hist.append(t)
52 52 u_hist.append(1.0*u)
53
53
54 54
55 55 # main program:
56 56 if __name__ == '__main__':
57
57
58 58 parser = argparse.ArgumentParser()
59 59 paa = parser.add_argument
60 60 paa('--grid', '-g',
@@ -75,16 +75,16 b" if __name__ == '__main__':"
75 75 paa('-t', '--tstop',
76 76 type=float, default=1.,
77 77 help="Time units to run")
78 paa('--profile',
78 paa('--profile',
79 79 type=unicode, default=u'default',
80 80 help="Specify the ipcluster profile for the client to connect to.")
81 paa('--save',
81 paa('--save',
82 82 action='store_true',
83 83 help="Add this flag to save the time/wave history during the run.")
84 paa('--scalar',
84 paa('--scalar',
85 85 action='store_true',
86 86 help="Also run with scalar interior implementation, to see vector speedup.")
87
87
88 88 ns = parser.parse_args()
89 89 # set up arguments
90 90 grid = ns.grid
@@ -97,25 +97,25 b" if __name__ == '__main__':"
97 97 user_action = wave_saver
98 98 else:
99 99 user_action = None
100
100
101 101 num_cells = 1.0*(grid[0]-1)*(grid[1]-1)
102 102 final_test = True
103
103
104 104 # create the Client
105 105 rc = Client(profile=ns.profile)
106 106 num_procs = len(rc.ids)
107
107
108 108 if partition is None:
109 109 partition = [num_procs,1]
110 110 else:
111 111 num_procs = min(num_procs, partition[0]*partition[1])
112
112
113 113 assert partition[0]*partition[1] == num_procs, "can't map partition %s to %i engines"%(partition, num_procs)
114
114
115 115 # construct the View:
116 116 view = rc[:num_procs]
117 117 print "Running %s system on %s processes until %f"%(grid, partition, tstop)
118
118
119 119 # functions defining initial/boundary/source conditions
120 120 def I(x,y):
121 121 from numpy import exp
@@ -126,7 +126,7 b" if __name__ == '__main__':"
126 126 # return 10*exp(-(x - sin(100*t))**2)
127 127 def bc(x,y,t):
128 128 return 0.0
129
129
130 130 # initialize t_hist/u_hist for saving the state at each step (optional)
131 131 view['t_hist'] = []
132 132 view['u_hist'] = []
@@ -136,16 +136,16 b" if __name__ == '__main__':"
136 136 impl['ic'] = 'vectorized'
137 137 impl['inner'] = 'scalar'
138 138 impl['bc'] = 'vectorized'
139
139
140 140 # execute some files so that the classes we need will be defined on the engines:
141 141 view.execute('import numpy')
142 142 view.run('communicator.py')
143 143 view.run('RectPartitioner.py')
144 144 view.run('wavesolver.py')
145
145
146 146 # scatter engine IDs
147 147 view.scatter('my_id', range(num_procs), flatten=True)
148
148
149 149 # create the engine connectors
150 150 view.execute('com = EngineCommunicator()')
151 151
@@ -154,7 +154,7 b" if __name__ == '__main__':"
154 154 peers = ar.get_dict()
155 155 # print peers
156 156 # this is a dict, keyed by engine ID, of the connection info for the EngineCommunicators
157
157
158 158 # setup remote partitioner
159 159 # note that Reference means that the argument passed to setup_partitioner will be the
160 160 # object named 'com' in the engine's namespace
@@ -180,14 +180,14 b" if __name__ == '__main__':"
180 180 norm = -1
181 181 t1 = time.time()
182 182 print 'scalar inner-version, Wtime=%g, norm=%g'%(t1-t0, norm)
183
183
184 184 # run again with faster numpy-vectorized inner implementation:
185 185 impl['inner'] = 'vectorized'
186 186 # setup remote solvers
187 187 view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl)
188 188
189 189 t0 = time.time()
190
190
191 191 ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test)#, user_action=wave_saver)
192 192 if final_test:
193 193 # this sum is performed element-wise as results finish
@@ -198,7 +198,7 b" if __name__ == '__main__':"
198 198 norm = -1
199 199 t1 = time.time()
200 200 print 'vector inner-version, Wtime=%g, norm=%g'%(t1-t0, norm)
201
201
202 202 # if ns.save is True, then u_hist stores the history of u as a list
203 203 # If the partion scheme is Nx1, then u can be reconstructed via 'gather':
204 204 if ns.save and partition[-1] == 1:
@@ -40,7 +40,7 b' class WaveSolver(object):'
40 40 tstop is the stop time for the simulation.
41 41
42 42 I, f are functions: I(x,y), f(x,y,t)
43
43
44 44 user_action: function of (u, x, y, t) called at each time
45 45 level (x and y are one-dimensional coordinate vectors).
46 46 This function allows the calling code to plot the solution,
@@ -67,13 +67,13 b' class WaveSolver(object):'
67 67 final_test: true means the discrete L2-norm of the final solution is
68 68 to be computed.
69 69 """
70
70
71 71 def __init__(self, I, f, c, bc, Lx, Ly, partitioner=None, dt=-1,
72 user_action=None,
72 user_action=None,
73 73 implementation={'ic': 'vectorized', # or 'scalar'
74 74 'inner': 'vectorized',
75 75 'bc': 'vectorized'}):
76
76
77 77 nx = partitioner.global_num_cells[0] # number of global cells in x dir
78 78 ny = partitioner.global_num_cells[1] # number of global cells in y dir
79 79 dx = Lx/float(nx)
@@ -130,7 +130,7 b' class WaveSolver(object):'
130 130 u_2[i,j] = u_1[i,j] + \
131 131 0.5*Cx2*(u_1[i-1,j] - 2*u_1[i,j] + u_1[i+1,j]) + \
132 132 0.5*Cy2*(u_1[i,j-1] - 2*u_1[i,j] + u_1[i,j+1]) + \
133 dt2*f(x[i], y[j], 0.0)
133 dt2*f(x[i], y[j], 0.0)
134 134
135 135 # boundary values of u_2 (equals u(t=dt) due to du/dt=0)
136 136 i = 0
@@ -162,8 +162,8 b' class WaveSolver(object):'
162 162 user_action(u_1, x, y, t) # allow user to plot etc.
163 163 # print list(self.us[2][2])
164 164 self.us = (u,u_1,u_2)
165
166
165
166
167 167 def solve(self, tstop, dt=-1, user_action=None, verbose=False, final_test=False):
168 168 t0=time.time()
169 169 f=self.f
@@ -191,7 +191,7 b' class WaveSolver(object):'
191 191 upper_y_neigh = partitioner.upper_neighbors[1]
192 192 u,u_1,u_2 = self.us
193 193 # u_1 = self.u_1
194
194
195 195 t = 0.0
196 196 while t <= tstop:
197 197 t_old = t; t += dt
@@ -211,7 +211,7 b' class WaveSolver(object):'
211 211 Cx2*(u_1[0:nx-1,1:ny] - 2*u_1[1:nx,1:ny] + u_1[2:nx+1,1:ny]) + \
212 212 Cy2*(u_1[1:nx,0:ny-1] - 2*u_1[1:nx,1:ny] + u_1[1:nx,2:ny+1]) + \
213 213 dt2*f(xv[1:nx,1:ny], yv[1:nx,1:ny], t_old)
214
214
215 215 # insert boundary conditions (if there's no neighbor):
216 216 if lower_x_neigh < 0:
217 217 if implementation['bc'] == 'scalar':
@@ -63,14 +63,14 b' def rescale_arr(arr,amin,amax):'
63 63 >>> rescale_arr(a,3,6)
64 64 array([ 3. , 3.75, 4.5 , 5.25, 6. ])
65 65 """
66
66
67 67 # old bounds
68 68 m = arr.min()
69 69 M = arr.max()
70 70 # scale/offset
71 71 s = float(amax-amin)/(M-m)
72 72 d = amin - s*m
73
73
74 74 # Apply clip before returning to cut off possible overflows outside the
75 75 # intended range due to roundoff error, so that we can absolutely guarantee
76 76 # that on output, there are no values > amax or < amin.
@@ -98,7 +98,7 b' def text_cleanup(text, min_length=3,'
98 98 """
99 99 return [w for w in text.lower().split()
100 100 if len(w)>=min_length and w not in remove]
101
101
102 102
103 103 def print_vk(lst):
104 104 """Print a list of value/key pairs nicely formatted in key/value order."""
@@ -120,7 +120,7 b' def word_freq(text):'
120 120
121 121 freqs = {}
122 122 for word in text:
123 freqs[word] = freqs.get(word, 0) + 1
123 freqs[word] = freqs.get(word, 0) + 1
124 124 return freqs
125 125
126 126
@@ -131,7 +131,7 b' def sort_freqs(freqs):'
131 131 ----------
132 132 freqs : dict
133 133 A dict with string keys and integer values.
134
134
135 135 Return
136 136 ------
137 137 items : list
@@ -155,7 +155,7 b' def summarize_freq_hist(freqs, n=10):'
155 155 freqs : dict or list
156 156 Word frequencies, represented either as a dict of word->count, or as a
157 157 list of count->word pairs.
158
158
159 159 n : int
160 160 The number of least/most frequent words to print.
161 161 """
@@ -199,7 +199,7 b' def get_text_from_url(url):'
199 199
200 200 def co_occurrences(lines, words):
201 201 """Return histogram of co-occurrences of words in a list of lines.
202
202
203 203 Parameters
204 204 ----------
205 205 lines : list
@@ -210,7 +210,7 b' def co_occurrences(lines, words):'
210 210 searched for co-occurrences.
211 211 """
212 212 wpairs = all_pairs(words)
213
213
214 214 # Now build histogram of co-occurrences
215 215 co_occur = {}
216 216 for w1, w2 in wpairs:
@@ -244,7 +244,7 b' def plot_graph(wgraph, pos=None):'
244 244 sizes.append(d['count'])
245 245 degrees.append(wgraph.degree(n))
246 246 sizes = rescale_arr(np.array(sizes, dtype=float), 100, 1000)
247
247
248 248 # Compute layout and label edges according to weight
249 249 pos = nx.spring_layout(wgraph) if pos is None else pos
250 250 labels = {}
@@ -256,7 +256,7 b' def plot_graph(wgraph, pos=None):'
256 256
257 257 # remap width to 1-10 range
258 258 width = rescale_arr(np.array(width, dtype=float), 1, 15)
259
259
260 260 # Create figure
261 261 fig = plt.figure()
262 262 ax = fig.add_subplot(111)
@@ -283,7 +283,7 b' def plot_word_histogram(freqs, show=10, title=None):'
283 283 # interpret as a fraction
284 284 start = -int(round(show*len(freqs)))
285 285 show_f = sorted_f[start:]
286
286
287 287 # Now, extract words and counts, plot
288 288 n_words = len(show_f)
289 289 ind = np.arange(n_words)
@@ -329,48 +329,48 b' def summarize_centrality(centrality):'
329 329 # # Configure user variables here
330 330 # # Specify the url (can be a local file path) of the text file to analyze.
331 331 # # If not given, it's read from the command line as the first argument
332 #
332 #
333 333 # # 11226 titles of recent articles in arxiv/math/prob
334 334 # default_url = "http://bibserver.berkeley.edu/tmp/titles.txt"
335 335 # # Number of words to display in detailed histogram
336 336 # n_words = 15
337 337 # # Number of words to use as nodes for co-occurrence graph.
338 338 # n_nodes = 15
339 #
339 #
340 340 # # End of user configuration
341 #
341 #
342 342 # # Actual code starts here
343 343 # try:
344 344 # url = sys.argv[1]
345 345 # except IndexError:
346 346 # url = default_url
347 #
347 #
348 348 # # Fetch text and do basic preprocessing
349 349 # text = get_text_from_url(url).lower()
350 350 # lines = text.splitlines()
351 351 # words = text_cleanup(text)
352 #
352 #
353 353 # # Compute frequency histogram
354 354 # wf = word_freq(words)
355 355 # sorted_wf = sort_freqs(wf)
356 #
356 #
357 357 # # Build a graph from the n_nodes most frequent words
358 358 # popular = sorted_wf[-n_nodes:]
359 359 # pop_words = [wc[0] for wc in popular]
360 360 # co_occur = co_occurrences(lines, pop_words)
361 361 # wgraph = co_occurrences_graph(popular, co_occur, cutoff=1)
362 362 # centrality = nx.eigenvector_centrality_numpy(wgraph)
363 #
363 #
364 364 # # Print summaries of single-word frequencies and graph structure
365 365 # summarize_freq_hist(sorted_wf)
366 366 # summarize_centrality(centrality)
367 #
367 #
368 368 # # Plot histogram and graph
369 369 # plt.close('all')
370 370 # plot_word_histogram(sorted_wf, n_words,
371 371 # "Frequencies for %s most frequent words" % n_words)
372 372 # plot_word_histogram(sorted_wf, 1.0, "Frequencies for entire word list")
373 373 # plot_graph(wgraph)
374 #
374 #
375 375 # # Display figures
376 376 # plt.show()
@@ -42,7 +42,7 b' extensions = ['
42 42 'sphinx.ext.autodoc',
43 43 'sphinx.ext.doctest',
44 44 'inheritance_diagram',
45 'ipython_console_highlighting',
45 'ipython_console_highlighting',
46 46 'numpydoc', # to preprocess docstrings
47 47 ]
48 48
@@ -168,7 +168,7 b' class ApiDocWriter(object):'
168 168 functions, classes = self._parse_lines(f)
169 169 f.close()
170 170 return functions, classes
171
171
172 172 def _parse_lines(self, linesource):
173 173 ''' Parse lines of text for functions and classes '''
174 174 functions = []
@@ -210,9 +210,9 b' class ApiDocWriter(object):'
210 210 return ''
211 211
212 212 # Make a shorter version of the uri that omits the package name for
213 # titles
213 # titles
214 214 uri_short = re.sub(r'^%s\.' % self.package_name,'',uri)
215
215
216 216 ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n'
217 217
218 218 chap_title = uri_short
@@ -291,7 +291,7 b' class ApiDocWriter(object):'
291 291 elif match_type == 'package':
292 292 patterns = self.package_skip_patterns
293 293 else:
294 raise ValueError('Cannot interpret match type "%s"'
294 raise ValueError('Cannot interpret match type "%s"'
295 295 % match_type)
296 296 # Match to URI without package name
297 297 L = len(self.package_name)
@@ -307,7 +307,7 b' class ApiDocWriter(object):'
307 307 return True
308 308
309 309 def discover_modules(self):
310 ''' Return module sequence discovered from ``self.package_name``
310 ''' Return module sequence discovered from ``self.package_name``
311 311
312 312
313 313 Parameters
@@ -328,7 +328,7 b' class ApiDocWriter(object):'
328 328 >>> dw.package_skip_patterns.append('\.util$')
329 329 >>> 'sphinx.util' in dw.discover_modules()
330 330 False
331 >>>
331 >>>
332 332 '''
333 333 modules = [self.package_name]
334 334 # raw directory parsing
@@ -351,7 +351,7 b' class ApiDocWriter(object):'
351 351 self._survives_exclude(module_uri, 'module')):
352 352 modules.append(module_uri)
353 353 return sorted(modules)
354
354
355 355 def write_modules_api(self, modules,outdir):
356 356 # write the list
357 357 written_modules = []
@@ -376,7 +376,7 b' class ApiDocWriter(object):'
376 376 outdir : string
377 377 Directory name in which to store files
378 378 We create automatic filenames for each module
379
379
380 380 Returns
381 381 -------
382 382 None
@@ -390,7 +390,7 b' class ApiDocWriter(object):'
390 390 # compose list of modules
391 391 modules = self.discover_modules()
392 392 self.write_modules_api(modules,outdir)
393
393
394 394 def write_index(self, outdir, froot='gen', relative_to=None):
395 395 """Make a reST API index file from written files
396 396
@@ -13,7 +13,7 b' import re'
13 13
14 14 # Third party
15 15 from pygments.lexer import Lexer, do_insertions
16 from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer,
16 from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer,
17 17 PythonTracebackLexer)
18 18 from pygments.token import Comment, Generic
19 19
@@ -48,7 +48,7 b' class IPythonConsoleLexer(Lexer):'
48 48
49 49 - It assumes the default IPython prompts, not customized ones.
50 50 """
51
51
52 52 name = 'IPython console session'
53 53 aliases = ['ipython']
54 54 mimetypes = ['text/x-ipython-console']
@@ -2,8 +2,8 b''
2 2 # -*- coding: utf-8 -*-
3 3 """Setup script for IPython.
4 4
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
5 Under Posix environments it works like a typical setup.py script.
6 Under Windows, the command sdist is not supported, since IPython
7 7 requires utilities which are not available under Windows."""
8 8
9 9 #-----------------------------------------------------------------------------
@@ -54,9 +54,9 b' from distutils.core import setup'
54 54 from IPython.utils.path import target_update
55 55
56 56 from setupbase import (
57 setup_args,
58 find_packages,
59 find_package_data,
57 setup_args,
58 find_packages,
59 find_package_data,
60 60 find_scripts,
61 61 find_data_files,
62 62 check_for_dependencies,
@@ -113,7 +113,7 b" if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):"
113 113 # target_update()
114 114 to_update = [
115 115 # FIXME - Disabled for now: we need to redo an automatic way
116 # of generating the magic info inside the rst.
116 # of generating the magic info inside the rst.
117 117 #('docs/magic.tex',
118 118 #['IPython/Magic.py'],
119 119 #"cd doc && ./update_magic.sh" ),
@@ -176,9 +176,9 b" if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'):"
176 176 docdeps,
177 177 "cd docs && make dist")
178 178 )
179
179
180 180 [ target_update(*t) for t in to_update ]
181
181
182 182 #---------------------------------------------------------------------------
183 183 # Find all the packages, package data, and data_files
184 184 #---------------------------------------------------------------------------
@@ -207,7 +207,7 b" if sys.platform == 'win32':"
207 207 if len(needs_setuptools.intersection(sys.argv)) > 0:
208 208 import setuptools
209 209
210 # This dict is used for passing extra arguments that are setuptools
210 # This dict is used for passing extra arguments that are setuptools
211 211 # specific to setup
212 212 setuptools_extra_args = {}
213 213
@@ -233,7 +233,7 b" if 'setuptools' in sys.modules:"
233 233 else:
234 234 pass
235 235 # do we want to install readline here?
236
236
237 237 # Script to be run by the windows binary installer after the default setup
238 238 # routine, to add shortcuts and similar windows-only things. Windows
239 239 # post-install scripts MUST reside in the scripts/ dir, otherwise distutils
@@ -43,7 +43,7 b' pjoin = os.path.join'
43 43 def oscmd(s):
44 44 print(">", s)
45 45 os.system(s)
46
46
47 47 try:
48 48 execfile
49 49 except NameError:
@@ -120,7 +120,7 b' def find_package_data():'
120 120 """
121 121 # This is not enough for these things to appear in an sdist.
122 122 # We need to muck with the MANIFEST to get this to work
123
123
124 124 # walk notebook resources:
125 125 cwd = os.getcwd()
126 126 os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook'))
@@ -130,7 +130,7 b' def find_package_data():'
130 130 for parent, dirs, files in static_walk:
131 131 for f in files:
132 132 static_data.append(os.path.join(parent, f))
133
133
134 134 package_data = {
135 135 'IPython.config.profile' : ['README', '*/*.py'],
136 136 'IPython.testing' : ['*.txt'],
@@ -151,23 +151,23 b' def make_dir_struct(tag,base,out_base):'
151 151
152 152 XXX - this needs a proper docstring!
153 153 """
154
154
155 155 # we'll use these a lot below
156 156 lbase = len(base)
157 157 pathsep = os.path.sep
158 158 lpathsep = len(pathsep)
159
159
160 160 out = []
161 161 for (dirpath,dirnames,filenames) in os.walk(base):
162 162 # we need to strip out the dirpath from the base to map it to the
163 163 # output (installation) path. This requires possibly stripping the
164 164 # path separator, because otherwise pjoin will not work correctly
165 165 # (pjoin('foo/','/bar') returns '/bar').
166
166
167 167 dp_eff = dirpath[lbase:]
168 168 if dp_eff.startswith(pathsep):
169 169 dp_eff = dp_eff[lpathsep:]
170 # The output path must be anchored at the out_base marker
170 # The output path must be anchored at the out_base marker
171 171 out_path = pjoin(out_base,dp_eff)
172 172 # Now we can generate the final filenames. Since os.walk only produces
173 173 # filenames, we must join back with the dirpath to get full valid file
@@ -178,7 +178,7 b' def make_dir_struct(tag,base,out_base):'
178 178 out.append((out_path, pfiles))
179 179
180 180 return out
181
181
182 182
183 183 def find_data_files():
184 184 """
@@ -186,10 +186,10 b' def find_data_files():'
186 186
187 187 Most of these are docs.
188 188 """
189
189
190 190 docdirbase = pjoin('share', 'doc', 'ipython')
191 191 manpagebase = pjoin('share', 'man', 'man1')
192
192
193 193 # Simple file lists can be made by hand
194 194 manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz')))
195 195 if not manpages:
@@ -241,19 +241,19 b' def make_man_update_target(manpage):'
241 241 gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" %
242 242 locals() )
243 243 return (manpath_gz, [manpath], gz_cmd)
244
244
245 245 #---------------------------------------------------------------------------
246 246 # Find scripts
247 247 #---------------------------------------------------------------------------
248 248
249 249 def find_scripts(entry_points=False, suffix=''):
250 250 """Find IPython's scripts.
251
251
252 252 if entry_points is True:
253 253 return setuptools entry_point-style definitions
254 254 else:
255 255 return file paths of plain scripts [default]
256
256
257 257 suffix is appended to script names if entry_points is True, so that the
258 258 Python 3 scripts get named "ipython3" etc.
259 259 """
@@ -293,7 +293,7 b" def find_scripts(entry_points=False, suffix=''):"
293 293
294 294 def check_for_dependencies():
295 295 """Check for IPython's dependencies.
296
296
297 297 This function should NOT be called if running under setuptools!
298 298 """
299 299 from setupext.setupext import (
@@ -308,7 +308,7 b' def check_for_dependencies():'
308 308 print_status('platform', sys.platform)
309 309 if sys.platform == 'win32':
310 310 print_status('Windows version', sys.getwindowsversion())
311
311
312 312 print_raw("")
313 313 print_raw("OPTIONAL DEPENDENCIES")
314 314
@@ -69,7 +69,7 b' def check_for_sphinx():'
69 69 print_status('sphinx', "Not found (required for building documentation)")
70 70 return False
71 71 else:
72 print_status('sphinx', sphinx.__version__)
72 print_status('sphinx', sphinx.__version__)
73 73 return True
74 74
75 75 def check_for_pygments():
@@ -142,7 +142,7 b' def check_for_pyzmq():'
142 142 if zmq.__version__ < '2.1.4':
143 143 print_status('pyzmq', "no (have %s, but require >= 2.1.4 for"
144 144 " qtconsole and parallel computing capabilities)"%zmq.__version__)
145
145
146 146 else:
147 147 print_status("pyzmq", zmq.__version__)
148 148 return True
@@ -14,7 +14,7 b' def main():'
14 14 print "Entering ipython for profiling. Type 'Exit' for profiler report"
15 15 IPython.ipapi.launch_new_instance()
16 16
17 if len(sys.argv) == 1:
17 if len(sys.argv) == 1:
18 18 profile.run('main()', 'ipython_profiler_results')
19 19
20 20 import pstats
General Comments 0
You need to be logged in to leave comments. Login now