Ticket #7514: sagelib-7514_combined.3.patch

File sagelib-7514_combined.3.patch, 59.4 KB (added by mpatel, 11 years ago)

Fix(?) loading of .spyx files. Add preparser.py to reference manual. Replaces previous.

  • doc/en/reference/cmd.rst

    # HG changeset patch
    # User William Stein <wstein@gmail.com>
    # Date 1258877567 28800
    # Node ID f22e81719e0d9465afc97d7364d5c58ca2a0e154
    # Parent  0ce03d21b776d92c73bf901c647b6be4a921c697
    trac 7514 -- rewrite load and attach
    
    diff --git a/doc/en/reference/cmd.rst b/doc/en/reference/cmd.rst
    a b Sage tutorial and the documentation for  
    1010.. toctree::
    1111   :maxdepth: 2
    1212
    13    sage/misc/attach
    1413   sage/misc/trace
    1514   options
  • doc/en/reference/misc.rst

    diff --git a/doc/en/reference/misc.rst b/doc/en/reference/misc.rst
    a b Miscellaneous 
    1616   sage/misc/mrange
    1717   sage/misc/dist
    1818   sage/misc/hg
     19   sage/misc/preparser
    1920   sage/misc/functional
    2021   sage/misc/latex
    2122   sage/misc/latex_macros
  • sage/misc/all.py

    diff --git a/sage/misc/all.py b/sage/misc/all.py
    a b from flatten import flatten 
    2121
    2222from map_threaded import map_threaded
    2323
    24 from session import load_session, save_session, show_identifiers
     24from session import load_session, save_session, show_identifiers, attach
    2525
    2626from remote_file import get_remote_file
    2727
    28 from attach import attach
    29 
    3028from profiler import Profiler
    3129
    3230from mrange import xmrange, mrange, xmrange_iter, mrange_iter, cartesian_product_iterator
    from mathml import mathml 
    6159
    6260from defaults import set_default_variable_name
    6361
    64 from preparser import preparse, implicit_multiplication, BackslashOperator
     62from preparser import preparse, implicit_multiplication, BackslashOperator, attached_files, detach
    6563
    6664from interpreter import preparser
    6765
  • sage/misc/attach.py

    diff --git a/sage/misc/attach.py b/sage/misc/attach.py
    a b Attach a file to a running instance of S 
    33"""
    44
    55class Attach:
    6     r"""
     6    """
    77    Attach a file to a running instance of Sage.
    8    
    9     .. note::
    10 
    11        ``attach`` is *not* a function and is not part of the Python
    12        language.
    13    
    14     ``load`` is exactly the same as attach, but doesn't
    15     automatically reload a file when it changes.
    16    
    17     You attach a file, e.g., ``foo.sage`` or
    18     ``foo.py`` or ``foo.spyx``, to a running
    19     Sage session by typing
    20    
    21     ::
    22    
    23         sage: attach foo.sage   # or foo.py   or foo.spyx  (not tested)
    24    
    25     The contents of the file are then loaded, which means they are
    26     read into the running Sage session. For example, if ``foo.sage``
    27     contains ``x=5``, after attaching ``foo.sage`` the variable ``x``
    28     will be set to 5. Moreover, any time you change ``foo.sage``, the
    29     attached file will be re-read automatically (with no intervention
    30     on your part).
    31    
    32     USAGE: ``attach file1 file2 ...`` - space-separated
    33     list of .py, .spyx, and .sage files.
    34    
    35     EFFECT: Each file is read in and added to an internal list of
    36     watched files. The meaning of reading a file in depends on the file
    37     type:
    38    
    39    
    40     -  read in with no preparsing (so, e.g., ``23`` is 2
    41        bit-xor 3),
    42    
    43     -  preparsed then the result is read in
    44    
    45     -  *not* preparsed. Compiled to a module ``m`` then
    46        ``from m import *`` is executed.
    47    
    48    
    49     Type ``attached_files()`` for a list of all currently
    50     attached files. You can remove files from this list to stop them
    51     from being watched.
    52    
    53     .. note::
    54 
    55         ``attach`` is exactly the same as load, except it keeps track of
    56         the loaded file and automatically reloads it when it changes.
    578    """
    589    def __repr__(self):
    5910        return self.__doc__
  • sage/misc/interpreter.py

    diff --git a/sage/misc/interpreter.py b/sage/misc/interpreter.py
    a b import remote_file 
    105105
    106106from IPython.iplib import InteractiveShell
    107107
    108 import preparser_ipython 
    109 from preparser import preparse_file
     108import preparser_ipython
     109from preparser import preparse_file, load_wrap, modified_attached_files, attached_files
    110110
    111111import cython
    112112
    113 #import signal
    114 #def sig(x,n):
    115 #    raise KeyboardInterrupt
    116 #def unsetsig():
    117 #    signal.signal(signal.SIGINT, sig)
    118 
    119113# IPython has a prefilter() function that analyzes each input line. We redefine
    120114# it here to first pre-process certain forms of input
    121115
    import cython 
    127121
    128122
    129123
    130 attached = { }
    131 
    132 def attached_files():
    133     """
    134     Return a list of all files attached to the current session.
    135     """
    136     global attached
    137     X = attached.keys()
    138     X.sort()
    139     return X
    140 
    141124def load_startup_file(file):
    142125    if os.path.exists(file):
    143126        X = do_prefilter_paste('load "%s"'%file,False)
    def do_prefilter_paste(line, continuatio 
    152135    Alternate prefilter for input.
    153136
    154137    INPUT:
    155         line -- a single line; must *not* have any newlines in it
    156         continuation -- whether the input line is really part
    157                      of the previous line, because of open parens or backslash.
     138   
     139        - ``line`` -- a single line; must *not* have any newlines in it
     140        - ``continuation`` -- whether the input line is really part
     141          of the previous line, because of open parens or backslash.
    158142    """
    159143    if '\n' in line:
    160144        raise RuntimeError, "bug in function that calls do_prefilter_paste -- there can be no newlines in the input"
    161    
    162     global attached
    163145
    164146    # This is so it's OK to have lots of blank space at the
    165147    # beginning of any non-continuation line.
    def do_prefilter_paste(line, continuatio 
    174156       
    175157    line = line.rstrip()
    176158
    177     if not line.startswith('attach ') and not line.startswith('load ') and not line.startswith('%run '):
    178         for F in attached.keys():
    179             tm = attached[F]
    180             if os.path.exists(F) and os.path.getmtime(F) > tm:
    181                 # Reload F.
    182                 try:
    183                     if F.endswith('.py'):
    184                         _ip.runlines('%%run -i "%s"'%F)
    185                     elif F.endswith('.sage'):
    186                         _ip.runlines('%%run -i "%s"'%preparse_file_named(F))
    187                     elif F.endswith('.spyx') or F.endswith('.pyx'):
    188                         X = load_cython(F)
    189                         __IPYTHON__.push(X)
    190                     else:
    191                         line = 'load("%s")'%F
    192                     t = os.path.getmtime(F)                   
    193                     attached[F] = t
    194                 except IOError:
    195                     del attached[F]
    196                
    197 
    198     # Get rid of leading sage: so that pasting of examples from the documentation
    199     # works.  This is like MAGMA's SetLinePrompt(false).
     159    # Process attached files.
     160    for F in modified_attached_files():
     161        _ip.runlines(load_wrap(F))
     162       
     163    # Get rid of leading sage: prompts so that pasting of examples
     164    # from the documentation works.  This is like MAGMA's
     165    # SetLinePrompt(false).
    200166    for prompt in ['sage:', '>>>']:
    201167        if not continuation:
    202168            while True:
    def do_prefilter_paste(line, continuatio 
    216182    if line.lower() in ['quit', 'exit', 'quit;', 'exit;']:
    217183        line = '%quit'
    218184
    219     #################################################################
    220185    # An interactive load command, like iload in MAGMA.
    221     #################################################################
    222186    if line[:6] == 'iload ':
    223187        try:
    224188            name = str(eval(line[6:]))
    def do_prefilter_paste(line, continuatio 
    252216
    253217       
    254218    #################################################################
    255     # A "load" command, like \r file in PARI or load "file" in MAGMA
     219    # load and attach commands
    256220    #################################################################
    257     if line[:5] == 'load ':
    258         # The -i so the file is run with the same environment,
    259         # e.g., including the "from sage import *"
    260         try:
    261             name = str(eval(line[5:])).strip()
    262         except:
    263             name = str(line[5:].strip())
    264         if name.lower().startswith('http://'):
    265             name = remote_file.get_remote_file(name)
    266         if isinstance(name, str):
    267             if not os.path.exists(name):
    268                 raise ImportError, "File '%s' not found (be sure to give .sage, .py, or .pyx extension)"%name
    269             elif name.endswith('.py'):
    270                 try:
    271                     line = '%run -i "' + name + '"'
    272                 except IOError, s:
    273                     print s
    274                     raise ImportError, "Error loading '%s'"%name
    275             elif name.endswith('.sage'):
    276                 try:
    277                     line = '%run -i "' + preparse_file_named(name) + '"'
    278                 except IOError, s:
    279                     print s
    280                     raise ImportError, "Error loading '%s'"%name
    281                     line = ""
    282             elif name.endswith('.spyx') or name.endswith('.pyx'):
    283                 line = load_cython(name)
    284             else:
    285                 line = 'load("%s")'%name
    286                 #raise ImportError, "Loading of '%s' not implemented (load .py, .pyx, and .sage files)"%name
    287                 #line = ''
     221    for cmd in ['load', 'attach']:
     222        if line.lstrip().startswith(cmd+' '):
     223            j = line.find(cmd+' ')
     224            s = line[j+len(cmd)+1:].strip()
     225            if not s.startswith('('):
     226                line = ' '*j + load_wrap(s, cmd=='attach')
    288227
    289     # This is an attach command like in MAGMA.  The file to attach is
    290     # any file that could be loaded.  At attach time it is loaded as
    291     # above.  It is put in a list that is a variable with scope this
    292     # interpreter.py file.  Each time prefilter_paste is called and
    293     # continuation is False, check all attached file names and if any
    294     # have changed, compile the file, then use %run to load them again
    295     # as above.  This is like the MAGMA attach, but in some ways
    296     # better.  It is very nice for interactive code development.
    297    
    298     if line.startswith('attach '):
    299         # The -i so the file is run with the same environment,
    300         # e.g., including the "from sage import *"
    301         try:
    302             name = str(eval(line[7:]))
    303         except:
    304             name = str(line[7:].strip())
    305         name = os.path.abspath(name)
    306         if not os.path.exists(name):
    307             raise ImportError, "File '%s' not found  (be sure to give .sage, .py, or .pyx extension)."%name
    308         elif name.endswith('.py'):
    309             try:
    310                 line = '%run -i "' + name + '"'
    311                 attached[name] = os.path.getmtime(name)
    312             except IOError, OSError:
    313                 raise ImportError, "File '%s' not found."%name
    314         elif name.endswith('.sage'):
    315             try:
    316                 line = '%run -i "' + preparse_file_named(name) + '"'
    317                 attached[name] = os.path.getmtime(name)
    318             except IOError, OSError:
    319                 raise ImportError, "File '%s' not found."%name
    320         elif name.endswith('.pyx') or name.endswith('.spyx'):
    321             try:
    322                 line = load_cython(name)
    323                 attached[name] = os.path.getmtime(name)
    324             except IOError, OSError:
    325                 raise ImportError, "File '%s' not found."%name
    326                 line = ''
    327         else:
    328             #line = 'load("%s")'%name
    329             raise ImportError, "Attaching of '%s' not implemented (load .py, .pyx, and .sage files)"%name
    330        
    331228    if len(line) > 0:
    332229        line = preparser_ipython.preparse_ipython(line, not continuation)
     230
    333231    return line
    334232
    335233def load_cython(name):
    def preparse_file_named_to_stream(name,  
    434332    os.chdir(dir)
    435333    contents = open(name).read()
    436334    contents = handle_encoding_declaration(contents, out)
    437     parsed = preparse_file(contents, attached, do_time=True)
     335    parsed = preparse_file(contents)
    438336    os.chdir(cur)
    439337    out.write("# -*- encoding: utf-8 -*-\n")
    440338    out.write('#'*70+'\n')
    def sage_prompt(): 
    568466__builtin__.sage_prompt = sage_prompt
    569467
    570468
     469
     470#######################################
     471#
     472def load_a_file(argstr, globals):
     473    s = open(argstr).read()
     474    return preparse_file(s, globals=globals)
     475   
  • sage/misc/preparser.py

    diff --git a/sage/misc/preparser.py b/sage/misc/preparser.py
    a b  
    11"""
    2 Sage pre-parser.
     2The Sage Preparser
    33
    4 AUTHOR:
    5     -- William Stein (2006-02-19): fixed bug when loading .py files.
    6     -- William Stein (2006-03-09): * fixed crash in parsing exponentials
    7                                    * precision of real literals now determined
    8                                      by digits of input (like Mathematica).
    9     -- Joe Wetherell (2006-04-14): * added MAGMA-style constructor preparsing.
    10     -- Bobby Moretti (2007-01-25): * added preliminary function assignment
    11                                      notation
    12     -- Robert Bradshaw (2007-09-19): * strip_string_literals, containing_block
    13                                        utility functions. Arrr!
    14                                      * Add [1,2,..,n] notation.
    15     -- Robert Bradshaw (2008-01-04): * Implicit multiplication (off by default)
    16     -- Robert Bradshaw (2008-09-23): * Factor out constants.
    17     -- Robert Bradshaw (2000-01):    * Simplify preparser by making it modular
    18                                        and using regular expressions. Also bug
    19                                        fixes, complex numbers, and binary input.
     4AUTHORS:
     5
     6    - William Stein (2006-02-19)
     7
     8      - Fixed bug when loading .py files.
     9
     10    - William Stein (2006-03-09)
     11
     12      - Fixed crash in parsing exponentials.
     13      - Precision of real literals now determined by digits of input
     14        (like Mathematica).
     15
     16    - Joe Wetherell (2006-04-14)
     17
     18      - Added MAGMA-style constructor preparsing.
     19
     20    - Bobby Moretti (2007-01-25)
     21
     22      - Added preliminary function assignment notation.
     23
     24    - Robert Bradshaw (2007-09-19)
     25
     26      - Added strip_string_literals, containing_block utility
     27        functions. Arrr!
     28      - Added [1,2,..,n] notation.
     29
     30    - Robert Bradshaw (2008-01-04)
     31
     32      - Implicit multiplication (off by default).
     33
     34    - Robert Bradshaw (2008-09-23)
     35
     36      - Factor out constants.
     37
     38    - Robert Bradshaw (2000-01)
     39
     40      - Simplify preparser by making it modular and using regular
     41        expressions.
     42      - Bug fixes, complex numbers, and binary input.
    2043
    2144EXAMPLES:
    2245
    23 PREPARSE:
     46Preparsing::
     47
    2448    sage: preparse('2/3')
    2549    'Integer(2)/Integer(3)'
    2650    sage: preparse('2.5')
    PREPARSE: 
    4064    'a*b*c in L'
    4165    sage: preparse('2e3x + 3exp(y)')
    4266    "RealNumber('2e3')*x + Integer(3)*exp(y)"
     67       
     68A string with escaped quotes in it (the point here is that the
     69preparser doesn't get confused by the internal quotes)::
    4370
    44 A string with escaped quotes in it (the point here is that the
    45 preparser doesn't get confused by the internal quotes):
    4671    sage: "\"Yes,\" he said."
    4772    '"Yes," he said.'
    4873    sage: s = "\\"; s
    4974    '\\'
    5075
     76A hex literal::
    5177
    52 A hex literal:
    5378    sage: preparse('0x2e3')
    5479    'Integer(0x2e3)'
    5580    sage: 0xA
    5681    10
    5782    sage: 0xe
    5883    14
     84   
     85Raw and hex work correctly::
    5986
    60 Raw and hex works correctly:
    6187    sage: type(0xa1)
    6288    <type 'sage.rings.integer.Integer'>
    6389    sage: type(0xa1r)
    6490    <type 'int'>
    6591    sage: type(0Xa1R)
    6692    <type 'int'>
    67    
    6893
    6994In Sage, methods can also be called on integer and real literals (note
    70 that in pure Python this would be a syntax error).
     95that in pure Python this would be a syntax error)::
     96
    7197    sage: 16.sqrt()
    7298    4
    7399    sage: 87.factor()
    that in pure Python this would be a synt 
    79105    sage: preparse('15.10.sqrt()')
    80106    "RealNumber('15.10').sqrt()"
    81107
    82 Note that calling methods on int literals in pure Python is a
    83 syntax error, but Sage allows this for Sage integers and reals,
    84 because users frequently request it.
     108Note that calling methods on int literals in pure Python is a syntax
     109error, but Sage allows this for Sage integers and reals, because users
     110frequently request it::
    85111
    86112    sage: eval('4.__add__(3)')
    87113    Traceback (most recent call last):
    88114    ...
    89115    SyntaxError: invalid syntax
    90116
    91 SYMBOLIC FUNCTIONAL NOTATION:
     117Symbolic functional notation::
     118
    92119    sage: a=10; f(theta, beta) = theta + beta; b = x^2 + theta
    93120    sage: f
    94121    (theta, beta) |--> beta + theta
    SYMBOLIC FUNCTIONAL NOTATION: 
    102129    sage: a = 5; f(x,y) = x*y*sqrt(a)
    103130    sage: f
    104131    (x, y) |--> sqrt(5)*x*y
     132   
     133This involves an =-, but should still be turned into a symbolic
     134expression::
    105135
    106 This involves an =-, but should still be turned into a symbolic expression:
    107136    sage: preparse('a(x) =- 5')
    108137    '__tmp__=var("x"); a = symbolic_expression(- Integer(5)).function(x)'
    109138    sage: f(x)=-x
    This involves an =-, but should still be 
    112141
    113142This involves -=, which should not be turned into a symbolic
    114143expression (of course a(x) isn't an identifier, so this will never be
    115 valid):
     144valid)::
     145
    116146    sage: preparse('a(x) -= 5')
    117147    'a(x) -= Integer(5)'
    118148
    119 RAW LITERALS:
     149Raw literals:
    120150
    121151Raw literals are not preparsed, which can be useful from an efficiency
    122152point of view.  Just like Python ints are denoted by an L, in Sage raw
    123153integer and floating literals are followed by an"r" (or "R") for raw,
    124154meaning not preparsed.
    125155
    126 We create a raw integer.
     156We create a raw integer::
     157
    127158    sage: a = 393939r
    128159    sage: a
    129160    393939
    130161    sage: type(a)
    131162    <type 'int'>
    132163   
    133 We create a raw float:   
     164We create a raw float::
     165
    134166    sage: z = 1.5949r
    135167    sage: z
    136168    1.5949
    137169    sage: type(z)
    138170    <type 'float'>
     171   
     172You can also use an upper case letter::
    139173
    140 You can also use an upper case letter:
    141174    sage: z = 3.1415R
    142175    sage: z
    143176    3.1415000000000002
    You can also use an upper case letter: 
    145178    <type 'float'>
    146179
    147180This next example illustrates how raw literals can be very useful in
    148 certain cases.  We make a list of even integers up to 10000.
     181certain cases.  We make a list of even integers up to 10000::
     182
    149183    sage: v = [ 2*i for i in range(10000)]
    150184
    151 This takes a noticeable fraction of a second (e.g., 0.25 seconds).
    152 After preparsing, what Python is really executing is the following:
     185This takes a noticeable fraction of a second (e.g., 0.25
     186seconds). After preparsing, what Python is really executing is the
     187following::
    153188
    154189    sage: preparse('v = [ 2*i for i in range(10000)]')
    155190    'v = [ Integer(2)*i for i in range(Integer(10000))]'
    156191
    157 If instead we use a raw 2 we get execution that is ``instant'' (0.00 seconds):
     192If instead we use a raw 2 we get execution that is *instant* (0.00
     193seconds)::
     194
    158195    sage: v = [ 2r * i for i in range(10000r)]
    159196
    160 Behind the scenes what happens is the following:
     197Behind the scenes what happens is the following::
     198
    161199    sage: preparse('v = [ 2r * i for i in range(10000r)]')
    162200    'v = [ 2 * i for i in range(10000)]'
    163201
    164 WARNING: The result of the above two expressions is different.  The
    165 first one computes a list of Sage integers, whereas the second creates
    166 a list of Python integers.  Python integers are typically much more
    167 efficient than Sage integers when they are very small; large Sage
    168 integers are much more efficient than Python integers, since they are
    169 implemented using the GMP C library.   
     202.. warning: The result of the above two expressions is different.  The
     203   first one computes a list of Sage integers, whereas the second
     204   creates a list of Python integers.  Python integers are typically
     205   much more efficient than Sage integers when they are very small;
     206   large Sage integers are much more efficient than Python integers,
     207   since they are implemented using the GMP C library.
    170208"""
    171209
    172 
    173 
    174210###########################################################################
    175211#       Copyright (C) 2006 William Stein <wstein@gmail.com>
    176212#
    numeric_literal_prefix = '_sage_const_' 
    185221
    186222def implicit_multiplication(level=None):
    187223    """
    188     Turn implicit multiplication on or off, optionally setting a specific level.
    189     Returns the current value if no argument is given.
     224    Turns implicit multiplication on or off, optionally setting a
     225    specific ``level``.  Returns the current ``level`` if no argument
     226    is given.
    190227   
    191     EXAMPLES:
     228    INPUT:
     229
     230    - ``level`` - an integer (default: None); see :func:`implicit_mul`
     231      for a list
     232
     233    EXAMPLES::
     234
    192235      sage: implicit_multiplication(True)
    193236      sage: implicit_multiplication()
    194237      5
    def in_quote(): 
    229272
    230273def strip_string_literals(code, state=None):
    231274    r"""
    232     Returns a string with all literal quotes replaced with
    233     labels and a dict of labels for re-substitution. This makes
    234     parsing much easier.
     275    Returns a string with all literal quotes replaced with labels and
     276    a dictionary of labels for re-substitution.  This makes parsing
     277    easier.
    235278   
     279    INPUT:
     280
     281    - ``code`` - a string; the input
     282
     283    - ``state`` - a 2-tuple (default: None); state with which to
     284      continue processing, e.g., across multiple calls to this
     285      function
     286
     287    OUTPUT:
     288
     289    - a 3-tuple of the processed code, the dictionary of labels, and
     290      any accumulated state
     291
    236292    EXAMPLES::
    237293   
    238294        sage: from sage.misc.preparser import strip_string_literals
    def strip_string_literals(code, state=No 
    343399
    344400def containing_block(code, ix, delimiters=['()','[]','{}'], require_delim=True):
    345401    """
    346     Returns the smallest range (start,end) such that code[start,end]
    347     is delimited by balanced parentheses/brackets/braces.
     402    Returns the smallest range (start,end) such that code[start,end]
     403    is delimited by balanced delimiters (e.g., parentheses, brackets,
     404    and braces).
     405
     406    INPUT:
     407
     408    - ``code`` - a string
     409
     410    - ``ix`` - an integer; a starting position
     411
     412    - ``delimiters`` - a list of strings (default: ['()', '[]',
     413      '{}']); the delimiters to balance
     414
     415    - ``require_delim`` - a boolean (default: True); whether to raise
     416      a SyntaxError if delimiters are unbalanced
     417
     418    OUTPUT:
     419
     420    - a 2-tuple of integers
    348421   
    349     EXAMPLES:
     422    EXAMPLES::
     423
    350424        sage: from sage.misc.preparser import containing_block
    351425        sage: s = "factor(next_prime(L[5]+1))"
    352426        sage: s[22]
    def containing_block(code, ix, delimiter 
    403477   
    404478def parse_ellipsis(code, preparse_step=True):
    405479    """
    406     Preparse [0,2,..,n] notation.
     480    Preparses [0,2,..,n] notation.
    407481   
    408     EXAMPLES:
     482    INPUT:
     483
     484    - ``code`` - a string
     485
     486    - ``preparse_step`` - a boolean (default: True)
     487
     488    OUTPUT:
     489
     490    - a string
     491
     492    EXAMPLES::
     493
    409494        sage: from sage.misc.preparser import parse_ellipsis
    410495        sage: parse_ellipsis("[1,2,..,n]")
    411496        '(ellipsis_range(1,2,Ellipsis,n))'
    412497        sage: parse_ellipsis("for i in (f(x) .. L[10]):")
    413498        'for i in (ellipsis_iter(f(x) ,Ellipsis, L[10])):'
    414 
    415499        sage: [1.0..2.0]
    416500        [1.00000000000000, 2.00000000000000]
    417501    """
    def parse_ellipsis(code, preparse_step=T 
    441525
    442526def extract_numeric_literals(code):
    443527    """
    444     To eliminate the re-parsing and creation of numeric literals (e.g. during
    445     every iteration of a loop) we wish to pull them out and assign them to
    446     global variables.
     528    Pulls out numeric literals and assigns them to global variables.
     529    This eliminates the need to re-parse and create the literals,
     530    e.g., during every iteration of a loop.
    447531   
    448     This function takes a block of code and returns a new block of code
    449     with literals replaced by variable names, as well as a dictionary of what
    450     variables need to be created.
    451    
    452     EXAMPLES:
     532    INPUT:
     533
     534    - ``code`` - a string; a block of code
     535
     536    OUTPUT:
     537
     538    - a (string, string:string dictionary) 2-tuple; the block with
     539      literals replaced by variable names and a mapping from names to
     540      the new variables
     541
     542    EXAMPLES::
     543
    453544        sage: from sage.misc.preparser import extract_numeric_literals
    454545        sage: code, nums = extract_numeric_literals("1.2 + 5")
    455546        sage: print code
    all_num_regex = None 
    469560
    470561def preparse_numeric_literals(code, extract=False):
    471562    """
    472     This preparses numerical literals into their sage counterparts,
    473     e.g. Integer, RealNumber, and ComplexNumber.
    474     If extract is true, then it will create names for the literals
    475     and return a dict of name-construction pairs along with the
    476     processed code.
     563    This preparses numerical literals into their Sage counterparts,
     564    e.g. Integer, RealNumber, and ComplexNumber.
    477565   
    478     EXAMPLES:
     566    INPUT:
     567
     568    - ``code`` - a string; a code block to preparse
     569
     570    - ``extract`` - a boolean (default: False); whether to create
     571      names for the literals and return a dictionary of
     572      name-construction pairs
     573
     574    OUTPUT:
     575
     576    - a string or (string, string:string dictionary) 2-tuple; the
     577      preparsed block and, if ``extract`` is True, the
     578      name-construction mapping
     579
     580    EXAMPLES::
     581
    479582        sage: from sage.misc.preparser import preparse_numeric_literals
    480583        sage: preparse_numeric_literals("5")
    481584        'Integer(5)'
    def preparse_numeric_literals(code, extr 
    614717
    615718
    616719def strip_prompts(line):
    617     r"""Get rid of leading sage: and >>> prompts so that pasting of examples from
    618     the documentation works.
     720    r"""
     721    Removes leading sage: and >>> prompts so that pasting of examples
     722    from the documentation works.
    619723
    620     sage: from sage.misc.preparser import strip_prompts
    621     sage: strip_prompts("sage: 2 + 2")
    622     '2 + 2'
    623     sage: strip_prompts(">>>   3 + 2")
    624     '3 + 2'
    625     sage: strip_prompts("  2 + 4")
    626     '  2 + 4'
     724    INPUT:
     725
     726    - ``line`` - a string to process
     727
     728    OUTPUT:
     729
     730    - a string stripped of leading prompts
     731
     732    EXAMPLES::
     733
     734        sage: from sage.misc.preparser import strip_prompts
     735        sage: strip_prompts("sage: 2 + 2")
     736        '2 + 2'
     737        sage: strip_prompts(">>>   3 + 2")
     738        '3 + 2'
     739        sage: strip_prompts("  2 + 4")
     740        '  2 + 4'
    627741    """
    628742    for prompt in ['sage:', '>>>']:
    629743        if line.startswith(prompt):
    def strip_prompts(line): 
    634748
    635749def preparse_calculus(code):
    636750    """
    637     Support for calculus-like function assignment, the line
    638     "f(x,y,z) = sin(x^3 - 4*y) + y^x"
    639     gets turnd into
    640     '__tmp__=var("x,y,z"); f = symbolic_expression(sin(x**3 - 4*y) + y**x).function(x,y,z)'
     751    Supports calculus-like function assignment, e.g., transforms::
     752
     753       f(x,y,z) = sin(x^3 - 4*y) + y^x
     754
     755    into::
     756
     757       __tmp__=var("x,y,z")
     758       f = symbolic_expression(sin(x**3 - 4*y) + y**x).function(x,y,z)
    641759   
    642760    AUTHORS:
    643         -- Bobby Moretti: initial version - 02/2007
    644         -- William Stein: make variables become defined if they aren't already defined.
    645         -- Robert Bradshaw: rewrite using regular expressions (01/2009)
     761
     762    - Bobby Moretti
     763
     764      - Initial version - 02/2007
     765
     766    - William Stein
     767
     768      - Make variables become defined if they aren't already defined.
     769
     770    - Robert Bradshaw
     771
     772      - Rewrite using regular expressions (01/2009)
    646773       
    647     EXAMPLES:
     774    EXAMPLES::
     775
    648776        sage: preparse("f(x) = x^3-x")
    649777        '__tmp__=var("x"); f = symbolic_expression(x**Integer(3)-x).function(x)'
    650778        sage: preparse("f(u,v) = u - v")
    def preparse_calculus(code): 
    656784        sage: preparse("f(x_1, x_2) = x_1^2 - x_2^2")
    657785        '__tmp__=var("x_1,x_2"); f = symbolic_expression(x_1**Integer(2) - x_2**Integer(2)).function(x_1,x_2)'
    658786       
    659     For simplicity, this function assumes all statements begin and end with a semicolon.
     787    For simplicity, this function assumes all statements begin and end
     788    with a semicolon::
     789
    660790        sage: from sage.misc.preparser import preparse_calculus
    661791        sage: preparse_calculus(";f(t,s)=t^2;")
    662792        ';__tmp__=var("t,s"); f = symbolic_expression(t^2).function(t,s);'
    def preparse_calculus(code): 
    681811
    682812
    683813def preparse_generators(code):
    684     r"""Parse R.<a, b> in line[start_index:].
     814    r"""
     815    Parses generator syntax, converting::
    685816
    686     Returns preparsed code.
     817        obj.<gen0,gen1,...,genN> = objConstructor(...)
    687818
    688     Support for generator construction syntax:
    689     "obj.<gen0,gen1,...,genN> = objConstructor(...)"
    690     is converted into
    691     "obj = objConstructor(..., names=("gen0", "gen1", ..., "genN")); \
    692      (gen0, gen1, ..., genN,) = obj.gens()"
     819    into::
    693820
    694     Also, obj.<gen0,gen1,...,genN> = R[interior] is converted into
    695     "obj = R[interior]; (gen0, gen1, ..., genN,) = obj.gens()"
     821        obj = objConstructor(..., names=("gen0", "gen1", ..., "genN"))
     822        (gen0, gen1, ..., genN,) = obj.gens()
     823
     824    and::
     825
     826        obj.<gen0,gen1,...,genN> = R[interior]
     827
     828    into::
     829
     830        obj = R[interior]; (gen0, gen1, ..., genN,) = obj.gens()
     831
     832    INPUT:
     833
     834    - ``code`` - a string
     835
     836    OUTPUT:
     837
     838    - a string
    696839
    697840    LIMITATIONS:
     841
    698842       - The entire constructor *must* be on one line.
    699843
    700844    AUTHORS:
    701         -- 2006-04-14: Joe Wetherell (jlwether@alum.mit.edu)
    702         -- 2006-04-17: William Stein - improvements to allow multiple statements.
    703         -- 2006-05-01: William -- fix bug that Joe found
    704         -- 2006-10-31: William -- fix so obj doesn't have to be mutated
    705         -- 2009-01-27: Robert Bradshaw -- rewrite using regular expressions
    706845
    707     TESTS:
     846    - 2006-04-14: Joe Wetherell (jlwether@alum.mit.edu)
     847
     848      - Initial version.
     849
     850    - 2006-04-17: William Stein
     851
     852      - Improvements to allow multiple statements.
     853
     854    - 2006-05-01: William
     855
     856      - Fix bug that Joe found.
     857
     858    - 2006-10-31: William
     859
     860      - Fix so obj doesn't have to be mutated.
     861
     862    - 2009-01-27: Robert Bradshaw
     863
     864      - Rewrite using regular expressions
     865
     866    TESTS::
     867
    708868        sage: from sage.misc.preparser import preparse, preparse_generators
    709869
    710         Vanilla:
    711        
     870    Vanilla::
     871
    712872        sage: preparse("R.<x> = ZZ['x']")
    713873        "R = ZZ['x']; (x,) = R._first_ngens(1)"
    714874        sage: preparse("R.<x,y> = ZZ['x,y']")
    715875        "R = ZZ['x,y']; (x, y,) = R._first_ngens(2)"
    716876
    717         No square brackets:
     877    No square brackets::
    718878
    719879        sage: preparse("R.<x> = PolynomialRing(ZZ, 'x')")
    720880        "R = PolynomialRing(ZZ, 'x', names=('x',)); (x,) = R._first_ngens(1)"
    721881        sage: preparse("R.<x,y> = PolynomialRing(ZZ, 'x,y')")
    722882        "R = PolynomialRing(ZZ, 'x,y', names=('x', 'y',)); (x, y,) = R._first_ngens(2)"
    723883
    724         Names filled in:
     884    Names filled in::
    725885
    726886        sage: preparse("R.<x> = ZZ[]")
    727887        "R = ZZ['x']; (x,) = R._first_ngens(1)"
    728888        sage: preparse("R.<x,y> = ZZ[]")
    729889        "R = ZZ['x, y']; (x, y,) = R._first_ngens(2)"
    730890
    731         Names given not the same as generator names:
     891    Names given not the same as generator names::
    732892
    733893        sage: preparse("R.<x> = ZZ['y']")
    734894        "R = ZZ['y']; (x,) = R._first_ngens(1)"
    735895        sage: preparse("R.<x,y> = ZZ['u,v']")
    736896        "R = ZZ['u,v']; (x, y,) = R._first_ngens(2)"
    737897
    738         Number fields:
     898    Number fields::
    739899
    740900        sage: preparse("K.<a> = QQ[2^(1/3)]")
    741901        'K = QQ[Integer(2)**(Integer(1)/Integer(3))]; (a,) = K._first_ngens(1)'
    742902        sage: preparse("K.<a, b> = QQ[2^(1/3), 2^(1/2)]")
    743903        'K = QQ[Integer(2)**(Integer(1)/Integer(3)), Integer(2)**(Integer(1)/Integer(2))]; (a, b,) = K._first_ngens(2)'
    744904
    745         Just the .<> notation:
     905    Just the .<> notation::
    746906
    747907        sage: preparse("R.<x> = ZZx")
    748908        'R = ZZx; (x,) = R._first_ngens(1)'
    def preparse_generators(code): 
    751911        sage: preparse("A.<x,y,z>=FreeAlgebra(ZZ,3)")
    752912        "A = FreeAlgebra(ZZ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = A._first_ngens(3)"
    753913
    754         Ensure we don't eat too much:
     914    Ensure we don't eat too much::
    755915
    756916        sage: preparse("R.<x, y> = ZZ;2")
    757917        'R = ZZ; (x, y,) = R._first_ngens(2);Integer(2)'
    def preparse_generators(code): 
    760920        sage: preparse("F.<b>, f, g = S.field_extension()")
    761921        "F, f, g  = S.field_extension(names=('b',)); (b,) = F._first_ngens(1)"
    762922   
    763     For simplicity, this function assumes all statements begin and end with a semicolon.
    764         preparse_generators(";  R.<x>=ZZ[];")
     923    For simplicity, this function assumes all statements begin and end
     924    with a semicolon::
     925
     926        sage: preparse_generators(";  R.<x>=ZZ[];")
     927        ";  R = ZZ['x']; (x,) = R._first_ngens(1);"
    765928    """
    766929    new_code = []
    767930    last_end = 0
    def preparse_generators(code): 
    799962
    800963quote_state = None
    801964
    802 def preparse(line, reset=True, do_time=False, ignore_prompts=False, numeric_literals=True):
     965def preparse(line, reset=True, do_time=False, ignore_prompts=False,
     966             numeric_literals=True):
    803967    r"""
    804     EXAMPLES:
     968    Preparses a line of input.
     969
     970    INPUT:
     971
     972    - ``line`` - a string
     973
     974    - ``reset`` - a boolean (default: True)
     975
     976    - ``do_time`` - a boolean (default: False)
     977
     978    - ``ignore_prompts`` - a boolean (default: False)
     979
     980    - ``numeric_literals`` - a boolean (default: True)
     981
     982    OUTPUT:
     983
     984    - a string
     985
     986    EXAMPLES::
     987
    805988        sage: preparse("ZZ.<x> = ZZ['x']")
    806989        "ZZ = ZZ['x']; (x,) = ZZ._first_ngens(1)"
    807990        sage: preparse("ZZ.<x> = ZZ['y']")
    def preparse(line, reset=True, do_time=F 
    9211104## Apply the preparser to an entire file
    9221105######################################################
    9231106
    924 _attached={}
    925 def preparse_file(contents, attached=_attached, magic=True,
    926                   do_time=False, ignore_prompts=False,
    927                   numeric_literals=True, reload_attached=False):
     1107attached = {}
     1108def preparse_file(contents, globals=None, numeric_literals=True):
    9281109    """
    929     NOTE: Temporarily, if @parallel is in the input, then numeric_literals
    930     is always set to False.
    931    
    932     TESTS:
     1110    Preparses input, attending to numeric literals and load/attach
     1111    file directives.
     1112
     1113    .. note:: Temporarily, if @parallel is in the input, then
     1114       numeric_literals is always set to False.
     1115
     1116    INPUT:
     1117
     1118    - ``contents`` - a string
     1119
     1120    - ``globals`` - dict or None (default: None); if given, then
     1121      arguments to load/attach are evaluated in the namespace of this
     1122      dict.
     1123
     1124    - ``numeric_literals`` - bool (default: True), whether to factor
     1125      out wrapping of integers and floats, so they don't get created
     1126      repeatedly inside loops
     1127
     1128    OUTPUT:
     1129
     1130    - a string
     1131
     1132    TESTS::
     1133
    9331134        sage: from sage.misc.preparser import preparse_file
    9341135        sage: lots_of_numbers = "[%s]" % ", ".join(str(i) for i in range(3000))
    9351136        sage: _ = preparse_file(lots_of_numbers)
    936         sage: preparse_file("type(100r), type(100)")
    937         '_sage_const_100 = Integer(100)\ntype(100 ), type(_sage_const_100 )'
     1137        sage: print preparse_file("type(100r), type(100)")
     1138        _sage_const_100 = Integer(100)
     1139        type(100 ), type(_sage_const_100 )
    9381140    """
     1141    if globals is None: globals = {}
     1142   
    9391143    if not isinstance(contents, str):
    9401144        raise TypeError, "contents must be a string"
    9411145
    9421146    assert isinstance(contents, str)
    9431147
    944     if reload_attached:
    945         # add lines to load each attached file that has changed
    946         for F, tm in attached.iteritems():
    947             if os.path.exists(F) and os.path.getmtime(F) > tm:
    948                 contents = 'load "%s"\n'%F + contents
     1148    # Reload attached files that have changed
     1149    for F, tm in attached.iteritems():
     1150        new_tm = os.path.getmtime(F)
     1151        if os.path.exists(F) and new_tm > tm:
     1152            contents = 'load "%s"\n'%F + contents
     1153        attached[F] = new_tm
    9491154   
    9501155    # We keep track of which files have been loaded so far
    9511156    # in order to avoid a recursive load that would result
    def preparse_file(contents, attached=_at 
    9631168        contents, nums = extract_numeric_literals(contents)
    9641169        contents = contents % literals
    9651170        if nums:
    966             # Stick the assignments at the top, trying not to shift the lines down.
     1171            # Stick the assignments at the top, trying not to shift
     1172            # the lines down.
    9671173            ix = contents.find('\n')
    9681174            if ix == -1: ix = len(contents)
    9691175            if not re.match(r"^ *(#.*)?$", contents[:ix]):
    9701176                contents = "\n"+contents
    9711177            assignments = ["%s = %s" % x for x in nums.items()]
    972             # the preparser recurses on semicolons, so we only attempt to preserve line numbers if there are a few
     1178            # the preparser recurses on semicolons, so we only attempt
     1179            # to preserve line numbers if there are a few
    9731180            if len(assignments) < 500:
    9741181                contents = "; ".join(assignments) + contents
    9751182            else:
    9761183                contents = "\n".join(assignments) + "\n\n" + contents
    9771184
     1185    # The list F contains the preparsed lines so far.
    9781186    F = []
     1187    # A is the input, as a list of lines.
    9791188    A = contents.splitlines()
     1189    # We are currently parsing the i-th input line.
    9801190    i = 0
    9811191    while i < len(A):
    982         L = A[i].rstrip()
    983         if magic and L[:7] == "attach ":
    984             name = os.path.abspath(_strip_quotes(L[7:]))
    985             try:
    986                 if not attached.has_key(name):
    987                     t = os.path.getmtime(name)
    988                     attached[name] = t
    989             except IOError, OSError:
    990                 pass
    991             L = 'load ' + L[7:]
    992 
    993         if magic and L[:5] == "load ":
    994             try:
    995                 name_load = _strip_quotes(L[5:])
    996             except:
    997                 name_load = L[5:].strip()
    998             if name_load in loaded_files:
    999                 i += 1
    1000                 continue
    1001             loaded_files.append(name_load)
    1002             if name_load[-3:] == '.py':
    1003                 import IPython.ipapi
    1004                 # This is a dangerous hack, actually, since it means
    1005                 # that if the input file is:
    1006                 #     load a.sage
    1007                 #     load b.py
    1008                 # Then b.py will be loaded while the file is being *parsed*,
    1009                 # and *before* a.sage is loaded.  That would be very confusing.
    1010                 # This is now Trac ticket #4474.
    1011                 IPython.ipapi.get().magic('run -i "%s"'%name_load)
    1012                 L = ''
    1013             elif name_load[-5:] == '.sage':
    1014                 try:
    1015                     G = open(name_load)
    1016                 except IOError:
    1017                     print "File '%s' not found, so skipping load of %s"%(name_load, name_load)
    1018                     i += 1
     1192        L = A[i]
     1193        do_preparse = True
     1194        for cmd in ['load', 'attach']:
     1195            if L.lstrip().startswith(cmd+' '):
     1196                j = L.find(cmd+' ')
     1197                s = L[j+len(cmd)+1:].strip()
     1198                if not s.startswith('('):
     1199                    F.append(' '*j + load_wrap(s, cmd=='attach'))
     1200                    do_preparse = False
    10191201                    continue
    1020                 else:
    1021                     A = A[:i] + G.readlines() + A[i+1:]
    1022                     continue
    1023             elif name_load[-5:] == '.spyx':
    1024                 import interpreter
    1025                 L = interpreter.load_cython(name_load)
    1026             else:
    1027                 #print "Loading of '%s' not implemented (load .py, .spyx, and .sage files)"%name_load
    1028                 L = 'load("%s")'%name_load
    1029 
    1030         M = preparse(L, reset=(i==0), do_time=do_time, ignore_prompts=ignore_prompts, numeric_literals=not numeric_literals)
    1031         F.append(M)
     1202        if do_preparse:
     1203            F.append(preparse(L, reset=(i==0), do_time=True, ignore_prompts=False,
     1204                              numeric_literals=not numeric_literals))
    10321205        i += 1
    1033     # end while
    10341206
    10351207    return '\n'.join(F)
    10361208
    10371209def implicit_mul(code, level=5):
    10381210    """
    1039     Insert explicit *'s for implicit multiplication.
     1211    Inserts \*'s to make implicit multiplication explicit.
    10401212
    1041     INPUT:
    1042         code  -- the code with missing *'s
    1043         level -- how aggressive to be in placing *'s
    1044                    0) Do nothing
    1045                    1) numeric followed by alphanumeric
    1046                    2) closing parentheses followed by alphanumeric
    1047                    3) Spaces between alphanumeric
    1048                   10) Adjacent parentheses (may mangle call statements)
     1213    INPUT:
     1214
     1215    - ``code``  -- a string; the code with missing \*'s
     1216
     1217    - ``level`` -- an integer (default: 5); how aggressive to be in
     1218      placing \*'s
     1219
     1220      -  0 - Do nothing
     1221      -  1 - Numeric followed by alphanumeric
     1222      -  2 - Closing parentheses followed by alphanumeric
     1223      -  3 - Spaces between alphanumeric
     1224      - 10 - Adjacent parentheses (may mangle call statements)
    10491225                   
    1050     EXAMPLES:
     1226    OUTPUT:
     1227
     1228    - a string
     1229
     1230    EXAMPLES::
     1231
    10511232        sage: from sage.misc.preparser import implicit_mul
    10521233        sage: implicit_mul('(2x^2-4x+3)a0')
    10531234        '(2*x^2-4*x+3)*a0'
    def _strip_quotes(s): 
    10941275    Strips one set of outer quotes.
    10951276   
    10961277    INPUT:
    1097         a string s
     1278
     1279    - ``s`` - a string
    10981280       
    10991281    OUTPUT:
    1100         a string with the single and double quotes on either side of s
    1101         removed, if there are any
     1282
     1283    - a string with any single and double quotes on either side of
     1284      ``s`` removed
    11021285
    11031286    EXAMPLES:
    1104     Both types of quotes work.
     1287
     1288    Both types of quotes work::
     1289
    11051290        sage: import sage.misc.preparser
    11061291        sage: sage.misc.preparser._strip_quotes('"foo.sage"')
    11071292        'foo.sage'
    11081293        sage: sage.misc.preparser._strip_quotes("'foo.sage'")
    11091294        'foo.sage'
    11101295
    1111     The only thing that is stripped is at most one set of outer quotes:
     1296    The only thing that is stripped is at most one set of outer quotes::
     1297
    11121298        sage: sage.misc.preparser._strip_quotes('""foo".sage""')
    11131299        '"foo".sage"'
    11141300    """
    def _strip_quotes(s): 
    11231309
    11241310class BackslashOperator:
    11251311    """
    1126     This implements Matlab-style backslash operator for system solving via A \ b.
     1312    Implements Matlab-style backslash operator for solving systems::
     1313
     1314        A / b
    11271315   
    1128     EXAMPLES:
     1316    EXAMPLES::
     1317
    11291318        sage: preparse("A \ matrix(QQ,2,1,[1/3,'2/3'])")
    11301319        "A  * BackslashOperator() * matrix(QQ,Integer(2),Integer(1),[Integer(1)/Integer(3),'2/3'])"
    11311320        sage: preparse("A \ matrix(QQ,2,1,[1/3,2*3])")
    class BackslashOperator: 
    11411330    """
    11421331    def __rmul__(self, left):
    11431332        """
    1144         EXAMPLES:
     1333        EXAMPLES::
     1334
    11451335            sage: A = random_matrix(ZZ, 4)
    11461336            sage: B = random_matrix(ZZ, 4)
    11471337            sage: temp = A * BackslashOperator()
    class BackslashOperator: 
    11561346       
    11571347    def __mul__(self, right):
    11581348        """
    1159         EXAMPLES:
     1349        EXAMPLES::
     1350
    11601351            sage: A = matrix(RDF, 5, 5, 2)
    11611352            sage: b = vector(RDF, 5, range(5))
    11621353            sage: A \ b
    class BackslashOperator: 
    11671358            (0.0, 0.5, 1.0, 1.5, 2.0)
    11681359        """
    11691360        return self.left._backslash_(right)
     1361
     1362
     1363def is_loadable_filename(filename):
     1364    """
     1365    Returns whether a file can be loaded into Sage.  This checks only
     1366    whether its name ends in one of the supported extensions .py,
     1367    .pyx, .sage, and .spyx.
     1368
     1369    INPUT:
     1370
     1371    - ``filename`` - a string
     1372
     1373    OUTPUT:
     1374
     1375    - a boolean
     1376
     1377    EXAMPLES::
     1378
     1379        sage: sage.misc.preparser.is_loadable_filename('foo.bar')
     1380        False
     1381        sage: sage.misc.preparser.is_loadable_filename('foo.c')
     1382        False
     1383        sage: sage.misc.preparser.is_loadable_filename('foo.sage')
     1384        True
     1385    """
     1386    # Loop over list of supported code file extensions for the load function.   
     1387    for ext in ['.py', '.pyx', '.sage', '.spyx']:
     1388        if filename.endswith(ext):
     1389            return True
     1390    return False
     1391
     1392def load(filename, globals, attach=False):
     1393    """
     1394    Executes a file in the scope given by ``globals``.  The
     1395    ``filename`` itself is also evaluated in the scope.  If the name
     1396    starts with http://, it is treated as a URL and downloaded.
     1397
     1398    .. note:: For Cython files, the situation is more complicated --
     1399       the module is first compiled to a temporary module t and
     1400       executed via::
     1401
     1402           from t import *
     1403
     1404    INPUT:
     1405
     1406    - ``filename`` -- a string; a .py, .sage, .pyx, etc., filename,
     1407      URL, or expression that evaluates to one
     1408
     1409    - ``globals`` -- a string:object dictionary; the context in which
     1410      to evaluate the ``filename`` and exec its contents
     1411
     1412    - ``attach`` -- a boolean (default: False); whether to add the
     1413      file to the list of attached files
     1414
     1415    EXAMPLES:
     1416
     1417    Note that .py files are *not* preparsed::
     1418   
     1419        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hi',2/3; z=-2/9")
     1420        sage: sage.misc.preparser.load(t,globals())
     1421        hi 0
     1422        sage: z
     1423        -1
     1424
     1425    A .sage file *is* preparsed::
     1426   
     1427        sage: t=tmp_filename()+'.sage'; open(t,'w').write("print 'hi',2/3; s=-2/7")
     1428        sage: sage.misc.preparser.load(t,globals())
     1429        hi 2/3
     1430        sage: s
     1431        -2/7
     1432
     1433    Cython files are *not* preparsed::
     1434   
     1435        sage: t=tmp_filename()+'.pyx'; open(t,'w').write("print 'hi',2/3; z=-2/9")
     1436        sage: z=0; sage.misc.preparser.load(t,globals())
     1437        Compiling ....pyx...
     1438        hi 0
     1439        sage: z
     1440        -1
     1441
     1442    If the file isn't a Cython, Python, or a Sage file, a ValueError
     1443    is raised::
     1444
     1445        sage: sage.misc.preparser.load('a.foo',globals())
     1446        Traceback (most recent call last):
     1447        ...
     1448        ValueError: argument (='a.foo') to load or attach must have extension py, sage, or pyx
     1449
     1450    A filename given as an expression get evaluated.  This ensures
     1451    that ``load DATA+'foo.sage'`` works in the Notebook, say::
     1452
     1453        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     1454        sage: sage.misc.preparser.load(t, globals())
     1455        hello world
     1456
     1457    We load a file given at a remote URL::
     1458
     1459        sage: sage.misc.preparser.load('http://wstein.org/loadtest.py', globals())  # optional - internet
     1460        hi from the net
     1461
     1462    We attach a file::
     1463
     1464        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     1465        sage: sage.misc.preparser.load(t, globals(), attach=True)
     1466        hello world
     1467        sage: t in sage.misc.preparser.attached
     1468        True
     1469
     1470    You can't attach remote URLs (yet)::
     1471
     1472        sage: sage.misc.preparser.load('http://wstein.org/loadtest.py', globals(), attach=True)  # optional - internet
     1473        Traceback (most recent call last):
     1474        ...
     1475        NotImplementedError: you can't attach a URL
     1476    """
     1477    try:
     1478        filename = eval(filename, globals)
     1479    except Exception:
     1480        # handle multiple input files separated by spaces, which was
     1481        # maybe a bad idea, but which we have to handle for backwards
     1482        # compatibility.
     1483        v = filename.split()
     1484        if len(v) > 1:
     1485            for file in v:
     1486                load(file, globals, attach=attach)
     1487            return
     1488       
     1489    filename = filename.strip()
     1490   
     1491    if filename.lower().startswith('http://'):
     1492        if attach:
     1493            # But see http://en.wikipedia.org/wiki/HTTP_ETag for how
     1494            # we will do this.
     1495            # http://www.diveintopython.org/http_web_services/etags.html
     1496            raise NotImplementedError, "you can't attach a URL"
     1497        from remote_file import get_remote_file
     1498        filename = get_remote_file(filename, verbose=False)
     1499
     1500    if filename.endswith('.py'):
     1501        execfile(filename, globals)
     1502    elif filename.endswith('.sage'):
     1503        exec(preparse_file(open(filename).read()), globals)
     1504    elif filename.endswith('.spyx') or filename.endswith('.pyx'):
     1505        import interpreter
     1506        exec(interpreter.load_cython(filename), globals)
     1507    elif filename.endswith('.m'):
     1508        # Assume magma for now, though maybe .m is used by maple and
     1509        # mathematica too, and we should really analyze the file
     1510        # further.
     1511        s = globals['magma'].load(filename)
     1512        i = s.find('\n'); s = s[i+1:]
     1513        print s
     1514    else:
     1515        raise ValueError, "argument (='%s') to load or attach must have extension py, sage, or pyx"%filename
     1516
     1517    if attach and os.path.exists(filename):
     1518        attached[filename] = os.path.getmtime(filename)
     1519
     1520
     1521import base64   
     1522def load_wrap(filename, attach=False):
     1523    """
     1524    Encodes a load or attach command as valid Python code.
     1525
     1526    INPUT:
     1527
     1528    - ``filename`` - a string; the argument to the load or attach
     1529      command
     1530
     1531    - ``attach`` - a boolean (default: False); whether to attach
     1532      ``filename``, instead of loading it
     1533
     1534    OUTPUT:
     1535
     1536    - a string
     1537
     1538    EXAMPLES::
     1539
     1540        sage: sage.misc.preparser.load_wrap('foo.py', True)
     1541        'sage.misc.preparser.load(sage.misc.preparser.base64.b64decode("Zm9vLnB5"),globals(),True)'
     1542        sage: sage.misc.preparser.load_wrap('foo.sage')
     1543        'sage.misc.preparser.load(sage.misc.preparser.base64.b64decode("Zm9vLnNhZ2U="),globals(),False)'
     1544        sage: sage.misc.preparser.base64.b64decode("Zm9vLnNhZ2U=")
     1545        'foo.sage'
     1546    """
     1547    return 'sage.misc.preparser.load(sage.misc.preparser.base64.b64decode("%s"),globals(),%s)'%(
     1548        base64.b64encode(filename), attach)
     1549
     1550
     1551def modified_attached_files():
     1552    """
     1553    Returns an iterator over the names of the attached files that have
     1554    changed since last time this function was called.
     1555
     1556    OUTPUT:
     1557
     1558    - an iterator over strings
     1559
     1560    EXAMPLES::
     1561   
     1562        sage: sage.misc.reset.reset_attached()
     1563        sage: t=tmp_filename()+'.py';
     1564        sage: a = 0
     1565        sage: f = open(t,'w'); f.write("a = 5"); f.close()
     1566        sage: attach(t)
     1567        sage: a
     1568        5
     1569        sage: len(list(sage.misc.preparser.modified_attached_files()))
     1570        0
     1571        sage: import time; time.sleep(2)
     1572        sage: f = open(t,'w'); f.write("a = 10"); f.close()
     1573        sage: len(list(sage.misc.preparser.modified_attached_files()))
     1574        1
     1575        sage: len(list(sage.misc.preparser.modified_attached_files()))
     1576        0
     1577    """
     1578    # A generator is the perfect data structure here, since something
     1579    # could go wrong loading one file, and we end up only marking the
     1580    # ones that we returned as loaded.
     1581    for F in attached.keys():
     1582        tm = attached[F]
     1583        new_tm = os.path.getmtime(F)
     1584        if os.path.exists(F) and new_tm > tm:
     1585            # F is newer than last time we loaded it.
     1586            attached[F] = os.path.getmtime(F)
     1587            yield F
     1588   
     1589def attached_files():
     1590    """
     1591    Returns a list of all files attached to the current session.
     1592
     1593    OUTPUT:
     1594
     1595    - a sorted list of strings; the filenames
     1596
     1597    EXAMPLES::
     1598
     1599        sage: sage.misc.reset.reset_attached()
     1600        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     1601        sage: attach(t)
     1602        hello world
     1603        sage: attached_files() == [t]
     1604        True
     1605   
     1606    """
     1607    return list(sorted(attached.keys()))
     1608
     1609def detach(filename):
     1610    """
     1611    Detaches a file, if it was attached with the attach command.
     1612
     1613    INPUT:
     1614
     1615    - ``filename`` - a string
     1616
     1617    EXAMPLES::
     1618
     1619        sage: sage.misc.reset.reset_attached()
     1620        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     1621        sage: attach(t)
     1622        hello world
     1623        sage: attached_files() == [t]
     1624        True
     1625        sage: detach(t)
     1626        sage: attached_files()
     1627        []
     1628    """
     1629    if attached.has_key(filename):
     1630        del attached[filename]
  • sage/misc/reset.pyx

    diff --git a/sage/misc/reset.pyx b/sage/misc/reset.pyx
    a b def reset(vars=None): 
    3838                pass
    3939    restore()
    4040    reset_interfaces()
     41    reset_attached()
    4142
    4243def restore(vars=None):
    4344    """
    def reset_interfaces(): 
    118119    from sage.interfaces.quit import expect_quitall
    119120    expect_quitall()
    120121   
    121 ##     import sys
    122 ##     M = sys.modules
    123 ##     for k in M.keys():
    124 ##         if 'sage.interfaces' in k:
    125 ##             if not M[k] is None:
    126 ##                 reload(M[k])
     122def reset_attached():
     123    """
     124    Remove all the attached files from the list of attached files.
    127125
    128 ##     import sage.interfaces.all
    129 ##     G = globals()
    130 ##     for k, v in sage.interfaces.all.__dict__.iteritems():
    131 ##         G[k] = v
     126    EXAMPLES::
     127   
     128        sage: sage.misc.reset.reset_attached()
     129        sage: t = tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     130        sage: attach(t)
     131        hello world
     132        sage: attached_files() == [t]
     133        True
     134        sage: sage.misc.reset.reset_attached()
     135        sage: attached_files()
     136        []
     137    """
     138    import preparser
     139    preparser.attached = {}
    132140
    133 
  • sage/misc/sageinspect.py

    diff --git a/sage/misc/sageinspect.py b/sage/misc/sageinspect.py
    a b Cython classes:: 
    5353
    5454Python classes::
    5555
     56    sage: import sage.misc.attach
    5657    sage: sage_getfile(sage.misc.attach.Attach)
    5758    '.../attach.py'
    5859
    5960    sage: sage_getdoc(sage.misc.attach.Attach).lstrip()
    60     "Attach a file to a running instance of Sage..."
     61    'Attach a file to a running instance of Sage...'
    6162
    6263    sage: sage_getsource(sage.misc.attach.Attach)
    6364    'class Attach:...'
  • sage/misc/session.pyx

    diff --git a/sage/misc/session.pyx b/sage/misc/session.pyx
    a b def load_session(name='sage_session', ve 
    319319    for k, x in D.items():
    320320        state[k] = x
    321321
     322
     323def attach(*files):
     324    """
     325    Attach a file or files to a running instance of Sage and also load
     326    that file.
     327   
     328    .. note::
     329
     330       In addition to ``attach('foo.sage')``, from the sage prompt
     331       you can also just type ``attach "foo.sage"``.  However this
     332       second common usage is not part of the Python language.
     333   
     334    ``load`` is the same as attach, but doesn't automatically reload a
     335    file when it changes.
     336   
     337    You attach a file, e.g., ``foo.sage`` or ``foo.py`` or
     338    ``foo.pyx``, to a running Sage session by typing::
     339   
     340        sage: attach foo.sage   # or foo.py   or foo.pyx or even a URL to such a file (not tested)
     341
     342    or::
     343   
     344        sage: attach('foo.sage')  # not tested
     345
     346    Here we test attaching multiple files at once::
     347   
     348        sage: sage.misc.reset.reset_attached()
     349        sage: t1=tmp_filename()+'.py'; open(t1,'w').write("print 'hello world'")
     350        sage: t2=tmp_filename()+'.py'; open(t2,'w').write("print 'hi there xxx'")
     351        sage: attach(t1, t2)
     352        hello world
     353        hi there xxx
     354        sage: attached_files() == [t1,t2]
     355        True
     356       
     357   
     358    The contents of the file are then loaded, which means they are
     359    read into the running Sage session. For example, if ``foo.sage``
     360    contains ``x=5``, after attaching ``foo.sage`` the variable ``x``
     361    will be set to 5. Moreover, any time you change ``foo.sage``,
     362    before you execute a command, the attached file will be re-read
     363    automatically (with no intervention on your part).
     364   
     365    USAGE: ``attach file1 ...`` - space-separated list of .py, .pyx,
     366    and .sage files.
     367   
     368    EFFECT: Each file is read in and added to an internal list of
     369    watched files. The meaning of reading a file in depends on the file
     370    type:
     371   
     372   
     373    -  read in with no preparsing (so, e.g., ``23`` is 2
     374       bit-xor 3),
     375   
     376    -  preparsed then the result is read in
     377   
     378    -  *not* preparsed. Compiled to a module ``m`` then
     379       ``from m import *`` is executed.
     380   
     381   
     382    Type ``attached_files()`` for a list of all currently
     383    attached files. You can remove files from this list to stop them
     384    from being watched.
     385   
     386    .. note::
     387
     388        ``attach`` is exactly the same as load, except it keeps track of
     389        the loaded file and automatically reloads it when it changes.
     390    """
     391    import preparser
     392    for filename in files:
     393        preparser.load(filename, globals(), attach=True)
  • sage/structure/sage_object.pyx

    diff --git a/sage/structure/sage_object.pyx b/sage/structure/sage_object.pyx
    a b def have_same_parent(self, other): 
    615615
    616616##################################################################
    617617
    618 def load(filename, compress=True, verbose=True):
     618def load(*filename, compress=True, verbose=True):
    619619    """   
    620     Load Sage object from the file with name filename, which will
    621     have an .sobj extension added if it doesn't have one.
     620    Load Sage object from the file with name filename, which will have
     621    an .sobj extension added if it doesn't have one.  Or, if the input
     622    is a filename ending in .py, .pyx, or .sage, load that file into
     623    the current running session.  Loaded files are not loaded into
     624    their own namespace, i.e., this is much more like Python's
     625    ``execfile`` than Python's ``import``.
    622626
    623627    .. note::
    624628
    def load(filename, compress=True, verbos 
    633637       documentation for load is almost identical to that for attach.
    634638       Type attach? for help on attach.
    635639
    636     This also loads a ".sobj" file over a network by specifying the full URL.
    637     (Setting "verbose = False" suppresses the loading progress indicator.)   
     640    This function also loads a ``.sobj`` file over a network by
     641    specifying the full URL.  (Setting ``verbose = False`` suppresses
     642    the loading progress indicator.)
     643
     644    Finally, if you give multiple positional input arguments, then all
     645    of those files are loaded, or all of the objects are loaded and a
     646    list of the corresponding loaded objects is returned.
    638647
    639648    EXAMPLE::
    640649   
    def load(filename, compress=True, verbos 
    644653        Loading: [.]       
    645654        sage: s                                                            # optional - internet
    646655        'hello SAGE'
     656
     657    We test loading a file or multiple files or even mixing loading files and objects::
     658   
     659        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     660        sage: load(t)
     661        hello world
     662        sage: load(t,t)
     663        hello world
     664        hello world
     665        sage: t2=tmp_filename(); save(2/3,t2)
     666        sage: load(t,t,t2)
     667        hello world
     668        hello world
     669        [None, None, 2/3]
    647670    """
    648 
     671    import sage.misc.preparser
     672    if len(filename) != 1:
     673        v = [load(file, compress=True, verbose=True) for file in filename]
     674        ret = False
     675        for file in filename:
     676            if not sage.misc.preparser.is_loadable_filename(file):
     677                ret = True
     678        return v if ret else None
     679    else:
     680        filename = filename[0]
     681   
     682    if sage.misc.preparser.is_loadable_filename(filename):
     683        sage.misc.preparser.load(filename, globals())
     684        return
     685   
    649686    ## Check if filename starts with "http://" or "https://"
    650687    lower = filename.lower()
    651688    if lower.startswith("http://") or lower.startswith("https://"):
    def register_unpickle_override(module, n 
    761798        sage: unpickle_global('sage.rings.integer', 'Integer')
    762799        <type 'sage.rings.integer.Integer'>
    763800
    764     Now we horribly break the pickling system:
     801    Now we horribly break the pickling system::
    765802
    766803        sage: register_unpickle_override('sage.rings.integer', 'Integer', Rational, call_name=('sage.rings.rational', 'Rational'))
    767804        sage: unpickle_global('sage.rings.integer', 'Integer')
    768805        <type 'sage.rings.rational.Rational'>
    769806
    770     And we reach into the internals and put it back:
     807    And we reach into the internals and put it back::
    771808
    772809        sage: del unpickle_override[('sage.rings.integer', 'Integer')]
    773810        sage: unpickle_global('sage.rings.integer', 'Integer')
    def unpickle_global(module, name): 
    790827        sage: unpickle_global('sage.rings.integer', 'Integer')
    791828        <type 'sage.rings.integer.Integer'>
    792829
    793     Now we horribly break the pickling system:
     830    Now we horribly break the pickling system::
    794831
    795832        sage: register_unpickle_override('sage.rings.integer', 'Integer', Rational, call_name=('sage.rings.rational', 'Rational'))
    796833        sage: unpickle_global('sage.rings.integer', 'Integer')
    797834        <type 'sage.rings.rational.Rational'>
    798835
    799     And we reach into the internals and put it back:
     836    And we reach into the internals and put it back::
    800837
    801838        sage: del unpickle_override[('sage.rings.integer', 'Integer')]
    802839        sage: unpickle_global('sage.rings.integer', 'Integer')