From 2f09c2ab3c6929cc9fa266fe666d312643264823 2008-02-16 09:50:47 From: ville Date: 2008-02-16 09:50:47 Subject: [PATCH] initialization (no svn history) --- diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..ecc75a2 --- /dev/null +++ b/.hgignore @@ -0,0 +1,18 @@ +syntax: glob + +*~ +*.tmp +*.pyc +*.bak +*.tgz +*.org +*.rej +.svn/ +.bzr/ +.settings/ +.project +*.diff +IPython_crash_report.txt + +syntax: regexp +.*\#.*\#$ diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..c1db38b --- /dev/null +++ b/ChangeLog @@ -0,0 +1 @@ +link doc/ChangeLog \ No newline at end of file diff --git a/IPython/ColorANSI.py b/IPython/ColorANSI.py new file mode 100644 index 0000000..780e9e9 --- /dev/null +++ b/IPython/ColorANSI.py @@ -0,0 +1,170 @@ +# -*- coding: utf-8 -*- +"""Tools for coloring text in ANSI terminals. + +$Id: ColorANSI.py 2167 2007-03-21 06:57:50Z fperez $""" + +#***************************************************************************** +# Copyright (C) 2002-2006 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 IPython.ipstruct 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. + + if os.name == 'nt' and os.environ.get('TERM','dumb') == 'emacs': + # (X)emacs on W32 gets confused with \001 and \002 so we remove them + Normal = '\033[0m' # Reset normal coloring + _base = '\033[%sm' # Template for all other colors + else: + 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) + + def copy(self,name=None): + """Return a full copy of the object, optionally renaming it.""" + 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""" + + 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. + """ + + # 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' + for scheme in scheme_list: + self.add_scheme(scheme) + self.set_active_scheme(default_scheme) + + def copy(self): + """Return full copy of object""" + return ColorSchemeTable(self.values(),self.active_scheme_name) + + 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_names = self.keys() + if case_sensitive: + valid_schemes = scheme_names + scheme_test = scheme + else: + valid_schemes = [s.lower() for s in scheme_names] + scheme_test = scheme.lower() + try: + scheme_idx = valid_schemes.index(scheme_test) + except ValueError: + raise ValueError,'Unrecognized color scheme: ' + scheme + \ + '\nValid schemes: '+str(scheme_names).replace("'', ",'') + else: + active = scheme_names[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..10a245a --- /dev/null +++ b/IPython/ConfigLoader.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +"""Configuration loader + +$Id: ConfigLoader.py 1005 2006-01-12 08:39:26Z fperez $""" + +#***************************************************************************** +# Copyright (C) 2001-2006 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 exceptions +import os +from pprint import pprint + +from IPython import ultraTB +from IPython.ipstruct 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..4cb6cb7 --- /dev/null +++ b/IPython/CrashHandler.py @@ -0,0 +1,228 @@ +# -*- coding: utf-8 -*- +"""sys.excepthook for IPython itself, leaves a detailed report on disk. + +$Id: CrashHandler.py 2908 2007-12-30 21:07:46Z vivainio $""" + +#***************************************************************************** +# Copyright (C) 2001-2006 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 +import sys +from pprint import pprint,pformat + +# Homebrewed +from IPython.Itpl import Itpl,itpl,printpl +from IPython.ColorANSI import ColorScheme,ColorSchemeTable # too long names +from IPython import ultraTB +from IPython.genutils import * + +#**************************************************************************** +class CrashHandler: + """Customizable crash handlers for IPython-based systems. + + Instances of this class provide a __call__ method which can be used as a + sys.excepthook, i.e., the __call__ signature is: + + def __call__(self,etype, evalue, etb) + + """ + + def __init__(self,IP,app_name,contact_name,contact_email, + bug_tracker,crash_report_fname, + show_crash_traceback=True): + """New crash handler. + + Inputs: + + - IP: a running IPython instance, which will be queried at crash time + for internal information. + + - app_name: a string containing the name of your application. + + - contact_name: a string with the name of the person to contact. + + - contact_email: a string with the email address of the contact. + + - bug_tracker: a string with the URL for your project's bug tracker. + + - crash_report_fname: a string with the filename for the crash report + to be saved in. These reports are left in the ipython user directory + as determined by the running IPython instance. + + Optional inputs: + + - show_crash_traceback(True): if false, don't print the crash + traceback on stderr, only generate the on-disk report + + + Non-argument instance attributes: + + These instances contain some non-argument attributes which allow for + further customization of the crash handler's behavior. Please see the + source for further details. + """ + + # apply args into instance + self.IP = IP # IPython instance + self.app_name = app_name + self.contact_name = contact_name + self.contact_email = contact_email + self.bug_tracker = bug_tracker + self.crash_report_fname = crash_report_fname + self.show_crash_traceback = show_crash_traceback + + # Hardcoded defaults, which can be overridden either by subclasses or + # at runtime for the instance. + + # Template for the user message. Subclasses which completely override + # this, or user apps, can modify it to suit their tastes. It gets + # expanded using itpl, so calls of the kind $self.foo are valid. + self.user_message_template = """ +Oops, $self.app_name 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 crash traceback. + - A copy of your input history during this session. + - Data on your current $self.app_name configuration. + +It was left in the file named: +\t'$self.crash_report_fname' +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.contact_name at $self.contact_email +with the subject '$self.app_name Crash Report'. + +If you want to do it now, the following command will work (under Unix): +mail -s '$self.app_name Crash Report' $self.contact_email < $self.crash_report_fname + +To ensure accurate tracking of this issue, please file a report about it at: +$self.bug_tracker +""" + + def __call__(self,etype, evalue, etb): + """Handle an exception, call for compatible with sys.excepthook""" + + # 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() + report_name = os.path.join(rptdir,self.crash_report_fname) + # write the report filename into the instance dict so it can get + # properly expanded out in the user message template + self.crash_report_fname = report_name + TBhandler = ultraTB.VerboseTB(color_scheme=color_scheme, + long_header=1) + traceback = TBhandler.text(etype,evalue,etb,context=31) + + # print traceback to screen + if self.show_crash_traceback: + print >> sys.stderr, traceback + + # and generate a complete report on disk + try: + report = open(report_name,'w') + except: + print >> sys.stderr, 'Could not create crash report on disk.' + return + + # Inform user on stderr of what happened + msg = itpl('\n'+'*'*70+'\n'+self.user_message_template) + print >> sys.stderr, msg + + # Construct report on disk + report.write(self.make_report(traceback)) + report.close() + raw_input("Press enter to exit:") + + def make_report(self,traceback): + """Return a string containing a crash report.""" + + sec_sep = '\n\n'+'*'*75+'\n\n' + + report = [] + rpt_add = report.append + + rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n') + rpt_add('IPython version: %s \n\n' % Release.version) + rpt_add('SVN revision : %s \n\n' % Release.revision) + rpt_add('Platform info : os.name -> %s, sys.platform -> %s' % + (os.name,sys.platform) ) + rpt_add(sec_sep+'Current user configuration structure:\n\n') + rpt_add(pformat(self.IP.rc.dict())) + rpt_add(sec_sep+'Crash traceback:\n\n' + traceback) + try: + rpt_add(sec_sep+"History of session input:") + for line in self.IP.user_ns['_ih']: + rpt_add(line) + rpt_add('\n*** Last line of input (may not be in above history):\n') + rpt_add(self.IP._last_input_line+'\n') + except: + pass + + return ''.join(report) + +class IPythonCrashHandler(CrashHandler): + """sys.excepthook for IPython itself, leaves a detailed report on disk.""" + + def __init__(self,IP): + + # Set here which of the IPython authors should be listed as contact + AUTHOR_CONTACT = 'Ville' + + # Set argument defaults + app_name = 'IPython' + bug_tracker = 'http://projects.scipy.org/ipython/ipython/report' + contact_name,contact_email = Release.authors[AUTHOR_CONTACT][:2] + crash_report_fname = 'IPython_crash_report.txt' + # Call parent constructor + CrashHandler.__init__(self,IP,app_name,contact_name,contact_email, + bug_tracker,crash_report_fname) + + def make_report(self,traceback): + """Return a string containing a crash report.""" + + sec_sep = '\n\n'+'*'*75+'\n\n' + + report = [] + rpt_add = report.append + + rpt_add('*'*75+'\n\n'+'IPython post-mortem report\n\n') + rpt_add('IPython version: %s \n\n' % Release.version) + rpt_add('SVN revision : %s \n\n' % Release.revision) + rpt_add('Platform info : os.name -> %s, sys.platform -> %s' % + (os.name,sys.platform) ) + rpt_add(sec_sep+'Current user configuration structure:\n\n') + rpt_add(pformat(self.IP.rc.dict())) + rpt_add(sec_sep+'Crash traceback:\n\n' + traceback) + try: + rpt_add(sec_sep+"History of session input:") + for line in self.IP.user_ns['_ih']: + rpt_add(line) + rpt_add('\n*** Last line of input (may not be in above history):\n') + rpt_add(self.IP._last_input_line+'\n') + except: + pass + + return ''.join(report) diff --git a/IPython/DPyGetOpt.py b/IPython/DPyGetOpt.py new file mode 100644 index 0000000..e9d8ce4 --- /dev/null +++ b/IPython/DPyGetOpt.py @@ -0,0 +1,693 @@ +# -*- coding: utf-8 -*- +"""DPyGetOpt -- Demiurge Python GetOptions Module + + $Id: DPyGetOpt.py 2872 2007-11-25 17:58:05Z 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 2872 2007-11-25 17:58:05Z 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 re +import string +import sys +import types + +class Error(Exception): + """Base class for exceptions in the DPyGetOpt module.""" + +class ArgumentError(Error): + """Exception indicating an error in the arguments passed to + DPyGetOpt.processArguments.""" + +class SpecificationError(Error): + """Exception indicating an error with an option specification.""" + +class TerminationError(Error): + """Exception indicating an error with an option processing terminator.""" + +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