diff --git a/IPython/ColorANSI.py b/IPython/ColorANSI.py new file mode 100644 index 0000000..420f706 --- /dev/null +++ b/IPython/ColorANSI.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +"""Tools for coloring text in ANSI terminals. + +$Id: ColorANSI.py 410 2004-11-04 07:58:17Z fperez $""" + +#***************************************************************************** +# Copyright (C) 2002-2004 Fernando Perez. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** + +from IPython import Release +__author__ = '%s <%s>' % Release.authors['Fernando'] +__license__ = Release.license + +__all__ = ['TermColors','InputTermColors','ColorScheme','ColorSchemeTable'] + +import os +from UserDict import UserDict + +from IPython.Struct import Struct + +def make_color_table(in_class): + """Build a set of color attributes in a class. + + Helper function for building the *TermColors classes.""" + + color_templates = ( + ("Black" , "0;30"), + ("Red" , "0;31"), + ("Green" , "0;32"), + ("Brown" , "0;33"), + ("Blue" , "0;34"), + ("Purple" , "0;35"), + ("Cyan" , "0;36"), + ("LightGray" , "0;37"), + ("DarkGray" , "1;30"), + ("LightRed" , "1;31"), + ("LightGreen" , "1;32"), + ("Yellow" , "1;33"), + ("LightBlue" , "1;34"), + ("LightPurple" , "1;35"), + ("LightCyan" , "1;36"), + ("White" , "1;37"), ) + + for name,value in color_templates: + setattr(in_class,name,in_class._base % value) + +class TermColors: + """Color escape sequences. + + 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 + +# Build the actual color table as a set of class attributes: +make_color_table(TermColors) + +class InputTermColors: + """Color escape sequences for input prompts. + + This class is similar to TermColors, but the escapes are wrapped in \001 + and \002 so that readline can properly know the length of each line and + 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?) + 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 = '\001\033[0m\002' # Reset normal coloring + _base = '\001\033[%sm\002' # Template for all other colors + +# Build the actual color table as a set of class attributes: +make_color_table(InputTermColors) + +class ColorScheme: + """Generic color scheme class. Just a name and a Struct.""" + def __init__(self,__scheme_name_,colordict=None,**colormap): + self.name = __scheme_name_ + if colordict is None: + self.colors = Struct(**colormap) + else: + self.colors = Struct(colordict) + +class ColorSchemeTable(UserDict): + """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""" + + def __init__(self,scheme_list=None,default_scheme=''): + """Create a table of color schemes. + + The table can be created empty and manually filled or it can be + created with a list of valid color schemes AND the specification for + the default active scheme. + """ + + UserDict.__init__(self) + if scheme_list is None: + self.active_scheme_name = '' + self.active_colors = None + else: + if default_scheme == '': + raise ValueError,'you must specify the default color scheme' + for scheme in scheme_list: + self.add_scheme(scheme) + self.set_active_scheme(default_scheme) + + def add_scheme(self,new_scheme): + """Add a new color scheme to the table.""" + 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. + + Names are by default compared in a case-insensitive way, but this can + be changed by setting the parameter case_sensitive to true.""" + + scheme_list = self.keys() + if case_sensitive: + valid_schemes = scheme_list + scheme_test = scheme + else: + valid_schemes = [s.lower() for s in scheme_list] + scheme_test = scheme.lower() + try: + scheme_idx = valid_schemes.index(scheme_test) + except ValueError: + raise ValueError,'Unrecognized color scheme: ' + scheme + \ + '\nValid schemes: '+str(scheme_list).replace("'', ",'') + else: + active = scheme_list[scheme_idx] + self.active_scheme_name = active + self.active_colors = self[active].colors + # Now allow using '' as an index for the current active scheme + self[''] = self[active] diff --git a/IPython/ConfigLoader.py b/IPython/ConfigLoader.py new file mode 100644 index 0000000..192a92e --- /dev/null +++ b/IPython/ConfigLoader.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +"""Configuration loader + +$Id: ConfigLoader.py 525 2005-02-19 10:53:12Z fperez $""" + +#***************************************************************************** +# Copyright (C) 2001-2004 Fernando Perez. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** + +from IPython import Release +__author__ = '%s <%s>' % Release.authors['Fernando'] +__license__ = Release.license + +import os +from pprint import pprint +import exceptions + +from IPython import ultraTB +from IPython.Struct import Struct +from IPython.genutils import * + +class ConfigLoaderError(exceptions.Exception): + """Exception for ConfigLoader class.""" + + def __init__(self,args=None): + self.args = args + +class ConfigLoader: + + """Configuration file loader capable of handling recursive inclusions and + with parametrized conflict resolution for multiply found keys.""" + + def __init__(self,conflict=None,field_sep=None,reclimit=15): + + """The reclimit parameter controls the number of recursive + configuration file inclusions. This way we can stop early on (before + python's own recursion limit is hit) if there is a circular + inclusion. + + - conflict: dictionary for conflict resolutions (see Struct.merge()) + + """ + self.conflict = conflict + self.field_sep = field_sep + self.reset(reclimit) + + def reset(self,reclimit=15): + self.reclimit = reclimit + self.recdepth = 0 + self.included = [] + + def load(self,fname,convert=None,recurse_key='',incpath = '.',**kw): + """Load a configuration file, return the resulting Struct. + + Call: load_config(fname,convert=None,conflict=None,recurse_key='') + + - fname: file to load from. + - convert: dictionary of type conversions (see read_dict()) + - recurse_key: keyword in dictionary to trigger recursive file + inclusions. + """ + + if self.recdepth > self.reclimit: + raise ConfigLoaderError, 'maximum recursive inclusion of rcfiles '+\ + 'exceeded: ' + `self.recdepth` + \ + '.\nMaybe you have a circular chain of inclusions?' + self.recdepth += 1 + fname = filefind(fname,incpath) + data = Struct() + # avoid including the same file more than once + if fname in self.included: + return data + Xinfo = ultraTB.AutoFormattedTB() + if convert==None and recurse_key : convert = {qwflat:recurse_key} + # for production, change warn to 0: + data.merge(read_dict(fname,convert,fs=self.field_sep,strip=1, + warn=0,no_empty=0,**kw)) + # keep track of successfully loaded files + self.included.append(fname) + if recurse_key in data.keys(): + for incfilename in data[recurse_key]: + found=0 + try: + incfile = filefind(incfilename,incpath) + except IOError: + if os.name in ['nt','dos']: + try: + # Try again with '.ini' extension + incfilename += '.ini' + incfile = filefind(incfilename,incpath) + except IOError: + found = 0 + else: + found = 1 + else: + found = 0 + else: + found = 1 + if found: + try: + data.merge(self.load(incfile,convert,recurse_key, + incpath,**kw), + self.conflict) + except: + Xinfo() + warn('Problem loading included file: '+ + `incfilename` + '. Ignoring it...') + else: + warn('File `%s` not found. Included by %s' % (incfilename,fname)) + + return data + +# end ConfigLoader diff --git a/IPython/CrashHandler.py b/IPython/CrashHandler.py new file mode 100644 index 0000000..12acbd6 --- /dev/null +++ b/IPython/CrashHandler.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +"""sys.excepthook for IPython itself, leaves a detailed report on disk. + +$Id: CrashHandler.py 410 2004-11-04 07:58:17Z fperez $""" + +#***************************************************************************** +# Copyright (C) 2001-2004 Fernando Perez. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** + +from IPython import Release +__author__ = '%s <%s>' % Release.authors['Fernando'] +__license__ = Release.license +__version__ = Release.version + +#**************************************************************************** +# Required modules + +# From the standard library +import os,sys +from pprint import pprint,pformat + +# Homebrewed +from IPython.genutils import * +from IPython.Itpl import Itpl,itpl,printpl +from IPython import ultraTB +from IPython.ultraTB import ColorScheme,ColorSchemeTable # too long names + +#**************************************************************************** +class CrashHandler: + """sys.excepthook for IPython itself, leaves a detailed report on disk.""" + + def __init__(self,IP): + self.IP = IP # IPython instance + self.bug_contact = Release.authors['Fernando'][0] + self.mailto = Release.authors['Fernando'][1] + + def __call__(self,etype, evalue, etb): + + # Report tracebacks shouldn't use color in general (safer for users) + color_scheme = 'NoColor' + + # Use this ONLY for developer debugging (keep commented out for release) + #color_scheme = 'Linux' # dbg + + try: + rptdir = self.IP.rc.ipythondir + except: + rptdir = os.getcwd() + if not os.path.isdir(rptdir): + rptdir = os.getcwd() + self.report_name = os.path.join(rptdir,'IPython_crash_report.txt') + self.TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme,long_header=1) + traceback = self.TBhandler.text(etype,evalue,etb,context=31) + + # print traceback to screen + print >> sys.stderr, traceback + + # and generate a complete report on disk + try: + report = open(self.report_name,'w') + except: + print >> sys.stderr, 'Could not create crash report on disk.' + return + + msg = itpl('\n'+'*'*70+'\n' +""" +Oops, IPython crashed. We do our best to make it stable, but... + +A crash report was automatically generated with the following information: + - A verbatim copy of the traceback above this text. + - A copy of your input history during this session. + - Data on your current IPython configuration. + +It was left in the file named: +\t'$self.report_name' +If you can email this file to the developers, the information in it will help +them in understanding and correcting the problem. + +You can mail it to $self.bug_contact at $self.mailto +with the subject 'IPython Crash Report'. + +If you want to do it now, the following command will work (under Unix): +mail -s 'IPython Crash Report' $self.mailto < $self.report_name + +To ensure accurate tracking of this issue, please file a report about it at: +http://www.scipy.net/roundup/ipython (IPython's online bug tracker). +""") + print >> sys.stderr, msg + + sec_sep = '\n\n'+'*'*75+'\n\n' + report.write('*'*75+'\n\n'+'IPython post-mortem report\n\n') + report.write('IPython version: %s \n\n' % __version__) + report.write('Platform info : os.name -> %s, sys.platform -> %s' % + (os.name,sys.platform) ) + report.write(sec_sep+'Current user configuration structure:\n\n') + report.write(pformat(self.IP.rc.dict())) + report.write(sec_sep+'Crash traceback:\n\n' + traceback) + try: + report.write(sec_sep+"History of session input:") + for line in self.IP.user_ns['_ih']: + report.write(line) + report.write('\n*** Last line of input (may not be in above history):\n') + report.write(self.IP._last_input_line+'\n') + except: + pass + report.close() diff --git a/IPython/DPyGetOpt.py b/IPython/DPyGetOpt.py new file mode 100644 index 0000000..75a7461 --- /dev/null +++ b/IPython/DPyGetOpt.py @@ -0,0 +1,671 @@ +# -*- coding: utf-8 -*- +"""DPyGetOpt -- Demiurge Python GetOptions Module + + $Id: DPyGetOpt.py 389 2004-10-09 07:59:30Z fperez $ + +This module is modeled after perl's Getopt::Long module-- which +is, in turn, modeled after GNU's extended getopt() function. + +Upon instantiation, the option specification should be a sequence +(list) of option definitions. + +Options that take no arguments should simply contain the name of +the option. If a ! is post-pended, the option can be negated by +prepending 'no'; ie 'debug!' specifies that -debug and -nodebug +should be accepted. + +Mandatory arguments to options are specified using a postpended +'=' + a type specifier. '=s' specifies a mandatory string +argument, '=i' specifies a mandatory integer argument, and '=f' +specifies a mandatory real number. In all cases, the '=' can be +substituted with ':' to specify that the argument is optional. + +Dashes '-' in option names are allowed. + +If an option has the character '@' postpended (after the +argumentation specification), it can appear multiple times within +each argument list that is processed. The results will be stored +in a list. + +The option name can actually be a list of names separated by '|' +characters; ie-- 'foo|bar|baz=f@' specifies that all -foo, -bar, +and -baz options that appear on within the parsed argument list +must have a real number argument and that the accumulated list +of values will be available under the name 'foo' + +$Id: DPyGetOpt.py 389 2004-10-09 07:59:30Z fperez $""" + +#***************************************************************************** +# +# Copyright (c) 2001 Bill Bumgarner +# +# +# Published under the terms of the MIT license, hereby reproduced: +# +# 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 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 DEALINGS +# IN THE SOFTWARE. +# +#***************************************************************************** + +__author__ = 'Bill Bumgarner ' +__license__ = 'MIT' +__version__ = '1.2' + +# Modified to use re instead of regex and regsub modules. +# 2001/5/7, Jonathan Hogg + +import string +import re +import sys +import types + +arg_error = 'DPyGetOpt Argument Error' +spec_error = 'DPyGetOpt Specification Error' +term_error = 'DPyGetOpt Termination Error' + +specificationExpr = re.compile('(?P.)(?P.)(?P@?)') + +ArgRequired = 'Requires an Argument' +ArgOptional = 'Argument Optional' + +# The types modules is not used for these identifiers because there +# is no identifier for 'boolean' or 'generic' +StringArgType = 'String Argument Type' +IntegerArgType = 'Integer Argument Type' +RealArgType = 'Real Argument Type' +BooleanArgType = 'Boolean Argument Type' +GenericArgType = 'Generic Argument Type' + +# dictionary of conversion functions-- boolean and generic options +# do not accept arguments and do not need conversion functions; +# the identity function is used purely for convenience. +ConversionFunctions = { + StringArgType : lambda x: x, + IntegerArgType : string.atoi, + RealArgType : string.atof, + BooleanArgType : lambda x: x, + GenericArgType : lambda x: x, + } + +class DPyGetOpt: + + def __init__(self, spec = None, terminators = ['--']): + """ + Declare and intialize instance variables + + Yes, declaration is not necessary... but one of the things + I sorely miss from C/Obj-C is the concept of having an + interface definition that clearly declares all instance + variables and methods without providing any implementation + details. it is a useful reference! + + all instance variables are initialized to 0/Null/None of + the appropriate type-- not even the default value... + """ + +# sys.stderr.write(string.join(spec) + "\n") + + self.allowAbbreviations = 1 # boolean, 1 if abbreviations will + # be expanded + self.freeValues = [] # list, contains free values + self.ignoreCase = 0 # boolean, YES if ignoring case + self.needsParse = 0 # boolean, YES if need to reparse parameter spec + self.optionNames = {} # dict, all option names-- value is index of tuple + self.optionStartExpr = None # regexp defining the start of an option (ie; '-', '--') + self.optionTuples = [] # list o' tuples containing defn of options AND aliases + self.optionValues = {} # dict, option names (after alias expansion) -> option value(s) + self.orderMixed = 0 # boolean, YES if options can be mixed with args + self.posixCompliance = 0 # boolean, YES indicates posix like behaviour + self.spec = [] # list, raw specs (in case it must be reparsed) + self.terminators = terminators # list, strings that terminate argument processing + self.termValues = [] # list, values after terminator + self.terminator = None # full name of terminator that ended + # option processing + + # set up defaults + self.setPosixCompliance() + self.setIgnoreCase() + self.setAllowAbbreviations() + + # parse spec-- if present + if spec: + self.parseConfiguration(spec) + + def setPosixCompliance(self, aFlag = 0): + """ + Enables and disables posix compliance. + + When enabled, '+' can be used as an option prefix and free + values can be mixed with options. + """ + self.posixCompliance = aFlag + self.needsParse = 1 + + if self.posixCompliance: + self.optionStartExpr = re.compile('(--|-)(?P