Ticket #7514: sagelib-7514_combined.3.patch
File sagelib-7514_combined.3.patch, 59.4 KB (added by , 13 years ago) |
---|
-
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 10 10 .. toctree:: 11 11 :maxdepth: 2 12 12 13 sage/misc/attach14 13 sage/misc/trace 15 14 options -
doc/en/reference/misc.rst
diff --git a/doc/en/reference/misc.rst b/doc/en/reference/misc.rst
a b Miscellaneous 16 16 sage/misc/mrange 17 17 sage/misc/dist 18 18 sage/misc/hg 19 sage/misc/preparser 19 20 sage/misc/functional 20 21 sage/misc/latex 21 22 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 21 21 22 22 from map_threaded import map_threaded 23 23 24 from session import load_session, save_session, show_identifiers 24 from session import load_session, save_session, show_identifiers, attach 25 25 26 26 from remote_file import get_remote_file 27 27 28 from attach import attach29 30 28 from profiler import Profiler 31 29 32 30 from mrange import xmrange, mrange, xmrange_iter, mrange_iter, cartesian_product_iterator … … from mathml import mathml 61 59 62 60 from defaults import set_default_variable_name 63 61 64 from preparser import preparse, implicit_multiplication, BackslashOperator 62 from preparser import preparse, implicit_multiplication, BackslashOperator, attached_files, detach 65 63 66 64 from interpreter import preparser 67 65 -
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 3 3 """ 4 4 5 5 class Attach: 6 r"""6 """ 7 7 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 Python12 language.13 14 ``load`` is exactly the same as attach, but doesn't15 automatically reload a file when it changes.16 17 You attach a file, e.g., ``foo.sage`` or18 ``foo.py`` or ``foo.spyx``, to a running19 Sage session by typing20 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 are26 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``, the29 attached file will be re-read automatically (with no intervention30 on your part).31 32 USAGE: ``attach file1 file2 ...`` - space-separated33 list of .py, .spyx, and .sage files.34 35 EFFECT: Each file is read in and added to an internal list of36 watched files. The meaning of reading a file in depends on the file37 type:38 39 40 - read in with no preparsing (so, e.g., ``23`` is 241 bit-xor 3),42 43 - preparsed then the result is read in44 45 - *not* preparsed. Compiled to a module ``m`` then46 ``from m import *`` is executed.47 48 49 Type ``attached_files()`` for a list of all currently50 attached files. You can remove files from this list to stop them51 from being watched.52 53 .. note::54 55 ``attach`` is exactly the same as load, except it keeps track of56 the loaded file and automatically reloads it when it changes.57 8 """ 58 9 def __repr__(self): 59 10 return self.__doc__ -
sage/misc/interpreter.py
diff --git a/sage/misc/interpreter.py b/sage/misc/interpreter.py
a b import remote_file 105 105 106 106 from IPython.iplib import InteractiveShell 107 107 108 import preparser_ipython 109 from preparser import preparse_file 108 import preparser_ipython 109 from preparser import preparse_file, load_wrap, modified_attached_files, attached_files 110 110 111 111 import cython 112 112 113 #import signal114 #def sig(x,n):115 # raise KeyboardInterrupt116 #def unsetsig():117 # signal.signal(signal.SIGINT, sig)118 119 113 # IPython has a prefilter() function that analyzes each input line. We redefine 120 114 # it here to first pre-process certain forms of input 121 115 … … import cython 127 121 128 122 129 123 130 attached = { }131 132 def attached_files():133 """134 Return a list of all files attached to the current session.135 """136 global attached137 X = attached.keys()138 X.sort()139 return X140 141 124 def load_startup_file(file): 142 125 if os.path.exists(file): 143 126 X = do_prefilter_paste('load "%s"'%file,False) … … def do_prefilter_paste(line, continuatio 152 135 Alternate prefilter for input. 153 136 154 137 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. 158 142 """ 159 143 if '\n' in line: 160 144 raise RuntimeError, "bug in function that calls do_prefilter_paste -- there can be no newlines in the input" 161 162 global attached163 145 164 146 # This is so it's OK to have lots of blank space at the 165 147 # beginning of any non-continuation line. … … def do_prefilter_paste(line, continuatio 174 156 175 157 line = line.rstrip() 176 158 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). 200 166 for prompt in ['sage:', '>>>']: 201 167 if not continuation: 202 168 while True: … … def do_prefilter_paste(line, continuatio 216 182 if line.lower() in ['quit', 'exit', 'quit;', 'exit;']: 217 183 line = '%quit' 218 184 219 #################################################################220 185 # An interactive load command, like iload in MAGMA. 221 #################################################################222 186 if line[:6] == 'iload ': 223 187 try: 224 188 name = str(eval(line[6:])) … … def do_prefilter_paste(line, continuatio 252 216 253 217 254 218 ################################################################# 255 # A "load" command, like \r file in PARI or load "file" in MAGMA219 # load and attach commands 256 220 ################################################################# 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') 288 227 289 # This is an attach command like in MAGMA. The file to attach is290 # any file that could be loaded. At attach time it is loaded as291 # above. It is put in a list that is a variable with scope this292 # interpreter.py file. Each time prefilter_paste is called and293 # continuation is False, check all attached file names and if any294 # have changed, compile the file, then use %run to load them again295 # as above. This is like the MAGMA attach, but in some ways296 # 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)."%name308 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."%name314 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."%name320 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."%name326 line = ''327 else:328 #line = 'load("%s")'%name329 raise ImportError, "Attaching of '%s' not implemented (load .py, .pyx, and .sage files)"%name330 331 228 if len(line) > 0: 332 229 line = preparser_ipython.preparse_ipython(line, not continuation) 230 333 231 return line 334 232 335 233 def load_cython(name): … … def preparse_file_named_to_stream(name, 434 332 os.chdir(dir) 435 333 contents = open(name).read() 436 334 contents = handle_encoding_declaration(contents, out) 437 parsed = preparse_file(contents , attached, do_time=True)335 parsed = preparse_file(contents) 438 336 os.chdir(cur) 439 337 out.write("# -*- encoding: utf-8 -*-\n") 440 338 out.write('#'*70+'\n') … … def sage_prompt(): 568 466 __builtin__.sage_prompt = sage_prompt 569 467 570 468 469 470 ####################################### 471 # 472 def 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 1 1 """ 2 Sage pre-parser. 2 The Sage Preparser 3 3 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. 4 AUTHORS: 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. 20 43 21 44 EXAMPLES: 22 45 23 PREPARSE: 46 Preparsing:: 47 24 48 sage: preparse('2/3') 25 49 'Integer(2)/Integer(3)' 26 50 sage: preparse('2.5') … … PREPARSE: 40 64 'a*b*c in L' 41 65 sage: preparse('2e3x + 3exp(y)') 42 66 "RealNumber('2e3')*x + Integer(3)*exp(y)" 67 68 A string with escaped quotes in it (the point here is that the 69 preparser doesn't get confused by the internal quotes):: 43 70 44 A string with escaped quotes in it (the point here is that the45 preparser doesn't get confused by the internal quotes):46 71 sage: "\"Yes,\" he said." 47 72 '"Yes," he said.' 48 73 sage: s = "\\"; s 49 74 '\\' 50 75 76 A hex literal:: 51 77 52 A hex literal:53 78 sage: preparse('0x2e3') 54 79 'Integer(0x2e3)' 55 80 sage: 0xA 56 81 10 57 82 sage: 0xe 58 83 14 84 85 Raw and hex work correctly:: 59 86 60 Raw and hex works correctly:61 87 sage: type(0xa1) 62 88 <type 'sage.rings.integer.Integer'> 63 89 sage: type(0xa1r) 64 90 <type 'int'> 65 91 sage: type(0Xa1R) 66 92 <type 'int'> 67 68 93 69 94 In Sage, methods can also be called on integer and real literals (note 70 that in pure Python this would be a syntax error). 95 that in pure Python this would be a syntax error):: 96 71 97 sage: 16.sqrt() 72 98 4 73 99 sage: 87.factor() … … that in pure Python this would be a synt 79 105 sage: preparse('15.10.sqrt()') 80 106 "RealNumber('15.10').sqrt()" 81 107 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. 108 Note that calling methods on int literals in pure Python is a syntax 109 error, but Sage allows this for Sage integers and reals, because users 110 frequently request it:: 85 111 86 112 sage: eval('4.__add__(3)') 87 113 Traceback (most recent call last): 88 114 ... 89 115 SyntaxError: invalid syntax 90 116 91 SYMBOLIC FUNCTIONAL NOTATION: 117 Symbolic functional notation:: 118 92 119 sage: a=10; f(theta, beta) = theta + beta; b = x^2 + theta 93 120 sage: f 94 121 (theta, beta) |--> beta + theta … … SYMBOLIC FUNCTIONAL NOTATION: 102 129 sage: a = 5; f(x,y) = x*y*sqrt(a) 103 130 sage: f 104 131 (x, y) |--> sqrt(5)*x*y 132 133 This involves an =-, but should still be turned into a symbolic 134 expression:: 105 135 106 This involves an =-, but should still be turned into a symbolic expression:107 136 sage: preparse('a(x) =- 5') 108 137 '__tmp__=var("x"); a = symbolic_expression(- Integer(5)).function(x)' 109 138 sage: f(x)=-x … … This involves an =-, but should still be 112 141 113 142 This involves -=, which should not be turned into a symbolic 114 143 expression (of course a(x) isn't an identifier, so this will never be 115 valid): 144 valid):: 145 116 146 sage: preparse('a(x) -= 5') 117 147 'a(x) -= Integer(5)' 118 148 119 R AW LITERALS:149 Raw literals: 120 150 121 151 Raw literals are not preparsed, which can be useful from an efficiency 122 152 point of view. Just like Python ints are denoted by an L, in Sage raw 123 153 integer and floating literals are followed by an"r" (or "R") for raw, 124 154 meaning not preparsed. 125 155 126 We create a raw integer. 156 We create a raw integer:: 157 127 158 sage: a = 393939r 128 159 sage: a 129 160 393939 130 161 sage: type(a) 131 162 <type 'int'> 132 163 133 We create a raw float: 164 We create a raw float:: 165 134 166 sage: z = 1.5949r 135 167 sage: z 136 168 1.5949 137 169 sage: type(z) 138 170 <type 'float'> 171 172 You can also use an upper case letter:: 139 173 140 You can also use an upper case letter:141 174 sage: z = 3.1415R 142 175 sage: z 143 176 3.1415000000000002 … … You can also use an upper case letter: 145 178 <type 'float'> 146 179 147 180 This next example illustrates how raw literals can be very useful in 148 certain cases. We make a list of even integers up to 10000. 181 certain cases. We make a list of even integers up to 10000:: 182 149 183 sage: v = [ 2*i for i in range(10000)] 150 184 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: 185 This takes a noticeable fraction of a second (e.g., 0.25 186 seconds). After preparsing, what Python is really executing is the 187 following:: 153 188 154 189 sage: preparse('v = [ 2*i for i in range(10000)]') 155 190 'v = [ Integer(2)*i for i in range(Integer(10000))]' 156 191 157 If instead we use a raw 2 we get execution that is ``instant'' (0.00 seconds): 192 If instead we use a raw 2 we get execution that is *instant* (0.00 193 seconds):: 194 158 195 sage: v = [ 2r * i for i in range(10000r)] 159 196 160 Behind the scenes what happens is the following: 197 Behind the scenes what happens is the following:: 198 161 199 sage: preparse('v = [ 2r * i for i in range(10000r)]') 162 200 'v = [ 2 * i for i in range(10000)]' 163 201 164 WARNING: The result of the above two expressions is different. The165 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. 170 208 """ 171 209 172 173 174 210 ########################################################################### 175 211 # Copyright (C) 2006 William Stein <wstein@gmail.com> 176 212 # … … numeric_literal_prefix = '_sage_const_' 185 221 186 222 def implicit_multiplication(level=None): 187 223 """ 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. 190 227 191 EXAMPLES: 228 INPUT: 229 230 - ``level`` - an integer (default: None); see :func:`implicit_mul` 231 for a list 232 233 EXAMPLES:: 234 192 235 sage: implicit_multiplication(True) 193 236 sage: implicit_multiplication() 194 237 5 … … def in_quote(): 229 272 230 273 def strip_string_literals(code, state=None): 231 274 r""" 232 Returns a string with all literal quotes replaced with 233 labels and a dict of labels for re-substitution. This makes234 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. 235 278 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 236 292 EXAMPLES:: 237 293 238 294 sage: from sage.misc.preparser import strip_string_literals … … def strip_string_literals(code, state=No 343 399 344 400 def containing_block(code, ix, delimiters=['()','[]','{}'], require_delim=True): 345 401 """ 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 348 421 349 EXAMPLES: 422 EXAMPLES:: 423 350 424 sage: from sage.misc.preparser import containing_block 351 425 sage: s = "factor(next_prime(L[5]+1))" 352 426 sage: s[22] … … def containing_block(code, ix, delimiter 403 477 404 478 def parse_ellipsis(code, preparse_step=True): 405 479 """ 406 Preparse [0,2,..,n] notation.480 Preparses [0,2,..,n] notation. 407 481 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 409 494 sage: from sage.misc.preparser import parse_ellipsis 410 495 sage: parse_ellipsis("[1,2,..,n]") 411 496 '(ellipsis_range(1,2,Ellipsis,n))' 412 497 sage: parse_ellipsis("for i in (f(x) .. L[10]):") 413 498 'for i in (ellipsis_iter(f(x) ,Ellipsis, L[10])):' 414 415 499 sage: [1.0..2.0] 416 500 [1.00000000000000, 2.00000000000000] 417 501 """ … … def parse_ellipsis(code, preparse_step=T 441 525 442 526 def extract_numeric_literals(code): 443 527 """ 444 To eliminate the re-parsing and creation of numeric literals (e.g. during445 every iteration of a loop) we wish to pull them out and assign them to446 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. 447 531 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 453 544 sage: from sage.misc.preparser import extract_numeric_literals 454 545 sage: code, nums = extract_numeric_literals("1.2 + 5") 455 546 sage: print code … … all_num_regex = None 469 560 470 561 def preparse_numeric_literals(code, extract=False): 471 562 """ 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. 477 565 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 479 582 sage: from sage.misc.preparser import preparse_numeric_literals 480 583 sage: preparse_numeric_literals("5") 481 584 'Integer(5)' … … def preparse_numeric_literals(code, extr 614 717 615 718 616 719 def 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. 619 723 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' 627 741 """ 628 742 for prompt in ['sage:', '>>>']: 629 743 if line.startswith(prompt): … … def strip_prompts(line): 634 748 635 749 def preparse_calculus(code): 636 750 """ 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) 641 759 642 760 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) 646 773 647 EXAMPLES: 774 EXAMPLES:: 775 648 776 sage: preparse("f(x) = x^3-x") 649 777 '__tmp__=var("x"); f = symbolic_expression(x**Integer(3)-x).function(x)' 650 778 sage: preparse("f(u,v) = u - v") … … def preparse_calculus(code): 656 784 sage: preparse("f(x_1, x_2) = x_1^2 - x_2^2") 657 785 '__tmp__=var("x_1,x_2"); f = symbolic_expression(x_1**Integer(2) - x_2**Integer(2)).function(x_1,x_2)' 658 786 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 660 790 sage: from sage.misc.preparser import preparse_calculus 661 791 sage: preparse_calculus(";f(t,s)=t^2;") 662 792 ';__tmp__=var("t,s"); f = symbolic_expression(t^2).function(t,s);' … … def preparse_calculus(code): 681 811 682 812 683 813 def preparse_generators(code): 684 r"""Parse R.<a, b> in line[start_index:]. 814 r""" 815 Parses generator syntax, converting:: 685 816 686 Returns preparsed code.817 obj.<gen0,gen1,...,genN> = objConstructor(...) 687 818 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:: 693 820 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 696 839 697 840 LIMITATIONS: 841 698 842 - The entire constructor *must* be on one line. 699 843 700 844 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 found704 -- 2006-10-31: William -- fix so obj doesn't have to be mutated705 -- 2009-01-27: Robert Bradshaw -- rewrite using regular expressions706 845 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 708 868 sage: from sage.misc.preparser import preparse, preparse_generators 709 869 710 Vanilla:711 870 Vanilla:: 871 712 872 sage: preparse("R.<x> = ZZ['x']") 713 873 "R = ZZ['x']; (x,) = R._first_ngens(1)" 714 874 sage: preparse("R.<x,y> = ZZ['x,y']") 715 875 "R = ZZ['x,y']; (x, y,) = R._first_ngens(2)" 716 876 717 No square brackets:877 No square brackets:: 718 878 719 879 sage: preparse("R.<x> = PolynomialRing(ZZ, 'x')") 720 880 "R = PolynomialRing(ZZ, 'x', names=('x',)); (x,) = R._first_ngens(1)" 721 881 sage: preparse("R.<x,y> = PolynomialRing(ZZ, 'x,y')") 722 882 "R = PolynomialRing(ZZ, 'x,y', names=('x', 'y',)); (x, y,) = R._first_ngens(2)" 723 883 724 Names filled in:884 Names filled in:: 725 885 726 886 sage: preparse("R.<x> = ZZ[]") 727 887 "R = ZZ['x']; (x,) = R._first_ngens(1)" 728 888 sage: preparse("R.<x,y> = ZZ[]") 729 889 "R = ZZ['x, y']; (x, y,) = R._first_ngens(2)" 730 890 731 Names given not the same as generator names:891 Names given not the same as generator names:: 732 892 733 893 sage: preparse("R.<x> = ZZ['y']") 734 894 "R = ZZ['y']; (x,) = R._first_ngens(1)" 735 895 sage: preparse("R.<x,y> = ZZ['u,v']") 736 896 "R = ZZ['u,v']; (x, y,) = R._first_ngens(2)" 737 897 738 Number fields:898 Number fields:: 739 899 740 900 sage: preparse("K.<a> = QQ[2^(1/3)]") 741 901 'K = QQ[Integer(2)**(Integer(1)/Integer(3))]; (a,) = K._first_ngens(1)' 742 902 sage: preparse("K.<a, b> = QQ[2^(1/3), 2^(1/2)]") 743 903 'K = QQ[Integer(2)**(Integer(1)/Integer(3)), Integer(2)**(Integer(1)/Integer(2))]; (a, b,) = K._first_ngens(2)' 744 904 745 Just the .<> notation:905 Just the .<> notation:: 746 906 747 907 sage: preparse("R.<x> = ZZx") 748 908 'R = ZZx; (x,) = R._first_ngens(1)' … … def preparse_generators(code): 751 911 sage: preparse("A.<x,y,z>=FreeAlgebra(ZZ,3)") 752 912 "A = FreeAlgebra(ZZ,Integer(3), names=('x', 'y', 'z',)); (x, y, z,) = A._first_ngens(3)" 753 913 754 Ensure we don't eat too much:914 Ensure we don't eat too much:: 755 915 756 916 sage: preparse("R.<x, y> = ZZ;2") 757 917 'R = ZZ; (x, y,) = R._first_ngens(2);Integer(2)' … … def preparse_generators(code): 760 920 sage: preparse("F.<b>, f, g = S.field_extension()") 761 921 "F, f, g = S.field_extension(names=('b',)); (b,) = F._first_ngens(1)" 762 922 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);" 765 928 """ 766 929 new_code = [] 767 930 last_end = 0 … … def preparse_generators(code): 799 962 800 963 quote_state = None 801 964 802 def preparse(line, reset=True, do_time=False, ignore_prompts=False, numeric_literals=True): 965 def preparse(line, reset=True, do_time=False, ignore_prompts=False, 966 numeric_literals=True): 803 967 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 805 988 sage: preparse("ZZ.<x> = ZZ['x']") 806 989 "ZZ = ZZ['x']; (x,) = ZZ._first_ngens(1)" 807 990 sage: preparse("ZZ.<x> = ZZ['y']") … … def preparse(line, reset=True, do_time=F 921 1104 ## Apply the preparser to an entire file 922 1105 ###################################################### 923 1106 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): 1107 attached = {} 1108 def preparse_file(contents, globals=None, numeric_literals=True): 928 1109 """ 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 933 1134 sage: from sage.misc.preparser import preparse_file 934 1135 sage: lots_of_numbers = "[%s]" % ", ".join(str(i) for i in range(3000)) 935 1136 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 ) 938 1140 """ 1141 if globals is None: globals = {} 1142 939 1143 if not isinstance(contents, str): 940 1144 raise TypeError, "contents must be a string" 941 1145 942 1146 assert isinstance(contents, str) 943 1147 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 949 1154 950 1155 # We keep track of which files have been loaded so far 951 1156 # in order to avoid a recursive load that would result … … def preparse_file(contents, attached=_at 963 1168 contents, nums = extract_numeric_literals(contents) 964 1169 contents = contents % literals 965 1170 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. 967 1173 ix = contents.find('\n') 968 1174 if ix == -1: ix = len(contents) 969 1175 if not re.match(r"^ *(#.*)?$", contents[:ix]): 970 1176 contents = "\n"+contents 971 1177 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 973 1180 if len(assignments) < 500: 974 1181 contents = "; ".join(assignments) + contents 975 1182 else: 976 1183 contents = "\n".join(assignments) + "\n\n" + contents 977 1184 1185 # The list F contains the preparsed lines so far. 978 1186 F = [] 1187 # A is the input, as a list of lines. 979 1188 A = contents.splitlines() 1189 # We are currently parsing the i-th input line. 980 1190 i = 0 981 1191 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 1019 1201 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)) 1032 1205 i += 1 1033 # end while1034 1206 1035 1207 return '\n'.join(F) 1036 1208 1037 1209 def implicit_mul(code, level=5): 1038 1210 """ 1039 Insert explicit *'s for implicit multiplication.1211 Inserts \*'s to make implicit multiplication explicit. 1040 1212 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) 1049 1225 1050 EXAMPLES: 1226 OUTPUT: 1227 1228 - a string 1229 1230 EXAMPLES:: 1231 1051 1232 sage: from sage.misc.preparser import implicit_mul 1052 1233 sage: implicit_mul('(2x^2-4x+3)a0') 1053 1234 '(2*x^2-4*x+3)*a0' … … def _strip_quotes(s): 1094 1275 Strips one set of outer quotes. 1095 1276 1096 1277 INPUT: 1097 a string s 1278 1279 - ``s`` - a string 1098 1280 1099 1281 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 1102 1285 1103 1286 EXAMPLES: 1104 Both types of quotes work. 1287 1288 Both types of quotes work:: 1289 1105 1290 sage: import sage.misc.preparser 1106 1291 sage: sage.misc.preparser._strip_quotes('"foo.sage"') 1107 1292 'foo.sage' 1108 1293 sage: sage.misc.preparser._strip_quotes("'foo.sage'") 1109 1294 'foo.sage' 1110 1295 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 1112 1298 sage: sage.misc.preparser._strip_quotes('""foo".sage""') 1113 1299 '"foo".sage"' 1114 1300 """ … … def _strip_quotes(s): 1123 1309 1124 1310 class BackslashOperator: 1125 1311 """ 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 1127 1315 1128 EXAMPLES: 1316 EXAMPLES:: 1317 1129 1318 sage: preparse("A \ matrix(QQ,2,1,[1/3,'2/3'])") 1130 1319 "A * BackslashOperator() * matrix(QQ,Integer(2),Integer(1),[Integer(1)/Integer(3),'2/3'])" 1131 1320 sage: preparse("A \ matrix(QQ,2,1,[1/3,2*3])") … … class BackslashOperator: 1141 1330 """ 1142 1331 def __rmul__(self, left): 1143 1332 """ 1144 EXAMPLES: 1333 EXAMPLES:: 1334 1145 1335 sage: A = random_matrix(ZZ, 4) 1146 1336 sage: B = random_matrix(ZZ, 4) 1147 1337 sage: temp = A * BackslashOperator() … … class BackslashOperator: 1156 1346 1157 1347 def __mul__(self, right): 1158 1348 """ 1159 EXAMPLES: 1349 EXAMPLES:: 1350 1160 1351 sage: A = matrix(RDF, 5, 5, 2) 1161 1352 sage: b = vector(RDF, 5, range(5)) 1162 1353 sage: A \ b … … class BackslashOperator: 1167 1358 (0.0, 0.5, 1.0, 1.5, 2.0) 1168 1359 """ 1169 1360 return self.left._backslash_(right) 1361 1362 1363 def 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 1392 def 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 1521 import base64 1522 def 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 1551 def 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 1589 def 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 1609 def 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): 38 38 pass 39 39 restore() 40 40 reset_interfaces() 41 reset_attached() 41 42 42 43 def restore(vars=None): 43 44 """ … … def reset_interfaces(): 118 119 from sage.interfaces.quit import expect_quitall 119 120 expect_quitall() 120 121 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]) 122 def reset_attached(): 123 """ 124 Remove all the attached files from the list of attached files. 127 125 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 = {} 132 140 133 -
sage/misc/sageinspect.py
diff --git a/sage/misc/sageinspect.py b/sage/misc/sageinspect.py
a b Cython classes:: 53 53 54 54 Python classes:: 55 55 56 sage: import sage.misc.attach 56 57 sage: sage_getfile(sage.misc.attach.Attach) 57 58 '.../attach.py' 58 59 59 60 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...' 61 62 62 63 sage: sage_getsource(sage.misc.attach.Attach) 63 64 '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 319 319 for k, x in D.items(): 320 320 state[k] = x 321 321 322 323 def 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): 615 615 616 616 ################################################################## 617 617 618 def load( filename, compress=True, verbose=True):618 def load(*filename, compress=True, verbose=True): 619 619 """ 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``. 622 626 623 627 .. note:: 624 628 … … def load(filename, compress=True, verbos 633 637 documentation for load is almost identical to that for attach. 634 638 Type attach? for help on attach. 635 639 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. 638 647 639 648 EXAMPLE:: 640 649 … … def load(filename, compress=True, verbos 644 653 Loading: [.] 645 654 sage: s # optional - internet 646 655 '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] 647 670 """ 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 649 686 ## Check if filename starts with "http://" or "https://" 650 687 lower = filename.lower() 651 688 if lower.startswith("http://") or lower.startswith("https://"): … … def register_unpickle_override(module, n 761 798 sage: unpickle_global('sage.rings.integer', 'Integer') 762 799 <type 'sage.rings.integer.Integer'> 763 800 764 Now we horribly break the pickling system: 801 Now we horribly break the pickling system:: 765 802 766 803 sage: register_unpickle_override('sage.rings.integer', 'Integer', Rational, call_name=('sage.rings.rational', 'Rational')) 767 804 sage: unpickle_global('sage.rings.integer', 'Integer') 768 805 <type 'sage.rings.rational.Rational'> 769 806 770 And we reach into the internals and put it back: 807 And we reach into the internals and put it back:: 771 808 772 809 sage: del unpickle_override[('sage.rings.integer', 'Integer')] 773 810 sage: unpickle_global('sage.rings.integer', 'Integer') … … def unpickle_global(module, name): 790 827 sage: unpickle_global('sage.rings.integer', 'Integer') 791 828 <type 'sage.rings.integer.Integer'> 792 829 793 Now we horribly break the pickling system: 830 Now we horribly break the pickling system:: 794 831 795 832 sage: register_unpickle_override('sage.rings.integer', 'Integer', Rational, call_name=('sage.rings.rational', 'Rational')) 796 833 sage: unpickle_global('sage.rings.integer', 'Integer') 797 834 <type 'sage.rings.rational.Rational'> 798 835 799 And we reach into the internals and put it back: 836 And we reach into the internals and put it back:: 800 837 801 838 sage: del unpickle_override[('sage.rings.integer', 'Integer')] 802 839 sage: unpickle_global('sage.rings.integer', 'Integer')