diff --git a/IPython/config/application.py b/IPython/config/application.py index ec71818..261e816 100644 --- a/IPython/config/application.py +++ b/IPython/config/application.py @@ -109,10 +109,10 @@ class Application(SingletonConfigurable): new = getattr(logging, new) self.log_level = new self.log.setLevel(new) - + # the alias map for configurables aliases = Dict({'log-level' : 'Application.log_level'}) - + # flags for loading Configurables or store_const style flags # flags are loaded from this dict by '--key' flags # this must be a dict of two-tuples, the first element being the Config/dict @@ -124,20 +124,20 @@ class Application(SingletonConfigurable): assert len(value) == 2, "Bad flag: %r:%s"%(key,value) assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s"%(key,value) assert isinstance(value[1], basestring), "Bad flag: %r:%s"%(key,value) - - + + # subcommands for launching other applications # if this is not empty, this will be a parent Application - # this must be a dict of two-tuples, + # this must be a dict of two-tuples, # the first element being the application class/import string # and the second being the help string for the subcommand subcommands = Dict() # parse_command_line will initialize a subapp, if requested subapp = Instance('IPython.config.application.Application', allow_none=True) - + # extra command-line arguments that don't set config values extra_args = List(Unicode) - + def __init__(self, **kwargs): SingletonConfigurable.__init__(self, **kwargs) @@ -145,7 +145,7 @@ class Application(SingletonConfigurable): # options and config files. if self.__class__ not in self.classes: self.classes.insert(0, self.__class__) - + self.init_logging() def _config_changed(self, name, old, new): @@ -157,7 +157,7 @@ class Application(SingletonConfigurable): """Start logging for this application. The default is to log to stdout using a StreaHandler. The log level - starts at loggin.WARN, but this can be adjusted by setting the + starts at loggin.WARN, but this can be adjusted by setting the ``log_level`` attribute. """ self.log = logging.getLogger(self.__class__.__name__) @@ -174,36 +174,36 @@ class Application(SingletonConfigurable): def initialize(self, argv=None): """Do the basic steps to configure me. - + Override in subclasses. """ self.parse_command_line(argv) - - + + def start(self): """Start the app mainloop. - + Override in subclasses. """ if self.subapp is not None: return self.subapp.start() - + def print_alias_help(self): """Print the alias part of the help.""" if not self.aliases: return - + lines = [] classdict = {} for cls in self.classes: # include all parents (up to, but excluding Configurable) in available names for c in cls.mro()[:-3]: classdict[c.__name__] = c - + for alias, longname in self.aliases.iteritems(): classname, traitname = longname.split('.',1) cls = classdict[classname] - + trait = cls.class_traits(config=True)[traitname] help = cls.class_get_trait_help(trait).splitlines() # reformat first line @@ -213,12 +213,12 @@ class Application(SingletonConfigurable): lines.extend(help) # lines.append('') print os.linesep.join(lines) - + def print_flag_help(self): """Print the flag part of the help.""" if not self.flags: return - + lines = [] for m, (cfg,help) in self.flags.iteritems(): prefix = '--' if len(m) > 1 else '-' @@ -226,7 +226,7 @@ class Application(SingletonConfigurable): lines.append(indent(dedent(help.strip()))) # lines.append('') print os.linesep.join(lines) - + def print_options(self): if not self.flags and not self.aliases: return @@ -240,12 +240,12 @@ class Application(SingletonConfigurable): self.print_flag_help() self.print_alias_help() print - + def print_subcommands(self): """Print the subcommand part of the help.""" if not self.subcommands: return - + lines = ["Subcommands"] lines.append('-'*len(lines[0])) lines.append('') @@ -258,15 +258,15 @@ class Application(SingletonConfigurable): lines.append(indent(dedent(help.strip()))) lines.append('') print os.linesep.join(lines) - + def print_help(self, classes=False): """Print the help for each Configurable class in self.classes. - + If classes=False (the default), only flags and aliases are printed. """ self.print_subcommands() self.print_options() - + if classes: if self.classes: print "Class parameters" @@ -275,7 +275,7 @@ class Application(SingletonConfigurable): for p in wrap_paragraphs(self.keyvalue_description): print p print - + for cls in self.classes: cls.class_print_help() print @@ -315,21 +315,21 @@ class Application(SingletonConfigurable): # Save the combined config as self.config, which triggers the traits # events. self.config = newconfig - + def initialize_subcommand(self, subc, argv=None): """Initialize a subcommand with argv.""" subapp,help = self.subcommands.get(subc) - + if isinstance(subapp, basestring): subapp = import_item(subapp) - + # clear existing instances self.__class__.clear_instance() # instantiate self.subapp = subapp.instance() # and initialize subapp self.subapp.initialize(argv) - + def parse_command_line(self, argv=None): """Parse the command line arguments.""" argv = sys.argv[1:] if argv is None else argv @@ -340,7 +340,7 @@ class Application(SingletonConfigurable): if re.match(r'^\w(\-?\w)*$', subc) and subc in self.subcommands: # it's a subcommand, and *not* a flag or class parameter return self.initialize_subcommand(subc, subargv) - + if '-h' in argv or '--help' in argv or '--help-all' in argv: self.print_description() self.print_help('--help-all' in argv) @@ -350,7 +350,7 @@ class Application(SingletonConfigurable): if '--version' in argv: self.print_version() self.exit(0) - + loader = KVArgParseConfigLoader(argv=argv, aliases=self.aliases, flags=self.flags) try: @@ -383,7 +383,7 @@ class Application(SingletonConfigurable): else: self.log.debug("Loaded config file: %s", loader.full_filename) self.update_config(config) - + def generate_config_file(self): """generate default config file from Configurables""" lines = ["# Configuration file for %s."%self.name] @@ -404,10 +404,10 @@ class Application(SingletonConfigurable): def boolean_flag(name, configurable, set_help='', unset_help=''): """Helper for building basic --trait, --no-trait flags. - + Parameters ---------- - + name : str The name of the flag. configurable : str @@ -416,10 +416,10 @@ def boolean_flag(name, configurable, set_help='', unset_help=''): help string for --name flag unset_help : unicode help string for --no-name flag - + Returns ------- - + cfg : dict A dict with two keys: 'name', and 'no-name', for setting and unsetting the trait, respectively. @@ -427,9 +427,9 @@ def boolean_flag(name, configurable, set_help='', unset_help=''): # default helpstrings set_help = set_help or "set %s=True"%configurable unset_help = unset_help or "set %s=False"%configurable - + cls,trait = configurable.split('.') - + setter = {cls : {trait : True}} unsetter = {cls : {trait : False}} return {name : (setter, set_help), 'no-'+name : (unsetter, unset_help)} diff --git a/IPython/config/configurable.py b/IPython/config/configurable.py index 8cfb695..275d2b5 100644 --- a/IPython/config/configurable.py +++ b/IPython/config/configurable.py @@ -55,16 +55,16 @@ class Configurable(HasTraits): Parameters ---------- config : Config - If this is empty, default values are used. If config is a + If this is empty, default values are used. If config is a :class:`Config` instance, it will be used to configure the instance. - + Notes ----- Subclasses of Configurable must call the :meth:`__init__` method of - :class:`Configurable` *before* doing anything else and using + :class:`Configurable` *before* doing anything else and using :func:`super`:: - + class MyConfigurable(Configurable): def __init__(self, config=None): super(MyConfigurable, self).__init__(config) @@ -82,7 +82,7 @@ class Configurable(HasTraits): # making that a class attribute. # self.config = deepcopy(config) self.config = config - # This should go second so individual keyword arguments override + # This should go second so individual keyword arguments override # the values in config. super(Configurable, self).__init__(**kwargs) self.created = datetime.datetime.now() @@ -105,11 +105,11 @@ class Configurable(HasTraits): # classes that are Configurable subclasses. This starts with Configurable # and works down the mro loading the config for each section. section_names = [cls.__name__ for cls in \ - reversed(self.__class__.__mro__) if + reversed(self.__class__.__mro__) if issubclass(cls, Configurable) and issubclass(self.__class__, cls)] for sname in section_names: - # Don't do a blind getattr as that would cause the config to + # Don't do a blind getattr as that would cause the config to # dynamically create the section with name self.__class__.__name__. if new._has_section(sname): my_config = new[sname] @@ -149,7 +149,7 @@ class Configurable(HasTraits): help = cls.class_get_trait_help(v) final_help.append(help) return '\n'.join(final_help) - + @classmethod def class_get_trait_help(cls, trait): """Get the help string for a single trait.""" @@ -167,7 +167,7 @@ class Configurable(HasTraits): if 'Enum' in trait.__class__.__name__: # include Enum choices lines.append(indent('Choices: %r'%(trait.values,))) - + help = trait.get_metadata('help') if help is not None: help = '\n'.join(wrap_paragraphs(help, 76)) @@ -185,9 +185,9 @@ class Configurable(HasTraits): def c(s): """return a commented, wrapped block.""" s = '\n\n'.join(wrap_paragraphs(s, 78)) - + return '# ' + s.replace('\n', '\n# ') - + # section header breaker = '#' + '-'*78 s = "# %s configuration"%cls.__name__ @@ -202,7 +202,7 @@ class Configurable(HasTraits): if desc: lines.append(c(desc)) lines.append('') - + parents = [] for parent in cls.mro(): # only include parents that are not base classes @@ -211,20 +211,20 @@ class Configurable(HasTraits): if parent is not cls and issubclass(parent, Configurable) and \ parent.class_traits(config=True): parents.append(parent) - + if parents: pstr = ', '.join([ p.__name__ for p in parents ]) lines.append(c('%s will inherit config from: %s'%(cls.__name__, pstr))) lines.append('') - + for name,trait in cls.class_traits(config=True).iteritems(): help = trait.get_metadata('help') or '' lines.append(c(help)) lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value())) lines.append('') return '\n'.join(lines) - - + + class SingletonConfigurable(Configurable): """A configurable that only allows one instance. @@ -235,20 +235,20 @@ class SingletonConfigurable(Configurable): """ _instance = None - + @classmethod def _walk_mro(cls): """Walk the cls.mro() for parent classes that are also singletons - + For use in instance() """ - + for subclass in cls.mro(): if issubclass(cls, subclass) and \ issubclass(subclass, SingletonConfigurable) and \ subclass != SingletonConfigurable: yield subclass - + @classmethod def clear_instance(cls): """unset _instance for this class and singleton parents. @@ -260,7 +260,7 @@ class SingletonConfigurable(Configurable): # only clear instances that are instances # of the calling class subclass._instance = None - + @classmethod def instance(cls, *args, **kwargs): """Returns a global instance of this class. @@ -297,7 +297,7 @@ class SingletonConfigurable(Configurable): # parent classes' _instance attribute. for subclass in cls._walk_mro(): subclass._instance = inst - + if isinstance(cls._instance, cls): return cls._instance else: @@ -314,15 +314,15 @@ class SingletonConfigurable(Configurable): class LoggingConfigurable(Configurable): """A parent class for Configurables that log. - + Subclasses have a log trait, and the default behavior is to get the logger from the currently running Application via Application.instance().log. """ - + log = Instance('logging.Logger') def _log_default(self): from IPython.config.application import Application return Application.instance().log - - + + diff --git a/IPython/config/loader.py b/IPython/config/loader.py index 0e93156..1b97d11 100644 --- a/IPython/config/loader.py +++ b/IPython/config/loader.py @@ -53,14 +53,14 @@ class ArgumentError(ConfigLoaderError): class ArgumentParser(argparse.ArgumentParser): """Simple argparse subclass that prints help to stdout by default.""" - + def print_help(self, file=None): if file is None: file = sys.stdout return super(ArgumentParser, self).print_help(file) - + print_help.__doc__ = argparse.ArgumentParser.print_help.__doc__ - + #----------------------------------------------------------------------------- # Config class for holding config information #----------------------------------------------------------------------------- @@ -125,10 +125,10 @@ class Config(dict): # infinite recursion on top of PyPy. Instead, we manually fish the # bound method. is_section_key = self.__class__._is_section_key.__get__(self) - + # Because we use this for an exec namespace, we need to delegate # the lookup of names in __builtin__ to itself. This means - # that you can't have section or attribute names that are + # that you can't have section or attribute names that are # builtins. try: return getattr(builtin_mod, key) @@ -182,25 +182,25 @@ class Config(dict): class ConfigLoader(object): """A object for loading configurations from just about anywhere. - + The resulting configuration is packaged as a :class:`Struct`. - + Notes ----- - A :class:`ConfigLoader` does one thing: load a config from a source + A :class:`ConfigLoader` does one thing: load a config from a source (file, command line arguments) and returns the data as a :class:`Struct`. There are lots of things that :class:`ConfigLoader` does not do. It does not implement complex logic for finding config files. It does not handle - default values or merge multiple configs. These things need to be + default values or merge multiple configs. These things need to be handled elsewhere. """ def __init__(self): """A base class for config loaders. - + Examples -------- - + >>> cl = ConfigLoader() >>> config = cl.load_config() >>> config @@ -213,7 +213,7 @@ class ConfigLoader(object): def load_config(self): """Load a config from somewhere, return a :class:`Config` instance. - + Usually, this will cause self.config to be set and then returned. However, in most cases, :meth:`ConfigLoader.clear` should be called to erase any previous state. @@ -233,7 +233,7 @@ class FileConfigLoader(ConfigLoader): class PyFileConfigLoader(FileConfigLoader): """A config loader for pure python files. - + This calls execfile on a plain python file and looks for attributes that are all caps. These attribute are added to the config Struct. """ @@ -276,10 +276,10 @@ class PyFileConfigLoader(FileConfigLoader): # and self.config. The sub-config is loaded with the same path # as the parent, but it uses an empty config which is then merged # with the parents. - + # If a profile is specified, the config file will be loaded # from that profile - + def load_subconfig(fname, profile=None): # import here to prevent circular imports from IPython.core.profiledir import ProfileDir, ProfileDirError @@ -303,7 +303,7 @@ class PyFileConfigLoader(FileConfigLoader): pass else: self.config._merge(sub_config) - + # Again, this needs to be a closure and should be used in config # files to get the config being loaded. def get_config(): @@ -340,7 +340,7 @@ class CommandLineConfigLoader(ConfigLoader): # it succeeds. If it still fails, we let it raise. exec_str = u'self.config.' + lhs + '=' + repr(rhs) exec exec_str in locals(), globals() - + def _load_flag(self, cfg): """update self.config from a flag, which can be a dict or Config""" if isinstance(cfg, (dict, Config)): @@ -373,7 +373,7 @@ class KeyValueConfigLoader(CommandLineConfigLoader): """A config loader that loads key value pairs from the command line. This allows command line options to be gives in the following form:: - + ipython --profile="foo" --InteractiveShell.autocall=False """ @@ -414,13 +414,13 @@ class KeyValueConfigLoader(CommandLineConfigLoader): self.argv = argv self.aliases = aliases or {} self.flags = flags or {} - - + + def clear(self): super(KeyValueConfigLoader, self).clear() self.extra_args = [] - - + + def _decode_argv(self, argv, enc=None): """decode argv if bytes, using stin.encoding, falling back on default enc""" uargv = [] @@ -432,16 +432,16 @@ class KeyValueConfigLoader(CommandLineConfigLoader): arg = arg.decode(enc) uargv.append(arg) return uargv - - + + def load_config(self, argv=None, aliases=None, flags=None): """Parse the configuration and generate the Config object. - + After loading, any arguments that are not key-value or flags will be stored in self.extra_args - a list of unparsed command-line arguments. This is used for arguments such as input files or subcommands. - + Parameters ---------- argv : list, optional @@ -454,7 +454,7 @@ class KeyValueConfigLoader(CommandLineConfigLoader): Of the form: `{'alias' : 'Configurable.trait'}` flags : dict A dict of flags, keyed by str name. Values can be Config objects - or dicts. When the flag is triggered, The config is loaded as + or dicts. When the flag is triggered, The config is loaded as `self.config.update(cfg)`. """ from IPython.config.configurable import Configurable @@ -466,20 +466,20 @@ class KeyValueConfigLoader(CommandLineConfigLoader): aliases = self.aliases if flags is None: flags = self.flags - + # ensure argv is a list of unicode strings: uargv = self._decode_argv(argv) for idx,raw in enumerate(uargv): # strip leading '-' item = raw.lstrip('-') - + if raw == '--': # don't parse arguments after '--' # this is useful for relaying arguments to scripts, e.g. # ipython -i foo.py --pylab=qt -- args after '--' go-to-foo.py self.extra_args.extend(uargv[idx+1:]) break - + if kv_pattern.match(raw): lhs,rhs = item.split('=',1) # Substitute longnames for aliases. @@ -489,7 +489,7 @@ class KeyValueConfigLoader(CommandLineConfigLoader): # probably a mistyped alias, but not technically illegal warn.warn("Unrecognized alias: '%s', it will probably have no effect."%lhs) self._exec_config_str(lhs, rhs) - + elif flag_pattern.match(raw): if item in flags: cfg,help = flags[item] @@ -503,7 +503,7 @@ class KeyValueConfigLoader(CommandLineConfigLoader): else: raise ArgumentError("Invalid argument: '%s'"%raw) else: - # keep all args that aren't valid in a list, + # keep all args that aren't valid in a list, # in case our parent knows what to do with them. self.extra_args.append(item) return self.config @@ -541,7 +541,7 @@ class ArgParseConfigLoader(CommandLineConfigLoader): self.argv = argv self.aliases = aliases or {} self.flags = flags or {} - + self.parser_args = parser_args self.version = parser_kw.pop("version", None) kwargs = dict(argument_default=argparse.SUPPRESS) @@ -597,10 +597,10 @@ class ArgParseConfigLoader(CommandLineConfigLoader): class KVArgParseConfigLoader(ArgParseConfigLoader): """A config loader that loads aliases and flags with argparse, - but will use KVLoader for the rest. This allows better parsing + but will use KVLoader for the rest. This allows better parsing of common args, such as `ipython -c 'print 5'`, but still gets arbitrary config with `ipython --InteractiveShell.use_readline=False`""" - + def _convert_to_config(self): """self.parsed_data->self.config""" for k, v in vars(self.parsed_data).iteritems(): @@ -626,14 +626,14 @@ class KVArgParseConfigLoader(ArgParseConfigLoader): paa('--'+key, type=unicode, dest=value, nargs=nargs) for key, (value, help) in flags.iteritems(): if key in self.aliases: - # + # self.alias_flags[self.aliases[key]] = value continue if len(key) is 1: paa('-'+key, '--'+key, action='append_const', dest='_flags', const=value) else: paa('--'+key, action='append_const', dest='_flags', const=value) - + def _convert_to_config(self): """self.parsed_data->self.config, parse unrecognized extra args via KVLoader.""" # remove subconfigs list from namespace before transforming the Namespace @@ -642,7 +642,7 @@ class KVArgParseConfigLoader(ArgParseConfigLoader): del self.parsed_data._flags else: subcs = [] - + for k, v in vars(self.parsed_data).iteritems(): if v is None: # it was a flag that shares the name of an alias @@ -650,10 +650,10 @@ class KVArgParseConfigLoader(ArgParseConfigLoader): else: # eval the KV assignment self._exec_config_str(k, v) - + for subc in subcs: self._load_flag(subc) - + if self.extra_args: sub_parser = KeyValueConfigLoader() sub_parser.load_config(self.extra_args) diff --git a/IPython/core/alias.py b/IPython/core/alias.py index 4b80770..49fa3e2 100644 --- a/IPython/core/alias.py +++ b/IPython/core/alias.py @@ -49,7 +49,7 @@ def default_aliases(): # their case. For example, things like 'less' or 'clear' that manipulate # the terminal should NOT be declared here, as they will only work if the # kernel is running inside a true terminal, and not over the network. - + if os.name == 'posix': default_aliases = [('mkdir', 'mkdir'), ('rmdir', 'rmdir'), ('mv', 'mv -i'), ('rm', 'rm -i'), ('cp', 'cp -i'), @@ -94,7 +94,7 @@ def default_aliases(): ] else: default_aliases = [] - + return default_aliases @@ -213,33 +213,33 @@ class AliasManager(Configurable): return cmd def expand_alias(self, line): - """ Expand an alias in the command line - - Returns the provided command line, possibly with the first word + """ Expand an alias in the command line + + Returns the provided command line, possibly with the first word (command) translated according to alias expansion rules. - + [ipython]|16> _ip.expand_aliases("np myfile.txt") <16> 'q:/opt/np/notepad++.exe myfile.txt' """ - + pre,_,fn,rest = split_user_input(line) res = pre + self.expand_aliases(fn, rest) return res def expand_aliases(self, fn, rest): """Expand multiple levels of aliases: - + if: - + alias foo bar /tmp alias baz foo - + then: - + baz huhhahhei -> bar /tmp huhhahhei """ line = fn + " " + rest - + done = set() while 1: pre,_,fn,rest = split_user_input(line, shell_line_split) @@ -259,5 +259,5 @@ class AliasManager(Configurable): line=l2 else: break - + return line diff --git a/IPython/core/application.py b/IPython/core/application.py index 3384f62..a1e07f0 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -5,7 +5,7 @@ An application for IPython. All top-level applications should use the classes in this module for handling configuration and creating componenets. -The job of an :class:`Application` is to create the master configuration +The job of an :class:`Application` is to create the master configuration object and then create the configurable objects, passing the config to them. Authors: @@ -78,15 +78,15 @@ class BaseIPythonApplication(Application): name = Unicode(u'ipython') description = Unicode(u'IPython: an enhanced interactive Python shell.') version = Unicode(release.version) - + aliases = Dict(base_aliases) flags = Dict(base_flags) classes = List([ProfileDir]) - + # Track whether the config_file has changed, # because some logic happens only if we aren't using the default. config_file_specified = Bool(False) - + config_file_name = Unicode(u'ipython_config.py') def _config_file_name_default(self): return self.name.replace('-','_') + u'_config.py' @@ -108,13 +108,13 @@ class BaseIPythonApplication(Application): ) def _profile_default(self): return "python3" if py3compat.PY3 else "default" - + def _profile_changed(self, name, old, new): self.builtin_profile_dir = os.path.join( get_ipython_package_dir(), u'config', u'profile', new ) - - ipython_dir = Unicode(get_ipython_dir(), config=True, + + ipython_dir = Unicode(get_ipython_dir(), config=True, help=""" The name of the IPython directory. This directory is used for logging configuration (through profiles), history storage, etc. The default @@ -122,16 +122,16 @@ class BaseIPythonApplication(Application): the environment variable IPYTHON_DIR. """ ) - + overwrite = Bool(False, config=True, help="""Whether to overwrite existing config files when copying""") auto_create = Bool(False, config=True, help="""Whether to create profile dir if it doesn't exist""") - + config_files = List(Unicode) def _config_files_default(self): return [u'ipython_config.py'] - + copy_config_files = Bool(False, config=True, help="""Whether to install the default config files into the profile dir. If a new profile is being created, and IPython contains config files for that @@ -147,7 +147,7 @@ class BaseIPythonApplication(Application): # ensure even default IPYTHON_DIR exists if not os.path.exists(self.ipython_dir): self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir) - + #------------------------------------------------------------------------- # Various stages of Application creation #------------------------------------------------------------------------- @@ -183,7 +183,7 @@ class BaseIPythonApplication(Application): try: Application.load_config_file( self, - base_config, + base_config, path=self.config_file_paths ) except IOError: @@ -198,7 +198,7 @@ class BaseIPythonApplication(Application): try: Application.load_config_file( self, - self.config_file_name, + self.config_file_name, path=self.config_file_paths ) except IOError: @@ -258,17 +258,17 @@ class BaseIPythonApplication(Application): self.exit(1) else: self.log.info("Using existing profile dir: %r"%location) - + self.profile_dir = p self.config_file_paths.append(p.location) - + def init_config_files(self): """[optionally] copy default config files into profile dir.""" # copy config files path = self.builtin_profile_dir if self.copy_config_files: src = self.profile - + cfg = self.config_file_name if path and os.path.exists(os.path.join(path, cfg)): self.log.warn("Staging %r from %s into %r [overwrite=%s]"%( @@ -289,8 +289,8 @@ class BaseIPythonApplication(Application): self.log.warn("Staging bundled %s from %s into %r"%( cfg, self.profile, self.profile_dir.location) ) - - + + def stage_default_config_file(self): """auto generate default config file, and stage it into the profile.""" s = self.generate_config_file() @@ -299,8 +299,8 @@ class BaseIPythonApplication(Application): self.log.warn("Generating default config file: %r"%(fname)) with open(fname, 'w') as f: f.write(s) - - + + def initialize(self, argv=None): # don't hook up crash handler before parsing command-line self.parse_command_line(argv) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 351d647..aa4bdeb 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -126,7 +126,7 @@ def has_open_quotes(s): def protect_filename(s): """Escape a string to protect certain characters.""" - + return "".join([(ch in PROTECTABLES and '\\' + ch or ch) for ch in s]) @@ -156,7 +156,7 @@ def expand_user(path): path : str String to be expanded. If no ~ is present, the output is the same as the input. - + Returns ------- newpath : str @@ -170,7 +170,7 @@ def expand_user(path): tilde_expand = False tilde_val = '' newpath = path - + if path.startswith('~'): tilde_expand = True rest = path[1:] @@ -229,7 +229,7 @@ class CompletionSplitter(object): automatically builds the necessary """ # Private interface - + # A string of delimiter characters. The default value makes sense for # IPython's most typical usage patterns. _delims = DELIMS @@ -265,15 +265,15 @@ class CompletionSplitter(object): class Completer(Configurable): - + greedy = CBool(False, config=True, help="""Activate greedy completion - + This will enable completion on elements of lists, results of function calls, etc., but can be unsafe because the code is actually evaluated on TAB. """ ) - + def __init__(self, namespace=None, global_namespace=None, config=None): """Create a new completer for the command line. @@ -307,7 +307,7 @@ class Completer(Configurable): self.global_namespace = {} else: self.global_namespace = global_namespace - + super(Completer, self).__init__(config=config) def complete(self, text, state): @@ -319,7 +319,7 @@ class Completer(Configurable): """ if self.use_main_ns: self.namespace = __main__.__dict__ - + if state == 0: if "." in text: self.matches = self.attr_matches(text) @@ -369,7 +369,7 @@ class Completer(Configurable): m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text) if m: - expr, attr = m.group(1, 3) + expr, attr = m.group(1, 3) elif self.greedy: m2 = re.match(r"(.+)\.(\w*)$", self.line_buffer) if not m2: @@ -377,7 +377,7 @@ class Completer(Configurable): expr, attr = m2.group(1,2) else: return [] - + try: obj = eval(expr, self.namespace) except: @@ -387,7 +387,7 @@ class Completer(Configurable): return [] words = dir2(obj) - + try: words = generics.complete_object(obj, words) except TryNext: @@ -407,10 +407,10 @@ class IPCompleter(Completer): self.splitter.set_delims(GREEDY_DELIMS) else: self.splitter.set_delims(DELIMS) - + if self.readline: self.readline.set_completer_delims(self.splitter.get_delims()) - + def __init__(self, shell=None, namespace=None, global_namespace=None, omit__names=True, alias_table=None, use_readline=True, config=None): @@ -448,7 +448,7 @@ class IPCompleter(Completer): # Readline configuration, only used by the rlcompleter method. if use_readline: - # We store the right version of readline so that later code + # We store the right version of readline so that later code import IPython.utils.rlineimpl as readline self.readline = readline else: @@ -475,7 +475,7 @@ class IPCompleter(Completer): # buffers, to avoid completion problems. term = os.environ.get('TERM','xterm') self.dumb_terminal = term in ['dumb','emacs'] - + # Special handling of backslashes needed in win32 platforms if sys.platform == "win32": self.clean_glob = self._clean_glob_win32 @@ -489,7 +489,7 @@ class IPCompleter(Completer): self.alias_matches, self.python_func_kw_matches, ] - + def all_completions(self, text): """ Wrapper around the complete method for the benefit of emacs @@ -502,7 +502,7 @@ class IPCompleter(Completer): def _clean_glob_win32(self,text): return [f.replace("\\","/") - for f in self.glob("%s*" % text)] + for f in self.glob("%s*" % text)] def file_matches(self, text): """Match filenames, expanding ~USER type strings. @@ -569,7 +569,7 @@ class IPCompleter(Completer): # beginning of filename so that we don't double-write the part # of the filename we have so far len_lsplit = len(lsplit) - matches = [text_prefix + text0 + + matches = [text_prefix + text0 + protect_filename(f[len_lsplit:]) for f in m0] else: if open_quotes: @@ -578,7 +578,7 @@ class IPCompleter(Completer): # would cause bugs when the filesystem call is made). matches = m0 else: - matches = [text_prefix + + matches = [text_prefix + protect_filename(f) for f in m0] #io.rprint('mm', matches) # dbg @@ -595,7 +595,7 @@ class IPCompleter(Completer): return [ pre+m for m in magics if m.startswith(baretext)] def alias_matches(self, text): - """Match internal system aliases""" + """Match internal system aliases""" #print 'Completer->alias_matches:',text,'lb',self.text_until_cursor # dbg # if we are not in the first 'item', alias matching @@ -715,10 +715,10 @@ class IPCompleter(Completer): def dispatch_custom_completer(self, text): #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg - line = self.line_buffer + line = self.line_buffer if not line.strip(): return None - + # Create a little structure to pass all the relevant information about # the current completion to any custom completer. event = Bunch() @@ -727,16 +727,16 @@ class IPCompleter(Completer): cmd = line.split(None,1)[0] event.command = cmd event.text_until_cursor = self.text_until_cursor - + #print "\ncustom:{%s]\n" % event # dbg - + # for foo etc, try also to find completer for %foo if not cmd.startswith(self.magic_escape): try_magic = self.custom_completers.s_matches( - self.magic_escape + cmd) + self.magic_escape + cmd) else: - try_magic = [] - + try_magic = [] + for c in itertools.chain(self.custom_completers.s_matches(cmd), try_magic, self.custom_completers.flat_matches(self.text_until_cursor)): @@ -753,9 +753,9 @@ class IPCompleter(Completer): return [r for r in res if r.lower().startswith(text_low)] except TryNext: pass - + return None - + def complete(self, text=None, line_buffer=None, cursor_pos=None): """Find completions for the given text and line context. @@ -785,7 +785,7 @@ class IPCompleter(Completer): ------- text : str Text that was actually used in the completion. - + matches : list A list of completion matches. """ @@ -803,7 +803,7 @@ class IPCompleter(Completer): # If no line buffer is given, assume the input text is all there was if line_buffer is None: line_buffer = text - + self.line_buffer = line_buffer self.text_until_cursor = self.line_buffer[:cursor_pos] #io.rprint('\nCOMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg @@ -893,7 +893,7 @@ class IPCompleter(Completer): import traceback; traceback.print_exc() else: # The normal production version is here - + # This method computes the self.matches array self.complete(text, line_buffer, cursor_pos) diff --git a/IPython/core/completerlib.py b/IPython/core/completerlib.py index 15e5b7e..279e1d6 100644 --- a/IPython/core/completerlib.py +++ b/IPython/core/completerlib.py @@ -78,7 +78,7 @@ def shlex_split(x): if len(endofline) >= 1: comps.append(''.join(endofline)) return comps - + except ValueError: endofline = [x[-1:]]+endofline x = x[:-1] @@ -108,7 +108,7 @@ def module_list(path): isfile = os.path.isfile pjoin = os.path.join basename = os.path.basename - + # Now find actual path matches for packages or modules folder_list = [p for p in folder_list if isfile(pjoin(path, p,'__init__.py')) @@ -125,12 +125,12 @@ def get_root_modules(): if 'rootmodules' in ip.db: return ip.db['rootmodules'] - + t = time() store = False modules = list(sys.builtin_module_names) for path in sys.path: - modules += module_list(path) + modules += module_list(path) if time() - t >= TIMEOUT_STORAGE and not store: store = True print("\nCaching the list of root modules, please wait!") @@ -141,7 +141,7 @@ def get_root_modules(): print("This is taking too long, we give up.\n") ip.db['rootmodules'] = [] return [] - + modules = set(modules) if '__init__' in modules: modules.remove('__init__') @@ -173,7 +173,7 @@ def try_import(mod, only_modules=False): if (not hasattr(m, '__file__')) or (not only_modules) or m_is_init: completions.extend( [attr for attr in dir(m) if is_importable(m, attr, only_modules)]) - + completions.extend(getattr(m, '__all__', [])) if m_is_init: completions.extend(module_list(os.path.dirname(m.__file__))) @@ -192,22 +192,22 @@ def quick_completer(cmd, completions): Takes either a list of completions, or all completions in string (that will be split on whitespace). - + Example:: - + [d:\ipython]|1> import ipy_completers [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz']) [d:\ipython]|3> foo b bar baz [d:\ipython]|3> foo ba """ - + if isinstance(completions, basestring): completions = completions.split() def do_complete(self, event): return completions - + get_ipython().set_hook('complete_command',do_complete, str_key = cmd) @@ -226,7 +226,7 @@ def module_completion(line): # from whatever -> 'import ' if nwords == 3 and words[0] == 'from': return ['import '] - + # 'from xy' or 'import xy' if nwords < 3 and (words[0] in ['import','from']) : if nwords == 1: @@ -236,7 +236,7 @@ def module_completion(line): return get_root_modules() completion_list = try_import('.'.join(mod[:-1]), True) return ['.'.join(mod[:-1] + [el]) for el in completion_list] - + # 'from xyz import abc' if nwords >= 3 and words[0] == 'from': mod = words[1] @@ -275,7 +275,7 @@ def magic_run_completer(self, event): lglob = glob.glob isdir = os.path.isdir relpath, tilde_expand, tilde_val = expand_user(relpath) - + dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*') if isdir(f)] # Find if the user has already typed the first filename, after which we @@ -305,7 +305,7 @@ def cd_completer(self, event): return bkms.keys() else: return [] - + if event.symbol == '-': width_dh = str(len(str(len(ip.user_ns['_dh']) + 1))) # jump in directory history by number @@ -329,7 +329,7 @@ def cd_completer(self, event): # we don't want to deal with any of that, complex code # for this is elsewhere raise TryNext - + found.append(d) if not found: @@ -341,7 +341,7 @@ def cd_completer(self, event): bkmatches = [s for s in bks if s.startswith(event.symbol)] if bkmatches: return bkmatches - + raise TryNext return [compress_user(p, tilde_expand, tilde_val) for p in found] diff --git a/IPython/core/crashhandler.py b/IPython/core/crashhandler.py index 6e84fbb..87312ef 100644 --- a/IPython/core/crashhandler.py +++ b/IPython/core/crashhandler.py @@ -67,14 +67,14 @@ class CrashHandler(object): message_template = _default_message_template section_sep = '\n\n'+'*'*75+'\n\n' - def __init__(self, app, contact_name=None, contact_email=None, + def __init__(self, app, contact_name=None, contact_email=None, bug_tracker=None, show_crash_traceback=True, call_pdb=False): """Create a new crash handler Parameters ---------- app : Application - A running :class:`Application` instance, which will be queried at + A running :class:`Application` instance, which will be queried at crash time for internal information. contact_name : str @@ -106,7 +106,7 @@ class CrashHandler(object): contact_email = contact_email, bug_tracker = bug_tracker, crash_report_fname = self.crash_report_fname) - + def __call__(self, etype, evalue, etb): """Handle an exception, call for compatible with sys.excepthook""" @@ -160,13 +160,13 @@ class CrashHandler(object): def make_report(self,traceback): """Return a string containing a crash report.""" - + sec_sep = self.section_sep - + report = ['*'*75+'\n\n'+'IPython post-mortem report\n\n'] rpt_add = report.append rpt_add(sys_info()) - + try: config = pformat(self.app.config) rpt_add(sec_sep) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 225e082..d7b22a3 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -39,7 +39,7 @@ has_pydb = False prompt = 'ipdb> ' #We have to check this directly from sys.argv, config struct not yet available if '-pydb' in sys.argv: - try: + try: import pydb if hasattr(pydb.pydb, "runl") and pydb.version>'1.17': # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we @@ -130,7 +130,7 @@ class Tracer(object): This is similar to the pdb.set_trace() function from the std lib, but using IPython's enhanced debugger.""" - + self.debugger.set_trace(sys._getframe().f_back) @@ -173,9 +173,9 @@ class Pdb(OldPdb): OldPdb.__init__(self,stdin=stdin,stdout=io.stdout) else: OldPdb.__init__(self,completekey,stdin,stdout) - + self.prompt = prompt # The default prompt is '(Pdb)' - + # IPython changes... self.is_pydb = has_pydb @@ -207,7 +207,7 @@ class Pdb(OldPdb): # module and add a few attributes needed for debugging self.color_scheme_table = exception_colors() - # shorthands + # shorthands C = coloransi.TermColors cst = self.color_scheme_table @@ -250,11 +250,11 @@ class Pdb(OldPdb): self.shell.set_completer_frame(self.curframe) def new_do_quit(self, arg): - + if hasattr(self, 'old_all_completions'): self.shell.Completer.all_completions=self.old_all_completions - - + + return OldPdb.do_quit(self, arg) do_q = do_quit = decorate_fn_with_doc(new_do_quit, OldPdb.do_quit) @@ -288,9 +288,9 @@ class Pdb(OldPdb): def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3): import linecache, repr - + ret = [] - + Colors = self.color_scheme_table.active_colors ColorsNormal = Colors.Normal tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal) @@ -298,9 +298,9 @@ class Pdb(OldPdb): tpl_line = '%%s%s%%s %s%%s' % (Colors.lineno, ColorsNormal) tpl_line_em = '%%s%s%%s %s%%s%s' % (Colors.linenoEm, Colors.line, ColorsNormal) - + frame, lineno = frame_lineno - + return_value = '' if '__return__' in frame.f_locals: rv = frame.f_locals['__return__'] @@ -311,14 +311,14 @@ class Pdb(OldPdb): #s = filename + '(' + `lineno` + ')' filename = self.canonic(frame.f_code.co_filename) link = tpl_link % filename - + if frame.f_code.co_name: func = frame.f_code.co_name else: func = "" - + call = '' - if func != '?': + if func != '?': if '__args__' in frame.f_locals: args = repr.repr(frame.f_locals['__args__']) else: @@ -332,13 +332,13 @@ class Pdb(OldPdb): else: ret.append(' ') ret.append('%s(%s)%s\n' % (link,lineno,call)) - + start = lineno - 1 - context//2 lines = linecache.getlines(filename) start = max(start, 0) start = min(start, len(lines) - context) lines = lines[start : start + context] - + for i,line in enumerate(lines): show_arrow = (start + 1 + i == lineno) linetpl = (frame is self.curframe or show_arrow) \ @@ -362,7 +362,7 @@ class Pdb(OldPdb): if lineno in self.get_file_breaks(filename): bps = self.get_breaks(filename, lineno) bp = bps[-1] - + if bp: Colors = self.color_scheme_table.active_colors bp_mark = str(bp.number) @@ -387,7 +387,7 @@ class Pdb(OldPdb): else: num = '%*s' % (numbers_width - len(bp_mark), str(lineno)) line = tpl_line % (bp_mark_color + bp_mark, num, line) - + return line def list_command_pydb(self, arg): @@ -395,7 +395,7 @@ class Pdb(OldPdb): filename, first, last = OldPdb.parse_list_cmd(self, arg) if filename is not None: self.print_list_lines(filename, first, last) - + def print_list_lines(self, filename, first, last): """The printing (as opposed to the parsing part of a 'list' command.""" @@ -496,7 +496,7 @@ class Pdb(OldPdb): # # End hack. The rest of this method is copied verbatim from 2.6 pdb.py ####################################################################### - + if not line: print >>self.stdout, 'End of file' return 0 diff --git a/IPython/core/display.py b/IPython/core/display.py index 3466272..3fd2206 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -49,7 +49,7 @@ def display(*objs, **kwargs): """ include = kwargs.get('include') exclude = kwargs.get('exclude') - + from IPython.core.interactiveshell import InteractiveShell inst = InteractiveShell.instance() format = inst.display_formatter.format @@ -237,7 +237,7 @@ class DisplayObject(object): in the frontend. The MIME type of the data should match the subclasses used, so the Png subclass should be used for 'image/png' data. If the data is a URL, the data will first be downloaded - and then displayed. If + and then displayed. If Parameters ---------- diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 4af17f3..d536a42 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -123,7 +123,7 @@ class DisplayHook(Configurable): return no_cache_def else: return p_str - + def set_colors(self, colors): """Set the active color scheme and configure colors for the three prompt subsystems.""" @@ -135,7 +135,7 @@ class DisplayHook(Configurable): prompts.prompt_specials = prompts.prompt_specials_nocolor else: prompts.prompt_specials = prompts.prompt_specials_color - + self.color_table.set_active_scheme(colors) self.prompt1.set_colors() self.prompt2.set_colors() @@ -227,7 +227,7 @@ class DisplayHook(Configurable): format_dict : dict The format dict for the object passed to `sys.displayhook`. """ - # We want to print because we want to always make sure we have a + # We want to print because we want to always make sure we have a # newline, even if all the prompt separators are ''. This is the # standard IPython behavior. result_repr = format_dict['text/plain'] @@ -291,7 +291,7 @@ class DisplayHook(Configurable): def __call__(self, result=None): """Printing with history cache management. - + This is invoked everytime the interpreter needs to print, and is activated by setting the variable sys.displayhook to it. """ @@ -310,17 +310,17 @@ class DisplayHook(Configurable): raise ValueError,"You shouldn't have reached the cache flush "\ "if full caching is not enabled!" # delete auto-generated vars from global namespace - + for n in range(1,self.prompt_count + 1): key = '_'+`n` try: del self.shell.user_ns[key] except: pass self.shell.user_ns['_oh'].clear() - + # Release our own references to objects: self._, self.__, self.___ = '', '', '' - + if '_' not in __builtin__.__dict__: self.shell.user_ns.update({'_':None,'__':None, '___':None}) import gc diff --git a/IPython/core/displaypub.py b/IPython/core/displaypub.py index ecfdf03..d214d1b 100644 --- a/IPython/core/displaypub.py +++ b/IPython/core/displaypub.py @@ -87,7 +87,7 @@ class DisplayPublisher(Configurable): A string that give the function or method that created the data, such as 'IPython.core.page'. data : dict - A dictionary having keys that are valid MIME types (like + A dictionary having keys that are valid MIME types (like 'text/plain' or 'image/svg+xml') and values that are the data for that MIME type. The data itself must be a JSON'able data structure. Minimally all data should have the 'text/plain' data, @@ -128,7 +128,7 @@ def publish_display_data(source, data, metadata=None): A string that give the function or method that created the data, such as 'IPython.core.page'. data : dict - A dictionary having keys that are valid MIME types (like + A dictionary having keys that are valid MIME types (like 'text/plain' or 'image/svg+xml') and values that are the data for that MIME type. The data itself must be a JSON'able data structure. Minimally all data should have the 'text/plain' data, diff --git a/IPython/core/error.py b/IPython/core/error.py index 3d033e7..78c78c7 100644 --- a/IPython/core/error.py +++ b/IPython/core/error.py @@ -32,7 +32,7 @@ class IPythonCoreError(Exception): class TryNext(IPythonCoreError): """Try next hook exception. - + Raise this in your hook function to indicate that the next hook handler should be used to handle the operation. If you pass arguments to the constructor those arguments will be used by the next hook instead of the @@ -45,7 +45,7 @@ class TryNext(IPythonCoreError): class UsageError(IPythonCoreError): """Error in magic function arguments, etc. - + Something that probably won't warrant a full traceback, but should - nevertheless interrupt a macro / batch file. + nevertheless interrupt a macro / batch file. """ diff --git a/IPython/core/excolors.py b/IPython/core/excolors.py index 14451d5..3524fff 100644 --- a/IPython/core/excolors.py +++ b/IPython/core/excolors.py @@ -27,16 +27,16 @@ def exception_colors(): >>> print ec.active_colors None - Now we activate a color scheme: + Now we activate a color scheme: >>> ec.set_active_scheme('NoColor') >>> ec.active_scheme_name 'NoColor' >>> ec.active_colors.keys() - ['em', 'filenameEm', 'excName', 'valEm', 'nameEm', 'line', 'topline', - 'name', 'caret', 'val', 'vName', 'Normal', 'filename', 'linenoEm', + ['em', 'filenameEm', 'excName', 'valEm', 'nameEm', 'line', 'topline', + 'name', 'caret', 'val', 'vName', 'Normal', 'filename', 'linenoEm', 'lineno', 'normalEm'] """ - + ex_colors = ColorSchemeTable() # Populate it with color schemes diff --git a/IPython/core/extensions.py b/IPython/core/extensions.py index a087b93..ea54d08 100644 --- a/IPython/core/extensions.py +++ b/IPython/core/extensions.py @@ -36,13 +36,13 @@ class ExtensionManager(Configurable): def load_ipython_extension(ipython): # Do things with ipython - This function is called after your extension is imported and the + This function is called after your extension is imported and the currently active :class:`InteractiveShell` instance is passed as the only argument. You can do anything you want with IPython at that point, including defining new magic and aliases, adding new components, etc. - The :func:`load_ipython_extension` will be called again is you + The :func:`load_ipython_extension` will be called again is you load or reload the extension again. It is up to the extension author to add code to manage that. diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 90e66e4..75d03c4 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -361,26 +361,26 @@ class PlainTextFormatter(BaseFormatter): # The newline character. newline = Unicode('\n', config=True) - + # format-string for pprinting floats float_format = Unicode('%r') # setter for float precision, either int or direct format-string float_precision = CUnicode('', config=True) - + def _float_precision_changed(self, name, old, new): """float_precision changed, set float_format accordingly. - + float_precision can be set by int or str. This will set float_format, after interpreting input. If numpy has been imported, numpy print precision will also be set. - + integer `n` sets format to '%.nf', otherwise, format set directly. - + An empty string returns to defaults (repr for float, 8 for numpy). - + This parameter can be set via the '%precision' magic. """ - + if '%' in new: # got explicit format string fmt = new @@ -397,7 +397,7 @@ class PlainTextFormatter(BaseFormatter): raise ValueError("Precision must be int or format string, not %r"%new) except AssertionError: raise ValueError("int precision must be non-negative, not %r"%i) - + fmt = '%%.%if'%i if 'numpy' in sys.modules: # set numpy precision if it has been imported @@ -458,7 +458,7 @@ class HTMLFormatter(BaseFormatter): this. The return value of this formatter should be a valid HTML snippet that - could be injected into an existing DOM. It should *not* include the + could be injected into an existing DOM. It should *not* include the ````` or ````` tags. """ format_type = Unicode('text/html') @@ -550,7 +550,7 @@ class JavascriptFormatter(BaseFormatter): """A Javascript formatter. To define the callables that compute the Javascript representation of - your objects, define a :meth:`_repr_javascript_` method or use the + your objects, define a :meth:`_repr_javascript_` method or use the :meth:`for_type` or :meth:`for_type_by_name` methods to register functions that handle this. diff --git a/IPython/core/history.py b/IPython/core/history.py index 3a81754..a750a35 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -67,19 +67,19 @@ class HistoryManager(Configurable): # Should we log output to the database? (default no) db_log_output = Bool(False, config=True) # Write to database every x commands (higher values save disk access & power) - # Values of 1 or less effectively disable caching. + # Values of 1 or less effectively disable caching. db_cache_size = Int(0, config=True) # The input and output caches db_input_cache = List() db_output_cache = List() - + # History saving in separate thread save_thread = Instance('IPython.core.history.HistorySavingThread') try: # Event is a function returning an instance of _Event... save_flag = Instance(threading._Event) except AttributeError: # ...until Python 3.3, when it's a class. save_flag = Instance(threading.Event) - + # Private interface # Variables used to store the three last inputs from the user. On each new # history update, we populate the user's namespace with these, shifted as @@ -119,7 +119,7 @@ class HistoryManager(Configurable): else: # The hist_file is probably :memory: or something else. raise - + self.save_flag = threading.Event() self.db_input_cache_lock = threading.Lock() self.db_output_cache_lock = threading.Lock() @@ -128,7 +128,7 @@ class HistoryManager(Configurable): self.new_session() - + def init_db(self): """Connect to the database, and create tables if necessary.""" # use detect_types so that timestamps return datetime objects @@ -136,7 +136,7 @@ class HistoryManager(Configurable): self.db.execute("""CREATE TABLE IF NOT EXISTS sessions (session integer primary key autoincrement, start timestamp, end timestamp, num_cmds integer, remark text)""") - self.db.execute("""CREATE TABLE IF NOT EXISTS history + self.db.execute("""CREATE TABLE IF NOT EXISTS history (session integer, line integer, source text, source_raw text, PRIMARY KEY (session, line))""") # Output history is optional, but ensure the table's there so it can be @@ -145,17 +145,17 @@ class HistoryManager(Configurable): (session integer, line integer, output text, PRIMARY KEY (session, line))""") self.db.commit() - + def new_session(self, conn=None): """Get a new session number.""" if conn is None: conn = self.db - + with conn: cur = conn.execute("""INSERT INTO sessions VALUES (NULL, ?, NULL, NULL, "") """, (datetime.datetime.now(),)) self.session_number = cur.lastrowid - + def end_session(self): """Close the database session, filling in the end time and line count.""" self.writeout_cache() @@ -164,33 +164,33 @@ class HistoryManager(Configurable): session==?""", (datetime.datetime.now(), len(self.input_hist_parsed)-1, self.session_number)) self.session_number = 0 - + def name_session(self, name): """Give the current session a name in the history database.""" with self.db: self.db.execute("UPDATE sessions SET remark=? WHERE session==?", (name, self.session_number)) - + def reset(self, new_session=True): """Clear the session history, releasing all object references, and optionally open a new session.""" self.output_hist.clear() # The directory history can't be completely empty self.dir_hist[:] = [os.getcwdu()] - + if new_session: if self.session_number: self.end_session() self.input_hist_parsed[:] = [""] self.input_hist_raw[:] = [""] self.new_session() - + ## ------------------------------- ## Methods for retrieving history: ## ------------------------------- def _run_sql(self, sql, params, raw=True, output=False): """Prepares and runs an SQL query for the history database. - + Parameters ---------- sql : str @@ -199,7 +199,7 @@ class HistoryManager(Configurable): Parameters passed to the SQL query (to replace "?") raw, output : bool See :meth:`get_range` - + Returns ------- Tuples as :meth:`get_range` @@ -214,38 +214,38 @@ class HistoryManager(Configurable): if output: # Regroup into 3-tuples, and parse JSON return ((ses, lin, (inp, out)) for ses, lin, inp, out in cur) return cur - - + + def get_session_info(self, session=0): """get info about a session - + Parameters ---------- - + session : int Session number to retrieve. The current session is 0, and negative numbers count back from current session, so -1 is previous session. - + Returns ------- - + (session_id [int], start [datetime], end [datetime], num_cmds [int], remark [unicode]) - + Sessions that are running or did not exit cleanly will have `end=None` and `num_cmds=None`. - + """ - + if session <= 0: session += self.session_number - + query = "SELECT * from sessions where session == ?" return self.db.execute(query, (session,)).fetchone() - - + + def get_tail(self, n=10, raw=True, output=False, include_latest=False): """Get the last n lines from the history database. - + Parameters ---------- n : int @@ -256,7 +256,7 @@ class HistoryManager(Configurable): If False (default), n+1 lines are fetched, and the latest one is discarded. This is intended to be used where the function is called by a user command, which it should not return. - + Returns ------- Tuples as :meth:`get_range` @@ -269,12 +269,12 @@ class HistoryManager(Configurable): if not include_latest: return reversed(list(cur)[1:]) return reversed(list(cur)) - + def search(self, pattern="*", raw=True, search_raw=True, output=False): """Search the database using unix glob-style matching (wildcards * and ?). - + Parameters ---------- pattern : str @@ -283,7 +283,7 @@ class HistoryManager(Configurable): If True, search the raw input, otherwise, the parsed input raw, output : bool See :meth:`get_range` - + Returns ------- Tuples as :meth:`get_range` @@ -294,12 +294,12 @@ class HistoryManager(Configurable): self.writeout_cache() return self._run_sql("WHERE %s GLOB ?" % tosearch, (pattern,), raw=raw, output=output) - + def _get_range_session(self, start=1, stop=None, raw=True, output=False): """Get input and output history from the current session. Called by get_range, and takes similar parameters.""" input_hist = self.input_hist_raw if raw else self.input_hist_parsed - + n = len(input_hist) if start < 0: start += n @@ -307,17 +307,17 @@ class HistoryManager(Configurable): stop = n elif stop < 0: stop += n - + for i in range(start, stop): if output: line = (input_hist[i], self.output_hist_reprs.get(i)) else: line = input_hist[i] yield (0, i, line) - + def get_range(self, session=0, start=1, stop=None, raw=True,output=False): """Retrieve input by session. - + Parameters ---------- session : int @@ -335,7 +335,7 @@ class HistoryManager(Configurable): objects for the current session, or text reprs from previous sessions if db_log_output was enabled at the time. Where no output is found, None is used. - + Returns ------- An iterator over the desired lines. Each line is a 3-tuple, either @@ -346,21 +346,21 @@ class HistoryManager(Configurable): return self._get_range_session(start, stop, raw, output) if session < 0: session += self.session_number - + if stop: lineclause = "line >= ? AND line < ?" params = (session, start, stop) else: lineclause = "line>=?" params = (session, start) - + return self._run_sql("WHERE session==? AND %s""" % lineclause, params, raw=raw, output=output) - + def get_range_by_str(self, rangestr, raw=True, output=False): """Get lines of history from a string of ranges, as used by magic commands %hist, %save, %macro, etc. - + Parameters ---------- rangestr : str @@ -368,7 +368,7 @@ class HistoryManager(Configurable): :func:`magic_history` for full details. raw, output : bool As :meth:`get_range` - + Returns ------- Tuples as :meth:`get_range` @@ -376,19 +376,19 @@ class HistoryManager(Configurable): for sess, s, e in extract_hist_ranges(rangestr): for line in self.get_range(sess, s, e, raw=raw, output=output): yield line - + ## ---------------------------- ## Methods for storing history: ## ---------------------------- def store_inputs(self, line_num, source, source_raw=None): """Store source and raw input in history and create input cache variables _i*. - + Parameters ---------- line_num : int The prompt number of this input. - + source : str Python input. @@ -400,14 +400,14 @@ class HistoryManager(Configurable): source_raw = source source = source.rstrip('\n') source_raw = source_raw.rstrip('\n') - + # do not store exit/quit commands if self._exit_re.match(source_raw.strip()): return - + self.input_hist_parsed.append(source) self.input_hist_raw.append(source_raw) - + with self.db_input_cache_lock: self.db_input_cache.append((line_num, source, source_raw)) # Trigger to flush cache and write to DB. @@ -427,12 +427,12 @@ class HistoryManager(Configurable): '_iii': self._iii, new_i : self._i00 } self.shell.user_ns.update(to_main) - + def store_output(self, line_num): """If database output logging is enabled, this saves all the outputs from the indicated prompt number to the database. It's called by run_cell after code has been executed. - + Parameters ---------- line_num : int @@ -441,29 +441,29 @@ class HistoryManager(Configurable): if (not self.db_log_output) or (line_num not in self.output_hist_reprs): return output = self.output_hist_reprs[line_num] - + with self.db_output_cache_lock: self.db_output_cache.append((line_num, output)) if self.db_cache_size <= 1: self.save_flag.set() - + def _writeout_input_cache(self, conn): with conn: for line in self.db_input_cache: conn.execute("INSERT INTO history VALUES (?, ?, ?, ?)", (self.session_number,)+line) - + def _writeout_output_cache(self, conn): with conn: for line in self.db_output_cache: conn.execute("INSERT INTO output_history VALUES (?, ?, ?)", (self.session_number,)+line) - + def writeout_cache(self, conn=None): """Write any entries in the cache to the database.""" if conn is None: conn = self.db - + with self.db_input_cache_lock: try: self._writeout_input_cache(conn) @@ -492,7 +492,7 @@ class HistoryManager(Configurable): class HistorySavingThread(threading.Thread): """This thread takes care of writing history to the database, so that the UI isn't held up while that happens. - + It waits for the HistoryManager's save_flag to be set, then writes out the history cache. The main thread is responsible for setting the flag when the cache size reaches a defined threshold.""" @@ -502,7 +502,7 @@ class HistorySavingThread(threading.Thread): super(HistorySavingThread, self).__init__() self.history_manager = history_manager atexit.register(self.stop) - + def run(self): # We need a separate db connection per thread: try: @@ -516,10 +516,10 @@ class HistorySavingThread(threading.Thread): except Exception as e: print(("The history saving thread hit an unexpected error (%s)." "History will not be written to the database.") % repr(e)) - + def stop(self): """This can be called from the main thread to safely stop this thread. - + Note that it does not attempt to write out remaining history before exiting. That should be done by calling the HistoryManager's end_session method.""" @@ -527,7 +527,7 @@ class HistorySavingThread(threading.Thread): self.history_manager.save_flag.set() self.join() - + # To match, e.g. ~5/8-~2/3 range_re = re.compile(r""" ((?P~?\d+)/)? @@ -539,7 +539,7 @@ $""", re.VERBOSE) def extract_hist_ranges(ranges_str): """Turn a string of history ranges into 3-tuples of (session, start, stop). - + Examples -------- list(extract_input_ranges("~8/5-~7/4 2")) @@ -578,7 +578,7 @@ def _format_lineno(session, line): @skip_doctest def magic_history(self, parameter_s = ''): """Print input history (_i variables), with most recent last. - + %history -> print at most 40 inputs (some may be multi-line)\\ %history n -> print at most n inputs\\ %history n1 n2 -> print inputs between n1 and n2 (n2 not included)\\ @@ -594,7 +594,7 @@ def magic_history(self, parameter_s = ''): ~8/1-~6/5 : From the first line of 8 sessions ago, to the fifth line of 6 sessions ago. Multiple ranges can be entered, separated by spaces - + The same syntax is used by %macro, %save, %edit, %rerun Options: @@ -609,29 +609,29 @@ def magic_history(self, parameter_s = ''): doctest-ready output. -r: (default) print the 'raw' history, i.e. the actual commands you typed. - + -t: print the 'translated' history, as IPython understands it. IPython filters your input and converts it all into valid Python source before executing it (things like magics or aliases are turned into function calls, for example). With this option, you'll see the native history instead of the user-entered version: '%cd /' will be seen as 'get_ipython().magic("%cd /")' instead of '%cd /'. - + -g: treat the arg as a pattern to grep for in (full) history. This includes the saved history (almost all commands ever written). Use '%hist -g' to show full saved history (may be very long). - + -l: get the last n lines from all sessions. Specify n as a single arg, or the default is the last 10 lines. -f FILENAME: instead of printing the output to the screen, redirect it to the given file. The file is always overwritten, though IPython asks for confirmation first if it already exists. - + Examples -------- :: - + In [6]: %hist -n 4 6 4:a = 12 5:print a**2 @@ -642,10 +642,10 @@ def magic_history(self, parameter_s = ''): print('This feature is only available if numbered prompts are in use.') return opts,args = self.parse_options(parameter_s,'noprtglf:',mode='string') - + # For brevity history_manager = self.shell.history_manager - + def _format_lineno(session, line): """Helper function to format line numbers properly.""" if session in (0, history_manager.session_number): @@ -661,22 +661,22 @@ def magic_history(self, parameter_s = ''): close_at_end = False else: if os.path.exists(outfname): - if not io.ask_yes_no("File %r exists. Overwrite?" % outfname): + if not io.ask_yes_no("File %r exists. Overwrite?" % outfname): print('Aborting.') return outfile = open(outfname,'w') close_at_end = True - + print_nums = 'n' in opts get_output = 'o' in opts pyprompts = 'p' in opts # Raw history is the default raw = not('t' in opts) - + default_length = 40 pattern = None - + if 'g' in opts: # Glob search pattern = "*" + args + "*" if args else "*" hist = history_manager.search(pattern, raw=raw, output=get_output) @@ -692,11 +692,11 @@ def magic_history(self, parameter_s = ''): hist = history_manager.get_range_by_str(args, raw, get_output) else: # Just get history for the current session hist = history_manager.get_range(raw=raw, output=get_output) - - # We could be displaying the entire history, so let's not try to pull it + + # We could be displaying the entire history, so let's not try to pull it # into a list in memory. Anything that needs more space will just misalign. width = 4 - + for session, lineno, inline in hist: # Print user history with tabs expanded to 4 spaces. The GUI clients # use hard tabs for easier usability in auto-indented code, but we want @@ -704,7 +704,7 @@ def magic_history(self, parameter_s = ''): if get_output: inline, output = inline inline = inline.expandtabs(4).rstrip() - + multiline = "\n" in inline line_sep = '\n' if multiline else ' ' if print_nums: @@ -727,29 +727,29 @@ def magic_rep(self, arg): %rep are equivalent. - %recall (no arguments): - + Place a string version of last computation result (stored in the special '_' variable) to the next input prompt. Allows you to create elaborate command lines without using copy-paste:: - + In[1]: l = ["hei", "vaan"] In[2]: "".join(l) Out[2]: heivaan In[3]: %rep In[4]: heivaan_ <== cursor blinking - + %recall 45 - + Place history line 45 on the next input prompt. Use %hist to find out the number. - + %recall 1-4 - + Combine the specified lines into one cell, and place it on the next input prompt. See %history for the slice syntax. - + %recall foo+bar - + If foo+bar can be evaluated in the user namespace, the result is placed at the next input prompt. Otherwise, the history is searched for lines which contain that substring, and the most recent one is @@ -777,18 +777,18 @@ def magic_rep(self, arg): else: self.set_next_input(cmd.rstrip()) print("Couldn't evaluate or find in history:", arg) - + def magic_rerun(self, parameter_s=''): """Re-run previous input - + By default, you can specify ranges of input history to be repeated (as with %history). With no arguments, it will repeat the last line. - + Options: - + -l : Repeat the last n lines of input, not including the current command. - + -g foo : Repeat the most recent line which contains foo """ opts, args = self.parse_options(parameter_s, 'l:g:', mode='string') @@ -820,7 +820,7 @@ def magic_rerun(self, parameter_s=''): def init_ipython(ip): - ip.define_magic("rep", magic_rep) + ip.define_magic("rep", magic_rep) ip.define_magic("recall", magic_rep) ip.define_magic("rerun", magic_rerun) ip.define_magic("hist",magic_history) # Alternative name diff --git a/IPython/core/hooks.py b/IPython/core/hooks.py index c34d4f7..853f5f2 100644 --- a/IPython/core/hooks.py +++ b/IPython/core/hooks.py @@ -64,24 +64,24 @@ def editor(self,filename, linenum=None): # IPython configures a default editor at startup by reading $EDITOR from # the environment, and falling back on vi (unix) or notepad (win32). editor = self.editor - + # marker for at which line to open the file (for existing objects) if linenum is None or editor=='notepad': linemark = '' else: linemark = '+%d' % int(linenum) - + # Enclose in quotes if necessary and legal if ' ' in editor and os.path.isfile(editor) and editor[0] != '"': editor = '"%s"' % editor - + # Call the actual editor if os.system('%s %s %s' % (editor,linemark,filename)) != 0: raise TryNext() import tempfile def fix_error_editor(self,filename,linenum,column,msg): - """Open the editor at the given filename, linenumber, column and + """Open the editor at the given filename, linenumber, column and show an error message. This is used for correcting syntax errors. The current implementation only has special support for the VIM editor, and falls back on the 'editor' hook if VIM is not used. @@ -110,25 +110,25 @@ def synchronize_with_editor(self, filename, linenum, column): class CommandChainDispatcher: """ Dispatch calls to a chain of commands until some func can handle it - + Usage: instantiate, execute "add" to add commands (with optional priority), execute normally via f() calling mechanism. - + """ def __init__(self,commands=None): if commands is None: self.chain = [] else: self.chain = commands - - + + def __call__(self,*args, **kw): - """ Command chain is called just like normal func. - + """ Command chain is called just like normal func. + This will call all funcs in chain with the same args as were given to this function, and return the result of first func that didn't raise TryNext """ - + for prio,cmd in self.chain: #print "prio",prio,"cmd",cmd #dbg try: @@ -139,32 +139,32 @@ class CommandChainDispatcher: kw = exc.kwargs # if no function will accept it, raise TryNext up to the caller raise TryNext - + def __str__(self): return str(self.chain) - + def add(self, func, priority=0): """ Add a func to the cmd chain with given priority """ bisect.insort(self.chain,(priority,func)) def __iter__(self): """ Return all objects in chain. - + Handy if the objects are not callable. """ return iter(self.chain) -def input_prefilter(self,line): +def input_prefilter(self,line): """ Default input prefilter - + This returns the line as unchanged, so that the interpreter knows that nothing was done and proceeds with "classic" prefiltering - (%magics, !shell commands etc.). - + (%magics, !shell commands etc.). + Note that leading whitespace is not passed to this hook. Prefilter can't alter indentation. - + """ #print "attempt to rewrite",line #dbg return line @@ -172,17 +172,17 @@ def input_prefilter(self,line): def shutdown_hook(self): """ default shutdown hook - + Typically, shotdown hooks should raise TryNext so all shutdown ops are done """ - + #print "default shutdown hook ok" # dbg return def late_startup_hook(self): - """ Executed after ipython has been constructed and configured - + """ Executed after ipython has been constructed and configured + """ #print "default startup hook ok" # dbg @@ -202,11 +202,11 @@ def show_in_pager(self,s): def pre_prompt_hook(self): """ Run before displaying the next prompt - - Use this e.g. to display output from asynchronous operations (in order - to not mess up text entry) + + Use this e.g. to display output from asynchronous operations (in order + to not mess up text entry) """ - + return None @@ -219,7 +219,7 @@ def clipboard_get(self): """ Get text from the clipboard. """ from IPython.lib.clipboard import ( - osx_clipboard_get, tkinter_clipboard_get, + osx_clipboard_get, tkinter_clipboard_get, win32_clipboard_get ) if sys.platform == 'win32': diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index b048248..e85137b 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -145,7 +145,7 @@ class ReadlineNoRecord(object): def __init__(self, shell): self.shell = shell self._nested_level = 0 - + def __enter__(self): if self._nested_level == 0: try: @@ -154,7 +154,7 @@ class ReadlineNoRecord(object): except (AttributeError, IndexError): # Can fail with pyreadline self.orig_length, self.readline_tail = 999999, [] self._nested_level += 1 - + def __exit__(self, type, value, traceback): self._nested_level -= 1 if self._nested_level == 0: @@ -164,7 +164,7 @@ class ReadlineNoRecord(object): if e > 0: for _ in range(e): self.shell.readline.remove_history_item(self.orig_length) - + # If it still doesn't match, just reload readline history. if self.current_length() != self.orig_length \ or self.get_readline_tail() != self.readline_tail: @@ -173,10 +173,10 @@ class ReadlineNoRecord(object): pass # Returning False will cause exceptions to propagate return False - + def current_length(self): return self.shell.readline.get_current_history_length() - + def get_readline_tail(self, n=10): """Get the last n items in readline history.""" end = self.shell.readline.get_current_history_length() + 1 @@ -243,7 +243,7 @@ class InteractiveShell(SingletonConfigurable, Magic): get confused with color codes, this capability can be turned off. """ ) - colors = CaselessStrEnum(('NoColor','LightBG','Linux'), + colors = CaselessStrEnum(('NoColor','LightBG','Linux'), default_value=get_default_colors(), config=True, help="Set the color scheme (NoColor, Linux, or LightBG)." ) @@ -315,7 +315,7 @@ class InteractiveShell(SingletonConfigurable, Magic): quiet = CBool(False, config=True) history_length = Int(10000, config=True) - + # The readline stuff will eventually be moved to the terminal subclass # but for now, we can't do that as readline is welded in everywhere. readline_use = CBool(True, config=True) @@ -345,7 +345,7 @@ class InteractiveShell(SingletonConfigurable, Magic): separate_out = SeparateUnicode('', config=True) separate_out2 = SeparateUnicode('', config=True) wildcards_case_sensitive = CBool(True, config=True) - xmode = CaselessStrEnum(('Context','Plain', 'Verbose'), + xmode = CaselessStrEnum(('Context','Plain', 'Verbose'), default_value='Context', config=True) # Subcomponents of InteractiveShell @@ -393,7 +393,7 @@ class InteractiveShell(SingletonConfigurable, Magic): # is what we want to do. self.save_sys_module_state() self.init_sys_modules() - + # While we're trying to have each part of the code directly access what # it needs without keeping redundant references to objects, we have too # much legacy code that expects ip.db to exist. @@ -583,7 +583,7 @@ class InteractiveShell(SingletonConfigurable, Magic): def init_io(self): # This will just use sys.stdout and sys.stderr. If you want to # override sys.stdout and sys.stderr themselves, you need to do that - # *before* instantiating this class, because io holds onto + # *before* instantiating this class, because io holds onto # references to the underlying streams. if sys.platform == 'win32' and self.has_readline: io.stdout = io.stderr = io.IOStream(self.readline._outputfile) @@ -593,7 +593,7 @@ class InteractiveShell(SingletonConfigurable, Magic): def init_prompts(self): # TODO: This is a pass for now because the prompts are managed inside - # the DisplayHook. Once there is a separate prompt manager, this + # the DisplayHook. Once there is a separate prompt manager, this # will initialize that object and all prompt related information. pass @@ -682,13 +682,13 @@ class InteractiveShell(SingletonConfigurable, Magic): """set_hook(name,hook) -> sets an internal IPython hook. IPython exposes some of its internal API as user-modifiable hooks. By - adding your function to one of these hooks, you can modify IPython's + adding your function to one of these hooks, you can modify IPython's behavior to call at runtime your own routines.""" # At some point in the future, this should validate the hook before it # accepts it. Probably at least check that the hook takes the number # of args it's supposed to. - + f = types.MethodType(hook,self) # check if the hook is for strdispatcher first @@ -702,14 +702,14 @@ class InteractiveShell(SingletonConfigurable, Magic): sdp.add_re(re.compile(re_key), f, priority ) self.strdispatchers[name] = sdp return - + dp = getattr(self.hooks, name, None) if name not in IPython.core.hooks.__all__: print "Warning! Hook '%s' is not one of %s" % \ (name, IPython.core.hooks.__all__ ) if not dp: dp = IPython.core.hooks.CommandChainDispatcher() - + try: dp.add(f,priority) except AttributeError: @@ -757,7 +757,7 @@ class InteractiveShell(SingletonConfigurable, Magic): must therefore make a *copy* of the given namespace, to allow the original module's __dict__ to be cleared and reused. - + Parameters ---------- ns : a namespace (a dict, typically) @@ -849,7 +849,7 @@ class InteractiveShell(SingletonConfigurable, Magic): else: # fallback to our internal debugger pm = lambda : self.InteractiveTB.debugger(force=True) - + with self.readline_no_record: pm() @@ -923,7 +923,7 @@ class InteractiveShell(SingletonConfigurable, Magic): # the script will fail, because the function's closure had references # to the original objects, which are now all None. So we must protect # these modules from deletion by keeping a cache. - # + # # To avoid keeping stale modules around (we only need the one from the # last run), we use a dict keyed with the full path to the script, so # only the last version of the module is held in the cache. Note, @@ -931,7 +931,7 @@ class InteractiveShell(SingletonConfigurable, Magic): # __dict__). Because if we try to cache the actual modules, old ones # (uncached) could be destroyed while still holding references (such as # those held by GUI objects that tend to be long-lived)> - # + # # The %reset command will flush this cache. See the cache_main_mod() # and clear_main_mod_cache() methods for details on use. @@ -1067,11 +1067,11 @@ class InteractiveShell(SingletonConfigurable, Magic): # module, and can even mutate at runtime, depending on the context # (Python makes no guarantees on it). In contrast, __builtin__ is # always a module object, though it must be explicitly imported. - + # For more details: # http://mail.python.org/pipermail/python-dev/2001-April/014068.html ns = dict(__builtin__ = builtin_mod) - + # Put 'help' in the user namespace try: from site import _Helper @@ -1093,7 +1093,7 @@ class InteractiveShell(SingletonConfigurable, Magic): # Store myself as the public api!!! ns['get_ipython'] = self.get_ipython - + ns['exit'] = self.exiter ns['quit'] = self.exiter @@ -1104,14 +1104,14 @@ class InteractiveShell(SingletonConfigurable, Magic): # Anything put into ns now would show up in %who. Think twice before # putting anything here, as we really want %who to show the user their # stuff, not our variables. - + # Finally, update the real user's namespace self.user_ns.update(ns) def reset(self, new_session=True): """Clear all internal namespaces, and attempt to release references to user objects. - + If new_session is True, a new history session will be opened. """ # Clear histories @@ -1119,11 +1119,11 @@ class InteractiveShell(SingletonConfigurable, Magic): # Reset counter used to index all histories if new_session: self.execution_count = 1 - + # Flush cached output items if self.displayhook.do_full_cache: self.displayhook.flush() - + # Restore the user namespaces to minimal usability for ns in self.ns_refs_table: ns.clear() @@ -1137,25 +1137,25 @@ class InteractiveShell(SingletonConfigurable, Magic): drop_keys.discard('__builtins__') for k in drop_keys: del ns[k] - + # Restore the user namespaces to minimal usability self.init_user_ns() # Restore the default and user aliases self.alias_manager.clear_aliases() self.alias_manager.init_aliases() - + # Flush the private list of module references kept for script # execution protection self.clear_main_mod_cache() - + # Clear out the namespace from the last %run self.new_main_mod() - + def del_var(self, varname, by_name=False): """Delete a variable from the various namespaces, so that, as far as possible, we're not keeping any hidden references to it. - + Parameters ---------- varname : str @@ -1170,7 +1170,7 @@ class InteractiveShell(SingletonConfigurable, Magic): ns_refs = self.ns_refs_table + [self.user_ns, self.user_global_ns, self._user_main_module.__dict__] +\ self._main_ns_cache.values() - + if by_name: # Delete by name for ns in ns_refs: try: @@ -1188,12 +1188,12 @@ class InteractiveShell(SingletonConfigurable, Magic): to_delete = [n for n, o in ns.iteritems() if o is obj] for name in to_delete: del ns[name] - + # displayhook keeps extra references, but not in a dictionary for name in ('_', '__', '___'): if getattr(self.displayhook, name) is obj: setattr(self.displayhook, name, None) - + def reset_selective(self, regex=None): """Clear selective variables from internal namespaces based on a specified regular expression. @@ -1214,8 +1214,8 @@ class InteractiveShell(SingletonConfigurable, Magic): for ns in self.ns_refs_table: for var in ns: if m.search(var): - del ns[var] - + del ns[var] + def push(self, variables, interactive=True): """Inject a group of variables into the IPython user namespace. @@ -1252,7 +1252,7 @@ class InteractiveShell(SingletonConfigurable, Magic): (name,cf.f_code.co_name)) else: raise ValueError('variables must be a dict/str/list/tuple') - + # Propagate variables to user namespace self.user_ns.update(vdict) @@ -1361,11 +1361,11 @@ class InteractiveShell(SingletonConfigurable, Magic): root = '.'.join(path[:-1]) if info.parent is not None: try: - target = getattr(info.parent, '__class__') - # The object belongs to a class instance. - try: + target = getattr(info.parent, '__class__') + # The object belongs to a class instance. + try: target = getattr(target, path[-1]) - # The class defines the object. + # The class defines the object. if isinstance(target, property): oname = root + '.__class__.' + path[-1] info = Struct(self._ofind(oname)) @@ -1380,7 +1380,7 @@ class InteractiveShell(SingletonConfigurable, Magic): """Find an object and return a struct with info about it.""" inf = Struct(self._ofind(oname, namespaces)) return Struct(self._ofind_property(oname, inf)) - + def _inspect(self, meth, oname, namespaces=None, **kw): """Generic interface to the inspector system. @@ -1422,7 +1422,7 @@ class InteractiveShell(SingletonConfigurable, Magic): def init_traceback_handlers(self, custom_exceptions): # Syntax error handler. self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor') - + # The interactive one is initialized with an offset, meaning we always # want to remove the topmost item in the traceback, which is our own # internal code. Valid modes: ['Plain','Context','Verbose'] @@ -1526,7 +1526,7 @@ class InteractiveShell(SingletonConfigurable, Magic): care of calling it if needed, so unless you are explicitly catching a SyntaxError exception, don't try to analyze the stack manually and simply call this method.""" - + try: if exc_tuple is None: etype, value, tb = sys.exc_info() @@ -1540,7 +1540,7 @@ class InteractiveShell(SingletonConfigurable, Magic): else: self.write_err('No traceback available to show.\n') return - + if etype is SyntaxError: # Though this won't be called by syntax errors in the input # line, there may be SyntaxError cases with imported code. @@ -1570,14 +1570,14 @@ class InteractiveShell(SingletonConfigurable, Magic): else: stb = self.InteractiveTB.structured_traceback(etype, value, tb, tb_offset=tb_offset) - + if self.call_pdb: # drop into debugger self.debugger(force=True) # Actually show the traceback self._showtraceback(etype, value, stb) - + except KeyboardInterrupt: self.write_err("\nKeyboardInterrupt\n") @@ -1604,7 +1604,7 @@ class InteractiveShell(SingletonConfigurable, Magic): sys.last_type = etype sys.last_value = value sys.last_traceback = last_traceback - + if filename and etype is SyntaxError: # Work hard to stuff the correct filename in the exception try: @@ -1622,13 +1622,13 @@ class InteractiveShell(SingletonConfigurable, Magic): value = msg, (filename, lineno, offset, line) stb = self.SyntaxTB.structured_traceback(etype, value, []) self._showtraceback(etype, value, stb) - + # This is overridden in TerminalInteractiveShell to show a message about # the %paste magic. def showindentationerror(self): """Called by run_cell when there's an IndentationError in code entered at the prompt. - + This is overridden in TerminalInteractiveShell to show a message about the %paste magic.""" self.showsyntaxerror() @@ -1660,7 +1660,7 @@ class InteractiveShell(SingletonConfigurable, Magic): self.has_readline = True self.readline = readline sys.modules['readline'] = readline - + # Platform-specific configuration if os.name == 'nt': # FIXME - check with Frederick to see if we can harmonize @@ -1686,7 +1686,7 @@ class InteractiveShell(SingletonConfigurable, Magic): except: warn('Problems reading readline initialization file <%s>' % inputrc_name) - + # Configure readline according to user's prefs # This is only done if GNU readline is being used. If libedit # is being used (as on Leopard) the readline config is @@ -1707,13 +1707,13 @@ class InteractiveShell(SingletonConfigurable, Magic): readline.set_completer_delims(delims) # otherwise we end up with a monster history after a while: readline.set_history_length(self.history_length) - + self.refill_readline_hist() self.readline_no_record = ReadlineNoRecord(self) # Configure auto-indent for all platforms self.set_autoindent(self.autoindent) - + def refill_readline_hist(self): # Load the last 1000 lines from history self.readline.clear_history() @@ -1727,13 +1727,13 @@ class InteractiveShell(SingletonConfigurable, Magic): def set_next_input(self, s): """ Sets the 'default' input string for the next command line. - + Requires readline. - + Example: - + [D:\ipython]|1> _ip.set_next_input("Hello Word") - [D:\ipython]|2> Hello Word_ # cursor is here + [D:\ipython]|2> Hello Word_ # cursor is here """ if isinstance(s, unicode): s = s.encode(self.stdin_encoding, 'replace') @@ -1770,7 +1770,7 @@ class InteractiveShell(SingletonConfigurable, Magic): from IPython.core.completer import IPCompleter from IPython.core.completerlib import (module_completer, magic_run_completer, cd_completer) - + self.Completer = IPCompleter(shell=self, namespace=self.user_ns, global_namespace=self.user_global_ns, @@ -1779,7 +1779,7 @@ class InteractiveShell(SingletonConfigurable, Magic): use_readline=self.has_readline, config=self.config, ) - + # Add custom completers to the basic ones built into IPCompleter sdisp = self.strdispatchers.get('complete_command', StrDispatch()) self.strdispatchers['complete_command'] = sdisp @@ -1823,7 +1823,7 @@ class InteractiveShell(SingletonConfigurable, Magic): The optional arguments allow the completion to take more context into account, and are part of the low-level completion API. - + This is a wrapper around the completion mechanism, similar to what readline does at the command line when the TAB key is hit. By exposing it as a method, it can be used by other non-readline @@ -1897,11 +1897,11 @@ class InteractiveShell(SingletonConfigurable, Magic): # We do this first so that magic functions can override it. if next_input: self.set_next_input(next_input) - + args = arg_s.split(' ',1) magic_name = args[0] magic_name = magic_name.lstrip(prefilter.ESC_MAGIC) - + try: magic_args = args[1] except IndexError: @@ -1921,14 +1921,14 @@ class InteractiveShell(SingletonConfigurable, Magic): return result def define_magic(self, magicname, func): - """Expose own function as magic function for ipython - + """Expose own function as magic function for ipython + def foo_impl(self,parameter_s=''): 'My very own magic!. (Use docstrings, IPython reads them).' print 'Magic function. Passed parameter is between < >:' print '<%s>' % parameter_s print 'The self object is:',self - + self.define_magic('foo',foo_impl) """ im = types.MethodType(func,self) @@ -1948,10 +1948,10 @@ class InteractiveShell(SingletonConfigurable, Magic): name : str The name of the macro. themacro : str or Macro - The action to do upon invoking the macro. If a string, a new + The action to do upon invoking the macro. If a string, a new Macro object is created by passing the string to it. """ - + from IPython.core import macro if isinstance(themacro, basestring): @@ -1981,15 +1981,15 @@ class InteractiveShell(SingletonConfigurable, Magic): # os.system() or use ip.system=ip.system_raw # if they really want a background process. raise OSError("Background processes not supported.") - + # we explicitly do NOT return the subprocess status code, because # a non-None value would trigger :func:`sys.displayhook` calls. # Instead, we store the exit_code in user_ns. self.user_ns['_exit_code'] = system(self.var_expand(cmd, depth=2)) - + def system_raw(self, cmd): """Call the given cmd in a subprocess using os.system - + Parameters ---------- cmd : str @@ -1999,7 +1999,7 @@ class InteractiveShell(SingletonConfigurable, Magic): # a non-None value would trigger :func:`sys.displayhook` calls. # Instead, we store the exit_code in user_ns. self.user_ns['_exit_code'] = os.system(self.var_expand(cmd, depth=2)) - + # use piped system by default, because it is better behaved system = system_piped @@ -2012,7 +2012,7 @@ class InteractiveShell(SingletonConfigurable, Magic): Command to execute (can not end in '&', as background processes are not supported. split : bool, optional - + If True, split the output into an IPython SList. Otherwise, an IPython LSString is returned. These are objects similar to normal lists and strings, with a few convenience attributes for easier @@ -2076,7 +2076,7 @@ class InteractiveShell(SingletonConfigurable, Magic): into:: ------> f(x) - + after the user's input prompt. This helps the user understand that the input line was transformed automatically by IPython. """ @@ -2089,7 +2089,7 @@ class InteractiveShell(SingletonConfigurable, Magic): print >> io.stdout, rw except UnicodeEncodeError: print "------> " + cmd - + #------------------------------------------------------------------------- # Things related to extracting values/expressions from kernel and user_ns #------------------------------------------------------------------------- @@ -2119,7 +2119,7 @@ class InteractiveShell(SingletonConfigurable, Magic): value = self._simple_error() out[varname] = value return out - + def user_expressions(self, expressions): """Evaluate a dict of expressions in the user's namespace. @@ -2129,7 +2129,7 @@ class InteractiveShell(SingletonConfigurable, Magic): A dict with string keys and string values. The expression values should be valid Python expressions, each of which will be evaluated in the user namespace. - + Returns ------- A dict, keyed like the input expressions dict, with the repr() of each @@ -2251,10 +2251,10 @@ class InteractiveShell(SingletonConfigurable, Magic): except: self.showtraceback() warn('Unknown failure executing file: <%s>' % fname) - + def run_cell(self, raw_cell, store_history=True): """Run a complete IPython cell. - + Parameters ---------- raw_cell : str @@ -2266,11 +2266,11 @@ class InteractiveShell(SingletonConfigurable, Magic): """ if (not raw_cell) or raw_cell.isspace(): return - + for line in raw_cell.splitlines(): self.input_splitter.push(line) cell = self.input_splitter.source_reset() - + with self.builtin_trap: prefilter_failed = False if len(cell.splitlines()) == 1: @@ -2285,18 +2285,18 @@ class InteractiveShell(SingletonConfigurable, Magic): # don't allow prefilter errors to crash IPython self.showtraceback() prefilter_failed = True - + # Store raw and processed history if store_history: - self.history_manager.store_inputs(self.execution_count, + self.history_manager.store_inputs(self.execution_count, cell, raw_cell) self.logger.log(cell, raw_cell) - + if not prefilter_failed: # don't run if prefilter failed cell_name = self.compile.cache(cell, self.execution_count) - + with self.display_trap: try: code_ast = self.compile.ast_parse(cell, filename=cell_name) @@ -2309,10 +2309,10 @@ class InteractiveShell(SingletonConfigurable, Magic): self.showsyntaxerror() self.execution_count += 1 return None - + self.run_ast_nodes(code_ast.body, cell_name, interactivity="last_expr") - + # Execute any registered post-execution functions. for func, status in self._post_execute.iteritems(): if not status: @@ -2323,18 +2323,18 @@ class InteractiveShell(SingletonConfigurable, Magic): self.showtraceback() # Deactivate failing function self._post_execute[func] = False - + if store_history: # Write output to the database. Does nothing unless # history output logging is enabled. self.history_manager.store_output(self.execution_count) # Each cell is a *single* input, regardless of how many lines it has self.execution_count += 1 - + def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr'): """Run a sequence of AST nodes. The execution mode depends on the interactivity parameter. - + Parameters ---------- nodelist : list @@ -2351,13 +2351,13 @@ class InteractiveShell(SingletonConfigurable, Magic): """ if not nodelist: return - + if interactivity == 'last_expr': if isinstance(nodelist[-1], ast.Expr): interactivity = "last" else: interactivity = "none" - + if interactivity == 'none': to_run_exec, to_run_interactive = nodelist, [] elif interactivity == 'last': @@ -2366,7 +2366,7 @@ class InteractiveShell(SingletonConfigurable, Magic): to_run_exec, to_run_interactive = [], nodelist else: raise ValueError("Interactivity was %r" % interactivity) - + exec_count = self.execution_count try: @@ -2394,7 +2394,7 @@ class InteractiveShell(SingletonConfigurable, Magic): self.showtraceback() return False - + def run_code(self, code_obj): """Execute a code object. @@ -2444,7 +2444,7 @@ class InteractiveShell(SingletonConfigurable, Magic): print return outflag - + # For backwards compatibility runcode = run_code @@ -2487,7 +2487,7 @@ class InteractiveShell(SingletonConfigurable, Magic): filename = tempfile.mktemp('.py', prefix) self.tempfiles.append(filename) - + if data: tmp_file = open(filename,'w') tmp_file.write(data) @@ -2508,16 +2508,16 @@ class InteractiveShell(SingletonConfigurable, Magic): if self.quiet: return True return ask_yes_no(prompt,default) - + def show_usage(self): """Show a usage message""" page.page(IPython.core.usage.interactive_usage) - + def find_user_code(self, target, raw=True): """Get a code string from history, file, or a string or macro. - - This is mainly used by magic functions. - + + This is mainly used by magic functions. + Parameters ---------- target : str @@ -2527,21 +2527,21 @@ class InteractiveShell(SingletonConfigurable, Magic): raw : bool If true (default), retrieve raw history. Has no effect on the other retrieval mechanisms. - + Returns ------- A string of code. - + ValueError is raised if nothing is found, and TypeError if it evaluates to an object of another type. In each case, .args[0] is a printable message. """ - code = self.extract_input_lines(target, raw=raw) # Grab history + code = self.extract_input_lines(target, raw=raw) # Grab history if code: return code if os.path.isfile(target): # Read file return open(target, "r").read() - + try: # User namespace codeobj = eval(target, self.user_ns) except Exception: @@ -2551,7 +2551,7 @@ class InteractiveShell(SingletonConfigurable, Magic): return codeobj elif isinstance(codeobj, Macro): return codeobj.value - + raise TypeError("%s is neither a string nor a macro." % target, codeobj) @@ -2567,20 +2567,20 @@ class InteractiveShell(SingletonConfigurable, Magic): For things that may depend on startup flags or platform specifics (such as having readline or not), register a separate atexit function in the code that has the appropriate information, rather than trying to - clutter + clutter """ # Close the history session (this stores the end time and line count) # this must be *before* the tempfile cleanup, in case of temporary # history db self.history_manager.end_session() - + # Cleanup all tempfiles left around for tfile in self.tempfiles: try: os.unlink(tfile) except OSError: pass - + # Clear all user namespaces to release all references cleanly. self.reset(new_session=False) diff --git a/IPython/core/logger.py b/IPython/core/logger.py index d83ec69..4bc162f 100644 --- a/IPython/core/logger.py +++ b/IPython/core/logger.py @@ -58,7 +58,7 @@ class Logger(object): return self._logmode logmode = property(_get_mode,_set_mode) - + def logstart(self,logfname=None,loghead=None,logmode=None, log_output=False,timestamp=False,log_raw_input=False): """Generate a new log-file with a default header. @@ -68,7 +68,7 @@ class Logger(object): if self.logfile is not None: raise RuntimeError('Log file is already active: %s' % self.logfname) - + # The parameters can override constructor defaults if logfname is not None: self.logfname = logfname if loghead is not None: self.loghead = loghead @@ -78,7 +78,7 @@ class Logger(object): self.timestamp = timestamp self.log_output = log_output self.log_raw_input = log_raw_input - + # init depending on the log mode requested isfile = os.path.isfile logmode = self.logmode @@ -102,12 +102,12 @@ class Logger(object): elif logmode == 'over': if isfile(self.logfname): - os.remove(self.logfname) + os.remove(self.logfname) self.logfile = open(self.logfname,'w') elif logmode == 'rotate': if isfile(self.logfname): - if isfile(self.logfname+'.001~'): + if isfile(self.logfname+'.001~'): old = glob.glob(self.logfname+'.*~') old.sort() old.reverse() @@ -117,7 +117,7 @@ class Logger(object): os.rename(f, root+'.'+`num`.zfill(3)+'~') os.rename(self.logfname, self.logfname+'.001~') self.logfile = open(self.logfname,'w') - + if logmode != 'append': self.logfile.write(self.loghead) @@ -130,7 +130,7 @@ class Logger(object): if val not in [False,True,0,1]: raise ValueError, \ 'Call switch_log ONLY with a boolean argument, not with:',val - + label = {0:'OFF',1:'ON',False:'OFF',True:'ON'} if self.logfile is None: @@ -140,7 +140,7 @@ Logging hasn't been started yet (use logstart for that). %logon/%logoff are for temporarily starting and stopping logging for a logfile which already exists. But you must first start the logging process with %logstart (optionally giving a logfile name).""" - + else: if self.log_active == val: print 'Logging is already',label[val] @@ -205,7 +205,7 @@ which already exists. But you must first start the logging process with In order to start logging again, a new logstart() call needs to be made, possibly (though not necessarily) with a new filename, mode and other options.""" - + if self.logfile is not None: self.logfile.close() self.logfile = None diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 34fc513..1f3cff2 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -84,13 +84,13 @@ def compress_dhist(dh): newhead.append(h) done.add(h) - return newhead + tail + return newhead + tail def needs_local_scope(func): """Decorator to mark magic functions which need to local scope to run.""" func.needs_local_scope = True return func - + # Used for exception handling in magic_edit class MacroToEdit(ValueError): pass @@ -101,7 +101,7 @@ class MacroToEdit(ValueError): pass # on construction of the main InteractiveShell object. Something odd is going # on with super() calls, Configurable and the MRO... For now leave it as-is, but # eventually this needs to be clarified. -# BG: This is because InteractiveShell inherits from this, but is itself a +# BG: This is because InteractiveShell inherits from this, but is itself a # Configurable. This messes up the MRO in some way. The fix is that we need to # make Magic a configurable that InteractiveShell does not subclass. @@ -124,7 +124,7 @@ class Magic: # some utility functions def __init__(self,shell): - + self.options_table = {} if profile is None: self.magic_prun = self.profile_missing_notice @@ -153,7 +153,7 @@ python-profiler package from non-free.""") ['magic_ls','magic_cd',...]""" # FIXME. This needs a cleanup, in the way the magics list is built. - + # magics in class definition class_magic = lambda fn: fn.startswith('magic_') and \ callable(Magic.__dict__[fn]) @@ -171,13 +171,13 @@ python-profiler package from non-free.""") out.append(fn.replace('magic_','',1)) out.sort() return out - + def extract_input_lines(self, range_str, raw=False): """Return as a string a set of input history slices. Inputs: - - range_str: the set of slices is given as a string, like + - range_str: the set of slices is given as a string, like "~5/6-~4/2 4:8 9", since this function is for use by magic functions which get their arguments as strings. The number before the / is the session number: ~n goes n back from the current session. @@ -195,7 +195,7 @@ python-profiler package from non-free.""") lines = self.shell.history_manager.\ get_range_by_str(range_str, raw=raw) return "\n".join(x for _, _, x in lines) - + def arg_err(self,func): """Print docstring if incorrect arguments were passed""" print 'Error in arguments:' @@ -209,7 +209,7 @@ python-profiler package from non-free.""") # Magic command names as headers: cmd_name_re = re.compile(r'^(%s.*?):' % ESC_MAGIC, re.MULTILINE) - # Magic commands + # Magic commands cmd_re = re.compile(r'(?P%s.+?\b)(?!\}\}:)' % ESC_MAGIC, re.MULTILINE) # Paragraph continue @@ -249,11 +249,11 @@ python-profiler package from non-free.""") -posix (True): whether to split the input line in POSIX mode or not, as per the conventions outlined in the shlex module from the standard library.""" - + # inject default options at the beginning of the input line caller = sys._getframe(1).f_code.co_name.replace('magic_','') arg_str = '%s %s' % (self.options_table.get(caller,''),arg_str) - + mode = kw.get('mode','string') if mode not in ['string','list']: raise ValueError,'incorrect mode given: %s' % mode @@ -272,7 +272,7 @@ python-profiler package from non-free.""") try: opts,args = getopt(argv,opt_str,*long_opts) except GetoptError,e: - raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str, + raise UsageError('%s ( allowed: "%s" %s)' % (e.msg,opt_str, " ".join(long_opts))) for o,a in opts: if o.startswith('--'): @@ -295,7 +295,7 @@ python-profiler package from non-free.""") args = ' '.join(args) return opts,args - + #...................................................................... # And now the actual magic functions @@ -307,11 +307,11 @@ python-profiler package from non-free.""") (' '+mesc).join(self.lsmagic()) print '\n' + Magic.auto_status[self.shell.automagic] return None - + def magic_magic(self, parameter_s = ''): """Print information about the magic function system. - - Supported formats: -latex, -brief, -rest + + Supported formats: -latex, -brief, -rest """ mode = '' @@ -338,30 +338,30 @@ python-profiler package from non-free.""") break if mode == 'brief': # only first line - if fn.__doc__: + if fn.__doc__: fndoc = fn.__doc__.split('\n',1)[0] else: fndoc = 'No documentation' else: if fn.__doc__: - fndoc = fn.__doc__.rstrip() + fndoc = fn.__doc__.rstrip() else: fndoc = 'No documentation' - - + + if mode == 'rest': rest_docs.append('**%s%s**::\n\n\t%s\n\n' %(ESC_MAGIC, fname,fndoc)) - + else: magic_docs.append('%s%s:\n\t%s\n' %(ESC_MAGIC, fname,fndoc)) - + magic_docs = ''.join(magic_docs) if mode == 'rest': return "".join(rest_docs) - + if mode == 'latex': print self.format_latex(magic_docs) return @@ -369,7 +369,7 @@ python-profiler package from non-free.""") magic_docs = format_screen(magic_docs) if mode == 'brief': return magic_docs - + outmsg = """ IPython's 'magic' functions =========================== @@ -495,11 +495,11 @@ Currently the magic system has the following functions:\n""" def magic_page(self, parameter_s=''): """Pretty print the object and display it through a pager. - + %page [options] OBJECT If no object is given, use _ (last output). - + Options: -r: page str(object), don't pretty-print it.""" @@ -524,12 +524,12 @@ Currently the magic system has the following functions:\n""" def magic_pinfo(self, parameter_s='', namespaces=None): """Provide detailed information about an object. - + '%pinfo object' is just a synonym for object? or ?object.""" - + #print 'pinfo par: <%s>' % parameter_s # dbg - - + + # detail_level: 0 -> obj? , 1 -> obj?? detail_level = 0 # We need to detect if we got called as 'pinfo pinfo foo', which can @@ -546,7 +546,7 @@ Currently the magic system has the following functions:\n""" def magic_pinfo2(self, parameter_s='', namespaces=None): """Provide extra detailed information about an object. - + '%pinfo2 object' is just a synonym for object?? or ??object.""" self.shell._inspect('pinfo', parameter_s, detail_level=1, namespaces=namespaces) @@ -556,11 +556,11 @@ Currently the magic system has the following functions:\n""" """Print the definition header for any callable object. If the object is a class, print the constructor information. - + Examples -------- :: - + In [3]: %pdef urllib.urlopen urllib.urlopen(url, data=None, proxies=None) """ @@ -615,7 +615,7 @@ Currently the magic system has the following functions:\n""" ?-i a* function Arguments: - + PATTERN where PATTERN is a string containing * as a wildcard similar to its @@ -642,8 +642,8 @@ Currently the magic system has the following functions:\n""" -i/-c: make the pattern case insensitive/sensitive. If neither of these options are given, the default is read from your configuration - file, with the option ``InteractiveShell.wildcards_case_sensitive``. - If this option is not specified in your configuration file, IPython's + file, with the option ``InteractiveShell.wildcards_case_sensitive``. + If this option is not specified in your configuration file, IPython's internal default is to do a case sensitive search. -e/-s NAMESPACE: exclude/search a given namespace. The pattern you @@ -659,9 +659,9 @@ Currently the magic system has the following functions:\n""" and it contains module-level globals. You can add namespaces to the search with -s or exclude them with -e (these options can be given more than once). - + Examples: - + %psearch a* -> objects beginning with an a %psearch -e builtin a* -> objects NOT in the builtin space starting in a %psearch a* function -> all functions beginning with an a @@ -670,11 +670,11 @@ Currently the magic system has the following functions:\n""" %psearch r*.* string -> all strings in modules beginning with r Case sensitve search: - + %psearch -c a* list all object beginning with lower case a Show objects beginning with a single _: - + %psearch -a _* list objects beginning with a single underscore""" try: parameter_s.encode('ascii') @@ -703,14 +703,14 @@ Currently the magic system has the following functions:\n""" def_search.extend(opt('s',[])) ns_exclude = ns_exclude=opt('e',[]) ns_search = [nm for nm in def_search if nm not in ns_exclude] - + # Call the actual search try: psearch(args,shell.ns_table,ns_search, show_all=opt('a'),ignore_case=ignore_case) except: shell.showtraceback() - + @skip_doctest def magic_who_ls(self, parameter_s=''): """Return a sorted list of all interactive variables. @@ -751,7 +751,7 @@ Currently the magic system has the following functions:\n""" out.sort() return out - + @skip_doctest def magic_who(self, parameter_s=''): """Print all interactive variables, with some minimal formatting. @@ -820,7 +820,7 @@ Currently the magic system has the following functions:\n""" The same type filtering of %who can be applied here. For all variables, the type is printed. Additionally it prints: - + - For {},[],(): their length. - For numpy arrays, a summary with shape, number of @@ -844,7 +844,7 @@ Currently the magic system has the following functions:\n""" alpha int 123 beta str test """ - + varnames = self.magic_who_ls(parameter_s) if not varnames: if parameter_s: @@ -875,13 +875,13 @@ Currently the magic system has the following functions:\n""" # Find all variable names and types so we can figure out column sizes def get_vars(i): return self.shell.user_ns[i] - + # some types are well known and can be shorter abbrevs = {'IPython.core.macro.Macro' : 'Macro'} def type_name(v): tn = type(v).__name__ return abbrevs.get(tn,tn) - + varlist = map(get_vars,varnames) typelist = [] @@ -927,7 +927,7 @@ Currently the magic system has the following functions:\n""" vsize = Numeric.size(var) vbytes = vsize*var.itemsize() vdtype = var.typecode() - + if vbytes < 100000: print aformat % (vshape,vsize,vdtype,vbytes) else: @@ -947,19 +947,19 @@ Currently the magic system has the following functions:\n""" print vstr else: print vstr[:25] + "<...>" + vstr[-25:] - + def magic_reset(self, parameter_s=''): """Resets the namespace by removing all names defined by the user. Parameters ---------- -f : force reset without asking for confirmation. - + -s : 'Soft' reset: Only clears your namespace, leaving history intact. References to objects may be kept. By default (without this option), we do a 'hard' reset, giving you a new session and removing all references to objects from the current session. - + Examples -------- In [6]: a = 1 @@ -984,16 +984,16 @@ Currently the magic system has the following functions:\n""" if not ans: print 'Nothing done.' return - + if 's' in opts: # Soft reset user_ns = self.shell.user_ns for i in self.magic_who_ls(): del(user_ns[i]) - + else: # Hard reset self.shell.reset(new_session = False) - - + + def magic_reset_selective(self, parameter_s=''): """Resets the namespace by removing names defined by the user. @@ -1003,7 +1003,7 @@ Currently the magic system has the following functions:\n""" %reset_selective [-f] regex No action is taken if regex is not included - + Options -f : force reset without asking for confirmation. @@ -1013,7 +1013,7 @@ Currently the magic system has the following functions:\n""" We first fully reset the namespace so your output looks identical to this example for pedagogical reasons; in practice you do not need a full reset. - + In [1]: %reset -f Now, with a clean namespace we can make a few variables and use @@ -1044,9 +1044,9 @@ Currently the magic system has the following functions:\n""" In [11]: who_ls Out[11]: ['a'] """ - + opts, regex = self.parse_options(parameter_s,'f') - + if opts.has_key('f'): ans = True else: @@ -1065,16 +1065,16 @@ Currently the magic system has the following functions:\n""" except TypeError: raise TypeError('regex must be a string or compiled pattern') for i in self.magic_who_ls(): - if m.search(i): + if m.search(i): del(user_ns[i]) - + def magic_xdel(self, parameter_s=''): """Delete a variable, trying to clear it from anywhere that IPython's machinery has references to it. By default, this uses the identity of the named object in the user namespace to remove references held under other names. The object is also removed from the output history. - + Options -n : Delete the specified name from all namespaces, without checking their identity. @@ -1084,7 +1084,7 @@ Currently the magic system has the following functions:\n""" self.shell.del_var(varname, ('n' in opts)) except (NameError, ValueError) as e: print type(e).__name__ +": "+ str(e) - + def magic_logstart(self,parameter_s=''): """Start logging anywhere in a session. @@ -1125,7 +1125,7 @@ Currently the magic system has the following functions:\n""" -t: put timestamps before each input line logged (these are put in comments).""" - + opts,par = self.parse_options(parameter_s,'ort') log_output = 'o' in opts log_raw_input = 'r' in opts @@ -1172,7 +1172,7 @@ Currently the magic system has the following functions:\n""" input_hist = self.shell.history_manager.input_hist_raw else: input_hist = self.shell.history_manager.input_hist_parsed - + if log_output: log_write = logger.log_write output_hist = self.shell.history_manager.output_hist @@ -1186,7 +1186,7 @@ Currently the magic system has the following functions:\n""" if timestamp: # re-enable timestamping logger.timestamp = True - + print ('Activating auto-logging. ' 'Current session state plus future input saved.') logger.logstate() @@ -1204,7 +1204,7 @@ Currently the magic system has the following functions:\n""" You must have previously started logging.""" self.shell.logger.switch_log(0) - + def magic_logon(self,parameter_s=''): """Restart logging. @@ -1212,14 +1212,14 @@ Currently the magic system has the following functions:\n""" stopped with %logoff. For starting logging for the first time, you must use the %logstart function, which allows you to specify an optional log filename.""" - + self.shell.logger.switch_log(1) - + def magic_logstate(self,parameter_s=''): """Print the status of the logging system.""" self.shell.logger.logstate() - + def magic_pdb(self, parameter_s=''): """Control the automatic calling of the pdb interactive debugger. @@ -1314,7 +1314,7 @@ Currently the magic system has the following functions:\n""" When more than one key is provided, additional keys are used as secondary criteria when the there is equality in all keys selected before them. - + Abbreviations can be used for any key names, as long as the abbreviation is unambiguous. The following are the keys currently defined: @@ -1353,16 +1353,16 @@ Currently the magic system has the following functions:\n""" If you want to run complete programs under the profiler's control, use '%run -p [prof_opts] filename.py [args to program]' where prof_opts contains profiler specific options as described here. - + You can read the complete documentation for the profile module with:: - + In [1]: import profile; profile.help() """ opts_def = Struct(D=[''],l=[],s=['time'],T=['']) # protect user quote marks parameter_s = parameter_s.replace('"',r'\"').replace("'",r"\'") - + if user_mode: # regular user call opts,arg_str = self.parse_options(parameter_s,'D:l:rs:T:', list_all=1) @@ -1382,7 +1382,7 @@ Currently the magic system has the following functions:\n""" namespace = locals() opts.merge(opts_def) - + prof = profile.Profile() try: prof = prof.runctx(arg_str,namespace,namespace) @@ -1403,7 +1403,7 @@ Currently the magic system has the following functions:\n""" lims.append(float(lim)) except ValueError: lims.append(lim) - + # Trap output. stdout_trap = StringIO() @@ -1420,7 +1420,7 @@ Currently the magic system has the following functions:\n""" stats.print_stats(*lims) finally: sys.stdout = sys_stdout - + output = stdout_trap.getvalue() output = output.rstrip() @@ -1454,7 +1454,7 @@ Currently the magic system has the following functions:\n""" Usage:\\ %run [-n -i -t [-N] -d [-b] -p [profile options]] file [args] - + Parameters after the filename are passed as command-line arguments to the program (put in sys.argv). Then, control returns to IPython's prompt. @@ -1475,7 +1475,7 @@ Currently the magic system has the following functions:\n""" interactive work, while giving each program a 'clean sheet' to run in. Options: - + -n: __name__ is NOT set to '__main__', but to the running file's name without extension (as python does under import). This allows running scripts and reloading the definitions in them without calling code @@ -1520,7 +1520,7 @@ Currently the magic system has the following functions:\n""" -d: run your program under the control of pdb, the Python debugger. This allows you to execute your program step by step, watch variables, etc. Internally, what IPython does is similar to calling: - + pdb.run('execfile("YOURFILENAME")') with a breakpoint set on line 1 of your file. You can change the line @@ -1580,10 +1580,10 @@ Currently the magic system has the following functions:\n""" if filename.lower().endswith('.ipy'): self.shell.safe_execfile_ipy(filename) return - + # Control the response to exit() calls made by the script being run exit_ignore = opts.has_key('e') - + # Make sure that the running script gets a proper sys.argv as if it # were run from a system shell. save_argv = sys.argv # save it for later restoring @@ -1626,7 +1626,7 @@ Currently the magic system has the following functions:\n""" # This needs to be undone at the end to prevent holding references to # every single object ever created. sys.modules[main_mod_name] = main_mod - + try: stats = None with self.readline_no_record: @@ -1663,7 +1663,7 @@ Currently the magic system has the following functions:\n""" print "%s prompt to start your script." % deb.prompt try: deb.run('execfile("%s")' % filename,prog_ns) - + except: etype, value, tb = sys.exc_info() # Skip three frames in the traceback: the %run one, @@ -1739,7 +1739,7 @@ Currently the magic system has the following functions:\n""" # we can do is to at least restore __builtins__ for the user on # exit. self.shell.user_ns['__builtins__'] = builtin_mod - + # Ensure key global structures are restored sys.argv = save_argv if restore_main: @@ -1749,7 +1749,7 @@ Currently the magic system has the following functions:\n""" # added. Otherwise it will trap references to objects # contained therein. del sys.modules[main_mod_name] - + return stats @skip_doctest @@ -1764,14 +1764,14 @@ Currently the magic system has the following functions:\n""" Options: -n: execute the given statement times in a loop. If this value - is not given, a fitting value is chosen. - + is not given, a fitting value is chosen. + -r: repeat the loop iteration times and take the best result. Default: 3 - + -t: use time.time to measure the time, which is the default on Unix. This function measures wall time. - + -c: use time.clock to measure the time, which is the default on Windows and measures wall time. On Unix, resource.getrusage is used instead and returns the CPU user time. @@ -1779,7 +1779,7 @@ Currently the magic system has the following functions:\n""" -p

: use a precision of

digits to display the timing result. Default: 3 - + Examples: In [1]: %timeit pass @@ -1797,7 +1797,7 @@ Currently the magic system has the following functions:\n""" In [6]: %timeit -n1 time.sleep(2) 1 loops, best of 3: 2 s per loop - + The times reported by %timeit will be slightly higher than those reported by the timeit.py script when variables are accessed. This is @@ -1828,10 +1828,10 @@ Currently the magic system has the following functions:\n""" # succeeds # # See bug: https://bugs.launchpad.net/ipython/+bug/348466 - + #units = [u"s", u"ms",u'\xb5',"ns"] units = [u"s", u"ms",u'us',"ns"] - + scaling = [1, 1e3, 1e6, 1e9] opts, stmt = self.parse_options(parameter_s,'n:r:tcp:', @@ -1857,15 +1857,15 @@ Currently the magic system has the following functions:\n""" # Track compilation time so it can be reported if too long # Minimum time above which compilation time will be reported tc_min = 0.1 - + t0 = clock() code = compile(src, "", "exec") tc = clock()-t0 - + ns = {} exec code in self.shell.user_ns, ns timer.inner = ns["inner"] - + if number == 0: # determine number so that 0.2 <= total time < 2.0 number = 1 @@ -1873,7 +1873,7 @@ Currently the magic system has the following functions:\n""" if timer.timeit(number) >= 0.2: break number *= 10 - + best = min(timer.repeat(repeat, number)) / number if best > 0.0 and best < 1000.0: @@ -1901,7 +1901,7 @@ Currently the magic system has the following functions:\n""" This function provides very basic timing functionality. In Python 2.3, the timeit module offers more control and sophistication, so this could be rewritten to use it (patches welcome). - + Some examples: In [1]: time 2**128 @@ -1936,14 +1936,14 @@ Currently the magic system has the following functions:\n""" Wall time: 0.00 s Compiler : 0.78 s """ - + # fail immediately if the given expression can't be compiled - + expr = self.shell.prefilter(parameter_s,False) # Minimum time above which compilation time will be reported tc_min = 0.1 - + try: mode = 'eval' t0 = clock() @@ -1992,7 +1992,7 @@ Currently the magic system has the following functions:\n""" %macro [options] name n1-n2 n3-n4 ... n5 .. n6 ... Options: - + -r: use 'raw' input. By default, the 'processed' history is used, so that magics are loaded in their transformed version to valid Python. If this option is given, the raw input as typed as the @@ -2011,7 +2011,7 @@ Currently the magic system has the following functions:\n""" notation, where N:M means numbers N through M-1. For example, if your history contains (%hist prints it): - + 44: x=1 45: y=3 46: z=x+y @@ -2036,9 +2036,9 @@ Currently the magic system has the following functions:\n""" code instead of printing them when you type their name. You can view a macro's contents by explicitly printing it with: - + 'print macro_name'. - + """ opts,args = self.parse_options(parameter_s,'r',mode='list') if not args: # List existing macros @@ -2048,7 +2048,7 @@ Currently the magic system has the following functions:\n""" raise UsageError( "%macro insufficient args; usage '%macro name n1-n2 n3-4...") name, codefrom = args[0], " ".join(args[1:]) - + #print 'rng',ranges # dbg try: lines = self.shell.find_user_code(codefrom, 'r' in opts) @@ -2068,13 +2068,13 @@ Currently the magic system has the following functions:\n""" %save [options] filename n1-n2 n3-n4 ... n5 .. n6 ... Options: - + -r: use 'raw' input. By default, the 'processed' history is used, so that magics are loaded in their transformed version to valid Python. If this option is given, the raw input as typed as the command line is used instead. - This function uses the same syntax as %history for input ranges, + This function uses the same syntax as %history for input ranges, then saves the lines to the filename you specify. It adds a '.py' extension to the file if you don't do so yourself, and @@ -2099,7 +2099,7 @@ Currently the magic system has the following functions:\n""" f.write(py3compat.cast_unicode(cmds)) print 'The following commands were written to file `%s`:' % fname print cmds - + def magic_pastebin(self, parameter_s = ''): """Upload code to the 'Lodge it' paste bin, returning the URL.""" try: @@ -2110,7 +2110,7 @@ Currently the magic system has the following functions:\n""" pbserver = ServerProxy('http://paste.pocoo.org/xmlrpc/') id = pbserver.pastes.newPaste("python", code) return "http://paste.pocoo.org/show/" + id - + def magic_loadpy(self, arg_s): """Load a .py python script into the GUI console. @@ -2130,10 +2130,10 @@ Currently the magic system has the following functions:\n""" with open(arg_s) as f: content = f.read() self.set_next_input(content) - + def _find_edit_target(self, args, opts, last_call): """Utility method used by magic_edit to find what to edit.""" - + def make_filename(arg): "Make a filename from the given args" arg = unquote_filename(arg) @@ -2141,20 +2141,20 @@ Currently the magic system has the following functions:\n""" filename = get_py_filename(arg) except IOError: # If it ends with .py but doesn't already exist, assume we want - # a new file. + # a new file. if arg.endswith('.py'): filename = arg else: filename = None return filename - + # Set a few locals from the options for convenience: opts_prev = 'p' in opts opts_raw = 'r' in opts # custom exceptions class DataIsObject(Exception): pass - + # Default line number value lineno = opts.get('n',None) @@ -2162,7 +2162,7 @@ Currently the magic system has the following functions:\n""" args = '_%s' % last_call[0] if not self.shell.user_ns.has_key(args): args = last_call[1] - + # use last_call to remember the state of the previous call, but don't # let it be clobbered by successive '-p' calls. try: @@ -2177,7 +2177,7 @@ Currently the magic system has the following functions:\n""" use_temp = True data = '' - + # First, see if the arguments should be a filename. filename = make_filename(args) if filename: @@ -2203,16 +2203,16 @@ Currently the magic system has the following functions:\n""" "or as a filename." % args) return use_temp = False - + except DataIsObject: # macros have a special edit function if isinstance(data, Macro): raise MacroToEdit(data) - + # For objects, try to edit the file where they are defined try: filename = inspect.getabsfile(data) - if 'fakemodule' in filename.lower() and inspect.isclass(data): + if 'fakemodule' in filename.lower() and inspect.isclass(data): # class created by %edit? Try to find source # by looking for method definitions instead, the # __module__ in those classes is FakeModule. @@ -2223,9 +2223,9 @@ Currently the magic system has the following functions:\n""" filename = inspect.getabsfile(attr) if filename and 'fakemodule' not in filename.lower(): # change the attribute to be the edit target instead - data = attr + data = attr break - + datafile = 1 except TypeError: filename = make_filename(args) @@ -2249,7 +2249,7 @@ Currently the magic system has the following functions:\n""" if use_temp: filename = self.shell.mktempfile(data) print 'IPython will make a temporary file named:',filename - + return filename, lineno, use_temp def _edit_macro(self,mname,macro): @@ -2266,7 +2266,7 @@ Currently the magic system has the following functions:\n""" def magic_ed(self,parameter_s=''): """Alias to %edit.""" return self.magic_edit(parameter_s) - + @skip_doctest def magic_edit(self,parameter_s='',last_call=['','']): """Bring up an editor and execute the resulting code. @@ -2280,15 +2280,15 @@ Currently the magic system has the following functions:\n""" notepad under Windows. See the end of this docstring for how to change the editor hook. - You can also set the value of this editor via the - ``TerminalInteractiveShell.editor`` option in your configuration file. - This is useful if you wish to use a different editor from your typical - default with IPython (and for Windows users who typically don't set + You can also set the value of this editor via the + ``TerminalInteractiveShell.editor`` option in your configuration file. + This is useful if you wish to use a different editor from your typical + default with IPython (and for Windows users who typically don't set environment variables). This command allows you to conveniently edit multi-line code right in your IPython session. - + If called without arguments, %edit opens up an empty editor with a temporary file and will execute the contents of this file when you close it (don't forget to save it!). @@ -2301,7 +2301,7 @@ Currently the magic system has the following functions:\n""" you can configure this by providing your own modified hook if your favorite editor supports line-number specifications with a different syntax. - + -p: this will call the editor with the same data as the previous time it was used, regardless of how long ago (in your current session) it was. @@ -2312,7 +2312,7 @@ Currently the magic system has the following functions:\n""" this option is given, the raw input as typed as the command line is used instead. When you exit the editor, it will be executed by IPython's own processor. - + -x: do not execute the edited code immediately upon exit. This is mainly useful if you are editing programs which need to be called with command line arguments, which you can then do using %run. @@ -2321,7 +2321,7 @@ Currently the magic system has the following functions:\n""" Arguments: If arguments are given, the following possibilites exist: - + - If the argument is a filename, IPython will load that into the editor. It will execute its contents with execfile() when you exit, loading any code in the file into your interactive namespace. @@ -2364,18 +2364,18 @@ Currently the magic system has the following functions:\n""" Out[1]: 'def foo():n print "foo() was defined in an editing session"n' We can then call the function foo(): - + In [2]: foo() foo() was defined in an editing session Now we edit foo. IPython automatically loads the editor with the (temporary) file where foo() was previously defined: - + In [3]: ed foo Editing... done. Executing edited code... And if we call foo() again we get the modified version: - + In [4]: foo() foo() has now been changed! @@ -2411,7 +2411,7 @@ Currently the magic system has the following functions:\n""" general instructions on how to set a new hook for use once you've defined it.""" opts,args = self.parse_options(parameter_s,'prxn:') - + try: filename, lineno, is_temp = self._find_edit_target(args, opts, last_call) except MacroToEdit as e: @@ -2429,12 +2429,12 @@ Currently the magic system has the following functions:\n""" except TryNext: warn('Could not open editor') return - + # XXX TODO: should this be generalized for all string vars? # For now, this is special-cased to blocks created by cpaste if args.strip() == 'pasted_block': self.shell.user_ns['pasted_block'] = file_read(filename) - + if 'x' in opts: # -x prevents actual execution print else: @@ -2445,7 +2445,7 @@ Currently the magic system has the following functions:\n""" else: self.shell.safe_execfile(filename,self.shell.user_ns, self.shell.user_ns) - + if is_temp: try: return open(filename).read() @@ -2481,19 +2481,19 @@ Currently the magic system has the following functions:\n""" Currently implemented schemes: NoColor, Linux, LightBG. Color scheme names are not case-sensitive. - + Examples -------- To get a plain black and white terminal:: - + %colors nocolor """ def color_switch_err(name): warn('Error changing %s color schemes.\n%s' % (name,sys.exc_info()[1])) - - + + new_scheme = parameter_s.strip() if not new_scheme: raise UsageError( @@ -2517,11 +2517,11 @@ http://starship.python.net/crew/theller/ctypes Defaulting color scheme to 'NoColor'""" new_scheme = 'NoColor' warn(msg) - + # readline option is 0 if not shell.colors_force and not shell.has_readline: new_scheme = 'NoColor' - + # Set prompt colors try: shell.displayhook.set_colors(new_scheme) @@ -2545,7 +2545,7 @@ Defaulting color scheme to 'NoColor'""" color_switch_err('object inspector') else: shell.inspector.set_active_scheme('NoColor') - + def magic_pprint(self, parameter_s=''): """Toggle pretty printing on/off.""" ptformatter = self.shell.display_formatter.formatters['text/plain'] @@ -2578,7 +2578,7 @@ Defaulting color scheme to 'NoColor'""" You can also define aliases with parameters using %s specifiers (one per parameter): - + In [1]: alias parts echo first %s second %s In [2]: %parts A B first A second B @@ -2589,7 +2589,7 @@ Defaulting color scheme to 'NoColor'""" Note that %l and %s are mutually exclusive. You can only use one or the other in your aliases. - Aliases expand Python variables just like system calls using ! or !! + Aliases expand Python variables just like system calls using ! or !! do: all expressions prefixed with '$' get expanded. For details of the semantic rules, see PEP-215: http://www.python.org/peps/pep-0215.html. This is the library used by @@ -2619,7 +2619,7 @@ Defaulting color scheme to 'NoColor'""" print "Total number of aliases:", len(aliases) sys.stdout.flush() return aliases - + # Now try to define a new one try: alias,cmd = par.split(None, 1) @@ -2649,7 +2649,7 @@ Defaulting color scheme to 'NoColor'""" Under Windows, it checks executability as a match agains a '|'-separated string of extensions, stored in the IPython config variable win_exec_ext. This defaults to 'exe|com|bat'. - + This function also resets the root module cache of module completer, used on slow filesystems. """ @@ -2657,8 +2657,8 @@ Defaulting color scheme to 'NoColor'""" # for the benefit of module completer in ipy_completers.py del self.db['rootmodules'] - - path = [os.path.abspath(os.path.expanduser(p)) for p in + + path = [os.path.abspath(os.path.expanduser(p)) for p in os.environ.get('PATH','').split(os.pathsep)] path = filter(os.path.isdir,path) @@ -2717,20 +2717,20 @@ Defaulting color scheme to 'NoColor'""" db['syscmdlist'] = syscmdlist finally: os.chdir(savedir) - - @skip_doctest + + @skip_doctest def magic_pwd(self, parameter_s = ''): """Return the current working directory path. - + Examples -------- :: - + In [9]: pwd Out[9]: '/home/tsuser/sprint/ipython' """ return os.getcwdu() - + @skip_doctest def magic_cd(self, parameter_s=''): """Change the current working directory. @@ -2749,25 +2749,25 @@ Defaulting color scheme to 'NoColor'""" cd -: changes to the n-th directory in the directory history. cd --foo: change to directory that matches 'foo' in history - + cd -b : jump to a bookmark set by %bookmark (note: cd is enough if there is no directory , but a bookmark with the name exists.) - 'cd -b ' allows you to tab-complete bookmark names. + 'cd -b ' allows you to tab-complete bookmark names. Options: -q: quiet. Do not print the working directory after the cd command is executed. By default IPython's cd command does print this directory, since the default prompts do not display path information. - + Note that !cd doesn't work for this purpose because the shell where !command runs is immediately discarded after executing 'command'. - + Examples -------- :: - + In [10]: cd parent/child /home/tsuser/parent/child """ @@ -2797,25 +2797,25 @@ Defaulting color scheme to 'NoColor'""" if pat in os.path.basename(ent) and os.path.isdir(ent): ps = ent break - + if fallback is None and pat in ent and os.path.isdir(ent): fallback = ent - + # if we have no last part match, pick the first full path match if ps is None: ps = fallback - + if ps is None: print "No matching entry in directory history" return else: opts = {} - - + + else: - #turn all non-space-escaping backslashes to slashes, + #turn all non-space-escaping backslashes to slashes, # for c:\windows\directory\names\ - parameter_s = re.sub(r'\\(?! )','/', parameter_s) + parameter_s = re.sub(r'\\(?! )','/', parameter_s) opts,ps = self.parse_options(parameter_s,'qb',mode='string') # jump to previous if ps == '-': @@ -2827,7 +2827,7 @@ Defaulting color scheme to 'NoColor'""" else: if not os.path.isdir(ps) or opts.has_key('b'): bkms = self.db.get('bookmarks', {}) - + if bkms.has_key(ps): target = bkms[ps] print '(bookmark:%s) -> %s' % (ps,target) @@ -2853,14 +2853,14 @@ Defaulting color scheme to 'NoColor'""" if oldcwd != cwd: dhist.append(cwd) self.db['dhist'] = compress_dhist(dhist)[-100:] - + else: os.chdir(self.shell.home_dir) if hasattr(self.shell, 'term_title') and self.shell.term_title: set_term_title('IPython: ' + '~') cwd = os.getcwdu() dhist = self.shell.user_ns['_dh'] - + if oldcwd != cwd: dhist.append(cwd) self.db['dhist'] = compress_dhist(dhist)[-100:] @@ -2870,16 +2870,16 @@ Defaulting color scheme to 'NoColor'""" def magic_env(self, parameter_s=''): """List environment variables.""" - + return os.environ.data def magic_pushd(self, parameter_s=''): """Place the current dir on stack and change directory. - + Usage:\\ %pushd ['dirname'] """ - + dir_s = self.shell.dir_stack tgt = os.path.expanduser(unquote_filename(parameter_s)) cwd = os.getcwdu().replace(self.home_dir,'~') @@ -2912,10 +2912,10 @@ Defaulting color scheme to 'NoColor'""" This history is automatically maintained by the %cd command, and always available as the global list variable _dh. You can use %cd - to go to directory number . - + Note that most of time, you should view directory history by entering cd -. - + """ dh = self.shell.user_ns['_dh'] @@ -2943,13 +2943,13 @@ Defaulting color scheme to 'NoColor'""" """Shell capture - execute a shell command and capture its output. DEPRECATED. Suboptimal, retained for backwards compatibility. - + You should use the form 'var = !command' instead. Example: - + "%sc -l myfiles = ls ~" should now be written as - + "myfiles = !ls ~" - + myfiles.s, myfiles.l and myfiles.n still apply as documented below. @@ -2963,7 +2963,7 @@ Defaulting color scheme to 'NoColor'""" The '=' sign in the syntax is mandatory, and the variable name you supply must follow Python's standard conventions for valid names. - + (A special format without variable name exists for internal use) Options: @@ -2983,7 +2983,7 @@ Defaulting color scheme to 'NoColor'""" For example: # all-random - + # Capture into variable a In [1]: sc a=ls *py @@ -3074,7 +3074,7 @@ Defaulting color scheme to 'NoColor'""" !!ls is a shorthand equivalent to: %sx ls - + 2) %sx differs from %sc in that %sx automatically splits into a list, like '%sc -l'. The reason for this is to make it as easy as possible to process line-oriented shell output via further python commands. @@ -3093,7 +3093,7 @@ Defaulting color scheme to 'NoColor'""" if parameter_s: return self.shell.getoutput(parameter_s) - + def magic_bookmark(self, parameter_s=''): """Manage IPython's bookmark system. @@ -3116,7 +3116,7 @@ Defaulting color scheme to 'NoColor'""" raise UsageError("%bookmark: too many arguments") bkms = self.db.get('bookmarks',{}) - + if opts.has_key('d'): try: todel = args[0] @@ -3157,7 +3157,7 @@ Defaulting color scheme to 'NoColor'""" This magic is similar to the cat utility, but it will assume the file to be Python source and will show it with syntax highlighting. """ - + try: filename = get_py_filename(parameter_s) cont = file_read(filename) @@ -3205,13 +3205,13 @@ Defaulting color scheme to 'NoColor'""" ] strip_from_start = map(re.compile,strip_re) - + lines = [] for l in raw_lines: - for pat in strip_from_start: + for pat in strip_from_start: l = pat.sub('',l) lines.append(l) - + block = "\n".join(lines) + '\n' #print "block:\n",block return block @@ -3231,7 +3231,7 @@ Defaulting color scheme to 'NoColor'""" """ Show a quick reference sheet """ import IPython.core.usage qr = IPython.core.usage.quick_reference + self.magic_magic('-brief') - + page.page(qr) def magic_doctest_mode(self,parameter_s=''): @@ -3298,7 +3298,7 @@ Defaulting color scheme to 'NoColor'""" ptformatter.pprint = False disp_formatter.plain_text_only = True - + shell.magic_xmode('Plain') else: # turn off @@ -3385,7 +3385,7 @@ Defaulting color scheme to 'NoColor'""" name = src.replace('profile_', '') print " %s"%name pd = ProfileDir.create_profile_dir_by_name(ipython_dir, name) - pd.copy_config_file('ipython_config.py', path=src, + pd.copy_config_file('ipython_config.py', path=src, overwrite=overwrite) @skip_doctest @@ -3452,16 +3452,16 @@ Defaulting color scheme to 'NoColor'""" Backend in use: Qt4Agg For more information, type 'help(pylab)'. """ - + if Application.initialized(): app = Application.instance() try: import_all_status = app.pylab_import_all except AttributeError: - import_all_status = True + import_all_status = True else: import_all_status = True - + self.shell.enable_pylab(s,import_all=import_all_status) def magic_tb(self, s): @@ -3469,50 +3469,50 @@ Defaulting color scheme to 'NoColor'""" See %xmode for changing exception reporting modes.""" self.shell.showtraceback() - + @skip_doctest def magic_precision(self, s=''): """Set floating point precision for pretty printing. - + Can set either integer precision or a format string. - + If numpy has been imported and precision is an int, numpy display precision will also be set, via ``numpy.set_printoptions``. - + If no argument is given, defaults will be restored. - + Examples -------- :: - + In [1]: from math import pi - + In [2]: %precision 3 Out[2]: u'%.3f' - + In [3]: pi Out[3]: 3.142 - + In [4]: %precision %i Out[4]: u'%i' - + In [5]: pi Out[5]: 3 - + In [6]: %precision %e Out[6]: u'%e' - + In [7]: pi**10 Out[7]: 9.364805e+04 - + In [8]: %precision Out[8]: u'%r' - + In [9]: pi**10 Out[9]: 93648.047476082982 - + """ - + ptformatter = self.shell.display_formatter.formatters['text/plain'] ptformatter.float_precision = s return ptformatter.float_format @@ -3583,6 +3583,6 @@ Defaulting color scheme to 'NoColor'""" nb = current.reads(s, u'xml') with open(new_fname, 'w') as f: current.write(nb, f, new_format) - + # end Magic diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 4597467..8d22e09 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -197,7 +197,7 @@ def call_tip(oinfo, format_call=True): When format_call is True, the whole call information is formattted as a single string. Otherwise, the object's name and its argspec dict are returned. If no call information is available, None is returned. - + docstring : str or None The most relevant docstring for calling purposes is returned, if available. The priority is: call docstring for callable instances, then @@ -219,7 +219,7 @@ def call_tip(oinfo, format_call=True): else: if has_self: argspec['args'] = argspec['args'][1:] - + call_line = oinfo['name']+format_argspec(argspec) # Now get docstring. @@ -249,14 +249,14 @@ class Inspector: If any exception is generated, None is returned instead and the exception is suppressed.""" - + try: # We need a plain string here, NOT unicode! hdef = oname + inspect.formatargspec(*getargspec(obj)) return py3compat.unicode_to_str(hdef, 'ascii') except: return None - + def __head(self,h): """Return a header string with proper colors.""" return '%s%s%s' % (self.color_table.active_colors.header,h, @@ -265,7 +265,7 @@ class Inspector: def set_active_scheme(self,scheme): self.color_table.set_active_scheme(scheme) self.parser.color_table.set_active_scheme(scheme) - + def noinfo(self,msg,oname): """Generic message when no information is found.""" print 'No %s found' % msg, @@ -273,7 +273,7 @@ class Inspector: print 'for %s' % oname else: print - + def pdef(self,obj,oname=''): """Print the definition header for any callable object. @@ -303,30 +303,30 @@ class Inspector: Optional: -formatter: a function to run the docstring through for specially formatted docstrings. - + Examples -------- - + In [1]: class NoInit: ...: pass - + In [2]: class NoDoc: ...: def __init__(self): ...: pass - + In [3]: %pdoc NoDoc No documentation found for NoDoc - + In [4]: %pdoc NoInit No documentation found for NoInit In [5]: obj = NoInit() - + In [6]: %pdoc obj No documentation found for obj In [5]: obj2 = NoDoc() - + In [6]: %pdoc obj2 No documentation found for obj2 """ @@ -355,14 +355,14 @@ class Inspector: self.noinfo('documentation',oname) else: page.page('\n'.join(lines)) - + def psource(self,obj,oname=''): """Print the source code for an object.""" # Flush the source cache because inspect can return out-of-date source linecache.checkcache() try: - src = getsource(obj) + src = getsource(obj) except: self.noinfo('source',oname) else: @@ -385,7 +385,7 @@ class Inspector: return # We only reach this point if object was successfully queried - + # run contents of file through pager starting at line # where the object is defined ofile = inspect.getabsfile(obj) @@ -399,10 +399,10 @@ class Inspector: # getsourcelines returns lineno with 1-offset and page() uses # 0-offset, so we must adjust. page.page(self.format(open(ofile).read()),lineno-1) - + def _format_fields(self, fields, title_width=12): """Formats a list of fields for display. - + Parameters ---------- fields : list @@ -428,17 +428,17 @@ class Inspector: ("Length", "length"), ("File", "file"), ("Definition", "definition")] - + pinfo_fields_obj = [("Class Docstring", "class_docstring"), ("Constructor Docstring","init_docstring"), ("Call def", "call_def"), ("Call docstring", "call_docstring")] - + def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0): """Show detailed information about an object. Optional arguments: - + - oname: name of the variable pointing to the object. - formatter: special formatter for docstrings (see pdoc) @@ -455,14 +455,14 @@ class Inspector: field = info[key] if field is not None: displayfields.append((title, field.rstrip())) - + # Source or docstring, depending on detail level and whether # source found. if detail_level > 0 and info['source'] is not None: displayfields.append(("Source", self.format(py3compat.unicode_to_str(info['source'])))) elif info['docstring'] is not None: displayfields.append(("Docstring", info["docstring"])) - + # Constructor info for classes if info['isclass']: if info['init_definition'] or info['init_docstring']: @@ -473,14 +473,14 @@ class Inspector: if info['init_docstring'] is not None: displayfields.append((" Docstring", indent(info['init_docstring']))) - + # Info for objects: else: for title, key in self.pinfo_fields_obj: field = info[key] if field is not None: displayfields.append((title, field.rstrip())) - + # Finally send to printer/pager: if displayfields: page.page(self._format_fields(displayfields)) @@ -489,7 +489,7 @@ class Inspector: """Compute a dict with detailed information about an object. Optional arguments: - + - oname: name of the variable pointing to the object. - formatter: special formatter for docstrings (see pdoc) @@ -532,7 +532,7 @@ class Inspector: # store output in a dict, we initialize it here and fill it as we go out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic) - + string_max = 200 # max size of strings to show (snipped if longer) shalf = int((string_max -5)/2) @@ -599,7 +599,7 @@ class Inspector: # avoid repetitions). If source fails, we add them back, see below. if ds and detail_level == 0: out['docstring'] = ds - + # Original source code for any callable if detail_level: # Flush the source cache because inspect can return out-of-date @@ -616,10 +616,10 @@ class Inspector: out['source'] = source.rstrip() except Exception: pass - + if ds and source is None: out['docstring'] = ds - + # Constructor docstring for classes if inspect.isclass(obj): @@ -692,7 +692,7 @@ class Inspector: # Compute the object's argspec as a callable. The key is to decide # whether to pull it from the object itself, from its __init__ or # from its __call__ method. - + if inspect.isclass(obj): # Old-style classes need not have an __init__ callable_obj = getattr(obj, "__init__", None) @@ -727,7 +727,7 @@ class Inspector: - ns_table: dict of name->namespaces for search. Optional arguments: - + - ns_search: list of namespace names to include in search. - ignore_case(False): make the search case-insensitive. @@ -736,7 +736,7 @@ class Inspector: underscores. """ #print 'ps pattern:<%r>' % pattern # dbg - + # defaults type_pattern = 'all' filter = '' diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index c31b34b..3dcf386 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -100,7 +100,7 @@ class PrefilterManager(Configurable): """Main prefilter component. The IPython prefilter is run on all user input before it is run. The - prefilter consumes lines of input and produces transformed lines of + prefilter consumes lines of input and produces transformed lines of input. The iplementation consists of two phases: @@ -119,12 +119,12 @@ class PrefilterManager(Configurable): After all the transformers have been run, the line is fed to the checkers, which are instances of :class:`PrefilterChecker`. The line is passed to - the :meth:`check` method, which either returns `None` or a + the :meth:`check` method, which either returns `None` or a :class:`PrefilterHandler` instance. If `None` is returned, the other checkers are tried. If an :class:`PrefilterHandler` instance is returned, the line is passed to the :meth:`handle` method of the returned handler and no further checkers are tried. - + Both transformers and checkers have a `priority` attribute, that determines the order in which they are called. Smaller priorities are tried first. @@ -317,7 +317,7 @@ class PrefilterManager(Configurable): # Now we compute line_info for the checkers and handlers line_info = LineInfo(line, continue_prompt) - + # the input history needs to track even empty lines stripped = line.strip() @@ -358,7 +358,7 @@ class PrefilterManager(Configurable): for lnum, line in enumerate(llines) ]) else: out = self.prefilter_line(llines[0], continue_prompt) - + return out #----------------------------------------------------------------------------- @@ -522,9 +522,9 @@ class ShellEscapeChecker(PrefilterChecker): class MacroChecker(PrefilterChecker): - + priority = Int(250, config=True) - + def check(self, line_info): obj = self.shell.user_ns.get(line_info.ifun) if isinstance(obj, Macro): @@ -555,7 +555,7 @@ class MultiLineMagicChecker(PrefilterChecker): "Allow ! and !! in multi-line statements if multi_line_specials is on" # Note that this one of the only places we check the first character of # ifun and *not* the pre_char. Also note that the below test matches - # both ! and !!. + # both ! and !!. if line_info.continue_prompt \ and self.prefilter_manager.multi_line_specials: if line_info.esc == ESC_MAGIC: @@ -591,7 +591,7 @@ class AssignmentChecker(PrefilterChecker): def check(self, line_info): """Check to see if user is assigning to a var for the first time, in which case we want to avoid any sort of automagic / autocall games. - + This allows users to assign to either alias or magic names true python variables (the magic/alias systems always take second seat to true python code). E.g. ls='hi', or ls,that=1,2""" @@ -669,7 +669,7 @@ class AutocallChecker(PrefilterChecker): oinfo = line_info.ofind(self.shell) # This can mutate state via getattr if not oinfo['found']: return None - + if callable(oinfo['obj']) \ and (not re_exclude_auto.match(line_info.the_rest)) \ and re_fun_name.match(line_info.ifun): @@ -735,7 +735,7 @@ class AliasHandler(PrefilterHandler): # aliases won't work in indented sections. line_out = '%sget_ipython().system(%s)' % (line_info.pre_whitespace, make_quoted_expr(transformed)) - + return line_out @@ -769,7 +769,7 @@ class ShellEscapeHandler(PrefilterHandler): class MacroHandler(PrefilterHandler): handler_name = Unicode("macro") - + def handle(self, line_info): obj = self.shell.user_ns.get(line_info.ifun) pre_space = line_info.pre_whitespace @@ -813,7 +813,7 @@ class AutoHandler(PrefilterHandler): force_auto = isinstance(obj, IPyAutocall) auto_rewrite = getattr(obj, 'rewrite', True) - + if esc == ESC_QUOTE: # Auto-quote splitting on whitespace newcmd = '%s("%s")' % (ifun,'", "'.join(the_rest.split()) ) @@ -848,7 +848,7 @@ class AutoHandler(PrefilterHandler): if auto_rewrite: self.shell.auto_rewrite_input(newcmd) - + return newcmd diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index f56526a..2ae9812 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -107,7 +107,7 @@ class ProfileList(Application): ) )) - ipython_dir = Unicode(get_ipython_dir(), config=True, + ipython_dir = Unicode(get_ipython_dir(), config=True, help=""" The name of the IPython directory. This directory is used for logging configuration (through profiles), history storage, etc. The default @@ -115,7 +115,7 @@ class ProfileList(Application): the environment variable IPYTHON_DIR. """ ) - + def list_profile_dirs(self): # Find the search paths paths = [os.getcwdu(), self.ipython_dir] @@ -129,7 +129,7 @@ class ProfileList(Application): profile = f.split('_',1)[-1] start_cmd = 'ipython profile=%s' % profile print start_cmd + " ==> " + full_path - + def start(self): self.list_profile_dirs() @@ -150,15 +150,15 @@ class ProfileCreate(BaseIPythonApplication): description = create_help examples = _create_examples auto_create = Bool(True, config=False) - + def _copy_config_files_default(self): return True - + parallel = Bool(False, config=True, help="whether to include parallel computing config files") def _parallel_changed(self, name, old, new): - parallel_files = [ 'ipcontroller_config.py', - 'ipengine_config.py', + parallel_files = [ 'ipcontroller_config.py', + 'ipengine_config.py', 'ipcluster_config.py' ] if new: @@ -168,17 +168,17 @@ class ProfileCreate(BaseIPythonApplication): for cf in parallel_files: if cf in self.config_files: self.config_files.remove(cf) - + def parse_command_line(self, argv): super(ProfileCreate, self).parse_command_line(argv) # accept positional arg as profile name if self.extra_args: self.profile = self.extra_args[0] - + flags = Dict(create_flags) - + classes = [ProfileDir] - + def init_config_files(self): super(ProfileCreate, self).init_config_files() # use local imports, since these classes may import from here @@ -223,7 +223,7 @@ class ProfileCreate(BaseIPythonApplication): app.profile = self.profile app.init_profile_dir() app.init_config_files() - + def stage_default_config_file(self): pass @@ -237,7 +237,7 @@ class ProfileApp(Application): create = (ProfileCreate, "Create a new profile dir with default config files"), list = (ProfileList, "List existing profiles") )) - + def start(self): if self.subapp is None: print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()) diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index 2964320..3f2c8d7 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -42,7 +42,7 @@ PromptColors.add_scheme(coloransi.ColorScheme( in_number = InputColors.NoColor, # Input prompt number in_prompt2 = InputColors.NoColor, # Continuation prompt in_normal = InputColors.NoColor, # color off (usu. Colors.Normal) - + out_prompt = Colors.NoColor, # Output prompt out_number = Colors.NoColor, # Output prompt number @@ -255,7 +255,7 @@ class BasePrompt(object): # by all prompt classes through the cache. Nice OO spaghetti code! self.cache = cache self.sep = sep - + # regexp to count the number of spaces at the end of a prompt # expression, useful for prompt auto-rewriting self.rspace = re.compile(r'(\s*)$') @@ -281,7 +281,7 @@ class BasePrompt(object): ('${self.sep}${self.col_p}', multiple_replace(prompt_specials, self.p_template), '${self.col_norm}'),self.cache.shell.user_ns,loc) - + self.p_str_nocolor = ItplNS(multiple_replace(prompt_specials_nocolor, self.p_template), self.cache.shell.user_ns,loc) @@ -369,8 +369,8 @@ class Prompt1(BasePrompt): self.col_norm = Colors.in_normal # We need a non-input version of these escapes for the '--->' # auto-call prompts used in the auto_rewrite() method. - self.col_p_ni = self.col_p.replace('\001','').replace('\002','') - self.col_norm_ni = Colors.normal + self.col_p_ni = self.col_p.replace('\001','').replace('\002','') + self.col_norm_ni = Colors.normal def __str__(self): self.cache.last_prompt = str_safe(self.p_str_nocolor).split('\n')[-1] @@ -405,7 +405,7 @@ class PromptOut(BasePrompt): class Prompt2(BasePrompt): """Interactive continuation prompt.""" - + def __init__(self, cache, prompt=' .\\D.: ', pad_left=True): self.cache = cache self.p_template = prompt diff --git a/IPython/core/release.py b/IPython/core/release.py index 1bb912b..10e9a6d 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -73,13 +73,13 @@ The enhanced interactive Python shells have the following main features: * Easily embeddable in other Python programs and wxPython GUIs. -* Integrated access to the pdb debugger and the Python profiler. +* Integrated access to the pdb debugger and the Python profiler. The parallel computing architecture has the following main features: * Quickly parallelize Python code from an interactive Python/IPython session. -* A flexible and dynamic process model that be deployed on anything from +* A flexible and dynamic process model that be deployed on anything from multicore workstations to supercomputers. * An architecture that supports many different styles of parallelism, from @@ -90,7 +90,7 @@ The parallel computing architecture has the following main features: * High level APIs that enable many things to be parallelized in a few lines of code. -* Share live parallel jobs with other users securely. +* Share live parallel jobs with other users securely. * Dynamically load balanced task farming system. diff --git a/IPython/core/splitinput.py b/IPython/core/splitinput.py index bd04f6a..ca787fc 100644 --- a/IPython/core/splitinput.py +++ b/IPython/core/splitinput.py @@ -37,7 +37,7 @@ from IPython.utils import py3compat # Although it's not solely driven by the regex, note that: # ,;/% only trigger if they are the first character on the line -# ! and !! trigger if they are first char(s) *or* follow an indent +# ! and !! trigger if they are first char(s) *or* follow an indent # ? triggers as first or last char. line_split = re.compile(""" @@ -54,7 +54,7 @@ def split_user_input(line, pattern=None): """ # We need to ensure that the rest of this routine deals only with unicode line = py3compat.cast_unicode(line, sys.stdin.encoding or 'utf-8') - + if pattern is None: pattern = line_split match = pattern.match(line) @@ -77,29 +77,29 @@ def split_user_input(line, pattern=None): class LineInfo(object): """A single line of input and associated info. - Includes the following as properties: + Includes the following as properties: line The original, raw line - + continue_prompt Is this line a continuation in a sequence of multiline input? - + pre Any leading whitespace. - + esc The escape character(s) in pre or the empty string if there isn't one. Note that '!!' and '??' are possible values for esc. Otherwise it will always be a single character. - + ifun The 'function part', which is basically the maximal initial sequence of valid python identifiers and the '.' character. This is what is checked for alias and magic transformations, used for auto-calling, etc. In contrast to Python identifiers, it may start with "%" and contain "*". - + the_rest Everything else on the line. """ @@ -111,7 +111,7 @@ class LineInfo(object): self.pre_char = self.pre.strip() if self.pre_char: self.pre_whitespace = '' # No whitespace allowd before esc chars - else: + else: self.pre_whitespace = self.pre self._oinfo = None @@ -134,5 +134,5 @@ class LineInfo(object): self._oinfo = ip.shell._ofind(self.ifun) return self._oinfo - def __str__(self): - return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest) + def __str__(self): + return "LineInfo [%s|%s|%s|%s]" %(self.pre, self.esc, self.ifun, self.the_rest) diff --git a/IPython/core/tests/test_handlers.py b/IPython/core/tests/test_handlers.py index 54166c2..173b6fe 100644 --- a/IPython/core/tests/test_handlers.py +++ b/IPython/core/tests/test_handlers.py @@ -81,7 +81,7 @@ def test_handlers(): #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache # post-esc-char whitespace goes inside - ("! true", 'get_ipython().system(u" true")'), + ("! true", 'get_ipython().system(u" true")'), # handle_help @@ -111,32 +111,32 @@ def test_handlers(): ('if 1:\n !!true', 'if 1:\n get_ipython().magic(u"sx true")'), # Even with m_l_s on, autocall is off even with special chars - ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'), + ('if 1:\n /fun 1 2', 'if 1:\n /fun 1 2'), ('if 1:\n ;fun 1 2', 'if 1:\n ;fun 1 2'), ('if 1:\n ,fun 1 2', 'if 1:\n ,fun 1 2'), ('if 1:\n ?fun 1 2', 'if 1:\n ?fun 1 2'), - # What about !! + # What about !! ]) # Objects which are instances of IPyAutocall are *always* autocalled autocallable = Autocallable() ip.user_ns['autocallable'] = autocallable - # auto + # auto ip.magic('autocall 0') # Only explicit escapes or instances of IPyAutocallable should get # expanded run([ - ('len "abc"', 'len "abc"'), - ('autocallable', 'autocallable()'), + ('len "abc"', 'len "abc"'), + ('autocallable', 'autocallable()'), (",list 1 2 3", 'list("1", "2", "3")'), - (";list 1 2 3", 'list("1 2 3")'), + (";list 1 2 3", 'list("1 2 3")'), ("/len range(1,4)", 'len(range(1,4))'), ]) ip.magic('autocall 1') run([ (",list 1 2 3", 'list("1", "2", "3")'), - (";list 1 2 3", 'list("1 2 3")'), + (";list 1 2 3", 'list("1 2 3")'), ("/len range(1,4)", 'len(range(1,4))'), ('len "abc"', 'len("abc")'), ('len "abc";', 'len("abc");'), # ; is special -- moves out of parens @@ -150,11 +150,11 @@ def test_handlers(): ip.magic('autocall 2') run([ (",list 1 2 3", 'list("1", "2", "3")'), - (";list 1 2 3", 'list("1 2 3")'), + (";list 1 2 3", 'list("1 2 3")'), ("/len range(1,4)", 'len(range(1,4))'), ('len "abc"', 'len("abc")'), ('len "abc";', 'len("abc");'), - ('len [1,2]', 'len([1,2])'), + ('len [1,2]', 'len([1,2])'), ('call_idx [1]', 'call_idx [1]'), ('call_idx 1', 'call_idx(1)'), # This is what's different: diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index a1f4530..bb73be5 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -31,18 +31,18 @@ def test_history(): hist = ['a=1', 'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"] for i, h in enumerate(hist, start=1): ip.history_manager.store_inputs(i, h) - + ip.history_manager.db_log_output = True # Doesn't match the input, but we'll just check it's stored. ip.history_manager.output_hist_reprs[3] = "spam" ip.history_manager.store_output(3) - + nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist) - - # Check whether specifying a range beyond the end of the current + + # Check whether specifying a range beyond the end of the current # session results in an error (gh-804) ip.magic('%hist 2-500') - + # New session ip.history_manager.reset() newcmds = ["z=5","class X(object):\n pass", "k='p'"] @@ -53,7 +53,7 @@ def test_history(): # Previous session: gothist = ip.history_manager.get_range(-1, 1, 4) nt.assert_equal(list(gothist), zip([1,1,1],[1,2,3], hist)) - + # Check get_hist_tail gothist = ip.history_manager.get_tail(4, output=True, include_latest=True) @@ -62,25 +62,25 @@ def test_history(): (2, 2, (newcmds[1], None)), (2, 3, (newcmds[2], None)),] nt.assert_equal(list(gothist), expected) - + gothist = ip.history_manager.get_tail(2) expected = [(2, 1, newcmds[0]), (2, 2, newcmds[1])] nt.assert_equal(list(gothist), expected) - + # Check get_hist_search gothist = ip.history_manager.search("*test*") nt.assert_equal(list(gothist), [(1,2,hist[1])] ) gothist = ip.history_manager.search("b*", output=True) nt.assert_equal(list(gothist), [(1,3,(hist[2],"spam"))] ) - + # Cross testing: check that magic %save can get previous session. testfilename = os.path.realpath(os.path.join(tmpdir, "test.py")) ip.magic_save(testfilename + " ~1/1-3") testfile = open(testfilename, "r") nt.assert_equal(testfile.read().decode("utf-8"), "# coding: utf-8\n" + "\n".join(hist)) - + # Duplicate line numbers - check that it doesn't crash, and # gets a new session ip.history_manager.store_inputs(1, "rogue") @@ -102,7 +102,7 @@ def test_extract_hist_ranges(): (-7, 1, 6)] actual = list(extract_hist_ranges(instr)) nt.assert_equal(actual, expected) - + def test_magic_rerun(): """Simple test for %rerun (no args -> rerun last line)""" ip = get_ipython() diff --git a/IPython/core/tests/test_inputsplitter.py b/IPython/core/tests/test_inputsplitter.py index 6f211f6..07e98a0 100644 --- a/IPython/core/tests/test_inputsplitter.py +++ b/IPython/core/tests/test_inputsplitter.py @@ -41,7 +41,7 @@ def mini_interactive_loop(input_func): raw_input that simulates interactive input.""" from IPython.core.inputsplitter import InputSplitter - + isp = InputSplitter() # In practice, this input loop would be wrapped in an outside loop to read # input indefinitely, until some exit/quit command was issued. Here we @@ -106,7 +106,7 @@ def test_remove_comments(): 'line \nline\nline\nline \n\n'), ] tt.check_pairs(isp.remove_comments, tests) - + def test_has_comment(): tests = [('text', False), ('text #comment', True), @@ -134,13 +134,13 @@ class NoInputEncodingTestCase(unittest.TestCase): class X: pass fake_stdin = X() sys.stdin = fake_stdin - + def test(self): # Verify that if sys.stdin has no 'encoding' attribute we do the right # thing enc = isp.get_input_encoding() self.assertEqual(enc, 'ascii') - + def tearDown(self): sys.stdin = self.old_stdin @@ -167,7 +167,7 @@ class InputSplitterTestCase(unittest.TestCase): self.assertEqual(self.isp.source_reset(), '1\n2\n') self.assertEqual(self.isp._buffer, []) self.assertEqual(self.isp.source, '') - + def test_indent(self): isp = self.isp # shorthand isp.push('x=1') @@ -200,7 +200,7 @@ class InputSplitterTestCase(unittest.TestCase): isp.push("if 1:") isp.push(" x = (1+\n 2)") self.assertEqual(isp.indent_spaces, 4) - + def test_indent4(self): # In cell mode, inputs must be fed in whole blocks, so skip this test if self.isp.input_mode == 'cell': return @@ -261,13 +261,13 @@ class InputSplitterTestCase(unittest.TestCase): self.assertFalse(isp.push('if 1:')) for line in [' x=1', '# a comment', ' y=2']: self.assertTrue(isp.push(line)) - + def test_push3(self): isp = self.isp isp.push('if True:') isp.push(' a = 1') self.assertFalse(isp.push('b = [1,')) - + def test_replace_mode(self): isp = self.isp isp.input_mode = 'cell' @@ -292,7 +292,7 @@ class InputSplitterTestCase(unittest.TestCase): self.assertTrue(isp.push_accepts_more()) isp.push('') self.assertFalse(isp.push_accepts_more()) - + def test_push_accepts_more3(self): isp = self.isp isp.push("x = (2+\n3)") @@ -318,7 +318,7 @@ class InputSplitterTestCase(unittest.TestCase): self.assertTrue(isp.push_accepts_more()) isp.push('') self.assertFalse(isp.push_accepts_more()) - + def test_push_accepts_more5(self): # In cell mode, inputs must be fed in whole blocks, so skip this test if self.isp.input_mode == 'cell': return @@ -368,7 +368,7 @@ class InteractiveLoopTestCase(unittest.TestCase): # we can check that the given dict is *contained* in test_ns for k,v in ns.iteritems(): self.assertEqual(test_ns[k], v) - + def test_simple(self): self.check_ns(['x=1'], dict(x=1)) @@ -380,10 +380,10 @@ class InteractiveLoopTestCase(unittest.TestCase): def test_abc(self): self.check_ns(['if 1:','a=1','b=2','c=3'], dict(a=1, b=2, c=3)) - + def test_multi(self): self.check_ns(['x =(1+','1+','2)'], dict(x=4)) - + def test_LineInfo(): """Simple test for LineInfo construction and str()""" @@ -453,7 +453,7 @@ syntax = \ ('?%hist', 'get_ipython().magic(u"pinfo %hist")'), ('?abc = qwe', 'get_ipython().magic(u"pinfo abc")'), ], - + end_help = [ ('x3?', 'get_ipython().magic(u"pinfo x3")'), ('x4??', 'get_ipython().magic(u"pinfo2 x4")'), @@ -473,7 +473,7 @@ syntax = \ ('%cd /home', 'get_ipython().magic(u"cd /home")'), (' %magic', ' get_ipython().magic(u"magic")'), ], - + # Quoting with separate arguments escaped_quote = [ (',f', 'f("")'), @@ -481,23 +481,23 @@ syntax = \ (' ,f y', ' f("y")'), (',f a b', 'f("a", "b")'), ], - + # Quoting with single argument - escaped_quote2 = + escaped_quote2 = [ (';f', 'f("")'), (';f x', 'f("x")'), (' ;f y', ' f("y")'), (';f a b', 'f("a b")'), ], - + # Simply apply parens - escaped_paren = + escaped_paren = [ ('/f', 'f()'), ('/f x', 'f(x)'), (' /f y', ' f(y)'), ('/f a b', 'f(a, b)'), ], - + # Check that we transform prompts before other transforms mixed = [ ('In [1]: %lsmagic', 'get_ipython().magic(u"lsmagic")'), @@ -532,7 +532,7 @@ syntax_ml = \ def test_assign_system(): tt.check_pairs(isp.transform_assign_system, syntax['assign_system']) - + def test_assign_magic(): tt.check_pairs(isp.transform_assign_magic, syntax['assign_magic']) @@ -541,7 +541,7 @@ def test_classic_prompt(): transform_checker(syntax['classic_prompt'], isp.transform_classic_prompt) for example in syntax_ml['classic_prompt']: transform_checker(example, isp.transform_classic_prompt) - + def test_ipy_prompt(): transform_checker(syntax['ipy_prompt'], isp.transform_ipy_prompt) @@ -599,7 +599,7 @@ class IPythonInputTestCase(InputSplitterTestCase): for raw, out_t in example: if raw.startswith(' '): continue - + isp.push(raw) out, out_raw = isp.source_raw_reset() self.assertEqual(out.rstrip(), out_t, @@ -622,13 +622,13 @@ class IPythonInputTestCase(InputSplitterTestCase): raw = '\n'.join(raw_parts).rstrip() self.assertEqual(out.rstrip(), out_t) self.assertEqual(out_raw.rstrip(), raw) - + class BlockIPythonInputTestCase(IPythonInputTestCase): # Deactivate tests that don't make sense for the block mode test_push3 = test_split = lambda s: None - + def setUp(self): self.isp = isp.IPythonInputSplitter(input_mode='cell') @@ -650,7 +650,7 @@ class BlockIPythonInputTestCase(IPythonInputTestCase): # Match ignoring trailing whitespace self.assertEqual(out.rstrip(), out_t.rstrip()) self.assertEqual(out_raw.rstrip(), raw.rstrip()) - + #----------------------------------------------------------------------------- # Main - use as a script, mostly for developer experiments @@ -667,7 +667,7 @@ if __name__ == '__main__': autoindent = True #autoindent = False - + try: while True: prompt = start_prompt diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index 913551c..e1a816d 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -45,7 +45,7 @@ class Call(object): def method(self, x, z=2): """Some method's docstring""" - + class OldStyle: """An old-style class for testing.""" pass @@ -62,7 +62,7 @@ def check_calltip(obj, name, call, docstring): info = inspector.info(obj, name) call_line, ds = oinspect.call_tip(info) nt.assert_equal(call_line, call) - nt.assert_equal(ds, docstring) + nt.assert_equal(ds, docstring) #----------------------------------------------------------------------------- # Tests @@ -92,7 +92,7 @@ def test_calltip_function2(): def test_calltip_builtin(): check_calltip(sum, 'sum', None, sum.__doc__) - + def test_info(): "Check that Inspector.info fills out various fields as expected." i = inspector.info(Call, oname='Call') @@ -112,11 +112,11 @@ def test_info(): nt.assert_true(i['isclass']) nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n") nt.assert_equal(i['init_docstring'], Call.__init__.__doc__) - + i = inspector.info(Call, detail_level=1) nt.assert_not_equal(i['source'], None) nt.assert_equal(i['docstring'], None) - + c = Call(1) c.__doc__ = "Modified instance docstring" i = inspector.info(c) @@ -125,12 +125,12 @@ def test_info(): nt.assert_equal(i['class_docstring'], Call.__doc__) nt.assert_equal(i['init_docstring'], Call.__init__.__doc__) nt.assert_equal(i['call_docstring'], c.__call__.__doc__) - + # Test old-style classes, which for example may not have an __init__ method. if not py3compat.PY3: i = inspector.info(OldStyle) nt.assert_equal(i['type_name'], 'classobj') - + i = inspector.info(OldStyle()) nt.assert_equal(i['type_name'], 'instance') nt.assert_equal(i['docstring'], OldStyle.__doc__) diff --git a/IPython/core/tests/test_run.py b/IPython/core/tests/test_run.py index 0cbe76b..3077bc4 100644 --- a/IPython/core/tests/test_run.py +++ b/IPython/core/tests/test_run.py @@ -32,7 +32,7 @@ def doctest_refbug(): In [1]: _ip.clear_main_mod_cache() # random - + In [2]: %run refbug In [3]: call_f() @@ -81,7 +81,7 @@ def doctest_run_builtins(): ....: os.unlink(fname) ....: except: ....: pass - ....: + ....: """ def doctest_reset_del(): @@ -90,7 +90,7 @@ def doctest_reset_del(): In [2]: class A(object): ...: def __del__(self): ...: print str("Hi") - ...: + ...: In [3]: a = A() @@ -127,7 +127,7 @@ class TestMagicRunPass(tt.TempFileMixin): def test_builtins_type(self): """Check that the type of __builtins__ doesn't change with %run. - + However, the above could pass if __builtins__ was already modified to be a dict (it should be a module) by a previous use of %run. So we also check explicitly that it really is a module: @@ -168,8 +168,8 @@ class TestMagicRunSimple(tt.TempFileMixin): "a = A()\n") self.mktmp(src) tt.ipexec_validate(self.fname, 'object A deleted') - - @dec.skip_known_failure + + @dec.skip_known_failure def test_aggressive_namespace_cleanup(self): """Test that namespace cleanup is not too aggressive GH-238 diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 2669c91..59da025 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -12,7 +12,7 @@ Installation instructions for ColorTB: import sys,ultratb sys.excepthook = ultratb.ColorTB() -* VerboseTB +* VerboseTB I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds of useful info when a traceback occurs. Ping originally had it spit out HTML and intended it for CGI programmers, but why should they have all the fun? I @@ -34,7 +34,7 @@ Note: Verbose_novars mode instead of the regular Verbose, which avoids formatting variables (but otherwise includes the information and context given by Verbose). - + Installation instructions for ColorTB: import sys,ultratb @@ -121,7 +121,7 @@ def inspect_error(): """Print a message about internal inspect errors. These are unfortunately quite common.""" - + error('Internal Python error in the inspect module.\n' 'Below is the traceback from this internal error.\n') @@ -197,7 +197,7 @@ def findsource(object): while lnum > 0: if pmatch(lines[lnum]): break lnum -= 1 - + return lines, lnum raise IOError('could not find code object') @@ -262,7 +262,7 @@ def _fixed_getinnerframes(etb, context=1,tb_offset=0): # (SyntaxErrors have to be treated specially because they have no traceback) _parser = PyColorize.Parser() - + def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None): numbers_width = INDENT_SIZE - 1 res = [] @@ -285,10 +285,10 @@ def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None): # is unicode-safe. So for now this is rather an ugly hack, but # necessary to at least have readable tracebacks. Improvements welcome! line = py3compat.cast_bytes_py2(line, 'utf-8') - + new_line, err = _line_format(line, 'str', scheme) if not err: line = new_line - + if i == lnum: # This is the line with the error pad = numbers_width - len(str(i)) @@ -301,11 +301,11 @@ def _format_traceback_lines(lnum, index, lines, Colors, lvals=None,scheme=None): else: marker = '' num = marker + str(i) - line = '%s%s%s %s%s' %(Colors.linenoEm, num, + line = '%s%s%s %s%s' %(Colors.linenoEm, num, Colors.line, line, Colors.Normal) else: num = '%*s' % (numbers_width,i) - line = '%s%s%s %s' %(Colors.lineno, num, + line = '%s%s%s %s' %(Colors.lineno, num, Colors.Normal, line) res.append(line) @@ -352,7 +352,7 @@ class TBTools(object): """Output stream that exceptions are written to. Valid values are: - + - None: the default, which means that IPython will dynamically resolve to io.stdout. This ensures compatibility with most tools, including Windows (where plain stdout doesn't recognize ANSI escapes). @@ -364,7 +364,7 @@ class TBTools(object): def _set_ostream(self, val): assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush')) self._ostream = val - + ostream = property(_get_ostream, _set_ostream) def set_colors(self,*args,**kw): @@ -380,7 +380,7 @@ class TBTools(object): def color_toggle(self): """Toggle between the currently active color scheme and NoColor.""" - + if self.color_scheme_table.active_scheme_name == 'NoColor': self.color_scheme_table.set_active_scheme(self.old_scheme) self.Colors = self.color_scheme_table.active_colors @@ -414,7 +414,7 @@ class TBTools(object): #--------------------------------------------------------------------------- class ListTB(TBTools): """Print traceback information from a traceback list, with optional color. - + Calling: requires 3 arguments: (etype, evalue, elist) as would be obtained by: @@ -434,7 +434,7 @@ class ListTB(TBTools): def __init__(self,color_scheme = 'NoColor', call_pdb=False, ostream=None): TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb, ostream=ostream) - + def __call__(self, etype, value, elist): self.ostream.flush() self.ostream.write(self.text(etype, value, elist)) @@ -458,7 +458,7 @@ class ListTB(TBTools): tb_offset : int, optional Number of frames in the traceback to skip. If not given, the instance value is used (set in constructor). - + context : int, optional Number of lines of context information to print. @@ -473,7 +473,7 @@ class ListTB(TBTools): if tb_offset and len(elist) > tb_offset: elist = elist[tb_offset:] - + out_list.append('Traceback %s(most recent call last)%s:' % (Colors.normalEm, Colors.Normal) + '\n') out_list.extend(self._format_list(elist)) @@ -482,7 +482,7 @@ class ListTB(TBTools): out_list.append(lines) # Note: this code originally read: - + ## for line in lines[:-1]: ## out_list.append(" "+line) ## out_list.append(lines[-1]) @@ -490,7 +490,7 @@ class ListTB(TBTools): # This means it was indenting everything but the last line by a little # bit. I've disabled this for now, but if we see ugliness somewhre we # can restore it. - + return out_list def _format_list(self, extracted_list): @@ -502,7 +502,7 @@ class ListTB(TBTools): same index in the argument list. Each string ends in a newline; the strings may contain internal newlines as well, for those items whose source text line is not None. - + Lifted almost verbatim from traceback.py """ @@ -510,7 +510,7 @@ class ListTB(TBTools): list = [] for filename, lineno, name, line in extracted_list[:-1]: item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \ - (Colors.filename, filename, Colors.Normal, + (Colors.filename, filename, Colors.Normal, Colors.lineno, lineno, Colors.Normal, Colors.name, name, Colors.Normal) if line: @@ -530,7 +530,7 @@ class ListTB(TBTools): list.append(item) #from pprint import pformat; print 'LISTTB', pformat(list) # dbg return list - + def _format_exception_only(self, etype, value): """Format the exception part of a traceback. @@ -541,7 +541,7 @@ class ListTB(TBTools): printed) display detailed information about where the syntax error occurred. The message indicating which exception occurred is the always last string in the list. - + Also lifted nearly verbatim from traceback.py """ @@ -573,7 +573,7 @@ class ListTB(TBTools): while i < len(line) and line[i].isspace(): i = i+1 list.append('%s %s%s\n' % (Colors.line, - line.strip(), + line.strip(), Colors.Normal)) if offset is not None: s = ' ' @@ -602,7 +602,7 @@ class ListTB(TBTools): def get_exception_only(self, etype, value): """Only print the exception type and message, without a traceback. - + Parameters ---------- etype : exception type @@ -613,7 +613,7 @@ class ListTB(TBTools): def show_exception_only(self, etype, evalue): """Only print the exception type and message, without a traceback. - + Parameters ---------- etype : exception type @@ -725,7 +725,7 @@ class VerboseTB(TBTools): # Header with the exception type, python version, and date pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable date = time.ctime(time.time()) - + head = '%s%s%s\n%s%s%s\n%s' % (Colors.topline, '-'*75, ColorsNormal, exc, ' '*(75-len(str(etype))-len(pyver)), pyver, date.rjust(75) ) @@ -797,7 +797,7 @@ class VerboseTB(TBTools): inspect_error() traceback.print_exc(file=self.ostream) info("\nIPython's exception reporting continues...\n") - + if func == '?': call = '' else: @@ -838,7 +838,7 @@ class VerboseTB(TBTools): there is no way to disambguate partial dotted structures until the full list is known. The caller is responsible for pruning the final list of duplicates before using it.""" - + # build composite names if token == '.': try: @@ -887,7 +887,7 @@ class VerboseTB(TBTools): "The following traceback may be corrupted or invalid\n" "The error message is: %s\n" % msg) error(_m) - + # prune names list of duplicates, but keep the right order unique_names = uniq_stable(names) @@ -965,11 +965,11 @@ class VerboseTB(TBTools): if ipinst is not None: ipinst.hooks.synchronize_with_editor(filepath, lnum, 0) # vds: << - + # return all our info assembled as a single string # return '%s\n\n%s\n%s' % (head,'\n'.join(frames),''.join(exception[0]) ) return [head] + frames + [''.join(exception[0])] - + def debugger(self,force=False): """Call up the pdb debugger if desired, always clean up the tb reference. @@ -1048,9 +1048,9 @@ class FormattedTB(VerboseTB, ListTB): one needs to remove a number of topmost frames from the traceback (such as occurs with python programs that themselves execute other python code, like Python shells). """ - + def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False, - ostream=None, + ostream=None, tb_offset=0, long_header=False, include_vars=False, check_cache=None): @@ -1068,7 +1068,7 @@ class FormattedTB(VerboseTB, ListTB): self._join_chars = dict(Plain='', Context='\n', Verbose='\n') # set_mode also sets the tb_join_char attribute self.set_mode(mode) - + def _extract_tb(self,tb): if tb: return traceback.extract_tb(tb) @@ -1096,7 +1096,7 @@ class FormattedTB(VerboseTB, ListTB): def stb2text(self, stb): """Convert a structured traceback (a list) to a string.""" return self.tb_join_char.join(stb) - + def set_mode(self,mode=None): """Switch to the desired mode. @@ -1134,14 +1134,14 @@ class AutoFormattedTB(FormattedTB): It will find out about exceptions by itself. A brief example: - + AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux') try: ... except: AutoTB() # or AutoTB(out=logfile) where logfile is an open file object """ - + def __call__(self,etype=None,evalue=None,etb=None, out=None,tb_offset=None): """Print out a formatted exception traceback. @@ -1153,7 +1153,7 @@ class AutoFormattedTB(FormattedTB): per-call basis (this overrides temporarily the instance's tb_offset given at initialization time. """ - + if out is None: out = self.ostream out.flush() @@ -1230,7 +1230,7 @@ if __name__ == "__main__": except: traceback.print_exc() print '' - + handler = ColorTB() print '*** ColorTB ***' try: @@ -1238,7 +1238,7 @@ if __name__ == "__main__": except: apply(handler, sys.exc_info() ) print '' - + handler = VerboseTB() print '*** VerboseTB ***' try: @@ -1246,4 +1246,4 @@ if __name__ == "__main__": except: apply(handler, sys.exc_info() ) print '' - + diff --git a/IPython/core/usage.py b/IPython/core/usage.py index b11181c..4dfee1b 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -36,7 +36,7 @@ Usage Almost all configuration in IPython is available via the command-line. Do `ipython --help-all` to see all available options. For persistent - configuration, look into your `ipython_config.py` configuration file for + configuration, look into your `ipython_config.py` configuration file for details. This file is typically installed in the `IPYTHON_DIR` directory, and there @@ -45,11 +45,11 @@ Usage IPYTHON_DIR defaults to `$HOME/.config/ipython`, and for other Unix systems to `$HOME/.ipython`. For Windows users, $HOME resolves to C:\\Documents and Settings\\YourUserName in most instances. - + To initialize a profile with the default configuration file, do:: - + $> ipython profile create - + and start editing `IPYTHON_DIR/profile_default/ipython_config.py` In IPython's documentation, we will refer to this directory as @@ -129,7 +129,7 @@ MAIN FEATURES * Persistent command history across sessions. * Logging of input with the ability to save and restore a working session. - + * System escape with !. Typing !ls will run 'ls' in the current directory. * The reload command does a 'deep' reload of a module: changes made to the @@ -201,7 +201,7 @@ MAIN FEATURES Note that the '/' MUST be the first character on the line! This won't work: >>> print /globals # syntax error - + In most cases the automatic algorithm should work, so you should rarely need to explicitly invoke /. One notable exception is if you are trying to call a function with a list of tuples as arguments (the @@ -210,12 +210,12 @@ MAIN FEATURES but this will work: In [2]: /zip (1,2,3),(4,5,6) ------> zip ((1,2,3),(4,5,6)) - Out[2]= [(1, 4), (2, 5), (3, 6)] + Out[2]= [(1, 4), (2, 5), (3, 6)] IPython tells you that it has altered your command line by displaying the new command line preceded by -->. e.g.: In [18]: callable list - -------> callable (list) + -------> callable (list) 2. Auto-Quoting You can force auto-quoting of a function's arguments by using ',' as @@ -255,7 +255,7 @@ obj?, obj?? : Get help, or more help for object (also works as Magic functions are prefixed by %, and typically take their arguments without parentheses, quotes or even commas for convenience. - + Example magic function calls: %alias d ls -F : 'd' is now an alias for 'ls -F' @@ -265,7 +265,7 @@ cd /usr/share : Obvious. cd - to choose from visited dirs. %cd?? : See help AND source for magic %cd System commands: - + !cp a.txt b/ : System command escape, calls os.system() cp a.txt b/ : after %rehashx, most system commands work without ! cp ${f}.txt $bar : Variable expansion in magics and system commands @@ -277,7 +277,7 @@ History: _i, _ii, _iii : Previous, next previous, next next previous input _i4, _ih[2:5] : Input history line 4, lines 2-4 exec _i81 : Execute input history line #81 again -%rep 81 : Edit input history line #81 +%rep 81 : Edit input history line #81 _, __, ___ : previous, next previous, next next previous output _dh : Directory history _oh : Output history @@ -327,10 +327,10 @@ blocks are evaluated once a single blank line is entered:: In [1]: print "Hello IPython!" # Enter was pressed at the end of the line Hello IPython! - + In [2]: for i in range(10): ...: print i, - ...: + ...: 0 1 2 3 4 5 6 7 8 9 If you want to enter more than one expression in a single input block @@ -348,7 +348,7 @@ cell is executed as if it was a script. An example should clarify this:: ...: z=3 ...: x**2 # This does *not* produce an Out[] value ...: x+y+z # Only the last expression does - ...: + ...: Out[3]: 6 The behavior where an extra blank line forces execution is only active if you diff --git a/IPython/deathrow/Gnuplot2.py b/IPython/deathrow/Gnuplot2.py index e085ccc..b75fe20 100644 --- a/IPython/deathrow/Gnuplot2.py +++ b/IPython/deathrow/Gnuplot2.py @@ -150,13 +150,13 @@ def zip_items(items,titles=None): with their index. Leave other plot items alone.""" class StandaloneItem(Exception): pass - + def get_titles(titles): """Return the next title and the input titles array. The input array may be changed to None when no titles are left to prevent extra unnecessary calls to this function.""" - + try: title = titles[tit_ct[0]] # tit_ct[0] is in zip_items'scope except IndexError: @@ -258,33 +258,33 @@ class Gnuplot(Gnuplot_ori.Gnuplot): explicit '' argument must be given as the limit to be kept. Similar functions exist for [y{2}z{2}rtuv]range.""" - + self('set xrange [%s:%s]' % (min,max)) - + def yrange(self,min='*',max='*'): self('set yrange [%s:%s]' % (min,max)) - + def zrange(self,min='*',max='*'): self('set zrange [%s:%s]' % (min,max)) - + def x2range(self,min='*',max='*'): self('set xrange [%s:%s]' % (min,max)) - + def y2range(self,min='*',max='*'): self('set yrange [%s:%s]' % (min,max)) - + def z2range(self,min='*',max='*'): self('set zrange [%s:%s]' % (min,max)) - + def rrange(self,min='*',max='*'): self('set rrange [%s:%s]' % (min,max)) - + def trange(self,min='*',max='*'): self('set trange [%s:%s]' % (min,max)) - + def urange(self,min='*',max='*'): self('set urange [%s:%s]' % (min,max)) - + def vrange(self,min='*',max='*'): self('set vrange [%s:%s]' % (min,max)) @@ -319,7 +319,7 @@ class Gnuplot(Gnuplot_ori.Gnuplot): # Filter out other options the original plot doesn't know hardcopy = popkey(keyw,'hardcopy',psargs['filename'] is not None) titles = popkey(keyw,'titles',0) - + # the filename keyword should control hardcopy generation, this is an # override switch only which needs to be explicitly set to zero if hardcopy: @@ -410,7 +410,7 @@ class Gnuplot(Gnuplot_ori.Gnuplot): - filename: a string, typically ending in .eps. If given, the plot is sent to this file in PostScript format. - + - hardcopy: this can be set to 0 to override 'filename'. It does not need to be given to produce PostScript, its purpose is to allow switching PostScript output off globally in scripts without having to @@ -421,7 +421,7 @@ class Gnuplot(Gnuplot_ori.Gnuplot): PostScript. For example: - + In [1]: x=frange(0,2*pi,npts=100) Generate a plot in file 'sin.eps': @@ -439,16 +439,16 @@ class Gnuplot(Gnuplot_ori.Gnuplot): PostScript generation through plot() is useful mainly for scripting uses where you are not interested in interactive plotting. For interactive use, the hardcopy() function is typically more convenient: - + In [5]: plot(x,sin(x)) In [6]: hardcopy('sin.eps') """ - + self.__plot_ps(Gnuplot_ori.Gnuplot.plot,*items,**keyw) - + def plot2(self,arg,**kw): - """Plot the entries of a dictionary or a list/tuple of arrays. - + """Plot the entries of a dictionary or a list/tuple of arrays. + This simple utility calls plot() with a list of Gnuplot.Data objects constructed either from the values of the input dictionary, or the entries in it if it is a tuple or list. Each item gets labeled with the key/index @@ -493,7 +493,7 @@ class Gnuplot(Gnuplot_ori.Gnuplot): Gnuplot.py, this version has several enhancements, listed in the plot() documentation. """ - + self.__plot_ps(Gnuplot_ori.Gnuplot.splot,*items,**keyw) def replot(self, *items, **keyw): @@ -508,7 +508,7 @@ class Gnuplot(Gnuplot_ori.Gnuplot): 'filename' keyword argument in each call to replot. The Gnuplot python interface has no way of knowing that your previous call to Gnuplot.plot() was meant for PostScript output.""" - + self.__plot_ps(Gnuplot_ori.Gnuplot.replot,*items,**keyw) # The original hardcopy has a bug. See fix at the end. The rest of the code diff --git a/IPython/deathrow/gui/wx/ipshell_nonblocking.py b/IPython/deathrow/gui/wx/ipshell_nonblocking.py index 8644ade..5a152fc 100755 --- a/IPython/deathrow/gui/wx/ipshell_nonblocking.py +++ b/IPython/deathrow/gui/wx/ipshell_nonblocking.py @@ -38,13 +38,13 @@ class _Helper(object): def __repr__(self): return "Type help() for interactive help, " \ "or help(object) for help about object." - + def __call__(self, *args, **kwds): class DummyWriter(object): - '''Dumy class to handle help output''' + '''Dumy class to handle help output''' def __init__(self, pager): self._pager = pager - + def write(self, data): '''hook to fill self._pager''' self._pager(data) @@ -52,17 +52,17 @@ class _Helper(object): import pydoc pydoc.help.output = DummyWriter(self._pager) pydoc.help.interact = lambda :1 - + return pydoc.help(*args, **kwds) - + ############################################################################## class _CodeExecutor(ThreadEx): ''' Thread that execute ipython code ''' def __init__(self, instance): ThreadEx.__init__(self) self.instance = instance - + def run(self): '''Thread main loop''' try: @@ -70,17 +70,17 @@ class _CodeExecutor(ThreadEx): self.instance._help_text = None self.instance._execute() # used for uper class to generate event after execution - self.instance._after_execute() - + self.instance._after_execute() + except KeyboardInterrupt: pass - + ############################################################################## class NonBlockingIPShell(object): ''' Create an IPython instance, running the commands in a separate, - non-blocking thread. + non-blocking thread. This allows embedding in any GUI without blockage. Note: The ThreadEx class supports asynchroneous function call @@ -111,7 +111,7 @@ class NonBlockingIPShell(object): self.init_ipython0(user_ns, user_global_ns, cin, cout, cerr, ask_exit_handler) - + #vars used by _execute self._iter_more = 0 self._history_level = 0 @@ -121,7 +121,7 @@ class NonBlockingIPShell(object): #thread working vars self._line_to_execute = '' self._threading = True - + #vars that will be checked by GUI loop to handle thread states... #will be replaced later by PostEvent GUI funtions... self._doc_text = None @@ -132,7 +132,7 @@ class NonBlockingIPShell(object): cin=None, cout=None, cerr=None, ask_exit_handler=None): ''' Initialize an ipython0 instance ''' - + #first we redefine in/out/error functions of IPython #BUG: we've got a limitation form ipython0 there #only one instance can be instanciated else tehre will be @@ -143,7 +143,7 @@ class NonBlockingIPShell(object): Term.cout = cout if cerr: Term.cerr = cerr - + excepthook = sys.excepthook #Hack to save sys.displayhook, because ipython seems to overwrite it... @@ -165,11 +165,11 @@ class NonBlockingIPShell(object): self._IP.stdin_encoding = loc #we replace the ipython default pager by our pager self._IP.set_hook('show_in_pager', self._pager) - - #we replace the ipython default shell command caller + + #we replace the ipython default shell command caller #by our shell handler self._IP.set_hook('shell_hook', self._shell) - + #we replace the ipython default input command caller by our method iplib.raw_input_original = self._raw_input_original #we replace the ipython default exit command by our method @@ -184,10 +184,10 @@ class NonBlockingIPShell(object): import __builtin__ __builtin__.raw_input = self._raw_input - + sys.excepthook = excepthook - #----------------------- Thread management section ---------------------- + #----------------------- Thread management section ---------------------- def do_execute(self, line): """ Tell the thread to process the 'line' command @@ -196,8 +196,8 @@ class NonBlockingIPShell(object): self._line_to_execute = line if self._threading: - #we launch the ipython line execution in a thread to make it - #interruptible with include it in self namespace to be able + #we launch the ipython line execution in a thread to make it + #interruptible with include it in self namespace to be able #to call ce.raise_exc(KeyboardInterrupt) self.ce = _CodeExecutor(self) self.ce.start() @@ -207,8 +207,8 @@ class NonBlockingIPShell(object): self._help_text = None self._execute() # used for uper class to generate event after execution - self._after_execute() - + self._after_execute() + except KeyboardInterrupt: pass @@ -225,7 +225,7 @@ class NonBlockingIPShell(object): @rtype: bool """ return self._threading - + def set_threading(self, state): """ Sets threading state, if set to True, then each command sent to @@ -247,7 +247,7 @@ class NonBlockingIPShell(object): @rtype: string """ return self._doc_text - + def get_help_text(self): """ Returns the output of the processing that need to be paged via help pager(if any) @@ -265,7 +265,7 @@ class NonBlockingIPShell(object): @rtype: string """ return self._IP.banner - + def get_prompt_count(self): """ Returns the prompt number. @@ -295,7 +295,7 @@ class NonBlockingIPShell(object): @rtype: int """ return self._IP.indent_current_nsp - + def update_namespace(self, ns_dict): ''' Add the current dictionary to the shell namespace. @@ -354,7 +354,7 @@ class NonBlockingIPShell(object): while((history == '' or history == '\n') and self._history_level >0): if self._history_level >= 1: self._history_level -= 1 - history = self._get_history() + history = self._get_history() return history def history_forward(self): @@ -406,7 +406,7 @@ class NonBlockingIPShell(object): @rtype: int ''' return len(self._IP.input_hist_raw)-1 - + def _get_history(self): ''' Get's the command string of the current history level. @@ -428,7 +428,7 @@ class NonBlockingIPShell(object): self._help_text = text else: self._help_text += text - + def _pager(self, IP, text): ''' This function is used as a callback replacment to IPython pager function @@ -437,7 +437,7 @@ class NonBlockingIPShell(object): get_doc_text function. ''' self._doc_text = text - + def _raw_input_original(self, prompt=''): ''' Custom raw_input() replacement. Get's current line from console buffer. @@ -454,7 +454,7 @@ class NonBlockingIPShell(object): """ A replacement from python's raw_input. """ raise NotImplementedError - + def _execute(self): ''' Executes the current line provided by the shell object. @@ -464,7 +464,7 @@ class NonBlockingIPShell(object): sys.stdout = Term.cout #self.sys_displayhook_ori = sys.displayhook #sys.displayhook = self.displayhook - + try: line = self._IP.raw_input(None, self._iter_more) if self._IP.autoindent: @@ -497,7 +497,7 @@ class NonBlockingIPShell(object): sys.stdout = orig_stdout #sys.displayhook = self.sys_displayhook_ori - + def _shell(self, ip, cmd): ''' Replacement method to allow shell commands without them blocking. diff --git a/IPython/deathrow/gui/wx/ipython_history.py b/IPython/deathrow/gui/wx/ipython_history.py index 2e88ef0..7d8c0be 100644 --- a/IPython/deathrow/gui/wx/ipython_history.py +++ b/IPython/deathrow/gui/wx/ipython_history.py @@ -16,12 +16,12 @@ class IPythonHistoryPanel(wx.Panel): def __init__(self, parent,flt_empty=True, flt_doc=True,flt_cmd=True,flt_magic=True): - + wx.Panel.__init__(self,parent,-1) #text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE) text_ctrl = PythonSTC(self, -1) - - + + st_filt = wx.StaticText(self, -1, " Filter:") self.filter_empty = wx.CheckBox(self, -1, "Empty commands") @@ -52,12 +52,12 @@ class IPythonHistoryPanel(wx.Panel): self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter) self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter) self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter) - + #self.filter_empty.SetValue(flt_empty) #self.filter_doc.SetValue(flt_doc) #self.filter_cmd.SetValue(flt_cmd) #self.filter_magic.SetValue(flt_magic) - + sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(text_ctrl, 1, wx.EXPAND) @@ -83,7 +83,7 @@ class IPythonHistoryPanel(wx.Panel): text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER) text_ctrl.SetMarginWidth(1, 15) - + def write(self,history_line): add = True if self.filter_empty.GetValue() == True and history_line == '': @@ -106,10 +106,10 @@ class IPythonHistoryPanel(wx.Panel): self.options[name]['value']='False' self.updateOptionTracker(name, self.options[name]['value']) - + def evtCheckEmptyFilter(self, event): self.processOptionCheckedEvt(event, 'filter_empty') - + def evtCheckDocFilter(self, event): self.processOptionCheckedEvt(event, 'filter_doc') @@ -118,10 +118,10 @@ class IPythonHistoryPanel(wx.Panel): def evtCheckMagicFilter(self, event): self.processOptionCheckedEvt(event, 'filter_magic') - + def getOptions(self): return self.options - + def reloadOptions(self,options): self.options = options for key in self.options.keys(): @@ -135,14 +135,14 @@ class IPythonHistoryPanel(wx.Panel): Default history tracker (does nothing) ''' pass - + def setOptionTrackerHook(self,func): ''' Define a new history tracker ''' self.updateOptionTracker = func - + #---------------------------------------------------------------------- # Font definition for Styled Text Control @@ -177,7 +177,7 @@ else: class PythonSTC(stc.StyledTextCtrl): fold_symbols = 3 - + def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): @@ -197,14 +197,14 @@ class PythonSTC(stc.StyledTextCtrl): #self.SetViewEOL(True) self.SetEOLMode(stc.STC_EOL_CRLF) #self.SetUseAntiAliasing(True) - + self.SetEdgeMode(stc.STC_EDGE_LINE) self.SetEdgeColumn(80) self.SetEdgeColour(wx.LIGHT_GREY) self.SetLayoutCache(stc.STC_CACHE_PAGE) # Setup a margin to hold fold markers - #self.SetFoldFlags(16) + #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER? self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) self.SetMarginMask(2, stc.STC_MASK_FOLDERS) @@ -212,7 +212,7 @@ class PythonSTC(stc.StyledTextCtrl): self.SetMarginWidth(2, 12) if self.fold_symbols == 0: - # Arrow pointing right for contracted folders, + # Arrow pointing right for contracted folders, # arrow pointing down for expanded self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \ stc.STC_MARK_ARROWDOWN, "black", "black") @@ -228,7 +228,7 @@ class PythonSTC(stc.StyledTextCtrl): stc.STC_MARK_EMPTY, "white", "black") self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \ stc.STC_MARK_EMPTY, "white", "black") - + elif self.fold_symbols == 1: # Plus for contracted folders, minus for expanded self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \ @@ -301,7 +301,7 @@ class PythonSTC(stc.StyledTextCtrl): self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") # Python styles - # Default + # Default self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces) # Comments self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces) @@ -335,9 +335,9 @@ class PythonSTC(stc.StyledTextCtrl): # register some images for use in the AutoComplete box. #self.RegisterImage(1, images.getSmilesBitmap()) - #self.RegisterImage(2, + #self.RegisterImage(2, # wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) - #self.RegisterImage(3, + #self.RegisterImage(3, # wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) @@ -365,7 +365,7 @@ class PythonSTC(stc.StyledTextCtrl): #self.AutoCompShow(0, st) kw = keyword.kwlist[:] - + kw.sort() # Python sorts are case sensitive self.AutoCompSetIgnoreCase(False) # so this needs to match @@ -398,7 +398,7 @@ class PythonSTC(stc.StyledTextCtrl): if braceAtCaret < 0: charAfter = self.GetCharAt(caretPos) styleAfter = self.GetStyleAt(caretPos) - + if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR: braceAtCaret = caretPos diff --git a/IPython/deathrow/gui/wx/ipython_view.py b/IPython/deathrow/gui/wx/ipython_view.py index 2fc44c3..f1a234a 100644 --- a/IPython/deathrow/gui/wx/ipython_view.py +++ b/IPython/deathrow/gui/wx/ipython_view.py @@ -53,11 +53,11 @@ class WxNonBlockingIPShell(NonBlockingIPShell): ''' An NonBlockingIPShell Thread that is WX dependent. ''' - def __init__(self, parent, + def __init__(self, parent, argv=[],user_ns={},user_global_ns=None, cin=None, cout=None, cerr=None, ask_exit_handler=None): - + NonBlockingIPShell.__init__(self, argv, user_ns, user_global_ns, cin, cout, cerr, ask_exit_handler) @@ -68,22 +68,22 @@ class WxNonBlockingIPShell(NonBlockingIPShell): self._IP.exit = self._ask_exit def addGUIShortcut(self, text, func): - wx.CallAfter(self.parent.add_button_handler, - button_info={ 'text':text, + wx.CallAfter(self.parent.add_button_handler, + button_info={ 'text':text, 'func':self.parent.doExecuteLine(func)}) def _raw_input(self, prompt=''): """ A replacement from python's raw_input. """ self.answer = None - if(self._threading == True): + if(self._threading == True): wx.CallAfter(self._yesNoBox, prompt) while self.answer is None: time.sleep(.1) else: self._yesNoBox(prompt) return self.answer - + def _yesNoBox(self, prompt): """ yes/no box managed with wx.CallAfter jsut in case caler is executed in a thread""" dlg = wx.TextEntryDialog( @@ -94,21 +94,21 @@ class WxNonBlockingIPShell(NonBlockingIPShell): answer = '' if dlg.ShowModal() == wx.ID_OK: answer = dlg.GetValue() - + dlg.Destroy() self.answer = answer - + def _ask_exit(self): wx.CallAfter(self.ask_exit_callback, ()) def _after_execute(self): wx.CallAfter(self.parent.evtStateExecuteDone, ()) - + class WxConsoleView(stc.StyledTextCtrl): ''' Specialized styled text control view for console-like workflow. - We use here a scintilla frontend thus it can be reused in any GUI that + We use here a scintilla frontend thus it can be reused in any GUI that supports scintilla with less work. @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names. @@ -128,7 +128,7 @@ class WxConsoleView(stc.StyledTextCtrl): '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'], '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'], '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'], - '1;34': [12, 'LIGHT BLUE'], '1;35': + '1;34': [12, 'LIGHT BLUE'], '1;35': [13, 'MEDIUM VIOLET RED'], '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']} @@ -163,8 +163,8 @@ class WxConsoleView(stc.StyledTextCtrl): stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style) ####### Scintilla configuration ################################### - - # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside + + # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside # the widget self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) @@ -188,7 +188,7 @@ class WxConsoleView(stc.StyledTextCtrl): self.SetTabWidth(4) self.EnsureCaretVisible() - + self.SetMargins(3, 3) #text is moved away from border with 3px # Suppressing Scintilla margins self.SetMarginWidth(0, 0) @@ -197,19 +197,19 @@ class WxConsoleView(stc.StyledTextCtrl): self.background_color = background_color self.buildStyles() - + self.indent = 0 self.prompt_count = 0 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?') - + self.write(intro) self.setPrompt(prompt) self.showPrompt() self.autocomplete_mode = autocomplete_mode - + self.Bind(wx.EVT_KEY_DOWN, self._onKeypress) - + def buildStyles(self): #we define platform specific fonts if wx.Platform == '__WXMSW__': @@ -246,29 +246,29 @@ class WxConsoleView(stc.StyledTextCtrl): self.SetCaretForeground("WHITE") self.ANSI_STYLES = self.ANSI_STYLES_BLACK - self.StyleSetSpec(stc.STC_STYLE_DEFAULT, - "fore:%s,back:%s,size:%d,face:%s" + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, + "fore:%s,back:%s,size:%d,face:%s" % (self.ANSI_STYLES['0;30'][1], self.background_color, faces['size'], faces['mono'])) self.StyleClearAll() - self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, + self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FF0000,back:#0000FF,bold") self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") for style in self.ANSI_STYLES.values(): self.StyleSetSpec(style[0], "bold,fore:%s" % style[1]) - + ####################################################################### - + def setBackgroundColor(self, color): self.background_color = color self.buildStyles() def getBackgroundColor(self, color): return self.background_color - + def asyncWrite(self, text): ''' Write given text to buffer in an asynchroneous way. @@ -278,16 +278,16 @@ class WxConsoleView(stc.StyledTextCtrl): ''' try: wx.MutexGuiEnter() - + #be sure not to be interrutpted before the MutexGuiLeave! self.write(text) - + except KeyboardInterrupt: wx.MutexGuiLeave() raise KeyboardInterrupt wx.MutexGuiLeave() - - + + def write(self, text): ''' Write given text to buffer. @@ -299,7 +299,7 @@ class WxConsoleView(stc.StyledTextCtrl): segment = segments.pop(0) self.StartStyling(self.getCurrentLineEnd(), 0xFF) self.AppendText(segment) - + if segments: ansi_tags = self.color_pat.findall(text) @@ -312,9 +312,9 @@ class WxConsoleView(stc.StyledTextCtrl): self.SetStyling(len(segments[i+1]), self.ANSI_STYLES[tag][0]) segments.pop(i) - + self.moveCursor(self.getCurrentLineEnd()) - + def getPromptLen(self): ''' Return the length of current prompt @@ -326,10 +326,10 @@ class WxConsoleView(stc.StyledTextCtrl): def setIndentation(self, indentation): self.indent = indentation - + def setPromptCount(self, count): self.prompt_count = count - + def showPrompt(self): ''' Prints prompt at start of line. @@ -340,11 +340,11 @@ class WxConsoleView(stc.StyledTextCtrl): self.write(self.prompt) #now we update the position of end of prompt self.current_start = self.getCurrentLineEnd() - + autoindent = self.indent*' ' autoindent = autoindent.replace(' ','\t') self.write(autoindent) - + def changeLine(self, text): ''' Replace currently entered command line with given text. @@ -379,15 +379,15 @@ class WxConsoleView(stc.StyledTextCtrl): #If cursor is at wrong position put it at last line... if self.GetCurrentPos() < self.getCurrentPromptStart(): self.GotoPos(self.getCurrentPromptStart()) - + def removeFromTo(self, from_pos, to_pos): if from_pos < to_pos: self.SetSelection(from_pos, to_pos) self.DeleteBack() - + def removeCurrentLine(self): self.LineDelete() - + def moveCursor(self, position): self.GotoPos(position) @@ -397,7 +397,7 @@ class WxConsoleView(stc.StyledTextCtrl): def selectFromTo(self, from_pos, to_pos): self.SetSelectionStart(from_pos) self.SetSelectionEnd(to_pos) - + def writeHistory(self, history): self.removeFromTo(self.getCurrentPromptStart(), self.getCurrentLineEnd()) self.changeLine(history) @@ -410,19 +410,19 @@ class WxConsoleView(stc.StyledTextCtrl): def getCompletionMethod(self, completion): return self.autocomplete_mode - + def writeCompletion(self, possibilities): if self.autocomplete_mode == 'IPYTHON': max_len = len(max(possibilities, key=len)) max_symbol = ' '*max_len - + #now we check how much symbol we can put on a line... test_buffer = max_symbol + ' '*4 - + allowed_symbols = 80/len(test_buffer) if allowed_symbols == 0: allowed_symbols = 1 - + pos = 1 buf = '' for symbol in possibilities: @@ -445,7 +445,7 @@ class WxConsoleView(stc.StyledTextCtrl): for breaker in splitter: last_word = last_word.split(breaker)[-1] self.AutoCompShow(len(last_word), " ".join(possibilities)) - + def _onKeypress(self, event, skip=True): ''' Key press callback used for correcting behavior for console-like @@ -476,7 +476,7 @@ class WxConsoleView(stc.StyledTextCtrl): elif event.GetKeyCode() == wx.WXK_LEFT: if event.Modifiers == wx.MOD_NONE: self.moveCursorOnNewValidKey() - + self.moveCursor(self.getCursorPos()-1) if self.getCursorPos() < self.getCurrentPromptStart(): self.moveCursor(self.getCurrentPromptStart()) @@ -487,18 +487,18 @@ class WxConsoleView(stc.StyledTextCtrl): if self.getCursorPos() > self.getCurrentPromptStart(): event.Skip() return True - + if skip: if event.GetKeyCode() not in [wx.WXK_PAGEUP, wx.WXK_PAGEDOWN]\ and event.Modifiers == wx.MOD_NONE: self.moveCursorOnNewValidKey() - + event.Skip() return True return False else: event.Skip() - + def OnUpdateUI(self, evt): # check for matching braces braceAtCaret = -1 @@ -533,19 +533,19 @@ class WxConsoleView(stc.StyledTextCtrl): #self.Refresh(True, wxRect(pt.x, pt.y, 5,5)) #print pt #self.Refresh(False) - + class IPShellWidget(wx.Panel): ''' This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl - If you want to port this to any other GUI toolkit, just replace the - WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate - from whatever container you want. I've choosed to derivate from a wx.Panel + If you want to port this to any other GUI toolkit, just replace the + WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate + from whatever container you want. I've choosed to derivate from a wx.Panel because it seems to be more useful Any idea to make it more 'generic' welcomed. ''' def __init__(self, parent, intro=None, - background_color="BLACK", add_button_handler=None, + background_color="BLACK", add_button_handler=None, wx_ip_shell=None, user_ns={},user_global_ns=None, ): ''' @@ -570,7 +570,7 @@ class IPShellWidget(wx.Panel): ### IPython wx console view instanciation ### #If user didn't defined an intro text, we create one for him - #If you really wnat an empty intro just call wxIPythonViewPanel + #If you really wnat an empty intro just call wxIPythonViewPanel #with intro='' if intro is None: welcome_text = "Welcome to WxIPython Shell.\n\n" @@ -598,7 +598,7 @@ class IPShellWidget(wx.Panel): self.threading_option.SetToolTip(wx.ToolTip( "Use threading: infinite loop don't freeze the GUI and commands can be breaked\nNo threading: maximum compatibility")) #self.threading_option.SetValue(False) - + self.options={'completion':{'value':'IPYTHON', 'checkbox':self.completion_option,'STC':True,'IPYTHON':False, 'setfunc':self.text_ctrl.setCompletionMethod}, @@ -614,12 +614,12 @@ class IPShellWidget(wx.Panel): self.cout.write = self.text_ctrl.asyncWrite #we reloard options self.reloadOptions(self.options) - + self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress) self.completion_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionCompletion) self.background_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionBackgroundColor) self.threading_option.Bind(wx.EVT_CHECKBOX, self.evtCheckOptionThreading) - + ### making the layout of the panel ### sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.text_ctrl, 1, wx.EXPAND) @@ -648,7 +648,7 @@ class IPShellWidget(wx.Panel): def askExitCallback(self, event): self.askExitHandler(event) - + #---------------------- IPython Thread Management ------------------------ def stateDoExecuteLine(self): lines=self.text_ctrl.getCurrentLine() @@ -660,7 +660,7 @@ class IPShellWidget(wx.Panel): if(self.text_ctrl.getCursorPos()!=0): self.text_ctrl.removeCurrentLine() self.setCurrentState('WAIT_END_OF_EXECUTION') - + def evtStateExecuteDone(self,evt): self.doc = self.IP.get_doc_text() self.help = self.IP.get_help_text() @@ -673,7 +673,7 @@ class IPShellWidget(wx.Panel): self.pager_lines = self.help.split('\n') self.pager_state = 'INIT' self.setCurrentState('SHOW_DOC') - self.pager(self.help) + self.pager(self.help) else: if(self.text_ctrl.getCursorPos()!=0): self.text_ctrl.removeCurrentLine() @@ -714,7 +714,7 @@ class IPShellWidget(wx.Panel): self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n') else: self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n') - + for line in self.pager_lines[self.pager_index+1:self.pager_index+9]: self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n') self.pager_index += 10 @@ -730,7 +730,7 @@ class IPShellWidget(wx.Panel): self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n') else: self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n') - + self.pager_index += 1 self.pager_nb_lines -= 1 if self.pager_nb_lines > 0: @@ -739,7 +739,7 @@ class IPShellWidget(wx.Panel): self.pager_nb_lines = 0 self.pager_state = 'DONE' self.stateShowPrompt() - + #------------------------ Key Handler ------------------------------------ def keyPress(self, event): ''' @@ -752,7 +752,7 @@ class IPShellWidget(wx.Panel): #we raise an exception inside the IPython thread container self.IP.ce.raise_exc(KeyboardInterrupt) return - + #let this before 'wx.WXK_RETURN' because we have to put 'IDLE' #mode if AutoComp has been set as inactive if self.cur_state == 'COMPLETING': @@ -772,13 +772,13 @@ class IPShellWidget(wx.Panel): self.pager_state = 'PROCESS_LINES' self.pager(self.doc) return - + if self.cur_state == 'WAITING_USER_INPUT': line=self.text_ctrl.getCurrentLine() self.text_ctrl.write('\n') self.setCurrentState('WAIT_END_OF_EXECUTION') return - + if event.GetKeyCode() in [ord('q'),ord('Q')]: if self.pager_state == 'WAITING': self.pager_state = 'DONE' @@ -787,8 +787,8 @@ class IPShellWidget(wx.Panel): return if self.cur_state == 'WAITING_USER_INPUT': - event.Skip() - + event.Skip() + if self.cur_state == 'IDLE': if event.KeyCode == wx.WXK_UP: history = self.IP.history_back() @@ -805,7 +805,7 @@ class IPShellWidget(wx.Panel): return completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine()) if len(possibilities) > 1: - if self.text_ctrl.autocomplete_mode == 'IPYTHON': + if self.text_ctrl.autocomplete_mode == 'IPYTHON': cur_slice = self.text_ctrl.getCurrentLine() self.text_ctrl.write('\n') self.text_ctrl.writeCompletion(possibilities) @@ -855,31 +855,31 @@ class IPShellWidget(wx.Panel): self.updateOptionTracker('threading', self.options['threading']['value']) self.text_ctrl.SetFocus() - + def getOptions(self): return self.options - + def reloadOptions(self,options): self.options = options for key in self.options.keys(): value = self.options[key]['value'] self.options[key]['checkbox'].SetValue(self.options[key][value]) self.options[key]['setfunc'](value) - + if self.options['threading']['value']=='True': self.IP.set_threading(True) self.cout.write = self.text_ctrl.asyncWrite else: self.IP.set_threading(False) self.cout.write = self.text_ctrl.write - + #------------------------ Hook Section ----------------------------------- def updateOptionTracker(self,name,value): ''' Default history tracker (does nothing) ''' pass - + def setOptionTrackerHook(self,func): ''' Define a new history tracker @@ -891,7 +891,7 @@ class IPShellWidget(wx.Panel): Default history tracker (does nothing) ''' pass - + def setHistoryTrackerHook(self,func): ''' Define a new history tracker @@ -903,7 +903,7 @@ class IPShellWidget(wx.Panel): Default status tracker (does nothing) ''' pass - + def setStatusTrackerHook(self,func): ''' Define a new status tracker diff --git a/IPython/deathrow/gui/wx/thread_ex.py b/IPython/deathrow/gui/wx/thread_ex.py index 0af86d0..b11a19a 100644 --- a/IPython/deathrow/gui/wx/thread_ex.py +++ b/IPython/deathrow/gui/wx/thread_ex.py @@ -6,8 +6,8 @@ raise_exc. import threading import inspect import ctypes - - + + def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" if not inspect.isclass(exctype): @@ -16,35 +16,35 @@ def _async_raise(tid, exctype): if res == 0: raise ValueError("invalid thread id") elif res != 1: - # """if it returns a number greater than one, you're in trouble, + # """if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect""" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0) raise SystemError("PyThreadState_SetAsyncExc failed") - - + + class ThreadEx(threading.Thread): def _get_my_tid(self): """determines this (self's) thread id""" if not self.isAlive(): raise threading.ThreadError("the thread is not active") - + # do we have it cached? if hasattr(self, "_thread_id"): return self._thread_id - + # no, look for it in the _active dict for tid, tobj in threading._active.items(): if tobj is self: self._thread_id = tid return tid - + raise AssertionError("could not determine the thread's id") - + def raise_exc(self, exctype): """raises the given exception type in the context of this thread""" _async_raise(self._get_my_tid(), exctype) - + def kill(self): - """raises SystemExit in the context of the given thread, which should + """raises SystemExit in the context of the given thread, which should cause the thread to exit silently (unless caught)""" self.raise_exc(SystemExit) diff --git a/IPython/deathrow/gui/wx/wxIPython.py b/IPython/deathrow/gui/wx/wxIPython.py index b5158b7..200d213 100644 --- a/IPython/deathrow/gui/wx/wxIPython.py +++ b/IPython/deathrow/gui/wx/wxIPython.py @@ -27,26 +27,26 @@ __email__ = "laurent.dufrechou _at_ gmail.com" __license__ = "BSD" #----------------------------------------- -# Creating one main frame for our +# Creating one main frame for our # application with movables windows #----------------------------------------- class MyFrame(wx.Frame): - """Creating one main frame for our + """Creating one main frame for our application with movables windows""" - def __init__(self, parent=None, id=-1, title="WxIPython", + def __init__(self, parent=None, id=-1, title="WxIPython", pos=wx.DefaultPosition, size=(800, 600), style=wx.DEFAULT_FRAME_STYLE, sync_ok=False): wx.Frame.__init__(self, parent, id, title, pos, size, style) self._mgr = wx.aui.AuiManager() - + # notify PyAUI which frame to use self._mgr.SetManagedWindow(self) - - #create differents panels and make them persistant + + #create differents panels and make them persistant self.history_panel = IPythonHistoryPanel(self) self.history_panel.setOptionTrackerHook(self.optionSave) - + self.ipython_panel = IPShellWidget(self,background_color = "BLACK") #self.ipython_panel = IPShellWidget(self,background_color = "WHITE") if(sync_ok): @@ -60,12 +60,12 @@ class MyFrame(wx.Frame): #Create a notebook to display different IPython shell implementations self.nb = wx.aui.AuiNotebook(self) - + self.optionLoad() - + self.statusbar = self.createStatus() self.createMenu() - + ######################################################################## ### add the panes to the manager # main panels @@ -75,12 +75,12 @@ class MyFrame(wx.Frame): self.nb.AddPage(self.ipython_panel2, "IPython1 Synchroneous Shell") self._mgr.AddPane(self.history_panel , wx.RIGHT, "IPython history") - + # now we specify some panel characteristics self._mgr.GetPane(self.ipython_panel).CaptionVisible(True); self._mgr.GetPane(self.history_panel).CaptionVisible(True); self._mgr.GetPane(self.history_panel).MinSize((200,400)); - + # tell the manager to "commit" all the changes just made self._mgr.Update() @@ -91,14 +91,14 @@ class MyFrame(wx.Frame): self.Bind(wx.EVT_MENU, self.OnShowHistoryPanel,id=wx.ID_HIGHEST+2) self.Bind(wx.EVT_MENU, self.OnShowAbout, id=wx.ID_HIGHEST+3) self.Bind(wx.EVT_MENU, self.OnShowAllPanel,id=wx.ID_HIGHEST+6) - + warn_text = 'Hello from IPython and wxPython.\n' warn_text +='Please Note that this work is still EXPERIMENTAL\n' warn_text +='It does NOT emulate currently all the IPython functions.\n' warn_text +="\nIf you use MATPLOTLIB with show() you'll need to deactivate the THREADING option.\n" if(not sync_ok): warn_text +="\n->No twisted package detected, IPython1 example deactivated." - + dlg = wx.MessageDialog(self, warn_text, 'Warning Box', @@ -120,9 +120,9 @@ class MyFrame(wx.Frame): opt.write(key + '=' + options_ipython_panel[key]['value']+'\n') for key in options_history_panel.keys(): opt.write(key + '=' + options_history_panel[key]['value']+'\n') - finally: + finally: opt.close() - + def optionLoad(self): try: ip = get() @@ -130,10 +130,10 @@ class MyFrame(wx.Frame): opt = open(path + '/options.conf','r') lines = opt.readlines() opt.close() - + options_ipython_panel = self.ipython_panel.getOptions() options_history_panel = self.history_panel.getOptions() - + for line in lines: key = line.split('=')[0] value = line.split('=')[1].replace('\n','').replace('\r','') @@ -145,25 +145,25 @@ class MyFrame(wx.Frame): print >>sys.__stdout__,"Warning: key ",key,"not found in widget options. Check Options.conf" self.ipython_panel.reloadOptions(options_ipython_panel) self.history_panel.reloadOptions(options_history_panel) - + except IOError: print >>sys.__stdout__,"Could not open Options.conf, defaulting to default values." - - + + def createMenu(self): """local method used to create one menu bar""" - + mb = wx.MenuBar() file_menu = wx.Menu() file_menu.Append(wx.ID_EXIT, "Exit") - + view_menu = wx.Menu() view_menu.Append(wx.ID_HIGHEST+1, "Show IPython Panel") view_menu.Append(wx.ID_HIGHEST+2, "Show History Panel") view_menu.AppendSeparator() view_menu.Append(wx.ID_HIGHEST+6, "Show All") - + about_menu = wx.Menu() about_menu.Append(wx.ID_HIGHEST+3, "About") @@ -171,7 +171,7 @@ class MyFrame(wx.Frame): mb.Append(view_menu, "View") mb.Append(about_menu, "About") #mb.Append(options_menu, "Options") - + self.SetMenuBar(mb) def createStatus(self): @@ -189,14 +189,14 @@ class MyFrame(wx.Frame): 'SHOW_DOC':'Showing doc', 'SHOW_PROMPT':'Showing prompt'} self.statusbar.SetStatusText(states[text], 0) - + def OnClose(self, event): """#event used to close program """ # deinitialize the frame manager self._mgr.UnInit() - self.Destroy() + self.Destroy() event.Skip() - + def OnExitDlg(self, event): dlg = wx.MessageDialog(self, 'Are you sure you want to quit WxIPython', 'WxIPython exit', @@ -208,17 +208,17 @@ class MyFrame(wx.Frame): self._mgr.UnInit() self.Destroy() dlg.Destroy() - - #event to display IPython pannel + + #event to display IPython pannel def OnShowIPythonPanel(self,event): """ #event to display Boxpannel """ self._mgr.GetPane(self.ipython_panel).Show(True) - self._mgr.Update() - #event to display History pannel + self._mgr.Update() + #event to display History pannel def OnShowHistoryPanel(self,event): self._mgr.GetPane(self.history_panel).Show(True) - self._mgr.Update() - + self._mgr.Update() + def OnShowAllPanel(self,event): """#event to display all Pannels""" self._mgr.GetPane(self.ipython_panel).Show(True) @@ -240,22 +240,22 @@ class MyFrame(wx.Frame): info.License = wordwrap(licenseText, 500, wx.ClientDC(self)) # Then we call wx.AboutBox giving it that info object - wx.AboutBox(info) - + wx.AboutBox(info) + #----------------------------------------- #Creating our application -#----------------------------------------- +#----------------------------------------- class MyApp(wx.PySimpleApp): """Creating our application""" def __init__(self, sync_ok=False): wx.PySimpleApp.__init__(self) - + self.frame = MyFrame(sync_ok=sync_ok) self.frame.Show() - + #----------------------------------------- #Main loop -#----------------------------------------- +#----------------------------------------- def main(): app = MyApp(is_sync_frontend_ok) app.SetTopWindow(app.frame) diff --git a/IPython/deathrow/ipy_constants.py b/IPython/deathrow/ipy_constants.py index 9e8ea5d..fa27e6c 100644 --- a/IPython/deathrow/ipy_constants.py +++ b/IPython/deathrow/ipy_constants.py @@ -3,18 +3,18 @@ Definition of Fundamental Physical Constants, CODATA Recommended Values -Source, Peter J. Mohr and Barry N. Taylor, +Source, Peter J. Mohr and Barry N. Taylor, CODATA Recommended Values of the Fundamental -Physical Constants, 1998 - -Website: physics.nist.gov/constants +Physical Constants, 1998 + +Website: physics.nist.gov/constants """ # License: BSD-like # Copyright: Gael Varoquaux (gael.varoquaux@normalesup.org) # inspired by maxima's physconst.mac by Cliff Yapp -#from math import * # math MUST be imported BEFORE PhysicalQInteractive +#from math import * # math MUST be imported BEFORE PhysicalQInteractive from IPython.extensions.PhysicalQInteractive import PhysicalQuantityInteractive # Math constants: @@ -111,7 +111,7 @@ ueVT_N.__doc__ = """nuclear magneton in eV T-1 """ # Atomic and Nuclear Constants # General #------------------------------------------------------------------------- -# fine-structure constant +# fine-structure constant alpha = 7.297352533E-3 @@ -163,19 +163,19 @@ me_MeV.__doc__ = """electron mass - energy equivalent in MeV""" # electron-muon mass ratio memu = 4.83633210E-3 -# electron-tau mass ratio +# electron-tau mass ratio metau = 2.87555E-4 -# electron-proton mass ratio +# electron-proton mass ratio memp = 5.446170232E-4 -# electron-neutron mass ratio +# electron-neutron mass ratio memn = 5.438673462E-4 -# electron-deuteron mass ratio +# electron-deuteron mass ratio memd = 2.7244371170E-4 -# electron to alpha particle mass ratio +# electron to alpha particle mass ratio memalpha = 1.3709335611E-4 @@ -202,31 +202,31 @@ sigma_e.__doc__ = """Thomson cross section """ u_e = PhysicalQuantityInteractive(-928.476362E-26 , 'J/T') u_e.__doc__ = """electron magnetic moment """ -# electron magnetic moment to Bohr magneton ratio +# electron magnetic moment to Bohr magneton ratio ueuB = -1.0011596521869 -# electron magnetic moment to nuclear magneton ratio +# electron magnetic moment to nuclear magneton ratio ueuN = -1838.2819660 -# electron magnetic moment anomaly |ue|/uB - 1 +# electron magnetic moment anomaly |ue|/uB - 1 a_e = 1.1596521869E-3 -# electron g-factor +# electron g-factor g_e = -2.0023193043737 -# electron-muon magnetic moment ratio +# electron-muon magnetic moment ratio ueuu = 206.7669720 -# electron-proton magnetic moment ratio +# electron-proton magnetic moment ratio ueup = -658.2106875 # electron to shielded proton magnetic moment ratio (H2O, sphere, 25 C) ueusp = -658.2275954 -# electron-neutron magnetic moment ratio +# electron-neutron magnetic moment ratio ueun = 960.92050 -# electron-deuteron magnetic moment ratio +# electron-deuteron magnetic moment ratio ueud = -2143.923498 # electron to shielded helione magnetic moment ratio (gas, sphere, 25 C) @@ -252,7 +252,7 @@ muc2_J.__doc__ = """energy equivalent """ muc2_MeV = PhysicalQuantityInteractive(105.6583568 , 'MeV') muc2_MeV.__doc__ = """energy equivalent in MeV """ -# muon-electron mass ratio +# muon-electron mass ratio mume = 206.7682657 # muon-tau mass ratio @@ -261,7 +261,7 @@ mum = 5.94572E-2 # muon-proton mass ratio mump = 0.1126095173 -# muon-neutron mass ratio +# muon-neutron mass ratio mumn = 0.1124545079 @@ -276,19 +276,19 @@ lambda_C_u.__doc__ = """muon Compton wavelength """ uu = PhysicalQuantityInteractive(-4.49044813E-26 , 'J/T') uu.__doc__ = """muon magnetic moment """ -# ratio of muon magnetic moment to Bohr magneton ratio +# ratio of muon magnetic moment to Bohr magneton ratio uuuB = -4.84197085E-3 -# ratio of muon magnetic moment to nuclear magneton ratio +# ratio of muon magnetic moment to nuclear magneton ratio uuuN = -8.89059770 -# muon magnetic moment anomaly |uu|/(e /2mu) - 1 +# muon magnetic moment anomaly |uu|/(e /2mu) - 1 a_u = 1.16591602E-3 # muon g-factor -2(1 + au) g_u = -2.0023318320 -# muon-proton magnetic moment ratio +# muon-proton magnetic moment ratio uuup = -3.18334539 # Tau, tau- @@ -308,16 +308,16 @@ mtauc2_J.__doc__ = """tau mass energy equivalent """ mtauc2_MeV = PhysicalQuantityInteractive(1777.05 , 'MeV') mtauc2_MeV.__doc__ = """tau mass energy equivalent in MeV """ -# tau-electron mass ratio +# tau-electron mass ratio mtaume = 3477.60 -# tau-muon mass ratio +# tau-muon mass ratio mtaumu = 16.8188 -# tau-proton mass ratio +# tau-proton mass ratio mtaump = 1.89396 -# tau-neutron mass ratio +# tau-neutron mass ratio mtaumn = 1.89135 @@ -344,16 +344,16 @@ mpc2_J.__doc__ = """energy equivalent """ mpc2_MeV = PhysicalQuantityInteractive(938.271998 , 'MeV') mpc2_MeV.__doc__ = """energy equivalent in MeV """ -# proton-electron mass ratio +# proton-electron mass ratio mpme = 1836.1526675 # proton-muon mass ratio mpmu = 8.88024408 -# proton-tau mass ratio +# proton-tau mass ratio mpmtau = 0.527994 -# proton-neutron mass ratio +# proton-neutron mass ratio mpmn = 0.99862347855 @@ -372,26 +372,26 @@ lambda_C_p.__doc__ = """proton Compton wavelength h/mpc """ up = PhysicalQuantityInteractive(1.410606633E-26 , 'J/T') up.__doc__ = """proton magnetic moment """ -# proton magnetic moment to Bohr magneton ratio +# proton magnetic moment to Bohr magneton ratio upuB = 1.521032203E-3 -# proton magnetic moment to nuclear magneton ratio +# proton magnetic moment to nuclear magneton ratio upuN = 2.792847337 -# proton g-factor 2up/uN +# proton g-factor 2up/uN g_p = 5.585694675 -# proton-neutron magnetic moment ratio +# proton-neutron magnetic moment ratio upun = -1.45989805 usp = PhysicalQuantityInteractive(1.410570399E-26 , 'J/T') usp.__doc__ = """shielded proton magnetic moment (H2O, sphere, 25 C)""" -# shielded proton magnetic moment to Bohr magneton ratio +# shielded proton magnetic moment to Bohr magneton ratio uspuB = 1.520993132E-3 -# shielded proton magnetic moment to nuclear magneton ratio +# shielded proton magnetic moment to nuclear magneton ratio uspuN = 2.792775597 # proton magnetic shielding correction 1 - u p/up (H2O, sphere, 25 C) @@ -422,16 +422,16 @@ mnc2_J.__doc__ = """neutron mass energy equivalent """ mnc2_MeV = PhysicalQuantityInteractive(939.565330 , 'MeV') mnc2_MeV.__doc__ = """neutron mass energy equivalent in MeV """ -# neutron-electron mass ratio +# neutron-electron mass ratio mnme = 1838.6836550 -# neutron-muon mass ratio +# neutron-muon mass ratio mnmu = 8.89248478 -# neutron-tau mass ratio +# neutron-tau mass ratio mnm = 0.528722 -# neutron-proton mass ratio +# neutron-proton mass ratio mnmp = 1.00137841887 @@ -446,19 +446,19 @@ lambda_C_n.__doc__ = """neutron Compton wavelength""" un = PhysicalQuantityInteractive(-0.96623640E-26 , 'J/T') un.__doc__ = """neutron magnetic moment """ -# neutron magnetic moment to Bohr magneton ratio +# neutron magnetic moment to Bohr magneton ratio unuB = -1.04187563E-3 -# neutron magnetic moment to nuclear magneton ratio +# neutron magnetic moment to nuclear magneton ratio unuN = -1.91304272 -# neutron g-factor +# neutron g-factor g_n = -3.82608545 -# neutron-electron magnetic moment ratio +# neutron-electron magnetic moment ratio unue = 1.04066882E-3 -# neutron-proton magnetic moment ratio +# neutron-proton magnetic moment ratio unup = -0.68497934 # neutron to shielded proton magnetic moment ratio (H2O, sphere, 25 C) @@ -486,10 +486,10 @@ mdc2_J.__doc__ = """deuteron mass energy equivalent """ mdc2_eV = PhysicalQuantityInteractive(1875.612762 , 'MeV') mdc2_eV.__doc__ = """deuteron mass energy equivalent in MeV """ -# deuteron-electron mass ratio +# deuteron-electron mass ratio mdme = 3670.4829550 -# deuteron-proton mass ratio +# deuteron-proton mass ratio mdmp = 1.99900750083 @@ -500,19 +500,19 @@ Molar_d.__doc__ = """deuteron molar mass """ ud = PhysicalQuantityInteractive(0.433073457E-26 , 'J/T') ud.__doc__ = """deuteron magnetic moment """ -# deuteron magnetic moment to Bohr magneton ratio +# deuteron magnetic moment to Bohr magneton ratio uduB = 0.4669754556E-3 -# deuteron magnetic moment to nuclear magneton ratio +# deuteron magnetic moment to nuclear magneton ratio uduN = 0.8574382284 -# deuteron-electron magnetic moment ratio +# deuteron-electron magnetic moment ratio udue = -4.664345537E-4 -# deuteron-proton magnetic moment ratio +# deuteron-proton magnetic moment ratio udup = 0.3070122083 -# deuteron-neutron magnetic moment ratio +# deuteron-neutron magnetic moment ratio udun = -0.44820652 # Helion, h @@ -532,10 +532,10 @@ mhc2_J.__doc__ = """helion mass energy equivalent """ mhc2_MeV = PhysicalQuantityInteractive(2808.39132 , 'MeV') mhc2_MeV.__doc__ = """helion mass energy equivalent in MeV """ -# helion-electron mass ratio +# helion-electron mass ratio mhme = 5495.885238 -# helion-proton mass ratio +# helion-proton mass ratio mhmp = 2.99315265850 @@ -546,10 +546,10 @@ Molar_h.__doc__ = """helion molar mass """ ush = PhysicalQuantityInteractive(-1.074552967E-26 , 'J/T') ush.__doc__ = """shielded helion magnetic moment (gas, sphere, 25 C)""" -# shielded helion magnetic moment to Bohr magneton ratio +# shielded helion magnetic moment to Bohr magneton ratio ushuB = -1.158671474E-3 -# shielded helion magnetic moment to nuclear magneton ratio +# shielded helion magnetic moment to nuclear magneton ratio ushuN = -2.127497718 # shielded helion to proton magnetic moment ratio (gas, sphere, 25 C) @@ -562,7 +562,7 @@ ushusp = -0.7617861313 gamma_h = PhysicalQuantityInteractive(2.037894764E8 , '1/(s*T)') gamma_h.__doc__ = """shielded helion gyromagnetic (gas, sphere, 25 C) """ -# Alpha particle, +# Alpha particle, #------------------------------------------------------------------------- m_alpha = PhysicalQuantityInteractive(6.64465598E-27 , 'kg') @@ -579,10 +579,10 @@ malphac2_J.__doc__ = """alpha particle mass energy equivalent """ malphac2_MeV = PhysicalQuantityInteractive(3727.37904 , 'MeV') malphac2_MeV.__doc__ = """alpha particle mass energy equivalent in MeV """ -# alpha particle to electron mass ratio +# alpha particle to electron mass ratio malphame = 7294.299508 -# alpha particle to proton mass ratio +# alpha particle to proton mass ratio malphamp = 3.9725996846 @@ -642,9 +642,9 @@ Vm_2 = PhysicalQuantityInteractive(22.710981E-3 , 'm**3/mol') Vm_2.__doc__ = """molar volume of ideal gas RT/p T = 273.15 K, p = 100 kPa """ # Sackur-Tetrode constant (absolute entropy constant) 52 + ln_(2 mukT1/h2)3/2kT1/p0 -# T1 = 1 K, p0 = 100 kPa +# T1 = 1 K, p0 = 100 kPa S_0R_1 = -1.1517048 -# T1 = 1 K, p0 = 101.325 kPa +# T1 = 1 K, p0 = 101.325 kPa S_0R_2 = -1.1648678 diff --git a/IPython/deathrow/ipy_defaults.py b/IPython/deathrow/ipy_defaults.py index 665a124..4937422 100644 --- a/IPython/deathrow/ipy_defaults.py +++ b/IPython/deathrow/ipy_defaults.py @@ -1,10 +1,10 @@ -""" Set default options for IPython. +""" Set default options for IPython. Just import this module to get reasonable defaults for everything. -These configurations used to be performed in ipythonrc (or ipythonrc.ini). +These configurations used to be performed in ipythonrc (or ipythonrc.ini). Therefore importing this in your config files makes ipython basically -ignore your ipythonrc. This is *not* imported by default, you need to import +ignore your ipythonrc. This is *not* imported by default, you need to import this manually in one of your config files. You can further override these defaults in e.g. your ipy_user_config.py, @@ -58,5 +58,5 @@ set show-all-if-ambiguous on if readline.have_readline: for cmd in rlopts.split('\n'): readline.parse_and_bind(cmd) - - + + diff --git a/IPython/deathrow/ipy_profile_sh.py b/IPython/deathrow/ipy_profile_sh.py index 571f5c4..a860637 100644 --- a/IPython/deathrow/ipy_profile_sh.py +++ b/IPython/deathrow/ipy_profile_sh.py @@ -2,7 +2,7 @@ Start ipython in shell mode by invoking "ipython -p sh" -(the old version, "ipython -p pysh" still works but this is the more "modern" +(the old version, "ipython -p pysh" still works but this is the more "modern" shell mode and is recommended for users who don't care about pysh-mode compatibility) """ @@ -16,29 +16,29 @@ import os,re,textwrap import ipy_defaults -def main(): +def main(): ip = ipapi.get() o = ip.options # autocall to "full" mode (smart mode is default, I like full mode) - + o.autocall = 2 - + # Jason Orendorff's path class is handy to have in user namespace # if you are doing shell-like stuff try: ip.ex("from IPython.external.path import path" ) except ImportError: pass - + # beefed up %env is handy in shell mode import envpersist - - # To see where mycmd resides (in path/aliases), do %which mycmd + + # To see where mycmd resides (in path/aliases), do %which mycmd import ipy_which - + # tab completers for hg, svn, ... import ipy_app_completers - + # To make executables foo and bar in mybin usable without PATH change, do: # %rehashdir c:/mybin # %store foo @@ -47,45 +47,45 @@ def main(): # does not work without subprocess module! #import ipy_signals - + ip.ex('import os') ip.ex("def up(): os.chdir('..')") - ip.user_ns['LA'] = LastArgFinder() - - # You can assign to _prompt_title variable + ip.user_ns['LA'] = LastArgFinder() + + # You can assign to _prompt_title variable # to provide some extra information for prompt # (e.g. the current mode, host/username...) ip.user_ns['_prompt_title'] = '' - + # Nice prompt o.prompt_in1= r'\C_Green${_prompt_title}\C_LightBlue[\C_LightCyan\Y2\C_LightBlue]\C_Green|\#> ' o.prompt_in2= r'\C_Green|\C_LightGreen\D\C_Green> ' o.prompt_out= '<\#> ' - + from IPython.core import release import sys # Non-chatty banner o.banner = "IPython %s [on Py %s]\n" % (release.version,sys.version.split(None,1)[0]) - - + + ip.default_option('cd','-q') ip.default_option('macro', '-r') - # If you only rarely want to execute the things you %edit... + # If you only rarely want to execute the things you %edit... #ip.default_option('edit','-x') - + o.prompts_pad_left="1" # Remove all blank lines in between prompts, like a normal shell. o.separate_in="0" o.separate_out="0" o.separate_out2="0" - + # now alias all syscommands - + db = ip.db - + syscmds = db.get("syscmdlist",[] ) if not syscmds: print textwrap.dedent(""" @@ -95,47 +95,47 @@ def main(): """) ip.magic('rehashx') syscmds = db.get("syscmdlist") - + # lowcase aliases on win32 only if os.name == 'posix': mapper = lambda s:s else: def mapper(s): return s.lower() - + for cmd in syscmds: # print "sys",cmd #dbg noext, ext = os.path.splitext(cmd) if ext.lower() == '.exe': cmd = noext - + key = mapper(cmd) if key not in ip.alias_manager.alias_table: # Dots will be removed from alias names, since ipython # assumes names with dots to be python code - + ip.define_alias(key.replace('.',''), cmd) # mglob combines 'find', recursion, exclusion... '%mglob?' to learn more - ip.load("IPython.external.mglob") + ip.load("IPython.external.mglob") # win32 is crippled w/o cygwin, try to help it a little bit if sys.platform == 'win32': - if 'cygwin' in os.environ['PATH'].lower(): + if 'cygwin' in os.environ['PATH'].lower(): # use the colors of cygwin ls (recommended) ip.define_alias('d', 'ls -F --color=auto') else: # get icp, imv, imkdir, igrep, irm,... ip.load('ipy_fsops') - + # and the next best thing to real 'ls -F' ip.define_alias('d','dir /w /og /on') - + ip.set_hook('input_prefilter', slash_prefilter_f) extend_shell_behavior(ip) class LastArgFinder: """ Allow $LA to work as "last argument of previous command", like $! in bash - + To call this in normal IPython code, do LA() """ def __call__(self, hist_idx = None): @@ -144,7 +144,7 @@ class LastArgFinder: return str(self) return ip.input_hist_raw[hist_idx].strip().split()[-1] def __str__(self): - ip = ipapi.get() + ip = ipapi.get() for cmd in reversed(ip.input_hist_raw): parts = cmd.strip().split() if len(parts) < 2 or parts[-1] in ['$LA', 'LA()']: @@ -154,7 +154,7 @@ class LastArgFinder: def slash_prefilter_f(self,line): """ ./foo, ~/foo and /bin/foo now run foo as system command - + Removes the need for doing !./foo, !~/foo or !/bin/foo """ from IPython.utils import genutils @@ -253,7 +253,7 @@ def extend_shell_behavior(ip): if command or more: # push to raw history, so hist line numbers stay in sync ip.input_hist_raw.append("# " + command + "\n") - + more = ip.push_line(ip.prefilter(command,more)) command = '' # IPython's runsource returns None if there was an error diff --git a/IPython/deathrow/ipy_profile_zope.py b/IPython/deathrow/ipy_profile_zope.py index 690b021..d8cbfe4 100644 --- a/IPython/deathrow/ipy_profile_zope.py +++ b/IPython/deathrow/ipy_profile_zope.py @@ -186,7 +186,7 @@ class ZopeDebug(object): query = {} if indexes.get('path'): from string import join - path = join(obj.getPhysicalPath(), '/') + path = join(obj.getPhysicalPath(), '/') query.update({'path': path}) if indexes.get('getID'): query.update({'getID': obj.id, }) @@ -288,7 +288,7 @@ def main(): ip = ipapi.get() o = ip.options # autocall to "full" mode (smart mode is default, I like full mode) - + SOFTWARE_HOME = os.environ.get( "SOFTWARE_HOME" ) sys.path.append( SOFTWARE_HOME ) print "SOFTWARE_HOME=%s\n" % SOFTWARE_HOME @@ -310,7 +310,7 @@ def main(): app portal utils.{ %s } - + Uses the $SOFTWARE_HOME and $CONFIG_FILE environment variables. """ % ( ",".join([ x for x in dir(zope_debug.utils) if not x.startswith("_") ] ) ) ) diff --git a/IPython/deathrow/ipy_vimserver.py b/IPython/deathrow/ipy_vimserver.py index 1902c6a..cbe6d9f 100644 --- a/IPython/deathrow/ipy_vimserver.py +++ b/IPython/deathrow/ipy_vimserver.py @@ -1,10 +1,10 @@ """ Integration with gvim, by Erich Heine -Provides a %vim magic command, and reuses the same vim session. Uses -unix domain sockets for communication between vim and IPython. ipy.vim is +Provides a %vim magic command, and reuses the same vim session. Uses +unix domain sockets for communication between vim and IPython. ipy.vim is available in doc/examples of the IPython distribution. -Slightly touched up email announcement (and description how to use it) by +Slightly touched up email announcement (and description how to use it) by Erich Heine is here: Ive recently been playing with ipython, and like it quite a bit. I did @@ -22,7 +22,7 @@ for having gvim and ipython work very nicely together. Ive attached both to this email (hoping of course that the mailing list allows such things). -There are 2 files: +There are 2 files: ipy_vimserver.py -- this file contains the ipython stuff ipy.vim -- this file contains the gvim stuff diff --git a/IPython/deathrow/numutils.py b/IPython/deathrow/numutils.py index 977d7ee..42012a5 100644 --- a/IPython/deathrow/numutils.py +++ b/IPython/deathrow/numutils.py @@ -40,7 +40,7 @@ from Numeric import * inf = infty = Infinity = (array([1])/0.0)[0] #**************************************************************************** -# function definitions +# function definitions exp_safe_MIN = math.log(2.2250738585072014e-308) exp_safe_MAX = 1.7976931348623157e+308 @@ -140,12 +140,12 @@ def norm(a,p=2): Ref: http://mathworld.wolfram.com/VectorNorm.html http://mathworld.wolfram.com/L-Infinity-Norm.html""" - + if p in ('inf','Infinity'): return max(absolute(a).flat) else: - return (sum_flat(absolute(a)**p))**(1.0/p) - + return (sum_flat(absolute(a)**p))**(1.0/p) + def frange(xini,xfin=None,delta=None,**kw): """frange([start,] stop[, step, keywords]) -> array of floats @@ -183,14 +183,14 @@ def frange(xini,xfin=None,delta=None,**kw): #defaults kw.setdefault('closed',1) endpoint = kw['closed'] != 0 - + # funny logic to allow the *first* argument to be optional (like range()) # This was modified with a simpler version from a similar frange() found # at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66472 if xfin == None: xfin = xini + 0.0 xini = 0.0 - + if delta == None: delta = 1.0 @@ -223,7 +223,7 @@ def identity(n,rank=2,typecode='l'): Since rank defaults to 2, this function behaves in the default case (when only n is given) like the Numeric identity function.""" - + iden = zeros((n,)*rank,typecode=typecode) for i in range(n): idx = (i,)*rank @@ -250,7 +250,7 @@ def binary_repr(number, max_length = 1025): Increase the value of max_length for very large numbers. Note that on 32-bit machines, 2**1023 is the largest integer power of 2 which can be converted to a Python float.""" - + assert number < 2L << max_length shifts = map (operator.rshift, max_length * [number], \ range (max_length - 1, -1, -1)) @@ -261,7 +261,7 @@ def binary_repr(number, max_length = 1025): def log2(x,ln2 = math.log(2.0)): """Return the log(x) in base 2. - + This is a _slow_ function but which is guaranteed to return the correct integer value if the input is an ineger exact power of 2.""" @@ -288,7 +288,7 @@ def ispower2(n): def fromfunction_kw(function, dimensions, **kwargs): """Drop-in replacement for fromfunction() from Numerical Python. - + Allows passing keyword arguments to the desired function. Call it as (keywords are optional): diff --git a/IPython/deathrow/oldfrontend/asyncfrontendbase.py b/IPython/deathrow/oldfrontend/asyncfrontendbase.py index 1171a83..0ab79d5 100644 --- a/IPython/deathrow/oldfrontend/asyncfrontendbase.py +++ b/IPython/deathrow/oldfrontend/asyncfrontendbase.py @@ -38,10 +38,10 @@ class AsyncFrontEndBase(FrontEndBase): Overrides FrontEndBase to wrap execute in a deferred result. All callbacks are made as callbacks on the deferred result. """ - + implements(IFrontEnd) classProvides(IFrontEndFactory) - + def __init__(self, engine=None, history=None): assert(engine==None or IEngineCore.providedBy(engine)) self.engine = IEngineCore(engine) @@ -49,26 +49,26 @@ class AsyncFrontEndBase(FrontEndBase): self.history = FrontEndHistory(input_cache=['']) else: self.history = history - + def execute(self, block, blockID=None): """Execute the block and return the deferred result. - + Parameters: block : {str, AST} blockID : any - Caller may provide an ID to identify this block. + Caller may provide an ID to identify this block. result['blockID'] := blockID - + Result: Deferred result of self.interpreter.execute """ - + if(not self.is_complete(block)): return Failure(Exception("Block is not compilable")) - + if(blockID == None): - blockID = guid.generate() - + blockID = guid.generate() + d = self.engine.execute(block) d.addCallback(self._add_history, block=block) d.addCallbacks(self._add_block_id_for_result, @@ -76,7 +76,7 @@ class AsyncFrontEndBase(FrontEndBase): callbackArgs=(blockID,), errbackArgs=(blockID,)) d.addBoth(self.update_cell_prompt, blockID=blockID) - d.addCallbacks(self.render_result, + d.addCallbacks(self.render_result, errback=self.render_error) - + return d diff --git a/IPython/deathrow/oldfrontend/cocoa/cocoa_frontend.py b/IPython/deathrow/oldfrontend/cocoa/cocoa_frontend.py index 349e794..a4e773f 100644 --- a/IPython/deathrow/oldfrontend/cocoa/cocoa_frontend.py +++ b/IPython/deathrow/oldfrontend/cocoa/cocoa_frontend.py @@ -1,10 +1,10 @@ # encoding: utf-8 # -*- test-case-name: IPython.frontend.cocoa.tests.test_cocoa_frontend -*- -"""PyObjC classes to provide a Cocoa frontend to the +"""PyObjC classes to provide a Cocoa frontend to the IPython.kernel.engineservice.IEngineBase. -To add an IPython interpreter to a cocoa app, instantiate an +To add an IPython interpreter to a cocoa app, instantiate an IPythonCocoaController in a XIB and connect its textView outlet to an NSTextView instance in your UI. That's it. @@ -32,7 +32,7 @@ from Foundation import NSObject, NSMutableArray, NSMutableDictionary,\ NSLog, NSNotificationCenter, NSMakeRange,\ NSLocalizedString, NSIntersectionRange,\ NSString, NSAutoreleasePool - + from AppKit import NSApplicationWillTerminateNotification, NSBeep,\ NSTextView, NSRulerView, NSVerticalRuler @@ -49,14 +49,14 @@ from twisted.python.failure import Failure # Classes to implement the Cocoa frontend #----------------------------------------------------------------------------- -# TODO: -# 1. use MultiEngineClient and out-of-process engine rather than +# TODO: +# 1. use MultiEngineClient and out-of-process engine rather than # ThreadedEngineService? # 2. integrate Xgrid launching of engines - + class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService): """Wrap all blocks in an NSAutoreleasePool""" - + def wrapped_execute(self, msg, lines): """wrapped_execute""" try: @@ -65,9 +65,9 @@ class AutoreleasePoolWrappedThreadedEngineService(ThreadedEngineService): self).wrapped_execute(msg, lines) finally: p.drain() - + return result - + class Cell(NSObject): @@ -75,20 +75,20 @@ class Cell(NSObject): Representation of the prompts, input and output of a cell in the frontend """ - + blockNumber = objc.ivar().unsigned_long() blockID = objc.ivar() inputBlock = objc.ivar() output = objc.ivar() - - + + class CellBlock(object): """ Storage for information about text ranges relating to a single cell """ - + def __init__(self, inputPromptRange, inputRange=None, outputPromptRange=None, outputRange=None): super(CellBlock, self).__init__() @@ -96,10 +96,10 @@ class CellBlock(object): self.inputRange = inputRange self.outputPromptRange = outputPromptRange self.outputRange = outputRange - + def update_ranges_for_insertion(self, text, textRange): """Update ranges for text insertion at textRange""" - + for r in [self.inputPromptRange,self.inputRange, self.outputPromptRange, self.outputRange]: if(r == None): @@ -117,11 +117,11 @@ class CellBlock(object): r.length += len(text) - intersection.length else: r.length -= intersection.length - - + + def update_ranges_for_deletion(self, textRange): """Update ranges for text deletion at textRange""" - + for r in [self.inputPromptRange,self.inputRange, self.outputPromptRange, self.outputRange]: if(r==None): @@ -139,52 +139,52 @@ class CellBlock(object): r.length += intersection.length else: r.length -= intersection.length - + def __repr__(self): return 'CellBlock('+ str((self.inputPromptRange, self.inputRange, self.outputPromptRange, self.outputRange)) + ')' - - + + class IPythonCocoaController(NSObject, AsyncFrontEndBase): userNS = objc.ivar() #mirror of engine.user_ns (key=>str(value)) waitingForEngine = objc.ivar().bool() textView = objc.IBOutlet() - + def init(self): self = super(IPythonCocoaController, self).init() AsyncFrontEndBase.__init__(self, engine=AutoreleasePoolWrappedThreadedEngineService()) if(self != None): self._common_init() - + return self - + def _common_init(self): """_common_init""" - + self.userNS = NSMutableDictionary.dictionary() self.waitingForEngine = False - + self.lines = {} self.tabSpaces = 4 self.tabUsesSpaces = True self.currentBlockID = self.next_block_ID() self.blockRanges = {} # blockID=>CellBlock - - + + def awakeFromNib(self): """awakeFromNib""" - + self._common_init() - + # Start the IPython engine self.engine.startService() NSLog('IPython engine started') - + # Register for app termination nc = NSNotificationCenter.defaultCenter() nc.addObserver_selector_name_object_( @@ -192,7 +192,7 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): 'appWillTerminate:', NSApplicationWillTerminateNotification, None) - + self.textView.setDelegate_(self) self.textView.enclosingScrollView().setHasVerticalRuler_(True) r = NSRulerView.alloc().initWithScrollView_orientation_( @@ -202,30 +202,30 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): self.verticalRulerView.setClientView_(self.textView) self._start_cli_banner() self.start_new_block() - - + + def appWillTerminate_(self, notification): """appWillTerminate""" - + self.engine.stopService() - - + + def complete(self, token): """Complete token in engine's user_ns - + Parameters ---------- token : string - + Result ------ - Deferred result of + Deferred result of IPython.kernel.engineservice.IEngineBase.complete """ - + return self.engine.complete(token) - - + + def execute(self, block, blockID=None): self.waitingForEngine = True self.willChangeValueForKey_('commandHistory') @@ -233,87 +233,87 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): blockID) d.addBoth(self._engine_done) d.addCallback(self._update_user_ns) - + return d - - + + def push_(self, namespace): """Push dictionary of key=>values to python namespace""" - + self.waitingForEngine = True self.willChangeValueForKey_('commandHistory') d = self.engine.push(namespace) d.addBoth(self._engine_done) d.addCallback(self._update_user_ns) - - + + def pull_(self, keys): """Pull keys from python namespace""" - + self.waitingForEngine = True result = blockingCallFromThread(self.engine.pull, keys) self.waitingForEngine = False - + @objc.signature('v@:@I') def executeFileAtPath_encoding_(self, path, encoding): """Execute file at path in an empty namespace. Update the engine user_ns with the resulting locals.""" - + lines,err = NSString.stringWithContentsOfFile_encoding_error_( path, encoding, None) self.engine.execute(lines) - - + + def _engine_done(self, x): self.waitingForEngine = False self.didChangeValueForKey_('commandHistory') return x - + def _update_user_ns(self, result): """Update self.userNS from self.engine's namespace""" d = self.engine.keys() d.addCallback(self._get_engine_namespace_values_for_keys) - + return result - - + + def _get_engine_namespace_values_for_keys(self, keys): d = self.engine.pull(keys) d.addCallback(self._store_engine_namespace_values, keys=keys) - - + + def _store_engine_namespace_values(self, values, keys=[]): assert(len(values) == len(keys)) self.willChangeValueForKey_('userNS') for (k,v) in zip(keys,values): self.userNS[k] = saferepr(v) self.didChangeValueForKey_('userNS') - - + + def update_cell_prompt(self, result, blockID=None): print self.blockRanges if(isinstance(result, Failure)): prompt = self.input_prompt() - + else: prompt = self.input_prompt(number=result['number']) - + r = self.blockRanges[blockID].inputPromptRange self.insert_text(prompt, textRange=r, scrollToVisible=False ) - + return result - - + + def render_result(self, result): blockID = result['blockID'] inputRange = self.blockRanges[blockID].inputRange del self.blockRanges[blockID] - + #print inputRange,self.current_block_range() self.insert_text('\n' + self.output_prompt(number=result['number']) + @@ -322,8 +322,8 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): textRange=NSMakeRange(inputRange.location+inputRange.length, 0)) return result - - + + def render_error(self, failure): print failure blockID = failure.blockID @@ -338,82 +338,82 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): 0)) self.start_new_block() return failure - - + + def _start_cli_banner(self): """Print banner""" - + banner = """IPython1 %s -- An enhanced Interactive Python.""" % \ IPython.__version__ - + self.insert_text(banner + '\n\n') - - + + def start_new_block(self): """""" - + self.currentBlockID = self.next_block_ID() self.blockRanges[self.currentBlockID] = self.new_cell_block() - self.insert_text(self.input_prompt(), + self.insert_text(self.input_prompt(), textRange=self.current_block_range().inputPromptRange) - - - + + + def next_block_ID(self): - - return guid.generate() - + + return guid.generate() + def new_cell_block(self): """A new CellBlock at the end of self.textView.textStorage()""" - - return CellBlock(NSMakeRange(self.textView.textStorage().length(), + + return CellBlock(NSMakeRange(self.textView.textStorage().length(), 0), #len(self.input_prompt())), NSMakeRange(self.textView.textStorage().length(),# + len(self.input_prompt()), 0)) - - + + def current_block_range(self): - return self.blockRanges.get(self.currentBlockID, + return self.blockRanges.get(self.currentBlockID, self.new_cell_block()) - + def current_block(self): """The current block's text""" - + return self.text_for_range(self.current_block_range().inputRange) - + def text_for_range(self, textRange): """text_for_range""" - + ts = self.textView.textStorage() return ts.string().substringWithRange_(textRange) - + def current_line(self): block = self.text_for_range(self.current_block_range().inputRange) block = block.split('\n') return block[-1] - - + + def insert_text(self, string=None, textRange=None, scrollToVisible=True): - """Insert text into textView at textRange, updating blockRanges + """Insert text into textView at textRange, updating blockRanges as necessary """ if(textRange == None): #range for end of text - textRange = NSMakeRange(self.textView.textStorage().length(), 0) - - + textRange = NSMakeRange(self.textView.textStorage().length(), 0) + + self.textView.replaceCharactersInRange_withString_( textRange, string) - + for r in self.blockRanges.itervalues(): r.update_ranges_for_insertion(string, textRange) - + self.textView.setSelectedRange_(textRange) if(scrollToVisible): self.textView.scrollRangeToVisible_(textRange) - - - + + + def replace_current_block_with_string(self, textView, string): textView.replaceCharactersInRange_withString_( self.current_block_range().inputRange, @@ -422,53 +422,53 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): r = NSMakeRange(textView.textStorage().length(), 0) textView.scrollRangeToVisible_(r) textView.setSelectedRange_(r) - - + + def current_indent_string(self): """returns string for indent or None if no indent""" - + return self._indent_for_block(self.current_block()) - - + + def _indent_for_block(self, block): lines = block.split('\n') if(len(lines) > 1): currentIndent = len(lines[-1]) - len(lines[-1].lstrip()) if(currentIndent == 0): currentIndent = self.tabSpaces - + if(self.tabUsesSpaces): result = ' ' * currentIndent else: result = '\t' * (currentIndent/self.tabSpaces) else: result = None - + return result - - + + # NSTextView delegate methods... def textView_doCommandBySelector_(self, textView, selector): assert(textView == self.textView) NSLog("textView_doCommandBySelector_: "+selector) - - + + if(selector == 'insertNewline:'): indent = self.current_indent_string() if(indent): line = indent + self.current_line() else: line = self.current_line() - + if(self.is_complete(self.current_block())): self.execute(self.current_block(), blockID=self.currentBlockID) self.start_new_block() - + return True - + return False - + elif(selector == 'moveUp:'): prevBlock = self.get_history_previous(self.current_block()) if(prevBlock != None): @@ -476,7 +476,7 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): else: NSBeep() return True - + elif(selector == 'moveDown:'): nextBlock = self.get_history_next() if(nextBlock != None): @@ -484,10 +484,10 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): else: NSBeep() return True - + elif(selector == 'moveToBeginningOfParagraph:'): textView.setSelectedRange_(NSMakeRange( - self.current_block_range().inputRange.location, + self.current_block_range().inputRange.location, 0)) return True elif(selector == 'moveToEndOfParagraph:'): @@ -499,16 +499,16 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): if(textView.selectedRange().location <= \ self.current_block_range().location): raise NotImplemented() - + return False # don't actually handle the delete - + elif(selector == 'insertTab:'): if(len(self.current_line().strip()) == 0): #only white space return False else: self.textView.complete_(self) return True - + elif(selector == 'deleteBackward:'): #if we're at the beginning of the current block, ignore if(textView.selectedRange().location == \ @@ -523,17 +523,17 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): r.update_ranges_for_deletion(deleteRange) return False return False - - - def textView_shouldChangeTextInRanges_replacementStrings_(self, + + + def textView_shouldChangeTextInRanges_replacementStrings_(self, textView, ranges, replacementStrings): """ Delegate method for NSTextView. - - Refuse change text in ranges not at end, but make those changes at + + Refuse change text in ranges not at end, but make those changes at end. """ - + assert(len(ranges) == len(replacementStrings)) allow = True for r,s in zip(ranges, replacementStrings): @@ -542,10 +542,10 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): r.location < self.current_block_range().inputRange.location): self.insert_text(s) allow = False - + return allow - - def textView_completions_forPartialWordRange_indexOfSelectedItem_(self, + + def textView_completions_forPartialWordRange_indexOfSelectedItem_(self, textView, words, charRange, index): try: ts = textView.textStorage() @@ -554,7 +554,7 @@ class IPythonCocoaController(NSObject, AsyncFrontEndBase): except: completions = objc.nil NSBeep() - + return (completions,0) - + diff --git a/IPython/deathrow/oldfrontend/cocoa/plugin/setup.py b/IPython/deathrow/oldfrontend/cocoa/plugin/setup.py index 11fdd25..d761fc7 100644 --- a/IPython/deathrow/oldfrontend/cocoa/plugin/setup.py +++ b/IPython/deathrow/oldfrontend/cocoa/plugin/setup.py @@ -2,7 +2,7 @@ """ setup.py -Setuptools installer script for generating a Cocoa plugin for the +Setuptools installer script for generating a Cocoa plugin for the IPython cocoa frontend Author: Barry Wark diff --git a/IPython/deathrow/oldfrontend/cocoa/tests/test_cocoa_frontend.py b/IPython/deathrow/oldfrontend/cocoa/tests/test_cocoa_frontend.py index 58b78e4..58ceb3b 100644 --- a/IPython/deathrow/oldfrontend/cocoa/tests/test_cocoa_frontend.py +++ b/IPython/deathrow/oldfrontend/cocoa/tests/test_cocoa_frontend.py @@ -1,18 +1,18 @@ # encoding: utf-8 -"""This file contains unittests for the +"""This file contains unittests for the IPython.frontend.cocoa.cocoa_frontend module. """ __docformat__ = "restructuredtext en" - + #--------------------------------------------------------------------------- -# Copyright (C) 2005 The IPython Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. +# Copyright (C) 2005 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. #--------------------------------------------------------------------------- - + #--------------------------------------------------------------------------- -# Imports +# Imports #--------------------------------------------------------------------------- # Tell nose to skip this module @@ -84,14 +84,14 @@ class TestIPythonCocoaControler(unittest.TestCase): """test that current_indent_string returns current indent or None. Uses _indent_for_block for direct unit testing. """ - + self.controller.tabUsesSpaces = True self.assert_(self.controller._indent_for_block("""a=3""") == None) self.assert_(self.controller._indent_for_block("") == None) block = """def test():\n a=3""" self.assert_(self.controller._indent_for_block(block) == \ ' ' * self.controller.tabSpaces) - + block = """if(True):\n%sif(False):\n%spass""" % \ (' '*self.controller.tabSpaces, 2*' '*self.controller.tabSpaces) diff --git a/IPython/deathrow/oldfrontend/frontendbase.py b/IPython/deathrow/oldfrontend/frontendbase.py index 3ae6e78..15921c4 100644 --- a/IPython/deathrow/oldfrontend/frontendbase.py +++ b/IPython/deathrow/oldfrontend/frontendbase.py @@ -1,10 +1,10 @@ # encoding: utf-8 # -*- test-case-name: IPython.frontend.tests.test_frontendbase -*- """ -frontendbase provides an interface and base class for GUI frontends for +frontendbase provides an interface and base class for GUI frontends for IPython.kernel/IPython.kernel.core. -Frontend implementations will likely want to subclass FrontEndBase. +Frontend implementations will likely want to subclass FrontEndBase. Author: Barry Wark """ @@ -26,8 +26,8 @@ from IPython.external import guid from IPython.frontend.zopeinterface import ( - Interface, - Attribute, + Interface, + Attribute, ) from IPython.kernel.core.history import FrontEndHistory from IPython.kernel.core.util import Bunch @@ -47,103 +47,103 @@ rc.prompt_out = r'Out [$number]: ' class IFrontEndFactory(Interface): """Factory interface for frontends.""" - + def __call__(engine=None, history=None): """ Parameters: interpreter : IPython.kernel.engineservice.IEngineCore """ - + pass class IFrontEnd(Interface): """Interface for frontends. All methods return t.i.d.Deferred""" - + Attribute("input_prompt_template", "string.Template instance\ substituteable with execute result.") Attribute("output_prompt_template", "string.Template instance\ substituteable with execute result.") Attribute("continuation_prompt_template", "string.Template instance\ substituteable with execute result.") - + def update_cell_prompt(result, blockID=None): - """Subclass may override to update the input prompt for a block. + """Subclass may override to update the input prompt for a block. In asynchronous frontends, this method will be called as a twisted.internet.defer.Deferred's callback/errback. Implementations should thus return result when finished. - + Result is a result dict in case of success, and a twisted.python.util.failure.Failure in case of an error """ - + pass - + def render_result(result): """Render the result of an execute call. Implementors may choose the method of rendering. - For example, a notebook-style frontend might render a Chaco plot + For example, a notebook-style frontend might render a Chaco plot inline. - + Parameters: result : dict (result of IEngineBase.execute ) blockID = result['blockID'] - + Result: Output of frontend rendering """ - + pass - + def render_error(failure): - """Subclasses must override to render the failure. - + """Subclasses must override to render the failure. + In asynchronous frontend, since this method will be called as a twisted.internet.defer.Deferred's callback. Implementations should thus return result when finished. - + blockID = failure.blockID """ - + pass - + def input_prompt(number=''): - """Returns the input prompt by subsituting into + """Returns the input prompt by subsituting into self.input_prompt_template """ pass - + def output_prompt(number=''): - """Returns the output prompt by subsituting into + """Returns the output prompt by subsituting into self.output_prompt_template """ - + pass - + def continuation_prompt(): - """Returns the continuation prompt by subsituting into + """Returns the continuation prompt by subsituting into self.continuation_prompt_template """ - + pass - + def is_complete(block): """Returns True if block is complete, False otherwise.""" - + pass - - + + def get_history_previous(current_block): """Returns the block previous in the history. Saves currentBlock if the history_cursor is currently at the end of the input history""" pass - + def get_history_next(): """Returns the next block in the history.""" - + pass - + def complete(self, line): """Returns the list of possible completions, and the completed line. @@ -156,7 +156,7 @@ class IFrontEnd(Interface): ############################################################################## -# Base class for all the frontends. +# Base class for all the frontends. ############################################################################## class FrontEndBase(object): @@ -164,86 +164,86 @@ class FrontEndBase(object): FrontEndBase manages the state tasks for a CLI frontend: - Input and output history management - Input/continuation and output prompt generation - + Some issues (due to possibly unavailable engine): - How do we get the current cell number for the engine? - How do we handle completions? """ - + history_cursor = 0 - + input_prompt_template = string.Template(rc.prompt_in1) output_prompt_template = string.Template(rc.prompt_out) continuation_prompt_template = string.Template(rc.prompt_in2) - + def __init__(self, shell=None, history=None): self.shell = shell if history is None: self.history = FrontEndHistory(input_cache=['']) else: self.history = history - - + + def input_prompt(self, number=''): """Returns the current input prompt - + It would be great to use ipython1.core.prompts.Prompt1 here """ return self.input_prompt_template.safe_substitute({'number':number}) - - + + def continuation_prompt(self): """Returns the current continuation prompt""" - + return self.continuation_prompt_template.safe_substitute() - + def output_prompt(self, number=''): """Returns the output prompt for result""" - + return self.output_prompt_template.safe_substitute({'number':number}) - - + + def is_complete(self, block): """Determine if block is complete. - + Parameters block : string - - Result + + Result True if block can be sent to the engine without compile errors. False otherwise. """ - + try: is_complete = codeop.compile_command(block.rstrip() + '\n\n', - "", "exec") + "", "exec") except: return False - + lines = block.split('\n') - return ((is_complete is not None) + return ((is_complete is not None) and (len(lines)==1 or str(lines[-1])=='')) - - + + def execute(self, block, blockID=None): """Execute the block and return the result. - + Parameters: block : {str, AST} blockID : any - Caller may provide an ID to identify this block. + Caller may provide an ID to identify this block. result['blockID'] := blockID - + Result: Deferred result of self.interpreter.execute """ - + if(not self.is_complete(block)): raise Exception("Block is not compilable") - + if(blockID == None): blockID = guid.generate() - + try: result = self.shell.execute(block) except Exception,e: @@ -254,90 +254,90 @@ class FrontEndBase(object): result = self._add_block_id_for_result(result, blockID=blockID) result = self.update_cell_prompt(result, blockID=blockID) result = self.render_result(result) - + return result - - + + def _add_block_id_for_result(self, result, blockID): - """Add the blockID to result or failure. Unfortunatley, we have to + """Add the blockID to result or failure. Unfortunatley, we have to treat failures differently than result dicts. """ - + result['blockID'] = blockID - + return result - + def _add_block_id_for_failure(self, failure, blockID): """_add_block_id_for_failure""" failure.blockID = blockID return failure - - + + def _add_history(self, result, block=None): """Add block to the history""" - + assert(block != None) self.history.add_items([block]) self.history_cursor += 1 - + return result - - + + def get_history_previous(self, current_block): """ Returns previous history string and decrement history cursor. """ command = self.history.get_history_item(self.history_cursor - 1) - + if command is not None: if(self.history_cursor+1 == len(self.history.input_cache)): self.history.input_cache[self.history_cursor] = current_block self.history_cursor -= 1 return command - - + + def get_history_next(self): """ Returns next history string and increment history cursor. """ command = self.history.get_history_item(self.history_cursor+1) - + if command is not None: self.history_cursor += 1 return command - + ### # Subclasses probably want to override these methods... ### - + def update_cell_prompt(self, result, blockID=None): - """Subclass may override to update the input prompt for a block. + """Subclass may override to update the input prompt for a block. This method only really makes sens in asyncrhonous frontend. - Since this method will be called as a - twisted.internet.defer.Deferred's callback, implementations should + Since this method will be called as a + twisted.internet.defer.Deferred's callback, implementations should return result when finished. """ - + raise NotImplementedError - - + + def render_result(self, result): - """Subclasses must override to render result. - + """Subclasses must override to render result. + In asynchronous frontends, this method will be called as a twisted.internet.defer.Deferred's callback. Implementations should thus return result when finished. """ - + raise NotImplementedError - - + + def render_error(self, failure): - """Subclasses must override to render the failure. - + """Subclasses must override to render the failure. + In asynchronous frontends, this method will be called as a twisted.internet.defer.Deferred's callback. Implementations should thus return result when finished. """ - + raise NotImplementedError diff --git a/IPython/deathrow/oldfrontend/linefrontendbase.py b/IPython/deathrow/oldfrontend/linefrontendbase.py index 1dc570c..251d9d5 100644 --- a/IPython/deathrow/oldfrontend/linefrontendbase.py +++ b/IPython/deathrow/oldfrontend/linefrontendbase.py @@ -48,13 +48,13 @@ class LineFrontEndBase(FrontEndBase): to be the base class behind all the frontend that are line-oriented, rather than block-oriented. """ - + # We need to keep the prompt number, to be able to increment # it when there is an exception. prompt_number = 1 # We keep a reference to the last result: it helps testing and - # programatic control of the frontend. + # programatic control of the frontend. last_result = dict(number=0) # The last prompt displayed. Useful for continuation prompts. @@ -93,11 +93,11 @@ class LineFrontEndBase(FrontEndBase): def complete(self, line): """Complete line in engine's user_ns - + Parameters ---------- line : string - + Returns ------- The replacement for the line and the list of possible completions. @@ -105,11 +105,11 @@ class LineFrontEndBase(FrontEndBase): completions = self.shell.complete(line) complete_sep = re.compile('[\s\{\}\[\]\(\)\=]') if completions: - prefix = common_prefix(completions) + prefix = common_prefix(completions) residual = complete_sep.split(line)[:-1] line = line[:-len(residual)] + prefix - return line, completions - + return line, completions + def render_result(self, result): """ Frontend-specific rendering of the result of a calculation @@ -118,15 +118,15 @@ class LineFrontEndBase(FrontEndBase): if 'stdout' in result and result['stdout']: self.write('\n' + result['stdout']) if 'display' in result and result['display']: - self.write("%s%s\n" % ( + self.write("%s%s\n" % ( self.output_prompt_template.substitute( number=result['number']), result['display']['pprint'] ) ) - + def render_error(self, failure): - """ Frontend-specific rendering of error. + """ Frontend-specific rendering of error. """ self.write('\n\n'+str(failure)+'\n\n') return failure @@ -146,7 +146,7 @@ class LineFrontEndBase(FrontEndBase): # thus want to consider an empty string as a complete # statement. return True - elif ( len(self.input_buffer.split('\n'))>2 + elif ( len(self.input_buffer.split('\n'))>2 and not re.findall(r"\n[\t ]*\n[\t ]*$", string)): return False else: @@ -157,7 +157,7 @@ class LineFrontEndBase(FrontEndBase): # This should probably be done in a different place (like # maybe 'prefilter_input' method? For now, this works. clean_string = string.rstrip('\n') - if not clean_string.endswith('\\'): clean_string +='\n\n' + if not clean_string.endswith('\\'): clean_string +='\n\n' is_complete = codeop.compile_command(clean_string, "", "exec") self.release_output() @@ -228,10 +228,10 @@ class LineFrontEndBase(FrontEndBase): def complete_current_input(self): - """ Do code completion on current line. + """ Do code completion on current line. """ if self.debug: - print >>sys.__stdout__, "complete_current_input", + print >>sys.__stdout__, "complete_current_input", line = self.input_buffer new_line, completions = self.complete(line) if len(completions)>1: @@ -241,7 +241,7 @@ class LineFrontEndBase(FrontEndBase): if self.debug: print >>sys.__stdout__, 'line', line print >>sys.__stdout__, 'new_line', new_line - print >>sys.__stdout__, completions + print >>sys.__stdout__, completions def get_line_width(self): @@ -259,10 +259,10 @@ class LineFrontEndBase(FrontEndBase): """ if new_line is None: new_line = self.input_buffer - + self.write('\n') max_len = len(max(possibilities, key=len)) + 1 - + # Now we check how much symbol we can put on a line... chars_per_line = self.get_line_width() symbols_per_line = max(1, chars_per_line/max_len) @@ -283,7 +283,7 @@ class LineFrontEndBase(FrontEndBase): def new_prompt(self, prompt): - """ Prints a prompt and starts a new editing buffer. + """ Prints a prompt and starts a new editing buffer. Subclasses should use this method to make sure that the terminal is put in a state favorable for a new line @@ -297,7 +297,7 @@ class LineFrontEndBase(FrontEndBase): """Returns the current continuation prompt. """ return ("."*(len(self.last_prompt)-2) + ': ') - + def execute_command(self, command, hidden=False): """ Execute a command, not only in the model, but also in the @@ -308,7 +308,7 @@ class LineFrontEndBase(FrontEndBase): #-------------------------------------------------------------------------- # Private API #-------------------------------------------------------------------------- - + def _on_enter(self, new_line_pos=0): """ Called when the return key is pressed in a line editing buffer. @@ -339,7 +339,7 @@ class LineFrontEndBase(FrontEndBase): new_line_pos = -new_line_pos lines = current_buffer.split('\n')[:-1] prompt_less_lines = prompt_less_buffer.split('\n') - # Create the new line, with the continuation prompt, and the + # Create the new line, with the continuation prompt, and the # same amount of indent than the line above it. new_line = self.continuation_prompt() + \ self._get_indent_string('\n'.join( @@ -356,7 +356,7 @@ class LineFrontEndBase(FrontEndBase): else: lines.insert(new_line_pos, new_line) self.input_buffer = '\n'.join(lines) - + def _get_indent_string(self, string): """ Return the string of whitespace that prefixes a line. Used to @@ -369,5 +369,5 @@ class LineFrontEndBase(FrontEndBase): ' '*(indent_chars % 4) return indent_string - - + + diff --git a/IPython/deathrow/oldfrontend/prefilterfrontend.py b/IPython/deathrow/oldfrontend/prefilterfrontend.py index 20726e2..269db63 100644 --- a/IPython/deathrow/oldfrontend/prefilterfrontend.py +++ b/IPython/deathrow/oldfrontend/prefilterfrontend.py @@ -51,7 +51,7 @@ def mk_system_call(system_call_function, command): return my_system_call #----------------------------------------------------------------------------- -# Frontend class using ipython0 to do the prefiltering. +# Frontend class using ipython0 to do the prefiltering. #----------------------------------------------------------------------------- class PrefilterFrontEnd(LineFrontEndBase): @@ -65,7 +65,7 @@ class PrefilterFrontEnd(LineFrontEndBase): """ debug = False - + def __init__(self, ipython0=None, *args, **kwargs): """ Parameters ---------- @@ -99,7 +99,7 @@ class PrefilterFrontEnd(LineFrontEndBase): __builtin__.raw_input = old_rawinput self.ipython0 = ipython0 # Set the pager: - self.ipython0.set_hook('show_in_pager', + self.ipython0.set_hook('show_in_pager', lambda s, string: self.write("\n" + string)) self.ipython0.write = self.write self._ip = _ip = self.ipython0 @@ -109,7 +109,7 @@ class PrefilterFrontEnd(LineFrontEndBase): # XXX: Muck around with magics so that they work better # in our environment if not sys.platform.startswith('win'): - self.ipython0.magic_ls = mk_system_call(self.system_call, + self.ipython0.magic_ls = mk_system_call(self.system_call, 'ls -CF') # And now clean up the mess created by ipython0 self.release_output() @@ -122,7 +122,7 @@ class PrefilterFrontEnd(LineFrontEndBase): self.start() #-------------------------------------------------------------------------- - # FrontEndBase interface + # FrontEndBase interface #-------------------------------------------------------------------------- def show_traceback(self): @@ -147,8 +147,8 @@ class PrefilterFrontEnd(LineFrontEndBase): def save_output_hooks(self): """ Store all the output hooks we can think of, to be able to - restore them. - + restore them. + We need to do this early, as starting the ipython0 instance will screw ouput hooks. """ @@ -178,8 +178,8 @@ class PrefilterFrontEnd(LineFrontEndBase): Term.cerr.write = self.__old_cerr_write sys.stdout = self.__old_stdout sys.stderr = self.__old_stderr - pydoc.help.output = self.__old_help_output - sys.displayhook = self.__old_display_hook + pydoc.help.output = self.__old_help_output + sys.displayhook = self.__old_display_hook def complete(self, line): @@ -191,12 +191,12 @@ class PrefilterFrontEnd(LineFrontEndBase): key = lambda x: x.replace('_', '') completions.sort(key=key) if completions: - prefix = common_prefix(completions) + prefix = common_prefix(completions) line = line[:-len(word)] + prefix return line, completions - + #-------------------------------------------------------------------------- - # LineFrontEndBase interface + # LineFrontEndBase interface #-------------------------------------------------------------------------- def prefilter_input(self, input_string): @@ -209,7 +209,7 @@ class PrefilterFrontEnd(LineFrontEndBase): # capture it. self.capture_output() self.last_result = dict(number=self.prompt_number) - + try: try: for line in input_string.split('\n'): @@ -227,9 +227,9 @@ class PrefilterFrontEnd(LineFrontEndBase): return filtered_string #-------------------------------------------------------------------------- - # PrefilterFrontEnd interface + # PrefilterFrontEnd interface #-------------------------------------------------------------------------- - + def system_call(self, command_string): """ Allows for frontend to define their own system call, to be able capture output and redirect input. @@ -250,7 +250,7 @@ class PrefilterFrontEnd(LineFrontEndBase): # that in the 'pyreadline' module (modes/basemode.py) where we break at # each delimiter and try to complete the residual line, until we get a # successful list of completions. - expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})' + expression = '\s|=|,|:|\((?!.*\))|\[(?!.*\])|\{(?!.*\})' complete_sep = re.compile(expression) text = complete_sep.split(line)[-1] return text diff --git a/IPython/deathrow/oldfrontend/process/killableprocess.py b/IPython/deathrow/oldfrontend/process/killableprocess.py index 399bd70..2c5c380 100644 --- a/IPython/deathrow/oldfrontend/process/killableprocess.py +++ b/IPython/deathrow/oldfrontend/process/killableprocess.py @@ -1,4 +1,4 @@ -# Addapted from killableprocess.py. +# Addapted from killableprocess.py. #______________________________________________________________________________ # # killableprocess - subprocesses which can be reliably killed @@ -118,10 +118,10 @@ else: if startupinfo is None: startupinfo = winprocess.STARTUPINFO() - + if None not in (p2cread, c2pwrite, errwrite): startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES - + startupinfo.hStdInput = int(p2cread) startupinfo.hStdOutput = int(c2pwrite) startupinfo.hStdError = int(errwrite) @@ -132,7 +132,7 @@ else: args = comspec + " /c " + args # We create a new job for this process, so that we can kill - # the process and any sub-processes + # the process and any sub-processes self._job = winprocess.CreateJobObject() creationflags |= winprocess.CREATE_SUSPENDED @@ -145,7 +145,7 @@ else: creationflags, winprocess.EnvironmentBlock(env), cwd, startupinfo) - + self._child_created = True self._handle = hp self._thread = ht @@ -173,7 +173,7 @@ else: winprocess.TerminateJobObject(self._job, 127) else: winprocess.TerminateProcess(self._handle, 127) - self.returncode = 127 + self.returncode = 127 else: if group: os.killpg(self.pid, signal.SIGKILL) diff --git a/IPython/deathrow/oldfrontend/process/pipedprocess.py b/IPython/deathrow/oldfrontend/process/pipedprocess.py index 1b145af..85b078c 100644 --- a/IPython/deathrow/oldfrontend/process/pipedprocess.py +++ b/IPython/deathrow/oldfrontend/process/pipedprocess.py @@ -1,6 +1,6 @@ # encoding: utf-8 """ -Object for encapsulating process execution by using callbacks for stdout, +Object for encapsulating process execution by using callbacks for stdout, stderr and stdin. """ __docformat__ = "restructuredtext en" @@ -26,10 +26,10 @@ class PipedProcess(Thread): killing it. """ - def __init__(self, command_string, out_callback, + def __init__(self, command_string, out_callback, end_callback=None,): """ command_string: the command line executed to start the - process. + process. out_callback: the python callable called on stdout/stderr. @@ -43,7 +43,7 @@ class PipedProcess(Thread): self.out_callback = out_callback self.end_callback = end_callback Thread.__init__(self) - + def run(self): """ Start the process and hook up the callbacks. @@ -70,5 +70,5 @@ class PipedProcess(Thread): if self.end_callback is not None: self.end_callback() - + diff --git a/IPython/deathrow/oldfrontend/tests/test_asyncfrontendbase.py b/IPython/deathrow/oldfrontend/tests/test_asyncfrontendbase.py index c009f98..2b59f1d 100644 --- a/IPython/deathrow/oldfrontend/tests/test_asyncfrontendbase.py +++ b/IPython/deathrow/oldfrontend/tests/test_asyncfrontendbase.py @@ -2,20 +2,20 @@ """This file contains unittests for the asyncfrontendbase module.""" #--------------------------------------------------------------------------- -# Copyright (C) 2008-2009 The IPython Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. +# Copyright (C) 2008-2009 The IPython Development Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- -# Imports +# Imports #--------------------------------------------------------------------------- from twisted.trial import unittest - + from IPython.frontend.asyncfrontendbase import AsyncFrontEndBase -from IPython.frontend import frontendbase +from IPython.frontend import frontendbase from IPython.kernel.engineservice import EngineService from IPython.testing.parametric import Parametric, parametric @@ -26,20 +26,20 @@ from IPython.testing.parametric import Parametric, parametric class FrontEndCallbackChecker(AsyncFrontEndBase): """FrontEndBase subclass for checking callbacks""" def __init__(self, engine=None, history=None): - super(FrontEndCallbackChecker, self).__init__(engine=engine, + super(FrontEndCallbackChecker, self).__init__(engine=engine, history=history) self.updateCalled = False self.renderResultCalled = False self.renderErrorCalled = False - + def update_cell_prompt(self, result, blockID=None): self.updateCalled = True return result - + def render_result(self, result): self.renderResultCalled = True return result - + def render_error(self, failure): self.renderErrorCalled = True return failure @@ -48,50 +48,50 @@ class FrontEndCallbackChecker(AsyncFrontEndBase): class TestAsyncFrontendBase(unittest.TestCase): def setUp(self): """Setup the EngineService and FrontEndBase""" - + self.fb = FrontEndCallbackChecker(engine=EngineService()) - + def test_implements_IFrontEnd(self): self.assert_(frontendbase.IFrontEnd.implementedBy( AsyncFrontEndBase)) - + def test_is_complete_returns_False_for_incomplete_block(self): block = """def test(a):""" self.assert_(self.fb.is_complete(block) == False) - + def test_is_complete_returns_True_for_complete_block(self): block = """def test(a): pass""" self.assert_(self.fb.is_complete(block)) block = """a=3""" self.assert_(self.fb.is_complete(block)) - + def test_blockID_added_to_result(self): block = """3+3""" d = self.fb.execute(block, blockID='TEST_ID') d.addCallback(lambda r: self.assert_(r['blockID']=='TEST_ID')) return d - + def test_blockID_added_to_failure(self): block = "raise Exception()" d = self.fb.execute(block,blockID='TEST_ID') d.addErrback(lambda f: self.assert_(f.blockID=='TEST_ID')) return d - + def test_callbacks_added_to_execute(self): d = self.fb.execute("10+10") d.addCallback(lambda r: self.assert_(self.fb.updateCalled and self.fb.renderResultCalled)) return d - + def test_error_callback_added_to_execute(self): """Test that render_error called on execution error.""" - + d = self.fb.execute("raise Exception()") d.addErrback(lambda f: self.assert_(self.fb.renderErrorCalled)) return d - + def test_history_returns_expected_block(self): """Make sure history browsing doesn't fail.""" - + blocks = ["a=1","a=2","a=3"] d = self.fb.execute(blocks[0]) d.addCallback(lambda _: self.fb.execute(blocks[1])) @@ -100,7 +100,7 @@ class TestAsyncFrontendBase(unittest.TestCase): d.addCallback(lambda _: self.assert_(self.fb.get_history_previous("")==blocks[-3])) d.addCallback(lambda _: self.assert_(self.fb.get_history_next()==blocks[-2])) return d - - def test_history_returns_none_at_startup(self): + + def test_history_returns_none_at_startup(self): self.assert_(self.fb.get_history_previous("")==None) self.assert_(self.fb.get_history_next()==None) diff --git a/IPython/deathrow/oldfrontend/tests/test_frontendbase.py b/IPython/deathrow/oldfrontend/tests/test_frontendbase.py index f3f4e5a..ea2d6f6 100644 --- a/IPython/deathrow/oldfrontend/tests/test_frontendbase.py +++ b/IPython/deathrow/oldfrontend/tests/test_frontendbase.py @@ -1,6 +1,6 @@ # encoding: utf-8 """ -Test the basic functionality of frontendbase. +Test the basic functionality of frontendbase. """ __docformat__ = "restructuredtext en" @@ -15,7 +15,7 @@ __docformat__ = "restructuredtext en" from IPython.frontend.frontendbase import FrontEndBase def test_iscomplete(): - """ Check that is_complete works. + """ Check that is_complete works. """ f = FrontEndBase() assert f.is_complete('(a + a)') diff --git a/IPython/deathrow/oldfrontend/tests/test_linefrontend.py b/IPython/deathrow/oldfrontend/tests/test_linefrontend.py index d0d53ac..ea3f42e 100644 --- a/IPython/deathrow/oldfrontend/tests/test_linefrontend.py +++ b/IPython/deathrow/oldfrontend/tests/test_linefrontend.py @@ -1,6 +1,6 @@ # encoding: utf-8 """ -Test the LineFrontEnd +Test the LineFrontEnd """ __docformat__ = "restructuredtext en" diff --git a/IPython/deathrow/oldfrontend/tests/test_prefilterfrontend.py b/IPython/deathrow/oldfrontend/tests/test_prefilterfrontend.py index 432225a..f22bf80 100644 --- a/IPython/deathrow/oldfrontend/tests/test_prefilterfrontend.py +++ b/IPython/deathrow/oldfrontend/tests/test_prefilterfrontend.py @@ -27,7 +27,7 @@ from IPython.testing.globalipapp import get_ipython #----------------------------------------------------------------------------- class TestPrefilterFrontEnd(PrefilterFrontEnd): - + input_prompt_template = string.Template('') output_prompt_template = string.Template('') banner = '' @@ -42,7 +42,7 @@ class TestPrefilterFrontEnd(PrefilterFrontEnd): self.out.truncate() def write(self, string, *args, **kwargs): - self.out.write(string) + self.out.write(string) def _on_enter(self): self.input_buffer += '\n' @@ -151,11 +151,11 @@ def test_capture(): out_value = f.out.getvalue() yield assert_equal, out_value, '1' - + @isolate_ipython0 def test_magic(): """ Test the magic expansion and history. - + This test is fairly fragile and will break when magics change. """ f = TestPrefilterFrontEnd() @@ -188,7 +188,7 @@ def test_help(): assert 'traceback' not in f.last_result ## XXX: ipython doctest magic breaks this. I have no clue why #out_value = f.out.getvalue() - #assert out_value.split()[-1] == 'foobar' + #assert out_value.split()[-1] == 'foobar' @isolate_ipython0 diff --git a/IPython/deathrow/oldfrontend/tests/test_process.py b/IPython/deathrow/oldfrontend/tests/test_process.py index ca49c26..f7ca511 100644 --- a/IPython/deathrow/oldfrontend/tests/test_process.py +++ b/IPython/deathrow/oldfrontend/tests/test_process.py @@ -35,7 +35,7 @@ def test_io(): """ Checks that we can send characters on stdin to the process. """ s = StringIO() - p = PipedProcess(sys.executable + ' -c "a = raw_input(); print a"', + p = PipedProcess(sys.executable + ' -c "a = raw_input(); print a"', out_callback=s.write, ) p.start() test_string = '12345\n' @@ -52,12 +52,12 @@ def test_kill(): """ Check that we can kill a process, and its subprocess. """ s = StringIO() - p = PipedProcess(sys.executable + ' -c "a = raw_input();"', + p = PipedProcess(sys.executable + ' -c "a = raw_input();"', out_callback=s.write, ) p.start() while not hasattr(p, 'process'): sleep(0.1) - p.process.kill() + p.process.kill() assert p.process.poll() is not None diff --git a/IPython/deathrow/oldfrontend/wx/console_widget.py b/IPython/deathrow/oldfrontend/wx/console_widget.py index 970a61d..a556419 100644 --- a/IPython/deathrow/oldfrontend/wx/console_widget.py +++ b/IPython/deathrow/oldfrontend/wx/console_widget.py @@ -36,7 +36,7 @@ import re # FIXME: Need to provide an API for non user-generated display on the # screen: this should not be editable by the user. #------------------------------------------------------------------------------- -# Constants +# Constants #------------------------------------------------------------------------------- _COMPLETE_BUFFER_MARKER = 31 _ERROR_MARKER = 30 @@ -75,7 +75,7 @@ _DEFAULT_STYLE = { # Default scintilla settings 'antialiasing' : True, 'carret_color' : 'BLACK', - 'background_color' :'WHITE', + 'background_color' :'WHITE', #prompt definition 'prompt_in1' : \ @@ -94,14 +94,14 @@ _TRACE_STYLE = 17 # system colors #SYS_COLOUR_BACKGROUND = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND) -# Translation table from ANSI escape sequences to color. +# Translation table from ANSI escape sequences to color. ANSI_STYLES = {'0;30': [0, 'BLACK'], '0;31': [1, 'RED'], '0;32': [2, 'GREEN'], '0;33': [3, 'BROWN'], '0;34': [4, 'BLUE'], '0;35': [5, 'PURPLE'], '0;36': [6, 'CYAN'], '0;37': [7, 'LIGHT GREY'], '1;30': [8, 'DARK GREY'], '1;31': [9, 'RED'], '1;32': [10, 'SEA GREEN'], '1;33': [11, 'YELLOW'], - '1;34': [12, 'LIGHT BLUE'], '1;35': + '1;34': [12, 'LIGHT BLUE'], '1;35': [13, 'MEDIUM VIOLET RED'], '1;36': [14, 'LIGHT STEEL BLUE'], '1;37': [15, 'YELLOW']} @@ -133,7 +133,7 @@ else: 'size' : 10, 'size2': 8, } - + #----------------------------------------------------------------------------- # The console widget class @@ -174,36 +174,36 @@ class ConsoleWidget(editwindow.EditWindow): # Translation table from ANSI escape sequences to color. Override # this to specify your colors. ANSI_STYLES = ANSI_STYLES.copy() - + # Font faces faces = FACES.copy() - + # Store the last time a refresh was done _last_refresh_time = 0 #-------------------------------------------------------------------------- # Public API #-------------------------------------------------------------------------- - - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.WANTS_CHARS, ): editwindow.EditWindow.__init__(self, parent, id, pos, size, style) self.configure_scintilla() # Track if 'enter' key as ever been processed # This variable will only be reallowed until key goes up - self.enter_catched = False + self.enter_catched = False self.current_prompt_pos = 0 self.Bind(wx.EVT_KEY_DOWN, self._on_key_down) self.Bind(wx.EVT_KEY_UP, self._on_key_up) - + def write(self, text, refresh=True): """ Write given text to buffer, while translating the ansi escape sequences. """ - # XXX: do not put print statements to sys.stdout/sys.stderr in - # this method, the print statements will call this method, as + # XXX: do not put print statements to sys.stdout/sys.stderr in + # this method, the print statements will call this method, as # you will end up with an infinit loop title = self.title_pat.split(text) if len(title)>1: @@ -219,7 +219,7 @@ class ConsoleWidget(editwindow.EditWindow): except UnicodeDecodeError: # XXX: Do I really want to skip the exception? pass - + if segments: for ansi_tag, text in zip(segments[::2], segments[1::2]): self.StartStyling(self.GetLength(), 0xFF) @@ -234,8 +234,8 @@ class ConsoleWidget(editwindow.EditWindow): else: style = self.ANSI_STYLES[ansi_tag][0] - self.SetStyling(len(text), style) - + self.SetStyling(len(text), style) + self.GotoPos(self.GetLength()) if refresh: current_time = time.time() @@ -245,9 +245,9 @@ class ConsoleWidget(editwindow.EditWindow): else: wx.Yield() # self.ProcessEvent(wx.PaintEvent()) - self._last_refresh_time = current_time + self._last_refresh_time = current_time + - def new_prompt(self, prompt): """ Prints a prompt at start of line, and move the start of the current block there. @@ -270,7 +270,7 @@ class ConsoleWidget(editwindow.EditWindow): # ASCII-less prompt ascii_less = ''.join(self.color_pat.split(self.last_prompt)[2::2]) return "."*(len(ascii_less)-2) + ': ' - + def scroll_to_bottom(self): maxrange = self.GetScrollRange(wx.VERTICAL) @@ -299,7 +299,7 @@ class ConsoleWidget(editwindow.EditWindow): widget. """ p = self.style.copy() - + # Marker for complete buffer. self.MarkerDefine(_COMPLETE_BUFFER_MARKER, stc.STC_MARK_BACKGROUND, background=p['trace']) @@ -313,14 +313,14 @@ class ConsoleWidget(editwindow.EditWindow): self.SetEOLMode(stc.STC_EOL_LF) - # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside + # Ctrl"+" or Ctrl "-" can be used to zoomin/zoomout the text inside # the widget self.CmdKeyAssign(ord('+'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) self.CmdKeyAssign(ord('-'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) - # Also allow Ctrl Shift "=" for poor non US keyboard users. - self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT, + # Also allow Ctrl Shift "=" for poor non US keyboard users. + self.CmdKeyAssign(ord('='), stc.STC_SCMOD_CTRL|stc.STC_SCMOD_SHIFT, stc.STC_CMD_ZOOMIN) - + # Keys: we need to clear some of the keys the that don't play # well with a console. self.CmdKeyClear(ord('D'), stc.STC_SCMOD_CTRL) @@ -341,7 +341,7 @@ class ConsoleWidget(editwindow.EditWindow): self.SetIndent(4) self.SetTabWidth(4) - # we don't want scintilla's autocompletion to choose + # we don't want scintilla's autocompletion to choose # automaticaly out of a single choice list, as we pop it up # automaticaly self.AutoCompSetChooseSingle(False) @@ -360,11 +360,11 @@ class ConsoleWidget(editwindow.EditWindow): self.title_pat = re.compile('\x1b]0;(.*?)\x07') # styles - + self.SetCaretForeground(p['carret_color']) - + background_color = p['background_color'] - + if 'default' in p: if 'back' not in p['default']: p['default'] += ',back:%s' % background_color @@ -372,20 +372,20 @@ class ConsoleWidget(editwindow.EditWindow): p['default'] += ',size:%s' % self.faces['size'] if 'face' not in p['default']: p['default'] += ',face:%s' % self.faces['mono'] - + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, p['default']) else: - self.StyleSetSpec(stc.STC_STYLE_DEFAULT, - "fore:%s,back:%s,size:%d,face:%s" - % (self.ANSI_STYLES['0;30'][1], + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, + "fore:%s,back:%s,size:%d,face:%s" + % (self.ANSI_STYLES['0;30'][1], background_color, self.faces['size'], self.faces['mono'])) - + self.StyleClearAll() - - # XXX: two lines below are usefull if not using the lexer + + # XXX: two lines below are usefull if not using the lexer #for style in self.ANSI_STYLES.values(): - # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1]) + # self.StyleSetSpec(style[0], "bold,fore:%s" % style[1]) # prompt definition self.prompt_in1 = p['prompt_in1'] @@ -417,25 +417,25 @@ class ConsoleWidget(editwindow.EditWindow): #we add a vertical line to console widget self.SetEdgeMode(stc.STC_EDGE_LINE) self.SetEdgeColumn(edge_column) - - + + #-------------------------------------------------------------------------- # EditWindow API #-------------------------------------------------------------------------- def OnUpdateUI(self, event): - """ Override the OnUpdateUI of the EditWindow class, to prevent + """ Override the OnUpdateUI of the EditWindow class, to prevent syntax highlighting both for faster redraw, and for more consistent look and feel. """ - + #-------------------------------------------------------------------------- # Private API #-------------------------------------------------------------------------- - + def _on_key_down(self, event, skip=True): - """ Key press callback used for correcting behavior for + """ Key press callback used for correcting behavior for console-like interfaces: the cursor is constraint to be after the last prompt. @@ -487,7 +487,7 @@ class ConsoleWidget(editwindow.EditWindow): if event.ShiftDown(): # Try to force execution self.GotoPos(self.GetLength()) - self.write('\n' + self.continuation_prompt(), + self.write('\n' + self.continuation_prompt(), refresh=False) self._on_enter() else: @@ -501,7 +501,7 @@ class ConsoleWidget(editwindow.EditWindow): else: # FIXME: This behavior is not ideal: if the selection # is already started, it will jump. - self.SetSelectionStart(self.current_prompt_pos) + self.SetSelectionStart(self.current_prompt_pos) self.SetSelectionEnd(self.GetCurrentPos()) catched = True @@ -591,15 +591,15 @@ class ConsoleWidget(editwindow.EditWindow): # Jump back up self.GotoPos(self.GetLineEndPosition(line_num-1)) return True - elif ( current_pos > self.GetLineEndPosition(line_num) - and not current_pos == self.GetLength()): + elif ( current_pos > self.GetLineEndPosition(line_num) + and not current_pos == self.GetLength()): # Jump to next line self.GotoPos(current_pos + 1 + len(continuation_prompt)) return True # We re-allow enter event processing - self.enter_catched = False + self.enter_catched = False return False diff --git a/IPython/deathrow/oldfrontend/wx/ipythonx.py b/IPython/deathrow/oldfrontend/wx/ipythonx.py index e4667b9..3f83ab8 100644 --- a/IPython/deathrow/oldfrontend/wx/ipythonx.py +++ b/IPython/deathrow/oldfrontend/wx/ipythonx.py @@ -38,7 +38,7 @@ class IPythonXController(WxController): self._input_state == 'readline': wx.CallAfter(self.ask_exit) else: - WxController._on_key_down(self, event, skip=skip) + WxController._on_key_down(self, event, skip=skip) def ask_exit(self): @@ -56,7 +56,7 @@ class IPythonXController(WxController): else: wx.CallAfter(wx.GetApp().Exit) self.write('Exiting ...', refresh=False) - + def do_exit(self): """ Exits the interpreter, kills the windows. @@ -81,10 +81,10 @@ class IPythonX(wx.Frame): self.Show(True) wx.EVT_CLOSE(self, self.on_close) - + def on_close(self, event): - """ Called on closing the windows. - + """ Called on closing the windows. + Stops the event loop, to close all the child windows. """ wx.CallAfter(wx.Exit) diff --git a/IPython/deathrow/oldfrontend/wx/wx_frontend.py b/IPython/deathrow/oldfrontend/wx/wx_frontend.py index e22c91e..7a80a89 100644 --- a/IPython/deathrow/oldfrontend/wx/wx_frontend.py +++ b/IPython/deathrow/oldfrontend/wx/wx_frontend.py @@ -47,7 +47,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): This class inherits from ConsoleWidget, that provides a console-like widget to provide a text-rendering widget suitable for a terminal. """ - + # Print debug info on what is happening to the console. debug = False @@ -83,7 +83,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): # A flag governing the behavior of the input. Can be: # - # 'readline' for readline-like behavior with a prompt + # 'readline' for readline-like behavior with a prompt # and an edit buffer. # 'raw_input' similar to readline, but triggered by a raw-input # call. Can be used by subclasses to act differently. @@ -111,7 +111,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): #-------------------------------------------------------------------------- # Public API #-------------------------------------------------------------------------- - + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.CLIP_CHILDREN|wx.WANTS_CHARS, @@ -129,7 +129,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): self.style = styledef ConsoleWidget.__init__(self, parent, id, pos, size, style) PrefilterFrontEnd.__init__(self, **kwds) - + # Stick in our own raw_input: self.ipython0.raw_input = self.raw_input @@ -147,14 +147,14 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): self.shell.user_ns['self'] = self # Inject our own raw_input in namespace self.shell.user_ns['raw_input'] = self.raw_input - + def raw_input(self, prompt=''): """ A replacement from python's raw_input. """ self.new_prompt(prompt) self._input_state = 'raw_input' if hasattr(self, '_cursor'): - del self._cursor + del self._cursor self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS)) self.__old_on_enter = self._on_enter event_loop = wx.EventLoop() @@ -162,7 +162,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): event_loop.Exit() self._on_enter = my_on_enter # XXX: Running a separate event_loop. Ugly. - event_loop.Run() + event_loop.Run() self._on_enter = self.__old_on_enter self._input_state = 'buffering' self._cursor = wx.BusyCursor() @@ -177,12 +177,12 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): self._running_process = False event_loop.Exit() - self._running_process = PipedProcess(command_string, + self._running_process = PipedProcess(command_string, out_callback=self.buffered_write, end_callback = _end_system_call) self._running_process.start() # XXX: Running a separate event_loop. Ugly. - event_loop.Run() + event_loop.Run() # Be sure to flush the buffer. self._buffer_flush(event=None) @@ -191,7 +191,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): """ Analyse current and displays useful calltip for it. """ if self.debug: - print >>sys.__stdout__, "do_calltip" + print >>sys.__stdout__, "do_calltip" separators = re.compile('[\s\{\}\[\]\(\)\= ,:]') symbol = self.input_buffer symbol_string = separators.split(symbol)[-1] @@ -217,11 +217,11 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): def _popup_completion(self, create=False): - """ Updates the popup completion menu if it exists. If create is + """ Updates the popup completion menu if it exists. If create is true, open the menu. """ if self.debug: - print >>sys.__stdout__, "_popup_completion" + print >>sys.__stdout__, "_popup_completion" line = self.input_buffer if (self.AutoCompActive() and line and not line[-1] == '.') \ or create==True: @@ -230,7 +230,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): offset = len(self._get_completion_text(line)) self.pop_completion(completions, offset=offset) if self.debug: - print >>sys.__stdout__, completions + print >>sys.__stdout__, completions def buffered_write(self, text): @@ -244,7 +244,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): self._out_buffer.append(text) self._out_buffer_lock.release() if not self._buffer_flush_timer.IsRunning(): - wx.CallAfter(self._buffer_flush_timer.Start, + wx.CallAfter(self._buffer_flush_timer.Start, milliseconds=100, oneShot=True) @@ -257,9 +257,9 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): #-------------------------------------------------------------------------- - # LineFrontEnd interface + # LineFrontEnd interface #-------------------------------------------------------------------------- - + def execute(self, python_string, raw_string=None): self._input_state = 'buffering' self.CallTipCancel() @@ -275,7 +275,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): # Use a callafter to update the display robustly under windows def callback(): self.GotoPos(self.GetLength()) - PrefilterFrontEnd.execute(self, python_string, + PrefilterFrontEnd.execute(self, python_string, raw_string=raw_string) wx.CallAfter(callback) @@ -314,7 +314,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): return True - def save_output_hooks(self): + def save_output_hooks(self): self.__old_raw_input = __builtin__.raw_input PrefilterFrontEnd.save_output_hooks(self) @@ -322,8 +322,8 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): self.SetLexer(stc.STC_LEX_NULL) PrefilterFrontEnd.capture_output(self) __builtin__.raw_input = self.raw_input - - + + def release_output(self): __builtin__.raw_input = self.__old_raw_input PrefilterFrontEnd.release_output(self) @@ -346,11 +346,11 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): for i in range(start_line, self.GetCurrentLine()): self._markers[i] = self.MarkerAdd(i, _ERROR_MARKER) - + #-------------------------------------------------------------------------- - # FrontEndBase interface + # FrontEndBase interface #-------------------------------------------------------------------------- - + def render_error(self, e): start_line = self.GetCurrentLine() self.write('\n' + e + '\n') @@ -359,7 +359,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): #-------------------------------------------------------------------------- - # ConsoleWidget interface + # ConsoleWidget interface #-------------------------------------------------------------------------- def new_prompt(self, prompt): @@ -405,7 +405,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): # get back to a prompt. elif self._input_state == 'subprocess' and ( ( key_code <256 and not event.ControlDown() ) - or + or ( key_code in (ord('d'), ord('D')) and event.ControlDown())): # We are running a process, we redirect keys. @@ -426,7 +426,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): self.do_calltip() elif self.AutoCompActive() and not key_code == ord('\t'): event.Skip() - if key_code in (wx.WXK_BACK, wx.WXK_DELETE): + if key_code in (wx.WXK_BACK, wx.WXK_DELETE): wx.CallAfter(self._popup_completion, create=True) elif not key_code in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_ESCAPE): @@ -455,7 +455,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): # Tab-completion elif key_code == ord('\t'): current_line, current_line_num = self.CurLine - if not re.match(r'^%s\s*$' % self.continuation_prompt(), + if not re.match(r'^%s\s*$' % self.continuation_prompt(), current_line): self.complete_current_input() if self.AutoCompActive(): @@ -491,7 +491,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): ConsoleWidget._on_key_down(self, event, skip=skip) else: ConsoleWidget._on_key_down(self, event, skip=skip) - + def _on_key_up(self, event, skip=True): @@ -503,7 +503,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): wx.CallAfter(self._popup_completion, create=True) else: ConsoleWidget._on_key_up(self, event, skip=skip) - # Make sure the continuation_prompts are always followed by a + # Make sure the continuation_prompts are always followed by a # whitespace new_lines = [] if self._input_state == 'readline': @@ -531,10 +531,10 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): if sys.platform == 'win32': self.input_buffer = self.input_buffer old_prompt_num = self.current_prompt_pos - has_executed = PrefilterFrontEnd._on_enter(self, + has_executed = PrefilterFrontEnd._on_enter(self, new_line_pos=new_line_pos) if old_prompt_num == self.current_prompt_pos: - # No execution has happened + # No execution has happened self.GotoPos(self.GetLineEndPosition(current_line_num + 1)) return has_executed @@ -544,7 +544,7 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): #-------------------------------------------------------------------------- def OnUpdateUI(self, event): - """ Override the OnUpdateUI of the EditWindow class, to prevent + """ Override the OnUpdateUI of the EditWindow class, to prevent syntax highlighting both for faster redraw, and for more consistent look and feel. """ @@ -554,10 +554,10 @@ class WxController(ConsoleWidget, PrefilterFrontEnd): #-------------------------------------------------------------------------- # Private API #-------------------------------------------------------------------------- - + def _buffer_flush(self, event): """ Called by the timer to flush the write buffer. - + This is always called in the mainloop, by the wx timer. """ self._out_buffer_lock.acquire() diff --git a/IPython/deathrow/oldfrontend/zopeinterface.py b/IPython/deathrow/oldfrontend/zopeinterface.py index 2081be3..d3aa94f 100644 --- a/IPython/deathrow/oldfrontend/zopeinterface.py +++ b/IPython/deathrow/oldfrontend/zopeinterface.py @@ -4,7 +4,7 @@ zope.interface mock. If zope is installed, this module provides a zope interface classes, if not it provides mocks for them. -Classes provided: +Classes provided: Interface, Attribute, implements, classProvides """ __docformat__ = "restructuredtext en" diff --git a/IPython/deathrow/tests/test_prefilter.py b/IPython/deathrow/tests/test_prefilter.py index 53fffca..410839f 100644 --- a/IPython/deathrow/tests/test_prefilter.py +++ b/IPython/deathrow/tests/test_prefilter.py @@ -23,7 +23,7 @@ if len(sys.argv) > 1: if sys.argv[1] == '-v': sys.argv = sys.argv[:-1] # IPython is confused by -v, apparently verbose = True - + IPython.Shell.start() ip = IPython.ipapi.get() @@ -41,7 +41,7 @@ def install_mock_handler(name): handler func always returns '', which causes ipython to cease handling the string immediately. That way, that it doesn't echo output, raise exceptions, etc. But do note that testing multiline strings thus gets - a bit hard.""" + a bit hard.""" def mock_handler(self, line, continue_prompt=None, pre=None,iFun=None,theRest=None, obj=None): @@ -76,7 +76,7 @@ def reset_esc_handlers(): s.ESC_SH_CAP : s.handle_shell_escape, } reset_esc_handlers() - + # This is so I don't have to quote over and over. Gotta be a better way. handle_normal = 'handle_normal' handle_auto = 'handle_auto' @@ -96,18 +96,18 @@ def check(assertion, failure_msg): if assertion: if verbose: sys.stdout.write('.') - sys.stdout.flush() + sys.stdout.flush() else: if verbose: sys.stdout.write('F') sys.stdout.flush() failures.append(failure_msg) - + def check_handler(expected_handler, line): """Verify that the expected hander was called (for the given line, passed in for failure reporting). - + Pulled out to its own function so that tests which don't use run_handler_tests can still take advantage of it.""" check(handler_called == expected_handler, @@ -115,16 +115,16 @@ def check_handler(expected_handler, line): "instead %s called" % (expected_handler, repr(line), handler_called)) - + def run_handler_tests(h_tests): """Loop through a series of (input_line, handler_name) pairs, verifying - that, for each ip calls the given handler for the given line. + that, for each ip calls the given handler for the given line. The verbose complaint includes the line passed in, so if that line can include enough info to find the error, the tests are modestly self-documenting. - """ + """ for ln, expected_handler in h_tests: global handler_called handler_called = None @@ -133,7 +133,7 @@ def run_handler_tests(h_tests): def run_one_test(ln, expected_handler): run_handler_tests([(ln, expected_handler)]) - + # ========================================= # Tests @@ -153,12 +153,12 @@ esc_handler_tests = [ ( '%magic', handle_magic), # XXX Possibly, add test for /,; once those are unhooked from %autocall ( 'emacs_mode # PYTHON-MODE', handle_emacs ), - ( ' ', handle_normal), + ( ' ', handle_normal), # Trailing qmark combos. Odd special cases abound # ! always takes priority! - ( '!thing?', handle_shell_escape), + ( '!thing?', handle_shell_escape), ( '!thing arg?', handle_shell_escape), ( '!!thing?', handle_shell_escape), ( '!!thing arg?', handle_shell_escape), @@ -186,8 +186,8 @@ run_handler_tests(esc_handler_tests) old_mls = ip.options.multi_line_specials for ln in [ ' !ls $f multi_line_specials %s', ' !!ls $f multi_line_specials %s', # !! escapes work on mls - # Trailing ? doesn't trigger help: - ' !ls $f multi_line_specials %s ?', + # Trailing ? doesn't trigger help: + ' !ls $f multi_line_specials %s ?', ' !!ls $f multi_line_specials %s ?', ]: ip.options.multi_line_specials = 1 @@ -271,16 +271,16 @@ class AttributeMutator(object): attr_mutator = AttributeMutator() ip.to_user_ns('attr_mutator') -ip.options.autocall = 1 +ip.options.autocall = 1 run_one_test('attr_mutator.foo should mutate', handle_normal) check(attr_mutator.called, 'ofind should be called in absence of assign characters') -for c in list('!=()<>+*/%^&|'): +for c in list('!=()<>+*/%^&|'): attr_mutator.called = False run_one_test('attr_mutator.foo %s should *not* mutate' % c, handle_normal) run_one_test('attr_mutator.foo%s should *not* mutate' % c, handle_normal) - + check(not attr_mutator.called, 'ofind should not be called near character %s' % c) @@ -302,7 +302,7 @@ for ac_state in [0,1]: run_handler_tests([ ("alias_cmd", handle_alias), # XXX See note above - #("alias_head.with_dot unshadowed, autocall=%s" % ac_state, handle_alias), + #("alias_head.with_dot unshadowed, autocall=%s" % ac_state, handle_alias), ("alias_cmd.something aliases must match whole expr", handle_normal), ("alias_cmd /", handle_alias), ]) @@ -331,7 +331,7 @@ import IPython.ipapi class Autocallable(IPython.ipapi.IPyAutocall): def __call__(self): return "called" - + autocallable = Autocallable() ip.to_user_ns('autocallable') @@ -344,13 +344,13 @@ run_handler_tests( [ ( 'len autocall_0', handle_normal), ( 'thing autocall_0', handle_normal), ( 'autocallable', handle_auto), - + # With explicit escapes, callable and non-callables both get expanded, # regardless of the %autocall setting: ( '/len autocall_0', handle_auto), ( ',len autocall_0 b0', handle_auto), ( ';len autocall_0 b0', handle_auto), - + ( '/thing autocall_0', handle_auto), ( ',thing autocall_0 b0', handle_auto), ( ';thing autocall_0 b0', handle_auto), @@ -370,7 +370,7 @@ run_handler_tests( [ # Now, with autocall in default, 'smart' mode -ip.options.autocall = 1 +ip.options.autocall = 1 run_handler_tests( [ # Autocalls without escapes -- only expand if it's callable ( 'len a1', handle_auto), @@ -416,8 +416,8 @@ for b in bin_ops: bin_tests.append((';len %s binop_autocall' % b, handle_auto)) bin_tests.append((',len %s binop_autocall' % b, handle_auto)) bin_tests.append(('/len %s binop_autocall' % b, handle_auto)) - -# Who loves auto-generating tests? + +# Who loves auto-generating tests? run_handler_tests(bin_tests) @@ -431,7 +431,7 @@ run_handler_tests(bin_tests) # ============ num_f = len(failures) if verbose: - print + print print "%s tests run, %s failure%s" % (num_tests, num_f, num_f != 1 and "s" or "") diff --git a/IPython/deathrow/twshell.py b/IPython/deathrow/twshell.py index dd09e7e..e724239 100644 --- a/IPython/deathrow/twshell.py +++ b/IPython/deathrow/twshell.py @@ -10,7 +10,7 @@ import sys from twisted.internet import reactor, threads from IPython.core.ipmaker import make_IPython -from IPython.core.iplib import InteractiveShell +from IPython.core.iplib import InteractiveShell from IPython.utils.ipstruct import Struct import Queue,thread,threading,signal from signal import signal, SIGINT @@ -43,7 +43,7 @@ def hijack_reactor(): return getattr(orig_reactor, name) def __setattr__(self, name, value): return setattr(orig_reactor, name, value) - + internet.reactor = DummyReactor() return orig_reactor @@ -62,12 +62,12 @@ class TwistedInteractiveShell(InteractiveShell): def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), user_ns=None,user_global_ns=None,banner2='',**kw): """Similar to the normal InteractiveShell, but with threading control""" - + InteractiveShell.__init__(self,name,usage,rc,user_ns, user_global_ns,banner2) - # A queue to hold the code to be executed. + # A queue to hold the code to be executed. self.code_queue = Queue.Queue() # Stuff to do at closing time @@ -82,13 +82,13 @@ class TwistedInteractiveShell(InteractiveShell): self.worker_ident = None self.reactor_started = False self.first_run = True - + def runsource(self, source, filename="", symbol="single"): """Compile and run some source in the interpreter. Modified version of code.py's runsource(), to handle threading issues. See the original for full docstring details.""" - + # If Ctrl-C was typed, we reset the flag and return right away if shellglobals.KBINT: shellglobals.KBINT = False @@ -97,7 +97,7 @@ class TwistedInteractiveShell(InteractiveShell): if self._kill: # can't queue new code if we are being killed return True - + try: code = self.compile(source, filename, symbol) except (OverflowError, SyntaxError, ValueError): @@ -109,21 +109,21 @@ class TwistedInteractiveShell(InteractiveShell): # Case 2 return True - # shortcut - if we are in worker thread, or the worker thread is not running, - # execute directly (to allow recursion and prevent deadlock if code is run early + # shortcut - if we are in worker thread, or the worker thread is not running, + # execute directly (to allow recursion and prevent deadlock if code is run early # in IPython construction) - - if (not self.reactor_started or (self.worker_ident is None and not self.first_run) + + if (not self.reactor_started or (self.worker_ident is None and not self.first_run) or self.worker_ident == thread.get_ident() or shellglobals.run_in_frontend(source)): InteractiveShell.runcode(self,code) return # Case 3 # Store code in queue, so the execution thread can handle it. - + self.first_run = False - completed_ev, received_ev = threading.Event(), threading.Event() - + completed_ev, received_ev = threading.Event(), threading.Event() + self.code_queue.put((code,completed_ev, received_ev)) reactor.callLater(0.0,self.runcode) @@ -133,18 +133,18 @@ class TwistedInteractiveShell(InteractiveShell): print "Warning: Timeout for mainloop thread exceeded" print "switching to nonthreaded mode (until mainloop wakes up again)" self.worker_ident = None - else: + else: completed_ev.wait() - + return False def runcode(self): """Execute a code object. Multithreaded wrapper around IPython's runcode().""" - - - # we are in worker thread, stash out the id for runsource() + + + # we are in worker thread, stash out the id for runsource() self.worker_ident = thread.get_ident() if self._kill: @@ -172,12 +172,12 @@ class TwistedInteractiveShell(InteractiveShell): code_to_run = None while 1: try: - code_to_run, completed_ev, received_ev = self.code_queue.get_nowait() + code_to_run, completed_ev, received_ev = self.code_queue.get_nowait() except Queue.Empty: break received_ev.set() - + # Exceptions need to be raised differently depending on which # thread is active. This convoluted try/except is only there to # protect against asynchronous exceptions, to ensure that a shellglobals.KBINT @@ -196,8 +196,8 @@ class TwistedInteractiveShell(InteractiveShell): finally: shellglobals.CODE_RUN = False # allow runsource() return from wait - completed_ev.set() - + completed_ev.set() + # This MUST return true for gtk threading to work return True @@ -237,7 +237,7 @@ class IPShellTwisted: while True and not self.quitting: reactorrun_orig() self.reactor.run = reactorrun - + self.IP = make_IPython(argv, user_ns=user_ns, debug=debug, shell_class=shell_class, on_kill=[mainquit]) @@ -258,8 +258,8 @@ class IPShellTwisted: reactor.callWhenRunning(spawnMainloopThread) self.IP.reactor_started = True self.reactor.run() - print "mainloop ending...." - + print "mainloop ending...." + exists = True diff --git a/IPython/extensions/parallelmagic.py b/IPython/extensions/parallelmagic.py index cd2c557..c69066c 100644 --- a/IPython/extensions/parallelmagic.py +++ b/IPython/extensions/parallelmagic.py @@ -53,19 +53,19 @@ class ParalleMagic(Plugin): def magic_result(self, ipself, parameter_s=''): """Print the result of command i on all engines.. - To use this a :class:`DirectView` instance must be created + To use this a :class:`DirectView` instance must be created and then activated by calling its :meth:`activate` method. Then you can do the following:: In [23]: %result - Out[23]: + Out[23]: [0] In [6]: a = 10 [1] In [6]: a = 10 - + In [22]: %result 6 - Out[22]: + Out[22]: [0] In [6]: a = 10 [1] In [6]: a = 10 @@ -85,14 +85,14 @@ class ParalleMagic(Plugin): def magic_px(self, ipself, parameter_s=''): """Executes the given python command in parallel. - To use this a :class:`DirectView` instance must be created + To use this a :class:`DirectView` instance must be created and then activated by calling its :meth:`activate` method. - + Then you can do the following:: In [24]: %px a = 5 Parallel execution on engine(s): all - Out[24]: + Out[24]: [0] In [7]: a = 5 [1] In [7]: a = 5 @@ -111,7 +111,7 @@ class ParalleMagic(Plugin): def magic_autopx(self, ipself, parameter_s=''): """Toggles auto parallel mode. - To use this a :class:`DirectView` instance must be created + To use this a :class:`DirectView` instance must be created and then activated by calling its :meth:`activate` method. Once this is called, all commands typed at the command line are send to the engines to be executed in parallel. To control which engine @@ -142,7 +142,7 @@ class ParalleMagic(Plugin): self._enable_autopx() def _enable_autopx(self): - """Enable %autopx mode by saving the original run_cell and installing + """Enable %autopx mode by saving the original run_cell and installing pxrun_cell. """ if self.active_view is None: @@ -157,7 +157,7 @@ class ParalleMagic(Plugin): self.autopx = True print "%autopx enabled" - + def _disable_autopx(self): """Disable %autopx by restoring the original InteractiveShell.run_cell. """ @@ -178,7 +178,7 @@ class ParalleMagic(Plugin): stdouts = [result.stdout.rstrip()] else: stdouts = [s.rstrip() for s in result.stdout] - + targets = self.active_view.targets if isinstance(targets, int): targets = [targets] @@ -192,29 +192,29 @@ class ParalleMagic(Plugin): def pxrun_cell(self, raw_cell, store_history=True): """drop-in replacement for InteractiveShell.run_cell. - + This executes code remotely, instead of in the local namespace. See InteractiveShell.run_cell for details. """ - + if (not raw_cell) or raw_cell.isspace(): return - + ipself = self.shell - + with ipself.builtin_trap: cell = ipself.prefilter_manager.prefilter_lines(raw_cell) - + # Store raw and processed history if store_history: - ipself.history_manager.store_inputs(ipself.execution_count, + ipself.history_manager.store_inputs(ipself.execution_count, cell, raw_cell) # ipself.logger.log(cell, raw_cell) - + cell_name = ipself.compile.cache(cell, ipself.execution_count) - + try: code_ast = ast.parse(cell, filename=cell_name) except (OverflowError, SyntaxError, ValueError, TypeError, MemoryError): @@ -232,7 +232,7 @@ class ParalleMagic(Plugin): ipself.history_manager.store_output(ipself.execution_count) # Each cell is a *single* input, regardless of how many lines it has ipself.execution_count += 1 - + if re.search(r'get_ipython\(\)\.magic\(u?"%?autopx', cell): self._disable_autopx() return False diff --git a/IPython/external/Itpl/_Itpl.py b/IPython/external/Itpl/_Itpl.py index 671e9ab..f8985c9 100644 --- a/IPython/external/Itpl/_Itpl.py +++ b/IPython/external/Itpl/_Itpl.py @@ -94,7 +94,7 @@ def matchorfail(text, pos): class Itpl: """Class representing a string with interpolation abilities. - + Upon creation, an instance works out what parts of the format string are literal and what parts need to be evaluated. The evaluation and substitution happens in the namespace of the @@ -106,10 +106,10 @@ class Itpl: The format string is parsed according to the following rules: - 1. A dollar sign and a name, possibly followed by any of: - - an open-paren, and anything up to the matching paren - - an open-bracket, and anything up to the matching bracket - - a period and a name + 1. A dollar sign and a name, possibly followed by any of: + - an open-paren, and anything up to the matching paren + - an open-bracket, and anything up to the matching bracket + - a period and a name any number of times, is evaluated as a Python expression. 2. A dollar sign immediately followed by an open-brace, and @@ -135,7 +135,7 @@ class Itpl: self.format = format self.codec = codec self.encoding_errors = encoding_errors - + namechars = "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; chunks = [] @@ -212,7 +212,7 @@ class Itpl: loc, glob = frame.f_locals, frame.f_globals return self._str(glob,loc) - + class ItplNS(Itpl): """Class representing a string with interpolation abilities. @@ -221,7 +221,7 @@ class ItplNS(Itpl): efficient, as no traceback needs to be extracte. It also allows the caller to supply a different namespace for the interpolation to occur than its own.""" - + def __init__(self, format,globals,locals=None, codec='utf_8',encoding_errors='backslashreplace'): """ItplNS(format,globals[,locals]) -> interpolating string instance. @@ -236,7 +236,7 @@ class ItplNS(Itpl): self.globals = globals self.locals = locals Itpl.__init__(self,format,codec,encoding_errors) - + def __str__(self): """Evaluate and substitute the appropriate parts of the string.""" return self._str(self.globals,self.locals) @@ -260,7 +260,7 @@ class ItplFile: def filter(file=sys.stdout): """Return an ItplFile that filters writes to the given file object. - + 'file = filter(file)' replaces 'file' with a filtered object that has a write() method. When called with no argument, this creates a filter to sys.stdout.""" @@ -268,7 +268,7 @@ def filter(file=sys.stdout): def unfilter(ifile=None): """Return the original file that corresponds to the given ItplFile. - + 'file = unfilter(file)' undoes the effect of 'file = filter(file)'. 'sys.stdout = unfilter()' undoes the effect of 'sys.stdout = filter()'.""" return ifile and ifile.file or sys.stdout.file diff --git a/IPython/external/decorator/_decorator.py b/IPython/external/decorator/_decorator.py index e4b1ce7..2791c1d 100644 --- a/IPython/external/decorator/_decorator.py +++ b/IPython/external/decorator/_decorator.py @@ -3,12 +3,12 @@ ## Copyright (c) 2005, Michele Simionato ## All rights reserved. ## -## Redistributions of source code must retain the above copyright +## Redistributions of source code must retain the above copyright ## notice, this list of conditions and the following disclaimer. ## Redistributions in bytecode form must reproduce the above copyright ## notice, this list of conditions and the following disclaimer in ## the documentation and/or other materials provided with the -## distribution. +## distribution. ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT @@ -39,7 +39,7 @@ except ImportError: # for Python version < 2.5 "A simple replacement of functools.partial" def __init__(self, func, *args, **kw): self.func = func - self.args = args + self.args = args self.keywords = kw def __call__(self, *otherargs, **otherkw): kw = self.keywords.copy() @@ -61,7 +61,7 @@ class FunctionMaker(object): # func can be a class or a callable, but not an instance method self.name = func.__name__ if self.name == '': # small hack for lambda functions - self.name = '_lambda_' + self.name = '_lambda_' self.doc = func.__doc__ self.module = func.__module__ if inspect.isfunction(func): @@ -138,7 +138,7 @@ class FunctionMaker(object): """ if isinstance(obj, str): # "name(signature)" name, rest = obj.strip().split('(', 1) - signature = rest[:-1] #strip a right parens + signature = rest[:-1] #strip a right parens func = None else: # a function name = None @@ -146,9 +146,9 @@ class FunctionMaker(object): func = obj fun = cls(func, name, signature, defaults, doc, module) ibody = '\n'.join(' ' + line for line in body.splitlines()) - return fun.make('def %(name)s(%(signature)s):\n' + ibody, + return fun.make('def %(name)s(%(signature)s):\n' + ibody, evaldict, addsource, **attrs) - + def decorator(caller, func=None): """ decorator(caller) converts a caller function into a decorator; @@ -164,7 +164,7 @@ def decorator(caller, func=None): # otherwise assume caller is a function f = inspect.getargspec(caller)[0][0] # first arg return FunctionMaker.create( - '%s(%s)' % (caller.__name__, f), + '%s(%s)' % (caller.__name__, f), 'return decorator(_call_, %s)' % f, dict(_call_=caller, decorator=decorator), undecorated=caller, doc=caller.__doc__, module=caller.__module__) @@ -191,7 +191,7 @@ def getinfo(func): - doc (the docstring : str) - module (the module name : str) - dict (the function __dict__ : str) - + >>> def f(self, x=1, y=2, *args, **kw): pass >>> info = getinfo(f) @@ -200,7 +200,7 @@ def getinfo(func): 'f' >>> info["argnames"] ['self', 'x', 'y', 'args', 'kw'] - + >>> info["defaults"] (1, 2) @@ -237,7 +237,7 @@ def update_wrapper(wrapper, model, infodict=None): def new_wrapper(wrapper, model): """ An improvement over functools.update_wrapper. The wrapper is a generic - callable object. It works by generating a copy of the wrapper with the + callable object. It works by generating a copy of the wrapper with the right signature and by updating the copy, not the original. Moreovoer, 'model' can be a dictionary with keys 'name', 'doc', 'module', 'dict', 'defaults'. diff --git a/IPython/external/decorators/_decorators.py b/IPython/external/decorators/_decorators.py index 3698a98..75e2ee8 100644 --- a/IPython/external/decorators/_decorators.py +++ b/IPython/external/decorators/_decorators.py @@ -138,9 +138,9 @@ def skipif(skip_condition, msg=None): def get_msg(func,msg=None): """Skip message with information about function being skipped.""" - if msg is None: + if msg is None: out = 'Test skipped due to test condition' - else: + else: out = '\n'+msg return "Skipping test: %s%s" % (func.__name__,out) @@ -167,7 +167,7 @@ def skipif(skip_condition, msg=None): skipper = skipper_gen else: skipper = skipper_func - + return nose.tools.make_decorator(f)(skipper) return skip_decorator diff --git a/IPython/external/guid/_guid.py b/IPython/external/guid/_guid.py index 74859c5..c5a73d0 100644 --- a/IPython/external/guid/_guid.py +++ b/IPython/external/guid/_guid.py @@ -5,41 +5,41 @@ # # Copyright (c) 2006 Conan C. Albrecht # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is furnished +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is furnished # to do so, subject to the following conditions: # -# The above copyright notice and this permission notice shall be included in all +# The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +# FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. ################################################################################################## -### A globally-unique identifier made up of time and ip and 8 digits for a counter: +### A globally-unique identifier made up of time and ip and 8 digits for a counter: ### each GUID is 40 characters wide ### -### A globally unique identifier that combines ip, time, and a counter. Since the -### time is listed first, you can sort records by guid. You can also extract the time -### and ip if needed. +### A globally unique identifier that combines ip, time, and a counter. Since the +### time is listed first, you can sort records by guid. You can also extract the time +### and ip if needed. ### -### Since the counter has eight hex characters, you can create up to +### Since the counter has eight hex characters, you can create up to ### 0xffffffff (4294967295) GUIDs every millisecond. If your processor ### is somehow fast enough to create more than that in a millisecond (looking ### toward the future, of course), the function will wait until the next ### millisecond to return. -### -### GUIDs make wonderful database keys. They require no access to the -### database (to get the max index number), they are extremely unique, and they sort +### +### GUIDs make wonderful database keys. They require no access to the +### database (to get the max index number), they are extremely unique, and they sort ### automatically by time. GUIDs prevent key clashes when merging ### two databases together, combining data, or generating keys in distributed ### systems. @@ -57,9 +57,9 @@ # December 2, 2003 Fixed duplicating GUIDs. Sometimes they duplicate if multiples are created # in the same millisecond (it checks the last 100 GUIDs now and has a larger random part) # December 9, 2003 Fixed MAX_RANDOM, which was going over sys.maxint -# June 12, 2004 Allowed a custom IP address to be sent in rather than always using the -# local IP address. -# November 4, 2005 Changed the random part to a counter variable. Now GUIDs are totally +# June 12, 2004 Allowed a custom IP address to be sent in rather than always using the +# local IP address. +# November 4, 2005 Changed the random part to a counter variable. Now GUIDs are totally # unique and more efficient, as long as they are created by only # on runtime on a given machine. The counter part is after the time # part so it sorts correctly. @@ -87,7 +87,7 @@ import threading #Makes a hex IP from a decimal dot-separated ip (eg: 127.0.0.1) make_hexip = lambda ip: ''.join(["%04x" % long(i) for i in ip.split('.')]) # leave space for ip v6 (65K in each sub) - + MAX_COUNTER = 0xfffffffe counter = 0L firstcounter = MAX_COUNTER @@ -104,7 +104,7 @@ except: # if we don't have an ip, default to someting in the 10.x.x.x private ra ip += '.' + str(rand.randrange(1, 0xffff)) # might as well use IPv6 range if we're making it up hexip = make_hexip(ip) - + ################################# ### Public module functions @@ -121,7 +121,7 @@ def generate(ip=None): # do we need to wait for the next millisecond (are we out of counters?) now = long(time.time() * 1000) - while lasttime == now and counter == firstcounter: + while lasttime == now and counter == firstcounter: time.sleep(.01) now = long(time.time() * 1000) @@ -136,7 +136,7 @@ def generate(ip=None): if counter > MAX_COUNTER: counter = 0 lasttime = now - parts.append("%08x" % (counter)) + parts.append("%08x" % (counter)) # ip part parts.append(hexip) @@ -145,10 +145,10 @@ def generate(ip=None): return ''.join(parts) finally: lock.release() - + def extract_time(guid): - '''Extracts the time portion out of the guid and returns the + '''Extracts the time portion out of the guid and returns the number of seconds since the epoch as a float''' return float(long(guid[0:16], 16)) / 1000.0 diff --git a/IPython/external/mglob/_mglob.py b/IPython/external/mglob/_mglob.py index 44a3b49..8605650 100644 --- a/IPython/external/mglob/_mglob.py +++ b/IPython/external/mglob/_mglob.py @@ -1,26 +1,26 @@ r""" mglob - enhanced file list expansion module -Use as stand-alone utility (for xargs, `backticks` etc.), -or a globbing library for own python programs. Globbing the sys.argv is something +Use as stand-alone utility (for xargs, `backticks` etc.), +or a globbing library for own python programs. Globbing the sys.argv is something that almost every Windows script has to perform manually, and this module is here -to help with that task. Also Unix users will benefit from enhanced modes +to help with that task. Also Unix users will benefit from enhanced modes such as recursion, exclusion, directory omission... -Unlike glob.glob, directories are not included in the glob unless specified +Unlike glob.glob, directories are not included in the glob unless specified with 'dir:' 'expand' is the function to use in python programs. Typical use to expand argv (esp. in windows):: try: - import mglob + import mglob files = mglob.expand(sys.argv[1:]) except ImportError: print "mglob not found; try 'easy_install mglob' for extra features" - files = sys.argv[1:] + files = sys.argv[1:] Note that for unix, shell expands *normal* wildcards (*.cpp, etc.) in argv. -Therefore, you might want to use quotes with normal wildcards to prevent this +Therefore, you might want to use quotes with normal wildcards to prevent this expansion, in order for mglob to see the wildcards and get the wanted behaviour. Not quoting the wildcards is harmless and typically has equivalent results, though. @@ -34,27 +34,27 @@ License: MIT Open Source license globsyntax = """\ This program allows specifying filenames with "mglob" mechanism. Supported syntax in globs (wilcard matching patterns):: - - *.cpp ?ellowo* + + *.cpp ?ellowo* - obvious. Differs from normal glob in that dirs are not included. Unix users might want to write this as: "*.cpp" "?ellowo*" - rec:/usr/share=*.txt,*.doc - - get all *.txt and *.doc under /usr/share, + rec:/usr/share=*.txt,*.doc + - get all *.txt and *.doc under /usr/share, recursively rec:/usr/share - All files under /usr/share, recursively rec:*.py - All .py files under current working dir, recursively - foo + foo - File or dir foo - !*.bak readme* + !*.bak readme* - readme*, exclude files ending with .bak !.svn/ !.hg/ !*_Data/ rec:. - Skip .svn, .hg, foo_Data dirs (and their subdirs) in recurse. Trailing / is the key, \ does not work! Use !.*/ for all hidden. - dir:foo + dir:foo - the directory foo if it exists (not files in foo) - dir:* + dir:* - all directories in current folder foo.py bar.* !h* rec:*.py - Obvious. !h* exclusion only applies for rec:*.py. @@ -71,16 +71,16 @@ __version__ = "0.2" import os,glob,fnmatch,sys,re - + def expand(flist,exp_dirs = False): """ Expand the glob(s) in flist. - + flist may be either a whitespace-separated list of globs/files or an array of globs/files. - + if exp_dirs is true, directory names in glob are expanded to the files contained in them - otherwise, directory names are returned as is. - + """ if isinstance(flist, basestring): import shlex @@ -89,7 +89,7 @@ def expand(flist,exp_dirs = False): denied_set = set() cont_set = set() cur_rejected_dirs = set() - + def recfind(p, pats = ["*"]): denied_dirs = [os.path.dirname(d) for d in denied_set if d.endswith("/")] for (dp,dnames,fnames) in os.walk(p): @@ -103,7 +103,7 @@ def expand(flist,exp_dirs = False): break if deny: continue - + #print "dp",dp bname = os.path.basename(dp) @@ -115,7 +115,7 @@ def expand(flist,exp_dirs = False): if deny: continue - + for f in fnames: matched = False for p in pats: @@ -123,7 +123,7 @@ def expand(flist,exp_dirs = False): matched = True break if matched: - yield os.path.join(dp,f) + yield os.path.join(dp,f) def once_filter(seq): for it in seq: @@ -146,30 +146,30 @@ def expand(flist,exp_dirs = False): if not re.search(pat,cont, re.IGNORECASE): deny = True break - + if not deny: yield it return - + res = [] for ent in flist: ent = os.path.expanduser(os.path.expandvars(ent)) if ent.lower().startswith('rec:'): - fields = ent[4:].split('=') + fields = ent[4:].split('=') if len(fields) == 2: pth, patlist = fields elif len(fields) == 1: if os.path.isdir(fields[0]): # single arg is dir pth, patlist = fields[0], '*' - else: + else: # single arg is pattern pth, patlist = '.', fields[0] - + elif len(fields) == 0: pth, pathlist = '.','*' - + pats = patlist.split(',') res.extend(once_filter(recfind(pth, pats))) # filelist @@ -186,7 +186,7 @@ def expand(flist,exp_dirs = False): # get all files in the specified dir elif os.path.isdir(ent) and exp_dirs: res.extend(once_filter(filter(os.path.isfile,glob.glob(ent + os.sep+"*")))) - + # glob only files elif '*' in ent or '?' in ent: @@ -195,19 +195,19 @@ def expand(flist,exp_dirs = False): else: res.extend(once_filter([ent])) return res - - + + def test(): assert ( - expand("*.py ~/.ipython/*.py rec:/usr/share/doc-base") == - expand( ['*.py', '~/.ipython/*.py', 'rec:/usr/share/doc-base'] ) + expand("*.py ~/.ipython/*.py rec:/usr/share/doc-base") == + expand( ['*.py', '~/.ipython/*.py', 'rec:/usr/share/doc-base'] ) ) - + def main(): if len(sys.argv) < 2: print globsyntax return - + print "\n".join(expand(sys.argv[1:])), def mglob_f(self, arg): @@ -220,8 +220,8 @@ def mglob_f(self, arg): def init_ipython(ip): """ register %mglob for IPython """ mglob_f.__doc__ = globsyntax - ip.define_magic("mglob",mglob_f) - + ip.define_magic("mglob",mglob_f) + # test() if __name__ == "__main__": main() diff --git a/IPython/external/pyparsing/_pyparsing.py b/IPython/external/pyparsing/_pyparsing.py index aa60fd8..a4f0c3b 100644 --- a/IPython/external/pyparsing/_pyparsing.py +++ b/IPython/external/pyparsing/_pyparsing.py @@ -86,7 +86,7 @@ __all__ = [ 'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno', 'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', 'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', +'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', 'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', 'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', 'indentedBlock', 'originalTextFor', @@ -430,7 +430,7 @@ class ParseResults(object): self[k] = v if isinstance(v[0],ParseResults): v[0].__parent = wkref(self) - + self.__toklist += other.__toklist self.__accumNames.update( other.__accumNames ) del other @@ -3269,12 +3269,12 @@ def originalTextFor(expr, asString=True): restore the parsed fields of an HTML start tag into the raw tag text itself, or to revert separate tokens with intervening whitespace back to the original matching input text. Simpler to use than the parse action keepOriginalText, and does not - require the inspect module to chase up the call stack. By default, returns a - string containing the original parsed text. - - If the optional asString argument is passed as False, then the return value is a - ParseResults containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if + require the inspect module to chase up the call stack. By default, returns a + string containing the original parsed text. + + If the optional asString argument is passed as False, then the return value is a + ParseResults containing any results names that were originally matched, and a + single token containing the original matched text from the input string. So if the expression passed to originalTextFor contains expressions with defined results names, you must set asString to False if you want to preserve those results name values.""" @@ -3290,7 +3290,7 @@ def originalTextFor(expr, asString=True): del t["_original_end"] matchExpr.setParseAction(extractText) return matchExpr - + # convenience constants for positional expressions empty = Empty().setName("empty") lineStart = LineStart().setName("lineStart") @@ -3570,7 +3570,7 @@ def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString): ).setParseAction(lambda t:t[0].strip())) else: if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + + content = (Combine(OneOrMore(~ignoreExpr + ~Literal(opener) + ~Literal(closer) + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) ).setParseAction(lambda t:t[0].strip())) diff --git a/IPython/external/qt.py b/IPython/external/qt.py index 61bab37..553123e 100644 --- a/IPython/external/qt.py +++ b/IPython/external/qt.py @@ -40,7 +40,7 @@ if QT_API is None: QT_API = QT_API_PYQT except ImportError: raise ImportError('Cannot import PySide >= 1.0.3 or PyQt4 >= 4.7') - + elif QT_API == QT_API_PYQT: # Note: This must be called *before* PyQt4 is imported. prepare_pyqt4() @@ -62,5 +62,5 @@ elif QT_API == QT_API_PYSIDE: from PySide import QtCore, QtGui, QtSvg else: - raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' % + raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' % (QT_API, QT_API_PYQT, QT_API_PYSIDE)) diff --git a/IPython/external/ssh/tunnel.py b/IPython/external/ssh/tunnel.py index e5148ca..3de70f5 100644 --- a/IPython/external/ssh/tunnel.py +++ b/IPython/external/ssh/tunnel.py @@ -75,7 +75,7 @@ def try_passwordless_ssh(server, keyfile, paramiko=None): """Attempt to make an ssh connection without a password. This is mainly used for requiring password input only once when many tunnels may be connected to the same server. - + If paramiko is None, the default for the platform is chosen. """ if paramiko is None: @@ -130,12 +130,12 @@ def _try_passwordless_paramiko(server, keyfile): def tunnel_connection(socket, addr, server, keyfile=None, password=None, paramiko=None, timeout=60): """Connect a socket to an address via an ssh tunnel. - + This is a wrapper for socket.connect(addr), when addr is not accessible from the local machine. It simply creates an ssh tunnel using the remaining args, and calls socket.connect('tcp://localhost:lport') where lport is the randomly selected local port of the tunnel. - + """ new_url, tunnel = open_tunnel(addr, server, keyfile=keyfile, password=password, paramiko=paramiko, timeout=timeout) socket.connect(new_url) @@ -144,15 +144,15 @@ def tunnel_connection(socket, addr, server, keyfile=None, password=None, paramik def open_tunnel(addr, server, keyfile=None, password=None, paramiko=None, timeout=60): """Open a tunneled connection from a 0MQ url. - + For use inside tunnel_connection. - + Returns ------- - + (url, tunnel): The 0MQ url that has been forwarded, and the tunnel object """ - + lport = select_random_ports(1)[0] transport, addr = addr.split('://') ip,rport = addr.split(':') @@ -163,7 +163,7 @@ def open_tunnel(addr, server, keyfile=None, password=None, paramiko=None, timeou tunnelf = paramiko_tunnel else: tunnelf = openssh_tunnel - + tunnel = tunnelf(lport, rport, server, remoteip=ip, keyfile=keyfile, password=password, timeout=timeout) return 'tcp://127.0.0.1:%i'%lport, tunnel @@ -172,15 +172,15 @@ def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pas on this machine to localhost:rport on server. The tunnel will automatically close when not in use, remaining open for a minimum of timeout seconds for an initial connection. - + This creates a tunnel redirecting `localhost:lport` to `remoteip:rport`, as seen from `server`. - + keyfile and password may be specified, but ssh config is checked for defaults. - + Parameters ---------- - + lport : int local port for connecting to the tunnel from this machine. rport : int @@ -192,11 +192,11 @@ def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pas The remote ip, specifying the destination of the tunnel. Default is localhost, which means that the tunnel would redirect localhost:lport on this machine to localhost:rport on the *server*. - + keyfile : str; path to public key file This specifies a key to be used in ssh login, default None. Regular default ssh keys will be used without specifying this argument. - password : str; + password : str; Your ssh password to the ssh server. Note that if this is left None, you will be prompted for it if passwordless key based login is unavailable. timeout : int [default: 60] @@ -207,7 +207,7 @@ def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pas raise ImportError("pexpect unavailable, use paramiko_tunnel") ssh="ssh " if keyfile: - ssh += "-i " + keyfile + ssh += "-i " + keyfile cmd = ssh + " -f -L 127.0.0.1:%i:%s:%i %s sleep %i"%(lport, remoteip, rport, server, timeout) tunnel = pexpect.spawn(cmd) failed = False @@ -232,7 +232,7 @@ def openssh_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pas password = getpass("%s's password: "%(server)) tunnel.sendline(password) failed = True - + def _split_server(server): if '@' in server: username,server = server.split('@', 1) @@ -248,20 +248,20 @@ def _split_server(server): def paramiko_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, password=None, timeout=60): """launch a tunner with paramiko in a subprocess. This should only be used when shell ssh is unavailable (e.g. Windows). - + This creates a tunnel redirecting `localhost:lport` to `remoteip:rport`, as seen from `server`. - + If you are familiar with ssh tunnels, this creates the tunnel: - + ssh server -L localhost:lport:remoteip:rport - + keyfile and password may be specified, but ssh config is checked for defaults. - - + + Parameters ---------- - + lport : int local port for connecting to the tunnel from this machine. rport : int @@ -273,33 +273,33 @@ def paramiko_tunnel(lport, rport, server, remoteip='127.0.0.1', keyfile=None, pa The remote ip, specifying the destination of the tunnel. Default is localhost, which means that the tunnel would redirect localhost:lport on this machine to localhost:rport on the *server*. - + keyfile : str; path to public key file This specifies a key to be used in ssh login, default None. Regular default ssh keys will be used without specifying this argument. - password : str; + password : str; Your ssh password to the ssh server. Note that if this is left None, you will be prompted for it if passwordless key based login is unavailable. timeout : int [default: 60] The time (in seconds) after which no activity will result in the tunnel closing. This prevents orphaned tunnels from running forever. - + """ if paramiko is None: raise ImportError("Paramiko not available") - + if password is None: if not _try_passwordless_paramiko(server, keyfile): password = getpass("%s's password: "%(server)) - p = Process(target=_paramiko_tunnel, - args=(lport, rport, server, remoteip), + p = Process(target=_paramiko_tunnel, + args=(lport, rport, server, remoteip), kwargs=dict(keyfile=keyfile, password=password)) p.daemon=False p.start() atexit.register(_shutdown_process, p) return p - + def _shutdown_process(p): if p.isalive(): p.terminate() @@ -342,7 +342,7 @@ if sys.platform == 'win32': else: ssh_tunnel = openssh_tunnel - + __all__ = ['tunnel_connection', 'ssh_tunnel', 'openssh_tunnel', 'paramiko_tunnel', 'try_passwordless_ssh'] diff --git a/IPython/frontend/html/notebook/handlers.py b/IPython/frontend/html/notebook/handlers.py index 600861d..e20b278 100644 --- a/IPython/frontend/html/notebook/handlers.py +++ b/IPython/frontend/html/notebook/handlers.py @@ -50,7 +50,7 @@ class AuthenticatedHandler(web.RequestHandler): if not self.application.password: user_id = 'anonymous' return user_id - + class NBBrowserHandler(AuthenticatedHandler): @web.authenticated @@ -176,13 +176,13 @@ class AuthenticatedZMQStreamHandler(ZMQStreamHandler): self.session = Session() self.save_on_message = self.on_message self.on_message = self.on_first_message - + def get_current_user(self): user_id = self.get_secure_cookie("user") if user_id == '' or (user_id is None and not self.application.password): user_id = 'anonymous' return user_id - + def _inject_cookie_message(self, msg): """Inject the first message, which is the document cookie, for authentication.""" @@ -193,14 +193,14 @@ class AuthenticatedZMQStreamHandler(ZMQStreamHandler): self._cookies = Cookie.SimpleCookie(msg) except: logging.warn("couldn't parse cookie string: %s",msg, exc_info=True) - + def on_first_message(self, msg): self._inject_cookie_message(msg) if self.get_current_user() is None: logging.warn("Couldn't authenticate WebSocket connection") raise web.HTTPError(403) self.on_message = self.save_on_message - + class IOPubHandler(AuthenticatedZMQStreamHandler): @@ -209,7 +209,7 @@ class IOPubHandler(AuthenticatedZMQStreamHandler): self._beating = False self.iopub_stream = None self.hb_stream = None - + def on_first_message(self, msg): try: super(IOPubHandler, self).on_first_message(msg) @@ -231,12 +231,12 @@ class IOPubHandler(AuthenticatedZMQStreamHandler): else: self.iopub_stream.on_recv(self._on_zmq_reply) self.start_hb(self.kernel_died) - + def on_message(self, msg): pass def on_close(self): - # This method can be called twice, once by self.kernel_died and once + # This method can be called twice, once by self.kernel_died and once # from the WebSocket close event. If the WebSocket connection is # closed before the ZMQ streams are setup, they could be None. self.stop_hb() @@ -245,7 +245,7 @@ class IOPubHandler(AuthenticatedZMQStreamHandler): self.iopub_stream.close() if self.hb_stream is not None and not self.hb_stream.closed(): self.hb_stream.close() - + def start_hb(self, callback): """Start the heartbeating and call the callback if the kernel dies.""" if not self._beating: diff --git a/IPython/frontend/qt/base_frontend_mixin.py b/IPython/frontend/qt/base_frontend_mixin.py index c4189d3..f59fd50 100644 --- a/IPython/frontend/qt/base_frontend_mixin.py +++ b/IPython/frontend/qt/base_frontend_mixin.py @@ -12,7 +12,7 @@ class BaseFrontendMixin(object): #--------------------------------------------------------------------------- # 'BaseFrontendMixin' concrete interface #--------------------------------------------------------------------------- - + def _get_kernel_manager(self): """ Returns the current kernel manager. """ @@ -34,7 +34,7 @@ class BaseFrontendMixin(object): old_manager.stdin_channel.message_received.disconnect(self._dispatch) old_manager.hb_channel.kernel_died.disconnect( self._handle_kernel_died) - + # Handle the case where the old kernel manager is still listening. if old_manager.channels_running: self._stopped_channels() @@ -77,9 +77,9 @@ class BaseFrontendMixin(object): since_last_heartbeat : float The time since the heartbeat was last received. """ - + def _started_channels(self): - """ Called when the KernelManager channels have started listening or + """ Called when the KernelManager channels have started listening or when the frontend is assigned an already listening KernelManager. """ @@ -93,7 +93,7 @@ class BaseFrontendMixin(object): #--------------------------------------------------------------------------- def _dispatch(self, msg): - """ Calls the frontend handler associated with the message type of the + """ Calls the frontend handler associated with the message type of the given message. """ msg_type = msg['header']['msg_type'] diff --git a/IPython/frontend/qt/console/ansi_code_processor.py b/IPython/frontend/qt/console/ansi_code_processor.py index cb53013..eeee218 100644 --- a/IPython/frontend/qt/console/ansi_code_processor.py +++ b/IPython/frontend/qt/console/ansi_code_processor.py @@ -112,7 +112,7 @@ class AnsiCodeProcessor(object): ---------- command : str The code identifier, i.e. the final character in the sequence. - + params : sequence of integers, optional The parameter codes for the command. """ @@ -143,7 +143,7 @@ class AnsiCodeProcessor(object): def set_osc_code(self, params): """ Set attributes based on OSC (Operating System Command) parameters. - + Parameters ---------- params : sequence of str @@ -162,7 +162,7 @@ class AnsiCodeProcessor(object): self.color_map[color] = self._parse_xterm_color_spec(spec) except (IndexError, ValueError): pass - + def set_sgr_code(self, params): """ Set attributes based on SGR (Select Graphic Rendition) codes. @@ -200,7 +200,7 @@ class AnsiCodeProcessor(object): self.underline = False elif code >= 30 and code <= 37: self.foreground_color = code - 30 - elif code == 38 and params and params.pop(0) == 5: + elif code == 38 and params and params.pop(0) == 5: # xterm-specific: 256 color support. if params: self.foreground_color = params.pop(0) @@ -226,7 +226,7 @@ class AnsiCodeProcessor(object): if spec.startswith('rgb:'): return tuple(map(lambda x: int(x, 16), spec[4:].split('/'))) elif spec.startswith('rgbi:'): - return tuple(map(lambda x: int(float(x) * 255), + return tuple(map(lambda x: int(float(x) * 255), spec[5:].split('/'))) elif spec == '?': raise ValueError('Unsupported xterm color spec') @@ -237,7 +237,7 @@ class AnsiCodeProcessor(object): if special == '\f': self.actions.append(ScrollAction('scroll', 'down', 'page', 1)) return '' - + class QtAnsiCodeProcessor(AnsiCodeProcessor): """ Translates ANSI escape codes into QTextCharFormats. @@ -288,7 +288,7 @@ class QtAnsiCodeProcessor(AnsiCodeProcessor): return QtGui.QColor(*constructor) return None - + def get_format(self): """ Returns a QTextCharFormat that encodes the current style attributes. """ @@ -322,7 +322,7 @@ class QtAnsiCodeProcessor(AnsiCodeProcessor): self.default_color_map = self.darkbg_color_map.copy() if color.value() >= 127: - # Colors appropriate for a terminal with a light background. For + # Colors appropriate for a terminal with a light background. For # now, only use non-bright colors... for i in xrange(8): self.default_color_map[i + 8] = self.default_color_map[i] diff --git a/IPython/frontend/qt/console/bracket_matcher.py b/IPython/frontend/qt/console/bracket_matcher.py index da822c3..f7955b9 100644 --- a/IPython/frontend/qt/console/bracket_matcher.py +++ b/IPython/frontend/qt/console/bracket_matcher.py @@ -9,7 +9,7 @@ class BracketMatcher(QtCore.QObject): """ Matches square brackets, braces, and parentheses based on cursor position. """ - + # Protected class variables. _opening_map = { '(':')', '{':'}', '[':']' } _closing_map = { ')':'(', '}':'{', ']':'[' } @@ -75,7 +75,7 @@ class BracketMatcher(QtCore.QObject): selection = QtGui.QTextEdit.ExtraSelection() cursor = self._text_edit.textCursor() cursor.setPosition(position) - cursor.movePosition(QtGui.QTextCursor.NextCharacter, + cursor.movePosition(QtGui.QTextCursor.NextCharacter, QtGui.QTextCursor.KeepAnchor) selection.cursor = cursor selection.format = self.format diff --git a/IPython/frontend/qt/console/call_tip_widget.py b/IPython/frontend/qt/console/call_tip_widget.py index 48f3654..6c2857f 100644 --- a/IPython/frontend/qt/console/call_tip_widget.py +++ b/IPython/frontend/qt/console/call_tip_widget.py @@ -134,7 +134,7 @@ class CallTipWidget(QtGui.QLabel): doc = doc[:match.end()] + '\n[Documentation continues...]' else: doc = '' - + if call_line: doc = '\n\n'.join([call_line, doc]) return self.show_tip(doc) @@ -147,7 +147,7 @@ class CallTipWidget(QtGui.QLabel): document = text_edit.document() cursor = text_edit.textCursor() search_pos = cursor.position() - 1 - self._start_position, _ = self._find_parenthesis(search_pos, + self._start_position, _ = self._find_parenthesis(search_pos, forward=False) if self._start_position == -1: return False @@ -155,7 +155,7 @@ class CallTipWidget(QtGui.QLabel): # Set the text and resize the widget accordingly. self.setText(tip) self.resize(self.sizeHint()) - + # Locate and show the widget. Place the tip below the current line # unless it would be off the screen. In that case, place it above # the current line. @@ -171,7 +171,7 @@ class CallTipWidget(QtGui.QLabel): self.move(point) self.show() return True - + #-------------------------------------------------------------------------- # Protected interface #-------------------------------------------------------------------------- diff --git a/IPython/frontend/qt/console/completion_lexer.py b/IPython/frontend/qt/console/completion_lexer.py index abadf0c..1d65bf9 100644 --- a/IPython/frontend/qt/console/completion_lexer.py +++ b/IPython/frontend/qt/console/completion_lexer.py @@ -3,7 +3,7 @@ from pygments.token import Token, is_token_subtype class CompletionLexer(object): - """ Uses Pygments and some auxillary information to lex code snippets for + """ Uses Pygments and some auxillary information to lex code snippets for symbol contexts. """ @@ -30,7 +30,7 @@ class CompletionLexer(object): if reversed_tokens and reversed_tokens[0][1].endswith('\n') and \ not string.endswith('\n'): reversed_tokens.pop(0) - + current_op = '' for token, text in reversed_tokens: @@ -71,4 +71,4 @@ class CompletionLexer(object): self._name_separators = list(name_separators) lexer = property(get_lexer, set_lexer) - + diff --git a/IPython/frontend/qt/console/completion_widget.py b/IPython/frontend/qt/console/completion_widget.py index b6db0a7..a11e38c 100644 --- a/IPython/frontend/qt/console/completion_widget.py +++ b/IPython/frontend/qt/console/completion_widget.py @@ -39,15 +39,15 @@ class CompletionWidget(QtGui.QListWidget): if etype == QtCore.QEvent.KeyPress: key, text = event.key(), event.text() - if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, + if key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter, QtCore.Qt.Key_Tab): self._complete_current() return True elif key == QtCore.Qt.Key_Escape: self.hide() return True - elif key in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, - QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown, + elif key in (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, + QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown, QtCore.Qt.Key_Home, QtCore.Qt.Key_End): self.keyPressEvent(event) return True @@ -114,16 +114,16 @@ class CompletionWidget(QtGui.QListWidget): """ cursor = self._text_edit.textCursor() if cursor.position() >= self._start_position: - cursor.setPosition(self._start_position, + cursor.setPosition(self._start_position, QtGui.QTextCursor.KeepAnchor) return cursor - + def _update_current(self): """ Updates the current item based on the current text. """ prefix = self._current_text_cursor().selection().toPlainText() if prefix: - items = self.findItems(prefix, (QtCore.Qt.MatchStartsWith | + items = self.findItems(prefix, (QtCore.Qt.MatchStartsWith | QtCore.Qt.MatchCaseSensitive)) if items: self.setCurrentItem(items[0]) diff --git a/IPython/frontend/qt/console/console_widget.py b/IPython/frontend/qt/console/console_widget.py index 2d29c49..2c8539b 100644 --- a/IPython/frontend/qt/console/console_widget.py +++ b/IPython/frontend/qt/console/console_widget.py @@ -40,11 +40,11 @@ def is_letter_or_number(char): #----------------------------------------------------------------------------- class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): - """ An abstract base class for console-type widgets. This class has + """ An abstract base class for console-type widgets. This class has functionality for: * Maintaining a prompt and editing region - * Providing the traditional Unix-style console keyboard shortcuts + * Providing the traditional Unix-style console keyboard shortcuts * Performing tab completion * Paging text * Handling ANSI escape codes @@ -79,11 +79,11 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): """ ) # NOTE: this value can only be specified during initialization. - paging = Enum(['inside', 'hsplit', 'vsplit', 'custom', 'none'], + paging = Enum(['inside', 'hsplit', 'vsplit', 'custom', 'none'], default_value='inside', config=True, help=""" The type of paging to use. Valid values are: - + 'inside' : The widget pages like a traditional terminal. 'hsplit' : When paging is requested, the widget is split horizontally. The top pane contains the console, and the @@ -264,7 +264,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): key = event.key() if self._control_key_down(event.modifiers()) and \ key in self._ctrl_down_remap: - new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, + new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, self._ctrl_down_remap[key], QtCore.Qt.NoModifier) QtGui.qApp.sendEvent(obj, new_event) @@ -378,10 +378,10 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): """ Returns whether text can be cut to the clipboard. """ cursor = self._control.textCursor() - return (cursor.hasSelection() and - self._in_buffer(cursor.anchor()) and + return (cursor.hasSelection() and + self._in_buffer(cursor.anchor()) and self._in_buffer(cursor.position())) - + def can_paste(self): """ Returns whether text can be pasted from the clipboard. """ @@ -390,7 +390,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): return False def clear(self, keep_input=True): - """ Clear the console. + """ Clear the console. Parameters: ----------- @@ -425,7 +425,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): input. Parameters: - ----------- + ----------- source : str, optional The source to execute. If not specified, the input buffer will be @@ -467,7 +467,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): source += '\n' elif not hidden: self.input_buffer = source - + # Execute the source or show a continuation prompt if it is incomplete. complete = self._is_complete(source, interactive) if hidden: @@ -475,7 +475,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): self._execute(source, hidden) else: error = 'Incomplete noninteractive input: "%s"' - raise RuntimeError(error % source) + raise RuntimeError(error % source) else: if complete: self._append_plain_text('\n') @@ -494,7 +494,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): # Perform actual execution. self._execute(source, hidden) - + else: # Do this inside an edit block so continuation prompts are # removed seamlessly via undo/redo. @@ -505,7 +505,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): cursor.endEditBlock() # Do not do this inside the edit block. It works as expected - # when using a QPlainTextEdit control, but does not have an + # when using a QPlainTextEdit control, but does not have an # effect when using a QTextEdit. I believe this is a Qt bug. self._control.moveCursor(QtGui.QTextCursor.End) @@ -617,7 +617,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): if self._get_cursor().blockNumber() < prompt_cursor.blockNumber(): self._set_cursor(prompt_cursor) self._set_top_cursor(prompt_cursor) - + def redo(self): """ Redo the last operation. If there is no operation to redo, nothing happens. @@ -729,7 +729,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): def _append_custom(self, insert, input, before_prompt=False): """ A low-level method for appending content to the end of the buffer. - + If 'before_prompt' is enabled, the content will be inserted before the current prompt, if there is one. """ @@ -750,7 +750,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): diff = cursor.position() - start_pos self._append_before_prompt_pos += diff self._prompt_pos += diff - + return result def _append_html(self, html, before_prompt=False): @@ -811,7 +811,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): self._cancel_text_completion() if len(items) == 1: - cursor.setPosition(self._control.textCursor().position(), + cursor.setPosition(self._control.textCursor().position(), QtGui.QTextCursor.KeepAnchor) cursor.insertText(items[0]) @@ -825,7 +825,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): if self.gui_completion: cursor.movePosition(QtGui.QTextCursor.Left, n=len(prefix)) - self._completion_widget.show_items(cursor, items) + self._completion_widget.show_items(cursor, items) else: cursor.beginEditBlock() self._append_plain_text('\n') @@ -963,7 +963,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): elif key in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter): intercepted = True - + # Special handling when tab completing in text mode. self._cancel_text_completion() @@ -1076,7 +1076,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): if key == QtCore.Qt.Key_B: self._set_cursor(self._get_word_start_cursor(position)) intercepted = True - + elif key == QtCore.Qt.Key_F: self._set_cursor(self._get_word_end_cursor(position)) intercepted = True @@ -1103,7 +1103,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): elif key == QtCore.Qt.Key_Greater: self._control.moveCursor(QtGui.QTextCursor.End) intercepted = True - + elif key == QtCore.Qt.Key_Less: self._control.setTextCursor(self._get_prompt_cursor()) intercepted = True @@ -1115,7 +1115,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): anchormode = QtGui.QTextCursor.KeepAnchor else: anchormode = QtGui.QTextCursor.MoveAnchor - + if key == QtCore.Qt.Key_Escape: self._keyboard_quit() intercepted = True @@ -1144,19 +1144,19 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): line, col = cursor.blockNumber(), cursor.columnNumber() if line > self._get_prompt_cursor().blockNumber() and \ col == len(self._continuation_prompt): - self._control.moveCursor(QtGui.QTextCursor.PreviousBlock, + self._control.moveCursor(QtGui.QTextCursor.PreviousBlock, mode=anchormode) - self._control.moveCursor(QtGui.QTextCursor.EndOfBlock, + self._control.moveCursor(QtGui.QTextCursor.EndOfBlock, mode=anchormode) intercepted = True # Regular left movement else: intercepted = not self._in_buffer(position - 1) - + elif key == QtCore.Qt.Key_Right: original_block_number = cursor.blockNumber() - cursor.movePosition(QtGui.QTextCursor.Right, + cursor.movePosition(QtGui.QTextCursor.Right, mode=anchormode) if cursor.blockNumber() != original_block_number: cursor.movePosition(QtGui.QTextCursor.Right, @@ -1237,7 +1237,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): return intercepted def _event_filter_page_keypress(self, event): - """ Filter key events for the paging widget to create console-like + """ Filter key events for the paging widget to create console-like interface. """ key = event.key() @@ -1253,7 +1253,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): if key == QtCore.Qt.Key_Greater: self._page_control.moveCursor(QtGui.QTextCursor.End) intercepted = True - + elif key == QtCore.Qt.Key_Less: self._page_control.moveCursor(QtGui.QTextCursor.Start) intercepted = True @@ -1266,15 +1266,15 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): return True elif key in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): - new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, - QtCore.Qt.Key_PageDown, + new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, + QtCore.Qt.Key_PageDown, QtCore.Qt.NoModifier) QtGui.qApp.sendEvent(self._page_control, new_event) return True elif key == QtCore.Qt.Key_Backspace: new_event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, - QtCore.Qt.Key_PageUp, + QtCore.Qt.Key_PageUp, QtCore.Qt.NoModifier) QtGui.qApp.sendEvent(self._page_control, new_event) return True @@ -1300,7 +1300,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): width = self._control.viewport().width() char_width = QtGui.QFontMetrics(self.font).width(' ') displaywidth = max(10, (width / char_width) - 1) - + return columnize(items, separator, displaywidth) def _get_block_plain_text(self, block): @@ -1308,7 +1308,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): """ cursor = QtGui.QTextCursor(block) cursor.movePosition(QtGui.QTextCursor.StartOfBlock) - cursor.movePosition(QtGui.QTextCursor.EndOfBlock, + cursor.movePosition(QtGui.QTextCursor.EndOfBlock, QtGui.QTextCursor.KeepAnchor) return cursor.selection().toPlainText() @@ -1316,7 +1316,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): """ Convenience method that returns a cursor for the current position. """ return self._control.textCursor() - + def _get_end_cursor(self): """ Convenience method that returns a cursor for the last character. """ @@ -1482,7 +1482,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): self._set_top_cursor(cursor) cursor.joinPreviousEditBlock() cursor.deletePreviousChar() - + format = self._ansi_processor.get_format() cursor.insertText(substring, format) else: @@ -1545,7 +1545,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): self._cancel_text_completion() else: self.input_buffer = '' - + def _page(self, text, html=False): """ Displays text using the pager if it exceeds the height of the viewport. @@ -1591,7 +1591,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): def _prompt_started(self): """ Called immediately after a new prompt is displayed. """ - # Temporarily disable the maximum block count to permit undo/redo and + # Temporarily disable the maximum block count to permit undo/redo and # to ensure that the prompt position does not change due to truncation. self._control.document().setMaximumBlockCount(0) self._control.setUndoRedoEnabled(True) @@ -1613,7 +1613,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): self._control.moveCursor(QtGui.QTextCursor.End) def _readline(self, prompt='', callback=None): - """ Reads one line of input from the user. + """ Reads one line of input from the user. Parameters ---------- @@ -1669,7 +1669,7 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): else: self._continuation_prompt = prompt self._continuation_prompt_html = None - + def _set_cursor(self, cursor): """ Convenience method to set the current cursor. """ @@ -1699,16 +1699,16 @@ class ConsoleWidget(LoggingConfigurable, QtGui.QWidget): as plain text, though ANSI color codes will be handled. newline : bool, optional (default True) - If set, a new line will be written before showing the prompt if + If set, a new line will be written before showing the prompt if there is not already a newline at the end of the buffer. """ # Save the current end position to support _append*(before_prompt=True). cursor = self._get_end_cursor() self._append_before_prompt_pos = cursor.position() - + # Insert a preliminary newline, if necessary. if newline and cursor.position() > 0: - cursor.movePosition(QtGui.QTextCursor.Left, + cursor.movePosition(QtGui.QTextCursor.Left, QtGui.QTextCursor.KeepAnchor) if cursor.selection().toPlainText() != '\n': self._append_plain_text('\n') diff --git a/IPython/frontend/qt/console/frontend_widget.py b/IPython/frontend/qt/console/frontend_widget.py index 88d6d8c..41ef33d 100644 --- a/IPython/frontend/qt/console/frontend_widget.py +++ b/IPython/frontend/qt/console/frontend_widget.py @@ -103,7 +103,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): # Emitted when an exit request has been received from the kernel. exit_requested = QtCore.Signal() - + # Protected class variables. _CallTipRequest = namedtuple('_CallTipRequest', ['id', 'pos']) _CompletionRequest = namedtuple('_CompletionRequest', ['id', 'pos']) @@ -115,7 +115,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): #--------------------------------------------------------------------------- # 'object' interface #--------------------------------------------------------------------------- - + def __init__(self, *args, **kw): super(FrontendWidget, self).__init__(*args, **kw) @@ -151,9 +151,9 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): # Connect signal handlers. document = self._control.document() document.contentsChange.connect(self._document_contents_change) - + # Set flag for whether we are connected via localhost. - self._local_kernel = kw.get('local_kernel', + self._local_kernel = kw.get('local_kernel', FrontendWidget._local_kernel) #--------------------------------------------------------------------------- @@ -193,7 +193,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): self._hidden = hidden if not hidden: self.executing.emit(source) - + def _prompt_started_hook(self): """ Called immediately after a new prompt is displayed. """ @@ -394,7 +394,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): # to spaces so that output looks as expected regardless of this # widget's tab width. text = msg['content']['data'].expandtabs(8) - + self._append_plain_text(text, before_prompt=True) self._control.moveCursor(QtGui.QTextCursor.End) @@ -432,7 +432,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): self.reset() def _started_channels(self): - """ Called when the KernelManager channels have started listening or + """ Called when the KernelManager channels have started listening or when the frontend is assigned an already listening KernelManager. """ self.reset() @@ -467,7 +467,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): def reset(self): """ Resets the widget to its initial state. Similar to ``clear``, but also re-writes the banner and aborts execution if necessary. - """ + """ if self._executing: self._executing = False self._request_info['execute'] = None @@ -550,7 +550,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): '.'.join(context), # text self._get_input_buffer_cursor_line(), # line self._get_input_buffer_cursor_column(), # cursor_pos - self.input_buffer) # block + self.input_buffer) # block pos = self._get_cursor().position() info = self._CompletionRequest(msg_id, pos) self._request_info['complete'] = info @@ -561,7 +561,7 @@ class FrontendWidget(HistoryConsoleWidget, BaseFrontendMixin): """ if cursor is None: cursor = self._get_cursor() - cursor.movePosition(QtGui.QTextCursor.StartOfBlock, + cursor.movePosition(QtGui.QTextCursor.StartOfBlock, QtGui.QTextCursor.KeepAnchor) text = cursor.selection().toPlainText() return self._completion_lexer.get_context(text) diff --git a/IPython/frontend/qt/console/history_console_widget.py b/IPython/frontend/qt/console/history_console_widget.py index c464898..6a54ae3 100644 --- a/IPython/frontend/qt/console/history_console_widget.py +++ b/IPython/frontend/qt/console/history_console_widget.py @@ -17,7 +17,7 @@ class HistoryConsoleWidget(ConsoleWidget): # an edit is made to a multi-line input buffer. To override the lock, use # Shift in conjunction with the standard history cycling keys. history_lock = Bool(False, config=True) - + #--------------------------------------------------------------------------- # 'object' interface #--------------------------------------------------------------------------- @@ -45,7 +45,7 @@ class HistoryConsoleWidget(ConsoleWidget): source, hidden, interactive) if executed and not hidden: - # Save the command unless it was an empty string or was identical + # Save the command unless it was an empty string or was identical # to the previous command. history = history.rstrip() if history and (not self._history or self._history[-1] != history): @@ -90,7 +90,7 @@ class HistoryConsoleWidget(ConsoleWidget): # search. cursor = self._get_prompt_cursor() if self._history_prefix: - cursor.movePosition(QtGui.QTextCursor.Right, + cursor.movePosition(QtGui.QTextCursor.Right, n=len(self._history_prefix)) else: cursor.movePosition(QtGui.QTextCursor.EndOfLine) @@ -111,7 +111,7 @@ class HistoryConsoleWidget(ConsoleWidget): return False # Perform the search. - replaced = self.history_next(self._history_prefix, + replaced = self.history_next(self._history_prefix, as_prefix=not shift_modifier) # Emulate readline: keep the cursor position fixed for a prefix @@ -120,7 +120,7 @@ class HistoryConsoleWidget(ConsoleWidget): # input buffer is set.) if self._history_prefix and replaced: cursor = self._get_prompt_cursor() - cursor.movePosition(QtGui.QTextCursor.Right, + cursor.movePosition(QtGui.QTextCursor.Right, n=len(self._history_prefix)) self._set_cursor(cursor) @@ -155,7 +155,7 @@ class HistoryConsoleWidget(ConsoleWidget): or (not as_prefix and substring in history): replace = True break - + if replace: self._store_edits() self._history_index = index @@ -186,7 +186,7 @@ class HistoryConsoleWidget(ConsoleWidget): or (not as_prefix and substring in history): replace = True break - + if replace: self._store_edits() self._history_index = index @@ -203,7 +203,7 @@ class HistoryConsoleWidget(ConsoleWidget): The (maximum) number of history items to get. """ return self._history[-n:] - + #--------------------------------------------------------------------------- # 'HistoryConsoleWidget' protected interface #--------------------------------------------------------------------------- @@ -211,8 +211,8 @@ class HistoryConsoleWidget(ConsoleWidget): def _history_locked(self): """ Returns whether history movement is locked. """ - return (self.history_lock and - (self._get_edited_history(self._history_index) != + return (self.history_lock and + (self._get_edited_history(self._history_index) != self.input_buffer) and (self._get_prompt_cursor().blockNumber() != self._get_end_cursor().blockNumber())) diff --git a/IPython/frontend/qt/console/ipython_widget.py b/IPython/frontend/qt/console/ipython_widget.py index 05f2a9e..d9ce346 100644 --- a/IPython/frontend/qt/console/ipython_widget.py +++ b/IPython/frontend/qt/console/ipython_widget.py @@ -81,7 +81,7 @@ class IPythonWidget(FrontendWidget): 2. Pygments: .c, .k, .o, etc. (see PygmentsHighlighter) 3. IPython: .error, .in-prompt, .out-prompt, etc """) - + syntax_style = Unicode(config=True, help=""" If not empty, use this Pygments style for syntax highlighting. @@ -110,12 +110,12 @@ class IPythonWidget(FrontendWidget): #--------------------------------------------------------------------------- # 'object' interface #--------------------------------------------------------------------------- - + def __init__(self, *args, **kw): super(IPythonWidget, self).__init__(*args, **kw) # IPythonWidget protected variables. - self._payload_handlers = { + self._payload_handlers = { self._payload_source_edit : self._handle_payload_edit, self._payload_source_exit : self._handle_payload_exit, self._payload_source_page : self._handle_payload_page, @@ -151,7 +151,7 @@ class IPythonWidget(FrontendWidget): # but the last component and then suitably decreasing the offset # between the current cursor position and the start of completion. if len(matches) > 1 and matches[0][:offset] == text: - parts = re.split(r'[./\\]', text) + parts = re.split(r'[./\\]', text) sep_count = len(parts) - 1 if sep_count: chop_length = sum(map(len, parts[:sep_count])) + sep_count @@ -228,7 +228,7 @@ class IPythonWidget(FrontendWidget): """ The base handler for the ``display_data`` message. """ self.log.debug("display: %s", msg.get('content', '')) - # For now, we don't display data from other frontends, but we + # For now, we don't display data from other frontends, but we # eventually will as this allows all frontends to monitor the display # data. But we need to figure out how to handle this in the GUI. if not self._hidden and self._is_from_this_session(msg): @@ -302,13 +302,13 @@ class IPythonWidget(FrontendWidget): # text field. Readline-based frontends do get a real text field which # they can use. text = '' - + # Send the completion request to the kernel msg_id = self.kernel_manager.shell_channel.complete( text, # text self._get_input_buffer_cursor_line(), # line self._get_input_buffer_cursor_column(), # cursor_pos - self.input_buffer) # block + self.input_buffer) # block pos = self._get_cursor().position() info = self._CompletionRequest(msg_id, pos) self._request_info['complete'] = info @@ -332,7 +332,7 @@ class IPythonWidget(FrontendWidget): self._append_html(traceback) else: # This is the fallback for now, using plain text with ansi escapes - self._append_plain_text(traceback) + self._append_plain_text(traceback) def _process_execute_payload(self, item): """ Reimplemented to dispatch payloads to handler methods. @@ -344,7 +344,7 @@ class IPythonWidget(FrontendWidget): else: handler(item) return True - + def _show_interpreter_prompt(self, number=None): """ Reimplemented for IPython-style prompts. """ @@ -383,7 +383,7 @@ class IPythonWidget(FrontendWidget): # Remove the old prompt and insert a new prompt. cursor = QtGui.QTextCursor(block) cursor.movePosition(QtGui.QTextCursor.Right, - QtGui.QTextCursor.KeepAnchor, + QtGui.QTextCursor.KeepAnchor, self._previous_prompt_obj.length) prompt = self._make_in_prompt(previous_prompt_number) self._prompt = self._insert_html_fetching_plain_text( @@ -485,7 +485,7 @@ class IPythonWidget(FrontendWidget): space_count = len(prompt.lstrip('\n')) - len(end_chars) body = ' ' * space_count + end_chars return '%s' % body - + def _make_out_prompt(self, number): """ Given a prompt number, returns an HTML Out prompt. """ diff --git a/IPython/frontend/qt/console/kill_ring.py b/IPython/frontend/qt/console/kill_ring.py index d6f3f69..98d1d09 100644 --- a/IPython/frontend/qt/console/kill_ring.py +++ b/IPython/frontend/qt/console/kill_ring.py @@ -14,7 +14,7 @@ from IPython.external.qt import QtCore, QtGui class KillRing(object): """ A generic Emacs-style kill ring. """ - + def __init__(self): self.clear() @@ -41,7 +41,7 @@ class KillRing(object): def rotate(self): """ Rotate the kill ring, then yank back the new top. - + Returns: -------- A text string or None. @@ -50,7 +50,7 @@ class KillRing(object): if self._index >= 0: return self._ring[self._index] return None - + class QtKillRing(QtCore.QObject): """ A kill ring attached to Q[Plain]TextEdit. """ @@ -109,12 +109,12 @@ class QtKillRing(QtCore.QObject): if text: self._skip_cursor = True cursor = self._text_edit.textCursor() - cursor.movePosition(QtGui.QTextCursor.Left, - QtGui.QTextCursor.KeepAnchor, + cursor.movePosition(QtGui.QTextCursor.Left, + QtGui.QTextCursor.KeepAnchor, n = len(self._prev_yank)) cursor.insertText(text) self._prev_yank = text - + #-------------------------------------------------------------------------- # Protected interface #-------------------------------------------------------------------------- diff --git a/IPython/frontend/qt/console/pygments_highlighter.py b/IPython/frontend/qt/console/pygments_highlighter.py index 02551de..a80bcec 100644 --- a/IPython/frontend/qt/console/pygments_highlighter.py +++ b/IPython/frontend/qt/console/pygments_highlighter.py @@ -79,7 +79,7 @@ class PygmentsBlockUserData(QtGui.QTextBlockUserData): def __repr__(self): attrs = ['syntax_stack'] - kwds = ', '.join([ '%s=%r' % (attr, getattr(self, attr)) + kwds = ', '.join([ '%s=%r' % (attr, getattr(self, attr)) for attr in attrs ]) return 'PygmentsBlockUserData(%s)' % kwds @@ -172,7 +172,7 @@ class PygmentsHighlighter(QtGui.QSyntaxHighlighter): return result def _get_format_from_document(self, token, document): - """ Returns a QTextCharFormat for token by + """ Returns a QTextCharFormat for token by """ code, html = self._formatter._format_lines([(token, 'dummy')]).next() self._document.setHtml(html) diff --git a/IPython/frontend/qt/console/rich_ipython_widget.py b/IPython/frontend/qt/console/rich_ipython_widget.py index b55d0a4..1166fe6 100644 --- a/IPython/frontend/qt/console/rich_ipython_widget.py +++ b/IPython/frontend/qt/console/rich_ipython_widget.py @@ -56,7 +56,7 @@ class RichIPythonWidget(IPythonWidget): if svg is not None: menu.addSeparator() menu.addAction('Copy SVG', lambda: svg_to_clipboard(svg)) - menu.addAction('Save SVG As...', + menu.addAction('Save SVG As...', lambda: save_svg(svg, self._control)) else: menu = super(RichIPythonWidget, self)._context_menu_make(pos) @@ -209,7 +209,7 @@ class RichIPythonWidget(IPythonWidget): # Chop stand-alone header from matplotlib SVG offset = svg.find(" -1) - + return svg[offset:] else: diff --git a/IPython/frontend/qt/kernelmanager.py b/IPython/frontend/qt/kernelmanager.py index f243114..4e68562 100644 --- a/IPython/frontend/qt/kernelmanager.py +++ b/IPython/frontend/qt/kernelmanager.py @@ -51,20 +51,20 @@ class QtShellSocketChannel(SocketChannelQObject, ShellSocketChannel): # Emitted when the first reply comes back. first_reply = QtCore.Signal() - # Used by the first_reply signal logic to determine if a reply is the + # Used by the first_reply signal logic to determine if a reply is the # first. _handlers_called = False #--------------------------------------------------------------------------- # 'ShellSocketChannel' interface #--------------------------------------------------------------------------- - + def call_handlers(self, msg): """ Reimplemented to emit signals instead of making callbacks. """ # Emit the generic signal. self.message_received.emit(msg) - + # Emit signals for specialized message types. msg_type = msg['header']['msg_type'] signal = getattr(self, msg_type, None) @@ -115,7 +115,7 @@ class QtSubSocketChannel(SocketChannelQObject, SubSocketChannel): #--------------------------------------------------------------------------- # 'SubSocketChannel' interface #--------------------------------------------------------------------------- - + def call_handlers(self, msg): """ Reimplemented to emit signals instead of making callbacks. """ @@ -153,7 +153,7 @@ class QtStdInSocketChannel(SocketChannelQObject, StdInSocketChannel): """ # Emit the generic signal. self.message_received.emit(msg) - + # Emit signals for specialized message types. msg_type = msg['header']['msg_type'] if msg_type == 'input_request': @@ -208,7 +208,7 @@ class QtKernelManager(KernelManager, SuperQObject): super(QtKernelManager, self).start_kernel(*args, **kw) #------ Channel management ------------------------------------------------- - + def start_channels(self, *args, **kw): """ Reimplemented to emit signal. """ @@ -217,7 +217,7 @@ class QtKernelManager(KernelManager, SuperQObject): def stop_channels(self): """ Reimplemented to emit signal. - """ + """ super(QtKernelManager, self).stop_channels() self.stopped_channels.emit() @@ -233,7 +233,7 @@ class QtKernelManager(KernelManager, SuperQObject): #--------------------------------------------------------------------------- # Protected interface #--------------------------------------------------------------------------- - + def _first_reply(self): """ Unpauses the heartbeat channel when the first reply is received on the execute channel. Note that this will *not* start the heartbeat diff --git a/IPython/frontend/qt/rich_text.py b/IPython/frontend/qt/rich_text.py index f7a97f4..d6071da 100644 --- a/IPython/frontend/qt/rich_text.py +++ b/IPython/frontend/qt/rich_text.py @@ -87,7 +87,7 @@ class HtmlExporter(object): ib.setShortcut('I') eb = QtGui.QPushButton("&External") eb.setShortcut('E') - box = QtGui.QMessageBox(QtGui.QMessageBox.Question, + box = QtGui.QMessageBox(QtGui.QMessageBox.Question, dialog.windowTitle(), msg) box.setInformativeText(info) box.addButton(ib, QtGui.QMessageBox.NoRole) @@ -190,12 +190,12 @@ def default_image_tag(match, path = None, format = "png"): """ Return (X)HTML mark-up for the image-tag given by match. This default implementation merely removes the image, and exists mostly - for documentation purposes. More information than is present in the Qt + for documentation purposes. More information than is present in the Qt HTML is required to supply the images. Parameters ---------- - match : re.SRE_Match + match : re.SRE_Match A match to an HTML image tag as exported by Qt, with match.group("Name") containing the matched image ID. @@ -212,7 +212,7 @@ def default_image_tag(match, path = None, format = "png"): def fix_html(html): """ Transforms a Qt-generated HTML string into a standards-compliant one. - + Parameters: ----------- html : str, diff --git a/IPython/frontend/terminal/embed.py b/IPython/frontend/terminal/embed.py index 4d26351..60b7a82 100644 --- a/IPython/frontend/terminal/embed.py +++ b/IPython/frontend/terminal/embed.py @@ -53,7 +53,7 @@ def kill_embedded(self,parameter_s=''): figured out what you needed from it, you may then kill it and the program will then continue to run without the interactive shell interfering again. """ - + kill = ask_yes_no("Are you sure you want to kill this embedded instance " "(y/n)? [y/N] ",'n') if kill: @@ -206,7 +206,7 @@ class InteractiveShellEmbed(TerminalInteractiveShell): with nested(self.builtin_trap, self.display_trap): self.interact(display_banner=display_banner) - + # now, purge out the user namespace from anything we might have added # from the caller's local namespace delvar = self.user_ns.pop @@ -234,7 +234,7 @@ def embed(**kwargs): d = 40 embed - Full customization can be done by passing a :class:`Struct` in as the + Full customization can be done by passing a :class:`Struct` in as the config argument. """ config = kwargs.get('config') diff --git a/IPython/frontend/terminal/interactiveshell.py b/IPython/frontend/terminal/interactiveshell.py index abe0328..74f88c9 100644 --- a/IPython/frontend/terminal/interactiveshell.py +++ b/IPython/frontend/terminal/interactiveshell.py @@ -117,7 +117,7 @@ class TerminalInteractiveShell(InteractiveShell): self.system = self.system_piped else: self.system = self.system_raw - + self.init_term_title() self.init_usage(usage) self.init_banner(banner1, banner2, display_banner) @@ -214,13 +214,13 @@ class TerminalInteractiveShell(InteractiveShell): If an optional banner argument is given, it will override the internally created default banner. """ - + with nested(self.builtin_trap, self.display_trap): while 1: try: self.interact(display_banner=display_banner) - #self.interact_with_readline() + #self.interact_with_readline() # XXX for testing of a readline-decoupled repl loop, call # interact_with_readline above break @@ -232,23 +232,23 @@ class TerminalInteractiveShell(InteractiveShell): def interact(self, display_banner=None): """Closely emulate the interactive Python console.""" - # batch run -> do not interact + # batch run -> do not interact if self.exit_now: return if display_banner is None: display_banner = self.display_banner - + if isinstance(display_banner, basestring): self.show_banner(display_banner) elif display_banner: self.show_banner() more = False - + # Mark activity in the builtins __builtin__.__dict__['__IPYTHON__active'] += 1 - + if self.has_readline: self.readline_startup_hook(self.pre_readline) # exit_now is set by a call to %Exit or %Quit, through the @@ -263,7 +263,7 @@ class TerminalInteractiveShell(InteractiveShell): self.showtraceback() if self.autoindent: self.rl_do_indent = True - + else: try: prompt = self.hooks.generate_prompt(False) @@ -276,7 +276,7 @@ class TerminalInteractiveShell(InteractiveShell): break if self.autoindent: self.rl_do_indent = False - + except KeyboardInterrupt: #double-guard against keyboardinterrupts during kbdint handling try: @@ -310,7 +310,7 @@ class TerminalInteractiveShell(InteractiveShell): if not more: source_raw = self.input_splitter.source_raw_reset()[1] self.run_cell(source_raw) - + # We are off again... __builtin__.__dict__['__IPYTHON__active'] -= 1 @@ -335,7 +335,7 @@ class TerminalInteractiveShell(InteractiveShell): if self.has_readline: self.set_readline_completer() - + try: line = py3compat.str_to_unicode(self.raw_input_original(prompt)) except ValueError: @@ -351,7 +351,7 @@ class TerminalInteractiveShell(InteractiveShell): if num_ini_spaces(line) > self.indent_current_nsp: line = line[self.indent_current_nsp:] self.indent_current_nsp = 0 - + return line #------------------------------------------------------------------------- @@ -378,7 +378,7 @@ class TerminalInteractiveShell(InteractiveShell): try: f = file(err.filename) try: - # This should be inside a display_trap block and I + # This should be inside a display_trap block and I # think it is. sys.displayhook(f.read()) finally: @@ -392,10 +392,10 @@ class TerminalInteractiveShell(InteractiveShell): if e.filename in ('','','', '','', None): - + return False try: - if (self.autoedit_syntax and + if (self.autoedit_syntax and not self.ask_yes_no('Return to editor to correct syntax error? ' '[Y/n] ','y')): return False @@ -468,7 +468,7 @@ class TerminalInteractiveShell(InteractiveShell): self.ask_exit() else: self.ask_exit() - + #------------------------------------------------------------------------ # Magic overrides #------------------------------------------------------------------------ @@ -486,38 +486,38 @@ class TerminalInteractiveShell(InteractiveShell): @skip_doctest def magic_cpaste(self, parameter_s=''): """Paste & execute a pre-formatted code block from clipboard. - + You must terminate the block with '--' (two minus-signs) alone on the - line. You can also provide your own sentinel with '%paste -s %%' ('%%' + line. You can also provide your own sentinel with '%paste -s %%' ('%%' is the new sentinel for this operation) - + The block is dedented prior to execution to enable execution of method definitions. '>' and '+' characters at the beginning of a line are ignored, to allow pasting directly from e-mails, diff files and doctests (the '...' continuation prompt is also stripped). The executed block is also assigned to variable named 'pasted_block' for later editing with '%edit pasted_block'. - + You can also pass a variable name as an argument, e.g. '%cpaste foo'. - This assigns the pasted block to variable 'foo' as string, without + This assigns the pasted block to variable 'foo' as string, without dedenting or executing it (preceding >>> and + is still stripped) - + '%cpaste -r' re-executes the block previously entered by cpaste. - - Do not be alarmed by garbled output on Windows (it's a readline bug). - Just press enter and type -- (and press enter again) and the block + + Do not be alarmed by garbled output on Windows (it's a readline bug). + Just press enter and type -- (and press enter again) and the block will be what was just pasted. - + IPython statements (magics, shell escapes) are not supported (yet). See also -------- paste: automatically pull code from clipboard. - + Examples -------- :: - + In [8]: %cpaste Pasting code; enter '--' alone on the line to stop. :>>> a = ["world!", "Hello"] @@ -525,13 +525,13 @@ class TerminalInteractiveShell(InteractiveShell): :-- Hello world! """ - + opts,args = self.parse_options(parameter_s,'rs:',mode='string') par = args.strip() if opts.has_key('r'): self._rerun_pasted() return - + sentinel = opts.get('s','--') block = self._strip_pasted_lines_for_code( @@ -541,7 +541,7 @@ class TerminalInteractiveShell(InteractiveShell): def magic_paste(self, parameter_s=''): """Paste & execute a pre-formatted code block from clipboard. - + The text is pulled directly from the clipboard without user intervention and printed back on the screen before execution (unless the -q flag is given to force quiet mode). @@ -552,18 +552,18 @@ class TerminalInteractiveShell(InteractiveShell): doctests (the '...' continuation prompt is also stripped). The executed block is also assigned to variable named 'pasted_block' for later editing with '%edit pasted_block'. - + You can also pass a variable name as an argument, e.g. '%paste foo'. - This assigns the pasted block to variable 'foo' as string, without + This assigns the pasted block to variable 'foo' as string, without dedenting or executing it (preceding >>> and + is still stripped) Options ------- - + -r: re-executes the block previously entered by cpaste. -q: quiet mode: do not echo the pasted text back to the terminal. - + IPython statements (magics, shell escapes) are not supported (yet). See also @@ -586,9 +586,9 @@ class TerminalInteractiveShell(InteractiveShell): if not block.endswith('\n'): write('\n') write("## -- End pasted text --\n") - + self._execute_block(block, par) - + def showindentationerror(self): super(TerminalInteractiveShell, self).showindentationerror() print("If you want to paste code into IPython, try the %paste magic function.") diff --git a/IPython/frontend/terminal/ipapp.py b/IPython/frontend/terminal/ipapp.py index 8db0974..fa24971 100755 --- a/IPython/frontend/terminal/ipapp.py +++ b/IPython/frontend/terminal/ipapp.py @@ -201,7 +201,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): PlainTextFormatter, Completer, ] - + subcommands = Dict(dict( qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp', """Launch the IPython Qt Console.""" @@ -216,7 +216,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): "Start a kernel without an attached frontend." ), )) - + # *do* autocreate requested profile, but don't create the config file. auto_create=Bool(True) # configurables @@ -253,7 +253,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): def _force_interact_changed(self, name, old, new): if new: self.interact = True - + def _file_to_run_changed(self, name, old, new): if new and not self.force_interact: self.interact = False @@ -283,7 +283,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): sub = '--pylab='+gui argv.pop(idx+1) argv[idx] = sub - + return super(TerminalIPythonApp, self).parse_command_line(argv) def initialize(self, argv=None): @@ -313,7 +313,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): sys.path.insert(0, '') # Create an InteractiveShell instance. - # shell.display_banner should always be False for the terminal + # shell.display_banner should always be False for the terminal # based app, because we call shell.show_banner() by hand below # so the banner shows *before* all extension loading stuff. self.shell = TerminalInteractiveShell.instance(config=self.config, diff --git a/IPython/lib/clipboard.py b/IPython/lib/clipboard.py index f42b93b..cc6fb2a 100644 --- a/IPython/lib/clipboard.py +++ b/IPython/lib/clipboard.py @@ -18,10 +18,10 @@ def win32_clipboard_get(): message = ("Getting text from the clipboard requires the pywin32 " "extensions: http://sourceforge.net/projects/pywin32/") raise TryNext(message) - win32clipboard.OpenClipboard() - text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT) + win32clipboard.OpenClipboard() + text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT) # FIXME: convert \r\n to \n? - win32clipboard.CloseClipboard() + win32clipboard.CloseClipboard() return text def osx_clipboard_get(): diff --git a/IPython/lib/deepreload.py b/IPython/lib/deepreload.py index d9f3ca1..81ac6bf 100644 --- a/IPython/lib/deepreload.py +++ b/IPython/lib/deepreload.py @@ -9,11 +9,11 @@ To enable it type:: You can then disable it with:: __builtin__.reload = deepreload.original_reload - + Alternatively, you can add a dreload builtin alongside normal reload with:: __builtin__.dreload = deepreload.reload - + This code is almost entirely based on knee.py from the standard library. """ @@ -30,7 +30,7 @@ import sys # Replacement for __import__() def deep_import_hook(name, globals=None, locals=None, fromlist=None, level=-1): - # For now level is ignored, it's just there to prevent crash + # For now level is ignored, it's just there to prevent crash # with from __future__ import absolute_import parent = determine_parent(globals) q, tail = find_head_package(parent, name) @@ -94,7 +94,7 @@ def load_tail(q, tail): # to: mname = m.__name__ # This needs more testing!!! (I don't understand this module too well) - + #print '** head,tail=|%s|->|%s|, mname=|%s|' % (head,tail,mname) # dbg m = import_module(head, mname, m) if not m: @@ -125,25 +125,25 @@ def import_module(partname, fqname, parent): global found_now if found_now.has_key(fqname): try: - return sys.modules[fqname] + return sys.modules[fqname] except KeyError: pass - + print 'Reloading', fqname #, sys.excepthook is sys.__excepthook__, \ #sys.displayhook is sys.__displayhook__ - + found_now[fqname] = 1 try: fp, pathname, stuff = imp.find_module(partname, parent and parent.__path__) except ImportError: return None - + try: m = imp.load_module(fqname, fp, pathname, stuff) finally: if fp: fp.close() - + if parent: setattr(parent, partname, m) @@ -168,14 +168,14 @@ except AttributeError: def reload(module, exclude=['sys', '__builtin__', '__main__']): """Recursively reload all modules used in the given module. Optionally takes a list of modules to exclude from reloading. The default exclude - list contains sys, __main__, and __builtin__, to prevent, e.g., resetting + list contains sys, __main__, and __builtin__, to prevent, e.g., resetting display, exception, and io hooks. """ global found_now for i in exclude: found_now[i] = 1 original_import = __builtin__.__import__ - __builtin__.__import__ = deep_import_hook + __builtin__.__import__ = deep_import_hook try: ret = deep_reload_hook(module) finally: diff --git a/IPython/lib/demo.py b/IPython/lib/demo.py index e11e339..b118fee 100644 --- a/IPython/lib/demo.py +++ b/IPython/lib/demo.py @@ -44,7 +44,7 @@ subclassing more convenient. Their docstrings below have some more details: - post_cmd(): run right after the execution of each block. If the block raises an exception, this is NOT called. - + Operation ========= @@ -72,14 +72,14 @@ The supported tags are: word 'stop', to help visually distinguish the blocks in a text editor: # --- stop --- - + # silent Make a block execute silently (and hence automatically). Typically used in cases where you have some boilerplate or initialization code which you need executed but do not want to be seen in the demo. - + # auto Make a block execute automatically, but still being printed. Useful for @@ -116,7 +116,7 @@ been added to the "docs/examples/core" directory. Just cd to this directory in an IPython session, and type:: %run demo-exercizer.py - + and then follow the directions. Example @@ -200,14 +200,14 @@ class Demo(object): IPython.Demo? in IPython to see it). Inputs: - + - src is either a file, or file-like object, or a string that can be resolved to a filename. Optional inputs: - + - title: a string to use as the demo name. Of most use when the demo - you are making comes from an object that has no filename, or if you + you are making comes from an object that has no filename, or if you want an alternate denotation distinct from the filename. - arg_str(''): a string of arguments, internally converted to a list @@ -238,7 +238,7 @@ class Demo(object): self.sys_argv = [src] + shlex.split(arg_str) self.auto_all = auto_all self.src = src - + # get a few things from ipython. While it's a bit ugly design-wise, # it ensures that things like color scheme and the like are always in # sync with the ipython mode being used. This class is only meant to @@ -268,7 +268,7 @@ class Demo(object): def reload(self): """Reload source from disk and initialize state.""" self.fload() - + self.src = self.fobj.read() src_b = [b.strip() for b in self.re_stop.split(self.src) if b] self._silent = [bool(self.re_silent.findall(b)) for b in src_b] @@ -315,7 +315,7 @@ class Demo(object): """Get the current block index, validating and checking status. Returns None if the demo is finished""" - + if index is None: if self.finished: print >>io.stdout, 'Demo finished. Use .reset() if you want to rerun it.' @@ -369,7 +369,7 @@ class Demo(object): # that the default demo.edit() call opens up the sblock we've last run if index>0: index -= 1 - + filename = self.shell.mktempfile(self.src_blocks[index]) self.shell.hooks.editor(filename,1) new_block = file_read(filename) @@ -379,7 +379,7 @@ class Demo(object): self.block_index = index # call to run with the newly edited index self() - + def show(self,index=None): """Show a single block on screen""" @@ -414,7 +414,7 @@ class Demo(object): """Execute a string with one or more lines of code""" exec source in self.user_ns - + def __call__(self,index=None): """run a block of the demo. @@ -452,7 +452,7 @@ class Demo(object): self.post_cmd() finally: sys.argv = save_argv - + except: self.ip_showtb(filename=self.fname) else: @@ -499,7 +499,7 @@ class IPythonDemo(Demo): """Execute a string with one or more lines of code""" self.shell.run_cell(source) - + class LineDemo(Demo): """Demo where each line is executed as a separate block. @@ -513,7 +513,7 @@ class LineDemo(Demo): Note: the input can not have *any* indentation, which means that only single-lines of input are accepted, not even function definitions are valid.""" - + def reload(self): """Reload source from disk and initialize state.""" # read data and parse into blocks @@ -542,26 +542,26 @@ class IPythonLineDemo(IPythonDemo,LineDemo): class ClearMixin(object): """Use this mixin to make Demo classes with less visual clutter. - + Demos using this mixin will clear the screen before every block and use blank marquees. - + Note that in order for the methods defined here to actually override those of the classes it's mixed with, it must go /first/ in the inheritance tree. For example: - + class ClearIPDemo(ClearMixin,IPythonDemo): pass - + will provide an IPythonDemo class with the mixin's features. """ - + def marquee(self,txt='',width=78,mark='*'): """Blank marquee that returns '' no matter what the input.""" return '' - + def pre_cmd(self): """Method called before executing each block. - + This one simply clears the screen.""" from IPython.utils.terminal import term_clear term_clear() diff --git a/IPython/lib/display.py b/IPython/lib/display.py index 2aad730..b25ef56 100644 --- a/IPython/lib/display.py +++ b/IPython/lib/display.py @@ -5,30 +5,30 @@ Authors : MinRK class YouTubeVideo(object): """Class for embedding a YouTube Video in an IPython session, based on its video id. - + e.g. to embed the video on this page: - + http://www.youtube.com/watch?v=foo - + you would do: - + vid = YouTubeVideo("foo") display(vid) """ - + def __init__(self, id, width=400, height=300): self.id = id self.width = width self.height = height - + def _repr_html_(self): """return YouTube embed iframe for this video id""" return """ - """%(self.width, self.height, self.id) diff --git a/IPython/lib/guisupport.py b/IPython/lib/guisupport.py index 6ffa50a..068a470 100644 --- a/IPython/lib/guisupport.py +++ b/IPython/lib/guisupport.py @@ -8,11 +8,11 @@ session. IPython has two different types of GUI integration: 1. The terminal based IPython supports GUI event loops through Python's PyOS_InputHook. PyOS_InputHook is a hook that Python calls periodically whenever raw_input is waiting for a user to type code. We implement GUI - support in the terminal by setting PyOS_InputHook to a function that + support in the terminal by setting PyOS_InputHook to a function that iterates the event loop for a short while. It is important to note that in this situation, the real GUI event loop is NOT run in the normal manner, so you can't use the normal means to detect that it is running. -2. In the two process IPython kernel/frontend, the GUI event loop is run in +2. In the two process IPython kernel/frontend, the GUI event loop is run in the kernel. In this case, the event loop is run in the normal manner by calling the function or method of the GUI toolkit that starts the event loop. @@ -47,7 +47,7 @@ we proposed the following informal protocol: *must* use its value. If it has not been set, you can query the toolkit in the normal manner. * If you want GUI support and no one else has created an application or - started the event loop you *must* do this. We don't want projects to + started the event loop you *must* do this. We don't want projects to attempt to defer these things to someone else if they themselves need it. The functions below implement this logic for each GUI toolkit. If you need diff --git a/IPython/lib/inputhookglut.py b/IPython/lib/inputhookglut.py index 83c61da..7d59cc7 100644 --- a/IPython/lib/inputhookglut.py +++ b/IPython/lib/inputhookglut.py @@ -45,7 +45,7 @@ from timeit import default_timer as clock # Frame per second : 60 # Should probably be an IPython option glut_fps = 60 - + # Display mode : double buffeed + rgba + depth # Should probably be an IPython option @@ -56,10 +56,10 @@ glut_display_mode = (glut.GLUT_DOUBLE | glutMainLoopEvent = None if sys.platform == 'darwin': try: - glutCheckLoop = platform.createBaseFunction( - 'glutCheckLoop', dll=platform.GLUT, resultType=None, + glutCheckLoop = platform.createBaseFunction( + 'glutCheckLoop', dll=platform.GLUT, resultType=None, argTypes=[], - doc='glutCheckLoop( ) -> None', + doc='glutCheckLoop( ) -> None', argNames=(), ) except AttributeError: @@ -125,7 +125,7 @@ def glut_int_handler(signum, frame): #----------------------------------------------------------------------------- def inputhook_glut(): """Run the pyglet event loop by processing pending events only. - + This keeps processing pending events until stdin is ready. After processing all pending events, a call to time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%. This sleep time should be tuned @@ -148,7 +148,7 @@ def inputhook_glut(): while not stdin_ready(): glutMainLoopEvent() # We need to sleep at this point to keep the idle CPU load - # low. However, if sleep to long, GUI response is poor. As + # low. However, if sleep to long, GUI response is poor. As # a compromise, we watch how often GUI events are being processed # and switch between a short and long sleep time. Here are some # stats useful in helping to tune this. diff --git a/IPython/lib/inputhookpyglet.py b/IPython/lib/inputhookpyglet.py index 45fbc03..b5a8361 100644 --- a/IPython/lib/inputhookpyglet.py +++ b/IPython/lib/inputhookpyglet.py @@ -68,7 +68,7 @@ else: def inputhook_pyglet(): """Run the pyglet event loop by processing pending events only. - + This keeps processing pending events until stdin is ready. After processing all pending events, a call to time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%. This sleep time should be tuned @@ -87,7 +87,7 @@ def inputhook_pyglet(): flip(window) # We need to sleep at this point to keep the idle CPU load - # low. However, if sleep to long, GUI response is poor. As + # low. However, if sleep to long, GUI response is poor. As # a compromise, we watch how often GUI events are being processed # and switch between a short and long sleep time. Here are some # stats useful in helping to tune this. diff --git a/IPython/lib/inputhookwx.py b/IPython/lib/inputhookwx.py index 65f7c3f..8e3d25b 100644 --- a/IPython/lib/inputhookwx.py +++ b/IPython/lib/inputhookwx.py @@ -46,8 +46,8 @@ def stdin_ready(): def inputhook_wx1(): """Run the wx event loop by processing pending events only. - - This approach seems to work, but its performance is not great as it + + This approach seems to work, but its performance is not great as it relies on having PyOS_InputHook called regularly. """ try: @@ -92,16 +92,16 @@ class EventLoopRunner(object): def inputhook_wx2(): """Run the wx event loop, polling for stdin. - + This version runs the wx eventloop for an undetermined amount of time, during which it periodically checks to see if anything is ready on stdin. If anything is ready on stdin, the event loop exits. - + The argument to elr.Run controls how often the event loop looks at stdin. This determines the responsiveness at the keyboard. A setting of 1000 enables a user to type at most 1 char per second. I have found that a - setting of 10 gives good keyboard response. We can shorten it further, - but eventually performance would suffer from calling select/kbhit too + setting of 10 gives good keyboard response. We can shorten it further, + but eventually performance would suffer from calling select/kbhit too often. """ try: @@ -118,9 +118,9 @@ def inputhook_wx2(): def inputhook_wx3(): """Run the wx event loop by processing pending events only. - + This is like inputhook_wx1, but it keeps processing pending events - until stdin is ready. After processing all pending events, a call to + until stdin is ready. After processing all pending events, a call to time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%. This sleep time should be tuned though for best performance. """ @@ -146,7 +146,7 @@ def inputhook_wx3(): evtloop.Dispatch() app.ProcessIdle() # We need to sleep at this point to keep the idle CPU load - # low. However, if sleep to long, GUI response is poor. As + # low. However, if sleep to long, GUI response is poor. As # a compromise, we watch how often GUI events are being processed # and switch between a short and long sleep time. Here are some # stats useful in helping to tune this. diff --git a/IPython/lib/irunner.py b/IPython/lib/irunner.py index 4ca9318..004c388 100755 --- a/IPython/lib/irunner.py +++ b/IPython/lib/irunner.py @@ -59,11 +59,11 @@ def pexpect_monkeypatch(): self.close() will trigger an exception because it tries to call os.close(), and os is now None. """ - + if pexpect.__version__[:3] >= '2.2': # No need to patch, fix is already the upstream version. return - + def __del__(self): """This makes sure that no system resources are left open. Python only garbage collects Python objects. OS file descriptors @@ -84,7 +84,7 @@ pexpect_monkeypatch() # The generic runner class class InteractiveRunner(object): """Class to run a sequence of commands through an interactive program.""" - + def __init__(self,program,prompts,args=None,out=sys.stdout,echo=True): """Construct a runner. @@ -121,7 +121,7 @@ class InteractiveRunner(object): increase this value (it is measured in seconds). Note that this variable is not honored at all by older versions of pexpect. """ - + self.program = program self.prompts = prompts if args is None: args = [] @@ -201,7 +201,7 @@ class InteractiveRunner(object): else: # Quiet mode, all writes are no-ops write = lambda s: None - + c = self.child prompts = c.compile_pattern_list(self.prompts) prompt_idx = c.expect_list(prompts) @@ -214,7 +214,7 @@ class InteractiveRunner(object): if get_output: output = [] store_output = output.append - + for cmd in source: # skip blank lines for all matches to the 'main' prompt, while the # secondary prompts do not @@ -233,7 +233,7 @@ class InteractiveRunner(object): write(c.before) end_normal = False break - + write(c.before) # With an echoing process, the output we get in c.before contains @@ -266,11 +266,11 @@ class InteractiveRunner(object): # hangs on the second invocation. if c.isalive(): c.send('\n') - + # Return any requested output if get_output: return ''.join(output) - + def main(self,argv=None): """Run as a command-line script.""" @@ -301,7 +301,7 @@ class IPythonRunner(InteractiveRunner): pexpect need to be matched to the actual prompts, so user-customized prompts would break this. """ - + def __init__(self,program = 'ipython',args=None,out=sys.stdout,echo=True): """New runner, optionally passing the ipython command to use.""" args0 = ['--colors=NoColor', @@ -327,10 +327,10 @@ class PythonRunner(InteractiveRunner): class SAGERunner(InteractiveRunner): """Interactive SAGE runner. - - WARNING: this runner only works if you manually adjust your SAGE + + WARNING: this runner only works if you manually adjust your SAGE configuration so that the 'color' option in the configuration file is set to - 'NoColor', because currently the prompt matching regexp does not identify + 'NoColor', because currently the prompt matching regexp does not identify color sequences.""" def __init__(self,program='sage',args=None,out=sys.stdout,echo=True): @@ -354,7 +354,7 @@ class RunnerFactory(object): def __init__(self,out=sys.stdout): """Instantiate a code runner.""" - + self.out = out self.runner = None self.runnerClass = None @@ -363,7 +363,7 @@ class RunnerFactory(object): self.runnerClass = runnerClass self.runner = runnerClass(out=self.out) return self.runner - + def __call__(self,fname): """Return a runner for the given filename.""" diff --git a/IPython/lib/tests/test_irunner_pylab_magic.py b/IPython/lib/tests/test_irunner_pylab_magic.py index 71292a7..eb3f352 100644 --- a/IPython/lib/tests/test_irunner_pylab_magic.py +++ b/IPython/lib/tests/test_irunner_pylab_magic.py @@ -1,5 +1,5 @@ """Test suite for pylab_import_all magic -Modified from the irunner module but using regex. +Modified from the irunner module but using regex. """ # Global to make tests extra verbose and help debugging @@ -24,7 +24,7 @@ class RunnerTestCase(unittest.TestCase): def _test_runner(self,runner,source,output): """Test that a given runner's input/output match.""" - + runner.run_source(source) out = self.out.getvalue() #out = '' diff --git a/IPython/nbformat/v2/__init__.py b/IPython/nbformat/v2/__init__.py index 4989a0d..8e41b05 100644 --- a/IPython/nbformat/v2/__init__.py +++ b/IPython/nbformat/v2/__init__.py @@ -47,7 +47,7 @@ def parse_filename(fname): format (json/py) and the notebook name. This logic can be summarized as follows: - * notebook.ipynb -> (notebook.ipynb, notebook, json) + * notebook.ipynb -> (notebook.ipynb, notebook, json) * notebook.json -> (notebook.json, notebook, json) * notebook.py -> (notebook.py, notebook, py) * notebook -> (notebook.ipynb, notebook, json) @@ -61,8 +61,8 @@ def parse_filename(fname): Returns ------- - (fname, name, format) : (unicode, unicode, unicode) - The filename, notebook name and format. + (fname, name, format) : (unicode, unicode, unicode) + The filename, notebook name and format. """ if fname.endswith(u'.ipynb'): format = u'json' diff --git a/IPython/nbformat/v2/nbbase.py b/IPython/nbformat/v2/nbbase.py index c55df07..d4ef94e 100644 --- a/IPython/nbformat/v2/nbbase.py +++ b/IPython/nbformat/v2/nbbase.py @@ -1,6 +1,6 @@ """The basic dict based notebook format. -The Python representation of a notebook is a nested structure of +The Python representation of a notebook is a nested structure of dictionary subclasses that support attribute access (IPython.utils.ipstruct.Struct). The functions in this module are merely helpers to build the structs in the right form. @@ -47,7 +47,7 @@ def from_dict(d): def new_output(output_type=None, output_text=None, output_png=None, - output_html=None, output_svg=None, output_latex=None, output_json=None, + output_html=None, output_svg=None, output_latex=None, output_json=None, output_javascript=None, output_jpeg=None, prompt_number=None, etype=None, evalue=None, traceback=None): """Create a new code cell with input and output""" diff --git a/IPython/nbformat/v2/nbpy.py b/IPython/nbformat/v2/nbpy.py index 1a36862..5cb5d2b 100644 --- a/IPython/nbformat/v2/nbpy.py +++ b/IPython/nbformat/v2/nbpy.py @@ -46,7 +46,7 @@ class PyReader(NotebookReader): cells.append(cell) state = u'codecell' cell_lines = [] - elif line.startswith(u'# '): + elif line.startswith(u'# '): cell = self.new_cell(state, cell_lines) if cell is not None: cells.append(cell) diff --git a/IPython/parallel/apps/ipclusterapp.py b/IPython/parallel/apps/ipclusterapp.py index 44d4ca4..0d77895 100755 --- a/IPython/parallel/apps/ipclusterapp.py +++ b/IPython/parallel/apps/ipclusterapp.py @@ -38,7 +38,7 @@ from IPython.core.profiledir import ProfileDir from IPython.utils.daemonize import daemonize from IPython.utils.importstring import import_item from IPython.utils.sysinfo import num_cpus -from IPython.utils.traitlets import (Int, Unicode, Bool, CFloat, Dict, List, +from IPython.utils.traitlets import (Int, Unicode, Bool, CFloat, Dict, List, DottedObjectName) from IPython.parallel.apps.baseapp import ( @@ -114,7 +114,7 @@ Start an ipython cluster by its profile name or cluster directory. Cluster directories contain configuration, log and security related files and are named using the convention 'profile_' and should be creating using the 'start' -subcommand of 'ipcluster'. If your cluster directory is in +subcommand of 'ipcluster'. If your cluster directory is in the cwd or the ipython directory, you can simply refer to it using its profile name, 'ipcluster start --n=4 --profile=`, otherwise use the 'profile-dir' option. @@ -123,7 +123,7 @@ stop_help = """Stop a running IPython cluster Stop a running ipython cluster by its profile name or cluster directory. Cluster directories are named using the convention -'profile_'. If your cluster directory is in +'profile_'. If your cluster directory is in the cwd or the ipython directory, you can simply refer to it using its profile name, 'ipcluster stop --profile=`, otherwise use the '--profile-dir' option. @@ -135,7 +135,7 @@ by profile name or cluster directory. Cluster directories contain configuration, log and security related files and are named using the convention 'profile_' and should be creating using the 'start' -subcommand of 'ipcluster'. If your cluster directory is in +subcommand of 'ipcluster'. If your cluster directory is in the cwd or the ipython directory, you can simply refer to it using its profile name, 'ipcluster engines --n=4 --profile=`, otherwise use the 'profile-dir' option. @@ -150,12 +150,12 @@ class IPClusterStop(BaseParallelApplication): description = stop_help examples = _stop_examples config_file_name = Unicode(default_config_file_name) - + signal = Int(signal.SIGINT, config=True, help="signal to use for stopping processes.") - + aliases = Dict(stop_aliases) - + def start(self): """Start the app for the stop subcommand.""" try: @@ -168,7 +168,7 @@ class IPClusterStop(BaseParallelApplication): # can watch for to learn how I existed. self.remove_pid_file() self.exit(ALREADY_STOPPED) - + if not self.check_pid(pid): self.log.critical( 'Cluster [pid=%r] is not running.' % pid @@ -177,7 +177,7 @@ class IPClusterStop(BaseParallelApplication): # Here I exit with a unusual exit status that other processes # can watch for to learn how I existed. self.exit(ALREADY_STOPPED) - + elif os.name=='posix': sig = self.signal self.log.info( @@ -197,7 +197,7 @@ class IPClusterStop(BaseParallelApplication): self.log.error("Stopping cluster failed, assuming already dead.", exc_info=True) self.remove_pid_file() - + engine_aliases = {} engine_aliases.update(base_aliases) engine_aliases.update(dict( @@ -228,7 +228,7 @@ class IPClusterEngines(BaseParallelApplication): launchers = launcher.all_launchers eslaunchers = [ l for l in launchers if 'EngineSet' in l.__name__] return [ProfileDir]+eslaunchers - + n = Int(num_cpus(), config=True, help="""The number of engines to start. The default is to use one for each CPU on your machine""") @@ -239,12 +239,12 @@ class IPClusterEngines(BaseParallelApplication): to use various batch systems to launch your engines, such as PBS,SGE,MPIExec,etc. Each launcher class has its own set of configuration options, for making sure it will work in your environment. - + You can also write your own launcher, and specify it's absolute import path, as in 'mymodule.launcher.FTLEnginesLauncher`. - + Examples include: - + LocalEngineSetLauncher : start engines locally as subprocesses [default] MPIExecEngineSetLauncher : use mpiexec to launch in an MPI environment PBSEngineSetLauncher : use PBS (qsub) to submit engines to a batch queue @@ -273,15 +273,15 @@ class IPClusterEngines(BaseParallelApplication): super(IPClusterEngines, self).initialize(argv) self.init_signal() self.init_launchers() - + def init_launchers(self): self.engine_launcher = self.build_launcher(self.engine_launcher_class, 'EngineSet') self.engine_launcher.on_stop(lambda r: self.loop.stop()) - + def init_signal(self): # Setup signals signal.signal(signal.SIGINT, self.sigint_handler) - + def build_launcher(self, clsname, kind=None): """import and instantiate a Launcher based on importstring""" if '.' not in clsname: @@ -302,7 +302,7 @@ class IPClusterEngines(BaseParallelApplication): profile_dir=self.profile_dir.location, cluster_id=self.cluster_id, ) return launcher - + def start_engines(self): self.log.info("Starting %i engines"%self.n) self.engine_launcher.start(self.n) @@ -327,7 +327,7 @@ class IPClusterEngines(BaseParallelApplication): def sigint_handler(self, signum, frame): self.log.debug("SIGINT received, stopping launchers...") self.stop_launchers() - + def start_logging(self): # Remove old log files of the controller and engine if self.clean_logs: @@ -342,7 +342,7 @@ class IPClusterEngines(BaseParallelApplication): """Start the app for the engines subcommand.""" self.log.info("IPython cluster: started") # First see if the cluster is already running - + # Now log and daemonize self.log.info( 'Starting engines with [daemon=%r]' % self.daemonize @@ -392,8 +392,8 @@ class IPClusterStart(IPClusterEngines): def _classes_default(self,): from IPython.parallel.apps import launcher return [ProfileDir] + [IPClusterEngines] + launcher.all_launchers - - clean_logs = Bool(True, config=True, + + clean_logs = Bool(True, config=True, help="whether to cleanup old logs before starting") delay = CFloat(1., config=True, @@ -403,12 +403,12 @@ class IPClusterStart(IPClusterEngines): config=True, helep="""The class for launching a Controller. Change this value if you want your controller to also be launched by a batch system, such as PBS,SGE,MPIExec,etc. - + Each launcher class has its own set of configuration options, for making sure it will work in your environment. - + Examples include: - + LocalControllerLauncher : start engines locally as subprocesses MPIExecControllerLauncher : use mpiexec to launch engines in an MPI universe PBSControllerLauncher : use PBS (qsub) to submit engines to a batch queue @@ -420,7 +420,7 @@ class IPClusterStart(IPClusterEngines): reset = Bool(False, config=True, help="Whether to reset config files as part of '--create'." ) - + # flags = Dict(flags) aliases = Dict(start_aliases) @@ -428,10 +428,10 @@ class IPClusterStart(IPClusterEngines): self.controller_launcher = self.build_launcher(self.controller_launcher_class, 'Controller') self.engine_launcher = self.build_launcher(self.engine_launcher_class, 'EngineSet') self.controller_launcher.on_stop(self.stop_launchers) - + def start_controller(self): self.controller_launcher.start() - + def stop_controller(self): # self.log.info("In stop_controller") if self.controller_launcher and self.controller_launcher.running: @@ -460,7 +460,7 @@ class IPClusterStart(IPClusterEngines): self.exit(ALREADY_STARTED) else: self.remove_pid_file() - + # Now log and daemonize self.log.info( @@ -501,11 +501,11 @@ class IPClusterApp(Application): 'stop' : (base+'Stop', stop_help), 'engines' : (base+'Engines', engines_help), } - + # no aliases or flags for parent App aliases = Dict() flags = Dict() - + def start(self): if self.subapp is None: print "No subcommand specified. Must specify one of: %s"%(self.subcommands.keys()) diff --git a/IPython/parallel/apps/launcher.py b/IPython/parallel/apps/launcher.py index 9267f38..8d85d24 100644 --- a/IPython/parallel/apps/launcher.py +++ b/IPython/parallel/apps/launcher.py @@ -115,10 +115,10 @@ class BaseLauncher(LoggingConfigurable): # the work_dir option. work_dir = Unicode(u'.') loop = Instance('zmq.eventloop.ioloop.IOLoop') - + start_data = Any() stop_data = Any() - + def _loop_default(self): return ioloop.IOLoop.instance() @@ -255,7 +255,7 @@ class LocalProcessLauncher(BaseLauncher): ``self.work_dir``. """ - # This is used to to construct self.args, which is passed to + # This is used to to construct self.args, which is passed to # spawnProcess. cmd_and_args = List([]) poll_frequency = Int(100) # in ms @@ -314,7 +314,7 @@ class LocalProcessLauncher(BaseLauncher): self.killer.start() # callbacks, etc: - + def handle_stdout(self, fd, events): if WINDOWS: line = self.stdout.recv() @@ -325,7 +325,7 @@ class LocalProcessLauncher(BaseLauncher): self.log.info(line[:-1]) else: self.poll() - + def handle_stderr(self, fd, events): if WINDOWS: line = self.stderr.recv() @@ -336,7 +336,7 @@ class LocalProcessLauncher(BaseLauncher): self.log.error(line[:-1]) else: self.poll() - + def poll(self): status = self.process.poll() if status is not None: @@ -373,13 +373,13 @@ class LocalEngineSetLauncher(LocalEngineLauncher): This can help force the engines to get their ids in order, or limit process flood when starting many engines.""" ) - + # launcher class launcher_class = LocalEngineLauncher - + launchers = Dict() stop_data = Dict() - + def __init__(self, work_dir=u'.', config=None, **kwargs): super(LocalEngineSetLauncher, self).__init__( work_dir=work_dir, config=config, **kwargs @@ -395,7 +395,7 @@ class LocalEngineSetLauncher(LocalEngineLauncher): el = self.launcher_class(work_dir=self.work_dir, config=self.config, log=self.log, profile_dir=self.profile_dir, cluster_id=self.cluster_id, ) - + # Copy the engine args over to each engine launcher. el.engine_cmd = copy.deepcopy(self.engine_cmd) el.engine_args = copy.deepcopy(self.engine_args) @@ -427,7 +427,7 @@ class LocalEngineSetLauncher(LocalEngineLauncher): def stop(self): return self.interrupt_then_kill() - + def _notice_engine_stopped(self, data): pid = data['pid'] for idx,el in self.launchers.iteritems(): @@ -480,7 +480,7 @@ class MPIExecControllerLauncher(MPIExecLauncher, ControllerMixin): @property def program(self): return self.controller_cmd - + @property def program_args(self): return self.cluster_args + self.controller_args @@ -500,7 +500,7 @@ class MPIExecEngineSetLauncher(MPIExecLauncher, EngineMixin): @property def program(self): return self.engine_cmd - + @property def program_args(self): return self.cluster_args + self.engine_args @@ -558,15 +558,15 @@ class SSHLauncher(LocalProcessLauncher): self.hostname = hostname if user is not None: self.user = user - + return super(SSHLauncher, self).start() - + def signal(self, sig): if self.state == 'running': # send escaped ssh connection-closer self.process.stdin.write('~.') self.process.stdin.flush() - + class SSHControllerLauncher(SSHLauncher, ControllerMixin): @@ -577,7 +577,7 @@ class SSHControllerLauncher(SSHLauncher, ControllerMixin): @property def program(self): return self.controller_cmd - + @property def program_args(self): return self.cluster_args + self.controller_args @@ -591,30 +591,30 @@ class SSHEngineLauncher(SSHLauncher, EngineMixin): @property def program(self): return self.engine_cmd - + @property def program_args(self): return self.cluster_args + self.engine_args - - + + class SSHEngineSetLauncher(LocalEngineSetLauncher): launcher_class = SSHEngineLauncher engines = Dict(config=True, help="""dict of engines to launch. This is a dict by hostname of ints, corresponding to the number of engines to start on that host.""") - + def start(self, n): """Start engines by profile or profile_dir. `n` is ignored, and the `engines` config property is used instead. """ - + dlist = [] for host, n in self.engines.iteritems(): if isinstance(n, (tuple, list)): n, args = n else: args = copy.deepcopy(self.engine_args) - + if '@' in host: user,host = host.split('@',1) else: @@ -625,7 +625,7 @@ class SSHEngineSetLauncher(LocalEngineSetLauncher): el = self.launcher_class(work_dir=self.work_dir, config=self.config, log=self.log, profile_dir=self.profile_dir, cluster_id=self.cluster_id, ) - + # Copy the engine args over to each engine launcher. el.engine_cmd = self.engine_cmd el.engine_args = args @@ -637,7 +637,7 @@ class SSHEngineSetLauncher(LocalEngineSetLauncher): dlist.append(d) self.notify_start(dlist) return dlist - + #----------------------------------------------------------------------------- @@ -687,7 +687,7 @@ class WindowsHPCLauncher(BaseLauncher): def find_args(self): return [u'job.exe'] - + def parse_job_id(self, output): """Take the output of the submit command and return the job id.""" m = re.search(self.job_id_regexp, output) @@ -748,7 +748,7 @@ class WindowsHPCControllerLauncher(WindowsHPCLauncher, ClusterAppMixin): job = IPControllerJob(config=self.config) t = IPControllerTask(config=self.config) - # The tasks work directory is *not* the actual work directory of + # The tasks work directory is *not* the actual work directory of # the controller. It is used as the base path for the stdout/stderr # files that the scheduler redirects to. t.work_directory = self.profile_dir @@ -781,7 +781,7 @@ class WindowsHPCEngineSetLauncher(WindowsHPCLauncher, ClusterAppMixin): for i in range(n): t = IPEngineTask(config=self.config) - # The tasks work directory is *not* the actual work directory of + # The tasks work directory is *not* the actual work directory of # the engine. It is used as the base path for the stdout/stderr # files that the scheduler redirects to. t.work_directory = self.profile_dir @@ -850,13 +850,13 @@ class BatchSystemLauncher(BaseLauncher): help="The filename of the instantiated batch script.") queue = Unicode(u'', config=True, help="The PBS Queue.") - + def _queue_changed(self, name, old, new): self.context[name] = new - + n = Int(1) _n_changed = _queue_changed - + # not configurable, override in subclasses # PBS Job Array regex job_array_regexp = Unicode('') @@ -873,10 +873,10 @@ class BatchSystemLauncher(BaseLauncher): # the Formatter instance for rendering the templates: formatter = Instance(EvalFormatter, (), {}) - + def find_args(self): return self.submit_command + [self.batch_file] - + def __init__(self, work_dir=u'.', config=None, **kwargs): super(BatchSystemLauncher, self).__init__( work_dir=work_dir, config=config, **kwargs @@ -905,7 +905,7 @@ class BatchSystemLauncher(BaseLauncher): if not self.batch_template: # third (last) priority is default_template self.batch_template = self.default_template - + # add jobarray or queue lines to user-specified template # note that this is *only* when user did not specify a template. regex = re.compile(self.job_array_regexp) @@ -914,17 +914,17 @@ class BatchSystemLauncher(BaseLauncher): self.log.info("adding job array settings to batch script") firstline, rest = self.batch_template.split('\n',1) self.batch_template = u'\n'.join([firstline, self.job_array_template, rest]) - + regex = re.compile(self.queue_regexp) # print regex.search(self.batch_template) if self.queue and not regex.search(self.batch_template): self.log.info("adding PBS queue settings to batch script") firstline, rest = self.batch_template.split('\n',1) self.batch_template = u'\n'.join([firstline, self.queue_template, rest]) - + script_as_string = self.formatter.format(self.batch_template, **self.context) self.log.info('Writing instantiated batch script: %s' % self.batch_file) - + with open(self.batch_file, 'w') as f: f.write(script_as_string) os.chmod(self.batch_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) @@ -935,7 +935,7 @@ class BatchSystemLauncher(BaseLauncher): # can be used in the batch script template as {profile_dir} self.write_batch_script(n) output = check_output(self.args, env=os.environ) - + job_id = self.parse_job_id(output) self.notify_start(job_id) return job_id @@ -955,7 +955,7 @@ class PBSLauncher(BatchSystemLauncher): help="The PBS delete command ['qsub']") job_id_regexp = Unicode(r'\d+', config=True, help="Regular expresion for identifying the job ID [r'\d+']") - + batch_file = Unicode(u'') job_array_regexp = Unicode('#PBS\W+-t\W+[\w\d\-\$]+') job_array_template = Unicode('#PBS -t 1-{n}') @@ -974,7 +974,7 @@ class PBSControllerLauncher(PBSLauncher, BatchClusterAppMixin): %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}" """%(' '.join(ipcontroller_cmd_argv))) - + def start(self): """Start the controller by profile or profile_dir.""" self.log.info("Starting PBSControllerLauncher: %r" % self.args) @@ -1041,20 +1041,20 @@ class SGEEngineSetLauncher(SGELauncher, BatchClusterAppMixin): class LSFLauncher(BatchSystemLauncher): """A BatchSystemLauncher subclass for LSF.""" - + submit_command = List(['bsub'], config=True, help="The PBS submit command ['bsub']") delete_command = List(['bkill'], config=True, help="The PBS delete command ['bkill']") job_id_regexp = Unicode(r'\d+', config=True, help="Regular expresion for identifying the job ID [r'\d+']") - + batch_file = Unicode(u'') job_array_regexp = Unicode('#BSUB[ \t]-J+\w+\[\d+-\d+\]') job_array_template = Unicode('#BSUB -J ipengine[1-{n}]') queue_regexp = Unicode('#BSUB[ \t]+-q[ \t]+\w+') queue_template = Unicode('#BSUB -q {queue}') - + def start(self, n): """Start n copies of the process using LSF batch system. This cant inherit from the base class because bsub expects @@ -1075,16 +1075,16 @@ class LSFLauncher(BatchSystemLauncher): class LSFControllerLauncher(LSFLauncher, BatchClusterAppMixin): """Launch a controller using LSF.""" - + batch_file_name = Unicode(u'lsf_controller', config=True, help="batch file name for the controller job.") default_template= Unicode("""#!/bin/sh #BSUB -J ipcontroller - #BSUB -oo ipcontroller.o.%%J - #BSUB -eo ipcontroller.e.%%J + #BSUB -oo ipcontroller.o.%%J + #BSUB -eo ipcontroller.e.%%J %s --log-to-file --profile-dir="{profile_dir}" --cluster-id="{cluster_id}" """%(' '.join(ipcontroller_cmd_argv))) - + def start(self): """Start the controller by profile or profile_dir.""" self.log.info("Starting LSFControllerLauncher: %r" % self.args) @@ -1096,11 +1096,11 @@ class LSFEngineSetLauncher(LSFLauncher, BatchClusterAppMixin): batch_file_name = Unicode(u'lsf_engines', config=True, help="batch file name for the engine(s) job.") default_template= Unicode(u"""#!/bin/sh - #BSUB -oo ipengine.o.%%J - #BSUB -eo ipengine.e.%%J + #BSUB -oo ipengine.o.%%J + #BSUB -eo ipengine.e.%%J %s --profile-dir="{profile_dir}" --cluster-id="{cluster_id}" """%(' '.join(ipengine_cmd_argv))) - + def start(self, n): """Start n engines by profile or profile_dir.""" self.log.info('Starting %i engines with LSFEngineSetLauncher: %r' % (n, self.args)) diff --git a/IPython/parallel/apps/winhpcjob.py b/IPython/parallel/apps/winhpcjob.py index f2c748f..9434805 100644 --- a/IPython/parallel/apps/winhpcjob.py +++ b/IPython/parallel/apps/winhpcjob.py @@ -1,6 +1,6 @@ # encoding: utf-8 """ -Job and task components for writing .xml files that the Windows HPC Server +Job and task components for writing .xml files that the Windows HPC Server 2008 can use to start jobs. Authors: @@ -297,7 +297,7 @@ class IPEngineTask(WinHPCTask): the_uuid = uuid.uuid1() self.std_out_file_path = os.path.join('log','ipengine-%s.out' % the_uuid) self.std_err_file_path = os.path.join('log','ipengine-%s.err' % the_uuid) - + @property def command_line(self): return ' '.join(self.engine_cmd + self.engine_args) @@ -307,7 +307,7 @@ class IPEngineTask(WinHPCTask): # j.job_name = 'IPCluster' # j.username = 'GNET\\bgranger' # j.requested_nodes = 'GREEN' -# +# # t = WinHPCTask(None) # t.task_name = 'Controller' # t.command_line = r"\\blue\domainusers$\bgranger\Python\Python25\Scripts\ipcontroller.exe --log-to-file -p default --log-level 10" diff --git a/IPython/parallel/client/asyncresult.py b/IPython/parallel/client/asyncresult.py index 291046f..12a7c6d 100644 --- a/IPython/parallel/client/asyncresult.py +++ b/IPython/parallel/client/asyncresult.py @@ -39,15 +39,15 @@ def check_ready(f, self, *args, **kwargs): class AsyncResult(object): """Class for representing results of non-blocking calls. - + Provides the same interface as :py:class:`multiprocessing.pool.AsyncResult`. """ - + msg_ids = None _targets = None _tracker = None _single_result = False - + def __init__(self, client, msg_ids, fname='unknown', targets=None, tracker=None): if isinstance(msg_ids, basestring): # always a list @@ -66,17 +66,17 @@ class AsyncResult(object): self._single_result = not isinstance(targets, (list, tuple)) else: self._single_result = False - + def __repr__(self): if self._ready: return "<%s: finished>"%(self.__class__.__name__) else: return "<%s: %s>"%(self.__class__.__name__,self._fname) - - + + def _reconstruct_result(self, res): """Reconstruct our result from actual result list (always a list) - + Override me in subclasses for turning a list of results into the expected form. """ @@ -84,10 +84,10 @@ class AsyncResult(object): return res[0] else: return res - + def get(self, timeout=-1): - """Return the result when it arrives. - + """Return the result when it arrives. + If `timeout` is not ``None`` and the result does not arrive within `timeout` seconds then ``TimeoutError`` is raised. If the remote call raised an exception then that exception will be reraised @@ -95,7 +95,7 @@ class AsyncResult(object): """ if not self.ready(): self.wait(timeout) - + if self._ready: if self._success: return self._result @@ -103,16 +103,16 @@ class AsyncResult(object): raise self._exception else: raise error.TimeoutError("Result not ready.") - + def ready(self): """Return whether the call has completed.""" if not self._ready: self.wait(0) return self._ready - + def wait(self, timeout=-1): """Wait until the result is available or until `timeout` seconds pass. - + This method always returns None. """ if self._ready: @@ -136,26 +136,26 @@ class AsyncResult(object): self._success = True finally: self._metadata = map(self._client.metadata.get, self.msg_ids) - - + + def successful(self): - """Return whether the call completed without raising an exception. - + """Return whether the call completed without raising an exception. + Will raise ``AssertionError`` if the result is not ready. """ assert self.ready() return self._success - + #---------------------------------------------------------------- # Extra methods not in mp.pool.AsyncResult #---------------------------------------------------------------- - + def get_dict(self, timeout=-1): """Get the results as a dict, keyed by engine_id. - + timeout behavior is described in `get()`. """ - + results = self.get(timeout) engine_ids = [ md['engine_id'] for md in self._metadata ] bycount = sorted(engine_ids, key=lambda k: engine_ids.count(k)) @@ -163,17 +163,17 @@ class AsyncResult(object): if maxcount > 1: raise ValueError("Cannot build dict, %i jobs ran on engine #%i"%( maxcount, bycount[-1])) - + return dict(zip(engine_ids,results)) - + @property def result(self): """result property wrapper for `get(timeout=0)`.""" return self.get() - + # abbreviated alias: r = result - + @property @check_ready def metadata(self): @@ -182,15 +182,15 @@ class AsyncResult(object): return self._metadata[0] else: return self._metadata - + @property def result_dict(self): """result property as a dict.""" return self.get_dict() - + def __dict__(self): return self.get_dict(0) - + def abort(self): """abort my tasks.""" assert not self.ready(), "Can't abort, I am already done!" @@ -200,10 +200,10 @@ class AsyncResult(object): def sent(self): """check whether my messages have been sent.""" return self._tracker.done - + def wait_for_send(self, timeout=-1): """wait for pyzmq send to complete. - + This is necessary when sending arrays that you intend to edit in-place. `timeout` is in seconds, and will raise TimeoutError if it is reached before the send completes. @@ -213,7 +213,7 @@ class AsyncResult(object): #------------------------------------- # dict-access #------------------------------------- - + @check_ready def __getitem__(self, key): """getitem returns result value(s) if keyed by int/slice, or metadata if key is str. @@ -230,7 +230,7 @@ class AsyncResult(object): return values else: raise TypeError("Invalid key type %r, must be 'int','slice', or 'str'"%type(key)) - + @check_ready def __getattr__(self, key): """getattr maps to getitem for convenient attr access to metadata.""" @@ -238,7 +238,7 @@ class AsyncResult(object): raise AttributeError("%r object has no attribute %r"%( self.__class__.__name__, key)) return self.__getitem__(key) - + # asynchronous iterator: def __iter__(self): if self._single_result: @@ -256,22 +256,22 @@ class AsyncResult(object): yield r - + class AsyncMapResult(AsyncResult): """Class for representing results of non-blocking gathers. - + This will properly reconstruct the gather. """ - + def __init__(self, client, msg_ids, mapObject, fname=''): AsyncResult.__init__(self, client, msg_ids, fname=fname) self._mapObject = mapObject self._single_result = False - + def _reconstruct_result(self, res): """Perform the gather on the actual results.""" return self._mapObject.joinPartitions(res) - + # asynchronous iterator: def __iter__(self): try: @@ -297,11 +297,11 @@ class AsyncMapResult(AsyncResult): class AsyncHubResult(AsyncResult): """Class to wrap pending results that must be requested from the Hub. - + Note that waiting/polling on these objects requires polling the Hubover the network, so use `AsyncHubResult.wait()` sparingly. """ - + def wait(self, timeout=-1): """wait for result to complete.""" start = time.time() @@ -341,5 +341,5 @@ class AsyncHubResult(AsyncResult): self._success = True finally: self._metadata = map(self._client.metadata.get, self.msg_ids) - + __all__ = ['AsyncResult', 'AsyncMapResult', 'AsyncHubResult'] \ No newline at end of file diff --git a/IPython/parallel/client/client.py b/IPython/parallel/client/client.py index 4f3acf7..4d93d84 100644 --- a/IPython/parallel/client/client.py +++ b/IPython/parallel/client/client.py @@ -71,9 +71,9 @@ def spin_first(f, self, *args, **kwargs): class Metadata(dict): """Subclass of dict for initializing metadata values. - + Attribute access works on keys. - + These objects have a strict set of keys - errors will raise if you try to add new keys. """ @@ -98,7 +98,7 @@ class Metadata(dict): } self.update(md) self.update(dict(*args, **kwargs)) - + def __getattr__(self, key): """getattr aliased to getitem""" if key in self.iterkeys(): @@ -112,21 +112,21 @@ class Metadata(dict): self[key] = value else: raise AttributeError(key) - + def __setitem__(self, key, value): """strict static key enforcement""" if key in self.iterkeys(): dict.__setitem__(self, key, value) else: raise KeyError(key) - + class Client(HasTraits): """A semi-synchronous client to the IPython ZMQ cluster - + Parameters ---------- - + url_or_file : bytes or unicode; zmq url or path to ipcontroller-client.json Connection information for the Hub's registration. If a json connector file is given, then likely no further configuration is necessary. @@ -139,12 +139,12 @@ class Client(HasTraits): Pass an existing zmq.Context instance, otherwise the client will create its own. debug : bool flag for lots of message printing for debug purposes - timeout : int/float + timeout : int/float time (in seconds) to wait for connection replies from the Hub [Default: 10] - + #-------------- session related args ---------------- - + config : Config object If specified, this will be relayed to the Session for configuration username : str @@ -157,16 +157,16 @@ class Client(HasTraits): unpacker : str (import_string) or callable The inverse of packer. Only necessary if packer is specified as *not* one of 'json' or 'pickle'. - + #-------------- ssh related args ---------------- # These are args for configuring the ssh tunnel to be used # credentials are used to forward connections over ssh to the Controller # Note that the ip given in `addr` needs to be relative to sshserver # The most basic case is to leave addr as pointing to localhost (127.0.0.1), - # and set sshserver as the same machine the Controller is on. However, + # and set sshserver as the same machine the Controller is on. However, # the only requirement is that sshserver is able to see the Controller # (i.e. is within the same trusted network). - + sshserver : str A string of the form passed to ssh, i.e. 'server.tld' or 'user@server.tld:port' If keyfile or password is specified, and this is not, it will default to @@ -174,81 +174,81 @@ class Client(HasTraits): sshkey : str; path to ssh private key file This specifies a key to be used in ssh login, default None. Regular default ssh keys will be used without specifying this argument. - password : str + password : str Your ssh password to sshserver. Note that if this is left None, you will be prompted for it if passwordless key based login is unavailable. paramiko : bool flag for whether to use paramiko instead of shell ssh for tunneling. [default: True on win32, False else] - + ------- exec authentication args ------- If even localhost is untrusted, you can have some protection against - unauthorized execution by signing messages with HMAC digests. - Messages are still sent as cleartext, so if someone can snoop your + unauthorized execution by signing messages with HMAC digests. + Messages are still sent as cleartext, so if someone can snoop your loopback traffic this will not protect your privacy, but will prevent unauthorized execution. - + exec_key : str an authentication key or file containing a key default: None - - + + Attributes ---------- - + ids : list of int engine IDs requesting the ids attribute always synchronizes the registration state. To request ids without synchronization, use semi-private _ids attributes. - + history : list of msg_ids a list of msg_ids, keeping track of all the execution messages you have submitted in order. - + outstanding : set of msg_ids a set of msg_ids that have been submitted, but whose results have not yet been received. - + results : dict a dict of all our results, keyed by msg_id - + block : bool determines default behavior when block not specified in execution methods - + Methods ------- - + spin flushes incoming results and registration state changes control methods spin, and requesting `ids` also ensures up to date - + wait wait on one or more msg_ids - + execution methods apply legacy: execute, run - + data movement push, pull, scatter, gather - + query methods queue_status, get_result, purge, result_status - + control methods abort, shutdown - + """ - - + + block = Bool(False) outstanding = Set() results = Instance('collections.defaultdict', (dict,)) metadata = Instance('collections.defaultdict', (Metadata,)) history = List() debug = Bool(False) - + profile=Unicode() def _profile_default(self): if BaseIPythonApplication.initialized(): @@ -261,8 +261,8 @@ class Client(HasTraits): return u'default' else: return u'default' - - + + _outstanding_dict = Instance('collections.defaultdict', (set,)) _ids = List() _connected=Bool(False) @@ -281,11 +281,11 @@ class Client(HasTraits): _closed = False _ignored_control_replies=Int(0) _ignored_hub_replies=Int(0) - + def __new__(self, *args, **kw): # don't raise on positional args return HasTraits.__new__(self, **kw) - + def __init__(self, url_or_file=None, profile=None, profile_dir=None, ipython_dir=None, context=None, debug=False, exec_key=None, sshserver=None, sshkey=None, password=None, paramiko=None, @@ -298,14 +298,14 @@ class Client(HasTraits): if context is None: context = zmq.Context.instance() self._context = context - + self._setup_profile_dir(self.profile, profile_dir, ipython_dir) if self._cd is not None: if url_or_file is None: url_or_file = pjoin(self._cd.security_dir, 'ipcontroller-client.json') assert url_or_file is not None, "I can't find enough information to connect to a hub!"\ " Please specify at least one of url_or_file or profile." - + try: util.validate_url(url_or_file) except AssertionError: @@ -317,7 +317,7 @@ class Client(HasTraits): cfg = json.loads(f.read()) else: cfg = {'url':url_or_file} - + # sync defaults from args, json: if sshserver: cfg['ssh'] = sshserver @@ -346,9 +346,9 @@ class Client(HasTraits): elif not sshserver: # otherwise sync with cfg sshserver = cfg['ssh'] - + self._config = cfg - + self._ssh = bool(sshserver or sshkey or password) if self._ssh and sshserver is None: # default to ssh via localhost @@ -359,7 +359,7 @@ class Client(HasTraits): else: password = getpass("SSH Password for %s: "%sshserver) ssh_kwargs = dict(keyfile=sshkey, password=password, paramiko=paramiko) - + # configure and construct the session if exec_key is not None: if os.path.isfile(exec_key): @@ -368,16 +368,16 @@ class Client(HasTraits): exec_key = util.asbytes(exec_key) extra_args['key'] = exec_key self.session = Session(**extra_args) - + self._query_socket = self._context.socket(zmq.DEALER) self._query_socket.setsockopt(zmq.IDENTITY, self.session.bsession) if self._ssh: tunnel.tunnel_connection(self._query_socket, url, sshserver, **ssh_kwargs) else: self._query_socket.connect(url) - + self.session.debug = self.debug - + self._notification_handlers = {'registration_notification' : self._register_engine, 'unregistration_notification' : self._unregister_engine, 'shutdown_notification' : lambda msg: self.close(), @@ -385,11 +385,11 @@ class Client(HasTraits): self._queue_handlers = {'execute_reply' : self._handle_execute_reply, 'apply_reply' : self._handle_apply_reply} self._connect(sshserver, ssh_kwargs, timeout) - + def __del__(self): """cleanup sockets, but _not_ context.""" self.close() - + def _setup_profile_dir(self, profile, profile_dir, ipython_dir): if ipython_dir is None: ipython_dir = get_ipython_dir() @@ -407,7 +407,7 @@ class Client(HasTraits): except ProfileDirError: pass self._cd = None - + def _update_engines(self, engines): """Update our engines dict and _ids from a dict of the form: {id:uuid}.""" for k,v in engines.iteritems(): @@ -418,7 +418,7 @@ class Client(HasTraits): if sorted(self._engines.keys()) != range(len(self._engines)) and \ self._task_scheme == 'pure' and self._task_socket: self._stop_scheduling_tasks() - + def _stop_scheduling_tasks(self): """Stop scheduling tasks because an engine has been unregistered from a pure ZMQ scheduler. @@ -431,7 +431,7 @@ class Client(HasTraits): msg += " If you were running tasks when this happened, " +\ "some `outstanding` msg_ids may never resolve." warnings.warn(msg, RuntimeWarning) - + def _build_targets(self, targets): """Turn valid target IDs or 'all' into two lists: (int_ids, uuids). @@ -440,7 +440,7 @@ class Client(HasTraits): # flush notification socket if no engines yet, just in case if not self.ids: raise error.NoEnginesRegistered("Can't build targets without any engines") - + if targets is None: targets = self._ids elif isinstance(targets, basestring): @@ -454,21 +454,21 @@ class Client(HasTraits): if targets not in self._ids: raise IndexError("No such engine: %i"%targets) targets = [targets] - + if isinstance(targets, slice): indices = range(len(self._ids))[targets] ids = self.ids targets = [ ids[i] for i in indices ] - + if not isinstance(targets, (tuple, list, xrange)): raise TypeError("targets by int/slice/collection of ints only, not %s"%(type(targets))) - + return [util.asbytes(self._engines[t]) for t in targets], list(targets) - + def _connect(self, sshserver, ssh_kwargs, timeout): """setup all our socket connections to the cluster. This is called from __init__.""" - + # Maybe allow reconnecting? if self._connected: return @@ -480,7 +480,7 @@ class Client(HasTraits): return tunnel.tunnel_connection(s, url, sshserver, **ssh_kwargs) else: return s.connect(url) - + self.session.send(self._query_socket, 'connection_request') # use Poller because zmq.select has wrong units in pyzmq 2.1.7 poller = zmq.Poller() @@ -527,11 +527,11 @@ class Client(HasTraits): else: self._connected = False raise Exception("Failed to connect!") - + #-------------------------------------------------------------------------- # handlers and callbacks for incoming messages #-------------------------------------------------------------------------- - + def _unwrap_exception(self, content): """unwrap exception, and remap engine_id to int.""" e = error.unwrap_exception(content) @@ -541,7 +541,7 @@ class Client(HasTraits): eid = self._engines[e_uuid] e.engine_info['engine_id'] = eid return e - + def _extract_metadata(self, header, parent, content): md = {'msg_id' : parent['msg_id'], 'received' : datetime.now(), @@ -550,10 +550,10 @@ class Client(HasTraits): 'after' : parent.get('after', []), 'status' : content['status'], } - + if md['engine_uuid'] is not None: md['engine_id'] = self._engines.get(md['engine_uuid'], None) - + if 'date' in parent: md['submitted'] = parent['date'] if 'started' in header: @@ -561,7 +561,7 @@ class Client(HasTraits): if 'date' in header: md['completed'] = header['date'] return md - + def _register_engine(self, msg): """Register a new engine, and update our connection info.""" content = msg['content'] @@ -576,25 +576,25 @@ class Client(HasTraits): if eid in self._ids: self._ids.remove(eid) uuid = self._engines.pop(eid) - + self._handle_stranded_msgs(eid, uuid) - + if self._task_socket and self._task_scheme == 'pure': self._stop_scheduling_tasks() - + def _handle_stranded_msgs(self, eid, uuid): """Handle messages known to be on an engine when the engine unregisters. - + It is possible that this will fire prematurely - that is, an engine will go down after completing a result, and the client will be notified of the unregistration and later receive the successful result. """ - + outstanding = self._outstanding_dict[uuid] - + for msg_id in list(outstanding): if msg_id in self.results: - # we already + # we already continue try: raise error.EngineError("Engine %r died while running task %r"%(eid, msg_id)) @@ -608,13 +608,13 @@ class Client(HasTraits): header['date'] = datetime.now() msg = dict(parent_header=parent, header=header, content=content) self._handle_apply_reply(msg) - + def _handle_execute_reply(self, msg): """Save the reply to an execute_request into our results. - + execute messages are never actually used. apply is used instead. """ - + parent = msg['parent_header'] msg_id = parent['msg_id'] if msg_id not in self.outstanding: @@ -625,7 +625,7 @@ class Client(HasTraits): else: self.outstanding.remove(msg_id) self.results[msg_id] = self._unwrap_exception(msg['content']) - + def _handle_apply_reply(self, msg): """Save the reply to an apply_request into our results.""" parent = msg['parent_header'] @@ -641,17 +641,17 @@ class Client(HasTraits): self.outstanding.remove(msg_id) content = msg['content'] header = msg['header'] - + # construct metadata: md = self.metadata[msg_id] md.update(self._extract_metadata(header, parent, content)) # is this redundant? self.metadata[msg_id] = md - + e_outstanding = self._outstanding_dict[md['engine_uuid']] if msg_id in e_outstanding: e_outstanding.remove(msg_id) - + # construct result: if content['status'] == 'ok': self.results[msg_id] = util.unserialize_object(msg['buffers'])[0] @@ -662,7 +662,7 @@ class Client(HasTraits): pass else: self.results[msg_id] = self._unwrap_exception(content) - + def _flush_notifications(self): """Flush notifications of engine registrations waiting in ZMQ queue.""" @@ -677,7 +677,7 @@ class Client(HasTraits): else: handler(msg) idents,msg = self.session.recv(self._notification_socket, mode=zmq.NOBLOCK) - + def _flush_results(self, sock): """Flush task or queue results waiting in ZMQ queue.""" idents,msg = self.session.recv(sock, mode=zmq.NOBLOCK) @@ -691,11 +691,11 @@ class Client(HasTraits): else: handler(msg) idents,msg = self.session.recv(sock, mode=zmq.NOBLOCK) - + def _flush_control(self, sock): """Flush replies from the control channel waiting in the ZMQ queue. - + Currently: ignore them.""" if self._ignored_control_replies <= 0: return @@ -705,18 +705,18 @@ class Client(HasTraits): if self.debug: pprint(msg) idents,msg = self.session.recv(sock, mode=zmq.NOBLOCK) - + def _flush_ignored_control(self): """flush ignored control replies""" while self._ignored_control_replies > 0: self.session.recv(self._control_socket) self._ignored_control_replies -= 1 - + def _flush_ignored_hub_replies(self): ident,msg = self.session.recv(self._query_socket, mode=zmq.NOBLOCK) while msg is not None: ident,msg = self.session.recv(self._query_socket, mode=zmq.NOBLOCK) - + def _flush_iopub(self, sock): """Flush replies from the iopub channel waiting in the ZMQ queue. @@ -730,10 +730,10 @@ class Client(HasTraits): content = msg['content'] header = msg['header'] msg_type = msg['header']['msg_type'] - + # init metadata: md = self.metadata[msg_id] - + if msg_type == 'stream': name = content['name'] s = md[name] or '' @@ -744,40 +744,40 @@ class Client(HasTraits): md.update({'pyin' : content['code']}) else: md.update({msg_type : content.get('data', '')}) - + # reduntant? self.metadata[msg_id] = md - + idents,msg = self.session.recv(sock, mode=zmq.NOBLOCK) - + #-------------------------------------------------------------------------- # len, getitem #-------------------------------------------------------------------------- - + def __len__(self): """len(client) returns # of engines.""" return len(self.ids) - + def __getitem__(self, key): """index access returns DirectView multiplexer objects - + Must be int, slice, or list/tuple/xrange of ints""" if not isinstance(key, (int, slice, tuple, list, xrange)): raise TypeError("key by int/slice/iterable of ints only, not %s"%(type(key))) else: return self.direct_view(key) - + #-------------------------------------------------------------------------- # Begin public methods #-------------------------------------------------------------------------- - + @property def ids(self): """Always up-to-date ids property.""" self._flush_notifications() # always copy: return list(self._ids) - + def close(self): if self._closed: return @@ -786,7 +786,7 @@ class Client(HasTraits): if isinstance(socket, zmq.Socket) and not socket.closed: socket.close() self._closed = True - + def spin(self): """Flush any registration notifications and execution results waiting in the ZMQ queue. @@ -803,13 +803,13 @@ class Client(HasTraits): self._flush_iopub(self._iopub_socket) if self._query_socket: self._flush_ignored_hub_replies() - + def wait(self, jobs=None, timeout=-1): """waits on one or more `jobs`, for up to `timeout` seconds. - + Parameters ---------- - + jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects ints are indices to self.history strs are msg_ids @@ -817,10 +817,10 @@ class Client(HasTraits): timeout : float a time in seconds, after which to give up. default is -1, which means no timeout - + Returns ------- - + True : when all msg_ids are done False : timeout reached, some msg_ids still outstanding """ @@ -848,11 +848,11 @@ class Client(HasTraits): time.sleep(1e-3) self.spin() return len(theids.intersection(self.outstanding)) == 0 - + #-------------------------------------------------------------------------- # Control methods #-------------------------------------------------------------------------- - + @spin_first def clear(self, targets=None, block=None): """Clear the namespace in target(s).""" @@ -873,22 +873,22 @@ class Client(HasTraits): self._ignored_control_replies += len(targets) if error: raise error - - + + @spin_first def abort(self, jobs=None, targets=None, block=None): """Abort specific jobs from the execution queues of target(s). - + This is a mechanism to prevent jobs that have already been submitted from executing. - + Parameters ---------- - + jobs : msg_id, list of msg_ids, or AsyncResult The jobs to be aborted - - + + """ block = self.block if block is None else block targets = self._build_targets(targets)[0] @@ -905,7 +905,7 @@ class Client(HasTraits): msg_ids.append(j) content = dict(msg_ids=msg_ids) for t in targets: - self.session.send(self._control_socket, 'abort_request', + self.session.send(self._control_socket, 'abort_request', content=content, ident=t) error = False if block: @@ -920,7 +920,7 @@ class Client(HasTraits): self._ignored_control_replies += len(targets) if error: raise error - + @spin_first def shutdown(self, targets=None, restart=False, hub=False, block=None): """Terminates one or more engine processes, optionally including the hub.""" @@ -929,7 +929,7 @@ class Client(HasTraits): targets = 'all' targets = self._build_targets(targets)[0] for t in targets: - self.session.send(self._control_socket, 'shutdown_request', + self.session.send(self._control_socket, 'shutdown_request', content={'restart':restart},ident=t) error = False if block or hub: @@ -942,7 +942,7 @@ class Client(HasTraits): error = self._unwrap_exception(msg['content']) else: self._ignored_control_replies += len(targets) - + if hub: time.sleep(0.25) self.session.send(self._query_socket, 'shutdown_request') @@ -951,34 +951,34 @@ class Client(HasTraits): pprint(msg) if msg['content']['status'] != 'ok': error = self._unwrap_exception(msg['content']) - + if error: raise error - + #-------------------------------------------------------------------------- # Execution related methods #-------------------------------------------------------------------------- - + def _maybe_raise(self, result): """wrapper for maybe raising an exception if apply failed.""" if isinstance(result, error.RemoteError): raise result - + return result - + def send_apply_message(self, socket, f, args=None, kwargs=None, subheader=None, track=False, ident=None): """construct and send an apply message via a socket. - + This is the principal method with which all engine execution is performed by views. """ - + assert not self._closed, "cannot use me anymore, I'm closed!" # defaults: args = args if args is not None else [] kwargs = kwargs if kwargs is not None else {} subheader = subheader if subheader is not None else {} - + # validate arguments if not callable(f): raise TypeError("f must be callable, not %s"%type(f)) @@ -988,12 +988,12 @@ class Client(HasTraits): raise TypeError("kwargs must be dict, not %s"%type(kwargs)) if not isinstance(subheader, dict): raise TypeError("subheader must be dict, not %s"%type(subheader)) - + bufs = util.pack_apply_message(f,args,kwargs) - + msg = self.session.send(socket, "apply_request", buffers=bufs, ident=ident, subheader=subheader, track=track) - + msg_id = msg['header']['msg_id'] self.outstanding.add(msg_id) if ident: @@ -1005,22 +1005,22 @@ class Client(HasTraits): self._outstanding_dict[ident].add(msg_id) self.history.append(msg_id) self.metadata[msg_id]['submitted'] = datetime.now() - + return msg #-------------------------------------------------------------------------- # construct a View object #-------------------------------------------------------------------------- - + def load_balanced_view(self, targets=None): """construct a DirectView object. - + If no arguments are specified, create a LoadBalancedView using all engines. - + Parameters ---------- - + targets: list,slice,int,etc. [default: use all engines] The subset of engines across which to load-balance """ @@ -1029,16 +1029,16 @@ class Client(HasTraits): if targets is not None: targets = self._build_targets(targets)[1] return LoadBalancedView(client=self, socket=self._task_socket, targets=targets) - + def direct_view(self, targets='all'): """construct a DirectView object. - + If no targets are specified, create a DirectView using all engines. - + Parameters ---------- - + targets: list,slice,int,etc. [default: use all engines] The engines to use for the View """ @@ -1049,56 +1049,56 @@ class Client(HasTraits): if single: targets = targets[0] return DirectView(client=self, socket=self._mux_socket, targets=targets) - + #-------------------------------------------------------------------------- # Query methods #-------------------------------------------------------------------------- - + @spin_first def get_result(self, indices_or_msg_ids=None, block=None): """Retrieve a result by msg_id or history index, wrapped in an AsyncResult object. - + If the client already has the results, no request to the Hub will be made. - + This is a convenient way to construct AsyncResult objects, which are wrappers that include metadata about execution, and allow for awaiting results that were not submitted by this Client. - + It can also be a convenient way to retrieve the metadata associated with blocking execution, since it always retrieves - + Examples -------- :: - + In [10]: r = client.apply() - + Parameters ---------- - + indices_or_msg_ids : integer history index, str msg_id, or list of either The indices or msg_ids of indices to be retrieved - + block : bool Whether to wait for the result to be done - + Returns ------- - + AsyncResult A single AsyncResult object will always be returned. - + AsyncHubResult A subclass of AsyncResult that retrieves results from the Hub - + """ block = self.block if block is None else block if indices_or_msg_ids is None: indices_or_msg_ids = -1 - + if not isinstance(indices_or_msg_ids, (list,tuple)): indices_or_msg_ids = [indices_or_msg_ids] - + theids = [] for id in indices_or_msg_ids: if isinstance(id, int): @@ -1106,18 +1106,18 @@ class Client(HasTraits): if not isinstance(id, basestring): raise TypeError("indices must be str or int, not %r"%id) theids.append(id) - + local_ids = filter(lambda msg_id: msg_id in self.history or msg_id in self.results, theids) remote_ids = filter(lambda msg_id: msg_id not in local_ids, theids) - + if remote_ids: ar = AsyncHubResult(self, msg_ids=theids) else: ar = AsyncResult(self, msg_ids=theids) - + if block: ar.wait() - + return ar @spin_first @@ -1181,27 +1181,27 @@ class Client(HasTraits): ar.wait() return ar - + @spin_first def result_status(self, msg_ids, status_only=True): """Check on the status of the result(s) of the apply request with `msg_ids`. - + If status_only is False, then the actual results will be retrieved, else only the status of the results will be checked. - + Parameters ---------- - + msg_ids : list of msg_ids if int: Passed as index to self.history for convenience. status_only : bool (default: True) if False: Retrieve the actual results of completed tasks. - + Returns ------- - + results : dict There will always be the keys 'pending' and 'completed', which will be lists of msg_ids that are incomplete or complete. If `status_only` @@ -1209,7 +1209,7 @@ class Client(HasTraits): """ if not isinstance(msg_ids, (list,tuple)): msg_ids = [msg_ids] - + theids = [] for msg_id in msg_ids: if isinstance(msg_id, int): @@ -1217,17 +1217,17 @@ class Client(HasTraits): if not isinstance(msg_id, basestring): raise TypeError("msg_ids must be str, not %r"%msg_id) theids.append(msg_id) - + completed = [] local_results = {} - + # comment this block out to temporarily disable local shortcut: for msg_id in theids: if msg_id in self.results: completed.append(msg_id) local_results[msg_id] = self.results[msg_id] theids.remove(msg_id) - + if theids: # some not locally cached content = dict(msg_ids=theids, status_only=status_only) msg = self.session.send(self._query_socket, "result_request", content=content) @@ -1241,16 +1241,16 @@ class Client(HasTraits): buffers = msg['buffers'] else: content = dict(completed=[],pending=[]) - + content['completed'].extend(completed) - + if status_only: return content - + failures = [] # load cached results into result: content.update(local_results) - + # update cache with results: for msg_id in sorted(theids): if msg_id in content['completed']: @@ -1261,34 +1261,34 @@ class Client(HasTraits): iodict = rec['io'] if isinstance(rcontent, str): rcontent = self.session.unpack(rcontent) - + md = self.metadata[msg_id] md.update(self._extract_metadata(header, parent, rcontent)) md.update(iodict) - + if rcontent['status'] == 'ok': res,buffers = util.unserialize_object(buffers) else: print rcontent res = self._unwrap_exception(rcontent) failures.append(res) - + self.results[msg_id] = res content[msg_id] = res - + if len(theids) == 1 and failures: raise failures[0] - + error.collect_exceptions(failures, "result_status") return content @spin_first def queue_status(self, targets='all', verbose=False): """Fetch the status of engine queues. - + Parameters ---------- - + targets : int/str/list of ints/strs the engines whose states are to be queried. default : all @@ -1310,31 +1310,31 @@ class Client(HasTraits): return content[targets] else: return content - + @spin_first def purge_results(self, jobs=[], targets=[]): """Tell the Hub to forget results. - + Individual results can be purged by msg_id, or the entire history of specific targets can be purged. - + Use `purge_results('all')` to scrub everything from the Hub's db. - + Parameters ---------- - + jobs : str or list of str or AsyncResult objects the msg_ids whose results should be forgotten. targets : int/str/list of ints/strs The targets, by int_id, whose entire history is to be purged. - + default : None """ if not targets and not jobs: raise ValueError("Must specify at least one of `targets` and `jobs`") if targets: targets = self._build_targets(targets)[1] - + # construct msg_ids from jobs if jobs == 'all': msg_ids = jobs @@ -1363,23 +1363,23 @@ class Client(HasTraits): @spin_first def hub_history(self): """Get the Hub's history - + Just like the Client, the Hub has a history, which is a list of msg_ids. This will contain the history of all clients, and, depending on configuration, may contain history across multiple cluster sessions. - + Any msg_id returned here is a valid argument to `get_result`. - + Returns ------- - + msg_ids : list of strs list of all msg_ids, ordered by task submission time. """ - + self.session.send(self._query_socket, "history_request", content={}) idents, msg = self.session.recv(self._query_socket, 0) - + if self.debug: pprint(msg) content = msg['content'] @@ -1391,12 +1391,12 @@ class Client(HasTraits): @spin_first def db_query(self, query, keys=None): """Query the Hub's TaskRecord database - + This will return a list of task record dicts that match `query` - + Parameters ---------- - + query : mongodb query dict The search dict. See mongodb query docs for details. keys : list of strs [optional] @@ -1413,9 +1413,9 @@ class Client(HasTraits): content = msg['content'] if content['status'] != 'ok': raise self._unwrap_exception(content) - + records = content['records'] - + buffer_lens = content['buffer_lens'] result_buffer_lens = content['result_buffer_lens'] buffers = msg['buffers'] @@ -1429,7 +1429,7 @@ class Client(HasTraits): if has_rbufs: blen = result_buffer_lens[i] rec['result_buffers'], buffers = buffers[:blen],buffers[blen:] - + return records __all__ = [ 'Client' ] diff --git a/IPython/parallel/client/remotefunction.py b/IPython/parallel/client/remotefunction.py index fb5e2fa..2c57102 100644 --- a/IPython/parallel/client/remotefunction.py +++ b/IPython/parallel/client/remotefunction.py @@ -33,14 +33,14 @@ from .asyncresult import AsyncMapResult @skip_doctest def remote(view, block=None, **flags): """Turn a function into a remote function. - + This method can be used for map: - + In [1]: @remote(view,block=True) ...: def func(a): ...: pass """ - + def remote_function(f): return RemoteFunction(view, f, block=block, **flags) return remote_function @@ -48,14 +48,14 @@ def remote(view, block=None, **flags): @skip_doctest def parallel(view, dist='b', block=None, **flags): """Turn a function into a parallel remote function. - + This method can be used for map: - + In [1]: @parallel(view, block=True) ...: def func(a): ...: pass """ - + def parallel_function(f): return ParallelFunction(view, f, dist=dist, block=block, **flags) return parallel_function @@ -66,10 +66,10 @@ def parallel(view, dist='b', block=None, **flags): class RemoteFunction(object): """Turn an existing function into a remote function. - + Parameters ---------- - + view : View instance The view to be used for execution f : callable @@ -77,37 +77,37 @@ class RemoteFunction(object): block : bool [default: None] Whether to wait for results or not. The default behavior is to use the current `block` attribute of `view` - + **flags : remaining kwargs are passed to View.temp_flags """ - + view = None # the remote connection func = None # the wrapped function block = None # whether to block flags = None # dict of extra kwargs for temp_flags - + def __init__(self, view, f, block=None, **flags): self.view = view self.func = f self.block=block self.flags=flags - + def __call__(self, *args, **kwargs): block = self.view.block if self.block is None else self.block with self.view.temp_flags(block=block, **self.flags): return self.view.apply(self.func, *args, **kwargs) - + class ParallelFunction(RemoteFunction): """Class for mapping a function to sequences. - + This will distribute the sequences according the a mapper, and call the function on each sub-sequence. If called via map, then the function will be called once on each element, rather that each sub-sequence. - + Parameters ---------- - + view : View instance The view to be used for execution f : callable @@ -124,17 +124,17 @@ class ParallelFunction(RemoteFunction): The size of chunk to use when breaking up sequences in a load-balanced manner **flags : remaining kwargs are passed to View.temp_flags """ - + chunksize=None mapObject=None - + def __init__(self, view, f, dist='b', block=None, chunksize=None, **flags): super(ParallelFunction, self).__init__(view, f, block=block, **flags) self.chunksize = chunksize - + mapClass = Map.dists[dist] self.mapObject = mapClass() - + def __call__(self, *sequences): # check that the length of sequences match len_0 = len(sequences[0]) @@ -155,7 +155,7 @@ class ParallelFunction(RemoteFunction): # multiplexed: targets = self.view.targets nparts = len(targets) - + msg_ids = [] # my_f = lambda *a: map(self.func, *a) client = self.view.client @@ -169,7 +169,7 @@ class ParallelFunction(RemoteFunction): args.append(part) if not args: continue - + # print (args) if hasattr(self, '_map'): if sys.version_info[0] >= 3: @@ -179,15 +179,15 @@ class ParallelFunction(RemoteFunction): args = [self.func]+args else: f=self.func - + view = self.view if balanced else client[t] with view.temp_flags(block=False, **self.flags): ar = view.apply(f, *args) - + msg_ids.append(ar.msg_ids[0]) - + r = AsyncMapResult(self.view.client, msg_ids, self.mapObject, fname=self.func.__name__) - + if self.block: try: return r.get() @@ -195,9 +195,9 @@ class ParallelFunction(RemoteFunction): return r else: return r - + def map(self, *sequences): - """call a function on each element of a sequence remotely. + """call a function on each element of a sequence remotely. This should behave very much like the builtin map, but return an AsyncMapResult if self.block is False. """ diff --git a/IPython/parallel/client/view.py b/IPython/parallel/client/view.py index 1b1eae6..a5eb8ca 100644 --- a/IPython/parallel/client/view.py +++ b/IPython/parallel/client/view.py @@ -76,56 +76,56 @@ def spin_after(f, self, *args, **kwargs): @skip_doctest class View(HasTraits): """Base View class for more convenint apply(f,*args,**kwargs) syntax via attributes. - + Don't use this class, use subclasses. - + Methods ------- - + spin flushes incoming results and registration state changes control methods spin, and requesting `ids` also ensures up to date - + wait wait on one or more msg_ids - + execution methods apply legacy: execute, run - + data movement push, pull, scatter, gather - + query methods get_result, queue_status, purge_results, result_status - + control methods abort, shutdown - + """ # flags block=Bool(False) track=Bool(True) targets = Any() - + history=List() outstanding = Set() results = Dict() client = Instance('IPython.parallel.Client') - + _socket = Instance('zmq.Socket') _flag_names = List(['targets', 'block', 'track']) _targets = Any() _idents = Any() - + def __init__(self, client=None, socket=None, **flags): super(View, self).__init__(client=client, _socket=socket) self.block = client.block - + self.set_flags(**flags) - + assert not self.__class__ is View, "Don't use base View objects, use subclasses" - + def __repr__(self): strtargets = str(self.targets) @@ -135,17 +135,17 @@ class View(HasTraits): def set_flags(self, **kwargs): """set my attribute flags by keyword. - + Views determine behavior with a few attributes (`block`, `track`, etc.). These attributes can be set all at once by name with this method. - + Parameters ---------- - + block : bool whether to wait for results track : bool - whether to create a MessageTracker to allow the user to + whether to create a MessageTracker to allow the user to safely edit after arrays and buffers during non-copying sends. """ @@ -154,16 +154,16 @@ class View(HasTraits): raise KeyError("Invalid name: %r"%name) else: setattr(self, name, value) - + @contextmanager def temp_flags(self, **kwargs): """temporarily set flags, for use in `with` statements. - + See set_flags for permanent setting of flags - + Examples -------- - + >>> view.track=False ... >>> with view.temp_flags(track=True): @@ -171,7 +171,7 @@ class View(HasTraits): ... ar.tracker.wait() # wait for send to finish >>> view.track False - + """ # preflight: save flags, and set temporaries saved_flags = {} @@ -184,23 +184,23 @@ class View(HasTraits): finally: # postflight: restore saved flags self.set_flags(**saved_flags) - - + + #---------------------------------------------------------------- # apply #---------------------------------------------------------------- - + @sync_results @save_ids def _really_apply(self, f, args, kwargs, block=None, **options): """wrapper for client.send_apply_message""" raise NotImplementedError("Implement in subclasses") - + def apply(self, f, *args, **kwargs): """calls f(*args, **kwargs) on remote engines, returning the result. - + This method sets all apply flags via this View's attributes. - + if self.block is False: returns AsyncResult else: @@ -210,7 +210,7 @@ class View(HasTraits): def apply_async(self, f, *args, **kwargs): """calls f(*args, **kwargs) on remote engines in a nonblocking manner. - + returns AsyncResult """ return self._really_apply(f, args, kwargs, block=False) @@ -219,7 +219,7 @@ class View(HasTraits): def apply_sync(self, f, *args, **kwargs): """calls f(*args, **kwargs) on remote engines in a blocking manner, returning the result. - + returns: actual result of f(*args, **kwargs) """ return self._really_apply(f, args, kwargs, block=True) @@ -231,14 +231,14 @@ class View(HasTraits): def spin(self): """spin the client, and sync""" self.client.spin() - + @sync_results def wait(self, jobs=None, timeout=-1): """waits on one or more `jobs`, for up to `timeout` seconds. - + Parameters ---------- - + jobs : int, str, or list of ints and/or strs, or one or more AsyncResult objects ints are indices to self.history strs are msg_ids @@ -246,23 +246,23 @@ class View(HasTraits): timeout : float a time in seconds, after which to give up. default is -1, which means no timeout - + Returns ------- - + True : when all msg_ids are done False : timeout reached, some msg_ids still outstanding """ if jobs is None: jobs = self.history return self.client.wait(jobs, timeout) - + def abort(self, jobs=None, targets=None, block=None): """Abort jobs on my engines. - + Parameters ---------- - + jobs : None, str, list of strs, optional if None: abort all jobs. else: abort specific msg_id(s). @@ -275,13 +275,13 @@ class View(HasTraits): """Fetch the Queue status of my engines""" targets = targets if targets is not None else self.targets return self.client.queue_status(targets=targets, verbose=verbose) - + def purge_results(self, jobs=[], targets=[]): """Instruct the controller to forget specific results.""" if targets is None or targets == 'all': targets = self.targets return self.client.purge_results(jobs=jobs, targets=targets) - + def shutdown(self, targets=None, restart=False, hub=False, block=None): """Terminates one or more engine processes, optionally including the hub. """ @@ -289,15 +289,15 @@ class View(HasTraits): if targets is None or targets == 'all': targets = self.targets return self.client.shutdown(targets=targets, restart=restart, hub=hub, block=block) - + @spin_after def get_result(self, indices_or_msg_ids=None): """return one or more results, specified by history index or msg_id. - + See client.get_result for details. - + """ - + if indices_or_msg_ids is None: indices_or_msg_ids = -1 if isinstance(indices_or_msg_ids, int): @@ -308,57 +308,57 @@ class View(HasTraits): if isinstance(index, int): indices_or_msg_ids[i] = self.history[index] return self.client.get_result(indices_or_msg_ids) - + #------------------------------------------------------------------- # Map #------------------------------------------------------------------- - + def map(self, f, *sequences, **kwargs): """override in subclasses""" raise NotImplementedError - + def map_async(self, f, *sequences, **kwargs): """Parallel version of builtin `map`, using this view's engines. - + This is equivalent to map(...block=False) - + See `self.map` for details. """ if 'block' in kwargs: raise TypeError("map_async doesn't take a `block` keyword argument.") kwargs['block'] = False return self.map(f,*sequences,**kwargs) - + def map_sync(self, f, *sequences, **kwargs): """Parallel version of builtin `map`, using this view's engines. - + This is equivalent to map(...block=True) - + See `self.map` for details. """ if 'block' in kwargs: raise TypeError("map_sync doesn't take a `block` keyword argument.") kwargs['block'] = True return self.map(f,*sequences,**kwargs) - + def imap(self, f, *sequences, **kwargs): """Parallel version of `itertools.imap`. - + See `self.map` for details. - + """ - + return iter(self.map_async(f,*sequences, **kwargs)) - + #------------------------------------------------------------------- # Decorators #------------------------------------------------------------------- - + def remote(self, block=True, **flags): """Decorator for making a RemoteFunction""" block = self.block if block is None else block return remote(self, block=block, **flags) - + def parallel(self, dist='b', block=None, **flags): """Decorator for making a ParallelFunction""" block = self.block if block is None else block @@ -367,45 +367,45 @@ class View(HasTraits): @skip_doctest class DirectView(View): """Direct Multiplexer View of one or more engines. - + These are created via indexed access to a client: - + >>> dv_1 = client[1] >>> dv_all = client[:] >>> dv_even = client[::2] >>> dv_some = client[1:3] - + This object provides dictionary access to engine namespaces: - + # push a=5: - >>> dv['a'] = 5 + >>> dv['a'] = 5 # pull 'foo': >>> db['foo'] - + """ - + def __init__(self, client=None, socket=None, targets=None): super(DirectView, self).__init__(client=client, socket=socket, targets=targets) - + @property def importer(self): """sync_imports(local=True) as a property. - + See sync_imports for details. - + """ return self.sync_imports(True) - + @contextmanager def sync_imports(self, local=True): """Context Manager for performing simultaneous local and remote imports. - + 'import x as y' will *not* work. The 'as y' part will simply be ignored. - + >>> with view.sync_imports(): ... from numpy import recarray importing recarray from numpy on engine(s) - + """ import __builtin__ local_import = __builtin__.__import__ @@ -424,7 +424,7 @@ class DirectView(View): user_ns[key] = getattr(mod, key) else: user_ns[name] = sys.modules[name] - + def view_import(name, globals={}, locals={}, fromlist=[], level=-1): """the drop-in replacement for __import__, that optionally imports locally as well. @@ -432,19 +432,19 @@ class DirectView(View): # don't override nested imports save_import = __builtin__.__import__ __builtin__.__import__ = local_import - + if imp.lock_held(): # this is a side-effect import, don't do it remotely, or even # ignore the local effects return local_import(name, globals, locals, fromlist, level) - + imp.acquire_lock() if local: mod = local_import(name, globals, locals, fromlist, level) else: raise NotImplementedError("remote-only imports not yet implemented") imp.release_lock() - + key = name+':'+','.join(fromlist or []) if level == -1 and key not in modules: modules.add(key) @@ -455,9 +455,9 @@ class DirectView(View): results.append(self.apply_async(remote_import, name, fromlist, level)) # restore override __builtin__.__import__ = save_import - + return mod - + # override __import__ __builtin__.__import__ = view_import try: @@ -470,38 +470,38 @@ class DirectView(View): finally: # always restore __import__ __builtin__.__import__ = local_import - + for r in results: # raise possible remote ImportErrors here r.get() - - + + @sync_results @save_ids def _really_apply(self, f, args=None, kwargs=None, targets=None, block=None, track=None): """calls f(*args, **kwargs) on remote engines, returning the result. - + This method sets all of `apply`'s flags via this View's attributes. - + Parameters ---------- - + f : callable - + args : list [default: empty] - + kwargs : dict [default: empty] - + targets : target list [default: self.targets] where to run block : bool [default: self.block] - whether to block + whether to block track : bool [default: self.track] whether to ask zmq to track the message, for safe non-copying sends - + Returns ------- - + if self.block is False: returns AsyncResult else: @@ -514,7 +514,7 @@ class DirectView(View): block = self.block if block is None else block track = self.track if track is None else track targets = self.targets if targets is None else targets - + _idents = self.client._build_targets(targets)[0] msg_ids = [] trackers = [] @@ -532,31 +532,31 @@ class DirectView(View): except KeyboardInterrupt: pass return ar - + @spin_after def map(self, f, *sequences, **kwargs): """view.map(f, *sequences, block=self.block) => list|AsyncMapResult - + Parallel version of builtin `map`, using this View's `targets`. - + There will be one task per target, so work will be chunked - if the sequences are longer than `targets`. - + if the sequences are longer than `targets`. + Results can be iterated as they are ready, but will become available in chunks. - + Parameters ---------- - + f : callable function to be mapped *sequences: one or more sequences of matching length the sequences to be distributed and passed to `f` block : bool whether to wait for the result or not [default self.block] - + Returns ------- - + if block=False: AsyncMapResult An object like AsyncResult, but which reassembles the sequence of results @@ -566,24 +566,24 @@ class DirectView(View): list the result of map(f,*sequences) """ - + block = kwargs.pop('block', self.block) for k in kwargs.keys(): if k not in ['block', 'track']: raise TypeError("invalid keyword arg, %r"%k) - + assert len(sequences) > 0, "must have some sequences to map onto!" pf = ParallelFunction(self, f, block=block, **kwargs) return pf.map(*sequences) - + def execute(self, code, targets=None, block=None): """Executes `code` on `targets` in blocking or nonblocking manner. - + ``execute`` is always `bound` (affects engine namespace) - + Parameters ---------- - + code : str the code string to be executed block : bool @@ -591,15 +591,15 @@ class DirectView(View): default: self.block """ return self._really_apply(util._execute, args=(code,), block=block, targets=targets) - + def run(self, filename, targets=None, block=None): - """Execute contents of `filename` on my engine(s). - + """Execute contents of `filename` on my engine(s). + This simply reads the contents of the file and calls `execute`. - + Parameters ---------- - + filename : str The path to the file targets : int/str/list of ints/strs @@ -608,34 +608,34 @@ class DirectView(View): block : bool whether or not to wait until done default: self.block - + """ with open(filename, 'r') as f: # add newline in case of trailing indented whitespace # which will cause SyntaxError code = f.read()+'\n' return self.execute(code, block=block, targets=targets) - + def update(self, ns): """update remote namespace with dict `ns` - + See `push` for details. """ return self.push(ns, block=self.block, track=self.track) - + def push(self, ns, targets=None, block=None, track=None): """update remote namespace with dict `ns` - + Parameters ---------- - + ns : dict dict of keys with which to update engine namespace(s) block : bool [default : self.block] whether to wait to be notified of engine receipt - + """ - + block = block if block is not None else self.block track = track if track is not None else self.track targets = targets if targets is not None else self.targets @@ -646,15 +646,15 @@ class DirectView(View): def get(self, key_s): """get object(s) by `key_s` from remote namespace - + see `pull` for details. """ # block = block if block is not None else self.block return self.pull(key_s, block=True) - + def pull(self, names, targets=None, block=None): """get object(s) by `name` from remote namespace - + will return one object if it is a key. can also take a list of keys, in which case it will return a list of objects. """ @@ -670,7 +670,7 @@ class DirectView(View): else: raise TypeError("names must be strs, not %r"%names) return self._really_apply(util._pull, (names,), block=block, targets=targets) - + def scatter(self, key, seq, dist='b', flatten=False, targets=None, block=None, track=None): """ Partition a Python sequence and send the partitions to a set of engines. @@ -678,7 +678,7 @@ class DirectView(View): block = block if block is not None else self.block track = track if track is not None else self.track targets = targets if targets is not None else self.targets - + mapObject = Map.dists[dist]() nparts = len(targets) msg_ids = [] @@ -693,18 +693,18 @@ class DirectView(View): msg_ids.extend(r.msg_ids) if track: trackers.append(r._tracker) - + if track: tracker = zmq.MessageTracker(*trackers) else: tracker = None - + r = AsyncResult(self.client, msg_ids, fname='scatter', targets=targets, tracker=tracker) if block: r.wait() else: return r - + @sync_results @save_ids def gather(self, key, dist='b', targets=None, block=None): @@ -715,53 +715,53 @@ class DirectView(View): targets = targets if targets is not None else self.targets mapObject = Map.dists[dist]() msg_ids = [] - + for index, engineid in enumerate(targets): msg_ids.extend(self.pull(key, block=False, targets=engineid).msg_ids) - + r = AsyncMapResult(self.client, msg_ids, mapObject, fname='gather') - + if block: try: return r.get() except KeyboardInterrupt: pass return r - + def __getitem__(self, key): return self.get(key) - + def __setitem__(self,key, value): self.update({key:value}) - + def clear(self, targets=None, block=False): """Clear the remote namespaces on my engines.""" block = block if block is not None else self.block targets = targets if targets is not None else self.targets return self.client.clear(targets=targets, block=block) - + def kill(self, targets=None, block=True): """Kill my engines.""" block = block if block is not None else self.block targets = targets if targets is not None else self.targets return self.client.kill(targets=targets, block=block) - + #---------------------------------------- # activate for %px,%autopx magics #---------------------------------------- def activate(self): """Make this `View` active for parallel magic commands. - + IPython has a magic command syntax to work with `MultiEngineClient` objects. In a given IPython session there is a single active one. While - there can be many `Views` created and used by the user, - there is only one active one. The active `View` is used whenever + there can be many `Views` created and used by the user, + there is only one active one. The active `View` is used whenever the magic commands %px and %autopx are used. - - The activate() method is called on a given `View` to make it + + The activate() method is called on a given `View` to make it active. Once this has been done, the magic commands can be used. """ - + try: # This is injected into __builtins__. ip = get_ipython() @@ -779,34 +779,34 @@ class DirectView(View): @skip_doctest class LoadBalancedView(View): """An load-balancing View that only executes via the Task scheduler. - + Load-balanced views can be created with the client's `view` method: - + >>> v = client.load_balanced_view() - + or targets can be specified, to restrict the potential destinations: - + >>> v = client.client.load_balanced_view(([1,3]) - + which would restrict loadbalancing to between engines 1 and 3. - + """ - + follow=Any() after=Any() timeout=CFloat() retries = CInt(0) - + _task_scheme = Any() _flag_names = List(['targets', 'block', 'track', 'follow', 'after', 'timeout', 'retries']) - + def __init__(self, client=None, socket=None, **flags): super(LoadBalancedView, self).__init__(client=client, socket=socket, **flags) self._task_scheme=client._task_scheme - + def _validate_dependency(self, dep): """validate a dependency. - + For use in `set_flags`. """ if dep is None or isinstance(dep, (basestring, AsyncResult, Dependency)): @@ -825,9 +825,9 @@ class LoadBalancedView(View): return False else: return False - + return True - + def _render_dependency(self, dep): """helper for building jsonable dependencies from various input forms.""" if isinstance(dep, Dependency): @@ -842,18 +842,18 @@ class LoadBalancedView(View): def set_flags(self, **kwargs): """set my attribute flags by keyword. - + A View is a wrapper for the Client's apply method, but with attributes that specify keyword arguments, those attributes can be set by keyword argument with this method. - + Parameters ---------- - + block : bool whether to wait for results track : bool - whether to create a MessageTracker to allow the user to + whether to create a MessageTracker to allow the user to safely edit after arrays and buffers during non-copying sends. @@ -878,7 +878,7 @@ class LoadBalancedView(View): retries : int Number of times a task will be retried on failure. """ - + super(LoadBalancedView, self).set_flags(**kwargs) for name in ('follow', 'after'): if name in kwargs: @@ -895,35 +895,35 @@ class LoadBalancedView(View): if t < 0: raise ValueError("Invalid timeout: %s"%t) self.timeout = t - + @sync_results @save_ids def _really_apply(self, f, args=None, kwargs=None, block=None, track=None, after=None, follow=None, timeout=None, targets=None, retries=None): """calls f(*args, **kwargs) on a remote engine, returning the result. - + This method temporarily sets all of `apply`'s flags for a single call. - + Parameters ---------- - + f : callable - + args : list [default: empty] - + kwargs : dict [default: empty] - + block : bool [default: self.block] - whether to block + whether to block track : bool [default: self.track] whether to ask zmq to track the message, for safe non-copying sends - + !!!!!! TODO: THE REST HERE !!!! - + Returns ------- - + if self.block is False: returns AsyncResult else: @@ -939,7 +939,7 @@ class LoadBalancedView(View): msg += " because the pure ZMQ scheduler cannot handle" msg += " disappearing engines." raise RuntimeError(msg) - + if self._task_scheme == 'pure': # pure zmq scheme doesn't support extra features msg = "Pure ZMQ scheduler doesn't support the following flags:" @@ -950,7 +950,7 @@ class LoadBalancedView(View): if isinstance(f, dependent): # soft warn on functional dependencies warnings.warn(msg, RuntimeWarning) - + # build args args = [] if args is None else args kwargs = {} if kwargs is None else kwargs @@ -961,7 +961,7 @@ class LoadBalancedView(View): follow = self.follow if follow is None else follow timeout = self.timeout if timeout is None else timeout targets = self.targets if targets is None else targets - + if not isinstance(retries, int): raise TypeError('retries must be int, not %r'%type(retries)) @@ -971,40 +971,40 @@ class LoadBalancedView(View): idents = self.client._build_targets(targets)[0] # ensure *not* bytes idents = [ ident.decode() for ident in idents ] - + after = self._render_dependency(after) follow = self._render_dependency(follow) subheader = dict(after=after, follow=follow, timeout=timeout, targets=idents, retries=retries) - + msg = self.client.send_apply_message(self._socket, f, args, kwargs, track=track, subheader=subheader) tracker = None if track is False else msg['tracker'] - + ar = AsyncResult(self.client, msg['header']['msg_id'], fname=f.__name__, targets=None, tracker=tracker) - + if block: try: return ar.get() except KeyboardInterrupt: pass return ar - + @spin_after @save_ids def map(self, f, *sequences, **kwargs): """view.map(f, *sequences, block=self.block, chunksize=1) => list|AsyncMapResult - + Parallel version of builtin `map`, load-balanced by this View. - + `block`, and `chunksize` can be specified by keyword only. - + Each `chunksize` elements will be a separate task, and will be load-balanced. This lets individual elements be available for iteration as soon as they arrive. - + Parameters ---------- - + f : callable function to be mapped *sequences: one or more sequences of matching length @@ -1012,15 +1012,15 @@ class LoadBalancedView(View): block : bool whether to wait for the result or not [default self.block] track : bool - whether to create a MessageTracker to allow the user to + whether to create a MessageTracker to allow the user to safely edit after arrays and buffers during non-copying sends. chunksize : int how many elements should be in each task [default 1] - + Returns ------- - + if block=False: AsyncMapResult An object like AsyncResult, but which reassembles the sequence of results @@ -1028,20 +1028,20 @@ class LoadBalancedView(View): results are complete. else: the result of map(f,*sequences) - + """ - + # default block = kwargs.get('block', self.block) chunksize = kwargs.get('chunksize', 1) - + keyset = set(kwargs.keys()) extra_keys = keyset.difference_update(set(['block', 'chunksize'])) if extra_keys: raise TypeError("Invalid kwargs: %s"%list(extra_keys)) - + assert len(sequences) > 0, "must have some sequences to map onto!" - + pf = ParallelFunction(self, f, block=block, chunksize=chunksize) return pf.map(*sequences) diff --git a/IPython/parallel/controller/dictdb.py b/IPython/parallel/controller/dictdb.py index d8caa6a..21e44c5 100644 --- a/IPython/parallel/controller/dictdb.py +++ b/IPython/parallel/controller/dictdb.py @@ -1,4 +1,4 @@ -"""A Task logger that presents our DB interface, +"""A Task logger that presents our DB interface, but exists entirely in memory and implemented with dicts. Authors: @@ -70,7 +70,7 @@ filters = { class CompositeFilter(object): """Composite filter for matching multiple properties.""" - + def __init__(self, dikt): self.tests = [] self.values = [] @@ -91,23 +91,23 @@ class BaseDB(LoggingConfigurable): class DictDB(BaseDB): """Basic in-memory dict-based object for saving Task Records. - + This is the first object to present the DB interface for logging tasks out of memory. - + The interface is based on MongoDB, so adding a MongoDB backend should be straightforward. """ - + _records = Dict() - + def _match_one(self, rec, tests): """Check if a specific record matches tests.""" for key,test in tests.iteritems(): if not test(rec.get(key, None)): return False return True - + def _match(self, check): """Find all the matches for a check dict.""" matches = [] @@ -117,12 +117,12 @@ class DictDB(BaseDB): tests[k] = CompositeFilter(v) else: tests[k] = lambda o: o==v - + for rec in self._records.itervalues(): if self._match_one(rec, tests): matches.append(rec) return matches - + def _extract_subdict(self, rec, keys): """extract subdict of keys""" d = {} @@ -130,42 +130,42 @@ class DictDB(BaseDB): for key in keys: d[key] = rec[key] return d - + def add_record(self, msg_id, rec): """Add a new Task Record, by msg_id.""" if self._records.has_key(msg_id): raise KeyError("Already have msg_id %r"%(msg_id)) self._records[msg_id] = rec - + def get_record(self, msg_id): """Get a specific Task Record, by msg_id.""" if not self._records.has_key(msg_id): raise KeyError("No such msg_id %r"%(msg_id)) return self._records[msg_id] - + def update_record(self, msg_id, rec): """Update the data in an existing record.""" self._records[msg_id].update(rec) - + def drop_matching_records(self, check): """Remove a record from the DB.""" matches = self._match(check) for m in matches: del self._records[m['msg_id']] - + def drop_record(self, msg_id): """Remove a record from the DB.""" del self._records[msg_id] - - + + def find_records(self, check, keys=None): """Find records matching a query dict, optionally extracting subset of keys. - + Returns dict keyed by msg_id of matching records. - + Parameters ---------- - + check: dict mongodb-style query argument keys: list of strs [optional] @@ -177,8 +177,8 @@ class DictDB(BaseDB): return [ self._extract_subdict(rec, keys) for rec in matches ] else: return matches - - + + def get_history(self): """get all msg_ids, ordered by time submitted.""" msg_ids = self._records.keys() diff --git a/IPython/parallel/controller/heartmonitor.py b/IPython/parallel/controller/heartmonitor.py index ad4fc7b..77e75f7 100755 --- a/IPython/parallel/controller/heartmonitor.py +++ b/IPython/parallel/controller/heartmonitor.py @@ -31,10 +31,10 @@ class Heart(object): """A basic heart object for responding to a HeartMonitor. This is a simple wrapper with defaults for the most common Device model for responding to heartbeats. - - It simply builds a threadsafe zmq.FORWARDER Device, defaulting to using + + It simply builds a threadsafe zmq.FORWARDER Device, defaulting to using SUB/XREQ for in/out. - + You can specify the XREQ's IDENTITY via the optional heart_id argument.""" device=None id=None @@ -49,27 +49,27 @@ class Heart(object): heart_id = uuid.uuid4().bytes self.device.setsockopt_out(zmq.IDENTITY, heart_id) self.id = heart_id - + def start(self): return self.device.start() - + class HeartMonitor(LoggingConfigurable): """A basic HeartMonitor class pingstream: a PUB stream pongstream: an XREP stream period: the period of the heartbeat in milliseconds""" - + period=CFloat(1000, config=True, help='The frequency at which the Hub pings the engines for heartbeats ' ' (in ms) [default: 100]', ) - + pingstream=Instance('zmq.eventloop.zmqstream.ZMQStream') pongstream=Instance('zmq.eventloop.zmqstream.ZMQStream') loop = Instance('zmq.eventloop.ioloop.IOLoop') def _loop_default(self): return ioloop.IOLoop.instance() - + # not settable: hearts=Set() responses=Set() @@ -79,30 +79,30 @@ class HeartMonitor(LoggingConfigurable): _failure_handlers = Set() lifetime = CFloat(0) tic = CFloat(0) - + def __init__(self, **kwargs): super(HeartMonitor, self).__init__(**kwargs) - + self.pongstream.on_recv(self.handle_pong) - + def start(self): self.caller = ioloop.PeriodicCallback(self.beat, self.period, self.loop) self.caller.start() - + def add_new_heart_handler(self, handler): """add a new handler for new hearts""" self.log.debug("heartbeat::new_heart_handler: %s"%handler) self._new_handlers.add(handler) - + def add_heart_failure_handler(self, handler): """add a new handler for heart failure""" self.log.debug("heartbeat::new heart failure handler: %s"%handler) self._failure_handlers.add(handler) - + def beat(self): - self.pongstream.flush() + self.pongstream.flush() self.last_ping = self.lifetime - + toc = time.time() self.lifetime += toc-self.tic self.tic = toc @@ -118,7 +118,7 @@ class HeartMonitor(LoggingConfigurable): # print self.on_probation, self.hearts # self.log.debug("heartbeat::beat %.3f, %i beating hearts"%(self.lifetime, len(self.hearts))) self.pingstream.send(asbytes(str(self.lifetime))) - + def handle_new_heart(self, heart): if self._new_handlers: for handler in self._new_handlers: @@ -126,7 +126,7 @@ class HeartMonitor(LoggingConfigurable): else: self.log.info("heartbeat::yay, got new heart %s!"%heart) self.hearts.add(heart) - + def handle_heart_failure(self, heart): if self._failure_handlers: for handler in self._failure_handlers: @@ -138,8 +138,8 @@ class HeartMonitor(LoggingConfigurable): else: self.log.info("heartbeat::Heart %s failed :("%heart) self.hearts.remove(heart) - - + + def handle_pong(self, msg): "a heart just beat" current = asbytes(str(self.lifetime)) @@ -164,10 +164,10 @@ if __name__ == '__main__': pub.bind('tcp://127.0.0.1:5555') xrep = context.socket(zmq.ROUTER) xrep.bind('tcp://127.0.0.1:5556') - + outstream = zmqstream.ZMQStream(pub, loop) instream = zmqstream.ZMQStream(xrep, loop) - + hb = HeartMonitor(loop, outstream, instream) - + loop.start() diff --git a/IPython/parallel/controller/hub.py b/IPython/parallel/controller/hub.py index 9dde8fb..d69e5f7 100644 --- a/IPython/parallel/controller/hub.py +++ b/IPython/parallel/controller/hub.py @@ -73,7 +73,7 @@ def empty_record(): 'stdout': '', 'stderr': '', } - + def init_record(msg): """Initialize a TaskRecord based on a request.""" header = msg['header'] @@ -118,7 +118,7 @@ class EngineConnector(HasTraits): class HubFactory(RegistrationFactory): """The Configurable for setting up a Hub.""" - + # port-pairs for monitoredqueues: hb = Tuple(Int,Int,config=True, help="""XREQ/SUB Port pair for Engine heartbeats""") @@ -127,10 +127,10 @@ class HubFactory(RegistrationFactory): mux = Tuple(Int,Int,config=True, help="""Engine/Client Port pair for MUX queue""") - + def _mux_default(self): return tuple(util.select_random_ports(2)) - + task = Tuple(Int,Int,config=True, help="""Engine/Client Port pair for Task queue""") def _task_default(self): @@ -138,88 +138,88 @@ class HubFactory(RegistrationFactory): control = Tuple(Int,Int,config=True, help="""Engine/Client Port pair for Control queue""") - + def _control_default(self): return tuple(util.select_random_ports(2)) iopub = Tuple(Int,Int,config=True, help="""Engine/Client Port pair for IOPub relay""") - + def _iopub_default(self): return tuple(util.select_random_ports(2)) - + # single ports: mon_port = Int(config=True, help="""Monitor (SUB) port for queue traffic""") def _mon_port_default(self): return util.select_random_ports(1)[0] - + notifier_port = Int(config=True, help="""PUB port for sending engine status notifications""") def _notifier_port_default(self): return util.select_random_ports(1)[0] - + engine_ip = Unicode('127.0.0.1', config=True, help="IP on which to listen for engine connections. [default: loopback]") engine_transport = Unicode('tcp', config=True, help="0MQ transport for engine connections. [default: tcp]") - + client_ip = Unicode('127.0.0.1', config=True, help="IP on which to listen for client connections. [default: loopback]") client_transport = Unicode('tcp', config=True, help="0MQ transport for client connections. [default : tcp]") - + monitor_ip = Unicode('127.0.0.1', config=True, help="IP on which to listen for monitor messages. [default: loopback]") monitor_transport = Unicode('tcp', config=True, help="0MQ transport for monitor messages. [default : tcp]") - + monitor_url = Unicode('') - + db_class = DottedObjectName('IPython.parallel.controller.dictdb.DictDB', config=True, help="""The class to use for the DB backend""") - + # not configurable db = Instance('IPython.parallel.controller.dictdb.BaseDB') heartmonitor = Instance('IPython.parallel.controller.heartmonitor.HeartMonitor') - + def _ip_changed(self, name, old, new): self.engine_ip = new self.client_ip = new self.monitor_ip = new self._update_monitor_url() - + def _update_monitor_url(self): self.monitor_url = "%s://%s:%i"%(self.monitor_transport, self.monitor_ip, self.mon_port) - + def _transport_changed(self, name, old, new): self.engine_transport = new self.client_transport = new self.monitor_transport = new self._update_monitor_url() - + def __init__(self, **kwargs): super(HubFactory, self).__init__(**kwargs) self._update_monitor_url() - - + + def construct(self): self.init_hub() - + def start(self): self.heartmonitor.start() self.log.info("Heartmonitor started") - + def init_hub(self): """construct""" client_iface = "%s://%s:"%(self.client_transport, self.client_ip) + "%i" engine_iface = "%s://%s:"%(self.engine_transport, self.engine_ip) + "%i" - + ctx = self.context loop = self.loop - + # Registrar socket q = ZMQStream(ctx.socket(zmq.ROUTER), loop) q.bind(client_iface % self.regport) @@ -227,7 +227,7 @@ class HubFactory(RegistrationFactory): if self.client_ip != self.engine_ip: q.bind(engine_iface % self.regport) self.log.info("Hub listening on %s for registration."%(engine_iface%self.regport)) - + ### Engine connections ### # heartbeat @@ -253,11 +253,11 @@ class HubFactory(RegistrationFactory): sub.bind(self.monitor_url) sub.bind('inproc://monitor') sub = ZMQStream(sub, loop) - + # connect the db self.log.info('Hub using DB backend: %r'%(self.db_class.split()[-1])) # cdir = self.config.Global.cluster_dir - self.db = import_item(str(self.db_class))(session=self.session.session, + self.db = import_item(str(self.db_class))(session=self.session.session, config=self.config, log=self.log) time.sleep(.25) try: @@ -295,11 +295,11 @@ class HubFactory(RegistrationFactory): query=q, notifier=n, resubmit=r, db=self.db, engine_info=self.engine_info, client_info=self.client_info, log=self.log) - + class Hub(SessionFactory): """The IPython Controller Hub with 0MQ connections - + Parameters ========== loop: zmq IOLoop instance @@ -333,7 +333,7 @@ class Hub(SessionFactory): incoming_registrations=Dict() registration_timeout=Int() _idcounter=Int(0) - + # objects from constructor: query=Instance(ZMQStream) monitor=Instance(ZMQStream) @@ -343,8 +343,8 @@ class Hub(SessionFactory): db=Instance(object) client_info=Dict() engine_info=Dict() - - + + def __init__(self, **kwargs): """ # universal: @@ -359,10 +359,10 @@ class Hub(SessionFactory): engine_info: zmq address/protocol dict for engine connections client_info: zmq address/protocol dict for client connections """ - + super(Hub, self).__init__(**kwargs) self.registration_timeout = max(5000, 2*self.heartmonitor.period) - + # validate connection dicts: for k,v in self.client_info.iteritems(): if k == 'task': @@ -371,14 +371,14 @@ class Hub(SessionFactory): util.validate_url_container(v) # util.validate_url_container(self.client_info) util.validate_url_container(self.engine_info) - + # register our callbacks self.query.on_recv(self.dispatch_query) self.monitor.on_recv(self.dispatch_monitor_traffic) - + self.heartmonitor.add_heart_failure_handler(self.handle_heart_failure) self.heartmonitor.add_new_heart_handler(self.handle_new_heart) - + self.monitor_handlers = {b'in' : self.save_queue_request, b'out': self.save_queue_result, b'intask': self.save_task_request, @@ -388,7 +388,7 @@ class Hub(SessionFactory): b'outcontrol': _passer, b'iopub': self.save_iopub_message, } - + self.query_handlers = {'queue_request': self.queue_status, 'result_request': self.get_results, 'history_request': self.get_history, @@ -401,16 +401,16 @@ class Hub(SessionFactory): 'unregistration_request' : self.unregister_engine, 'connection_request': self.connection_request, } - + # ignore resubmit replies self.resubmit.on_recv(lambda msg: None, copy=False) self.log.info("hub::created hub") - + @property def _next_id(self): """gemerate a new ID. - + No longer reuse old ids, just count from 0.""" newid = self._idcounter self._idcounter += 1 @@ -421,17 +421,17 @@ class Hub(SessionFactory): # while newid in self.ids or newid in incoming: # newid += 1 # return newid - + #----------------------------------------------------------------------------- # message validation #----------------------------------------------------------------------------- - + def _validate_targets(self, targets): """turn any valid targets argument into a list of integer ids""" if targets is None: # default to all targets = self.ids - + if isinstance(targets, (int,str,unicode)): # only one target specified targets = [targets] @@ -448,12 +448,12 @@ class Hub(SessionFactory): if not targets: raise IndexError("No Engines Registered") return targets - + #----------------------------------------------------------------------------- # dispatch methods (1 per stream) #----------------------------------------------------------------------------- - - + + def dispatch_monitor_traffic(self, msg): """all ME and Task queue messages come through here, as well as IOPub traffic.""" @@ -471,8 +471,8 @@ class Hub(SessionFactory): handler(idents, msg) else: self.log.error("Invalid monitor topic: %r"%switch) - - + + def dispatch_query(self, msg): """Route registration requests and queries from clients.""" try: @@ -488,7 +488,7 @@ class Hub(SessionFactory): except Exception: content = error.wrap_exception() self.log.error("Bad Query Message: %r"%msg, exc_info=True) - self.session.send(self.query, "hub_error", ident=client_id, + self.session.send(self.query, "hub_error", ident=client_id, content=content) return # print client_id, header, parent, content @@ -501,23 +501,23 @@ class Hub(SessionFactory): except: content = error.wrap_exception() self.log.error("Bad Message Type: %r"%msg_type, exc_info=True) - self.session.send(self.query, "hub_error", ident=client_id, + self.session.send(self.query, "hub_error", ident=client_id, content=content) return else: handler(idents, msg) - + def dispatch_db(self, msg): """""" raise NotImplementedError - + #--------------------------------------------------------------------------- # handler methods (1 per event) #--------------------------------------------------------------------------- - + #----------------------- Heartbeat -------------------------------------- - + def handle_new_heart(self, heart): """handler to attach to heartbeater. Called when a new heart starts to beat. @@ -527,8 +527,8 @@ class Hub(SessionFactory): self.log.info("heartbeat::ignoring new heart: %r"%heart) else: self.finish_registration(heart) - - + + def handle_heart_failure(self, heart): """handler to attach to heartbeater. called when a previously registered heart fails to respond to beat request. @@ -540,9 +540,9 @@ class Hub(SessionFactory): self.log.info("heartbeat::ignoring heart failure %r"%heart) else: self.unregister_engine(heart, dict(content=dict(id=eid, queue=queue))) - + #----------------------- MUX Queue Traffic ------------------------------ - + def save_queue_request(self, idents, msg): if len(idents) < 2: self.log.error("invalid identity prefix: %r"%idents) @@ -553,7 +553,7 @@ class Hub(SessionFactory): except Exception: self.log.error("queue::client %r sent invalid message to %r: %r"%(client_id, queue_id, msg), exc_info=True) return - + eid = self.by_ident.get(queue_id, None) if eid is None: self.log.error("queue::target %r not registered"%queue_id) @@ -584,16 +584,16 @@ class Hub(SessionFactory): self.db.add_record(msg_id, record) except Exception: self.log.error("DB Error adding record %r"%msg_id, exc_info=True) - - + + self.pending.add(msg_id) self.queues[eid].append(msg_id) - + def save_queue_result(self, idents, msg): if len(idents) < 2: self.log.error("invalid identity prefix: %r"%idents) return - + client_id, queue_id = idents[:2] try: msg = self.session.unserialize(msg) @@ -601,12 +601,12 @@ class Hub(SessionFactory): self.log.error("queue::engine %r sent invalid message to %r: %r"%( queue_id,client_id, msg), exc_info=True) return - + eid = self.by_ident.get(queue_id, None) if eid is None: self.log.error("queue::unknown engine %r is sending a reply: "%queue_id) return - + parent = msg['parent_header'] if not parent: return @@ -637,14 +637,14 @@ class Hub(SessionFactory): self.db.update_record(msg_id, result) except Exception: self.log.error("DB Error updating record %r"%msg_id, exc_info=True) - - + + #--------------------- Task Queue Traffic ------------------------------ - + def save_task_request(self, idents, msg): """Save the submission of a task.""" client_id = idents[0] - + try: msg = self.session.unserialize(msg) except Exception: @@ -691,7 +691,7 @@ class Hub(SessionFactory): self.log.error("DB Error adding record %r"%msg_id, exc_info=True) except Exception: self.log.error("DB Error saving task request %r"%msg_id, exc_info=True) - + def save_task_result(self, idents, msg): """save the result of a completed task.""" client_id = idents[0] @@ -701,7 +701,7 @@ class Hub(SessionFactory): self.log.error("task::invalid task result message send to %r: %r"%( client_id, msg), exc_info=True) return - + parent = msg['parent_header'] if not parent: # print msg @@ -710,11 +710,11 @@ class Hub(SessionFactory): msg_id = parent['msg_id'] if msg_id in self.unassigned: self.unassigned.remove(msg_id) - + header = msg['header'] engine_uuid = header.get('engine', None) eid = self.by_ident.get(engine_uuid, None) - + if msg_id in self.pending: self.pending.remove(msg_id) self.all_completed.add(msg_id) @@ -737,10 +737,10 @@ class Hub(SessionFactory): self.db.update_record(msg_id, result) except Exception: self.log.error("DB Error saving task request %r"%msg_id, exc_info=True) - + else: self.log.debug("task::unknown task %r finished"%msg_id) - + def save_task_destination(self, idents, msg): try: msg = self.session.unserialize(msg, content=True) @@ -752,30 +752,30 @@ class Hub(SessionFactory): msg_id = content['msg_id'] engine_uuid = content['engine_id'] eid = self.by_ident[util.asbytes(engine_uuid)] - + self.log.info("task::task %r arrived on %r"%(msg_id, eid)) if msg_id in self.unassigned: self.unassigned.remove(msg_id) # else: # self.log.debug("task::task %r not listed as MIA?!"%(msg_id)) - + self.tasks[eid].append(msg_id) # self.pending[msg_id][1].update(received=datetime.now(),engine=(eid,engine_uuid)) try: self.db.update_record(msg_id, dict(engine_uuid=engine_uuid)) except Exception: self.log.error("DB Error saving task destination %r"%msg_id, exc_info=True) - - + + def mia_task_request(self, idents, msg): raise NotImplementedError client_id = idents[0] # content = dict(mia=self.mia,status='ok') # self.session.send('mia_reply', content=content, idents=client_id) - - + + #--------------------- IOPub Traffic ------------------------------ - + def save_iopub_message(self, topics, msg): """save an iopub message into the db""" # print (topics) @@ -784,7 +784,7 @@ class Hub(SessionFactory): except Exception: self.log.error("iopub::invalid IOPub message", exc_info=True) return - + parent = msg['parent_header'] if not parent: self.log.error("iopub::invalid IOPub message: %r"%msg) @@ -792,7 +792,7 @@ class Hub(SessionFactory): msg_id = parent['msg_id'] msg_type = msg['header']['msg_type'] content = msg['content'] - + # ensure msg_id is in db try: rec = self.db.get_record(msg_id) @@ -806,25 +806,25 @@ class Hub(SessionFactory): name = content['name'] s = rec[name] or '' d[name] = s + content['data'] - + elif msg_type == 'pyerr': d['pyerr'] = content elif msg_type == 'pyin': d['pyin'] = content['code'] else: d[msg_type] = content.get('data', '') - + try: self.db.update_record(msg_id, d) except Exception: self.log.error("DB Error saving iopub message %r"%msg_id, exc_info=True) - - - + + + #------------------------------------------------------------------------- # Registration requests #------------------------------------------------------------------------- - + def connection_request(self, client_id, msg): """Reply with connection addresses for clients.""" self.log.info("client::client %r connected"%client_id) @@ -836,7 +836,7 @@ class Hub(SessionFactory): jsonable[str(k)] = v.decode('ascii') content['engines'] = jsonable self.session.send(self.query, 'connection_reply', content, parent=msg, ident=client_id) - + def register_engine(self, reg, msg): """Register a new engine.""" content = msg['content'] @@ -851,9 +851,9 @@ class Hub(SessionFactory): """register a new engine, and create the socket(s) necessary""" eid = self._next_id # print (eid, queue, reg, heart) - + self.log.debug("registration::register_engine(%i, %r, %r, %r)"%(eid, queue, reg, heart)) - + content = dict(id=eid,status='ok') content.update(self.engine_info) # check if requesting available IDs: @@ -885,11 +885,11 @@ class Hub(SessionFactory): self.log.error("queue_id %r in use"%queue, exc_info=True) content = error.wrap_exception() break - - msg = self.session.send(self.query, "registration_reply", - content=content, + + msg = self.session.send(self.query, "registration_reply", + content=content, ident=reg) - + if content['status'] == 'ok': if heart in self.heartmonitor.hearts: # already beating @@ -903,7 +903,7 @@ class Hub(SessionFactory): else: self.log.error("registration::registration %i failed: %r"%(eid, content['evalue'])) return eid - + def unregister_engine(self, ident, msg): """Unregister an engine that explicitly requested to leave.""" try: @@ -918,7 +918,7 @@ class Hub(SessionFactory): self.dead_engines.add(uuid) # self.ids.remove(eid) # uuid = self.keytable.pop(eid) - # + # # ec = self.engines.pop(eid) # self.hearts.pop(ec.heartbeat) # self.by_ident.pop(ec.queue) @@ -927,20 +927,20 @@ class Hub(SessionFactory): dc = ioloop.DelayedCallback(handleit, self.registration_timeout, self.loop) dc.start() ############## TODO: HANDLE IT ################ - + if self.notifier: self.session.send(self.notifier, "unregistration_notification", content=content) - + def _handle_stranded_msgs(self, eid, uuid): """Handle messages known to be on an engine when the engine unregisters. - + It is possible that this will fire prematurely - that is, an engine will go down after completing a result, and the client will be notified that the result failed and later receive the actual result. """ - + outstanding = self.queues[eid] - + for msg_id in outstanding: self.pending.remove(msg_id) self.all_completed.add(msg_id) @@ -959,12 +959,12 @@ class Hub(SessionFactory): self.db.update_record(msg_id, rec) except Exception: self.log.error("DB Error handling stranded msg %r"%msg_id, exc_info=True) - - + + def finish_registration(self, heart): """Second half of engine registration, called after our HeartMonitor has received a beat from the Engine's Heart.""" - try: + try: (eid,queue,reg,purge) = self.incoming_registrations.pop(heart) except KeyError: self.log.error("registration::tried to finish nonexistant registration", exc_info=True) @@ -975,7 +975,7 @@ class Hub(SessionFactory): control = queue self.ids.add(eid) self.keytable[eid] = queue - self.engines[eid] = EngineConnector(id=eid, queue=queue, registration=reg, + self.engines[eid] = EngineConnector(id=eid, queue=queue, registration=reg, control=control, heartbeat=heart) self.by_ident[queue] = eid self.queues[eid] = list() @@ -986,18 +986,18 @@ class Hub(SessionFactory): if self.notifier: self.session.send(self.notifier, "registration_notification", content=content) self.log.info("engine::Engine Connected: %i"%eid) - + def _purge_stalled_registration(self, heart): if heart in self.incoming_registrations: eid = self.incoming_registrations.pop(heart)[0] self.log.info("registration::purging stalled registration: %i"%eid) else: pass - + #------------------------------------------------------------------------- # Client Requests #------------------------------------------------------------------------- - + def shutdown_request(self, client_id, msg): """handle shutdown request.""" self.session.send(self.query, 'shutdown_reply', content={'status': 'ok'}, ident=client_id) @@ -1005,13 +1005,13 @@ class Hub(SessionFactory): self.session.send(self.notifier, 'shutdown_notice', content={'status': 'ok'}) dc = ioloop.DelayedCallback(lambda : self._shutdown(), 1000, self.loop) dc.start() - + def _shutdown(self): self.log.info("hub::hub shutting down.") time.sleep(0.1) sys.exit(0) - - + + def check_load(self, client_id, msg): content = msg['content'] try: @@ -1019,17 +1019,17 @@ class Hub(SessionFactory): targets = self._validate_targets(targets) except: content = error.wrap_exception() - self.session.send(self.query, "hub_error", + self.session.send(self.query, "hub_error", content=content, ident=client_id) return - + content = dict(status='ok') # loads = {} for t in targets: content[bytes(t)] = len(self.queues[t])+len(self.tasks[t]) self.session.send(self.query, "load_reply", content=content, ident=client_id) - - + + def queue_status(self, client_id, msg): """Return the Queue status of one or more targets. if verbose: return the msg_ids @@ -1043,7 +1043,7 @@ class Hub(SessionFactory): targets = self._validate_targets(targets) except: content = error.wrap_exception() - self.session.send(self.query, "hub_error", + self.session.send(self.query, "hub_error", content=content, ident=client_id) return verbose = content.get('verbose', False) @@ -1060,7 +1060,7 @@ class Hub(SessionFactory): content['unassigned'] = list(self.unassigned) if verbose else len(self.unassigned) # print (content) self.session.send(self.query, "queue_reply", content=content, ident=client_id) - + def purge_results(self, client_id, msg): """Purge results from memory. This method is more valuable before we move to a DB based message storage mechanism.""" @@ -1101,9 +1101,9 @@ class Hub(SessionFactory): except Exception: reply = error.wrap_exception() break - + self.session.send(self.query, 'purge_reply', content=reply, ident=client_id) - + def resubmit_task(self, client_id, msg): """Resubmit one or more tasks.""" def finish(reply): @@ -1169,7 +1169,7 @@ class Hub(SessionFactory): finish(dict(status='ok')) - + def _extract_record(self, rec): """decompose a TaskRecord dict into subsection of reply for get_result""" io_dict = {} @@ -1184,9 +1184,9 @@ class Hub(SessionFactory): buffers = map(bytes, rec['result_buffers']) else: buffers = [] - + return content, buffers - + def get_results(self, client_id, msg): """Get the result of 1 or more messages.""" content = msg['content'] @@ -1207,7 +1207,7 @@ class Hub(SessionFactory): records[rec['msg_id']] = rec except Exception: content = error.wrap_exception() - self.session.send(self.query, "result_reply", content=content, + self.session.send(self.query, "result_reply", content=content, parent=msg, ident=client_id) return else: @@ -1235,7 +1235,7 @@ class Hub(SessionFactory): except: content = error.wrap_exception() break - self.session.send(self.query, "result_reply", content=content, + self.session.send(self.query, "result_reply", content=content, parent=msg, ident=client_id, buffers=buffers) @@ -1247,8 +1247,8 @@ class Hub(SessionFactory): content = error.wrap_exception() else: content = dict(status='ok', history=msg_ids) - - self.session.send(self.query, "history_reply", content=content, + + self.session.send(self.query, "history_reply", content=content, parent=msg, ident=client_id) def db_query(self, client_id, msg): @@ -1270,7 +1270,7 @@ class Hub(SessionFactory): else: buffer_lens = [] result_buffer_lens = [] - + for rec in records: # buffers may be None, so double check if buffer_lens is not None: @@ -1284,7 +1284,7 @@ class Hub(SessionFactory): content = dict(status='ok', records=records, buffer_lens=buffer_lens, result_buffer_lens=result_buffer_lens) # self.log.debug (content) - self.session.send(self.query, "db_reply", content=content, + self.session.send(self.query, "db_reply", content=content, parent=msg, ident=client_id, buffers=buffers) diff --git a/IPython/parallel/controller/scheduler.py b/IPython/parallel/controller/scheduler.py index b063123..2a216a7 100644 --- a/IPython/parallel/controller/scheduler.py +++ b/IPython/parallel/controller/scheduler.py @@ -66,18 +66,18 @@ def plainrandom(loads): def lru(loads): """Always pick the front of the line. - + The content of `loads` is ignored. - + Assumes LRU ordering of loads, with oldest first. """ return 0 def twobin(loads): """Pick two at random, use the LRU of the two. - + The content of loads is ignored. - + Assumes LRU ordering of loads, with oldest first. """ n = len(loads) @@ -87,7 +87,7 @@ def twobin(loads): def weighted(loads): """Pick two at random using inverse load as weight. - + Return the less loaded of the two. """ # weight 0 a million times more than 1: @@ -109,7 +109,7 @@ def weighted(loads): def leastload(loads): """Always choose the lowest load. - + If the lowest load occurs more than once, the first occurance will be used. If loads has LRU ordering, this means the LRU of those with the lowest load is chosen. @@ -124,13 +124,13 @@ MET = Dependency([]) class TaskScheduler(SessionFactory): """Python TaskScheduler object. - + This is the simplest object that supports msg_id based DAG dependencies. *Only* task msg_ids are checked, not msg_ids of jobs submitted via the MUX queue. - + """ - + hwm = Int(0, config=True, shortname='hwm', help="""specify the High Water Mark (HWM) for the downstream socket in the Task scheduler. This is the maximum number @@ -144,7 +144,7 @@ class TaskScheduler(SessionFactory): def _scheme_name_changed(self, old, new): self.log.debug("Using scheme %r"%new) self.scheme = globals()[new] - + # input arguments: scheme = Instance(FunctionType) # function for determining the destination def _scheme_default(self): @@ -153,7 +153,7 @@ class TaskScheduler(SessionFactory): engine_stream = Instance(zmqstream.ZMQStream) # engine-facing stream notifier_stream = Instance(zmqstream.ZMQStream) # hub-facing sub stream mon_stream = Instance(zmqstream.ZMQStream) # hub-facing pub stream - + # internals: graph = Dict() # dict by msg_id of [ msg_ids that depend on key ] retries = Dict() # dict by msg_id of retries remaining (non-neg ints) @@ -173,12 +173,12 @@ class TaskScheduler(SessionFactory): all_ids = Set() # set of all submitted task IDs blacklist = Dict() # dict by msg_id of locations where a job has encountered UnmetDependency auditor = Instance('zmq.eventloop.ioloop.PeriodicCallback') - + ident = CBytes() # ZMQ identity. This should just be self.session.session # but ensure Bytes def _ident_default(self): return self.session.bsession - + def start(self): self.engine_stream.on_recv(self.dispatch_result, copy=False) self._notification_handlers = dict( @@ -189,20 +189,20 @@ class TaskScheduler(SessionFactory): self.auditor = ioloop.PeriodicCallback(self.audit_timeouts, 2e3, self.loop) # 1 Hz self.auditor.start() self.log.info("Scheduler started [%s]"%self.scheme_name) - + def resume_receiving(self): """Resume accepting jobs.""" self.client_stream.on_recv(self.dispatch_submission, copy=False) - + def stop_receiving(self): """Stop accepting jobs while there are no engines. Leave them in the ZMQ queue.""" self.client_stream.on_recv(None) - + #----------------------------------------------------------------------- # [Un]Registration Handling #----------------------------------------------------------------------- - + def dispatch_notification(self, msg): """dispatch register/unregister events.""" try: @@ -215,9 +215,9 @@ class TaskScheduler(SessionFactory): except ValueError: self.log.warn("task::Unauthorized message from: %r"%idents) return - + msg_type = msg['header']['msg_type'] - + handler = self._notification_handlers.get(msg_type, None) if handler is None: self.log.error("Unhandled message type: %r"%msg_type) @@ -226,7 +226,7 @@ class TaskScheduler(SessionFactory): handler(asbytes(msg['content']['queue'])) except Exception: self.log.error("task::Invalid notification msg: %r",msg) - + def _register_engine(self, uid): """New engine with ident `uid` became available.""" # head of the line: @@ -247,10 +247,10 @@ class TaskScheduler(SessionFactory): if len(self.targets) == 1: # this was our only engine self.stop_receiving() - + # handle any potentially finished tasks: self.engine_stream.flush() - + # don't pop destinations, because they might be used later # map(self.destinations.pop, self.completed.pop(uid)) # map(self.destinations.pop, self.failed.pop(uid)) @@ -259,7 +259,7 @@ class TaskScheduler(SessionFactory): idx = self.targets.index(uid) self.targets.pop(idx) self.loads.pop(idx) - + # wait 5 seconds before cleaning up pending jobs, since the results might # still be incoming if self.pending[uid]: @@ -269,7 +269,7 @@ class TaskScheduler(SessionFactory): self.completed.pop(uid) self.failed.pop(uid) - + def handle_stranded_tasks(self, engine): """Deal with jobs resident in an engine that died.""" lost = self.pending[engine] @@ -296,8 +296,8 @@ class TaskScheduler(SessionFactory): # finally scrub completed/failed lists self.completed.pop(engine) self.failed.pop(engine) - - + + #----------------------------------------------------------------------- # Job Submission #----------------------------------------------------------------------- @@ -311,24 +311,24 @@ class TaskScheduler(SessionFactory): except Exception: self.log.error("task::Invaid task msg: %r"%raw_msg, exc_info=True) return - - + + # send to monitor self.mon_stream.send_multipart([b'intask']+raw_msg, copy=False) - + header = msg['header'] msg_id = header['msg_id'] self.all_ids.add(msg_id) - + # get targets as a set of bytes objects # from a list of unicode objects targets = header.get('targets', []) targets = map(asbytes, targets) targets = set(targets) - + retries = header.get('retries', 0) self.retries[msg_id] = retries - + # time dependencies after = header.get('after', None) if after: @@ -352,17 +352,17 @@ class TaskScheduler(SessionFactory): after = MET else: after = MET - + # location dependencies follow = Dependency(header.get('follow', [])) - + # turn timeouts into datetime objects: timeout = header.get('timeout', None) if timeout: timeout = datetime.now() + timedelta(0,timeout,0) - + args = [raw_msg, targets, after, follow, timeout] - + # validate and reduce dependencies: for dep in after,follow: if not dep: # empty dependency @@ -375,7 +375,7 @@ class TaskScheduler(SessionFactory): if dep.unreachable(self.all_completed, self.all_failed): self.depending[msg_id] = args return self.fail_unreachable(msg_id) - + if after.check(self.all_completed, self.all_failed): # time deps already met, try to run if not self.maybe_run(msg_id, *args): @@ -385,7 +385,7 @@ class TaskScheduler(SessionFactory): self.save_unmet(msg_id, *args) else: self.save_unmet(msg_id, *args) - + def audit_timeouts(self): """Audit all waiting tasks for expired timeouts.""" now = datetime.now() @@ -395,7 +395,7 @@ class TaskScheduler(SessionFactory): raw,after,targets,follow,timeout = self.depending[msg_id] if timeout and timeout < now: self.fail_unreachable(msg_id, error.TaskTimeout) - + def fail_unreachable(self, msg_id, why=error.ImpossibleDependency): """a task has become unreachable, send a reply with an ImpossibleDependency error.""" @@ -406,25 +406,25 @@ class TaskScheduler(SessionFactory): for mid in follow.union(after): if mid in self.graph: self.graph[mid].remove(msg_id) - + # FIXME: unpacking a message I've already unpacked, but didn't save: idents,msg = self.session.feed_identities(raw_msg, copy=False) header = self.session.unpack(msg[1].bytes) - + try: raise why() except: content = error.wrap_exception() - + self.all_done.add(msg_id) self.all_failed.add(msg_id) - - msg = self.session.send(self.client_stream, 'apply_reply', content, + + msg = self.session.send(self.client_stream, 'apply_reply', content, parent=header, ident=idents) self.session.send(self.mon_stream, msg, ident=[b'outtask']+idents) - + self.update_graph(msg_id, success=False) - + def maybe_run(self, msg_id, raw_msg, targets, after, follow, timeout): """check location dependencies, and run if they are met.""" blacklist = self.blacklist.setdefault(msg_id, set()) @@ -443,7 +443,7 @@ class TaskScheduler(SessionFactory): return False # check follow return follow.check(self.completed[target], self.failed[target]) - + indices = filter(can_run, range(len(self.targets))) if not indices: @@ -472,10 +472,10 @@ class TaskScheduler(SessionFactory): return False else: indices = None - + self.submit_task(msg_id, raw_msg, targets, follow, timeout, indices) return True - + def save_unmet(self, msg_id, raw_msg, targets, after, follow, timeout): """Save a message for later submission when its dependencies are met.""" self.depending[msg_id] = [raw_msg,targets,after,follow,timeout] @@ -484,7 +484,7 @@ class TaskScheduler(SessionFactory): if dep_id not in self.graph: self.graph[dep_id] = set() self.graph[dep_id].add(msg_id) - + def submit_task(self, msg_id, raw_msg, targets, follow, timeout, indices=None): """Submit a task to any of a subset of our targets.""" if indices: @@ -504,10 +504,10 @@ class TaskScheduler(SessionFactory): self.pending[target][msg_id] = (raw_msg, targets, MET, follow, timeout) # notify Hub content = dict(msg_id=msg_id, engine_id=target.decode('ascii')) - self.session.send(self.mon_stream, 'task_destination', content=content, + self.session.send(self.mon_stream, 'task_destination', content=content, ident=[b'tracktask',self.ident]) - - + + #----------------------------------------------------------------------- # Result Handling #----------------------------------------------------------------------- @@ -545,7 +545,7 @@ class TaskScheduler(SessionFactory): self.mon_stream.send_multipart([b'outtask']+raw_msg, copy=False) else: self.handle_unmet_dependency(idents, parent) - + def handle_result(self, idents, parent, raw_msg, success=True): """handle a real task result, either success or failure""" # first, relay result to client @@ -567,21 +567,21 @@ class TaskScheduler(SessionFactory): self.all_failed.add(msg_id) self.all_done.add(msg_id) self.destinations[msg_id] = engine - + self.update_graph(msg_id, success) - + def handle_unmet_dependency(self, idents, parent): """handle an unmet dependency""" engine = idents[0] msg_id = parent['msg_id'] - + if msg_id not in self.blacklist: self.blacklist[msg_id] = set() self.blacklist[msg_id].add(engine) - + args = self.pending[engine].pop(msg_id) raw,targets,after,follow,timeout = args - + if self.blacklist[msg_id] == targets: self.depending[msg_id] = args self.fail_unreachable(msg_id) @@ -590,7 +590,7 @@ class TaskScheduler(SessionFactory): if msg_id not in self.all_failed: # put it back in our dependency tree self.save_unmet(msg_id, *args) - + if self.hwm: try: idx = self.targets.index(engine) @@ -599,13 +599,13 @@ class TaskScheduler(SessionFactory): else: if self.loads[idx] == self.hwm-1: self.update_graph(None) - - - + + + def update_graph(self, dep_id=None, success=True): """dep_id just finished. Update our dependency graph and submit any jobs that just became runable. - + Called with dep_id=None to update entire graph for hwm, but without finishing a task. """ @@ -624,26 +624,26 @@ class TaskScheduler(SessionFactory): # or b) dep_id was given as None if dep_id is None or self.hwm and any( [ load==self.hwm-1 for load in self.loads ]): jobs = self.depending.keys() - + for msg_id in jobs: raw_msg, targets, after, follow, timeout = self.depending[msg_id] - + if after.unreachable(self.all_completed, self.all_failed)\ or follow.unreachable(self.all_completed, self.all_failed): self.fail_unreachable(msg_id) - + elif after.check(self.all_completed, self.all_failed): # time deps met, maybe run if self.maybe_run(msg_id, raw_msg, targets, MET, follow, timeout): - + self.depending.pop(msg_id) for mid in follow.union(after): if mid in self.graph: self.graph[mid].remove(msg_id) - + #---------------------------------------------------------------------- # methods to be overridden by subclasses #---------------------------------------------------------------------- - + def add_job(self, idx): """Called after self.targets[idx] just got the job with header. Override with subclasses. The default ordering is simple LRU. @@ -651,21 +651,21 @@ class TaskScheduler(SessionFactory): self.loads[idx] += 1 for lis in (self.targets, self.loads): lis.append(lis.pop(idx)) - - + + def finish_job(self, idx): """Called after self.targets[idx] just finished a job. Override with subclasses.""" self.loads[idx] -= 1 - + def launch_scheduler(in_addr, out_addr, mon_addr, not_addr, config=None, logname='root', log_url=None, loglevel=logging.DEBUG, identity=b'task', in_thread=False): - + ZMQStream = zmqstream.ZMQStream - + if config: # unwrap dict back into Config config = Config(config) @@ -675,14 +675,14 @@ def launch_scheduler(in_addr, out_addr, mon_addr, not_addr, config=None, ctx = zmq.Context.instance() loop = ioloop.IOLoop.instance() else: - # in a process, don't use instance() + # in a process, don't use instance() # for safety with multiprocessing ctx = zmq.Context() loop = ioloop.IOLoop() ins = ZMQStream(ctx.socket(zmq.ROUTER),loop) ins.setsockopt(zmq.IDENTITY, identity) ins.bind(in_addr) - + outs = ZMQStream(ctx.socket(zmq.ROUTER),loop) outs.setsockopt(zmq.IDENTITY, identity) outs.bind(out_addr) @@ -691,7 +691,7 @@ def launch_scheduler(in_addr, out_addr, mon_addr, not_addr, config=None, nots = zmqstream.ZMQStream(ctx.socket(zmq.SUB),loop) nots.setsockopt(zmq.SUBSCRIBE, b'') nots.connect(not_addr) - + # setup logging. if in_thread: log = Application.instance().log @@ -700,7 +700,7 @@ def launch_scheduler(in_addr, out_addr, mon_addr, not_addr, config=None, log = connect_logger(logname, ctx, log_url, root="scheduler", loglevel=loglevel) else: log = local_logger(logname, loglevel) - + scheduler = TaskScheduler(client_stream=ins, engine_stream=outs, mon_stream=mons, notifier_stream=nots, loop=loop, log=log, diff --git a/IPython/parallel/controller/sqlitedb.py b/IPython/parallel/controller/sqlitedb.py index f5cdafc..80806e8 100644 --- a/IPython/parallel/controller/sqlitedb.py +++ b/IPython/parallel/controller/sqlitedb.py @@ -87,7 +87,7 @@ def _convert_bufs(bs): class SQLiteDB(BaseDB): """SQLite3 TaskRecord backend.""" - + filename = Unicode('tasks.db', config=True, help="""The filename of the sqlite task database. [default: 'tasks.db']""") location = Unicode('', config=True, @@ -98,7 +98,7 @@ class SQLiteDB(BaseDB): a new table will be created with the Hub's IDENT. Specifying the table will result in tasks from previous sessions being available via Clients' db_query and get_result methods.""") - + _db = Instance('sqlite3.Connection') # the ordered list of column names _keys = List(['msg_id' , @@ -142,7 +142,7 @@ class SQLiteDB(BaseDB): 'stdout' : 'text', 'stderr' : 'text', }) - + def __init__(self, **kwargs): super(SQLiteDB, self).__init__(**kwargs) if not self.table: @@ -160,14 +160,14 @@ class SQLiteDB(BaseDB): else: self.location = u'.' self._init_db() - + # register db commit as 2s periodic callback # to prevent clogging pipes # assumes we are being run in a zmq ioloop app loop = ioloop.IOLoop.instance() pc = ioloop.PeriodicCallback(self._db.commit, 2000, loop) pc.start() - + def _defaults(self, keys=None): """create an empty record""" d = {} @@ -175,10 +175,10 @@ class SQLiteDB(BaseDB): for key in keys: d[key] = None return d - + def _check_table(self): """Ensure that an incorrect table doesn't exist - + If a bad (old) table does exist, return False """ cursor = self._db.execute("PRAGMA table_info(%s)"%self.table) @@ -202,7 +202,7 @@ class SQLiteDB(BaseDB): ) return False return True - + def _init_db(self): """Connect to the database and get new session number.""" # register adapters @@ -212,7 +212,7 @@ class SQLiteDB(BaseDB): sqlite3.register_converter('bufs', _convert_bufs) # connect to the db dbfile = os.path.join(self.location, self.filename) - self._db = sqlite3.connect(dbfile, detect_types=sqlite3.PARSE_DECLTYPES, + self._db = sqlite3.connect(dbfile, detect_types=sqlite3.PARSE_DECLTYPES, # isolation_level = None)#, cached_statements=64) # print dir(self._db) @@ -225,8 +225,8 @@ class SQLiteDB(BaseDB): "Table %s exists and doesn't match db format, trying %s"% (first_table,self.table) ) - - self._db.execute("""CREATE TABLE IF NOT EXISTS %s + + self._db.execute("""CREATE TABLE IF NOT EXISTS %s (msg_id text PRIMARY KEY, header dict text, content dict text, @@ -248,32 +248,32 @@ class SQLiteDB(BaseDB): stderr text) """%self.table) self._db.commit() - + def _dict_to_list(self, d): """turn a mongodb-style record dict into a list.""" - + return [ d[key] for key in self._keys ] - + def _list_to_dict(self, line, keys=None): """Inverse of dict_to_list""" keys = self._keys if keys is None else keys d = self._defaults(keys) for key,value in zip(keys, line): d[key] = value - + return d - + def _render_expression(self, check): """Turn a mongodb-style search dict into an SQL query.""" expressions = [] args = [] - + skeys = set(check.keys()) skeys.difference_update(set(self._keys)) skeys.difference_update(set(['buffers', 'result_buffers'])) if skeys: raise KeyError("Illegal testing key(s): %s"%skeys) - + for name,sub_check in check.iteritems(): if isinstance(sub_check, dict): for test,value in sub_check.iteritems(): @@ -283,7 +283,7 @@ class SQLiteDB(BaseDB): raise KeyError("Unsupported operator: %r"%test) if isinstance(op, tuple): op, join = op - + if value is None and op in null_operators: expr = "%s %s"%null_operators[op] else: @@ -304,10 +304,10 @@ class SQLiteDB(BaseDB): else: expressions.append("%s = ?"%name) args.append(sub_check) - + expr = " AND ".join(expressions) return expr, args - + def add_record(self, msg_id, rec): """Add a new Task Record, by msg_id.""" d = self._defaults() @@ -317,7 +317,7 @@ class SQLiteDB(BaseDB): tups = '(%s)'%(','.join(['?']*len(line))) self._db.execute("INSERT INTO %s VALUES %s"%(self.table, tups), line) # self._db.commit() - + def get_record(self, msg_id): """Get a specific Task Record, by msg_id.""" cursor = self._db.execute("""SELECT * FROM %s WHERE msg_id==?"""%self.table, (msg_id,)) @@ -325,7 +325,7 @@ class SQLiteDB(BaseDB): if line is None: raise KeyError("No such msg: %r"%msg_id) return self._list_to_dict(line) - + def update_record(self, msg_id, rec): """Update the data in an existing record.""" query = "UPDATE %s SET "%self.table @@ -340,27 +340,27 @@ class SQLiteDB(BaseDB): values.append(msg_id) self._db.execute(query, values) # self._db.commit() - + def drop_record(self, msg_id): """Remove a record from the DB.""" self._db.execute("""DELETE FROM %s WHERE msg_id==?"""%self.table, (msg_id,)) # self._db.commit() - + def drop_matching_records(self, check): """Remove a record from the DB.""" expr,args = self._render_expression(check) query = "DELETE FROM %s WHERE %s"%(self.table, expr) self._db.execute(query,args) # self._db.commit() - + def find_records(self, check, keys=None): """Find records matching a query dict, optionally extracting subset of keys. - + Returns list of matching records. - + Parameters ---------- - + check: dict mongodb-style query argument keys: list of strs [optional] @@ -371,7 +371,7 @@ class SQLiteDB(BaseDB): bad_keys = [ key for key in keys if key not in self._keys ] if bad_keys: raise KeyError("Bad record key(s): %s"%bad_keys) - + if keys: # ensure msg_id is present and first: if 'msg_id' in keys: @@ -389,7 +389,7 @@ class SQLiteDB(BaseDB): rec = self._list_to_dict(line, keys) records.append(rec) return records - + def get_history(self): """get all msg_ids, ordered by time submitted.""" query = """SELECT msg_id FROM %s ORDER by submitted ASC"""%self.table diff --git a/IPython/parallel/engine/engine.py b/IPython/parallel/engine/engine.py index 8b7800e..0a14f23 100644 --- a/IPython/parallel/engine/engine.py +++ b/IPython/parallel/engine/engine.py @@ -27,7 +27,7 @@ from IPython.external.ssh import tunnel from IPython.utils.traitlets import ( Instance, Dict, Int, Type, CFloat, Unicode, CBytes, Bool ) -# from IPython.utils.localinterfaces import LOCALHOST +# from IPython.utils.localinterfaces import LOCALHOST from IPython.parallel.controller.heartmonitor import Heart from IPython.parallel.factory import RegistrationFactory @@ -39,7 +39,7 @@ from .streamkernel import Kernel class EngineFactory(RegistrationFactory): """IPython engine""" - + # configurables: out_stream_factory=Type('IPython.zmq.iostream.OutStream', config=True, help="""The OutStream for handling stdout/err. @@ -60,32 +60,32 @@ class EngineFactory(RegistrationFactory): help="""The SSH private key file to use when tunneling connections to the Controller.""") paramiko=Bool(sys.platform == 'win32', config=True, help="""Whether to use paramiko instead of openssh for tunnels.""") - + # not configurable: user_ns=Dict() id=Int(allow_none=True) registrar=Instance('zmq.eventloop.zmqstream.ZMQStream') kernel=Instance(Kernel) - + bident = CBytes() ident = Unicode() def _ident_changed(self, name, old, new): self.bident = asbytes(new) using_ssh=Bool(False) - - + + def __init__(self, **kwargs): super(EngineFactory, self).__init__(**kwargs) self.ident = self.session.session - + def init_connector(self): """construct connection function, which handles tunnels.""" self.using_ssh = bool(self.sshkey or self.sshserver) - + if self.sshkey and not self.sshserver: # We are using ssh directly to the controller, tunneling localhost to localhost self.sshserver = self.url.split('://')[1].split(':')[0] - + if self.using_ssh: if tunnel.try_passwordless_ssh(self.sshserver, self.sshkey, self.paramiko): password=False @@ -93,7 +93,7 @@ class EngineFactory(RegistrationFactory): password = getpass("SSH Password for %s: "%self.sshserver) else: password = False - + def connect(s, url): url = disambiguate_url(url, self.location) if self.using_ssh: @@ -104,7 +104,7 @@ class EngineFactory(RegistrationFactory): ) else: return s.connect(url) - + def maybe_tunnel(url): """like connect, but don't complete the connection (for use by heartbeat)""" url = disambiguate_url(url, self.location) @@ -116,10 +116,10 @@ class EngineFactory(RegistrationFactory): ) return url return connect, maybe_tunnel - + def register(self): """send the registration_request""" - + self.log.info("Registering with controller at %s"%self.url) ctx = self.context connect,maybe_tunnel = self.init_connector() @@ -127,13 +127,13 @@ class EngineFactory(RegistrationFactory): reg.setsockopt(zmq.IDENTITY, self.bident) connect(reg, self.url) self.registrar = zmqstream.ZMQStream(reg, self.loop) - - + + content = dict(queue=self.ident, heartbeat=self.ident, control=self.ident) self.registrar.on_recv(lambda msg: self.complete_registration(msg, connect, maybe_tunnel)) # print (self.session.key) self.session.send(self.registrar, "registration_request",content=content) - + def complete_registration(self, msg, connect, maybe_tunnel): # print msg self._abort_dc.stop() @@ -142,25 +142,25 @@ class EngineFactory(RegistrationFactory): identity = self.bident idents,msg = self.session.feed_identities(msg) msg = Message(self.session.unserialize(msg)) - + if msg.content.status == 'ok': self.id = int(msg.content.id) - + # launch heartbeat hb_addrs = msg.content.heartbeat - + # possibly forward hb ports with tunnels hb_addrs = [ maybe_tunnel(addr) for addr in hb_addrs ] heart = Heart(*map(str, hb_addrs), heart_id=identity) heart.start() - + # create Shell Streams (MUX, Task, etc.): queue_addr = msg.content.mux shell_addrs = [ str(queue_addr) ] task_addr = msg.content.task if task_addr: shell_addrs.append(str(task_addr)) - + # Uncomment this to go back to two-socket model # shell_streams = [] # for addr in shell_addrs: @@ -168,7 +168,7 @@ class EngineFactory(RegistrationFactory): # stream.setsockopt(zmq.IDENTITY, identity) # stream.connect(disambiguate_url(addr, self.location)) # shell_streams.append(stream) - + # Now use only one shell stream for mux and tasks stream = zmqstream.ZMQStream(ctx.socket(zmq.ROUTER), loop) stream.setsockopt(zmq.IDENTITY, identity) @@ -176,19 +176,19 @@ class EngineFactory(RegistrationFactory): for addr in shell_addrs: connect(stream, addr) # end single stream-socket - + # control stream: control_addr = str(msg.content.control) control_stream = zmqstream.ZMQStream(ctx.socket(zmq.ROUTER), loop) control_stream.setsockopt(zmq.IDENTITY, identity) connect(control_stream, control_addr) - + # create iopub stream: iopub_addr = msg.content.iopub iopub_stream = zmqstream.ZMQStream(ctx.socket(zmq.PUB), loop) iopub_stream.setsockopt(zmq.IDENTITY, identity) connect(iopub_stream, iopub_addr) - + # # Redirect input streams and set a display hook. if self.out_stream_factory: sys.stdout = self.out_stream_factory(self.session, iopub_stream, u'stdout') @@ -199,25 +199,25 @@ class EngineFactory(RegistrationFactory): sys.displayhook = self.display_hook_factory(self.session, iopub_stream) sys.displayhook.topic = 'engine.%i.pyout'%self.id - self.kernel = Kernel(config=self.config, int_id=self.id, ident=self.ident, session=self.session, - control_stream=control_stream, shell_streams=shell_streams, iopub_stream=iopub_stream, + self.kernel = Kernel(config=self.config, int_id=self.id, ident=self.ident, session=self.session, + control_stream=control_stream, shell_streams=shell_streams, iopub_stream=iopub_stream, loop=loop, user_ns = self.user_ns, log=self.log) self.kernel.start() - - + + else: self.log.fatal("Registration Failed: %s"%msg) raise Exception("Registration Failed: %s"%msg) - + self.log.info("Completed registration with id %i"%self.id) - - + + def abort(self): self.log.fatal("Registration timed out after %.1f seconds"%self.timeout) self.session.send(self.registrar, "unregistration_request", content=dict(id=self.id)) time.sleep(1) sys.exit(255) - + def start(self): dc = ioloop.DelayedCallback(self.register, 0, self.loop) dc.start() diff --git a/IPython/parallel/engine/streamkernel.py b/IPython/parallel/engine/streamkernel.py index 02626ee..1669c00 100644 --- a/IPython/parallel/engine/streamkernel.py +++ b/IPython/parallel/engine/streamkernel.py @@ -47,17 +47,17 @@ def printer(*args): class _Passer(zmqstream.ZMQStream): """Empty class that implements `send()` that does nothing. - + Subclass ZMQStream for Session typechecking - + """ def __init__(self, *args, **kwargs): pass - + def send(self, *args, **kwargs): pass send_multipart = send - + #----------------------------------------------------------------------------- # Main kernel class @@ -68,63 +68,63 @@ class Kernel(SessionFactory): #--------------------------------------------------------------------------- # Kernel interface #--------------------------------------------------------------------------- - + # kwargs: exec_lines = List(Unicode, config=True, help="List of lines to execute") - + # identities: int_id = Int(-1) bident = CBytes() ident = Unicode() def _ident_changed(self, name, old, new): self.bident = asbytes(new) - + user_ns = Dict(config=True, help="""Set the user's namespace of the Kernel""") - + control_stream = Instance(zmqstream.ZMQStream) task_stream = Instance(zmqstream.ZMQStream) iopub_stream = Instance(zmqstream.ZMQStream) client = Instance('IPython.parallel.Client') - + # internals shell_streams = List() compiler = Instance(CommandCompiler, (), {}) completer = Instance(KernelCompleter) - + aborted = Set() shell_handlers = Dict() control_handlers = Dict() - + def _set_prefix(self): self.prefix = "engine.%s"%self.int_id - + def _connect_completer(self): self.completer = KernelCompleter(self.user_ns) - + def __init__(self, **kwargs): super(Kernel, self).__init__(**kwargs) self._set_prefix() self._connect_completer() - + self.on_trait_change(self._set_prefix, 'id') self.on_trait_change(self._connect_completer, 'user_ns') - + # Build dict of handlers for message types - for msg_type in ['execute_request', 'complete_request', 'apply_request', + for msg_type in ['execute_request', 'complete_request', 'apply_request', 'clear_request']: self.shell_handlers[msg_type] = getattr(self, msg_type) - + for msg_type in ['shutdown_request', 'abort_request']+self.shell_handlers.keys(): self.control_handlers[msg_type] = getattr(self, msg_type) - + self._initial_exec_lines() - + def _wrap_exception(self, method=None): e_info = dict(engine_uuid=self.ident, engine_id=self.int_id, method=method) content=wrap_exception(e_info) return content - + def _initial_exec_lines(self): s = _Passer() content = dict(silent=True, user_variable=[],user_expressions=[]) @@ -133,20 +133,20 @@ class Kernel(SessionFactory): content.update({'code':line}) msg = self.session.msg('execute_request', content) self.execute_request(s, [], msg) - - + + #-------------------- control handlers ----------------------------- def abort_queues(self): for stream in self.shell_streams: if stream: self.abort_queue(stream) - + def abort_queue(self, stream): while True: idents,msg = self.session.recv(stream, zmq.NOBLOCK, content=True) if msg is None: return - + self.log.info("Aborting:") self.log.info(str(msg)) msg_type = msg['header']['msg_type'] @@ -154,13 +154,13 @@ class Kernel(SessionFactory): # reply_msg = self.session.msg(reply_type, {'status' : 'aborted'}, msg) # self.reply_socket.send(ident,zmq.SNDMORE) # self.reply_socket.send_json(reply_msg) - reply_msg = self.session.send(stream, reply_type, + reply_msg = self.session.send(stream, reply_type, content={'status' : 'aborted'}, parent=msg, ident=idents) self.log.debug(str(reply_msg)) # We need to wait a bit for requests to come in. This can probably # be set shorter for true asynchronous clients. time.sleep(0.05) - + def abort_request(self, stream, ident, parent): """abort a specifig msg by id""" msg_ids = parent['content'].get('msg_ids', None) @@ -170,12 +170,12 @@ class Kernel(SessionFactory): self.abort_queues() for mid in msg_ids: self.aborted.add(str(mid)) - + content = dict(status='ok') - reply_msg = self.session.send(stream, 'abort_reply', content=content, + reply_msg = self.session.send(stream, 'abort_reply', content=content, parent=parent, ident=ident) self.log.debug(str(reply_msg)) - + def shutdown_request(self, stream, ident, parent): """kill ourself. This should really be handled in an external process""" try: @@ -190,7 +190,7 @@ class Kernel(SessionFactory): self.log.debug(str(msg)) dc = ioloop.DelayedCallback(lambda : sys.exit(0), 1000, self.loop) dc.start() - + def dispatch_control(self, msg): idents,msg = self.session.feed_identities(msg, copy=False) try: @@ -200,7 +200,7 @@ class Kernel(SessionFactory): return else: self.log.debug("Control received, %s", msg) - + header = msg['header'] msg_id = header['msg_id'] msg_type = header['msg_type'] @@ -210,10 +210,10 @@ class Kernel(SessionFactory): self.log.error("UNKNOWN CONTROL MESSAGE TYPE: %r"%msg_type) else: handler(self.control_stream, idents, msg) - + #-------------------- queue helpers ------------------------------ - + def check_dependencies(self, dependencies): if not dependencies: return True @@ -225,28 +225,28 @@ class Kernel(SessionFactory): results = self.client.get_results(dependencies,status_only=True) if results['status'] != 'ok': return False - + if anyorall == 'any': if not results['completed']: return False else: if results['pending']: return False - + return True - + def check_aborted(self, msg_id): return msg_id in self.aborted - + #-------------------- queue handlers ----------------------------- - + def clear_request(self, stream, idents, parent): """Clear our namespace.""" self.user_ns = {} - msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent, + msg = self.session.send(stream, 'clear_reply', ident=idents, parent=parent, content = dict(status='ok')) self._initial_exec_lines() - + def execute_request(self, stream, ident, parent): self.log.debug('execute request %s'%parent) try: @@ -273,8 +273,8 @@ class Kernel(SessionFactory): reply_content = exc_content else: reply_content = {'status' : 'ok'} - - reply_msg = self.session.send(stream, u'execute_reply', reply_content, parent=parent, + + reply_msg = self.session.send(stream, u'execute_reply', reply_content, parent=parent, ident=ident, subheader = dict(started=started)) self.log.debug(str(reply_msg)) if reply_msg['content']['status'] == u'error': @@ -289,7 +289,7 @@ class Kernel(SessionFactory): def complete(self, msg): return self.completer.complete(msg.content.line, msg.content.text) - + def apply_request(self, stream, ident, parent): # flush previous reply, so this request won't block it stream.flush(zmq.POLLOUT) @@ -314,21 +314,21 @@ class Kernel(SessionFactory): sys.stderr.set_parent(parent) # exec "f(*args,**kwargs)" in self.user_ns, self.user_ns working = self.user_ns - # suffix = + # suffix = prefix = "_"+str(msg_id).replace("-","")+"_" - + f,args,kwargs = unpack_apply_message(bufs, working, copy=False) # if bound: # bound_ns = Namespace(working) # args = [bound_ns]+list(args) fname = getattr(f, '__name__', 'f') - + fname = prefix+"f" argname = prefix+"args" kwargname = prefix+"kwargs" resultname = prefix+"result" - + ns = { fname : f, argname : args, kwargname : kwargs , resultname : None } # print ns working.update(ns) @@ -341,7 +341,7 @@ class Kernel(SessionFactory): working.pop(key) # if bound: # working.update(bound_ns) - + packed_result,buf = serialize_object(result) result_buf = [packed_result]+buf except: @@ -351,24 +351,24 @@ class Kernel(SessionFactory): ident=asbytes('%s.pyerr'%self.prefix)) reply_content = exc_content result_buf = [] - + if exc_content['ename'] == 'UnmetDependency': sub['dependencies_met'] = False else: reply_content = {'status' : 'ok'} - + # put 'ok'/'error' status in header, for scheduler introspection: sub['status'] = reply_content['status'] - - reply_msg = self.session.send(stream, u'apply_reply', reply_content, + + reply_msg = self.session.send(stream, u'apply_reply', reply_content, parent=parent, ident=ident,buffers=result_buf, subheader=sub) - + # flush i/o - # should this be before reply_msg is sent, like in the single-kernel code, + # should this be before reply_msg is sent, like in the single-kernel code, # or should nothing get in the way of real results? sys.stdout.flush() sys.stderr.flush() - + def dispatch_queue(self, stream, msg): self.control_stream.flush() idents,msg = self.session.feed_identities(msg, copy=False) @@ -379,8 +379,8 @@ class Kernel(SessionFactory): return else: self.log.debug("Message received, %s", msg) - - + + header = msg['header'] msg_id = header['msg_id'] msg_type = msg['header']['msg_type'] @@ -397,25 +397,25 @@ class Kernel(SessionFactory): self.log.error("UNKNOWN MESSAGE TYPE: %r"%msg_type) else: handler(stream, idents, msg) - + def start(self): #### stream mode: if self.control_stream: self.control_stream.on_recv(self.dispatch_control, copy=False) self.control_stream.on_err(printer) - + def make_dispatcher(stream): def dispatcher(msg): return self.dispatch_queue(stream, msg) return dispatcher - + for s in self.shell_streams: s.on_recv(make_dispatcher(s), copy=False) s.on_err(printer) - + if self.iopub_stream: self.iopub_stream.on_err(printer) - + #### while True mode: # while True: # idle = True @@ -428,7 +428,7 @@ class Kernel(SessionFactory): # else: # idle=False # self.dispatch_queue(self.shell_stream, msg) - # + # # if not self.task_stream.empty(): # idle=False # msg = self.task_stream.recv_multipart() diff --git a/IPython/parallel/error.py b/IPython/parallel/error.py index d27dfb5..abfb578 100644 --- a/IPython/parallel/error.py +++ b/IPython/parallel/error.py @@ -56,7 +56,7 @@ class NotDefined(KernelError): def __repr__(self): return '' % self.name - + __str__ = __repr__ @@ -175,35 +175,35 @@ class RemoteError(KernelError): evalue=None traceback=None engine_info=None - + def __init__(self, ename, evalue, traceback, engine_info=None): self.ename=ename self.evalue=evalue self.traceback=traceback self.engine_info=engine_info or {} self.args=(ename, evalue) - + def __repr__(self): engineid = self.engine_info.get('engine_id', ' ') return ""%(engineid, self.ename, self.evalue) - + def __str__(self): sig = "%s(%s)"%(self.ename, self.evalue) if self.traceback: return sig + '\n' + self.traceback else: return sig - + class TaskRejectError(KernelError): """Exception to raise when a task should be rejected by an engine. - + This exception can be used to allow a task running on an engine to test if the engine (or the user's namespace on the engine) has the needed task dependencies. If not, the task should raise this exception. For the task to be retried on another engine, the task should be created with the `retries` argument > 1. - + The advantage of this approach over our older properties system is that tasks have full access to the user's namespace on the engines and the properties don't have to be managed or tested by the controller. @@ -240,7 +240,7 @@ class CompositeError(RemoteError): engine_str = self._get_engine_str(ei) s = s + '\n' + engine_str + en + ': ' + str(ev) return s - + def __repr__(self): return "CompositeError(%i)"%len(self.elist) @@ -258,7 +258,7 @@ class CompositeError(RemoteError): else: print (self._get_engine_str(ei)) print (etb or 'No traceback available') - + def raise_exception(self, excid=0): try: en,ev,etb,ei = self.elist[excid] @@ -280,7 +280,7 @@ def collect_exceptions(rdict_or_list, method='unspecified'): if isinstance(r, RemoteError): en, ev, etb, ei = r.ename, r.evalue, r.traceback, r.engine_info # Sometimes we could have CompositeError in our list. Just take - # the errors out of them and put them in our new list. This + # the errors out of them and put them in our new list. This # has the effect of flattening lists of CompositeErrors into one # CompositeError if en=='CompositeError': @@ -312,7 +312,7 @@ def wrap_exception(engine_info={}): return exc_content def unwrap_exception(content): - err = RemoteError(content['ename'], content['evalue'], + err = RemoteError(content['ename'], content['evalue'], ''.join(content['traceback']), content.get('engine_info', {})) return err diff --git a/IPython/quarantine/InterpreterExec.py b/IPython/quarantine/InterpreterExec.py index 9faba79..8d1a2a3 100644 --- a/IPython/quarantine/InterpreterExec.py +++ b/IPython/quarantine/InterpreterExec.py @@ -61,7 +61,7 @@ def pysh(): """Pysh is a set of modules and extensions to IPython which make shell-like usage with Python syntax more convenient. Keep in mind that pysh is NOT a full-blown shell, so don't try to make it your /etc/passwd entry! - + In particular, it has no job control, so if you type Ctrl-Z (under Unix), you'll suspend pysh itself, not the process you just started. @@ -72,7 +72,7 @@ def pysh(): ALIASES ------- All of your $PATH has been loaded as IPython aliases, so you should be - able to type any normal system command and have it executed. See %alias? + able to type any normal system command and have it executed. See %alias? and %unalias? for details on the alias facilities. SPECIAL SYNTAX @@ -139,7 +139,7 @@ def pysh(): sys.platform is: linux2 IPython's input history handling is still active, which allows you to - rerun a single block of multi-line input by simply using exec: + rerun a single block of multi-line input by simply using exec: fperez[~/test]|14> $$alist = ls *.eps fperez[~/test]|15> exec _i11 file image2.eps 921 image2.eps @@ -155,7 +155,7 @@ def pysh(): automatically loaded. Some additional functions, useful for shell usage, are listed below. You can request more help about them with '?'. - shell - execute a command in the underlying system shell + shell - execute a command in the underlying system shell system - like shell(), but return the exit status of the command sout - capture the output of a command as a string lout - capture the output of a command as a list (split on '\\n') @@ -180,7 +180,7 @@ def pysh(): PROMPT CUSTOMIZATION -------------------- - + The supplied ipythonrc-pysh profile comes with an example of a very colored and detailed prompt, mainly to serve as an illustration. The valid escape sequences, besides color names, are: diff --git a/IPython/quarantine/clearcmd.py b/IPython/quarantine/clearcmd.py index aa83835..7b140e4 100644 --- a/IPython/quarantine/clearcmd.py +++ b/IPython/quarantine/clearcmd.py @@ -7,14 +7,14 @@ ip = ipapi.get() def clear_f(self,arg): """ Clear various data (e.g. stored history data) - + %clear in - clear input history %clear out - clear output history %clear shadow_compress - Compresses shadow history (to speed up ipython) %clear shadow_nuke - permanently erase all entries in shadow history %clear dhist - clear dir history %clear array - clear only variables that are NumPy arrays - + Examples: In [1]: clear in @@ -29,11 +29,11 @@ def clear_f(self,arg): In [4]: clear dhist Clearing directory history """ - + api = self.getapi() user_ns = self.user_ns # local lookup, heavily used - - + + for target in arg.split(): if target == 'out': @@ -50,7 +50,7 @@ def clear_f(self,arg): del user_ns[key] except: pass # must be done in-place - self.history_manager.input_hist_parsed[:] = ['\n'] * pc + self.history_manager.input_hist_parsed[:] = ['\n'] * pc self.history_manager.input_hist_raw[:] = ['\n'] * pc elif target == 'array': @@ -68,7 +68,7 @@ def clear_f(self,arg): elif target == 'shadow_compress': print "Compressing shadow history" api.db.hcompress('shadowhist') - + elif target == 'shadow_nuke': print "Erased all keys from shadow history " for k in ip.db.keys('shadowhist/*'): @@ -78,7 +78,7 @@ def clear_f(self,arg): print "Clearing directory history" del user_ns['_dh'][:] - gc.collect() + gc.collect() # Activate the extension ip.define_magic("clear",clear_f) diff --git a/IPython/quarantine/envpersist.py b/IPython/quarantine/envpersist.py index 2144c78..45d68fd 100644 --- a/IPython/quarantine/envpersist.py +++ b/IPython/quarantine/envpersist.py @@ -9,7 +9,7 @@ ip = ipapi.get() import os,sys -def restore_env(self): +def restore_env(self): ip = self.getapi() env = ip.db.get('stored_env', {'set' : {}, 'add' : [], 'pre' : []}) for k,v in env['set'].items(): @@ -19,51 +19,51 @@ def restore_env(self): for k,v in env['pre']: os.environ[k] = v + os.environ.get(k,"") raise TryNext - + ip.set_hook('late_startup_hook', restore_env) def persist_env(self, parameter_s=''): """ Store environment variables persistently - - IPython remembers the values across sessions, which is handy to avoid + + IPython remembers the values across sessions, which is handy to avoid editing startup files. - + %env - Show all environment variables %env VISUAL=jed - set VISUAL to jed %env PATH+=;/foo - append ;foo to PATH %env PATH+=;/bar - also append ;bar to PATH %env PATH-=/wbin; - prepend /wbin; to PATH %env -d VISUAL - forget VISUAL persistent val - %env -p - print all persistent env modifications + %env -p - print all persistent env modifications """ - + if not parameter_s.strip(): return os.environ.data - + ip = self.getapi() db = ip.db env = ip.db.get('stored_env', {'set' : {}, 'add' : [], 'pre' : []}) if parameter_s.startswith('-p'): return env - + elif parameter_s.startswith('-d'): parts = (parameter_s.split()[1], '') - + else: - parts = parameter_s.strip().split('=') - + parts = parameter_s.strip().split('=') + if len(parts) == 2: k,v = [p.strip() for p in parts] - + if v == '': if k in env['set']: del env['set'][k] env['add'] = [el for el in env['add'] if el[0] != k] env['pre'] = [el for el in env['pre'] if el[0] != k] - + print "Forgot '%s' (for next session)" % k - + elif k.endswith('+'): k = k[:-1] env['add'].append((k,v)) @@ -74,13 +74,13 @@ def persist_env(self, parameter_s=''): env['pre'].append((k,v)) os.environ[k] = v + os.environ.get(k,"") print k,"after prepend =",os.environ[k] - - + + else: env['set'][k] = v print "Setting",k,"to",v os.environ[k] = v - + db['stored_env'] = env def env_completer(self,event): diff --git a/IPython/quarantine/ext_rescapture.py b/IPython/quarantine/ext_rescapture.py index eb0c391..da96bf8 100644 --- a/IPython/quarantine/ext_rescapture.py +++ b/IPython/quarantine/ext_rescapture.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- -""" IPython extension: new prefilters for output grabbing +""" IPython extension: new prefilters for output grabbing -Provides +Provides var = %magic blah blah @@ -41,7 +41,7 @@ def init_handlers(): install_re_handler('(?P[\w\.]+)\s*=\s*%(?P.*)', hnd_magic ) - + install_re_handler('(?P[\w\.]+)\s*=\s*!(?P.*)', hnd_syscmd ) @@ -53,7 +53,7 @@ def regex_prefilter_f(self,line): mo = pat.match(line) if mo: return handler(line,mo) - + raise TryNext -ip.set_hook('input_prefilter', regex_prefilter_f) +ip.set_hook('input_prefilter', regex_prefilter_f) diff --git a/IPython/quarantine/ipy_completers.py b/IPython/quarantine/ipy_completers.py index 2542568..dc822c7 100644 --- a/IPython/quarantine/ipy_completers.py +++ b/IPython/quarantine/ipy_completers.py @@ -82,7 +82,7 @@ def bzr_commands(): return __bzr_commands out = os.popen('bzr help commands') __bzr_commands = [l.split()[0] for l in out] - return __bzr_commands + return __bzr_commands def bzr_completer(self,event): """ Completer for bazaar commands """ @@ -113,8 +113,8 @@ def apt_get_packages(prefix): for p in out: if p.startswith(prefix): yield p.rstrip() - - + + apt_commands = """\ update upgrade install remove purge source build-dep dist-upgrade dselect-upgrade clean autoclean check""" diff --git a/IPython/quarantine/ipy_extutil.py b/IPython/quarantine/ipy_extutil.py index e899e55..0b13ed2 100644 --- a/IPython/quarantine/ipy_extutil.py +++ b/IPython/quarantine/ipy_extutil.py @@ -18,15 +18,15 @@ def indent(s, ind= ' '): class ExtUtil: """ IPython extensios (ipy_* etc.) management utilities """ - + def describe(self): for n,mod in self._active(): doc = inspect.getdoc(mod) if doc: print '== %s ==' % n print indent(doc) - - + + def ls(self): """ Show list of installed extensions. """ for n,m in self._active(): @@ -37,8 +37,8 @@ class ExtUtil: o = getattr(m, 'ip', None) if isinstance(o, InteractiveShell): act.append((mname,m)) - act.sort() + act.sort() return act -extutil = ExtUtil() +extutil = ExtUtil() ip.push('extutil') diff --git a/IPython/quarantine/ipy_fsops.py b/IPython/quarantine/ipy_fsops.py index 9121a58..0a7f9fa 100644 --- a/IPython/quarantine/ipy_fsops.py +++ b/IPython/quarantine/ipy_fsops.py @@ -27,30 +27,30 @@ import IPython.utils.generics def parse_args(args): """ Given arg string 'CMD files... target', return ([files], target) """ - + tup = args.split(None, 1) if len(tup) == 1: raise UsageError("Expected arguments for " + tup[0]) - + tup2 = shlex.split(tup[1]) - + flist, trg = mglob.expand(tup2[0:-1]), tup2[-1] if not flist: raise UsageError("No files found:" + str(tup2[0:-1])) return flist, trg - + def icp(ip,arg): """ icp files... targetdir - + Copy all files to target, creating dirs for target if necessary - + icp srcdir dstdir - + Copy srcdir to distdir - + """ import distutils.dir_util - + fs, targetdir = parse_args(arg) if not os.path.isdir(targetdir) and len(fs) > 1: distutils.dir_util.mkpath(targetdir,verbose =1) @@ -64,21 +64,21 @@ ip.define_alias("icp",icp) def imv(ip,arg): """ imv src tgt - + Move source to target. """ - + fs, target = parse_args(arg) if len(fs) > 1: assert os.path.isdir(target) - for f in fs: + for f in fs: shutil.move(f, target) return fs -ip.define_alias("imv",imv) +ip.define_alias("imv",imv) def irm(ip,arg): """ irm path[s]... - + Remove file[s] or dir[s] path. Dirs are deleted recursively. """ try: @@ -97,24 +97,24 @@ ip.define_alias("irm",irm) def imkdir(ip,arg): """ imkdir path - + Creates dir path, and all dirs on the road """ import distutils.dir_util targetdir = arg.split(None,1)[1] - distutils.dir_util.mkpath(targetdir,verbose =1) + distutils.dir_util.mkpath(targetdir,verbose =1) -ip.define_alias("imkdir",imkdir) +ip.define_alias("imkdir",imkdir) def igrep(ip,arg): """ igrep PAT files... - + Very dumb file scan, case-insensitive. - + e.g. - + igrep "test this" rec:*.py - + """ elems = shlex.split(arg) dummy, pat, fs = elems[0], elems[1], mglob.expand(elems[2:]) @@ -130,19 +130,19 @@ def igrep(ip,arg): print l.rstrip() return res -ip.define_alias("igrep",igrep) +ip.define_alias("igrep",igrep) def collect(ip,arg): """ collect foo/a.txt rec:bar=*.py - + Copies foo/a.txt to ~/_ipython/collect/foo/a.txt and *.py from bar, likewise - + Without args, try to open ~/_ipython/collect dir (in win32 at least). """ from IPython.external.path import path basedir = path(ip.ipython_dir + '/collect') - try: + try: fs = mglob.expand(arg.split(None,1)[1]) except IndexError: os.startfile(basedir) @@ -160,23 +160,23 @@ def collect(ip,arg): print f,"=>",trg shutil.copy2(f,trg) -ip.define_alias("collect",collect) +ip.define_alias("collect",collect) def inote(ip,arg): """ inote Hello world - + Adds timestamp and Hello world to ~/_ipython/notes.txt - + Without args, opens notes.txt for editing. """ import time fname = ip.ipython_dir + '/notes.txt' - + try: entry = " === " + time.asctime() + ': ===\n' + arg.split(None,1)[1] + '\n' - f= open(fname, 'a').write(entry) + f= open(fname, 'a').write(entry) except IndexError: - ip.hooks.editor(fname) + ip.hooks.editor(fname) ip.define_alias("inote",inote) @@ -186,7 +186,7 @@ def pathobj_unmangle(s): return s.replace('__',' ').replace('DOT','.') - + class PathObj(path): def __init__(self,p): self.path = p @@ -205,7 +205,7 @@ class PathObj(path): sep = '' else: sep = '/' - + tgt = self.path + sep + pathobj_unmangle(name) #print "tgt",tgt if os.path.isdir(tgt): @@ -216,15 +216,15 @@ class PathObj(path): raise AttributeError, name # <<< DON'T FORGET THIS LINE !! def __str__(self): return self.path - + def __repr__(self): return "" % self.path - + def __call__(self): print "cd:",self.path os.chdir(self.path) - -def complete_pathobj(obj, prev_completions): + +def complete_pathobj(obj, prev_completions): if hasattr(obj,'__complete__'): res = obj.__complete__() if res: @@ -242,5 +242,5 @@ def test_pathobj(): startmenu = PathObj("d:/Documents and Settings/All Users/Start Menu/Programs") cwd = PathObj('.') ip.push("rootdir startmenu cwd") - + #test_pathobj() \ No newline at end of file diff --git a/IPython/quarantine/ipy_jot.py b/IPython/quarantine/ipy_jot.py index a64e3ec..5a8fec3 100644 --- a/IPython/quarantine/ipy_jot.py +++ b/IPython/quarantine/ipy_jot.py @@ -7,7 +7,7 @@ Stores variables in Struct with some notes in PicleShare database """ -from datetime import datetime +from datetime import datetime from IPython.core import ipapi ip = ipapi.get() @@ -15,7 +15,7 @@ import pickleshare import inspect,pickle,os,sys,textwrap from IPython.core.fakemodule import FakeModule -from IPython.utils.ipstruct import Struct +from IPython.utils.ipstruct import Struct from IPython.utils.warn import error @@ -43,7 +43,7 @@ def refresh_variables(ip, key=None): print "Restored", justkey else: ip.user_ns[origname] = obj['val'] - print "Restored", origname + print "Restored", origname def read_variables(ip, key=None): db = ip.db @@ -54,7 +54,7 @@ def read_variables(ip, key=None): for key in keys: # strip autorestore justkey = os.path.basename(key) - print "restoring from ", justkey + print "restoring from ", justkey try: obj = db[key] except KeyError: @@ -66,7 +66,7 @@ def read_variables(ip, key=None): def detail_variables(ip, key=None): db, get = ip.db, ip.db.get - + if key is None: keys = db.keys('jot/*') else: @@ -82,7 +82,7 @@ def detail_variables(ip, key=None): for key in keys: v = get(key,'') justkey = os.path.basename(key) - try: + try: print fmthead % (justkey, datetime.ctime(v.get('time',''))) print fmtbody % (v.get('comment','')) d = v.get('val','unavailable') @@ -105,7 +105,7 @@ def jot_obj(self, obj, name, comment=''): write obj data to the note database, with whatever that should be noted. """ had = self.db.keys('jot/'+name+'*') - # if it the same name but a later version, we stupidly add a number to the + # if it the same name but a later version, we stupidly add a number to the # so the name doesn't collide. Any better idea? suffix = '' if len(had)>0: @@ -116,47 +116,47 @@ def jot_obj(self, obj, name, comment=''): uname = 'jot/'+name+suffix - # which one works better? + # which one works better? #all = ip.shadowhist.all() all = ip.shell.history_manager.input_hist_parsed # We may actually want to make snapshot of files that are run-ned. - # get the comment + # get the comment try: comment = ip.magic_edit('-x').strip() except: print "No comment is recorded." comment = '' - self.db[uname] = Struct({'val':obj, - 'time' : datetime.now(), + self.db[uname] = Struct({'val':obj, + 'time' : datetime.now(), 'hist' : all, 'name' : name, 'comment' : comment,}) print "Jotted down notes for '%s' (%s)" % (uname, obj.__class__.__name__) - + def magic_jot(self, parameter_s=''): """Lightweight persistence for python variables. Example: - + ville@badger[~]|1> A = ['hello',10,'world']\\ ville@badger[~]|2> %jot A\\ ville@badger[~]|3> Exit - + (IPython session is closed and started again...) - + ville@badger:~$ ipython -p pysh\\ ville@badger[~]|1> print A - + ['hello', 10, 'world'] - + Usage: - + %jot - Show list of all variables and their current values\\ %jot -l - Show list of all variables and their current values in detail\\ %jot -l - Show one variable and its current values in detail\\ @@ -165,16 +165,16 @@ def magic_jot(self, parameter_s=''): %jot -z - Remove all variables from storage (disabled)\\ %jot -r - Refresh/Load variable from jot (delete current vals)\\ %jot foo >a.txt - Store value of foo to new file a.txt\\ - %jot foo >>a.txt - Append value of foo to file a.txt\\ - + %jot foo >>a.txt - Append value of foo to file a.txt\\ + It should be noted that if you change the value of a variable, you need to %note it again if you want to persist the new value. - + Note also that the variables will need to be pickleable; most basic python types can be safely %stored. - + """ - + opts,argsl = self.parse_options(parameter_s,'drzl',mode='string') args = argsl.split(None,1) ip = self.getapi() @@ -214,30 +214,30 @@ def magic_jot(self, parameter_s=''): else: print "Details for", tolist, ":" detail_variables(ip, tolist) - - # run without arguments -> list noted variables & notes + + # run without arguments -> list noted variables & notes elif not args: vars = self.db.keys('jot/*') - vars.sort() + vars.sort() if vars: - size = max(map(len,vars)) - 4 + size = max(map(len,vars)) - 4 else: size = 0 - + print 'Variables and their in-db values:' fmt = '%-'+str(size)+'s [%s] -> %s' get = db.get for var in vars: justkey = os.path.basename(var) v = get(var,'') - try: + try: print fmt % (justkey,\ datetime.ctime(v.get('time','')),\ v.get('comment','')[:70].replace('\n',' '),) except AttributeError: print fmt % (justkey, '', '', repr(v)[:50]) - + # default action - store the variable else: # %store foo >file.txt or >>file.txt @@ -251,7 +251,7 @@ def magic_jot(self, parameter_s=''): print "Writing '%s' (%s) to file '%s'." % (args[0], obj.__class__.__name__, fnam) - + if not isinstance (obj,basestring): from pprint import pprint pprint(obj,fil) @@ -259,10 +259,10 @@ def magic_jot(self, parameter_s=''): fil.write(obj) if not obj.endswith('\n'): fil.write('\n') - + fil.close() return - + # %note foo try: obj = ip.user_ns[args[0]] @@ -270,18 +270,18 @@ def magic_jot(self, parameter_s=''): # this should not be alias, for aliases, use %store print print "Error: %s doesn't exist." % args[0] - print + print print "Use %note -r to retrieve variables. This should not be used " +\ - "to store alias, for saving aliases, use %store" + "to store alias, for saving aliases, use %store" return else: if isinstance(inspect.getmodule(obj), FakeModule): print textwrap.dedent("""\ - Warning:%s is %s + Warning:%s is %s Proper storage of interactively declared classes (or instances of those classes) is not possible! Only instances of classes in real modules on file system can be %%store'd. - """ % (args[0], obj) ) + """ % (args[0], obj) ) return #pickled = pickle.dumps(obj) #self.db[ 'jot/' + args[0] ] = obj @@ -289,11 +289,11 @@ def magic_jot(self, parameter_s=''): def magic_read(self, parameter_s=''): - """ + """ %read - Load variable from data that is jotted down.\\ - + """ - + opts,argsl = self.parse_options(parameter_s,'drzl',mode='string') args = argsl.split(None,1) ip = self.getapi() diff --git a/IPython/quarantine/ipy_lookfor.py b/IPython/quarantine/ipy_lookfor.py index 98738c3..33729ce 100644 --- a/IPython/quarantine/ipy_lookfor.py +++ b/IPython/quarantine/ipy_lookfor.py @@ -45,7 +45,7 @@ def lookfor(what, modules=None, import_modules=True, regenerate=False): cache.update(c) except ImportError: pass - + # Search # XXX: maybe using a real stemming search engine would be better? found = [] @@ -53,7 +53,7 @@ def lookfor(what, modules=None, import_modules=True, regenerate=False): if not whats: return for name, (docstring, kind, index) in cache.iteritems(): - if kind in ('module', 'object'): + if kind in ('module', 'object'): # don't show modules or objects continue ok = True @@ -69,7 +69,7 @@ def lookfor(what, modules=None, import_modules=True, regenerate=False): # XXX: this is full Harrison-Stetson heuristics now, # XXX: it probably could be improved - kind_relevance = {'func': 1000, 'class': 1000, + kind_relevance = {'func': 1000, 'class': 1000, 'module': -1000, 'object': -1000} def relevance(name, docstr, kind, index): @@ -138,7 +138,7 @@ def _lookfor_generate_cache(module, import_modules, regenerate): cache : dict {obj_full_name: (docstring, kind, index), ...} Docstring cache for the module, either cached one (regenerate=False) or newly generated. - + """ global _lookfor_caches @@ -164,7 +164,7 @@ def _lookfor_generate_cache(module, import_modules, regenerate): index += 1 kind = "object" - + if inspect.ismodule(item): kind = "module" try: @@ -190,7 +190,7 @@ def _lookfor_generate_cache(module, import_modules, regenerate): stack.append(("%s.%s" % (name, n), v)) elif callable(item): kind = "func" - + doc = inspect.getdoc(item) if doc is not None: cache[name] = (doc, kind, index) diff --git a/IPython/quarantine/ipy_rehashdir.py b/IPython/quarantine/ipy_rehashdir.py index 07faf13..3c7cbd2 100644 --- a/IPython/quarantine/ipy_rehashdir.py +++ b/IPython/quarantine/ipy_rehashdir.py @@ -4,9 +4,9 @@ Usage: %rehashdir c:/bin c:/tools - - Add all executables under c:/bin and c:/tools to alias table, in + - Add all executables under c:/bin and c:/tools to alias table, in order to make them directly executable from any directory. - + This also serves as an example on how to extend ipython with new magic functions. @@ -23,27 +23,27 @@ import os,re,fnmatch,sys def selflaunch(ip,line): """ Launch python script with 'this' interpreter - + e.g. d:\foo\ipykit.exe a.py - + """ - + tup = line.split(None,1) if len(tup) == 1: print "Launching nested ipython session" os.system(sys.executable) return - + cmd = sys.executable + ' ' + tup[1] print ">",cmd os.system(cmd) class PyLauncher: """ Invoke selflanucher on the specified script - + This is mostly useful for associating with scripts using:: _ip.define_alias('foo',PyLauncher('foo_script.py')) - + """ def __init__(self,script): self.script = os.path.abspath(script) @@ -57,22 +57,22 @@ class PyLauncher: tail = ' ' + tup[1] else: tail = '' - + selflaunch(ip,"py " + self.script + tail) def __repr__(self): return 'PyLauncher("%s")' % self.script def rehashdir_f(self,arg): """ Add executables in all specified dirs to alias table - + Usage: %rehashdir c:/bin;c:/tools - - Add all executables under c:/bin and c:/tools to alias table, in + - Add all executables under c:/bin and c:/tools to alias table, in order to make them directly executable from any directory. - + Without arguments, add all executables in current directory. - + """ # most of the code copied from Magic.magic_rehashx @@ -83,13 +83,13 @@ def rehashdir_f(self,arg): if fnmatch.fnmatch(fname, j): return True return False - + created = [] if not arg: arg = '.' path = map(os.path.abspath,arg.split(';')) alias_table = self.shell.alias_manager.alias_table - + if os.name == 'posix': isexec = lambda fname:os.path.isfile(fname) and \ os.access(fname,os.X_OK) @@ -101,7 +101,7 @@ def rehashdir_f(self,arg): winext = 'exe|com|bat|py' if 'py' not in winext: winext += '|py' - + execre = re.compile(r'(.*)\.(%s)$' % winext,re.IGNORECASE) isexec = lambda fname:os.path.isfile(fname) and execre.match(fname) savedir = os.getcwdu() @@ -117,7 +117,7 @@ def rehashdir_f(self,arg): # where N is the number of positional arguments of the # alias. src,tgt = os.path.splitext(ff)[0], os.path.abspath(ff) - created.append(src) + created.append(src) alias_table[src] = (0,tgt) else: for pdir in path: @@ -126,7 +126,7 @@ def rehashdir_f(self,arg): if isexec(ff) and not isjunk(ff): src, tgt = execre.sub(r'\1',ff), os.path.abspath(ff) src = src.lower() - created.append(src) + created.append(src) alias_table[src] = (0,tgt) # Make sure the alias table doesn't contain keywords or builtins self.shell.alias_table_validate() diff --git a/IPython/quarantine/ipy_render.py b/IPython/quarantine/ipy_render.py index 129d5c3..37585ba 100644 --- a/IPython/quarantine/ipy_render.py +++ b/IPython/quarantine/ipy_render.py @@ -11,7 +11,7 @@ from IPython.external.Itpl import itplns def toclip_w32(s): """ Places contents of s to clipboard - + Needs pyvin32 to work: http://sourceforge.net/projects/pywin32/ """ @@ -23,29 +23,29 @@ def toclip_w32(s): cl.CloseClipboard() try: - import win32clipboard + import win32clipboard toclip = toclip_w32 except ImportError: def toclip(s): pass - + def render(tmpl): """ Render a template (Itpl format) from ipython variables Example: - + $ import ipy_render $ my_name = 'Bob' # %store this for convenience $ t_submission_form = "Submission report, author: $my_name" # %store also $ render t_submission_form - + => returns "Submission report, author: Bob" and copies to clipboard on win32 # if template exist as a file, read it. Note: ;f hei vaan => f("hei vaan") - $ ;render c:/templates/greeting.txt - + $ ;render c:/templates/greeting.txt + Template examples (Ka-Ping Yee's Itpl library): - + Here is a $string. Here is a $module.member. Here is an $object.member. @@ -54,10 +54,10 @@ def render(tmpl): Here is an $array[3] member. Here is a $dictionary['member']. """ - + if os.path.isfile(tmpl): tmpl = open(tmpl).read() - + res = itplns(tmpl, ip.user_ns) toclip(res) return res diff --git a/IPython/quarantine/ipy_server.py b/IPython/quarantine/ipy_server.py index a409942..ba1c12f 100644 --- a/IPython/quarantine/ipy_server.py +++ b/IPython/quarantine/ipy_server.py @@ -6,7 +6,7 @@ import ipy_server ipy_server.serve_thread(16455) Now, to execute the statements in this ipython instance, open a TCP socket -(port 16455), write out the statements, and close the socket. +(port 16455), write out the statements, and close the socket. You can use e.g. "telnet localhost 16455" or a script to do this. This is a bit like 'M-x server-start" or gnuserv in the emacs world. diff --git a/IPython/quarantine/ipy_signals.py b/IPython/quarantine/ipy_signals.py index 3d7f072..64478db 100644 --- a/IPython/quarantine/ipy_signals.py +++ b/IPython/quarantine/ipy_signals.py @@ -17,27 +17,27 @@ ip = ipapi.get() def new_ipsystem_posix(cmd): """ ctrl+c ignoring replacement for system() command in iplib. - - Ignore ctrl + c in IPython process during the command execution. + + Ignore ctrl + c in IPython process during the command execution. The subprocess will still get the ctrl + c signal. - + posix implementation """ - + p = subprocess.Popen(cmd, shell = True) - + old_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) pid,status = os.waitpid(p.pid,0) signal.signal(signal.SIGINT, old_handler) if status and ip.options.verbose: print "[exit status: %d]" % status - -def new_ipsystem_win32(cmd): + +def new_ipsystem_win32(cmd): """ ctrl+c ignoring replacement for system() command in iplib. - - Ignore ctrl + c in IPython process during the command execution. + + Ignore ctrl + c in IPython process during the command execution. The subprocess will still get the ctrl + c signal. - + win32 implementation """ old_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) @@ -45,8 +45,8 @@ def new_ipsystem_win32(cmd): signal.signal(signal.SIGINT, old_handler) if status and ip.options.verbose: print "[exit status: %d]" % status - - + + def init(): o = ip.options try: @@ -54,9 +54,8 @@ def init(): except AttributeError: o.allow_new_attr (True ) o.verbose = 0 - - ip.system = (sys.platform == 'win32' and new_ipsystem_win32 or + + ip.system = (sys.platform == 'win32' and new_ipsystem_win32 or new_ipsystem_posix) - + init() - \ No newline at end of file diff --git a/IPython/quarantine/ipy_system_conf.py b/IPython/quarantine/ipy_system_conf.py index 539650d..1bda585 100644 --- a/IPython/quarantine/ipy_system_conf.py +++ b/IPython/quarantine/ipy_system_conf.py @@ -3,7 +3,7 @@ This will be imported by ipython for all users. After this ipy_user_conf.py is imported, user specific configuration -should reside there. +should reside there. """ @@ -11,7 +11,7 @@ from IPython.core import ipapi ip = ipapi.get() # add system wide configuration information, import extensions etc. here. -# nothing here is essential +# nothing here is essential import sys diff --git a/IPython/quarantine/ipy_winpdb.py b/IPython/quarantine/ipy_winpdb.py index 2150b17..d59de7c 100644 --- a/IPython/quarantine/ipy_winpdb.py +++ b/IPython/quarantine/ipy_winpdb.py @@ -3,8 +3,8 @@ Usage: %wdb test.py - run test.py, with a winpdb breakpoint at start of the file - + run test.py, with a winpdb breakpoint at start of the file + %wdb pass Change the password (e.g. if you have forgotten the old one) @@ -31,16 +31,16 @@ rpdb_started = False def wdb_f(self, arg): """ Debug a script (like %run -d) in IPython process, Using WinPdb - + Usage: - + %wdb test.py - run test.py, with a winpdb breakpoint at start of the file - + run test.py, with a winpdb breakpoint at start of the file + %wdb pass Change the password (e.g. if you have forgotten the old one) - - Note that after the script has been run, you need to do "Go" (f5) + + Note that after the script has been run, you need to do "Go" (f5) in WinPdb to resume normal IPython operation. """ @@ -48,15 +48,15 @@ def wdb_f(self, arg): if not arg.strip(): print __doc__ return - + if arg.strip() == 'pass': passwd = raw_input('Enter new winpdb session password: ') ip.db['winpdb_pass'] = passwd print "Winpdb password changed" if rpdb_started: print "You need to restart IPython to use the new password" - return - + return + path = os.path.abspath(arg) if not os.path.isfile(path): raise UsageError("%%wdb: file %s does not exist" % path) @@ -66,19 +66,19 @@ def wdb_f(self, arg): import textwrap print textwrap.dedent("""\ Winpdb sessions need a password that you use for attaching the external - winpdb session. IPython will remember this. You can change the password later + winpdb session. IPython will remember this. You can change the password later by '%wpdb pass' """) passwd = raw_input('Enter new winpdb session password: ') ip.db['winpdb_pass'] = passwd - + print "Starting rpdb2 in IPython process" rpdb2.start_embedded_debugger(passwd, timeout = 0) rpdb_started = True - + rpdb2.set_temp_breakpoint(path) print 'It is time to attach with WinPdb (launch WinPdb if needed, File -> Attach)' ip.magic('%run ' + arg) - + ip.define_magic('wdb', wdb_f) diff --git a/IPython/quarantine/ipy_workdir.py b/IPython/quarantine/ipy_workdir.py index 4b79e44..539bb21 100644 --- a/IPython/quarantine/ipy_workdir.py +++ b/IPython/quarantine/ipy_workdir.py @@ -5,14 +5,14 @@ import os, subprocess workdir = None def workdir_f(ip,line): - """ Exceute commands residing in cwd elsewhere - + """ Exceute commands residing in cwd elsewhere + Example:: - + workdir /myfiles cd bin - workdir myscript.py - + workdir myscript.py + executes myscript.py (stored in bin, but not in path) in /myfiles """ global workdir diff --git a/IPython/quarantine/jobctrl.py b/IPython/quarantine/jobctrl.py index 0c8d70f..d687fb6 100644 --- a/IPython/quarantine/jobctrl.py +++ b/IPython/quarantine/jobctrl.py @@ -1,4 +1,4 @@ -""" Preliminary "job control" extensions for IPython +""" Preliminary "job control" extensions for IPython requires python 2.4 (or separate 'subprocess' module @@ -39,7 +39,7 @@ Now launch a new IPython prompt and kill the process: [Q:/ipython]|4> (you don't need to specify PID for %kill if only one task is running) -""" +""" from subprocess import * import os,shlex,sys,time @@ -55,8 +55,8 @@ if os.name == 'nt': else: def kill_process(pid): os.system('kill -9 %d' % pid) - - + + class IpyPopen(Popen): def go(self): @@ -66,7 +66,7 @@ class IpyPopen(Popen): def kill(self): kill_process(self.pid) - + def startjob(job): p = IpyPopen(shlex.split(job), stdout=PIPE, shell = False) p.line = job @@ -85,7 +85,7 @@ class AsyncJobQ(threading.Thread): self.output.append("** Discarding: '%s' - %s" % (cmd,cwd)) continue self.output.append("** Task started: '%s' - %s" % (cmd,cwd)) - + p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd = cwd) out = p.stdout.read() self.output.append("** Task complete: '%s'\n" % cmd) @@ -93,16 +93,16 @@ class AsyncJobQ(threading.Thread): def add(self,cmd): self.q.put_nowait((cmd, os.getcwdu())) - + def dumpoutput(self): while self.output: item = self.output.pop(0) - print item + print item _jobq = None def jobqueue_f(self, line): - + global _jobq if not _jobq: print "Starting jobqueue - do '&some_long_lasting_system_command' to enqueue" @@ -118,11 +118,11 @@ def jobqueue_f(self, line): if line.strip() == 'start': _jobq.stop = False return - -def jobctrl_prefilter_f(self,line): + +def jobctrl_prefilter_f(self,line): if line.startswith('&'): pre,fn,rest = self.split_user_input(line[1:]) - + line = ip.expand_aliases(fn,rest) if not _jobq: return 'get_ipython().startjob(%s)' % make_quoted_expr(line) @@ -147,7 +147,7 @@ def magic_tasks(self,line): A 'task' is a process that has been started in IPython when 'jobctrl' extension is enabled. Tasks can be killed with %kill. - + '%tasks clear' clears the task list (from stale tasks) """ ip = self.getapi() @@ -156,7 +156,7 @@ def magic_tasks(self,line): print "Clearing",ip.db[k] del ip.db[k] return - + ents = job_list(ip) if not ents: print "No tasks running" @@ -181,19 +181,19 @@ def magic_kill(self,line): else: magic_tasks(self,line) return - + try: pid = int(line) kill_process(pid) except ValueError: magic_tasks(self,line) - + if sys.platform == 'win32': shell_internal_commands = 'break chcp cls copy ctty date del erase dir md mkdir path prompt rd rmdir start time type ver vol'.split() PopenExc = WindowsError else: # todo linux commands - shell_internal_commands = [] + shell_internal_commands = [] PopenExc = OSError @@ -218,10 +218,10 @@ def jobctrl_shellcmd(ip,cmd): else: # have to go via shell, sucks p = Popen(cmd,shell = True) - + jobentry = 'tasks/t' + str(p.pid) ip.db[jobentry] = (p.pid,cmd,os.getcwdu(),time.time()) - p.communicate() + p.communicate() finally: if jobentry: @@ -238,5 +238,5 @@ def install(): ip.define_magic('kill',magic_kill) ip.define_magic('tasks',magic_tasks) ip.define_magic('jobqueue',jobqueue_f) - ip.set_hook('pre_prompt_hook', jobq_output_hook) + ip.set_hook('pre_prompt_hook', jobq_output_hook) install() diff --git a/IPython/quarantine/ledit.py b/IPython/quarantine/ledit.py index fa309b1..e98269c 100644 --- a/IPython/quarantine/ledit.py +++ b/IPython/quarantine/ledit.py @@ -1,9 +1,9 @@ -""" Fun magic line editor for ipython +""" Fun magic line editor for ipython -Use this to easily edit lists of strings gradually without crafting long +Use this to easily edit lists of strings gradually without crafting long list comprehensions. -'l' is the magic variable name for every line (array element). Save the current +'l' is the magic variable name for every line (array element). Save the current result (or more exactly, retrieve the last ipython computation result into %led work area) by running '%led s'. Just run '%led' to show the current work area data. @@ -51,9 +51,9 @@ curdata = [] def line_edit_f(self, cmd ): global curdata - + if not cmd: - + print "Magic line editor (for lists of strings)" if curdata: print "current data is:" @@ -62,12 +62,12 @@ def line_edit_f(self, cmd ): print "No current data, you should set it by running '%led s'" print "When you have your data in _ (result of last computation)." return - + if cmd == 's': curdata = ip.ev('_') print "Data set from last result (_)" newlines = curdata - + else: # simple method call, e.g. upper if cmd.isalpha(): @@ -83,16 +83,16 @@ def line_edit_f(self, cmd ): continue newlines.append(l2) - + return newlines def line_edit_complete_f(self,event): """ Show all string methods in completions """ if event.symbol.startswith('l.'): return ['l.' + func for func in dir('')] - + return dir('') + ['l.' + func for func in dir('')] ip.set_hook('complete_command', line_edit_complete_f , str_key = '%led') - + ip.define_magic('led', line_edit_f) \ No newline at end of file diff --git a/IPython/quarantine/pspersistence.py b/IPython/quarantine/pspersistence.py index dbba916..564557e 100644 --- a/IPython/quarantine/pspersistence.py +++ b/IPython/quarantine/pspersistence.py @@ -36,56 +36,56 @@ def refresh_variables(ip): else: #print "restored",justkey,"=",obj #dbg ip.user_ns[justkey] = obj - + def restore_dhist(ip): db = ip.db ip.user_ns['_dh'] = db.get('dhist',[]) - + def restore_data(self): ip = self.getapi() refresh_variables(ip) restore_aliases(self) restore_dhist(self) raise TryNext - + ip.set_hook('late_startup_hook', restore_data) def magic_store(self, parameter_s=''): """Lightweight persistence for python variables. Example: - + ville@badger[~]|1> A = ['hello',10,'world']\\ ville@badger[~]|2> %store A\\ ville@badger[~]|3> Exit - + (IPython session is closed and started again...) - + ville@badger:~$ ipython -p pysh\\ ville@badger[~]|1> print A - + ['hello', 10, 'world'] - + Usage: - + %store - Show list of all variables and their current values\\ %store - Store the *current* value of the variable to disk\\ %store -d - Remove the variable and its value from storage\\ %store -z - Remove all variables from storage\\ %store -r - Refresh all variables from store (delete current vals)\\ %store foo >a.txt - Store value of foo to new file a.txt\\ - %store foo >>a.txt - Append value of foo to file a.txt\\ - + %store foo >>a.txt - Append value of foo to file a.txt\\ + It should be noted that if you change the value of a variable, you need to %store it again if you want to persist the new value. - + Note also that the variables will need to be pickleable; most basic python types can be safely %stored. - + Also aliases can be %store'd across sessions. """ - + opts,argsl = self.parse_options(parameter_s,'drz',mode='string') args = argsl.split(None,1) ip = self.getapi() @@ -109,16 +109,16 @@ def magic_store(self, parameter_s=''): elif opts.has_key('r'): refresh_variables(ip) - + # run without arguments -> list variables & values elif not args: vars = self.db.keys('autorestore/*') - vars.sort() + vars.sort() if vars: size = max(map(len,vars)) else: size = 0 - + print 'Stored variables and their in-db values:' fmt = '%-'+str(size)+'s -> %s' get = db.get @@ -126,7 +126,7 @@ def magic_store(self, parameter_s=''): justkey = os.path.basename(var) # print 30 first characters from every var print fmt % (justkey,repr(get(var,''))[:50]) - + # default action - store the variable else: # %store foo >file.txt or >>file.txt @@ -140,7 +140,7 @@ def magic_store(self, parameter_s=''): print "Writing '%s' (%s) to file '%s'." % (args[0], obj.__class__.__name__, fnam) - + if not isinstance (obj,basestring): from pprint import pprint pprint(obj,fil) @@ -148,10 +148,10 @@ def magic_store(self, parameter_s=''): fil.write(obj) if not obj.endswith('\n'): fil.write('\n') - + fil.close() return - + # %store foo try: obj = ip.user_ns[args[0]] @@ -161,20 +161,20 @@ def magic_store(self, parameter_s=''): if args[0] in self.alias_table: staliases = db.get('stored_aliases',{}) staliases[ args[0] ] = self.alias_table[ args[0] ] - db['stored_aliases'] = staliases + db['stored_aliases'] = staliases print "Alias stored:", args[0], self.alias_table[ args[0] ] return else: raise UsageError("Unknown variable '%s'" % args[0]) - + else: if isinstance(inspect.getmodule(obj), FakeModule): print textwrap.dedent("""\ - Warning:%s is %s + Warning:%s is %s Proper storage of interactively declared classes (or instances of those classes) is not possible! Only instances of classes in real modules on file system can be %%store'd. - """ % (args[0], obj) ) + """ % (args[0], obj) ) return #pickled = pickle.dumps(obj) self.db[ 'autorestore/' + args[0] ] = obj diff --git a/IPython/quarantine/win32clip.py b/IPython/quarantine/win32clip.py index 8c836a0..121559a 100644 --- a/IPython/quarantine/win32clip.py +++ b/IPython/quarantine/win32clip.py @@ -11,12 +11,12 @@ def clip_f( self, parameter_s = '' ): This function uses the same syntax as %macro for line extraction, but instead of creating a macro it saves the resulting string to the clipboard. - - When used without arguments, this returns the text contents of the clipboard. + + When used without arguments, this returns the text contents of the clipboard. E.g. - + mytext = %clip - + """ import win32clipboard as cl @@ -28,7 +28,7 @@ def clip_f( self, parameter_s = '' ): cl.CloseClipboard() return data api = self.getapi() - + if parameter_s.lstrip().startswith('='): rest = parameter_s[parameter_s.index('=')+1:].strip() val = str(api.ev(rest)) @@ -41,5 +41,5 @@ def clip_f( self, parameter_s = '' ): cl.CloseClipboard() print 'The following text was written to the clipboard' print val - + ip.define_magic( "clip", clip_f ) diff --git a/IPython/testing/decorators.py b/IPython/testing/decorators.py index 040b97a..126ede1 100644 --- a/IPython/testing/decorators.py +++ b/IPython/testing/decorators.py @@ -150,7 +150,7 @@ def make_label_dec(label,ds=None): labels = [label] else: labels = label - + # Validate that the given label(s) are OK for use in setattr() by doing a # dry run on a dummy function. tmp = lambda : None @@ -162,12 +162,12 @@ def make_label_dec(label,ds=None): for label in labels: setattr(f,label,True) return f - + # Apply the user's docstring, or autogenerate a basic one if ds is None: ds = "Labels a test as %r." % label decor.__doc__ = ds - + return decor @@ -179,11 +179,11 @@ def skipif(skip_condition, msg=None): Parameters ---------- - skip_condition : bool or callable. - Flag to determine whether to skip test. If the condition is a - callable, it is used at runtime to dynamically make the decision. This - is useful for tests that may require costly imports, to delay the cost - until the test suite is actually executed. + skip_condition : bool or callable. + Flag to determine whether to skip test. If the condition is a + callable, it is used at runtime to dynamically make the decision. This + is useful for tests that may require costly imports, to delay the cost + until the test suite is actually executed. msg : string Message to give on raising a SkipTest exception @@ -202,8 +202,8 @@ def skipif(skip_condition, msg=None): ''' def skip_decorator(f): - # Local import to avoid a hard nose dependency and only incur the - # import time overhead at actual test-time. + # Local import to avoid a hard nose dependency and only incur the + # import time overhead at actual test-time. import nose # Allow for both boolean or callable skip conditions. @@ -225,7 +225,7 @@ def skipif(skip_condition, msg=None): if skip_val(): raise nose.SkipTest(get_msg(f,msg)) else: - return f(*args, **kwargs) + return f(*args, **kwargs) def skipper_gen(*args, **kwargs): """Skipper for test generators.""" @@ -240,7 +240,7 @@ def skipif(skip_condition, msg=None): skipper = skipper_gen else: skipper = skipper_func - + return nose.tools.make_decorator(f)(skipper) return skip_decorator diff --git a/IPython/testing/globalipapp.py b/IPython/testing/globalipapp.py index ceb6ad4..0a4231c 100644 --- a/IPython/testing/globalipapp.py +++ b/IPython/testing/globalipapp.py @@ -38,20 +38,20 @@ from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell class StreamProxy(io.IOStream): """Proxy for sys.stdout/err. This will request the stream *at call time* allowing for nose's Capture plugin's redirection of sys.stdout/err. - + Parameters ---------- name : str The name of the stream. This will be requested anew at every call """ - + def __init__(self, name): self.name=name - + @property def stream(self): return getattr(sys, self.name) - + def flush(self): self.stream.flush() @@ -62,7 +62,7 @@ class StreamProxy(io.IOStream): class py_file_finder(object): def __init__(self,test_filename): self.test_filename = test_filename - + def __call__(self,name,win32=False): from IPython.utils.path import get_py_filename try: @@ -71,7 +71,7 @@ class py_file_finder(object): test_dir = os.path.dirname(self.test_filename) new_path = os.path.join(test_dir,name) return get_py_filename(new_path,win32=win32) - + def _run_ns_sync(self,arg_s,runner=None): """Modified version of %run that syncs testing namespaces. @@ -94,7 +94,7 @@ class ipnsdict(dict): which is needed because of how Python's doctest machinery operates with '_'. See constructor and :meth:`update` for details. """ - + def __init__(self,*a): dict.__init__(self,*a) self._savedict = {} @@ -102,11 +102,11 @@ class ipnsdict(dict): # remove a key named '_'. This is so that such a dict can be used as a # namespace in doctests that call '_'. self.protect_underscore = False - + def clear(self): dict.clear(self) self.update(self._savedict) - + def _checkpoint(self): self._savedict.clear() self._savedict.update(self) @@ -132,7 +132,7 @@ class ipnsdict(dict): # correct for that ourselves, to ensure consitency with the 'real' # ipython. self['__builtins__'] = builtin_mod - + def __delitem__(self, key): """Part of the test suite checks that we can release all references to an object. So we need to make sure that we're not @@ -177,7 +177,7 @@ def start_ipython(): if hasattr(start_ipython, 'already_called'): return start_ipython.already_called = True - + # Store certain global objects that IPython modifies _displayhook = sys.displayhook _excepthook = sys.excepthook @@ -187,16 +187,16 @@ def start_ipython(): config = tools.default_config() # Create and initialize our test-friendly IPython instance. - shell = TerminalInteractiveShell.instance(config=config, + shell = TerminalInteractiveShell.instance(config=config, user_ns=ipnsdict(), user_global_ns={} ) # A few more tweaks needed for playing nicely with doctests... - + # remove history file shell.tempfiles.append(config.HistoryManager.hist_file) - + # These traps are normally only active for interactive use, set them # permanently since we'll be mocking interactive sessions. shell.builtin_trap.activate() @@ -205,12 +205,12 @@ def start_ipython(): # can capture subcommands and print them to Python's stdout, otherwise the # doctest machinery would miss them. shell.system = py3compat.MethodType(xsys, shell) - + shell._showtraceback = py3compat.MethodType(_showtraceback, shell) # IPython is ready, now clean up some global state... - + # Deactivate the various python system hooks added by ipython for # interactive convenience so we don't confuse the doctest system sys.modules['__main__'] = _main @@ -224,7 +224,7 @@ def start_ipython(): get_ipython = _ip.get_ipython builtin_mod._ip = _ip builtin_mod.get_ipython = get_ipython - + # To avoid extra IPython messages during testing, suppress io.stdout/stderr io.stdout = StreamProxy('stdout') io.stderr = StreamProxy('stderr') diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 97b7e5a..e97ad63 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -88,18 +88,18 @@ def extract_version(mod): def test_for(item, min_version=None, callback=extract_version): """Test to see if item is importable, and optionally check against a minimum version. - + If min_version is given, the default behavior is to check against the `__version__` attribute of the item, but specifying `callback` allows you to extract the value you are interested in. e.g:: - + In [1]: import sys - + In [2]: from IPython.testing.iptest import test_for - + In [3]: test_for('sys', (2,6), callback=lambda sys: sys.version_info) Out[3]: True - + """ try: check = import_item(item) @@ -112,7 +112,7 @@ def test_for(item, min_version=None, callback=extract_version): if callback: # extra processing step to get version to compare check = callback(check) - + return check >= min_version else: return True @@ -156,7 +156,7 @@ def report(): avail = [] not_avail = [] - + for k, is_avail in have.items(): if is_avail: avail.append(k) @@ -172,7 +172,7 @@ def report(): out.append('\nTools and libraries NOT available at test time:\n') not_avail.sort() out.append(' ' + ' '.join(not_avail)+'\n') - + return ''.join(out) @@ -188,7 +188,7 @@ def make_exclude(): # Simple utility to make IPython paths more readably, we need a lot of # these below ipjoin = lambda *paths: pjoin('IPython', *paths) - + exclusions = [ipjoin('external'), pjoin('IPython_doctest_plugin'), ipjoin('quarantine'), @@ -207,7 +207,7 @@ def make_exclude(): if not have['wx']: exclusions.append(ipjoin('lib', 'inputhookwx')) - + # We do this unconditionally, so that the test suite doesn't import # gtk, changing the default encoding and masking some unicode bugs. exclusions.append(ipjoin('lib', 'inputhookgtk')) @@ -229,7 +229,7 @@ def make_exclude(): exclusions.append(ipjoin('parallel')) elif not have['qt']: exclusions.append(ipjoin('frontend', 'qt')) - + if not have['pymongo']: exclusions.append(ipjoin('parallel', 'controller', 'mongodb')) exclusions.append(ipjoin('parallel', 'tests', 'test_mongodb')) @@ -259,7 +259,7 @@ class IPTester(object): call_args = None #: list, process ids of subprocesses we start (for cleanup) pids = None - + def __init__(self, runner='iptest', params=None): """Create new test runner.""" p = os.path @@ -303,7 +303,7 @@ class IPTester(object): retcode = subp.wait() self.pids.pop() return retcode - + def run(self): """Run the stored commands""" try: @@ -318,7 +318,7 @@ class IPTester(object): if not hasattr(os, 'kill'): return - + for pid in self.pids: try: print 'Cleaning stale PID:', pid @@ -326,7 +326,7 @@ class IPTester(object): except OSError: # This is just a best effort, if we fail or the process was # really gone, ignore it. - pass + pass def make_runners(): @@ -336,10 +336,10 @@ def make_runners(): # Packages to be tested via nose, that only depend on the stdlib nose_pkg_names = ['config', 'core', 'extensions', 'frontend', 'lib', 'scripts', 'testing', 'utils', 'nbformat' ] - + if have['zmq']: nose_pkg_names.append('parallel') - + # For debugging this code, only load quick stuff #nose_pkg_names = ['core', 'extensions'] # dbg @@ -348,29 +348,29 @@ def make_runners(): # Make runners runners = [ (v, IPTester('iptest', params=v)) for v in nose_packages ] - + return runners def run_iptest(): """Run the IPython test suite using nose. - + This function is called when this script is **not** called with the form `iptest all`. It simply calls nose with appropriate command line flags and accepts all of the standard nose arguments. """ - warnings.filterwarnings('ignore', + warnings.filterwarnings('ignore', 'This will be removed soon. Use IPython.testing.util instead') argv = sys.argv + [ '--detailed-errors', # extra info in tracebacks - + # Loading ipdoctest causes problems with Twisted, but # our test suite runner now separates things and runs # all Twisted tests with trial. '--with-ipdoctest', '--ipdoctest-tests','--ipdoctest-extension=txt', - + # We add --exe because of setuptools' imbecility (it # blindly does chmod +x on ALL files). Nose does the # right thing and it tries to avoid executables, @@ -402,7 +402,7 @@ def run_iptest(): def run_iptestall(): """Run the entire IPython test suite by calling nose and trial. - + This function constructs :class:`IPTester` instances for all IPython modules and package and then runs each of them. This causes the modules and packages of IPython to be tested each in their own subprocess using diff --git a/IPython/testing/mkdoctests.py b/IPython/testing/mkdoctests.py index bfec99e..f06f20f 100755 --- a/IPython/testing/mkdoctests.py +++ b/IPython/testing/mkdoctests.py @@ -45,7 +45,7 @@ class IndentOut(object): Instances of this class trap output to a given stream and first reformat it to indent every input line.""" - + def __init__(self,out=sys.stdout,indent=4): """Create an indented writer. @@ -57,7 +57,7 @@ class IndentOut(object): - `indent` : int Number of spaces to indent every input line by. """ - + self.indent_text = ' '*indent self.indent = re.compile('^',re.MULTILINE).sub self.out = out @@ -77,7 +77,7 @@ class IndentOut(object): data = ''.join(self.buffer) self.buffer[:] = [] self._write(self.indent(self.indent_text,data)) - + def close(self): self.flush() self._closed = True @@ -96,7 +96,7 @@ class RunnerFactory(object): def __init__(self,out=sys.stdout): """Instantiate a code runner.""" - + self.out = out self.runner = None self.runnerClass = None @@ -105,7 +105,7 @@ class RunnerFactory(object): self.runnerClass = runnerClass self.runner = runnerClass(out=self.out) return self.runner - + def __call__(self,fname): """Return a runner for the given filename.""" @@ -199,7 +199,7 @@ def main(): outfile = open(outfname,'w') - # all output from included files will be indented + # all output from included files will be indented indentOut = IndentOut(outfile,4) getRunner = RunnerFactory(indentOut) diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py index b36632d..ca63bcb 100644 --- a/IPython/testing/plugin/ipdoctest.py +++ b/IPython/testing/plugin/ipdoctest.py @@ -3,10 +3,10 @@ Limitations: - When generating examples for use as doctests, make sure that you have - pretty-printing OFF. This can be done either by setting the - ``PlainTextFormatter.pprint`` option in your configuration file to False, or + pretty-printing OFF. This can be done either by setting the + ``PlainTextFormatter.pprint`` option in your configuration file to False, or by interactively disabling it with %Pprint. This is required so that IPython - output matches that of normal Python, which is used by doctest for internal + output matches that of normal Python, which is used by doctest for internal execution. - Do not rely on specific prompt numbers for results (such as using @@ -68,7 +68,7 @@ def is_extension_module(filename): class DocTestSkip(object): """Object wrapper for doctests to be skipped.""" - + ds_skip = """Doctest to skip. >>> 1 #doctest: +SKIP """ @@ -166,13 +166,13 @@ class DocTestFinder(doctest.DocTestFinder): class IPDoctestOutputChecker(doctest.OutputChecker): """Second-chance checker with support for random tests. - + If the default comparison doesn't pass, this checker looks in the expected output string for flags that tell us to ignore the output. """ random_re = re.compile(r'#\s*random\s+') - + def check_output(self, want, got, optionflags): """Check output, accepting special markers embedded in the output. @@ -236,7 +236,7 @@ class DocTestCase(doctests.DocTestCase): def runTest(self): test = self._dt_test runner = self._dt_runner - + old = sys.stdout new = StringIO() optionflags = self._dt_optionflags @@ -289,7 +289,7 @@ class DocTestCase(doctests.DocTestCase): # Restore the behavior of the '_' key in the user namespace to # normal after each doctest, so that unittests behave normally _ip.user_ns.protect_underscore = False - + # XXX - fperez: I am not sure if this is truly a bug in nose 0.11, but # it does look like one to me: its tearDown method tries to run # @@ -376,7 +376,7 @@ class IPDocTestParser(doctest.DocTestParser): # Mark tests to be executed in an external process - currently unsupported. _EXTERNAL_IP = re.compile(r'#\s*ipdoctest:\s*EXTERNAL') - + def ip2py(self,source): """Convert input IPython source into valid Python.""" out = [] @@ -459,7 +459,7 @@ class IPDocTestParser(doctest.DocTestParser): # Append the random-output marker (it defaults to empty in most # cases, it's only non-empty for 'all-random' tests): want += random_marker - + if Example is IPExternalExample: options[doctest.NORMALIZE_WHITESPACE] = True want += '\n' @@ -569,7 +569,7 @@ SKIP = doctest.register_optionflag('SKIP') class IPDocTestRunner(doctest.DocTestRunner,object): """Test runner that synchronizes the IPython namespace with test globals. """ - + def run(self, test, compileflags=None, out=None, clear_globs=True): # Hack: ipython needs access to the execution context of the example, @@ -582,7 +582,7 @@ class IPDocTestRunner(doctest.DocTestRunner,object): #_ip._ipdoctest_test_filename = test.filename test.globs.update(_ip.user_ns) - + return super(IPDocTestRunner,self).run(test, compileflags,out,clear_globs) @@ -669,7 +669,7 @@ class ExtensionDoctest(doctests.Doctest): def loadTestsFromModule(self, module): #print '*** ipdoctest - lTM',module # dbg - + if not self.matches(module.__name__): log.debug("Doctest doesn't want module %s", module) return @@ -691,7 +691,7 @@ class ExtensionDoctest(doctests.Doctest): continue if not test.filename: test.filename = module_file - + yield DocTestCase(test, optionflags=optionflags, checker=self.checker) diff --git a/IPython/testing/tests/test_ipunittest.py b/IPython/testing/tests/test_ipunittest.py index 487386a..ddd781c 100644 --- a/IPython/testing/tests/test_ipunittest.py +++ b/IPython/testing/tests/test_ipunittest.py @@ -26,7 +26,7 @@ Notes: - running this script with python (it has a __main__ section at the end) misses one docstring test, the one embedded in the Foo object method. Since our approach relies on using decorators that create standalone TestCase - instances, it can only be used for functions, not for methods of objects. + instances, it can only be used for functions, not for methods of objects. Authors ------- @@ -66,8 +66,8 @@ In [20]: print 1 In [26]: for i in range(10): ....: print i, - ....: - ....: + ....: + ....: 0 1 2 3 4 5 6 7 8 9 In [27]: 3+4 @@ -83,8 +83,8 @@ def ipdt_indented_test(): In [26]: for i in range(10): ....: print i, - ....: - ....: + ....: + ....: 0 1 2 3 4 5 6 7 8 9 In [27]: 3+4 @@ -107,8 +107,8 @@ class Foo(object): In [26]: for i in range(10): ....: print i, - ....: - ....: + ....: + ....: 0 1 2 3 4 5 6 7 8 9 In [27]: 3+4 diff --git a/IPython/testing/tools.py b/IPython/testing/tools.py index 9750575..abe2be3 100644 --- a/IPython/testing/tools.py +++ b/IPython/testing/tools.py @@ -134,7 +134,7 @@ def parse_test_output(txt): nerr = int(err_m.group(1)) nfail = 0 return nerr, nfail - + fail_m = re.search(r'^FAILED \(failures=(\d+)\)', txt, re.MULTILINE) if fail_m: nerr = 0 @@ -147,7 +147,7 @@ def parse_test_output(txt): nerr = int(both_m.group(1)) nfail = int(both_m.group(2)) return nerr, nfail - + # If the input didn't match any of these forms, assume no error/failures return 0, 0 @@ -197,15 +197,15 @@ def ipexec(fname, options=None): (stdout, stderr) of ipython subprocess. """ if options is None: options = [] - + # For these subprocess calls, eliminate all prompt printing so we only see # output from script execution - prompt_opts = [ '--InteractiveShell.prompt_in1=""', - '--InteractiveShell.prompt_in2=""', + prompt_opts = [ '--InteractiveShell.prompt_in1=""', + '--InteractiveShell.prompt_in2=""', '--InteractiveShell.prompt_out=""' ] cmdargs = ' '.join(default_argv() + prompt_opts + options) - + _ip = get_ipython() test_dir = os.path.dirname(__file__) @@ -256,7 +256,7 @@ def ipexec_validate(fname, expected_out, expected_err='', """ import nose.tools as nt - + out, err = ipexec(fname) #print 'OUT', out # dbg #print 'ERR', err # dbg @@ -276,7 +276,7 @@ class TempFileMixin(object): """Utility class to create temporary Python/IPython files. Meant as a mixin class for test cases.""" - + def mktmp(self, src, ext='.py'): """Make a valid python temp file.""" fname, f = temp_pyfile(src, ext) @@ -303,16 +303,16 @@ pair_fail_msg = ("Testing {0}\n\n" "Got:\n" " {3!r}\n") def check_pairs(func, pairs): - """Utility function for the common case of checking a function with a + """Utility function for the common case of checking a function with a sequence of input/output pairs. - + Parameters ---------- func : callable The function to be tested. Should accept a single argument. pairs : iterable A list of (input, expected_output) tuples. - + Returns ------- None. Raises an AssertionError if any output does not match the expected diff --git a/IPython/utils/autoattr.py b/IPython/utils/autoattr.py index 0536d98..98de1e1 100644 --- a/IPython/utils/autoattr.py +++ b/IPython/utils/autoattr.py @@ -20,7 +20,7 @@ Hettinger. http://users.rcn.com/python/download/Descriptor.htm Notes ----- -This module is taken from the NiPy project +This module is taken from the NiPy project (http://neuroimaging.scipy.org/site/index.html), and is BSD licensed. Authors @@ -57,7 +57,7 @@ class ResetMixin(object): ... def y(self): ... print '*** y computation executed ***' ... return self.x / 2.0 - ... + ... >>> a = A(10) @@ -70,7 +70,7 @@ class ResetMixin(object): Changing x >>> a.x = 20 - + a.y doesn't change to 10, since it is a static attribute: >>> a.y 5.0 @@ -111,7 +111,7 @@ class OneTimeProperty(object): Parameters ---------- func : method - + The method that will be called the first time to compute a value. Afterwards, the method's name will be a standard attribute holding the value of this computation. @@ -150,7 +150,7 @@ def auto_attr(func): ... @auto_attr ... def a(self): ... return 99 - ... + ... >>> x = MagicProp() >>> 'a' in x.__dict__ False diff --git a/IPython/utils/codeutil.py b/IPython/utils/codeutil.py index ffefe52..8c45796 100644 --- a/IPython/utils/codeutil.py +++ b/IPython/utils/codeutil.py @@ -3,7 +3,7 @@ """Utilities to enable code objects to be pickled. Any process that import this module will be able to pickle code objects. This -includes the func_code attribute of any function. Once unpickled, new +includes the func_code attribute of any function. Once unpickled, new functions can be built using new.function(code, globals()). Eventually we need to automate all of this so that functions themselves can be pickled. @@ -28,7 +28,7 @@ import types, copy_reg def code_ctor(*args): return types.CodeType(*args) - + def reduce_code(co): if co.co_freevars or co.co_cellvars: raise ValueError("Sorry, cannot pickle code objects with closures") diff --git a/IPython/utils/coloransi.py b/IPython/utils/coloransi.py index cdc5a68..88a7e65 100644 --- a/IPython/utils/coloransi.py +++ b/IPython/utils/coloransi.py @@ -19,7 +19,7 @@ def make_color_table(in_class): """Build a set of color attributes in a class. Helper function for building the *TermColors classes.""" - + color_templates = ( # Dark colors ("Black" , "0;30"), @@ -38,7 +38,7 @@ def make_color_table(in_class): ("LightBlue" , "1;34"), ("LightPurple" , "1;35"), ("LightCyan" , "1;36"), - ("White" , "1;37"), + ("White" , "1;37"), # Blinking colors. Probably should not be used in anything serious. ("BlinkBlack" , "5;30"), ("BlinkRed" , "5;31"), @@ -56,13 +56,13 @@ def make_color_table(in_class): class TermColors: """Color escape sequences. - This class defines the escape sequences for all the standard (ANSI?) + This class defines the escape sequences for all the standard (ANSI?) colors in terminals. Also defines a NoColor escape which is just the null string, suitable for defining 'dummy' color schemes in terminals which get confused by color escapes. This class should be used as a mixin for building color schemes.""" - + NoColor = '' # for color schemes in color-less terminals. Normal = '\033[0m' # Reset normal coloring _base = '\033[%sm' # Template for all other colors @@ -78,13 +78,13 @@ class InputTermColors: can wrap lines accordingly. Use this class for any colored text which needs to be used in input prompts, such as in calls to raw_input(). - This class defines the escape sequences for all the standard (ANSI?) + This class defines the escape sequences for all the standard (ANSI?) colors in terminals. Also defines a NoColor escape which is just the null string, suitable for defining 'dummy' color schemes in terminals which get confused by color escapes. This class should be used as a mixin for building color schemes.""" - + NoColor = '' # for color schemes in color-less terminals. if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs': @@ -112,13 +112,13 @@ class ColorScheme: if name is None: name = self.name return ColorScheme(name, self.colors.dict()) - + class ColorSchemeTable(dict): """General class to handle tables of color schemes. It's basically a dict of color schemes with a couple of shorthand attributes and some convenient methods. - + active_scheme_name -> obvious active_colors -> actual color table of the active scheme""" @@ -129,11 +129,11 @@ class ColorSchemeTable(dict): created with a list of valid color schemes AND the specification for the default active scheme. """ - + # create object attributes to be set later self.active_scheme_name = '' self.active_colors = None - + if scheme_list: if default_scheme == '': raise ValueError,'you must specify the default color scheme' @@ -150,7 +150,7 @@ class ColorSchemeTable(dict): if not isinstance(new_scheme,ColorScheme): raise ValueError,'ColorSchemeTable only accepts ColorScheme instances' self[new_scheme.name] = new_scheme - + def set_active_scheme(self,scheme,case_sensitive=0): """Set the currently active scheme. diff --git a/IPython/utils/generics.py b/IPython/utils/generics.py index a482d49..b65496a 100644 --- a/IPython/utils/generics.py +++ b/IPython/utils/generics.py @@ -41,7 +41,7 @@ def complete_object(obj, prev_completions): List of attributes discovered so far. This should return the list of attributes in obj. If you only wish to - add to the attributes already discovered normally, return + add to the attributes already discovered normally, return own_attrs + prev_completions. """ raise TryNext diff --git a/IPython/utils/growl.py b/IPython/utils/growl.py index 71822b7..6b8cb6a 100644 --- a/IPython/utils/growl.py +++ b/IPython/utils/growl.py @@ -34,7 +34,7 @@ class Notifier(object): def _notify(self, title, msg): if self.g_notifier is not None: - self.g_notifier.notify('core', title, msg) + self.g_notifier.notify('core', title, msg) def notify(self, title, msg): self._notify(title, msg) diff --git a/IPython/utils/io.py b/IPython/utils/io.py index 9e475ec..e46d34f 100644 --- a/IPython/utils/io.py +++ b/IPython/utils/io.py @@ -32,13 +32,13 @@ class IOStream: raise ValueError("fallback required, but not specified") self.stream = stream self._swrite = stream.write - + # clone all methods not overridden: def clone(meth): return not hasattr(self, meth) and not meth.startswith('_') for meth in filter(clone, dir(stream)): setattr(self, meth, getattr(stream, meth)) - + def write(self,data): try: self._swrite(data) @@ -52,7 +52,7 @@ class IOStream: # if we get here, something is seriously broken. print('ERROR - failed to write data to stream:', self.stream, file=sys.stderr) - + def writelines(self, lines): if isinstance(lines, basestring): lines = [lines] @@ -66,7 +66,7 @@ class IOStream: @property def closed(self): return self.stream.closed - + def close(self): pass @@ -114,11 +114,11 @@ class Tee(object): mode : optional, valid mode for open(). If a filename was give, open with this mode. - channel : str, one of ['stdout', 'stderr'] + channel : str, one of ['stdout', 'stderr'] """ if channel not in ['stdout', 'stderr']: raise ValueError('Invalid channel spec %s' % channel) - + if hasattr(file_or_name, 'write') and hasattr(file_or_name, 'seek'): self.file = file_or_name else: @@ -302,7 +302,7 @@ def temp_pyfile(src, ext='.py'): def raw_print(*args, **kw): """Raw print to sys.__stdout__, otherwise identical interface to print().""" - + print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'), file=sys.__stdout__) sys.__stdout__.flush() @@ -310,7 +310,7 @@ def raw_print(*args, **kw): def raw_print_err(*args, **kw): """Raw print to sys.__stderr__, otherwise identical interface to print().""" - + print(*args, sep=kw.get('sep', ' '), end=kw.get('end', '\n'), file=sys.__stderr__) sys.__stderr__.flush() diff --git a/IPython/utils/ipstruct.py b/IPython/utils/ipstruct.py index e23faf5..fd6e159 100644 --- a/IPython/utils/ipstruct.py +++ b/IPython/utils/ipstruct.py @@ -1,7 +1,7 @@ # encoding: utf-8 """A dict subclass that supports attribute style access. -Authors: +Authors: * Fernando Perez (original) * Brian Granger (refactoring to a dict subclass) @@ -81,7 +81,7 @@ class Struct(dict): ... s['b'] = 20 ... except KeyError: ... print 'this is not allowed' - ... + ... this is not allowed """ if not self._allownew and not self.has_key(key): @@ -92,7 +92,7 @@ class Struct(dict): def __setattr__(self, key, value): """Set an attr with protection of class members. - This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to + This calls :meth:`self.__setitem__` but convert :exc:`KeyError` to :exc:`AttributeError`. Examples @@ -106,13 +106,13 @@ class Struct(dict): ... s.get = 10 ... except AttributeError: ... print "you can't set a class member" - ... + ... you can't set a class member """ # If key is an str it might be a class member or instance var if isinstance(key, str): # I can't simply call hasattr here because it calls getattr, which - # calls self.__getattr__, which returns True for keys in + # calls self.__getattr__, which returns True for keys in # self._data. But I only want keys in the class and in # self.__dict__ if key in self.__dict__ or hasattr(Struct, key): @@ -127,7 +127,7 @@ class Struct(dict): def __getattr__(self, key): """Get an attr by calling :meth:`dict.__getitem__`. - Like :meth:`__setattr__`, this method converts :exc:`KeyError` to + Like :meth:`__setattr__`, this method converts :exc:`KeyError` to :exc:`AttributeError`. Examples @@ -142,7 +142,7 @@ class Struct(dict): ... s.b ... except AttributeError: ... print "I don't have that key" - ... + ... I don't have that key """ try: @@ -154,10 +154,10 @@ class Struct(dict): def __iadd__(self, other): """s += s2 is a shorthand for s.merge(s2). - + Examples -------- - + >>> s = Struct(a=10,b=30) >>> s2 = Struct(a=20,c=40) >>> s += s2 @@ -169,10 +169,10 @@ class Struct(dict): def __add__(self,other): """s + s2 -> New Struct made from s.merge(s2). - + Examples -------- - + >>> s1 = Struct(a=10,b=30) >>> s2 = Struct(a=20,c=40) >>> s = s1 + s2 @@ -185,10 +185,10 @@ class Struct(dict): def __sub__(self,other): """s1 - s2 -> remove keys in s2 from s1. - + Examples -------- - + >>> s1 = Struct(a=10,b=30) >>> s2 = Struct(a=40) >>> s = s1 - s2 @@ -201,10 +201,10 @@ class Struct(dict): def __isub__(self,other): """Inplace remove keys from self that are in other. - + Examples -------- - + >>> s1 = Struct(a=10,b=30) >>> s2 = Struct(a=40) >>> s1 -= s2 @@ -217,9 +217,9 @@ class Struct(dict): return self def __dict_invert(self, data): - """Helper function for merge. + """Helper function for merge. - Takes a dictionary whose values are lists and returns a dict with + Takes a dictionary whose values are lists and returns a dict with the elements of each list as keys and the original keys as values. """ outdict = {} @@ -235,10 +235,10 @@ class Struct(dict): def copy(self): """Return a copy as a Struct. - + Examples -------- - + >>> s = Struct(a=10,b=30) >>> s2 = s.copy() >>> s2 @@ -304,14 +304,14 @@ class Struct(dict): The `__conflict_solve` dict is a dictionary of binary functions which will be used to solve key conflicts. Here is an example:: - + __conflict_solve = dict( func1=['a','b','c'], func2=['d','e'] ) - + In this case, the function :func:`func1` will be used to resolve - keys 'a', 'b' and 'c' and the function :func:`func2` will be used for + keys 'a', 'b' and 'c' and the function :func:`func2` will be used for keys 'd' and 'e'. This could also be written as:: __conflict_solve = dict(func1='a b c',func2='d e') @@ -344,15 +344,15 @@ class Struct(dict): -------- This show the default policy: - + >>> s = Struct(a=10,b=30) >>> s2 = Struct(a=20,c=40) >>> s.merge(s2) >>> s {'a': 10, 'c': 40, 'b': 30} - + Now, show how to specify a conflict dict: - + >>> s = Struct(a=10,b=30) >>> s2 = Struct(a=20,b=40) >>> conflict = {'update':'a','add':'b'} diff --git a/IPython/utils/localinterfaces.py b/IPython/utils/localinterfaces.py index 4945223..fbf6f73 100644 --- a/IPython/utils/localinterfaces.py +++ b/IPython/utils/localinterfaces.py @@ -1,7 +1,7 @@ """Simple utility for building a list of local IPs using the socket module. This module defines two constants: -LOCALHOST : The loopback interface, or the first interface that points to this +LOCALHOST : The loopback interface, or the first interface that points to this machine. It will *almost* always be '127.0.0.1' LOCAL_IPS : A list of IP addresses, loopback first, that point to this machine. diff --git a/IPython/utils/notification.py b/IPython/utils/notification.py index e1c3cfb..b9af495 100644 --- a/IPython/utils/notification.py +++ b/IPython/utils/notification.py @@ -29,7 +29,7 @@ class NotificationError(Exception): class NotificationCenter(object): """Synchronous notification center. - + Examples -------- Here is a simple example of how to use this:: @@ -83,9 +83,9 @@ class NotificationCenter(object): "Notification type and sender are required.") # If there are no registered observers for the type/sender pair - if((ntype not in self.registered_types and + if((ntype not in self.registered_types and None not in self.registered_types) or - (sender not in self.registered_senders and + (sender not in self.registered_senders and None not in self.registered_senders)): return @@ -110,11 +110,11 @@ class NotificationCenter(object): def add_observer(self, callback, ntype, sender): """Add an observer callback to this notification center. - + The given callback will be called upon posting of notifications of the given type/sender and will receive any additional arguments passed to post_notification. - + Parameters ---------- callback : callable @@ -131,12 +131,12 @@ class NotificationCenter(object): self.registered_types.add(ntype) self.registered_senders.add(sender) self.observers.setdefault((ntype,sender), set()).add(callback) - + def remove_all_observers(self): """Removes all observers from this notification center""" - + self._init_observers() - + shared_center = NotificationCenter() diff --git a/IPython/utils/path.py b/IPython/utils/path.py index 0e5b9df..99ae75b 100644 --- a/IPython/utils/path.py +++ b/IPython/utils/path.py @@ -89,7 +89,7 @@ def get_py_filename(name, force_win32=None): If the given name is not a file, it adds '.py' and searches again. Raises IOError with an informative message if the file isn't found. - + On Windows, apply Windows semantics to the filename. In particular, remove any quoting that has been applied to it. This option can be forced for testing purposes. @@ -125,7 +125,7 @@ def filefind(filename, path_dirs=None): Will find the file in the users home directory. This function does not automatically try any paths, such as the cwd or the user's home directory. - + Parameters ---------- filename : str @@ -136,30 +136,30 @@ def filefind(filename, path_dirs=None): put into a sequence and the searched. If a sequence, walk through each element and join with ``filename``, calling :func:`expandvars` and :func:`expanduser` before testing for existence. - + Returns ------- Raises :exc:`IOError` or returns absolute path to file. """ - + # If paths are quoted, abspath gets confused, strip them... filename = filename.strip('"').strip("'") # If the input is an absolute path, just check it exists if os.path.isabs(filename) and os.path.isfile(filename): return filename - + if path_dirs is None: path_dirs = ("",) elif isinstance(path_dirs, basestring): path_dirs = (path_dirs,) - + for path in path_dirs: if path == '.': path = os.getcwdu() testname = expand_path(os.path.join(path, filename)) if os.path.isfile(testname): return os.path.abspath(testname) - - raise IOError("File %r does not exist in any of the search paths: %r" % + + raise IOError("File %r does not exist in any of the search paths: %r" % (filename, path_dirs) ) @@ -178,7 +178,7 @@ def get_home_dir(): - Registry hack for My Documents - %HOME%: rare, but some people with unix-like setups may have defined it * On Dos C:\ - + Currently only Posix and NT are implemented, a HomeDirError exception is raised for all other OSes. """ @@ -191,7 +191,7 @@ def get_home_dir(): if hasattr(sys, "frozen"): #Is frozen by py2exe if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file root, rest = IPython.__file__.lower().split('library.zip') - else: + else: root=os.path.join(os.path.split(IPython.__file__)[0],"../../") root=os.path.abspath(root).rstrip('\\') if _writable_dir(os.path.join(root, '_ipython')): @@ -208,7 +208,7 @@ def get_home_dir(): # still knows it - reported once as: # https://github.com/ipython/ipython/issues/154 from subprocess import Popen, PIPE - homedir = Popen('echo $HOME', shell=True, + homedir = Popen('echo $HOME', shell=True, stdout=PIPE).communicate()[0].strip() if homedir: return py3compat.cast_unicode(homedir, fs_encoding) @@ -221,7 +221,7 @@ def get_home_dir(): # For some strange reason all of these return 'nt' for os.name. # First look for a network home directory. This will return the UNC # path (\\server\\Users\%username%) not the mapped path (Z:\). This - # is needed when running IPython on cluster where all paths have to + # is needed when running IPython on cluster where all paths have to # be UNC. try: homedir = env['HOMESHARE'] @@ -284,36 +284,36 @@ def get_home_dir(): def get_xdg_dir(): """Return the XDG_CONFIG_HOME, if it is defined and exists, else None. - + This is only for posix (Linux,Unix,OS X, etc) systems. """ env = os.environ - + if os.name == 'posix': # Linux, Unix, AIX, OS X # use ~/.config if not set OR empty xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config') if xdg and _writable_dir(xdg): return py3compat.cast_unicode(xdg, fs_encoding) - + return None - + def get_ipython_dir(): """Get the IPython directory for this platform and user. - + This uses the logic in `get_home_dir` to find the home directory and then adds .ipython to the end of the path. """ - + env = os.environ pjoin = os.path.join - - + + ipdir_def = '.ipython' xdg_def = 'ipython' - + home_dir = get_home_dir() xdg_dir = get_xdg_dir() # import pdb; pdb.set_trace() # dbg @@ -324,18 +324,18 @@ def get_ipython_dir(): if xdg_dir: # use XDG, as long as the user isn't already # using $HOME/.ipython and *not* XDG/ipython - + xdg_ipdir = pjoin(xdg_dir, xdg_def) - + if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir): ipdir = xdg_ipdir - + if ipdir is None: # not using XDG ipdir = home_ipdir ipdir = os.path.normpath(os.path.expanduser(ipdir)) - + if os.path.exists(ipdir) and not _writable_dir(ipdir): # ipdir exists, but is not writable warn.warn("IPython dir '%s' is not a writable location," @@ -377,7 +377,7 @@ def expand_path(s): """Expand $VARS and ~names in a string, like a shell :Examples: - + In [2]: os.environ['FOO']='test' In [3]: expand_path('variable FOO is $FOO') @@ -464,7 +464,7 @@ def check_for_old_config(ipython_dir=None): else: warn.warn("Found old IPython config file %r (modified by user)"%f) warned = True - + if warned: warn.info(""" The IPython configuration system has changed as of 0.11, and these files will diff --git a/IPython/utils/pickleshare.py b/IPython/utils/pickleshare.py index c2ca26a..1afcb50 100755 --- a/IPython/utils/pickleshare.py +++ b/IPython/utils/pickleshare.py @@ -2,16 +2,16 @@ """ PickleShare - a small 'shelve' like datastore with concurrency support -Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike -shelve, many processes can access the database simultaneously. Changing a -value in database is immediately visible to other processes accessing the +Like shelve, a PickleShareDB object acts like a normal dictionary. Unlike +shelve, many processes can access the database simultaneously. Changing a +value in database is immediately visible to other processes accessing the same database. Concurrency is possible because the values are stored in separate files. Hence the "database" is a directory where *all* files are governed by PickleShare. Example usage:: - + from pickleshare import * db = PickleShareDB('~/testpickleshare') db.clear() @@ -22,8 +22,8 @@ Example usage:: print db.keys() del db['aku ankka'] -This module is certainly not ZODB, but can be used for low-load -(non-mission-critical) situations where tiny code size trumps the +This module is certainly not ZODB, but can be used for low-load +(non-mission-critical) situations where tiny code size trumps the advanced features of a "real" object database. Installation guide: easy_install pickleshare @@ -53,7 +53,7 @@ class PickleShareDB(collections.MutableMapping): self.root.makedirs() # cache has { 'key' : (obj, orig_mod_time) } self.cache = {} - + def __getitem__(self,key): """ db['key'] reading """ @@ -70,10 +70,10 @@ class PickleShareDB(collections.MutableMapping): obj = pickle.load(fil.open()) except: raise KeyError(key) - + self.cache[fil] = (obj,mtime) return obj - + def __setitem__(self,key,value): """ db['key'] = 5 """ fil = self.root / key @@ -86,7 +86,7 @@ class PickleShareDB(collections.MutableMapping): except OSError,e: if e.errno != 2: raise - + def hset(self, hashroot, key, value): """ hashed set """ hroot = self.root / hashroot @@ -95,27 +95,27 @@ class PickleShareDB(collections.MutableMapping): hfile = hroot / gethashfile(key) d = self.get(hfile, {}) d.update( {key : value}) - self[hfile] = d + self[hfile] = d + + - - def hget(self, hashroot, key, default = _sentinel, fast_only = True): """ hashed get """ hroot = self.root / hashroot hfile = hroot / gethashfile(key) - + d = self.get(hfile, _sentinel ) #print "got dict",d,"from",hfile if d is _sentinel: if fast_only: if default is _sentinel: raise KeyError(key) - + return default - + # slow mode ok, works even after hcompress() d = self.hdict(hashroot) - + return d.get(key, default) def hdict(self, hashroot): @@ -126,9 +126,9 @@ class PickleShareDB(collections.MutableMapping): if last.endswith('xx'): # print "using xx" hfiles = [last] + hfiles[:-1] - + all = {} - + for f in hfiles: # print "using",f try: @@ -136,17 +136,17 @@ class PickleShareDB(collections.MutableMapping): except KeyError: print "Corrupt",f,"deleted - hset is not threadsafe!" del self[f] - + self.uncache(f) - + return all - + def hcompress(self, hashroot): """ Compress category 'hashroot', so hset is fast again - + hget will fail if fast_only is True for compressed items (that were hset before hcompress). - + """ hfiles = self.keys(hashroot + "/*") all = {} @@ -154,16 +154,16 @@ class PickleShareDB(collections.MutableMapping): # print "using",f all.update(self[f]) self.uncache(f) - + self[hashroot + '/xx'] = all for f in hfiles: p = self.root / f if p.basename() == 'xx': continue p.remove() - - - + + + def __delitem__(self,key): """ del db["key"] """ fil = self.root / key @@ -174,53 +174,53 @@ class PickleShareDB(collections.MutableMapping): # notfound and permission denied are ok - we # lost, the other process wins the conflict pass - + def _normalized(self, p): """ Make a key suitable for user's eyes """ return str(self.root.relpathto(p)).replace('\\','/') - + def keys(self, globpat = None): """ All keys in DB, or all keys matching a glob""" - + if globpat is None: files = self.root.walkfiles() else: files = [Path(p) for p in glob.glob(self.root/globpat)] return [self._normalized(p) for p in files if p.isfile()] - + def __iter__(self): return iter(keys) - + def __len__(self): return len(keys) def uncache(self,*items): """ Removes all, or specified items from cache - + Use this after reading a large amount of large objects to free up memory, when you won't be needing the objects for a while. - + """ if not items: self.cache = {} for it in items: self.cache.pop(it,None) - + def waitget(self,key, maxwaittime = 60 ): """ Wait (poll) for a key to get a value - + Will wait for `maxwaittime` seconds before raising a KeyError. The call exits normally if the `key` field in db gets a value within the timeout period. - + Use this for synchronizing different processes or for ensuring - that an unfortunately timed "db['key'] = newvalue" operation - in another process (which causes all 'get' operation to cause a - KeyError for the duration of pickling) won't screw up your program - logic. + that an unfortunately timed "db['key'] = newvalue" operation + in another process (which causes all 'get' operation to cause a + KeyError for the duration of pickling) won't screw up your program + logic. """ - + wtimes = [0.2] * 3 + [0.5] * 2 + [1] tries = 0 waited = 0 @@ -230,24 +230,24 @@ class PickleShareDB(collections.MutableMapping): return val except KeyError: pass - + if waited > maxwaittime: raise KeyError(key) - + time.sleep(wtimes[tries]) waited+=wtimes[tries] if tries < len(wtimes) -1: tries+=1 - + def getlink(self,folder): """ Get a convenient link for accessing items """ return PickleShareLink(self, folder) - + def __repr__(self): return "PickleShareDB('%s')" % self.root - - - + + + class PickleShareLink: """ A shortdand for accessing nested PickleShare data conveniently. @@ -256,11 +256,11 @@ class PickleShareLink: lnk = db.getlink('myobjects/test') lnk.foo = 2 lnk.bar = lnk.foo + 5 - + """ - def __init__(self, db, keydir ): + def __init__(self, db, keydir ): self.__dict__.update(locals()) - + def __getattr__(self,key): return self.__dict__['db'][self.__dict__['keydir']+'/' + key] def __setattr__(self,key,val): @@ -271,8 +271,8 @@ class PickleShareLink: return "" % ( self.__dict__['keydir'], ";".join([Path(k).basename() for k in keys])) - - + + def test(): db = PickleShareDB('~/testpickleshare') db.clear() @@ -308,22 +308,22 @@ def stress(): if j%33 == 0: time.sleep(0.02) - + db[str(j)] = db.get(str(j), []) + [(i,j,"proc %d" % os.getpid())] db.hset('hash',j, db.hget('hash',j,15) + 1 ) - + print i, sys.stdout.flush() if i % 10 == 0: db.uncache() - + def main(): import textwrap usage = textwrap.dedent("""\ - pickleshare - manage PickleShare databases - + pickleshare - manage PickleShare databases + Usage: - + pickleshare dump /path/to/db > dump.txt pickleshare load /path/to/db < dump.txt pickleshare test /path/to/db @@ -333,7 +333,7 @@ def main(): if len(sys.argv) < 2: print usage return - + cmd = sys.argv[1] args = sys.argv[2:] if cmd == 'dump': @@ -355,8 +355,8 @@ def main(): elif cmd == 'test': test() stress() - + if __name__== "__main__": main() - - + + diff --git a/IPython/utils/pickleutil.py b/IPython/utils/pickleutil.py index 881496a..d081351 100644 --- a/IPython/utils/pickleutil.py +++ b/IPython/utils/pickleutil.py @@ -32,8 +32,8 @@ class CannedObject(object): self.obj = copy.copy(obj) for key in keys: setattr(self.obj, key, can(getattr(obj, key))) - - + + def getObject(self, g=None): if g is None: g = globals() @@ -47,10 +47,10 @@ class Reference(CannedObject): if not isinstance(name, basestring): raise TypeError("illegal name: %r"%name) self.name = name - + def __repr__(self): return ""%self.name - + def getObject(self, g=None): if g is None: g = globals() @@ -58,20 +58,20 @@ class Reference(CannedObject): return g[self.name] except KeyError: raise NameError("name %r is not defined"%self.name) - + class CannedFunction(CannedObject): - + def __init__(self, f): - self._checkType(f) + self._checkType(f) self.code = f.func_code self.defaults = f.func_defaults self.module = f.__module__ or '__main__' self.__name__ = f.__name__ - + def _checkType(self, obj): assert isinstance(obj, FunctionType), "Not a function type" - + def getObject(self, g=None): # try to load function back into its module: if not self.module.startswith('__'): @@ -81,7 +81,7 @@ class CannedFunction(CannedObject): pass else: g = sys.modules[self.module].__dict__ - + if g is None: g = globals() newFunc = FunctionType(self.code, g, self.__name__, self.defaults) diff --git a/IPython/utils/process.py b/IPython/utils/process.py index f317e34..abc58bc 100644 --- a/IPython/utils/process.py +++ b/IPython/utils/process.py @@ -40,7 +40,7 @@ class FindCmdError(Exception): def find_cmd(cmd): """Find absolute path to executable cmd in a cross platform manner. - + This function tries to determine the full path to a command line program using `which` on Unix/Linux/OS X and `win32api` on Windows. Most of the time it will use the version that is first on the users `PATH`. If @@ -49,7 +49,7 @@ def find_cmd(cmd): Warning, don't use this to find IPython command line programs as there is a risk you will find the wrong one. Instead find those using the following code and looking for the application itself:: - + from IPython.utils.path import get_ipython_module_path from IPython.utils.process import pycmd2argv argv = pycmd2argv(get_ipython_module_path('IPython.frontend.terminal.ipapp')) @@ -79,7 +79,7 @@ def pycmd2argv(cmd): sure the right version is used. For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe, - .com or .bat, and [, cmd] otherwise. + .com or .bat, and [, cmd] otherwise. Parameters ---------- @@ -97,7 +97,7 @@ def pycmd2argv(cmd): if sys.platform == 'win32': # The -u option here turns on unbuffered output, which is required # on Win32 to prevent wierd conflict and problems with Twisted. - # Also, use sys.executable to make sure we are picking up the + # Also, use sys.executable to make sure we are picking up the # right python exe. return [sys.executable, '-u', cmd] else: diff --git a/IPython/utils/strdispatch.py b/IPython/utils/strdispatch.py index c03c282..03709c0 100644 --- a/IPython/utils/strdispatch.py +++ b/IPython/utils/strdispatch.py @@ -20,21 +20,21 @@ class StrDispatch(object): >>> print list(dis.flat_matches('hei')) [123, 34, 686] """ - + def __init__(self): self.strs = {} self.regexs = {} def add_s(self, s, obj, priority= 0 ): """ Adds a target 'string' for dispatching """ - + chain = self.strs.get(s, CommandChainDispatcher()) chain.add(obj,priority) self.strs[s] = chain def add_re(self, regex, obj, priority= 0 ): """ Adds a target regexp for dispatching """ - + chain = self.regexs.get(regex, CommandChainDispatcher()) chain.add(obj,priority) self.regexs[regex] = chain @@ -43,23 +43,23 @@ class StrDispatch(object): """ Get a seq of Commandchain objects that match key """ if key in self.strs: yield self.strs[key] - + for r, obj in self.regexs.items(): if re.match(r, key): yield obj - else: + else: #print "nomatch",key # dbg pass def __repr__(self): return "" % (self.strs, self.regexs) - + def s_matches(self, key): if key not in self.strs: return for el in self.strs[key]: yield el[1] - + def flat_matches(self, key): """ Yield all 'value' targets, without priority """ for val in self.dispatch(key): diff --git a/IPython/utils/tests/test_notification.py b/IPython/utils/tests/test_notification.py index 76d3c2f..df9070f 100644 --- a/IPython/utils/tests/test_notification.py +++ b/IPython/utils/tests/test_notification.py @@ -24,7 +24,7 @@ from IPython.utils.notification import shared_center class Observer(object): - def __init__(self, expected_ntype, expected_sender, + def __init__(self, expected_ntype, expected_sender, center=shared_center, *args, **kwargs): super(Observer, self).__init__() self.expected_ntype = expected_ntype @@ -32,10 +32,10 @@ class Observer(object): self.expected_args = args self.expected_kwargs = kwargs self.recieved = False - center.add_observer(self.callback, - self.expected_ntype, + center.add_observer(self.callback, + self.expected_ntype, self.expected_sender) - + def callback(self, ntype, sender, *args, **kwargs): assert(ntype == self.expected_ntype or self.expected_ntype == None) @@ -44,10 +44,10 @@ class Observer(object): assert(args == self.expected_args) assert(kwargs == self.expected_kwargs) self.recieved = True - + def verify(self): assert(self.recieved) - + def reset(self): self.recieved = False @@ -74,7 +74,7 @@ class NotificationTests(unittest.TestCase): def tearDown(self): shared_center.remove_all_observers() - + def test_notification_delivered(self): """Test that notifications are delivered""" @@ -100,7 +100,7 @@ class NotificationTests(unittest.TestCase): def test_sender_specificity(self): """Test that observers are registered by sender""" - + expected_ntype = "EXPECTED_TYPE" sender1 = Notifier(expected_ntype) sender2 = Notifier(expected_ntype) @@ -117,7 +117,7 @@ class NotificationTests(unittest.TestCase): for i in xrange(10): Observer('TYPE', None, center=shared_center) - self.assert_(len(shared_center.observers[('TYPE',None)]) >= 10, + self.assert_(len(shared_center.observers[('TYPE',None)]) >= 10, "observers registered") shared_center.remove_all_observers() @@ -139,7 +139,7 @@ class NotificationTests(unittest.TestCase): def test_post_performance(self): """Test that post_notification, even with many registered irrelevant observers is fast""" - + for i in xrange(10): Observer("UNRELATED_TYPE", None) diff --git a/IPython/utils/tests/test_path.py b/IPython/utils/tests/test_path.py index 8b9b27e..c8acc8b 100644 --- a/IPython/utils/tests/test_path.py +++ b/IPython/utils/tests/test_path.py @@ -44,7 +44,7 @@ except ImportError: import _winreg as wreg #Add entries that needs to be stubbed by the testing code (wreg.OpenKey, wreg.QueryValueEx,) = (None, None) - + try: reload except NameError: # Python 3 @@ -65,7 +65,7 @@ IP_TEST_DIR = join(HOME_TEST_DIR,'.ipython') def setup(): """Setup testenvironment for the module: - + - Adds dummy home dir tree """ # Do not mask exceptions here. In particular, catching WindowsError is a @@ -76,7 +76,7 @@ def setup(): def teardown(): """Teardown testenvironment for the module: - + - Remove dummy home dir tree """ # Note: we remove the parent test dir, which is the root of all test @@ -86,10 +86,10 @@ def teardown(): def setup_environment(): - """Setup testenvironment for some functions that are tested + """Setup testenvironment for some functions that are tested in this module. In particular this functions stores attributes and other things that we need to stub in some test functions. - This needs to be done on a function level and not module level because + This needs to be done on a function level and not module level because each testfunction needs a pristine environment. """ global oldstuff, platformstuff @@ -105,7 +105,7 @@ def teardown_environment(): (oldenv, os.name, path.get_home_dir, IPython.__file__, old_wd) = oldstuff os.chdir(old_wd) reload(path) - + for key in env.keys(): if key not in oldenv: del env[key] @@ -125,10 +125,10 @@ def test_get_home_dir_1(): """Testcase for py2exe logic, un-compressed lib """ sys.frozen = True - + #fake filename for IPython.__init__ IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py")) - + home_dir = path.get_home_dir() nt.assert_equal(home_dir, abspath(HOME_TEST_DIR)) @@ -141,7 +141,7 @@ def test_get_home_dir_2(): sys.frozen = True #fake filename for IPython.__init__ IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower() - + home_dir = path.get_home_dir() nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower()) @@ -158,9 +158,9 @@ def test_get_home_dir_3(): @with_environment @skip_win32 def test_get_home_dir_4(): - """Testcase $HOME is not set, os=='posix'. + """Testcase $HOME is not set, os=='posix'. This should fail with HomeDirError""" - + os.name = 'posix' if 'HOME' in env: del env['HOME'] nt.assert_raises(path.HomeDirError, path.get_home_dir) @@ -208,13 +208,13 @@ def test_get_home_dir_7(): home_dir = path.get_home_dir() nt.assert_equal(home_dir, abspath(HOME_TEST_DIR)) - + # Should we stub wreg fully so we can run the test on all platforms? @skip_if_not_win32 @with_environment def test_get_home_dir_8(): """Using registry hack for 'My Documents', os=='nt' - + HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing. """ os.name = 'nt' @@ -333,7 +333,7 @@ def test_get_xdg_dir_1(): env.pop('IPYTHON_DIR', None) env.pop('IPYTHONDIR', None) env.pop('XDG_CONFIG_HOME', None) - + nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config')) @@ -359,7 +359,7 @@ def test_get_xdg_dir_2(): env.pop('XDG_CONFIG_HOME', None) cfgdir=os.path.join(path.get_home_dir(), '.config') os.makedirs(cfgdir) - + nt.assert_equal(path.get_xdg_dir(), cfgdir) def test_filefind(): @@ -384,7 +384,7 @@ def test_get_ipython_module_path(): @dec.skip_if_not_win32 def test_get_long_path_name_win32(): p = path.get_long_path_name('c:\\docume~1') - nt.assert_equals(p,u'c:\\Documents and Settings') + nt.assert_equals(p,u'c:\\Documents and Settings') @dec.skip_win32 diff --git a/IPython/utils/tests/test_traitlets.py b/IPython/utils/tests/test_traitlets.py index 9d25a03..d6e7d2f 100644 --- a/IPython/utils/tests/test_traitlets.py +++ b/IPython/utils/tests/test_traitlets.py @@ -75,7 +75,7 @@ class TestTraitType(TestCase): return -1 class A(HasTraitsStub): tt = MyTT - + a = A() a.tt = 10 self.assertEquals(a.tt, -1) @@ -393,7 +393,7 @@ class TestHasTraits(TestCase): traits = a.traits(config_key='VALUE1', other_thing='VALUE2') self.assertEquals(traits, dict(i=A.i)) - # This passes, but it shouldn't because I am replicating a bug in + # This passes, but it shouldn't because I am replicating a bug in # traits. traits = a.traits(config_key=lambda v: True) self.assertEquals(traits, dict(i=A.i, f=A.f, j=A.j)) @@ -432,7 +432,7 @@ class TestType(TestCase): class C(object): pass class A(HasTraits): klass = Type(B) - + a = A() self.assertEquals(a.klass, B) self.assertRaises(TraitError, setattr, a, 'klass', C) @@ -486,7 +486,7 @@ class TestType(TestCase): a = A() a.klass = Struct self.assertEquals(a.klass, Struct) - + self.assertRaises(TraitError, setattr, a, 'klass', 10) class TestInstance(TestCase): @@ -495,7 +495,7 @@ class TestInstance(TestCase): class Foo(object): pass class Bar(Foo): pass class Bah(object): pass - + class A(HasTraits): inst = Instance(Foo) @@ -547,7 +547,7 @@ class TestInstance(TestCase): class A(HasTraits): inst = Instance(Foo, allow_none=False) - + self.assertRaises(TraitError, A) def test_instance(self): @@ -556,7 +556,7 @@ class TestInstance(TestCase): def inner(): class A(HasTraits): inst = Instance(Foo()) - + self.assertRaises(TraitError, inner) @@ -576,7 +576,7 @@ class TestThis(TestCase): def test_this_inst(self): class Foo(HasTraits): this = This() - + f = Foo() f.this = Foo() self.assert_(isinstance(f.this, Foo)) @@ -696,7 +696,7 @@ class TestComplex(TraitTestBase): obj = ComplexTrait() _default_value = 99.0-99.0j - _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j, + _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j, 10.1j, 10.1+10.1j, 10.1-10.1j] _bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None] @@ -725,7 +725,7 @@ class TestUnicode(TraitTestBase): obj = UnicodeTrait() _default_value = u'unicode' - _good_values = ['10', '-10', '10L', '-10L', '10.1', + _good_values = ['10', '-10', '10L', '-10L', '10.1', '-10.1', '', u'', 'string', u'string', u"€"] _bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j, [10], ['ten'], [u'ten'], {'ten': 10},(10,), None] @@ -733,10 +733,10 @@ class TestUnicode(TraitTestBase): class ObjectNameTrait(HasTraits): value = ObjectName("abc") - + class TestObjectName(TraitTestBase): obj = ObjectNameTrait() - + _default_value = "abc" _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"] _bad_values = [1, "", u"€", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]", @@ -752,7 +752,7 @@ class DottedObjectNameTrait(HasTraits): class TestDottedObjectName(TraitTestBase): obj = DottedObjectNameTrait() - + _default_value = "a.b" _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"] _bad_values = [1, u"abc.€", "_.@", ".", ".abc", "abc.", ".abc."] diff --git a/IPython/utils/text.py b/IPython/utils/text.py index cb40f41..cfec757 100644 --- a/IPython/utils/text.py +++ b/IPython/utils/text.py @@ -39,7 +39,7 @@ from IPython.utils.data import flatten # won't need to make changes all over IPython. def getdefaultencoding(): """Return IPython's guess for the default encoding for bytes as text. - + Asks for stdin.encoding first, to match the calling Terminal, but that is often None for subprocesses. Fall back on locale.getpreferredencoding() which should be a sensible platform default (that respects LANG environment), @@ -124,8 +124,8 @@ class LSString(str): # """ Prettier (non-repr-like) and more informative printer for LSString """ # print "LSString (.p, .n, .l, .s available). Value:" # print arg -# -# +# +# # print_lsstring = result_display.when_type(LSString)(print_lsstring) @@ -283,9 +283,9 @@ class SList(list): # if hasattr(arg, 'hideonce') and arg.hideonce: # arg.hideonce = False # return -# +# # nlprint(arg) -# +# # print_slist = result_display.when_type(SList)(print_slist) @@ -421,10 +421,10 @@ def indent(instr,nspaces=4, ntabs=0, flatten=False): """Indent a string a given number of spaces or tabstops. indent(str,nspaces=4,ntabs=0) -> indent str by ntabs+nspaces. - + Parameters ---------- - + instr : basestring The string to be indented. nspaces : int (default: 4) @@ -435,12 +435,12 @@ def indent(instr,nspaces=4, ntabs=0, flatten=False): Whether to scrub existing indentation. If True, all lines will be aligned to the same indentation. If False, existing indentation will be strictly increased. - + Returns ------- - + str|unicode : string indented by ntabs and nspaces. - + """ if instr is None: return @@ -547,25 +547,25 @@ def format_screen(strng): def dedent(text): """Equivalent of textwrap.dedent that ignores unindented first line. - + This means it will still dedent strings like: '''foo is a bar ''' - + For use in wrap_paragraphs. """ - + if text.startswith('\n'): # text starts with blank line, don't ignore the first line return textwrap.dedent(text) - + # split first line splits = text.split('\n',1) if len(splits) == 1: # only one line return textwrap.dedent(text) - + first, rest = splits # dedent everything but the first line rest = textwrap.dedent(rest) @@ -573,13 +573,13 @@ def dedent(text): def wrap_paragraphs(text, ncols=80): """Wrap multiple paragraphs to fit a specified width. - + This is equivalent to textwrap.wrap, but with support for multiple paragraphs, as separated by empty lines. - + Returns ------- - + list of complete paragraphs, wrapped to fill `ncols` columns. """ paragraph_re = re.compile(r'\n(\s*\n)+', re.MULTILINE) @@ -588,42 +588,42 @@ def wrap_paragraphs(text, ncols=80): out_ps = [] indent_re = re.compile(r'\n\s+', re.MULTILINE) for p in paragraphs: - # presume indentation that survives dedent is meaningful formatting, + # presume indentation that survives dedent is meaningful formatting, # so don't fill unless text is flush. if indent_re.search(p) is None: # wrap paragraph p = textwrap.fill(p, ncols) out_ps.append(p) return out_ps - + class EvalFormatter(Formatter): """A String Formatter that allows evaluation of simple expressions. - + Any time a format key is not found in the kwargs, it will be tried as an expression in the kwargs namespace. - + This is to be used in templating cases, such as the parallel batch script templates, where simple arithmetic on arguments is useful. - + Examples -------- - + In [1]: f = EvalFormatter() In [2]: f.format('{n//4}', n=8) Out[2]: '2' - + In [3]: f.format('{list(range(3))}') Out[3]: '[0, 1, 2]' In [4]: f.format('{3*2}') Out[4]: '6' """ - + # should we allow slicing by disabling the format_spec feature? allow_slicing = True - + # copied from Formatter._vformat with minor changes to allow eval # and replace the format_spec code with slicing def _vformat(self, format_string, args, kwargs, used_args, recursion_depth): @@ -677,7 +677,7 @@ def columnize(items, separator=' ', displaywidth=80): displaywidth : int, optional [default is 80] Width of the display in number of characters. - + Returns ------- The formatted string. @@ -687,7 +687,7 @@ def columnize(items, separator=' ', displaywidth=80): # Some degenerate cases. size = len(items) - if size == 0: + if size == 0: return '\n' elif size == 1: return '%s\n' % items[0] @@ -715,9 +715,9 @@ def columnize(items, separator=' ', displaywidth=80): colwidth = max(colwidth, len_x) colwidths.append(colwidth) totwidth += colwidth + len(separator) - if totwidth > displaywidth: + if totwidth > displaywidth: break - if totwidth <= displaywidth: + if totwidth <= displaywidth: break # The smallest number of rows computed and the max widths for each diff --git a/IPython/utils/traitlets.py b/IPython/utils/traitlets.py index 4926a9f..895a675 100644 --- a/IPython/utils/traitlets.py +++ b/IPython/utils/traitlets.py @@ -58,7 +58,7 @@ try: ClassTypes = (ClassType, type) except: ClassTypes = (type,) - + from .importstring import import_item from IPython.utils import py3compat @@ -119,10 +119,10 @@ def repr_type(obj): def parse_notifier_name(name): """Convert the name argument to a list of names. - + Examples -------- - + >>> parse_notifier_name('a') ['a'] >>> parse_notifier_name(['a','b']) @@ -153,7 +153,7 @@ class _SimpleTest: def getmembers(object, predicate=None): """A safe version of inspect.getmembers that handles missing attributes. - This is useful when there are descriptor based attributes that for + This is useful when there are descriptor based attributes that for some reason raise AttributeError even though they exist. This happens in zope.inteface with the __provides__ attribute. """ @@ -192,7 +192,7 @@ class TraitType(object): This is used by the :class:`This` trait to allow subclasses to accept superclasses for :class:`This` values. """ - + metadata = {} default_value = Undefined @@ -231,7 +231,7 @@ class TraitType(object): created. This method trigger the creation and validation of default values - and also things like the resolution of str given class names in + and also things like the resolution of str given class names in :class:`Type` and :class`Instance`. Parameters @@ -246,7 +246,7 @@ class TraitType(object): """Set the default value on a per instance basis. This method is called by :meth:`instance_init` to create and - validate the default value. The creation and validation of + validate the default value. The creation and validation of default values must be delayed until the parent :class:`HasTraits` class has been instantiated. """ @@ -270,7 +270,7 @@ class TraitType(object): """Get the value of the trait by self.name for the instance. Default values are instantiated when :meth:`HasTraits.__new__` - is called. Thus by the time this method gets called either the + is called. Thus by the time this method gets called either the default value or a user defined value (they called :meth:`__set__`) is in the :class:`HasTraits` instance. """ @@ -347,14 +347,14 @@ class TraitType(object): class MetaHasTraits(type): """A metaclass for HasTraits. - + This metaclass makes sure that any TraitType class attributes are instantiated and sets their name attribute. """ - + def __new__(mcls, name, bases, classdict): """Create the HasTraits class. - + This instantiates all TraitTypes in the class dict and sets their :attr:`name` attribute. """ @@ -373,7 +373,7 @@ class MetaHasTraits(type): def __init__(cls, name, bases, classdict): """Finish initializing the HasTraits class. - + This sets the :attr:`this_class` attribute of each TraitType in the class dict to the newly created class ``cls``. """ @@ -398,7 +398,7 @@ class HasTraits(object): inst._trait_notifiers = {} inst._trait_dyn_inits = {} # Here we tell all the TraitType instances to set their default - # values on the instance. + # values on the instance. for key in dir(cls): # Some descriptors raise AttributeError like zope.interface's # __provides__ attributes even though they exist. This causes @@ -462,7 +462,7 @@ class HasTraits(object): else: raise TraitError('a trait changed callback ' 'must be callable.') - + def _add_notifiers(self, handler, name): if not self._trait_notifiers.has_key(name): @@ -487,17 +487,17 @@ class HasTraits(object): """Setup a handler to be called when a trait changes. This is used to setup dynamic notifications of trait changes. - + Static handlers can be created by creating methods on a HasTraits subclass with the naming convention '_[traitname]_changed'. Thus, to create static handler for the trait 'a', create the method _a_changed(self, name, old, new) (fewer arguments can be used, see below). - + Parameters ---------- handler : callable - A callable that is called when a trait changes. Its + A callable that is called when a trait changes. Its signature can be handler(), handler(name), handler(name, new) or handler(name, old, new). name : list, str, None @@ -651,12 +651,12 @@ class Type(ClassBasedTraitType): default_value : class, str or None The default value must be a subclass of klass. If an str, the str must be a fully specified class name, like 'foo.bar.Bah'. - The string is resolved into real class, when the parent + The string is resolved into real class, when the parent :class:`HasTraits` class is instantiated. klass : class, str, None Values of this trait must be a subclass of klass. The klass may be specified in a string like: 'foo.bar.MyClass'. - The string is resolved into real class, when the parent + The string is resolved into real class, when the parent :class:`HasTraits` class is instantiated. allow_none : boolean Indicates whether None is allowed as an assignable value. Even if @@ -725,11 +725,11 @@ class DefaultValueGenerator(object): class Instance(ClassBasedTraitType): """A trait whose value must be an instance of a specified class. - + The value can also be an instance of a subclass of the specified class. """ - def __init__(self, klass=None, args=None, kw=None, + def __init__(self, klass=None, args=None, kw=None, allow_none=True, **metadata ): """Construct an Instance trait. @@ -754,7 +754,7 @@ class Instance(ClassBasedTraitType): ------------- If both ``args`` and ``kw`` are None, then the default value is None. If ``args`` is a tuple and ``kw`` is a dict, then the default is - created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is + created as ``klass(*args, **kw)``. If either ``args`` or ``kw`` is not (but not both), None is replace by ``()`` or ``{}``. """ @@ -764,7 +764,7 @@ class Instance(ClassBasedTraitType): raise TraitError('The klass argument must be a class' ' you gave: %r' % klass) self.klass = klass - + # self.klass is a class, so handle default_value if args is None and kw is None: default_value = None @@ -775,12 +775,12 @@ class Instance(ClassBasedTraitType): elif kw is None: # args is not None kw = {} - + if not isinstance(kw, dict): raise TraitError("The 'kw' argument must be a dict or None.") if not isinstance(args, tuple): raise TraitError("The 'args' argument must be a tuple or None.") - + default_value = DefaultValueGenerator(*args, **kw) super(Instance, self).__init__(default_value, **metadata) @@ -817,7 +817,7 @@ class Instance(ClassBasedTraitType): def get_default_value(self): """Instantiate a default value instance. - + This is called when the containing HasTraits classes' :meth:`__new__` method is called to ensure that a unique instance is created for each HasTraits instance. @@ -833,7 +833,7 @@ class This(ClassBasedTraitType): """A trait for instances of the class containing this trait. Because how how and when class bodies are executed, the ``This`` - trait can only have a default value of None. This, and because we + trait can only have a default value of None. This, and because we always validate default values, ``allow_none`` is *always* true. """ @@ -1002,18 +1002,18 @@ class CUnicode(Unicode): return unicode(value) except: self.error(obj, value) - - + + class ObjectName(TraitType): """A string holding a valid object name in this version of Python. - + This does not check that the name exists in any scope.""" info_text = "a valid object identifier in Python" if py3compat.PY3: # Python 3: coerce_str = staticmethod(lambda _,s: s) - + else: # Python 2: def coerce_str(self, obj, value): @@ -1024,10 +1024,10 @@ class ObjectName(TraitType): except UnicodeEncodeError: self.error(obj, value) return value - + def validate(self, obj, value): value = self.coerce_str(obj, value) - + if isinstance(value, str) and py3compat.isidentifier(value): return value self.error(obj, value) @@ -1036,7 +1036,7 @@ class DottedObjectName(ObjectName): """A string holding a valid dotted object name in Python, such as A.b3._c""" def validate(self, obj, value): value = self.coerce_str(obj, value) - + if isinstance(value, str) and py3compat.isidentifier(value, dotted=True): return value self.error(obj, value) @@ -1360,7 +1360,7 @@ class Dict(Instance): def __init__(self, default_value=None, allow_none=True, **metadata): """Create a dict trait type from a dict. - The default value is created by doing ``dict(default_value)``, + The default value is created by doing ``dict(default_value)``, which creates a copy of the ``default_value``. """ if default_value is None: @@ -1372,7 +1372,7 @@ class Dict(Instance): else: raise TypeError('default value of Dict was %s' % default_value) - super(Dict,self).__init__(klass=dict, args=args, + super(Dict,self).__init__(klass=dict, args=args, allow_none=allow_none, **metadata) class TCPAddress(TraitType): diff --git a/IPython/utils/wildcard.py b/IPython/utils/wildcard.py index e0fd9b4..d86628a 100644 --- a/IPython/utils/wildcard.py +++ b/IPython/utils/wildcard.py @@ -24,7 +24,7 @@ def create_typestr2type_dicts(dont_include_in_type2typestr=["lambda"]): objects from the types package, and vice versa.""" typenamelist = [tname for tname in dir(types) if tname.endswith("Type")] typestr2type, type2typestr = {}, {} - + for tname in typenamelist: name = tname[:-4].lower() # Cut 'Type' off the end of the name obj = getattr(types, tname) @@ -36,10 +36,10 @@ def create_typestr2type_dicts(dont_include_in_type2typestr=["lambda"]): typestr2type, type2typestr = create_typestr2type_dicts() def is_type(obj, typestr_or_type): - """is_type(obj, typestr_or_type) verifies if obj is of a certain type. It + """is_type(obj, typestr_or_type) verifies if obj is of a certain type. It can take strings or actual python types for the second argument, i.e. 'tuple'<->TupleType. 'all' matches all types. - + TODO: Should be extended for choosing more than one type.""" if typestr_or_type == "all": return True @@ -71,7 +71,7 @@ def dict_dir(obj): except AttributeError: pass return ns - + def filter_ns(ns, name_pattern="*", type_pattern="all", ignore_case=True, show_all=True): """Filter a namespace dictionary by name pattern and item type.""" @@ -80,7 +80,7 @@ def filter_ns(ns, name_pattern="*", type_pattern="all", ignore_case=True, reg = re.compile(pattern+"$", re.I) else: reg = re.compile(pattern+"$") - + # Check each one matches regex; shouldn't be hidden; of correct type. return dict((key,obj) for key, obj in ns.iteritems() if reg.match(key) \ and show_hidden(key, show_all) \ @@ -103,7 +103,7 @@ def list_namespace(namespace, type_pattern, filter, ignore_case=False, show_all= ignore_case=ignore_case, show_all=show_all) results = {} for name, obj in filtered.iteritems(): - ns = list_namespace(dict_dir(obj), type_pattern, + ns = list_namespace(dict_dir(obj), type_pattern, ".".join(pattern_list[1:]), ignore_case=ignore_case, show_all=show_all) for inner_name, inner_obj in ns.iteritems(): diff --git a/IPython/zmq/entry_point.py b/IPython/zmq/entry_point.py index dcb3f70..6ca4615 100644 --- a/IPython/zmq/entry_point.py +++ b/IPython/zmq/entry_point.py @@ -44,7 +44,7 @@ def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0 executable : str, optional (default sys.executable) The Python executable to use for the kernel process. - independent : bool, optional (default False) + independent : bool, optional (default False) If set, the kernel process is guaranteed to survive if this process dies. If not set, an effort is made to ensure that the kernel is killed when this process dies. Note that in this case it is still good practice @@ -104,11 +104,11 @@ def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0 # If this process in running on pythonw, we know that stdin, stdout, and # stderr are all invalid. redirect_out = sys.executable.endswith('pythonw.exe') - if redirect_out: + if redirect_out: _stdout = PIPE if stdout is None else stdout _stderr = PIPE if stderr is None else stderr else: - _stdout, _stderr = stdout, stderr + _stdout, _stderr = stdout, stderr # Spawn a kernel. if sys.platform == 'win32': @@ -130,14 +130,14 @@ def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0 # Launch the kernel process. if independent: - proc = Popen(arguments, + proc = Popen(arguments, creationflags=512, # CREATE_NEW_PROCESS_GROUP stdin=_stdin, stdout=_stdout, stderr=_stderr) else: from _subprocess import DuplicateHandle, GetCurrentProcess, \ DUPLICATE_SAME_ACCESS pid = GetCurrentProcess() - handle = DuplicateHandle(pid, pid, pid, 0, + handle = DuplicateHandle(pid, pid, pid, 0, True, # Inheritable by new processes. DUPLICATE_SAME_ACCESS) proc = Popen(arguments + ['--parent=%i'%int(handle)], @@ -163,5 +163,5 @@ def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0 proc.stdout.close() if stderr is None: proc.stderr.close() - + return proc, shell_port, iopub_port, stdin_port, hb_port diff --git a/IPython/zmq/frontend.py b/IPython/zmq/frontend.py index 671f27d..8b97639 100755 --- a/IPython/zmq/frontend.py +++ b/IPython/zmq/frontend.py @@ -69,14 +69,14 @@ class Console(code.InteractiveConsole): def print_pyerr(self, err): print >> sys.stderr, err.etype,':', err.evalue - print >> sys.stderr, ''.join(err.traceback) + print >> sys.stderr, ''.join(err.traceback) def handle_pyerr(self, omsg): if omsg.parent_header.session == self.session.session: return print >> sys.stderr, '[ERR from %s]' % omsg.parent_header.username self.print_pyerr(omsg.content) - + def handle_stream(self, omsg): if omsg.content.name == 'stdout': outstream = sys.stdout @@ -104,7 +104,7 @@ class Console(code.InteractiveConsole): if rep is None: return if rep.content.status == 'error': - self.print_pyerr(rep.content) + self.print_pyerr(rep.content) elif rep.content.status == 'aborted': print >> sys.stderr, "ERROR: ABORTED" ab = self.messages[rep.parent_header.msg_id].content @@ -137,7 +137,7 @@ class Console(code.InteractiveConsole): omsg = self.session.send(self.request_socket, 'execute_request', dict(code=src)) self.messages[omsg.header.msg_id] = omsg - + # Fake asynchronicity by letting the user put ';' at the end of the line if src.endswith(';'): self.backgrounded += 1 @@ -162,7 +162,7 @@ class InteractiveClient(object): self.sub_socket = sub_socket self.console = Console(None, '', session, request_socket, sub_socket) - + def interact(self): self.console.interact() @@ -176,12 +176,12 @@ def main(): connection = ('tcp://%s' % ip) + ':%i' req_conn = connection % port_base sub_conn = connection % (port_base+1) - + # Create initial sockets c = zmq.Context() request_socket = c.socket(zmq.DEALER) request_socket.connect(req_conn) - + sub_socket = c.socket(zmq.SUB) sub_socket.connect(sub_conn) sub_socket.setsockopt(zmq.SUBSCRIBE, '') diff --git a/IPython/zmq/ipkernel.py b/IPython/zmq/ipkernel.py index 0df9093..f3289c6 100755 --- a/IPython/zmq/ipkernel.py +++ b/IPython/zmq/ipkernel.py @@ -111,7 +111,7 @@ class Kernel(Configurable): self.shell._reply_content = None # Build dict of handlers for message types - msg_types = [ 'execute_request', 'complete_request', + msg_types = [ 'execute_request', 'complete_request', 'object_info_request', 'history_request', 'connect_request', 'shutdown_request'] self.handlers = {} @@ -135,7 +135,7 @@ class Kernel(Configurable): # We now require 2.0.8 or above, so we can uncomment for safety. # print(ident,msg, file=sys.__stdout__) assert ident is not None, "Missing message part." - + # Print some info about this message and leave a '--->' marker, so it's # easier to trace visually the message chain when debugging. Each # handler prints its message at the end. @@ -148,7 +148,7 @@ class Kernel(Configurable): self.log.error("UNKNOWN MESSAGE TYPE:" +str(msg)) else: handler(ident, msg) - + # Check whether we should exit, in case the incoming message set the # exit flag on if self.shell.exit_now: @@ -169,7 +169,7 @@ class Kernel(Configurable): # reason for this to be anything less than ~ 0.1s # since it is a real poller and will respond # to events immediately - + # double nested try/except, to properly catch KeyboardInterrupt # due to pyzmq Issue #130 try: @@ -199,17 +199,17 @@ class Kernel(Configurable): pyin_msg = self.session.send(self.iopub_socket, u'pyin',{u'code':code}, parent=parent) def execute_request(self, ident, parent): - + status_msg = self.session.send(self.iopub_socket, u'status', {u'execution_state':u'busy'}, parent=parent ) - + try: content = parent[u'content'] code = content[u'code'] - silent = content[u'silent'] + silent = content[u'silent'] except: self.log.error("Got bad msg: ") self.log.error(str(Message(parent))) @@ -217,7 +217,7 @@ class Kernel(Configurable): shell = self.shell # we'll need this a lot here - # Replace raw_input. Note that is not sufficient to replace + # Replace raw_input. Note that is not sufficient to replace # raw_input in the user namespace. raw_input = lambda prompt='': self._raw_input(prompt, ident, parent) if py3compat.PY3: @@ -261,7 +261,7 @@ class Kernel(Configurable): status = u'ok' reply_content[u'status'] = status - + # Return the execution counter so clients can display prompts reply_content['execution_count'] = shell.execution_count -1 @@ -301,7 +301,7 @@ class Kernel(Configurable): # to better understand what's going on. if self._execute_sleep: time.sleep(self._execute_sleep) - + # Send the reply. reply_content = json_clean(reply_content) reply_msg = self.session.send(self.shell_socket, u'execute_reply', @@ -345,18 +345,18 @@ class Kernel(Configurable): n = parent['content']['n'] hist = self.shell.history_manager.get_tail(n, raw=raw, output=output, include_latest=True) - + elif hist_access_type == 'range': session = parent['content']['session'] start = parent['content']['start'] stop = parent['content']['stop'] hist = self.shell.history_manager.get_range(session, start, stop, raw=raw, output=output) - + elif hist_access_type == 'search': pattern = parent['content']['pattern'] hist = self.shell.history_manager.search(pattern, raw=raw, output=output) - + else: hist = [] content = {'history' : list(hist)} @@ -430,7 +430,7 @@ class Kernel(Configurable): self.log.error(str(Message(parent))) value = '' return value - + def _complete(self, msg): c = msg['content'] try: @@ -562,11 +562,11 @@ class TkKernel(Kernel): self.app = Tkinter.Tk() self.app.withdraw() self.func = func - + def on_timer(self): self.func() self.app.after(poll_interval, self.on_timer) - + def start(self): self.on_timer() # Call it once to get things going. self.app.mainloop() @@ -577,11 +577,11 @@ class TkKernel(Kernel): class GTKKernel(Kernel): """A Kernel subclass with GTK support.""" - + def start(self): """Start the kernel, coordinating with the GTK event loop""" from .gui.gtkembed import GTKEmbed - + gtk_kernel = GTKEmbed(self) gtk_kernel.start() @@ -666,7 +666,7 @@ class IPKernelApp(KernelApp, InteractiveShellApp): import_all = self.pylab_import_all pylabtools.import_pylab(kernel.shell.user_ns, backend, import_all, shell=kernel.shell) - + def init_shell(self): self.shell = self.kernel.shell diff --git a/IPython/zmq/kernelmanager.py b/IPython/zmq/kernelmanager.py index 841a1b9..3b9325e 100644 --- a/IPython/zmq/kernelmanager.py +++ b/IPython/zmq/kernelmanager.py @@ -122,12 +122,12 @@ class ZMQSocketChannel(Thread): raise else: break - + def stop(self): """Stop the channel's activity. This calls :method:`Thread.join` and returns when the thread - terminates. :class:`RuntimeError` will be raised if + terminates. :class:`RuntimeError` will be raised if :method:`self.start` is called again. """ self.join() @@ -135,7 +135,7 @@ class ZMQSocketChannel(Thread): @property def address(self): """Get the channel's address as an (ip, port) tuple. - + By the default, the address is (localhost, 0), where 0 means a random port. """ @@ -191,7 +191,7 @@ class ShellSocketChannel(ZMQSocketChannel): self.socket.setsockopt(zmq.IDENTITY, self.session.bsession) self.socket.connect('tcp://%s:%i' % self.address) self.iostate = POLLERR|POLLIN - self.ioloop.add_handler(self.socket, self._handle_events, + self.ioloop.add_handler(self.socket, self._handle_events, self.iostate) self._run_loop() @@ -217,7 +217,7 @@ class ShellSocketChannel(ZMQSocketChannel): ---------- code : str A string of Python code. - + silent : bool, optional (default False) If set, the kernel will execute the code as quietly possible. @@ -225,7 +225,7 @@ class ShellSocketChannel(ZMQSocketChannel): A list of variable names to pull from the user's namespace. They will come back as a dict with these names as keys and their :func:`repr` as values. - + user_expressions : dict, optional A dict with string keys and to pull from the user's namespace. They will come back as a dict with these names as keys @@ -239,7 +239,7 @@ class ShellSocketChannel(ZMQSocketChannel): user_variables = [] if user_expressions is None: user_expressions = {} - + # Don't waste network traffic if inputs are invalid if not isinstance(code, basestring): raise ValueError('code %r must be a string' % code) @@ -263,7 +263,7 @@ class ShellSocketChannel(ZMQSocketChannel): text : str The text to complete. line : str - The full line of text that is the surrounding context for the + The full line of text that is the surrounding context for the text to complete. cursor_pos : int The position of the cursor in the line where the completion was @@ -287,7 +287,7 @@ class ShellSocketChannel(ZMQSocketChannel): ---------- oname : str A string specifying the object name. - + Returns ------- The msg_id of the message sent. @@ -309,7 +309,7 @@ class ShellSocketChannel(ZMQSocketChannel): hist_access_type : str 'range' (fill in session, start and stop params), 'tail' (fill in n) or 'search' (fill in pattern param). - + session : int For a range request, the session from which to get lines. Session numbers are positive integers; negative ones count back from the @@ -318,10 +318,10 @@ class ShellSocketChannel(ZMQSocketChannel): The first line number of a history range. stop : int The final (excluded) line number of a history range. - + n : int The number of lines of history to get for a tail request. - + pattern : str The glob-syntax pattern for a search request. @@ -398,7 +398,7 @@ class SubSocketChannel(ZMQSocketChannel): self.socket.setsockopt(zmq.IDENTITY, self.session.bsession) self.socket.connect('tcp://%s:%i' % self.address) self.iostate = POLLIN|POLLERR - self.ioloop.add_handler(self.socket, self._handle_events, + self.ioloop.add_handler(self.socket, self._handle_events, self.iostate) self._run_loop() @@ -486,7 +486,7 @@ class StdInSocketChannel(ZMQSocketChannel): self.socket.setsockopt(zmq.IDENTITY, self.session.bsession) self.socket.connect('tcp://%s:%i' % self.address) self.iostate = POLLERR|POLLIN - self.ioloop.add_handler(self.socket, self._handle_events, + self.ioloop.add_handler(self.socket, self._handle_events, self.iostate) self._run_loop() @@ -616,7 +616,7 @@ class HBSocketChannel(ZMQSocketChannel): raise else: break - + since_last_heartbeat = time.time()-request_time if since_last_heartbeat > self.time_to_dead: self.call_handlers(since_last_heartbeat) @@ -671,15 +671,15 @@ class KernelManager(HasTraits): The SUB channel is for the frontend to receive messages published by the kernel. - + The REQ channel is for the frontend to make requests of the kernel. - + The REP channel is for the kernel to request stdin (raw_input) from the frontend. """ # config object for passing to child configurables config = Instance(Config) - + # The PyZMQ Context to use for communication with the kernel. context = Instance(zmq.Context) def _context_default(self): @@ -691,7 +691,7 @@ class KernelManager(HasTraits): # The kernel process with which the KernelManager is communicating. kernel = Instance(Popen) - # The addresses for the communication channels. + # The addresses for the communication channels. shell_address = TCPAddress((LOCALHOST, 0)) sub_address = TCPAddress((LOCALHOST, 0)) stdin_address = TCPAddress((LOCALHOST, 0)) @@ -788,7 +788,7 @@ class KernelManager(HasTraits): "configured properly. " "Currently valid addresses are: %s"%LOCAL_IPS ) - + self._launch_args = kw.copy() launch_kernel = kw.pop('launcher', None) if launch_kernel is None: @@ -830,10 +830,10 @@ class KernelManager(HasTraits): # OK, we've waited long enough. if self.has_kernel: self.kill_kernel() - + def restart_kernel(self, now=False, **kw): """Restarts a kernel with the arguments that were used to launch it. - + If the old kernel was launched with random ports, the same ports will be used for the new kernel. @@ -977,7 +977,7 @@ class KernelManager(HasTraits): """Get the heartbeat socket channel object to check that the kernel is alive.""" if self._hb_channel is None: - self._hb_channel = self.hb_channel_class(self.context, + self._hb_channel = self.hb_channel_class(self.context, self.session, self.hb_address) return self._hb_channel diff --git a/IPython/zmq/parentpoller.py b/IPython/zmq/parentpoller.py index a718add..bdbaf7b 100644 --- a/IPython/zmq/parentpoller.py +++ b/IPython/zmq/parentpoller.py @@ -10,14 +10,14 @@ from IPython.utils.warn import warn class ParentPollerUnix(Thread): - """ A Unix-specific daemon thread that terminates the program immediately + """ A Unix-specific daemon thread that terminates the program immediately when the parent process no longer exists. """ def __init__(self): super(ParentPollerUnix, self).__init__() self.daemon = True - + def run(self): # We cannot use os.waitpid because it works only for child processes. from errno import EINTR @@ -37,7 +37,7 @@ class ParentPollerWindows(Thread): signals an interrupt and, optionally, terminates the program immediately when the parent process no longer exists. """ - + def __init__(self, interrupt_handle=None, parent_handle=None): """ Create the poller. At least one of the optional parameters must be provided. @@ -49,7 +49,7 @@ class ParentPollerWindows(Thread): handle is signaled. parent_handle : HANDLE (int), optional - If provided, the program will terminate immediately when this + If provided, the program will terminate immediately when this handle is signaled. """ assert(interrupt_handle or parent_handle) @@ -71,8 +71,8 @@ class ParentPollerWindows(Thread): # handle by new processes. # FIXME: We can clean up this mess by requiring pywin32 for IPython. class SECURITY_ATTRIBUTES(ctypes.Structure): - _fields_ = [ ("nLength", ctypes.c_int), - ("lpSecurityDescriptor", ctypes.c_void_p), + _fields_ = [ ("nLength", ctypes.c_int), + ("lpSecurityDescriptor", ctypes.c_void_p), ("bInheritHandle", ctypes.c_int) ] sa = SECURITY_ATTRIBUTES() sa_p = ctypes.pointer(sa) diff --git a/IPython/zmq/pykernel.py b/IPython/zmq/pykernel.py index 27f96d3..625318a 100755 --- a/IPython/zmq/pykernel.py +++ b/IPython/zmq/pykernel.py @@ -71,7 +71,7 @@ class Kernel(HasTraits): self.completer = KernelCompleter(self.user_ns) # Build dict of handlers for message types - msg_types = [ 'execute_request', 'complete_request', + msg_types = [ 'execute_request', 'complete_request', 'object_info_request', 'shutdown_request' ] self.handlers = {} for msg_type in msg_types: @@ -114,7 +114,7 @@ class Kernel(HasTraits): try: comp_code = self.compiler(code, '') - # Replace raw_input. Note that is not sufficient to replace + # Replace raw_input. Note that is not sufficient to replace # raw_input in the user namespace. raw_input = lambda prompt='': self._raw_input(prompt, ident, parent) if py3compat.PY3: @@ -141,7 +141,7 @@ class Kernel(HasTraits): reply_content = exc_content else: reply_content = { 'status' : 'ok', 'payload' : {} } - + # Flush output before sending the reply. sys.stderr.flush() sys.stdout.flush() @@ -259,7 +259,7 @@ class Kernel(HasTraits): def launch_kernel(*args, **kwargs): """ Launches a simple Python kernel, binding to the specified ports. - + This function simply calls entry_point.base_launch_kernel with the right first command to start a pykernel. See base_launch_kernel for arguments. diff --git a/IPython/zmq/session.py b/IPython/zmq/session.py index 4636f91..54a6c00 100644 --- a/IPython/zmq/session.py +++ b/IPython/zmq/session.py @@ -92,36 +92,36 @@ class SessionFactory(LoggingConfigurable): """The Base class for configurables that have a Session, Context, logger, and IOLoop. """ - + logname = Unicode('') def _logname_changed(self, name, old, new): self.log = logging.getLogger(new) - + # not configurable: context = Instance('zmq.Context') def _context_default(self): return zmq.Context.instance() - + session = Instance('IPython.zmq.session.Session') - + loop = Instance('zmq.eventloop.ioloop.IOLoop', allow_none=False) def _loop_default(self): return IOLoop.instance() - + def __init__(self, **kwargs): super(SessionFactory, self).__init__(**kwargs) - + if self.session is None: # construct the session self.session = Session(**kwargs) - + class Message(object): """A simple message object that maps dict keys to attributes. A Message can be created from a dict and a dict from a Message instance simply by calling dict(msg_obj).""" - + def __init__(self, msg_dict): dct = self.__dict__ for k, v in dict(msg_dict).iteritems(): @@ -132,7 +132,7 @@ class Message(object): # Having this iterator lets dict(msg_obj) work out of the box. def __iter__(self): return iter(self.__dict__.iteritems()) - + def __repr__(self): return repr(self.__dict__) @@ -171,28 +171,28 @@ def extract_header(msg_or_header): class Session(Configurable): """Object for handling serialization and sending of messages. - + The Session object handles building messages and sending them with ZMQ sockets or ZMQStream objects. Objects can communicate with each other over the network via Session objects, and only need to work with the - dict-based IPython message spec. The Session will handle + dict-based IPython message spec. The Session will handle serialization/deserialization, security, and metadata. - + Sessions support configurable serialiization via packer/unpacker traits, and signing with HMAC digests via the key/keyfile traits. - + Parameters ---------- - + debug : bool whether to trigger extra debugging statements packer/unpacker : str : 'json', 'pickle' or import_string importstrings for methods to serialize message parts. If just 'json' or 'pickle', predefined JSON and pickle packers will be used. Otherwise, the entire importstring must be used. - + The functions must accept at least valid JSON input, and output *bytes*. - + For example, to use msgpack: packer = 'msgpack.packb', unpacker='msgpack.unpackb' pack/unpack : callables @@ -207,11 +207,11 @@ class Session(Configurable): keyfile : filepath The file containing a key. If this is set, `key` will be initialized to the contents of the file. - + """ - + debug=Bool(False, config=True, help="""Debug output in the Session""") - + packer = DottedObjectName('json',config=True, help="""The name of the packer for serializing messages. Should be one of 'json', 'pickle', or an import name @@ -238,23 +238,23 @@ class Session(Configurable): self.unpack = pickle_unpacker else: self.unpack = import_item(str(new)) - + session = CUnicode(u'', config=True, help="""The UUID identifying this session.""") def _session_default(self): u = unicode(uuid.uuid4()) self.bsession = u.encode('ascii') return u - + def _session_changed(self, name, old, new): self.bsession = self.session.encode('ascii') - + # bsession is the session as bytes bsession = CBytes(b'') - + username = Unicode(os.environ.get('USER',u'username'), config=True, help="""Username for the Session. Default is your system username.""") - + # message signature related traits: key = CBytes(b'', config=True, help="""execution key, for extra authentication.""") @@ -265,7 +265,7 @@ class Session(Configurable): self.auth = None auth = Instance(hmac.HMAC) digest_history = Set() - + keyfile = Unicode('', config=True, help="""path to file containing execution key.""") def _keyfile_changed(self, name, old, new): @@ -276,16 +276,16 @@ class Session(Configurable): def _pack_changed(self, name, old, new): if not callable(new): raise TypeError("packer must be callable, not %s"%type(new)) - + unpack = Any(default_unpacker) # the actual packer function def _unpack_changed(self, name, old, new): - # unpacker is not checked - it is assumed to be + # unpacker is not checked - it is assumed to be if not callable(new): raise TypeError("unpacker must be callable, not %s"%type(new)) def __init__(self, **kwargs): """create a Session object - + Parameters ---------- @@ -305,7 +305,7 @@ class Session(Configurable): You can also set the pack/unpack callables for serialization directly. session : unicode (must be ascii) - the ID of this Session object. The default is to generate a new + the ID of this Session object. The default is to generate a new UUID. bsession : bytes The session as bytes @@ -315,7 +315,7 @@ class Session(Configurable): The key used to initialize an HMAC signature. If unset, messages will not be signed or checked. keyfile : filepath - The file containing a key. If this is set, `key` will be + The file containing a key. If this is set, `key` will be initialized to the contents of the file. """ super(Session, self).__init__(**kwargs) @@ -333,24 +333,24 @@ class Session(Configurable): """check packers for binary data and datetime support.""" pack = self.pack unpack = self.unpack - + # check simple serialization msg = dict(a=[1,'hi']) try: packed = pack(msg) except Exception: raise ValueError("packer could not serialize a simple message") - + # ensure packed message is bytes if not isinstance(packed, bytes): raise ValueError("message packed to %r, but bytes are required"%type(packed)) - + # check that unpack is pack's inverse try: unpacked = unpack(packed) except Exception: raise ValueError("unpacker could not handle the packer's output") - + # check datetime support msg = dict(t=datetime.now()) try: @@ -358,7 +358,7 @@ class Session(Configurable): except Exception: self.pack = lambda o: pack(squash_dates(o)) self.unpack = lambda s: extract_dates(unpack(s)) - + def msg_header(self, msg_type): return msg_header(self.msg_id, msg_type, self.username, self.session) @@ -386,7 +386,7 @@ class Session(Configurable): Parameters ---------- msg_list : list - The [p_header,p_parent,p_content] part of the message list. + The [p_header,p_parent,p_content] part of the message list. """ if self.auth is None: return b'' @@ -394,7 +394,7 @@ class Session(Configurable): for m in msg_list: h.update(m) return str_to_bytes(h.hexdigest()) - + def serialize(self, msg, ident=None): """Serialize the message components to bytes. @@ -429,12 +429,12 @@ class Session(Configurable): content = content.encode('utf8') else: raise TypeError("Content incorrect type: %s"%type(content)) - - real_message = [self.pack(msg['header']), - self.pack(msg['parent_header']), + + real_message = [self.pack(msg['header']), + self.pack(msg['parent_header']), content ] - + to_send = [] if isinstance(ident, list): @@ -443,14 +443,14 @@ class Session(Configurable): elif ident is not None: to_send.append(ident) to_send.append(DELIM) - + signature = self.sign(real_message) to_send.append(signature) - + to_send.extend(real_message) return to_send - + def send(self, stream, msg_or_type, content=None, parent=None, ident=None, buffers=None, subheader=None, track=False, header=None): """Build and send a message via stream or socket. @@ -458,21 +458,21 @@ class Session(Configurable): The message format used by this function internally is as follows: [ident1,ident2,...,DELIM,HMAC,p_header,p_parent,p_content, - buffer1,buffer2,...] + buffer1,buffer2,...] The serialize/unserialize methods convert the nested message dict into this format. Parameters ---------- - + stream : zmq.Socket or ZMQStream The socket-like object used to send the data. msg_or_type : str or Message/dict - Normally, msg_or_type will be a msg_type unless a message is being + Normally, msg_or_type will be a msg_type unless a message is being sent more than once. If a header is supplied, this can be set to None and the msg_type will be pulled from the header. - + content : dict or None The content of the message (ignored if msg_or_type is a message). header : dict or None @@ -490,29 +490,29 @@ class Session(Configurable): track : bool Whether to track. Only for use with Sockets, because ZMQStream objects cannot track messages. - + Returns ------- msg : dict The constructed message. (msg,tracker) : (dict, MessageTracker) - if track=True, then a 2-tuple will be returned, + if track=True, then a 2-tuple will be returned, the first element being the constructed message, and the second being the MessageTracker - + """ if not isinstance(stream, (zmq.Socket, ZMQStream)): raise TypeError("stream must be Socket or ZMQStream, not %r"%type(stream)) elif track and isinstance(stream, ZMQStream): raise TypeError("ZMQStream cannot track messages") - + if isinstance(msg_or_type, (Message, dict)): # We got a Message or message dict, not a msg_type so don't # build a new Message. msg = msg_or_type else: - msg = self.msg(msg_or_type, content=content, parent=parent, + msg = self.msg(msg_or_type, content=content, parent=parent, subheader=subheader, header=header) buffers = [] if buffers is None else buffers @@ -540,9 +540,9 @@ class Session(Configurable): pprint.pprint(msg) pprint.pprint(to_send) pprint.pprint(buffers) - + msg['tracker'] = tracker - + return msg def send_raw(self, stream, msg_list, flags=0, copy=True, ident=None): @@ -571,7 +571,7 @@ class Session(Configurable): to_send.append(self.sign(msg_list)) to_send.extend(msg_list) stream.send_multipart(msg_list, flags, copy=copy) - + def recv(self, socket, mode=zmq.NOBLOCK, content=True, copy=True): """Receive and unpack a message. @@ -605,21 +605,21 @@ class Session(Configurable): except Exception as e: # TODO: handle it raise e - + def feed_identities(self, msg_list, copy=True): """Split the identities from the rest of the message. Feed until DELIM is reached, then return the prefix as idents and remainder as msg_list. This is easily broken by setting an IDENT to DELIM, but that would be silly. - + Parameters ---------- msg_list : a list of Message or bytes objects The message to be split. copy : bool flag determining whether the arguments are bytes or Messages - + Returns ------- (idents, msg_list) : two lists @@ -642,7 +642,7 @@ class Session(Configurable): raise ValueError("DELIM not in msg_list") idents, msg_list = msg_list[:idx], msg_list[idx+1:] return [m.bytes for m in idents], msg_list - + def unserialize(self, msg_list, content=True, copy=True): """Unserialize a msg_list to a nested message dict. @@ -694,7 +694,7 @@ class Session(Configurable): message['content'] = self.unpack(msg_list[3]) else: message['content'] = msg_list[3] - + message['buffers'] = msg_list[4:] return message @@ -706,10 +706,10 @@ def test_msg2obj(): am['y'] = dict(z=1) ao = Message(am) assert ao.y.z == am['y']['z'] - + k1, k2 = 'y', 'z' assert ao[k1][k2] == am[k1][k2] - + am2 = dict(ao) assert am['x'] == am2['x'] assert am['y']['z'] == am2['y']['z'] diff --git a/IPython/zmq/tests/test_session.py b/IPython/zmq/tests/test_session.py index b2b522c..5b010ae 100644 --- a/IPython/zmq/tests/test_session.py +++ b/IPython/zmq/tests/test_session.py @@ -21,7 +21,7 @@ from zmq.eventloop.zmqstream import ZMQStream from IPython.zmq import session as ss class SessionTestCase(BaseZMQTestCase): - + def setUp(self): BaseZMQTestCase.setUp(self) self.session = ss.Session() @@ -43,7 +43,7 @@ class MockSocket(zmq.Socket): return self.data class TestSession(SessionTestCase): - + def test_msg(self): """message format""" msg = self.session.msg('execute') @@ -82,7 +82,7 @@ class TestSession(SessionTestCase): self.assertEquals(new_msg['msg_type'],msg['msg_type']) self.assertEquals(new_msg['header'],msg['header']) self.assertEquals(new_msg['content'],msg['content']) - self.assertEquals(new_msg['parent_header'],msg['parent_header']) + self.assertEquals(new_msg['parent_header'],msg['parent_header']) self.assertEquals(new_msg['buffers'],[b'bar']) socket.data = [] @@ -100,7 +100,7 @@ class TestSession(SessionTestCase): self.assertEquals(new_msg['msg_type'],msg['msg_type']) self.assertEquals(new_msg['header'],msg['header']) self.assertEquals(new_msg['content'],msg['content']) - self.assertEquals(new_msg['parent_header'],msg['parent_header']) + self.assertEquals(new_msg['parent_header'],msg['parent_header']) self.assertEquals(new_msg['buffers'],[b'bar']) socket.data = [] @@ -112,7 +112,7 @@ class TestSession(SessionTestCase): self.assertEquals(new_msg['msg_type'],msg['msg_type']) self.assertEquals(new_msg['header'],msg['header']) self.assertEquals(new_msg['content'],msg['content']) - self.assertEquals(new_msg['parent_header'],msg['parent_header']) + self.assertEquals(new_msg['parent_header'],msg['parent_header']) self.assertEquals(new_msg['buffers'],[b'bar']) socket.close() @@ -123,17 +123,17 @@ class TestSession(SessionTestCase): self.assertTrue(s.pack is ss.default_packer) self.assertTrue(s.unpack is ss.default_unpacker) self.assertEquals(s.username, os.environ.get('USER', u'username')) - + s = ss.Session() self.assertEquals(s.username, os.environ.get('USER', u'username')) - + self.assertRaises(TypeError, ss.Session, pack='hi') self.assertRaises(TypeError, ss.Session, unpack='hi') u = str(uuid.uuid4()) s = ss.Session(username=u'carrot', session=u) self.assertEquals(s.session, u) self.assertEquals(s.username, u'carrot') - + def test_tracking(self): """test tracking messages""" a,b = self.create_bound_pair(zmq.PAIR, zmq.PAIR) @@ -150,26 +150,26 @@ class TestSession(SessionTestCase): self.assertRaises(zmq.NotDone, t.wait, .1) del M t.wait(1) # this will raise - - + + # def test_rekey(self): # """rekeying dict around json str keys""" # d = {'0': uuid.uuid4(), 0:uuid.uuid4()} # self.assertRaises(KeyError, ss.rekey, d) - # + # # d = {'0': uuid.uuid4(), 1:uuid.uuid4(), 'asdf':uuid.uuid4()} # d2 = {0:d['0'],1:d[1],'asdf':d['asdf']} # rd = ss.rekey(d) # self.assertEquals(d2,rd) - # + # # d = {'1.5':uuid.uuid4(),'1':uuid.uuid4()} # d2 = {1.5:d['1.5'],1:d['1']} # rd = ss.rekey(d) # self.assertEquals(d2,rd) - # + # # d = {'1.0':uuid.uuid4(),'1':uuid.uuid4()} # self.assertRaises(KeyError, ss.rekey, d) - # + # def test_unique_msg_ids(self): """test that messages receive unique ids""" ids = set() @@ -178,14 +178,14 @@ class TestSession(SessionTestCase): msg_id = h['msg_id'] self.assertTrue(msg_id not in ids) ids.add(msg_id) - + def test_feed_identities(self): """scrub the front for zmq IDENTITIES""" theids = "engine client other".split() content = dict(code='whoda',stuff=object()) themsg = self.session.msg('execute',content=content) pmsg = theids - + def test_session_id(self): session = ss.Session() # get bs before us @@ -206,5 +206,5 @@ class TestSession(SessionTestCase): # get us before bs self.assertEquals(session.bsession, session.session.encode('ascii')) self.assertEquals(b'stuff', session.bsession) - + diff --git a/IPython/zmq/zmqshell.py b/IPython/zmq/zmqshell.py index 7cb11d3..8b287ca 100644 --- a/IPython/zmq/zmqshell.py +++ b/IPython/zmq/zmqshell.py @@ -80,7 +80,7 @@ class ZMQInteractiveShell(InteractiveShell): displayhook_class = Type(ZMQShellDisplayHook) display_pub_class = Type(ZMQDisplayPublisher) - + # Override the traitlet in the parent class, because there's no point using # readline for the kernel. Can be removed when the readline code is moved # to the terminal frontend. @@ -89,7 +89,7 @@ class ZMQInteractiveShell(InteractiveShell): # autoindent has no meaning in a zmqshell, and attempting to enable it # will print a warning in the absence of readline. autoindent = CBool(False) - + exiter = Instance(ZMQExitAutocall) def _exiter_default(self): return ZMQExitAutocall(self) @@ -122,7 +122,7 @@ class ZMQInteractiveShell(InteractiveShell): transformed_input=new, ) self.payload_manager.write_payload(payload) - + def ask_exit(self): """Engage the exit actions.""" payload = dict( @@ -153,7 +153,7 @@ class ZMQInteractiveShell(InteractiveShell): exc_content[u'status'] = u'error' self._reply_content = exc_content # /FIXME - + return exc_content #------------------------------------------------------------------------ @@ -205,7 +205,7 @@ class ZMQInteractiveShell(InteractiveShell): save_dstore('rc_pprint', ptformatter.pprint) save_dstore('rc_plain_text_only',disp_formatter.plain_text_only) save_dstore('xmode', shell.InteractiveTB.mode) - + if mode == False: # turn on ptformatter.pprint = False @@ -221,7 +221,7 @@ class ZMQInteractiveShell(InteractiveShell): dstore.mode = bool(1-int(mode)) mode_label = ['OFF','ON'][dstore.mode] print('Doctest mode is:', mode_label) - + # Send the payload back so that clients can modify their prompt display payload = dict( source='IPython.zmq.zmqshell.ZMQInteractiveShell.magic_doctest_mode', @@ -240,7 +240,7 @@ class ZMQInteractiveShell(InteractiveShell): This command allows you to conveniently edit multi-line code right in your IPython session. - + If called without arguments, %edit opens up an empty editor with a temporary file and will execute the contents of this file when you close it (don't forget to save it!). @@ -253,7 +253,7 @@ class ZMQInteractiveShell(InteractiveShell): you can configure this by providing your own modified hook if your favorite editor supports line-number specifications with a different syntax. - + -p: this will call the editor with the same data as the previous time it was used, regardless of how long ago (in your current session) it was. @@ -264,7 +264,7 @@ class ZMQInteractiveShell(InteractiveShell): this option is given, the raw input as typed as the command line is used instead. When you exit the editor, it will be executed by IPython's own processor. - + -x: do not execute the edited code immediately upon exit. This is mainly useful if you are editing programs which need to be called with command line arguments, which you can then do using %run. @@ -319,18 +319,18 @@ class ZMQInteractiveShell(InteractiveShell): Out[1]: 'def foo():n print "foo() was defined in an editing session"n' We can then call the function foo(): - + In [2]: foo() foo() was defined in an editing session Now we edit foo. IPython automatically loads the editor with the (temporary) file where foo() was previously defined: - + In [3]: ed foo Editing... done. Executing edited code... And if we call foo() again we get the modified version: - + In [4]: foo() foo() has now been changed! @@ -356,9 +356,9 @@ class ZMQInteractiveShell(InteractiveShell): hello again Out[7]: "print 'hello again'n" """ - + opts,args = self.parse_options(parameter_s,'prn:') - + try: filename, lineno, _ = self._find_edit_target(args, opts, last_call) except MacroToEdit as e: @@ -400,7 +400,7 @@ class ZMQInteractiveShell(InteractiveShell): magic_cls = magic_clear # Terminal pagers won't work over pexpect, but we do have our own pager - + def magic_less(self, arg_s): """Show a file through the pager. @@ -427,12 +427,12 @@ class ZMQInteractiveShell(InteractiveShell): """Show a basic reference about the GUI console.""" from IPython.core.usage import gui_reference page.page(gui_reference, auto_html=True) - + def set_next_input(self, text): """Send the specified text to the frontend to be presented at the next input cell.""" payload = dict( - source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input', + source='IPython.zmq.zmqshell.ZMQInteractiveShell.set_next_input', text=text ) self.payload_manager.write_payload(payload) diff --git a/docs/examples/lib/gui-wx.py b/docs/examples/lib/gui-wx.py index 3956e69..c55ce4f 100755 --- a/docs/examples/lib/gui-wx.py +++ b/docs/examples/lib/gui-wx.py @@ -14,7 +14,7 @@ In [6]: %run gui-wx.py Ref: Modified from wxPython source code wxPython/samples/simple/simple.py -This example can only be run once in a given IPython session because when +This example can only be run once in a given IPython session because when the frame is closed, wx goes through its shutdown sequence, killing further attempts. I am sure someone who knows wx can fix this issue. @@ -42,7 +42,7 @@ class MyFrame(wx.Frame): # Create the menubar menuBar = wx.MenuBar() - # and a menu + # and a menu menu = wx.Menu() # add an item to the menu, using \tKeyName automatically diff --git a/docs/examples/newparallel/fetchparse.py b/docs/examples/newparallel/fetchparse.py index 0d2d162..aca8707 100644 --- a/docs/examples/newparallel/fetchparse.py +++ b/docs/examples/newparallel/fetchparse.py @@ -4,7 +4,7 @@ Ken Kinder Updated for newparallel by Min Ragan-Kelley -This module gives an example of how the task interface to the +This module gives an example of how the task interface to the IPython controller works. Before running this script start the IPython controller and some engines using something like:: @@ -34,42 +34,42 @@ def fetchAndParse(url, data=None): return links class DistributedSpider(object): - + # Time to wait between polling for task results. pollingDelay = 0.5 - + def __init__(self, site): self.client = Client() self.view = self.client.load_balanced_view() self.mux = self.client[:] - + self.allLinks = [] self.linksWorking = {} self.linksDone = {} - + self.site = site - + def visitLink(self, url): if url not in self.allLinks: self.allLinks.append(url) if url.startswith(self.site): print ' ', url self.linksWorking[url] = self.view.apply(fetchAndParse, url) - + def onVisitDone(self, links, url): print url, ':' self.linksDone[url] = None del self.linksWorking[url] for link in links: self.visitLink(link) - + def run(self): self.visitLink(self.site) while self.linksWorking: print len(self.linksWorking), 'pending...' self.synchronize() time.sleep(self.pollingDelay) - + def synchronize(self): for url, ar in self.linksWorking.items(): # Calling get_task_result with block=False will return None if the diff --git a/docs/examples/newparallel/multiengine1.py b/docs/examples/newparallel/multiengine1.py index 746a1d1..1e5926e 100644 --- a/docs/examples/newparallel/multiengine1.py +++ b/docs/examples/newparallel/multiengine1.py @@ -196,7 +196,7 @@ except error.CompositeError: try: ar.r except error.CompositeError: - print "Caught ZeroDivisionError OK." + print "Caught ZeroDivisionError OK." # push/pull diff --git a/docs/examples/newparallel/options/mcpricer.py b/docs/examples/newparallel/options/mcpricer.py index 8b089a4..4f2e751 100644 --- a/docs/examples/newparallel/options/mcpricer.py +++ b/docs/examples/newparallel/options/mcpricer.py @@ -50,7 +50,7 @@ c = Client(profile=cluster_profile) # -# A LoadBalancedView is an interface to the engines that provides dynamic load +# A LoadBalancedView is an interface to the engines that provides dynamic load # balancing at the expense of not knowing which engine will execute the code. # @@ -115,7 +115,7 @@ prices = np.empty(n_strikes*n_sigmas, for i, price in enumerate(results): prices[i] = tuple(price) - + prices.shape = (n_strikes, n_sigmas) strike_mesh, sigma_mesh = np.meshgrid(strike_vals, sigma_vals) diff --git a/docs/examples/newparallel/pi/parallelpi.py b/docs/examples/newparallel/pi/parallelpi.py index dbdc770..9a3b6b4 100644 --- a/docs/examples/newparallel/pi/parallelpi.py +++ b/docs/examples/newparallel/pi/parallelpi.py @@ -12,9 +12,9 @@ variable below. The dataset we have been using for this is the 200 million digit one here: ftp://pi.super-computing.org/.2/pi200m/ -and the files used will be downloaded if they are not in the working directory +and the files used will be downloaded if they are not in the working directory of the IPython engines. -""" +""" from IPython.parallel import Client from matplotlib import pyplot as plt diff --git a/docs/examples/newparallel/pi/pidigits.py b/docs/examples/newparallel/pi/pidigits.py index 6c58ae9..9057c88 100644 --- a/docs/examples/newparallel/pi/pidigits.py +++ b/docs/examples/newparallel/pi/pidigits.py @@ -1,7 +1,7 @@ """Compute statistics on the digits of pi. This uses precomputed digits of pi from the website -of Professor Yasumasa Kanada at the University of +of Professor Yasumasa Kanada at the University of Tokoyo: http://www.super-computing.org/ Currently, there are only functions to read the @@ -70,7 +70,7 @@ def compute_n_digit_freqs(filename, n): return freqs # Read digits from a txt file - + def txt_file_to_digits(filename, the_type=str): """ Yield the digits of pi read from a .txt file. @@ -81,7 +81,7 @@ def txt_file_to_digits(filename, the_type=str): if c != '\n' and c!= ' ': yield the_type(c) -# Actual counting functions +# Actual counting functions def one_digit_freqs(digits, normalize=False): """ @@ -93,7 +93,7 @@ def one_digit_freqs(digits, normalize=False): if normalize: freqs = freqs/freqs.sum() return freqs - + def two_digit_freqs(digits, normalize=False): """ Consume digits of pi and compute 2 digits freq. counts. diff --git a/docs/examples/newparallel/plotting/plotting_backend.py b/docs/examples/newparallel/plotting/plotting_backend.py index 2dcfca4..3e2050e 100644 --- a/docs/examples/newparallel/plotting/plotting_backend.py +++ b/docs/examples/newparallel/plotting/plotting_backend.py @@ -2,15 +2,15 @@ The two files plotting_frontend.py and plotting_backend.py go together. -This file (plotting_backend.py) performs the actual computation. For this +This file (plotting_backend.py) performs the actual computation. For this example, the computation just generates a set of random numbers that -look like a distribution of particles with 2D position (x,y) and +look like a distribution of particles with 2D position (x,y) and momentum (px,py). In a real situation, this file would do some time consuming and complicated calculation, and could possibly make calls to MPI. One important feature is that this script can also be run standalone without -IPython. This is nice as it allows it to be run in more traditional +IPython. This is nice as it allows it to be run in more traditional settings where IPython isn't being used. When used with IPython.parallel, this code is run on the engines. Because this diff --git a/docs/examples/newparallel/rmt/rmt.py b/docs/examples/newparallel/rmt/rmt.py index a3292aa..1f4c5fe 100644 --- a/docs/examples/newparallel/rmt/rmt.py +++ b/docs/examples/newparallel/rmt/rmt.py @@ -6,7 +6,7 @@ # -# The eigenvalues of random matrices obey certain statistical laws. Here we construct random matrices +# The eigenvalues of random matrices obey certain statistical laws. Here we construct random matrices # from the Gaussian Orthogonal Ensemble (GOE), find their eigenvalues and then investigate the nearest # neighbor eigenvalue distribution $\rho(s)$. @@ -24,7 +24,7 @@ from IPython.parallel import Client # The Wigner distribution gives the theoretical result for the nearest neighbor eigenvalue distribution # for the GOE: -# +# # $$\rho(s) = \frac{\pi s}{2} \exp(-\pi s^2/4)$$ # diff --git a/docs/examples/newparallel/task_profiler.py b/docs/examples/newparallel/task_profiler.py index c88c4ef..10e807d 100644 --- a/docs/examples/newparallel/task_profiler.py +++ b/docs/examples/newparallel/task_profiler.py @@ -3,7 +3,7 @@ This script submits a set of tasks via a LoadBalancedView. The tasks are basically just a time.sleep(t), where t is a random number between -two limits that can be configured at the command line. To run +two limits that can be configured at the command line. To run the script there must first be an IPython controller and engines running:: ipclusterz start -n 16 @@ -12,7 +12,7 @@ A good test to run with 16 engines is:: python task_profiler.py -n 128 -t 0.01 -T 1.0 -This should show a speedup of 13-14x. The limitation here is that the +This should show a speedup of 13-14x. The limitation here is that the overhead of a single task is about 0.001-0.01 seconds. """ import random, sys @@ -27,19 +27,19 @@ def main(): parser.set_defaults(tmin=1e-3) parser.set_defaults(tmax=1) parser.set_defaults(profile='default') - + parser.add_option("-n", type='int', dest='n', help='the number of tasks to run') - parser.add_option("-t", type='float', dest='tmin', + parser.add_option("-t", type='float', dest='tmin', help='the minimum task length in seconds') parser.add_option("-T", type='float', dest='tmax', help='the maximum task length in seconds') parser.add_option("-p", '--profile', type='str', dest='profile', help="the cluster profile [default: 'default']") - + (opts, args) = parser.parse_args() assert opts.tmax >= opts.tmin, "tmax must not be smaller than tmin" - + rc = Client() view = rc.load_balanced_view() print view @@ -51,7 +51,7 @@ def main(): # the jobs should take a random time within a range times = [random.random()*(opts.tmax-opts.tmin)+opts.tmin for i in range(opts.n)] stime = sum(times) - + print "executing %i tasks, totalling %.1f secs on %i engines"%(opts.n, stime, nengines) time.sleep(1) start = time.time() @@ -61,7 +61,7 @@ def main(): ptime = stop-start scale = stime/ptime - + print "executed %.1f secs in %.1f secs"%(stime, ptime) print "%.3fx parallel performance on %i engines"%(scale, nengines) print "%.1f%% of theoretical max"%(100*scale/nengines) diff --git a/docs/examples/newparallel/wave2D/parallelwave-mpi.py b/docs/examples/newparallel/wave2D/parallelwave-mpi.py index f747217..b3114b8 100755 --- a/docs/examples/newparallel/wave2D/parallelwave-mpi.py +++ b/docs/examples/newparallel/wave2D/parallelwave-mpi.py @@ -11,7 +11,7 @@ An example of running the program is (8 processors, 4x2 partition, $ ipclusterz start --profile mpi -n 8 # start 8 engines (assuming mpi profile has been configured) $ ./parallelwave-mpi.py --grid 400 100 --partition 4 2 --profile mpi -See also parallelwave-mpi, which runs the same program, but uses MPI +See also parallelwave-mpi, which runs the same program, but uses MPI (via mpi4py) for the inter-engine communication. Authors @@ -50,11 +50,11 @@ def wave_saver(u, x, y, t): global t_hist t_hist.append(t) u_hist.append(1.0*u) - + # main program: if __name__ == '__main__': - + parser = argparse.ArgumentParser() paa = parser.add_argument paa('--grid', '-g', @@ -75,16 +75,16 @@ if __name__ == '__main__': paa('-t', '--tstop', type=float, default=1., help="Time units to run") - paa('--profile', + paa('--profile', type=unicode, default=u'default', help="Specify the ipcluster profile for the client to connect to.") - paa('--save', + paa('--save', action='store_true', help="Add this flag to save the time/wave history during the run.") - paa('--scalar', + paa('--scalar', action='store_true', help="Also run with scalar interior implementation, to see vector speedup.") - + ns = parser.parse_args() # set up arguments grid = ns.grid @@ -97,22 +97,22 @@ if __name__ == '__main__': user_action = wave_saver else: user_action = None - + num_cells = 1.0*(grid[0]-1)*(grid[1]-1) final_test = True - + # create the Client rc = Client(profile=ns.profile) num_procs = len(rc.ids) - + if partition is None: partition = [1,num_procs] - + assert partition[0]*partition[1] == num_procs, "can't map partition %s to %i engines"%(partition, num_procs) - + view = rc[:] print "Running %s system on %s processes until %f"%(grid, partition, tstop) - + # functions defining initial/boundary/source conditions def I(x,y): from numpy import exp @@ -123,28 +123,28 @@ if __name__ == '__main__': # return 10*exp(-(x - sin(100*t))**2) def bc(x,y,t): return 0.0 - + # initial imports, setup rank view.execute('\n'.join([ "from mpi4py import MPI", "import numpy", "mpi = MPI.COMM_WORLD", "my_id = MPI.COMM_WORLD.Get_rank()"]), block=True) - + # initialize t_hist/u_hist for saving the state at each step (optional) view['t_hist'] = [] view['u_hist'] = [] - + # set vector/scalar implementation details impl = {} impl['ic'] = 'vectorized' impl['inner'] = 'scalar' impl['bc'] = 'vectorized' - + # execute some files so that the classes we need will be defined on the engines: view.run('RectPartitioner.py') view.run('wavesolver.py') - + # setup remote partitioner # note that Reference means that the argument passed to setup_partitioner will be the # object named 'my_id' in the engine's namespace @@ -156,7 +156,7 @@ if __name__ == '__main__': # lambda for calling solver.solve: _solve = lambda *args, **kwargs: solver.solve(*args, **kwargs) - + if ns.scalar: impl['inner'] = 'scalar' # run first with element-wise Python operations for each cell @@ -171,12 +171,12 @@ if __name__ == '__main__': norm = -1 t1 = time.time() print 'scalar inner-version, Wtime=%g, norm=%g'%(t1-t0, norm) - + impl['inner'] = 'vectorized' # setup new solvers view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl) view.execute('mpi.barrier()') - + # run again with numpy vectorized inner-implementation t0 = time.time() ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test)#, user_action=wave_saver) @@ -189,7 +189,7 @@ if __name__ == '__main__': norm = -1 t1 = time.time() print 'vector inner-version, Wtime=%g, norm=%g'%(t1-t0, norm) - + # if ns.save is True, then u_hist stores the history of u as a list # If the partion scheme is Nx1, then u can be reconstructed via 'gather': if ns.save and partition[-1] == 1: diff --git a/docs/examples/newparallel/wave2D/parallelwave.py b/docs/examples/newparallel/wave2D/parallelwave.py index af2f15c..cb3e055 100755 --- a/docs/examples/newparallel/wave2D/parallelwave.py +++ b/docs/examples/newparallel/wave2D/parallelwave.py @@ -11,7 +11,7 @@ An example of running the program is (8 processors, 4x2 partition, $ ipclusterz start -n 8 # start 8 engines $ ./parallelwave.py --grid 200 200 --partition 4 2 -See also parallelwave-mpi, which runs the same program, but uses MPI +See also parallelwave-mpi, which runs the same program, but uses MPI (via mpi4py) for the inter-engine communication. Authors @@ -50,11 +50,11 @@ def wave_saver(u, x, y, t): global t_hist t_hist.append(t) u_hist.append(1.0*u) - + # main program: if __name__ == '__main__': - + parser = argparse.ArgumentParser() paa = parser.add_argument paa('--grid', '-g', @@ -75,16 +75,16 @@ if __name__ == '__main__': paa('-t', '--tstop', type=float, default=1., help="Time units to run") - paa('--profile', + paa('--profile', type=unicode, default=u'default', help="Specify the ipcluster profile for the client to connect to.") - paa('--save', + paa('--save', action='store_true', help="Add this flag to save the time/wave history during the run.") - paa('--scalar', + paa('--scalar', action='store_true', help="Also run with scalar interior implementation, to see vector speedup.") - + ns = parser.parse_args() # set up arguments grid = ns.grid @@ -97,25 +97,25 @@ if __name__ == '__main__': user_action = wave_saver else: user_action = None - + num_cells = 1.0*(grid[0]-1)*(grid[1]-1) final_test = True - + # create the Client rc = Client(profile=ns.profile) num_procs = len(rc.ids) - + if partition is None: partition = [num_procs,1] else: num_procs = min(num_procs, partition[0]*partition[1]) - + assert partition[0]*partition[1] == num_procs, "can't map partition %s to %i engines"%(partition, num_procs) - + # construct the View: view = rc[:num_procs] print "Running %s system on %s processes until %f"%(grid, partition, tstop) - + # functions defining initial/boundary/source conditions def I(x,y): from numpy import exp @@ -126,7 +126,7 @@ if __name__ == '__main__': # return 10*exp(-(x - sin(100*t))**2) def bc(x,y,t): return 0.0 - + # initialize t_hist/u_hist for saving the state at each step (optional) view['t_hist'] = [] view['u_hist'] = [] @@ -136,16 +136,16 @@ if __name__ == '__main__': impl['ic'] = 'vectorized' impl['inner'] = 'scalar' impl['bc'] = 'vectorized' - + # execute some files so that the classes we need will be defined on the engines: view.execute('import numpy') view.run('communicator.py') view.run('RectPartitioner.py') view.run('wavesolver.py') - + # scatter engine IDs view.scatter('my_id', range(num_procs), flatten=True) - + # create the engine connectors view.execute('com = EngineCommunicator()') @@ -154,7 +154,7 @@ if __name__ == '__main__': peers = ar.get_dict() # print peers # this is a dict, keyed by engine ID, of the connection info for the EngineCommunicators - + # setup remote partitioner # note that Reference means that the argument passed to setup_partitioner will be the # object named 'com' in the engine's namespace @@ -180,14 +180,14 @@ if __name__ == '__main__': norm = -1 t1 = time.time() print 'scalar inner-version, Wtime=%g, norm=%g'%(t1-t0, norm) - + # run again with faster numpy-vectorized inner implementation: impl['inner'] = 'vectorized' # setup remote solvers view.apply_sync(setup_solver, I,f,c,bc,Lx,Ly,partitioner=Reference('partitioner'), dt=0,implementation=impl) t0 = time.time() - + ar = view.apply_async(_solve, tstop, dt=0, verbose=True, final_test=final_test)#, user_action=wave_saver) if final_test: # this sum is performed element-wise as results finish @@ -198,7 +198,7 @@ if __name__ == '__main__': norm = -1 t1 = time.time() print 'vector inner-version, Wtime=%g, norm=%g'%(t1-t0, norm) - + # if ns.save is True, then u_hist stores the history of u as a list # If the partion scheme is Nx1, then u can be reconstructed via 'gather': if ns.save and partition[-1] == 1: diff --git a/docs/examples/newparallel/wave2D/wavesolver.py b/docs/examples/newparallel/wave2D/wavesolver.py index 00cb2fc..0c02e68 100755 --- a/docs/examples/newparallel/wave2D/wavesolver.py +++ b/docs/examples/newparallel/wave2D/wavesolver.py @@ -40,7 +40,7 @@ class WaveSolver(object): tstop is the stop time for the simulation. I, f are functions: I(x,y), f(x,y,t) - + user_action: function of (u, x, y, t) called at each time level (x and y are one-dimensional coordinate vectors). This function allows the calling code to plot the solution, @@ -67,13 +67,13 @@ class WaveSolver(object): final_test: true means the discrete L2-norm of the final solution is to be computed. """ - + def __init__(self, I, f, c, bc, Lx, Ly, partitioner=None, dt=-1, - user_action=None, + user_action=None, implementation={'ic': 'vectorized', # or 'scalar' 'inner': 'vectorized', 'bc': 'vectorized'}): - + nx = partitioner.global_num_cells[0] # number of global cells in x dir ny = partitioner.global_num_cells[1] # number of global cells in y dir dx = Lx/float(nx) @@ -130,7 +130,7 @@ class WaveSolver(object): u_2[i,j] = u_1[i,j] + \ 0.5*Cx2*(u_1[i-1,j] - 2*u_1[i,j] + u_1[i+1,j]) + \ 0.5*Cy2*(u_1[i,j-1] - 2*u_1[i,j] + u_1[i,j+1]) + \ - dt2*f(x[i], y[j], 0.0) + dt2*f(x[i], y[j], 0.0) # boundary values of u_2 (equals u(t=dt) due to du/dt=0) i = 0 @@ -162,8 +162,8 @@ class WaveSolver(object): user_action(u_1, x, y, t) # allow user to plot etc. # print list(self.us[2][2]) self.us = (u,u_1,u_2) - - + + def solve(self, tstop, dt=-1, user_action=None, verbose=False, final_test=False): t0=time.time() f=self.f @@ -191,7 +191,7 @@ class WaveSolver(object): upper_y_neigh = partitioner.upper_neighbors[1] u,u_1,u_2 = self.us # u_1 = self.u_1 - + t = 0.0 while t <= tstop: t_old = t; t += dt @@ -211,7 +211,7 @@ class WaveSolver(object): Cx2*(u_1[0:nx-1,1:ny] - 2*u_1[1:nx,1:ny] + u_1[2:nx+1,1:ny]) + \ Cy2*(u_1[1:nx,0:ny-1] - 2*u_1[1:nx,1:ny] + u_1[1:nx,2:ny+1]) + \ dt2*f(xv[1:nx,1:ny], yv[1:nx,1:ny], t_old) - + # insert boundary conditions (if there's no neighbor): if lower_x_neigh < 0: if implementation['bc'] == 'scalar': diff --git a/docs/examples/notebooks/text_analysis.py b/docs/examples/notebooks/text_analysis.py index c98a372..44ee8f2 100644 --- a/docs/examples/notebooks/text_analysis.py +++ b/docs/examples/notebooks/text_analysis.py @@ -63,14 +63,14 @@ def rescale_arr(arr,amin,amax): >>> rescale_arr(a,3,6) array([ 3. , 3.75, 4.5 , 5.25, 6. ]) """ - + # old bounds m = arr.min() M = arr.max() # scale/offset s = float(amax-amin)/(M-m) d = amin - s*m - + # Apply clip before returning to cut off possible overflows outside the # intended range due to roundoff error, so that we can absolutely guarantee # that on output, there are no values > amax or < amin. @@ -98,7 +98,7 @@ def text_cleanup(text, min_length=3, """ return [w for w in text.lower().split() if len(w)>=min_length and w not in remove] - + def print_vk(lst): """Print a list of value/key pairs nicely formatted in key/value order.""" @@ -120,7 +120,7 @@ def word_freq(text): freqs = {} for word in text: - freqs[word] = freqs.get(word, 0) + 1 + freqs[word] = freqs.get(word, 0) + 1 return freqs @@ -131,7 +131,7 @@ def sort_freqs(freqs): ---------- freqs : dict A dict with string keys and integer values. - + Return ------ items : list @@ -155,7 +155,7 @@ def summarize_freq_hist(freqs, n=10): freqs : dict or list Word frequencies, represented either as a dict of word->count, or as a list of count->word pairs. - + n : int The number of least/most frequent words to print. """ @@ -199,7 +199,7 @@ def get_text_from_url(url): def co_occurrences(lines, words): """Return histogram of co-occurrences of words in a list of lines. - + Parameters ---------- lines : list @@ -210,7 +210,7 @@ def co_occurrences(lines, words): searched for co-occurrences. """ wpairs = all_pairs(words) - + # Now build histogram of co-occurrences co_occur = {} for w1, w2 in wpairs: @@ -244,7 +244,7 @@ def plot_graph(wgraph, pos=None): sizes.append(d['count']) degrees.append(wgraph.degree(n)) sizes = rescale_arr(np.array(sizes, dtype=float), 100, 1000) - + # Compute layout and label edges according to weight pos = nx.spring_layout(wgraph) if pos is None else pos labels = {} @@ -256,7 +256,7 @@ def plot_graph(wgraph, pos=None): # remap width to 1-10 range width = rescale_arr(np.array(width, dtype=float), 1, 15) - + # Create figure fig = plt.figure() ax = fig.add_subplot(111) @@ -283,7 +283,7 @@ def plot_word_histogram(freqs, show=10, title=None): # interpret as a fraction start = -int(round(show*len(freqs))) show_f = sorted_f[start:] - + # Now, extract words and counts, plot n_words = len(show_f) ind = np.arange(n_words) @@ -329,48 +329,48 @@ def summarize_centrality(centrality): # # Configure user variables here # # Specify the url (can be a local file path) of the text file to analyze. # # If not given, it's read from the command line as the first argument - # + # # # 11226 titles of recent articles in arxiv/math/prob # default_url = "http://bibserver.berkeley.edu/tmp/titles.txt" # # Number of words to display in detailed histogram # n_words = 15 # # Number of words to use as nodes for co-occurrence graph. # n_nodes = 15 - # + # # # End of user configuration - # + # # # Actual code starts here # try: # url = sys.argv[1] # except IndexError: # url = default_url - # + # # # Fetch text and do basic preprocessing # text = get_text_from_url(url).lower() # lines = text.splitlines() # words = text_cleanup(text) - # + # # # Compute frequency histogram # wf = word_freq(words) # sorted_wf = sort_freqs(wf) - # + # # # Build a graph from the n_nodes most frequent words # popular = sorted_wf[-n_nodes:] # pop_words = [wc[0] for wc in popular] # co_occur = co_occurrences(lines, pop_words) # wgraph = co_occurrences_graph(popular, co_occur, cutoff=1) # centrality = nx.eigenvector_centrality_numpy(wgraph) - # + # # # Print summaries of single-word frequencies and graph structure # summarize_freq_hist(sorted_wf) # summarize_centrality(centrality) - # + # # # Plot histogram and graph # plt.close('all') # plot_word_histogram(sorted_wf, n_words, # "Frequencies for %s most frequent words" % n_words) # plot_word_histogram(sorted_wf, 1.0, "Frequencies for entire word list") # plot_graph(wgraph) - # + # # # Display figures # plt.show() diff --git a/docs/source/conf.py b/docs/source/conf.py index 60a9e48..e9cf104 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -42,7 +42,7 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'inheritance_diagram', - 'ipython_console_highlighting', + 'ipython_console_highlighting', 'numpydoc', # to preprocess docstrings ] diff --git a/docs/sphinxext/apigen.py b/docs/sphinxext/apigen.py index 1237409..56d3450 100644 --- a/docs/sphinxext/apigen.py +++ b/docs/sphinxext/apigen.py @@ -168,7 +168,7 @@ class ApiDocWriter(object): functions, classes = self._parse_lines(f) f.close() return functions, classes - + def _parse_lines(self, linesource): ''' Parse lines of text for functions and classes ''' functions = [] @@ -210,9 +210,9 @@ class ApiDocWriter(object): return '' # Make a shorter version of the uri that omits the package name for - # titles + # titles uri_short = re.sub(r'^%s\.' % self.package_name,'',uri) - + ad = '.. AUTO-GENERATED FILE -- DO NOT EDIT!\n\n' chap_title = uri_short @@ -291,7 +291,7 @@ class ApiDocWriter(object): elif match_type == 'package': patterns = self.package_skip_patterns else: - raise ValueError('Cannot interpret match type "%s"' + raise ValueError('Cannot interpret match type "%s"' % match_type) # Match to URI without package name L = len(self.package_name) @@ -307,7 +307,7 @@ class ApiDocWriter(object): return True def discover_modules(self): - ''' Return module sequence discovered from ``self.package_name`` + ''' Return module sequence discovered from ``self.package_name`` Parameters @@ -328,7 +328,7 @@ class ApiDocWriter(object): >>> dw.package_skip_patterns.append('\.util$') >>> 'sphinx.util' in dw.discover_modules() False - >>> + >>> ''' modules = [self.package_name] # raw directory parsing @@ -351,7 +351,7 @@ class ApiDocWriter(object): self._survives_exclude(module_uri, 'module')): modules.append(module_uri) return sorted(modules) - + def write_modules_api(self, modules,outdir): # write the list written_modules = [] @@ -376,7 +376,7 @@ class ApiDocWriter(object): outdir : string Directory name in which to store files We create automatic filenames for each module - + Returns ------- None @@ -390,7 +390,7 @@ class ApiDocWriter(object): # compose list of modules modules = self.discover_modules() self.write_modules_api(modules,outdir) - + def write_index(self, outdir, froot='gen', relative_to=None): """Make a reST API index file from written files diff --git a/docs/sphinxext/ipython_console_highlighting.py b/docs/sphinxext/ipython_console_highlighting.py index 217b779..f0a41be 100644 --- a/docs/sphinxext/ipython_console_highlighting.py +++ b/docs/sphinxext/ipython_console_highlighting.py @@ -13,7 +13,7 @@ import re # Third party from pygments.lexer import Lexer, do_insertions -from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer, +from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer, PythonTracebackLexer) from pygments.token import Comment, Generic @@ -48,7 +48,7 @@ class IPythonConsoleLexer(Lexer): - It assumes the default IPython prompts, not customized ones. """ - + name = 'IPython console session' aliases = ['ipython'] mimetypes = ['text/x-ipython-console'] diff --git a/setup2.py b/setup2.py index f6b7e01..1c12356 100755 --- a/setup2.py +++ b/setup2.py @@ -2,8 +2,8 @@ # -*- coding: utf-8 -*- """Setup script for IPython. -Under Posix environments it works like a typical setup.py script. -Under Windows, the command sdist is not supported, since IPython +Under Posix environments it works like a typical setup.py script. +Under Windows, the command sdist is not supported, since IPython requires utilities which are not available under Windows.""" #----------------------------------------------------------------------------- @@ -54,9 +54,9 @@ from distutils.core import setup from IPython.utils.path import target_update from setupbase import ( - setup_args, - find_packages, - find_package_data, + setup_args, + find_packages, + find_package_data, find_scripts, find_data_files, check_for_dependencies, @@ -113,7 +113,7 @@ if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'): # target_update() to_update = [ # FIXME - Disabled for now: we need to redo an automatic way - # of generating the magic info inside the rst. + # of generating the magic info inside the rst. #('docs/magic.tex', #['IPython/Magic.py'], #"cd doc && ./update_magic.sh" ), @@ -176,9 +176,9 @@ if len(sys.argv) >= 2 and sys.argv[1] in ('sdist','bdist_rpm'): docdeps, "cd docs && make dist") ) - + [ target_update(*t) for t in to_update ] - + #--------------------------------------------------------------------------- # Find all the packages, package data, and data_files #--------------------------------------------------------------------------- @@ -207,7 +207,7 @@ if sys.platform == 'win32': if len(needs_setuptools.intersection(sys.argv)) > 0: import setuptools -# This dict is used for passing extra arguments that are setuptools +# This dict is used for passing extra arguments that are setuptools # specific to setup setuptools_extra_args = {} @@ -233,7 +233,7 @@ if 'setuptools' in sys.modules: else: pass # do we want to install readline here? - + # Script to be run by the windows binary installer after the default setup # routine, to add shortcuts and similar windows-only things. Windows # post-install scripts MUST reside in the scripts/ dir, otherwise distutils diff --git a/setupbase.py b/setupbase.py index f9e6e08..df406bb 100644 --- a/setupbase.py +++ b/setupbase.py @@ -43,7 +43,7 @@ pjoin = os.path.join def oscmd(s): print(">", s) os.system(s) - + try: execfile except NameError: @@ -120,7 +120,7 @@ def find_package_data(): """ # This is not enough for these things to appear in an sdist. # We need to muck with the MANIFEST to get this to work - + # walk notebook resources: cwd = os.getcwd() os.chdir(os.path.join('IPython', 'frontend', 'html', 'notebook')) @@ -130,7 +130,7 @@ def find_package_data(): for parent, dirs, files in static_walk: for f in files: static_data.append(os.path.join(parent, f)) - + package_data = { 'IPython.config.profile' : ['README', '*/*.py'], 'IPython.testing' : ['*.txt'], @@ -151,23 +151,23 @@ def make_dir_struct(tag,base,out_base): XXX - this needs a proper docstring! """ - + # we'll use these a lot below lbase = len(base) pathsep = os.path.sep lpathsep = len(pathsep) - + out = [] for (dirpath,dirnames,filenames) in os.walk(base): # we need to strip out the dirpath from the base to map it to the # output (installation) path. This requires possibly stripping the # path separator, because otherwise pjoin will not work correctly # (pjoin('foo/','/bar') returns '/bar'). - + dp_eff = dirpath[lbase:] if dp_eff.startswith(pathsep): dp_eff = dp_eff[lpathsep:] - # The output path must be anchored at the out_base marker + # The output path must be anchored at the out_base marker out_path = pjoin(out_base,dp_eff) # Now we can generate the final filenames. Since os.walk only produces # filenames, we must join back with the dirpath to get full valid file @@ -178,7 +178,7 @@ def make_dir_struct(tag,base,out_base): out.append((out_path, pfiles)) return out - + def find_data_files(): """ @@ -186,10 +186,10 @@ def find_data_files(): Most of these are docs. """ - + docdirbase = pjoin('share', 'doc', 'ipython') manpagebase = pjoin('share', 'man', 'man1') - + # Simple file lists can be made by hand manpages = filter(isfile, glob(pjoin('docs','man','*.1.gz'))) if not manpages: @@ -241,19 +241,19 @@ def make_man_update_target(manpage): gz_cmd = ( "cd %(man_dir)s && gzip -9c %(manpage)s > %(manpage_gz)s" % locals() ) return (manpath_gz, [manpath], gz_cmd) - + #--------------------------------------------------------------------------- # Find scripts #--------------------------------------------------------------------------- def find_scripts(entry_points=False, suffix=''): """Find IPython's scripts. - + if entry_points is True: return setuptools entry_point-style definitions else: return file paths of plain scripts [default] - + suffix is appended to script names if entry_points is True, so that the Python 3 scripts get named "ipython3" etc. """ @@ -293,7 +293,7 @@ def find_scripts(entry_points=False, suffix=''): def check_for_dependencies(): """Check for IPython's dependencies. - + This function should NOT be called if running under setuptools! """ from setupext.setupext import ( @@ -308,7 +308,7 @@ def check_for_dependencies(): print_status('platform', sys.platform) if sys.platform == 'win32': print_status('Windows version', sys.getwindowsversion()) - + print_raw("") print_raw("OPTIONAL DEPENDENCIES") diff --git a/setupext/setupext.py b/setupext/setupext.py index 93a0adf..c97c768 100644 --- a/setupext/setupext.py +++ b/setupext/setupext.py @@ -69,7 +69,7 @@ def check_for_sphinx(): print_status('sphinx', "Not found (required for building documentation)") return False else: - print_status('sphinx', sphinx.__version__) + print_status('sphinx', sphinx.__version__) return True def check_for_pygments(): @@ -142,7 +142,7 @@ def check_for_pyzmq(): if zmq.__version__ < '2.1.4': print_status('pyzmq', "no (have %s, but require >= 2.1.4 for" " qtconsole and parallel computing capabilities)"%zmq.__version__) - + else: print_status("pyzmq", zmq.__version__) return True diff --git a/tools/run_ipy_in_profiler.py b/tools/run_ipy_in_profiler.py index 01d287b..7362293 100755 --- a/tools/run_ipy_in_profiler.py +++ b/tools/run_ipy_in_profiler.py @@ -14,7 +14,7 @@ def main(): print "Entering ipython for profiling. Type 'Exit' for profiler report" IPython.ipapi.launch_new_instance() -if len(sys.argv) == 1: +if len(sys.argv) == 1: profile.run('main()', 'ipython_profiler_results') import pstats