Ticket #12719: 12719-newipython-take2.patch

File 12719-newipython-take2.patch, 60.3 KB (added by jason, 9 years ago)
  • sage/misc/displayhook.py

    # HG changeset patch
    # User Jason Grout <jason.grout@drake.edu>
    # Date 1347562361 18000
    # Branch ipython
    # Node ID 1745b8b7b106c820df342144f9b3abd7c2d986dd
    # Parent  b90229c40457bf8ccd446a0a1ce7431720661c0c
    A massive restructuring of the ipython 0.13 compatibility code.
    
    This puts much of the functionality into a sage.misc.sage_extension.py IPython extension (so it can be loaded into a normal IPython instance, like in the IPython notebook).  Also, fixed some bugs with how load and attach were working, and lots of other little things.
    
    diff --git a/sage/misc/displayhook.py b/sage/misc/displayhook.py
    a b  
    9292    # Output any remaining entries.
    9393    if len(running_lines[0]) > 0:
    9494        _print_tall_list_row(out_stream, running_lines, True)
    95     print >>out_stream, parens[1]
     95    out_stream.write(str(parens[1]))
    9696    return True
    9797
    9898# This helper function for _print_tall_list processes and outputs the
     
    109109    if not last_row:
    110110        print >>out_stream
    111111
     112def format_obj(obj):
     113    """
     114    Return a string if we want to print it in a special way; otherwise, return None.
     115
     116    EXAMPLES::
     117
     118        sage: import sage.misc.displayhook
     119
     120    For most objects, nothing is done (None is returned):
     121
     122        sage: sage.misc.displayhook.format_obj('Hello, world!')
     123        sage: sage.misc.displayhook.format_obj((1, 2, 3, 4))
     124
     125    We demonstrate the special format for lists of matrices::
     126
     127        sage: sage.misc.displayhook.format_obj( \
     128                [matrix([[1], [2]]), matrix([[3], [4]])])
     129        '[\n[1]  [3]\n[2], [4]\n]'
     130    """
     131    # We only apply the special formatting to lists (or tuples) where the first
     132    # element is a matrix, or an ArithmeticSubgroupElement (a thin wrapper
     133    # around a matrix). This should cover most cases.
     134    if isinstance(obj, (tuple, list)):
     135        from sage.matrix.matrix import is_Matrix
     136        from sage.modular.arithgroup.arithgroup_element import ArithmeticSubgroupElement
     137        if len(obj) > 0 and (is_Matrix(obj[0]) or isinstance(obj[0], ArithmeticSubgroupElement)):
     138            from cStringIO import StringIO
     139            s = StringIO()
     140            if _check_tall_list_and_print(s, obj):
     141                return s.getvalue()
     142    return None
     143
    112144def print_obj(out_stream, obj):
    113145    """
    114     Print an object. This function is used internally by the displayhook.
     146    Return a string if we want to print it in a special way; otherwise, return False.
    115147
    116148    EXAMPLES::
    117149
     
    133165        [2], [4]
    134166        ]
    135167    """
    136     # We only apply the special formatting to lists (or tuples) where the first
    137     # element is a matrix, or an ArithmeticSubgroupElement (a thin wrapper
    138     # around a matrix). This should cover most cases.
    139     if isinstance(obj, (tuple, list)):
    140         from sage.matrix.matrix import is_Matrix
    141         from sage.modular.arithgroup.arithgroup_element import ArithmeticSubgroupElement
    142         if len(obj) > 0 and (is_Matrix(obj[0]) or isinstance(obj[0], ArithmeticSubgroupElement)):
    143             if _check_tall_list_and_print(out_stream, obj):
    144                 return
    145     print >>out_stream, `obj`
     168    s = format_obj(obj)
     169    if s is None:
     170        s = repr(obj)
     171    print >>out_stream, s
    146172
    147173def displayhook(obj):
    148174    """
  • sage/misc/interpreter.py

    diff --git a/sage/misc/interpreter.py b/sage/misc/interpreter.py
    a b  
    22Sage's IPython Modifications
    33
    44This module contains all of Sage's customizations to the IPython
    5 interpreter.  These changes consist of the following magjor components:
     5interpreter.  These changes consist of the following major components:
    66
    77  - :class:`SageTerminalApp`
    88  - :class:`SageInteractiveShell`
     
    1818  - Initialize the :class:`SageInteractiveShell`.
    1919
    2020  - Provide default configuration options for the shell, and its
    21     subcomponents.  These work with (and can be overrided by)
     21    subcomponents.  These work with (and can be overridden by)
    2222    IPython's configuration system.
    2323
    24   - Monkey-patch IPython in order to support Sage's customization when
    25     introspecting objects.
     24  - Load the Sage ipython extension (which does things like preparsing,
     25    add magics, etc.).
    2626
    2727  - Provide a custom :class:`SageCrashHandler` to give the user
    2828    instructions on how to report the crash to the Sage support
     
    4040The :class:`SageInteractiveShell` provides the following
    4141customizations:
    4242
    43   - Modifying the input before it is evaluated. This is done in
    44     :class:`SageInputSplitter`, which uses
    45     :class:`SagePromptTransformer`, :class:`SagePreparseTransformer`,
    46     :class:`LoadAttachTransformer`, and
    47     :class:`InterfaceMagicTransformer` to do the actual work.
    48 
    49   - Provide a number of IPython magic functions that work with Sage
    50     and its preparser.  See :meth:`~SageInteractiveShell.magic_timeit`,
    51     :meth:`~SageInteractiveShell.magic_prun`,
    52     :meth:`~SageInteractiveShell.magic_load`,
    53     :meth:`~SageInteractiveShell.magic_attach`, and
    54     :meth:`~SageInteractiveShell.magic_iload`.
    55 
    56   - Adding support for attached files.  See
    57     :meth:`~SageInteractiveShell.run_cell`.
    58 
    5943  - Cleanly deinitialize the Sage library before exiting.  See
    6044    :meth:`~SageInteractiveShell.ask_exit`.
    6145
     
    147131        sage: from sage.misc.interpreter import get_test_shell
    148132        sage: shell = get_test_shell()
    149133        sage: shell.run_cell('from sage.misc.interpreter import set_sage_prompt')
    150         sage: shell.run_cell('set_sage_prompt(u"new: ")')
     134        sage: shell.run_cell('set_sage_prompt(u"new")')
    151135        sage: shell.prompt_manager.in_template
    152136        u'new: '
    153         sage: shell.run_cell('set_sage_prompt(u"sage: ")')
     137        sage: shell.run_cell('set_sage_prompt(u"sage")')
    154138    """
    155139    ipython = get_ipython()
    156     ipython.prompt_manager.in_template = s
     140    ipython.prompt_manager.in_template = s+': '
    157141
    158142def sage_prompt():
    159143    """
     
    164148        sage: from sage.misc.interpreter import get_test_shell
    165149        sage: shell = get_test_shell()
    166150        sage: shell.run_cell('sage_prompt()')
    167         u'sage: '
     151        u'sage'
    168152    """
    169153    ipython = get_ipython()
    170     return ipython.prompt_manager.in_template
    171 
    172 ###############
    173 # Displayhook #
    174 ###############
    175 from IPython.core.displayhook import DisplayHook
    176 class SageDisplayHook(DisplayHook):
    177     """
    178     A replacement for ``sys.displayhook`` which correctly print lists
    179     of matrices.
    180 
    181     EXAMPLES::
    182 
    183         sage: from sage.misc.interpreter import SageDisplayHook, get_test_shell
    184         sage: shell = get_test_shell()
    185         sage: shell.displayhook
    186         <sage.misc.interpreter.SageDisplayHook object at 0x...>
    187         sage: shell.run_cell('a = identity_matrix(ZZ, 2); [a,a]')
    188         [
    189         [1 0]  [1 0]
    190         [0 1], [0 1]
    191         ]
    192     """
    193     def compute_format_data(self, result):
    194         r"""
    195         Computes the format data of ``result``.  If the
    196         :func:`sage.misc.displayhook.print_obj` writes a string, then
    197         we override IPython's :class:`DisplayHook` formatting.
    198 
    199         EXAMPLES::
    200 
    201             sage: from sage.misc.interpreter import get_test_shell
    202             sage: shell = get_test_shell()
    203             sage: shell.displayhook
    204             <sage.misc.interpreter.SageDisplayHook object at 0x...>
    205             sage: shell.displayhook.compute_format_data(2)
    206             {u'text/plain': '2'}
    207             sage: a = identity_matrix(ZZ, 2)
    208             sage: shell.displayhook.compute_format_data([a,a])
    209             {u'text/plain': '[\n[1 0]  [1 0]\n[0 1], [0 1]\n]'}
    210         """
    211         format_data = super(SageDisplayHook, self).compute_format_data(result)
    212 
    213         from cStringIO import StringIO
    214         s = StringIO()
    215         from sage.misc.displayhook import print_obj
    216         print_obj(s, result)
    217         if s:
    218             format_data['text/plain'] = s.getvalue().strip()
    219         return format_data
    220 
     154    return ipython.prompt_manager.in_template[:-2]
    221155
    222156####################
    223157# InteractiveShell #
     
    225159from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
    226160class SageInteractiveShell(TerminalInteractiveShell):
    227161
    228     # used by init_displayhook
    229     displayhook_class = Type(SageDisplayHook)
    230    
    231     # Input splitter, to split entire cells of input into either individual
    232     # interactive statements or whole blocks.
    233     input_splitter = Instance('sage.misc.interpreter.SageInputSplitter', (), {})
    234 
    235     def run_cell(self, *args, **kwds):
    236         r"""
    237         This method loads all modified attached files before executing
    238         any code.  Any arguments and keyword arguments are passed to
    239         :meth:`TerminalInteractiveShell.run_cell`.
    240 
    241         EXAMPLES::
    242 
    243             sage: import os
    244             sage: from sage.misc.interpreter import get_test_shell
    245             sage: from sage.misc.misc import tmp_dir
    246             sage: shell = get_test_shell()
    247             sage: tmp = os.path.join(tmp_dir(), 'run_cell.py')
    248             sage: f = open(tmp, 'w'); f.write('a = 2\n'); f.close()
    249             sage: shell.run_cell('%attach ' + tmp)
    250             sage: shell.run_cell('a')
    251             2
    252             sage: import time; time.sleep(1)
    253             sage: f = open(tmp, 'w'); f.write('a = 3\n'); f.close()
    254             sage: shell.run_cell('a')
    255             3
    256             sage: os.remove(tmp)
    257         """
    258         for f in modified_attached_files():
    259             super(SageInteractiveShell, self).run_cell('%%load "%s"'%f)
    260         return super(SageInteractiveShell, self).run_cell(*args, **kwds)
    261 
    262     def ask_exit(self):
    263         """
    264         We need to run the :func:`sage.all.quit_sage` function when we
    265         exit the shell.
    266 
    267         EXAMPLES:
    268 
    269         We install a fake :func:`sage.all.quit_sage`::
    270        
    271             sage: import sage.all
    272             sage: old_quit = sage.all.quit_sage
    273             sage: def new_quit(): print "Quitter!!!"
    274             sage: sage.all.quit_sage = new_quit
    275 
    276         Now, we can check to see that this method works::
    277        
    278             sage: from sage.misc.interpreter import get_test_shell
    279             sage: shell = get_test_shell()
    280             sage: shell.ask_exit()
    281             Quitter!!!
    282             sage: shell.exit_now
    283             True
    284 
    285         Clean up after ourselves::
    286 
    287             sage: shell.exit_now = False
    288             sage: sage.all.quit_sage = old_quit
    289         """
    290         from sage.all import quit_sage
    291         quit_sage()
    292         super(SageInteractiveShell, self).ask_exit()
    293 
    294162    def system_raw(self, cmd):
    295163        """
    296164        Adjust the libraries before calling system commands.  See Trac
     
    313181            if DARWIN_SYSTEM:
    314182                libraries += 'DYLD_LIBRARY_PATH=$$SAGE_ORIG_DYLD_LIBRARY_PATH;'
    315183            return super(SageInteractiveShell, self).system_raw(cmd)
    316    
    317     def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr'):
     184
     185    def ask_exit(self):
    318186        """
    319         Override ``interactivity``
     187        We need to run the :func:`sage.all.quit_sage` function when we
     188        exit the shell.
    320189
    321         EXAMPLES::
     190        EXAMPLES:
     191
     192        We install a fake :func:`sage.all.quit_sage`::
     193
     194            sage: import sage.all
     195            sage: old_quit = sage.all.quit_sage
     196            sage: def new_quit(): print "Quitter!!!"
     197            sage: sage.all.quit_sage = new_quit
     198
     199        Now, we can check to see that this method works::
    322200
    323201            sage: from sage.misc.interpreter import get_test_shell
    324202            sage: shell = get_test_shell()
    325             sage: shell.run_cell('for i in range(3): i')  # indirect doctest
    326             0
    327             1
    328             2
     203            sage: shell.ask_exit()
     204            Quitter!!!
     205            sage: shell.exit_now
     206            True
     207
     208        Clean up after ourselves::
     209
     210            sage: shell.exit_now = False
     211            sage: sage.all.quit_sage = old_quit
    329212        """
    330         super(SageInteractiveShell, self).run_ast_nodes(nodelist, cell_name, interactivity='all')
    331 
    332     #######################################
    333     # Magic functions
    334     #######################################
    335     def magic_timeit(self, s):
    336         """
    337         Runs :func:`sage_timeit` on the code s.  This is designed to
    338         be used from the command line as ``%timeit 2+2``.
    339 
    340         :param s: code to be timed
    341         :type s: string
    342 
    343         EXAMPLES::
    344 
    345             sage: from sage.misc.interpreter import get_test_shell
    346             sage: shell = get_test_shell()
    347             sage: shell.magic_timeit('2+2') #random output
    348             625 loops, best of 3: 525 ns per loop
    349             sage: shell.magic_timeit('2r+2r').__class__
    350             <class sage.misc.sage_timeit.SageTimeitResult at 0x...>
    351         """
    352         from sage.misc.sage_timeit import sage_timeit
    353         return sage_timeit(s, self.user_ns)
    354 
    355     def magic_prun(self, parameter_s='', **kwds):
    356         """
    357         Profiles the code contained in ``parameter_s``. This is
    358         designed to be used from the command line as ``%prun 2+2``.
    359 
    360         :param parameter_s: code to be profiled
    361         :type parameter_s: string
    362 
    363         EXAMPLES::
    364 
    365             sage: from sage.misc.interpreter import get_test_shell
    366             sage: shell = get_test_shell()
    367             sage: shell.magic_prun('2+2')
    368                      2 function calls in 0.000 seconds
    369             <BLANKLINE>
    370                Ordered by: internal time
    371             <BLANKLINE>
    372                ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    373                     1    0.000    0.000    0.000    0.000 <string>:1(<module>)
    374                     1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    375         """
    376         return super(SageInteractiveShell, self).magic_prun(parameter_s=preparse(parameter_s),
    377                                                             **kwds)
    378 
    379     def magic_load(self, s):
    380         r"""     
    381         Loads the code contained in the file ``s``. This is designed
    382         to be used from the command line as ``%load /path/to/file``.
    383 
    384         :param s: file to be loaded
    385         :type s: string
    386 
    387         EXAMPLES::
    388 
    389             sage: import os
    390             sage: from sage.misc.interpreter import get_test_shell
    391             sage: from sage.misc.misc import tmp_dir
    392             sage: shell = get_test_shell()
    393             sage: tmp = os.path.join(tmp_dir(), 'run_cell.py')
    394             sage: f = open(tmp, 'w'); f.write('a = 2\n'); f.close()
    395             sage: shell.magic_load(tmp)
    396             sage: shell.run_cell('a')
    397             2
    398         """
    399         from sage.misc.preparser import load_wrap
    400         return self.ex(load_wrap(s, attach=False))
    401 
    402     def magic_attach(self, s):
    403         r"""     
    404         Attaches the code contained in the file ``s``. This is
    405         designed to be used from the command line as
    406         ``%attach /path/to/file``.
    407 
    408         :param s: file to be attached
    409         :type s: string
    410 
    411         EXAMPLES::
    412 
    413             sage: import os
    414             sage: from sage.misc.interpreter import get_test_shell
    415             sage: from sage.misc.misc import tmp_dir
    416             sage: shell = get_test_shell()
    417             sage: tmp = os.path.join(tmp_dir(), 'run_cell.py')
    418             sage: f = open(tmp, 'w'); f.write('a = 2\n'); f.close()
    419             sage: shell.magic_attach(tmp)
    420             sage: shell.run_cell('a')
    421             2
    422             sage: import time; time.sleep(1)
    423             sage: f = open(tmp, 'a'); f.write('a = 3\n'); f.close()
    424             sage: shell.run_cell('a')
    425             3
    426         """
    427         from sage.misc.preparser import load_wrap
    428         return self.ex(load_wrap(s, attach=True))
    429 
    430     def magic_iload(self, s):
    431         """
    432         A magic command to interactively load a file as in MAGMA.
    433 
    434         :param s: the file to be interactively loaded
    435         :type s: string
    436 
    437         .. note::
    438 
    439             Currently, this cannot be completely doctested as it
    440             relies on :func:`raw_input`.
    441 
    442         EXAMPLES::
    443 
    444             sage: ip = get_ipython()           # not tested: works only in interactive shell
    445             sage: ip.magic_iload('/dev/null')  # not tested: works only in interactive shell
    446             Interactively loading "/dev/null"  # not tested: works only in interactive shell
    447         """
    448         try:
    449             name = str(eval(s))
    450         except Exception:
    451             name = s.strip()
    452 
    453         try:
    454             F = open(name)
    455         except IOError:
    456             raise ImportError, 'could not open file "%s"'%name
    457 
    458         #We need to update the execution count so that the history for the
    459         #iload command and the history for the first line of the loaded
    460         #file are not written to the history database with the same line
    461         #number (execution count).  This happens since the execution count
    462         #is updated only after the magic command is run.
    463         self.execution_count += 1
    464 
    465         print 'Interactively loading "%s"'%name
    466 
    467         # The following code is base on IPython's
    468         # InteractiveShell.interact,
    469         more = False
    470         for line in F.readlines():
    471             prompt = self.prompt_manager.render('in' if not more else 'in2', color=True)
    472             raw_input(prompt.encode('utf-8') + ' ' + line.rstrip())
    473 
    474             self.input_splitter.push(line)
    475             more = self.input_splitter.push_accepts_more()
    476             if not more:
    477                 source, source_raw = self.input_splitter.source_raw_reset()
    478                 self.run_cell(source_raw, store_history=True)
    479 
     213        from sage.all import quit_sage
     214        quit_sage()
     215        super(SageInteractiveShell, self).ask_exit()
    480216
    481217###################################################################
    482218# Transformers used in the SageInputSplitter
     
    489225    """
    490226    Preparse the line of code before it get evaluated by IPython.
    491227    """
    492     def __call__(self, line, line_number, block_start):
     228    def __call__(self, line, line_number):
    493229        """
    494230        Transform ``line``.
    495231
     
    497233
    498234        - ``line`` -- string. The line to be transformed.
    499235
    500         - ``line_number`` -- integer. The line number. For a single-line input, this is always zero.
    501        
    502         - ``block_start`` -- boolean. Whether the line is at the
    503           beginning of a new block.
    504 
    505236        OUTPUT:
    506237
    507238        A string, the transformed line.
     
    510241
    511242            sage: from sage.misc.interpreter import SagePreparseTransformer
    512243            sage: spt = SagePreparseTransformer()
    513             sage: spt('2', 0, False)
     244            sage: spt('2', 0)
    514245            'Integer(2)'
    515246            sage: preparser(False)
    516             sage: spt('2', 0, False)
     247            sage: spt('2', 0)
    517248            '2'
    518249            sage: preparser(True)
    519250        """
    520251        if do_preparse and not line.startswith('%'):
    521             return preparse(line)
     252            # we use preparse_file instead of just preparse because preparse_file
     253            # automatically prepends attached files
     254            return preparse(line, reset=(line_number==0))
    522255        else:
    523256            return line
    524257
    525 class LoadAttachTransformer():
     258class MagicTransformer():
    526259    r"""
    527260    Handle input lines that start out like ``load ...`` or ``attach
    528261    ...``.
     
    532265    into ``%load ...`` and ``%attach ...``, respectively.  Thus, we
    533266    have to do it manually.
    534267    """
    535     def __call__(self, line, line_number, block_start):
     268    deprecations = {'load': '%runfile',
     269                    'attach': '%attach',
     270                    'time': '%time'}
     271    def __call__(self, line, line_number):
    536272        """
    537273        Transform ``line``.
    538274
     
    540276
    541277        - ``line`` -- string. The line to be transformed.
    542278
    543         - ``line_number`` -- integer. The line number. For a single-line input, this is always zero.
    544        
    545         - ``block_start`` -- boolean. Whether the line is at the
    546           beginning of a new block.
    547 
    548279        OUTPUT:
    549280
    550281        A string, the transformed line.
    551282
    552283        EXAMPLES::
    553284
    554             sage: from sage.misc.interpreter import get_test_shell, LoadAttachTransformer
    555             sage: lat = LoadAttachTransformer()
    556             sage: lat('load /path/to/file', 0, False)
    557             '%load /path/to/file'
    558             sage: lat('attach /path/to/file', 0, False)
     285            sage: from sage.misc.interpreter import get_test_shell, MagicTransformer
     286            sage: mt = MagicTransformer()
     287            sage: mt('load /path/to/file', 0)
     288            doctest:1: DeprecationWarning: Use %runfile instead of load.
     289            See http://trac.sagemath.org/12719 for details.
     290            '%runfile /path/to/file'
     291            sage: mt('attach /path/to/file', 0)
     292            doctest:1: DeprecationWarning: Use %attach instead of attach.
     293            See http://trac.sagemath.org/12719 for details.
    559294            '%attach /path/to/file'
     295            sage: mt('time 1+2', 0)
     296            doctest:1: DeprecationWarning: Use %time instead of time.
     297            See http://trac.sagemath.org/12719 for details.
     298            '%time 1+2'
    560299        """
    561         if line_number>0:
    562             return line
    563         for cmd in ['load', 'attach']:
    564             if line.startswith(cmd + ' '):
    565                 return '%' + line
     300        for old,new in self.deprecations.items():
     301            if line.startswith(old+' '):
     302                from sage.misc.superseded import deprecation
     303                deprecation(12719, 'Use %s instead of %s.'%(new,old))
     304                return new+line[len(old):]
    566305        return line
    567    
     306
    568307class SagePromptTransformer():
    569308    """
    570     Remove Sage prompts from the imput line.
     309    Remove Sage prompts from the input line.
    571310    """
    572311    _sage_prompt_re = re.compile(r'(^[ \t]*sage: |^[ \t]*\.+:? )+')
    573312
    574     def __call__(self, line, line_number, block_start):
     313    def __call__(self, line, line_number):
    575314        """
    576315        Transform ``line``.
    577316
     
    579318
    580319        - ``line`` -- string. The line to be transformed.
    581320
    582         - ``line_number`` -- integer. The line number. For a single-line input, this is always zero.
    583        
    584         - ``block_start`` -- boolean. Whether the line is at the
    585           beginning of a new block.
    586 
    587321        OUTPUT:
    588322
    589323        A string, the transformed line.
     
    592326
    593327            sage: from sage.misc.interpreter import SagePromptTransformer
    594328            sage: spt = SagePromptTransformer()
    595             sage: spt("sage: sage: 2 + 2", 0, False)
     329            sage: spt("sage: sage: 2 + 2", 0)
    596330            '2 + 2'
    597             sage: spt('', 0, False)
     331            sage: spt('', 0)
    598332            ''
    599             sage: spt("      sage: 2+2", 0, False)
     333            sage: spt("      sage: 2+2", 0)
    600334            '2+2'
    601             sage: spt("      ... 2+2", 0, False)
     335            sage: spt("      ... 2+2", 0)
    602336            '2+2'
    603337        """
    604338        if not line or line.isspace() or line.strip() == '...':
     
    614348                break
    615349        return line
    616350
    617 class InterfaceMagicTransformer():
     351class SagePromptDedenter():
    618352    """
    619     This transformer is for handling commands like ``%maxima`` to
    620     switch to a Maxima shell.
     353    Remove leading spaces from the input line.
    621354    """
    622     _magic_command_re = re.compile(r"get_ipython\(\).magic\(u'([^\d\W]\w+)'\)", re.UNICODE)
    623 
    624     def interfaces(self):
    625         """
    626         Return the list of interfaces
    627 
    628         OUTPUT:
    629 
    630         A list of stings.
    631 
    632         EXAMPLES::
    633 
    634             sage: from sage.misc.interpreter import InterfaceMagicTransformer
    635             sage: imt = InterfaceMagicTransformer()
    636             sage: imt.interfaces()
    637             ['LiE', 'Lisp', 'MuPAD', 'axiom', 'fricas', 'gap', 'gap3', 'giac',
    638              'kash', 'macaulay2', 'magma', 'maple', 'mathematica', 'matlab',
    639              'maxima', 'mwrank', 'octave', 'pari', 'r', 'sage', 'scilab', 'singular']
    640         """
    641         if '_interfaces' in self.__dict__:
    642             return self._interfaces
    643         import sage.interfaces
    644         self._interfaces = sorted([ obj.name()
    645                                     for obj in sage.interfaces.all.__dict__.values()
    646                                     if isinstance(obj, sage.interfaces.interface.Interface) ])
    647         return self._interfaces
    648 
    649     def __call__(self, line, line_number, block_start):
     355    def __call__(self, line, line_number):
    650356        """
    651357        Transform ``line``.
    652358
     
    656362
    657363        - ``line_number`` -- integer. The line number. For a single-line input, this is always zero.
    658364       
    659         - ``block_start`` -- boolean. Whether the line is at the
    660           beginning of a new block.
    661 
    662         OUTPUT:
    663 
    664         A string, the transformed line.
    665 
    666         EXAMPLES::
    667 
    668             sage: from sage.misc.interpreter import InterfaceMagicTransformer
    669             sage: imt = InterfaceMagicTransformer()
    670             sage: imt('%maxima', 0, False)
    671             'maxima.interact()'
    672             sage: imt('%prun', 0, False)
    673             '%prun'
    674         """
    675         if line_number>0:
    676             return line
    677         if line.startswith('%'):
    678             interface = line[1:].strip()
    679             if interface in self.interfaces():
    680                 return interface + '.interact()'
    681         return line
    682 
    683 class SagePromptDedenter():
    684     """
    685     Remove leading spaces from the imput line.
    686     """
    687     def __call__(self, line, line_number, block_start):
    688         """
    689         Transform ``line``.
    690 
    691         INPUT:
    692 
    693         - ``line`` -- string. The line to be transformed.
    694 
    695         - ``line_number`` -- integer. The line number. For a single-line input, this is always zero.
    696        
    697         - ``block_start`` -- boolean. Whether the line is at the
    698           beginning of a new block.
    699 
    700365        OUTPUT:
    701366
    702367        A string, the transformed line.
     
    705370
    706371            sage: from sage.misc.interpreter import SagePromptDedenter
    707372            sage: spd = SagePromptDedenter()
    708             sage: spd('  1 + \\', 0, False)
     373            sage: spd('  1 + \\', 0)
    709374            '1 + \\'
    710             sage: spd('  2',     1, False)
     375            sage: spd('  2', 1)
    711376            '2'
    712             sage: spd('3',     2, False)   # try our best with incorrect indentation
     377            sage: spd('3', 2)   # try our best with incorrect indentation
    713378            '3'
    714379        """
    715380        if line_number == 0:
     
    720385            dedent = min(len(line)-len(line.lstrip()), self._dedent)
    721386            return line[dedent:]
    722387
    723 ###################################################################
    724 # Input Splitter
    725 ###################################################################
    726 # the main entry point for input handling in Sage
    727 
    728 from IPython.core.inputsplitter import InputSplitter
    729 class SageInputSplitter(InputSplitter):
    730     """
    731     An input splitter for Sage syntax
    732     """
    733     # Whether a multi-line input is complete, i.e. line = empty line at the end
    734     _is_complete = False
    735 
    736     # String with raw, untransformed input.
    737     source_raw = ''
    738 
    739     ### Private attributes
    740     # List with lines of raw input accumulated so far.
    741     _buffer_raw = None
    742     _magic_interfaces = []
    743     cell_magic_parts = None
    744    
    745     def __init__(self, input_mode=None):
    746         """
    747         The Python constructor
    748        
    749         TESTS::
    750        
    751             sage: from sage.misc.interpreter import SageInputSplitter
    752             sage: SageInputSplitter()
    753             <sage.misc.interpreter.SageInputSplitter object at 0x...>
    754         """
    755         InputSplitter.__init__(self, input_mode)
    756         self._buffer_raw = []
    757         self._transforms = [
    758             SagePromptDedenter(),
    759             SagePromptTransformer(),
    760             InterfaceMagicTransformer(),
    761             LoadAttachTransformer(),
    762             SagePreparseTransformer() ]
    763          
    764     def reset(self):
    765         """
    766         Reset the input buffer and associated state.
    767 
    768         EXAMPLES::
    769  
    770             sage: from sage.misc.interpreter import SageInputSplitter
    771             sage: sis = SageInputSplitter()
    772             sage: sis.push('1')
    773             True
    774             sage: sis._buffer
    775             [u'Integer(1)\n']
    776             sage: sis.reset()
    777             sage: sis._buffer
    778             []
    779         """
    780         # print 'SageInputSplitter.reset buf = '+str(self._buffer)
    781         InputSplitter.reset(self)
    782         self._buffer_raw[:] = []
    783         self.source_raw = ''
    784 
    785     def source_raw_reset(self):
    786         """
    787         Return input and raw source and perform a full reset.
    788 
    789         EXAMPLES::
    790  
    791             sage: from sage.misc.interpreter import SageInputSplitter
    792             sage: sis = SageInputSplitter()
    793             sage: sis.push('1')
    794             True
    795             sage: sis._buffer
    796             [u'Integer(1)\n']
    797             sage: sis.source_raw_reset()
    798             (u'Integer(1)\n', u'1\n')
    799             sage: sis._buffer
    800             []
    801         """
    802         # print 'SageInputSplitter.source_raw_reset'
    803         out = self.source
    804         out_r = self.source_raw
    805         self.reset()
    806         return out, out_r
    807 
    808     def push(self, lines):
    809         """
    810         Push one or more lines of Sage input.
    811 
    812         This is mostly copy & paste from IPython, but with different transformers
    813        
    814         EXAMPLES::
    815 
    816             sage: from sage.misc.interpreter import SageInputSplitter
    817             sage: sis = SageInputSplitter()
    818             sage: sis._buffer
    819             []
    820             sage: sis.push('1')
    821             True
    822             sage: sis._buffer
    823             [u'Integer(1)\n']
    824         """
    825         # print 'SageInputSplitter.push '+lines+' ('+str(len(self._buffer))+')'  # dbg
    826 
    827         if not lines:
    828             return super(SageInputSplitter, self).push(lines)
    829 
    830         # We must ensure all input is pure unicode
    831         lines = cast_unicode(lines, self.encoding)
    832         lines_list = lines.splitlines()
    833 
    834         # Transform logic
    835         #
    836         # We only apply the line transformers to the input if we have either no
    837         # input yet, or complete input, or if the last line of the buffer ends
    838         # with ':' (opening an indented block).  This prevents the accidental
    839         # transformation of escapes inside multiline expressions like
    840         # triple-quoted strings or parenthesized expressions.
    841         #
    842         # The last heuristic, while ugly, ensures that the first line of an
    843         # indented block is correctly transformed.
    844         #
    845         # FIXME: try to find a cleaner approach for this last bit.
    846         # If we were in 'block' mode, since we're going to pump the parent
    847         # class by hand line by line, we need to temporarily switch out to
    848         # 'line' mode, do a single manual reset and then feed the lines one
    849         # by one.  Note that this only matters if the input has more than one
    850         # line.
    851         saved_input_mode = None
    852         if self.input_mode != 'line':
    853             saved_input_mode = self.input_mode
    854             self.reset()
    855             self.input_mode = 'line'
    856 
    857         # Store raw source before applying any transformations to it.  Note
    858         # that this must be done *after* the reset() call that would otherwise
    859         # flush the buffer.
    860         self._store(lines, self._buffer_raw, 'source_raw')
    861        
    862         push = super(SageInputSplitter, self).push
    863         buf = self._buffer
    864         try:
    865             for line in lines_list:
    866                 line_number = len(buf)
    867                 block_start = self._is_complete or not buf or \
    868                     (buf and (buf[-1].rstrip().endswith(':') or
    869                               buf[-1].rstrip().endswith(',')) )
    870                 for f in self._transforms:
    871                     line = f(line, line_number, block_start)
    872                 out = push(line)
    873         finally:
    874             if saved_input_mode is not None:
    875                 self.input_mode = saved_input_mode
    876         return out
    877 
    878 
    879388###################
    880389# Interface shell #
    881390###################
    882391from IPython.core.prefilter import PrefilterTransformer
    883392from IPython.frontend.terminal.embed import InteractiveShellEmbed
    884393from IPython import Config
    885            
     394
    886395class InterfaceShellTransformer(PrefilterTransformer):
    887396    priority = 50
    888397    def __init__(self, *args, **kwds):
     
    1043552    try:
    1044553        cfg = Config(get_ipython().config)
    1045554    except NameError:
    1046         cfg = Config(SageTerminalApp.DEFAULT_SAGE_CONFIG)
     555        cfg = Config(DEFAULT_SAGE_CONFIG)
    1047556    cfg.PromptManager['in_template'] = interface.name() + ': '
    1048557
    1049558    ipshell = InteractiveShellEmbed(config=cfg,
     
    1067576    Returns a IPython shell that can be used in testing the functions
    1068577    in this module.
    1069578
    1070     :keyword sage_ext: load the Sage extension
    1071     :type sage_ext: bool
    1072579    :returns: an IPython shell
    1073580
    1074581    EXAMPLES::
     
    1077584        sage: shell = get_test_shell(); shell
    1078585        <sage.misc.interpreter.SageInteractiveShell object at 0x...>
    1079586    """
    1080     app = SageTerminalApp.instance()
     587    app = SageTerminalApp.instance(config=DEFAULT_SAGE_CONFIG)
    1081588    app.test_shell = True
    1082589    if app.shell is None:
    1083590        app.initialize()
     
    1117624            app, contact_name, contact_email, bug_tracker, show_crash_traceback=False)
    1118625        self.crash_report_fname = 'Sage_crash_report.txt'
    1119626
     627DEFAULT_SAGE_CONFIG = Config(PromptManager = Config(in_template = 'sage: ',
     628                                                    in2_template = '....: ',
     629                                                    justify = False,
     630                                                    out_template = ''),
     631                            TerminalIPythonApp = Config(display_banner = False,
     632                                                        verbose_crash = True),
     633                            TerminalInteractiveShell = Config(ast_node_interactivity = 'all',
     634                                                              colors = 'NoColor',
     635                                                              confirm_exit = False,
     636                                                              separate_in = ''),
     637                            # The extension is *always* loaded for SageTerminalApp
     638                            # See the code for SageTerminalApp.init_shell
     639                            #InteractiveShellApp = Config(extensions=['sage.misc.sage_extension']),
     640    )
     641
    1120642class SageTerminalApp(TerminalIPythonApp):
    1121643    name = u'Sage'
    1122644    crash_handler_class = SageCrashHandler
    1123     verbose_crash = True   # Needed to use Sage Crash Handler
    1124     display_banner = False
    1125645    test_shell = False
    1126    
    1127     DEFAULT_SAGE_CONFIG = Config(
    1128         {'PromptManager':    {'in_template':  u'sage: ',
    1129                               'in2_template': u'....: ',
    1130                               'out_template': u'',
    1131                               'justify':      False},
    1132          'InteractiveShell': {'separate_in':  u'',
    1133                               'autoindent':   True,
    1134                               'confirm_exit': False,
    1135                               'colors':       'NoColor'},
    1136          })
     646
     647    def __init__(self, **kwargs):
     648        # Overwrite the default Sage configuration with the user's.
     649        new_config = Config()
     650        new_config._merge(DEFAULT_SAGE_CONFIG)
     651        new_config._merge(kwargs.get('config', Config()))
     652        kwargs['config']=new_config
     653        super(SageTerminalApp, self).__init__(**kwargs)
     654
    1137655
    1138656    def init_shell(self):
    1139657        r"""
     
    1141659        Additionally, this also does the following:
    1142660
    1143661          - Merges the default shell configuration with the user's.
    1144          
    1145           - Monkey-patch :mod:`IPython.core.oinspect` to add Sage
    1146             introspection functions.
    1147662
    1148           - Run additional Sage startup code.
    1149          
    1150663        .. note::
    1151664
    1152665            This code is based on
     
    1154667
    1155668        EXAMPLES::
    1156669
    1157             sage: from sage.misc.interpreter import SageTerminalApp
    1158             sage: app = SageTerminalApp.instance()
     670            sage: from sage.misc.interpreter import SageTerminalApp, DEFAULT_SAGE_CONFIG
     671            sage: app = SageTerminalApp(config=DEFAULT_SAGE_CONFIG)
    1159672            sage: app.initialize() #indirect doctest
    1160673            sage: app.shell
    1161674            <sage.misc.interpreter.SageInteractiveShell object at 0x...>
    1162675        """
    1163         import sys
    1164         sys.path.insert(0, '')
     676        # We need verbose crashes for the Sage crash handler.  We set it here
     677        # so that we don't overwrite the traitlet attribute
     678        self.verbose_crash = True
    1165679
    1166         # Overwrite the default Sage configuration with the user's.
    1167         new_config = Config()
    1168         new_config._merge(self.DEFAULT_SAGE_CONFIG)
    1169         new_config._merge(self.config)
     680        # what is the purpose behind this??
     681        os.chdir(os.environ["CUR"])
    1170682
    1171683        # Shell initialization
    1172         self.shell = SageInteractiveShell.instance(config=new_config,
     684        self.shell = SageInteractiveShell.instance(config=self.config,
    1173685                        display_banner=False, profile_dir=self.profile_dir,
    1174686                        ipython_dir=self.ipython_dir)
    1175687        self.shell.configurables.append(self)
    1176 
    1177 
    1178         # Ideally, these would just be methods of the Inspector class
    1179         # that we could override; however, IPython looks them up in
    1180         # the global :class:`IPython.core.oinspect` module namespace.
    1181         # Thus, we have to monkey-patch.
    1182         import sagedoc, sageinspect, IPython.core.oinspect
    1183         IPython.core.oinspect.getdoc = sageinspect.sage_getdoc #sagedoc.my_getdoc
    1184         IPython.core.oinspect.getsource = sagedoc.my_getsource
    1185         IPython.core.oinspect.getargspec = sageinspect.sage_getargspec
    1186 
    1187         from sage.misc.edit_module import edit_devel
    1188         self.shell.set_hook('editor', edit_devel)
    1189 
    1190         # Additional initalization code
    1191         preparser(True)
    1192         os.chdir(os.environ["CUR"])
    1193 
    1194         from sage.misc.misc import branch_current_hg_notice, branch_current_hg
    1195         branch = branch_current_hg_notice(branch_current_hg())
    1196         if branch and self.test_shell is False:
    1197             print branch
    1198            
    1199         try:
    1200             self.shell.ex('from sage.all import Integer, RealNumber')
    1201         except Exception:
    1202             import traceback
    1203             print "Error importing the Sage library"
    1204             traceback.print_exc()
    1205             print
    1206             print "To debug this, you can run:"
    1207             print 'sage -ipython -i -c "import sage.all"'
    1208             print 'and then type "%debug" to enter the interactive debugger'
    1209             sys.exit(1)
    1210 
    1211         self.shell.push(dict(sage_prompt=sage_prompt))
    1212 
    1213         if os.environ.get('SAGE_IMPORTALL', 'yes') != 'yes':
    1214             return
    1215 
    1216         self.shell.ex('from sage.all_cmdline import *')
    1217         startup_file = os.environ.get('SAGE_STARTUP_FILE', '')
    1218        
    1219         if os.path.exists(startup_file):
    1220             self.shell.run_cell('%%load "%s"'%startup_file)
    1221 
     688        self.shell.extension_manager.load_extension('sage.misc.sage_extension')
  • sage/misc/preparser.py

    diff --git a/sage/misc/preparser.py b/sage/misc/preparser.py
    a b  
    11451145load_debug_mode = False
    11461146attach_debug_mode = True
    11471147
    1148 def preparse_file(contents, globals=None, numeric_literals=True):
     1148def load_attached():
     1149    contents = ""
     1150    for F, tm in attached.iteritems():
     1151        new_tm = os.path.getmtime(F)
     1152        if os.path.exists(F) and new_tm > tm:
     1153            contents += load_wrap(F, attach=True)
     1154    return contents
     1155
     1156
     1157def preparse_file(contents, globals=None, numeric_literals=True, run_attached=True):
    11491158    """
    11501159    Preparses input, attending to numeric literals and load/attach
    11511160    file directives.
     
    11801189    """
    11811190    if globals is None: globals = {}
    11821191   
    1183     if not isinstance(contents, str):
     1192    if not isinstance(contents, basestring):
    11841193        raise TypeError, "contents must be a string"
    11851194
    1186     assert isinstance(contents, str)
     1195    assert isinstance(contents, basestring)
    11871196
    11881197    # Reload attached files that have changed
    1189     for F, tm in attached.iteritems():
    1190         new_tm = os.path.getmtime(F)
    1191         if os.path.exists(F) and new_tm > tm:
    1192             contents = 'attach "%s"\n'%F + contents
     1198    if run_attached:
     1199        for F, tm in attached.iteritems():
     1200            new_tm = os.path.getmtime(F)
     1201            if os.path.exists(F) and new_tm > tm:
     1202                contents = ' "%s"\n'%F + contents
     1203
    11931204   
    11941205    # We keep track of which files have been loaded so far
    11951206    # in order to avoid a recursive load that would result
     
    16011612    out.write("# -*- coding: utf-8 -*-\n")
    16021613    return contents
    16031614   
    1604 def preparse_file_named_to_stream(name, out):
     1615def preparse_file_named_to_stream(name, out, run_attached=True):
    16051616    r"""
    16061617    Preparse file named \code{name} (presumably a .sage file), outputting to
    16071618    stream \code{out}.
     
    16121623    os.chdir(dir)
    16131624    contents = open(name).read()
    16141625    contents = handle_encoding_declaration(contents, out)
    1615     parsed = preparse_file(contents)
     1626    parsed = preparse_file(contents, run_attached=run_attached)
    16161627    os.chdir(cur)
    16171628    out.write("# -*- encoding: utf-8 -*-\n")
    16181629    out.write('#'*70+'\n')
     
    16201631    out.write('#'*70+'\n')
    16211632    out.write(parsed)
    16221633
    1623 def preparse_file_named(name):
     1634def preparse_file_named(name, run_attached=True):
    16241635    r"""
    16251636    Preparse file named \code{name} (presumably a .sage file), outputting to a
    16261637    temporary file.  Returns name of temporary file.
     
    16291640    name = os.path.abspath(name)
    16301641    tmpfilename = os.path.abspath(sage.misc.misc.tmp_filename(name) + ".py")
    16311642    out = open(tmpfilename,'w')
    1632     preparse_file_named_to_stream(name, out)
     1643    preparse_file_named_to_stream(name, out, run_attached=run_attached)
    16331644    out.close()
    16341645    return tmpfilename
    16351646
     
    18081819            # code snippets. Use preparse_file_named to make
    18091820            # the file name appear in the traceback as well.
    18101821            # See Trac 11812.
    1811             execfile(preparse_file_named(fpath), globals)
     1822            execfile(preparse_file_named(fpath, run_attached=False), globals)
    18121823        else:
    18131824            # Preparse in memory only for speed.
    1814             exec(preparse_file(open(fpath).read()) + "\n", globals)
     1825            exec(preparse_file(open(fpath).read(), run_attached=False) + "\n", globals)
    18151826    elif fpath.endswith('.spyx') or fpath.endswith('.pyx'):
    18161827        exec(load_cython(fpath), globals)
    18171828    elif fpath.endswith('.m'):
  • new file sage/misc/sage_extension.py

    diff --git a/sage/misc/sage_extension.py b/sage/misc/sage_extension.py
    new file mode 100644
    - +  
     1"""
     2A Sage extension which adds sage-specific features:
     3
     4* magics
     5  - %loadfile
     6  - %attach
     7  - %mode (like %maxima, etc.)
     8* preparsing of input
     9  - also make runfile and attach magics so that the '%' is optional, but encouraged
     10* loading Sage library
     11* running init.sage
     12* changing prompt to Sage prompt
     13* Display hook
     14"""
     15
     16from IPython.core.hooks import TryNext
     17from IPython.core.magic import Magics, magics_class, line_magic
     18from IPython.core.plugin import Plugin
     19import os
     20import sys
     21import sage
     22import sage.all
     23from sage.misc.interpreter import preparser
     24from sage.misc.preparser import preparse
     25
     26@magics_class
     27class SageMagics(Magics):
     28
     29    @line_magic
     30    def runfile(self, s):
     31        r"""     
     32        Loads the code contained in the file ``s``. This is designed
     33        to be used from the command line as ``%runfile /path/to/file``.
     34
     35        :param s: file to be loaded
     36        :type s: string
     37
     38        EXAMPLES::
     39
     40            sage: import os
     41            sage: from sage.misc.interpreter import get_test_shell
     42            sage: from sage.misc.misc import tmp_dir
     43            sage: shell = get_test_shell()
     44            sage: tmp = os.path.join(tmp_dir(), 'run_cell.py')
     45            sage: f = open(tmp, 'w'); f.write('a = 2\n'); f.close()
     46            sage: shell.run_cell('%runfile '+tmp)
     47            sage: shell.run_cell('a')
     48            2
     49        """
     50        from sage.misc.preparser import load_wrap
     51        return self.shell.ex(load_wrap(s, attach=False))
     52
     53    @line_magic
     54    def attach(self, s):
     55        r"""     
     56        Attaches the code contained in the file ``s``. This is
     57        designed to be used from the command line as
     58        ``%attach /path/to/file``.
     59
     60        :param s: file to be attached
     61        :type s: string
     62
     63        EXAMPLES::
     64
     65            sage: import os
     66            sage: from sage.misc.interpreter import get_test_shell
     67            sage: shell = get_test_shell()
     68            sage: tmp = os.path.normpath(os.path.join(SAGE_TMP, 'run_cell.py'))
     69            sage: f = open(tmp, 'w'); f.write('a = 2\n'); f.close()
     70            sage: shell.run_cell('%attach ' + tmp)
     71            sage: shell.run_cell('a')
     72            2
     73            sage: import time; time.sleep(1)
     74            sage: f = open(tmp, 'w'); f.write('a = 3\n'); f.close()
     75            sage: shell.run_cell('a')
     76            3
     77            sage: shell.run_cell('detach(%r)'%tmp)
     78            sage: shell.run_cell('attached_files()')
     79            []
     80            sage: os.remove(tmp)
     81        """
     82        from sage.misc.preparser import load_wrap
     83        return self.shell.ex(load_wrap(s, attach=True))
     84
     85    def pre_run_code_hook(self, ip):
     86        """
     87        Load the attached files (if needed) before running some code.
     88
     89        The examples are from the %attach magic.
     90
     91        EXAMPLES::
     92
     93            sage: import os
     94            sage: from sage.misc.interpreter import get_test_shell
     95            sage: shell = get_test_shell()
     96            sage: tmp = os.path.normpath(os.path.join(SAGE_TMP, 'run_cell.py'))
     97            sage: f = open(tmp, 'w'); f.write('a = 2\n'); f.close()
     98            sage: shell.run_cell('%attach ' + tmp)
     99            sage: shell.run_cell('a')
     100            2
     101            sage: import time; time.sleep(1)
     102            sage: f = open(tmp, 'w'); f.write('a = 3\n'); f.close()
     103            sage: shell.run_cell('a')
     104            3
     105            sage: shell.run_cell('detach(%r)'%tmp)
     106            sage: shell.run_cell('attached_files()')
     107            []
     108            sage: os.remove(tmp)
     109        """
     110        from sage.misc.preparser import load_attached
     111        s=load_attached()
     112        if s:
     113            self.shell.ex(s)
     114        raise TryNext
     115
     116    @line_magic
     117    def iload(self, s):
     118        """
     119        A magic command to interactively load a file as in MAGMA.
     120
     121        :param s: the file to be interactively loaded
     122        :type s: string
     123
     124        .. note::
     125
     126            Currently, this cannot be completely doctested as it
     127            relies on :func:`raw_input`.
     128
     129        EXAMPLES::
     130
     131            sage: ip = get_ipython()           # not tested: works only in interactive shell
     132            sage: ip.magic_iload('/dev/null')  # not tested: works only in interactive shell
     133            Interactively loading "/dev/null"  # not tested: works only in interactive shell
     134        """
     135        try:
     136            name = str(eval(s))
     137        except Exception:
     138            name = s.strip()
     139
     140        try:
     141            F = open(name)
     142        except IOError:
     143            raise ImportError, 'could not open file "%s"'%name
     144
     145
     146        shell = self.shell
     147
     148        #We need to update the execution count so that the history for the
     149        #iload command and the history for the first line of the loaded
     150        #file are not written to the history database with the same line
     151        #number (execution count).  This happens since the execution count
     152        #is updated only after the magic command is run.
     153        shell.execution_count += 1
     154
     155        print 'Interactively loading "%s"'%name
     156
     157        # The following code is base on IPython's
     158        # InteractiveShell.interact,
     159        more = False
     160        for line in F.readlines():
     161            prompt = shell.prompt_manager.render('in' if not more else 'in2', color=True)
     162            raw_input(prompt.encode('utf-8') + line.rstrip())
     163
     164            shell.input_splitter.push(line)
     165            more = shell.input_splitter.push_accepts_more()
     166            if not more:
     167                source, source_raw = shell.input_splitter.source_raw_reset()
     168                shell.run_cell(source_raw, store_history=True)
     169
     170from IPython.core.formatters import PlainTextFormatter
     171class SagePlainTextFormatter(PlainTextFormatter):
     172    """
     173    A replacement for the plain text formatter which correctly print lists
     174    of matrices.
     175
     176    EXAMPLES::
     177
     178        sage: from sage.misc.interpreter import get_test_shell
     179        sage: shell = get_test_shell()
     180        sage: shell.display_formatter.formatters['text/plain']
     181        <...sage_extension.SagePlainTextFormatter object at 0x...>
     182        sage: shell.run_cell('a = identity_matrix(ZZ, 2); [a,a]')
     183        [
     184        [1 0]  [1 0]
     185        [0 1], [0 1]
     186        ]
     187    """
     188    def __call__(self, obj):
     189        r"""
     190        Computes the format data of ``result``.  If the
     191        :func:`sage.misc.displayhook.format_obj` writes a string, then
     192        we override IPython's :class:`DisplayHook` formatting.
     193
     194        EXAMPLES::
     195
     196            sage: from sage.misc.interpreter import get_test_shell
     197            sage: shell = get_test_shell()
     198            sage: shell.display_formatter.formatters['text/plain']
     199            <...sage_extension.SagePlainTextFormatter object at 0x...>
     200            sage: shell.displayhook.compute_format_data(2)
     201            {u'text/plain': '2'}
     202            sage: a = identity_matrix(ZZ, 2)
     203            sage: shell.displayhook.compute_format_data([a,a])
     204            {u'text/plain': '[\n[1 0]  [1 0]\n[0 1], [0 1]\n]'}
     205        """
     206        import sage
     207        from sage.misc.displayhook import format_obj
     208        s = format_obj(obj)
     209        if s is None:
     210            s = super(SagePlainTextFormatter, self).__call__(obj)
     211        return s
     212
     213
     214# SageInputSplitter:
     215#  Hopefully most or all of this code can go away when
     216#  https://github.com/ipython/ipython/issues/2293 is resolved
     217#  apparently we will have stateful transformations then.
     218#  see also https://github.com/ipython/ipython/pull/2402
     219from IPython.core.inputsplitter import (transform_ipy_prompt, transform_classic_prompt,
     220                                        transform_help_end, transform_escaped,
     221                                        transform_assign_system, transform_assign_magic,
     222                                        cast_unicode,
     223                                        IPythonInputSplitter)
     224
     225def first_arg(f):
     226    def tm(arg1, arg2):
     227        return f(arg1)
     228    return tm
     229
     230class SageInputSplitter(IPythonInputSplitter):
     231    """
     232    We override the input splitter for two reasons:
     233
     234    1. to make the list of transforms a class attribute that can be modified
     235
     236    2. to pass the line number to transforms (we strip the line number off for IPython transforms)
     237    """
     238
     239    # List of input transforms to apply
     240    transforms = map(first_arg, [transform_ipy_prompt, transform_classic_prompt,
     241                                 transform_help_end, transform_escaped,
     242                                 transform_assign_system, transform_assign_magic])
     243
     244    # a direct copy of the IPython splitter, except that the
     245    # transforms are called with the line numbers, and the transforms come from the class attribute
     246    def push(self, lines):
     247        """Push one or more lines of IPython input.
     248
     249        This stores the given lines and returns a status code indicating
     250        whether the code forms a complete Python block or not, after processing
     251        all input lines for special IPython syntax.
     252
     253        Any exceptions generated in compilation are swallowed, but if an
     254        exception was produced, the method returns True.
     255
     256        Parameters
     257        ----------
     258        lines : string
     259          One or more lines of Python input.
     260
     261        Returns
     262        -------
     263        is_complete : boolean
     264          True if the current input source (the result of the current input
     265        plus prior inputs) forms a complete Python execution block.  Note that
     266        this value is also stored as a private attribute (_is_complete), so it
     267        can be queried at any time.
     268        """
     269        if not lines:
     270            return super(IPythonInputSplitter, self).push(lines)
     271
     272        # We must ensure all input is pure unicode
     273        lines = cast_unicode(lines, self.encoding)
     274
     275        # If the entire input block is a cell magic, return after handling it
     276        # as the rest of the transformation logic should be skipped.
     277        if lines.startswith('%%') and not \
     278          (len(lines.splitlines()) == 1 and lines.strip().endswith('?')):
     279            return self._handle_cell_magic(lines)
     280
     281        # In line mode, a cell magic can arrive in separate pieces
     282        if self.input_mode == 'line' and self.processing_cell_magic:
     283            return self._line_mode_cell_append(lines)
     284
     285        # The rest of the processing is for 'normal' content, i.e. IPython
     286        # source that we process through our transformations pipeline.
     287        lines_list = lines.splitlines()
     288
     289        # Transform logic
     290        #
     291        # We only apply the line transformers to the input if we have either no
     292        # input yet, or complete input, or if the last line of the buffer ends
     293        # with ':' (opening an indented block).  This prevents the accidental
     294        # transformation of escapes inside multiline expressions like
     295        # triple-quoted strings or parenthesized expressions.
     296        #
     297        # The last heuristic, while ugly, ensures that the first line of an
     298        # indented block is correctly transformed.
     299        #
     300        # FIXME: try to find a cleaner approach for this last bit.
     301
     302        # If we were in 'block' mode, since we're going to pump the parent
     303        # class by hand line by line, we need to temporarily switch out to
     304        # 'line' mode, do a single manual reset and then feed the lines one
     305        # by one.  Note that this only matters if the input has more than one
     306        # line.
     307        changed_input_mode = False
     308
     309        if self.input_mode == 'cell':
     310            self.reset()
     311            changed_input_mode = True
     312            saved_input_mode = 'cell'
     313            self.input_mode = 'line'
     314
     315        # Store raw source before applying any transformations to it.  Note
     316        # that this must be done *after* the reset() call that would otherwise
     317        # flush the buffer.
     318        self._store(lines, self._buffer_raw, 'source_raw')
     319
     320        try:
     321            push = super(IPythonInputSplitter, self).push
     322            buf = self._buffer
     323            for line in lines_list:
     324                line_number = len(buf)
     325                if self._is_complete or not buf or \
     326                       (buf and buf[-1].rstrip().endswith((':', ','))):
     327                    for f in self.transforms:
     328                        line = f(line, line_number)
     329                out = push(line)
     330        finally:
     331            if changed_input_mode:
     332                self.input_mode = saved_input_mode
     333        return out
     334
     335# END SageIPythonInputSplitter
     336#
     337#
     338
     339
     340class SagePlugin(Plugin):
     341    startup_code = """from sage.all_cmdline import *
     342from sage.misc.interpreter import sage_prompt
     343"""
     344
     345    def __init__(self, shell=None, config=None):
     346        """
     347        Initialize the Sage plugin.
     348        """
     349
     350        super(SagePlugin, self).__init__(shell=shell, config=config)
     351        self.shell = shell
     352        self.auto_magics = SageMagics(shell)
     353        shell.register_magics(self.auto_magics)
     354        shell.set_hook('pre_run_code_hook', self.auto_magics.pre_run_code_hook)
     355        shell.display_formatter.formatters['text/plain'] = SagePlainTextFormatter(config=config)
     356        from sage.misc.edit_module import edit_devel
     357        self.shell.set_hook('editor', edit_devel)
     358        self.init_inspector()
     359        self.init_line_transforms()
     360        self.register_interface_magics()
     361
     362        # right now, the shutdown hook calling quit_sage() doesn't
     363        # work when we run doctests that involve creating test shells.
     364        # The test run segfaults right when it exits, complaining
     365        # about a bad memory access in the pari_close() function.
     366        #self.set_quit_hook()
     367
     368        self.print_branch()
     369
     370        # These are things I'm not sure that we need to do anymore
     371        #self.deprecated()
     372
     373
     374        if os.environ.get('SAGE_IMPORTALL', 'yes') != 'yes':
     375            return
     376
     377        self.init_environment()
     378
     379    def register_interface_magics(self):
     380        """Register magics for each of the Sage interfaces"""
     381        interfaces = sorted([ obj.name()
     382                              for obj in sage.interfaces.all.__dict__.values()
     383                              if isinstance(obj, sage.interfaces.interface.Interface) ])
     384        for name in interfaces:
     385            def tmp(line,name=name):
     386                self.shell.run_cell('%s.interact()'%name)
     387            tmp.__doc__="Interact with %s"%name
     388            self.shell.register_magic_function(tmp, magic_name=name)
     389
     390   
     391    def set_quit_hook(self):
     392        """
     393        Set the exit hook to cleanly exit Sage.  This does not work in all cases right now.
     394        """
     395        def quit(shell):
     396            import sage
     397            sage.all.quit_sage()
     398        self.shell.set_hook('shutdown_hook', quit)
     399
     400    def print_branch(self):
     401        """
     402        Print the branch we are on currently
     403        """
     404        from sage.misc.misc import branch_current_hg_notice, branch_current_hg
     405        branch = branch_current_hg_notice(branch_current_hg())
     406        if branch and not self.shell.test_shell:
     407            print branch
     408
     409    def init_environment(self):
     410        """
     411        Set up Sage command-line environment
     412        """
     413        try:
     414            self.shell.run_cell('from sage.all import Integer, RealNumber')
     415        except Exception:
     416            import traceback
     417            print "Error importing the Sage library"
     418            traceback.print_exc()
     419            print
     420            print "To debug this, you can run:"
     421            print 'sage -ipython -i -c "import sage.all"'
     422            print 'and then type "%debug" to enter the interactive debugger'
     423            sys.exit(1)
     424        self.shell.run_cell(self.startup_code)
     425        self.run_init()
     426
     427
     428    def run_init(self):
     429        """
     430        Run Sage's initial startup file.
     431        """
     432        startup_file = os.environ.get('SAGE_STARTUP_FILE', '')
     433        if os.path.exists(startup_file):
     434            self.shell.run_cell('%%run %r'%startup_file)
     435
     436    def init_inspector(self):
     437        # Ideally, these would just be methods of the Inspector class
     438        # that we could override; however, IPython looks them up in
     439        # the global :class:`IPython.core.oinspect` module namespace.
     440        # Thus, we have to monkey-patch.
     441        from sage.misc import sagedoc, sageinspect
     442        import IPython.core.oinspect
     443        IPython.core.oinspect.getdoc = sageinspect.sage_getdoc #sagedoc.my_getdoc
     444        IPython.core.oinspect.getsource = sagedoc.my_getsource
     445        IPython.core.oinspect.getargspec = sageinspect.sage_getargspec
     446
     447    def init_line_transforms(self):
     448        """
     449        Set up transforms (like the preparser).
     450        """
     451        self.shell.input_splitter = SageInputSplitter()
     452        import sage
     453        import sage.all
     454        from sage.misc.interpreter import (SagePromptDedenter, SagePromptTransformer,
     455                                           MagicTransformer, SagePreparseTransformer)
     456
     457        self.shell.input_splitter.transforms = [SagePromptDedenter(),
     458                                                SagePromptTransformer(),
     459                                                MagicTransformer(),
     460                                                SagePreparseTransformer()] + self.shell.input_splitter.transforms
     461
     462        preparser(True)
     463
     464    def deprecated(self):
     465        """
     466        These are things I don't think we need to do anymore; are they used?
     467        """
     468        # I'm not sure this is ever needed; when would this not be ''?
     469        if sys.path[0]!='':
     470            sys.path.insert(0, '')
     471
     472# from http://stackoverflow.com/questions/4103773/efficient-way-of-having-a-function-only-execute-once-in-a-loop
     473from functools import wraps
     474def run_once(f):
     475    """Runs a function (successfully) only once.
     476
     477    The running can be reset by setting the `has_run` attribute to False
     478    """
     479    @wraps(f)
     480    def wrapper(*args, **kwargs):
     481        if not wrapper.has_run:
     482            result = f(*args, **kwargs)
     483            wrapper.has_run = True
     484            return result
     485    wrapper.has_run = False
     486    return wrapper
     487
     488@run_once
     489def load_ipython_extension(ip):
     490    """Load the extension in IPython."""
     491    plugin = SagePlugin(shell=ip, config=ip.config)
     492    ip.plugin_manager.register_plugin('sage', plugin)