Ticket #7514: sagelib-7514_combined.2.patch
File sagelib-7514_combined.2.patch, 32.4 KB (added by , 13 years ago) |
---|
-
sage/misc/all.py
# HG changeset patch # User William Stein <wstein@gmail.com> # Date 1258877567 28800 # Node ID e08039b9dd24e2372e4ad21303f54b8f13aa7e1f # Parent 0ce03d21b776d92c73bf901c647b6be4a921c697 trac 7514 -- rewrite load and attach 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 def preparse(line, reset=True, do_time=F 921 921 ## Apply the preparser to an entire file 922 922 ###################################################### 923 923 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): 924 attached = {} 925 def preparse_file(contents, globals=None, numeric_literals=True): 928 926 """ 929 927 NOTE: Temporarily, if @parallel is in the input, then numeric_literals 930 is always set to False. 928 is always set to False. 929 930 INPUT: 931 932 - ``contents`` -- a string 933 - ``globals`` -- dict or None (default: None); if given, then arguments to load/attach 934 are evaluated in the namespace of this dict. 935 - ``numeric_literals`` -- bool (default: True), whether to factor out wrapping of 936 integers and floats, so they don't get created repeatedly inside loops 931 937 932 TESTS: 938 TESTS:: 939 933 940 sage: from sage.misc.preparser import preparse_file 934 941 sage: lots_of_numbers = "[%s]" % ", ".join(str(i) for i in range(3000)) 935 942 sage: _ = preparse_file(lots_of_numbers) 936 943 sage: preparse_file("type(100r), type(100)") 937 944 '_sage_const_100 = Integer(100)\ntype(100 ), type(_sage_const_100 )' 938 945 """ 946 if globals is None: globals = {} 947 939 948 if not isinstance(contents, str): 940 949 raise TypeError, "contents must be a string" 941 950 942 951 assert isinstance(contents, str) 943 952 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 953 # Reload attached files that have changed 954 for F, tm in attached.iteritems(): 955 new_tm = os.path.getmtime(F) 956 if os.path.exists(F) and new_tm > tm: 957 contents = 'load "%s"\n'%F + contents 958 attached[F] = new_tm 949 959 950 960 # We keep track of which files have been loaded so far 951 961 # in order to avoid a recursive load that would result … … def preparse_file(contents, attached=_at 975 985 else: 976 986 contents = "\n".join(assignments) + "\n\n" + contents 977 987 988 # The list F contains the preparsed lines so far. 978 989 F = [] 990 # A is the input, as a list of lines. 979 991 A = contents.splitlines() 992 # We are currently parsing the i-th input line. 980 993 i = 0 981 994 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 995 L = A[i] 996 do_preparse = True 997 for cmd in ['load', 'attach']: 998 if L.lstrip().startswith(cmd+' '): 999 j = L.find(cmd+' ') 1000 s = L[j+len(cmd)+1:].strip() 1001 if not s.startswith('('): 1002 F.append(' '*j + load_wrap(s, cmd=='attach')) 1003 do_preparse = False 1019 1004 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) 1005 if do_preparse: 1006 F.append(preparse(L, reset=(i==0), do_time=True, ignore_prompts=False, 1007 numeric_literals=not numeric_literals)) 1032 1008 i += 1 1033 # end while1034 1009 1035 1010 return '\n'.join(F) 1036 1011 … … class BackslashOperator: 1167 1142 (0.0, 0.5, 1.0, 1.5, 2.0) 1168 1143 """ 1169 1144 return self.left._backslash_(right) 1145 1146 1147 def is_loadable_filename(filename): 1148 """ 1149 Returns True if filename ends in one of the supported extensions for files that 1150 can be loaded into Sage. 1151 1152 INPUT: 1153 1154 - ``filename`` -- a string 1155 1156 EXAMPLES:: 1157 1158 sage: sage.misc.preparser.is_loadable_filename('foo.bar') 1159 False 1160 sage: sage.misc.preparser.is_loadable_filename('foo.c') 1161 False 1162 sage: sage.misc.preparser.is_loadable_filename('foo.sage') 1163 True 1164 """ 1165 # Loop over list of supported code file extensions for the load function. 1166 for ext in ['.py', '.pyx', '.sage', '.spyx']: 1167 if filename.endswith(ext): 1168 return True 1169 return False 1170 1171 def load(filename, globals, attach=False): 1172 """ 1173 Execute the file with the given name in the scope specified by 1174 globals (except in case of Cython, where the situation is more 1175 complicated -- the module is compiled to a temporary module t and 1176 ``from t import *`` is executed.). If the filename starts with 1177 http:// then it is treated as a URL and downloaded first. 1178 Finally, the filename is first evaluated as an expression that 1179 evaluates in the globals scope to a filename. 1180 1181 INPUT: 1182 1183 - ``filename`` -- a .py, .sage, .pyx, etc., filename or expression 1184 that evaluates to one.... 1185 - ``globals`` -- a dictionary 1186 - ``attach`` -- bool (default: False); if True, the filename 1187 is added to the attached files list 1188 1189 EXAMPLES:: 1190 1191 Note that .py files are not preparsed:: 1192 1193 sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hi',2/3; z=-2/9") 1194 sage: sage.misc.preparser.load(t,globals()) 1195 hi 0 1196 sage: z 1197 -1 1198 1199 Python files are preparsed:: 1200 1201 sage: t=tmp_filename()+'.sage'; open(t,'w').write("print 'hi',2/3; s=-2/7") 1202 sage: sage.misc.preparser.load(t,globals()) 1203 hi 2/3 1204 sage: s 1205 -2/7 1206 1207 A Cython file:: 1208 1209 sage: t=tmp_filename()+'.pyx'; open(t,'w').write("print 'hi',2/3; z=-2/9") 1210 sage: z=0; sage.misc.preparser.load(t,globals()) 1211 Compiling ....pyx... 1212 hi 0 1213 sage: z 1214 -1 1215 1216 If the file isn't a Cython, Python, or a Sage file, a ValueError is raised:: 1217 1218 sage: sage.misc.preparser.load('a.foo',globals()) 1219 Traceback (most recent call last): 1220 ... 1221 ValueError: argument (='a.foo') to load or attach must have extension py, sage, or pyx 1222 1223 A filename that is given as an expression (that gets evaluated). 1224 This is important in making it so that ``load DATA+'foo.sage'`` 1225 works, say:: 1226 1227 sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'") 1228 sage: sage.misc.preparser.load(t, globals()) 1229 hello world 1230 1231 We load a file given at a remote URL:: 1232 1233 sage: sage.misc.preparser.load('http://wstein.org/loadtest.py', globals()) # optional - internet 1234 hi from the net 1235 1236 We attach a file:: 1237 1238 sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'") 1239 sage: sage.misc.preparser.load(t, globals(), attach=True) 1240 hello world 1241 sage: t in sage.misc.preparser.attached 1242 True 1243 1244 You can't attach remote URL's (yet):: 1245 1246 sage: sage.misc.preparser.load('http://wstein.org/loadtest.py', globals(), attach=True) # optional - internet 1247 Traceback (most recent call last): 1248 ... 1249 NotImplementedError: you can't attach a URL 1250 """ 1251 try: 1252 filename = eval(filename, globals) 1253 except Exception: 1254 # handle multiple input files separated by spaces, which was 1255 # maybe a bad idea, but which we have to handle for backwards 1256 # compatibility. 1257 v = filename.split() 1258 if len(v) > 1: 1259 for file in v: 1260 load(file, globals, attach=attach) 1261 return 1262 1263 filename = filename.strip() 1264 1265 if filename.lower().startswith('http://'): 1266 if attach: 1267 # But see http://en.wikipedia.org/wiki/HTTP_ETag for how we will do this. 1268 # http://www.diveintopython.org/http_web_services/etags.html 1269 raise NotImplementedError, "you can't attach a URL" 1270 from remote_file import get_remote_file 1271 filename = get_remote_file(filename, verbose=False) 1272 1273 if filename.endswith('.py'): 1274 execfile(filename, globals) 1275 elif filename.endswith('.sage'): 1276 exec(preparse_file(open(filename).read()), globals) 1277 elif filename.endswith('.spyx') or filename.endswith('.pyx'): 1278 import interpreter 1279 exec(interpreter.load_cython(filename), globals) 1280 elif filename.endswith('.m'): 1281 # Assume magma for now, though maybe .m is used by maple and 1282 # mathematica too, and we should really analyze the file 1283 # further. 1284 s = globals['magma'].load(filename) 1285 i = s.find('\n'); s = s[i+1:] 1286 print s 1287 else: 1288 raise ValueError, "argument (='%s') to load or attach must have extension py, sage, or pyx"%filename 1289 1290 if attach and os.path.exists(filename): 1291 attached[filename] = os.path.getmtime(filename) 1292 1293 1294 import base64 1295 def load_wrap(filename, attach=False): 1296 """ 1297 Internal function used to encode a load command as valid Python. 1298 filename is the argument to the load or attach command, and attach 1299 is True if the command is attach (rather than load). 1300 1301 INPUT: 1302 1303 - ``filename`` -- a string 1304 - ``attach`` -- bool (default: False) 1305 1306 EXAMPLES:: 1307 1308 sage: sage.misc.preparser.load_wrap('foo.py', True) 1309 'sage.misc.preparser.load(sage.misc.preparser.base64.b64decode("Zm9vLnB5"),globals(),True)' 1310 sage: sage.misc.preparser.load_wrap('foo.sage') 1311 'sage.misc.preparser.load(sage.misc.preparser.base64.b64decode("Zm9vLnNhZ2U="),globals(),False)' 1312 sage: sage.misc.preparser.base64.b64decode("Zm9vLnNhZ2U=") 1313 'foo.sage' 1314 """ 1315 return 'sage.misc.preparser.load(sage.misc.preparser.base64.b64decode("%s"),globals(),%s)'%( 1316 base64.b64encode(filename), attach) 1317 1318 1319 def modified_attached_files(): 1320 """ 1321 Return iterator over the names of the attached files that have 1322 changed since last time this function was called. 1323 1324 EXAMPLES:: 1325 1326 sage: sage.misc.reset.reset_attached() 1327 sage: t=tmp_filename()+'.py'; 1328 sage: a = 0 1329 sage: f = open(t,'w'); f.write("a = 5"); f.close() 1330 sage: attach(t) 1331 sage: a 1332 5 1333 sage: len(list(sage.misc.preparser.modified_attached_files())) 1334 0 1335 sage: import time; time.sleep(2) 1336 sage: f = open(t,'w'); f.write("a = 10"); f.close() 1337 sage: len(list(sage.misc.preparser.modified_attached_files())) 1338 1 1339 sage: len(list(sage.misc.preparser.modified_attached_files())) 1340 0 1341 """ 1342 # A generator is the perfect data structure here, since something 1343 # could go wrong loading one file, and we end up only marking the 1344 # ones that we returned as loaded. 1345 for F in attached.keys(): 1346 tm = attached[F] 1347 new_tm = os.path.getmtime(F) 1348 if os.path.exists(F) and new_tm > tm: 1349 # F is newer than last time we loaded it. 1350 attached[F] = os.path.getmtime(F) 1351 yield F 1352 1353 def attached_files(): 1354 """ 1355 Return a list of all files attached to the current session. 1356 1357 OUTPUT: 1358 1359 -- sorted list of filenames 1360 1361 EXAMPLES:: 1362 1363 sage: sage.misc.reset.reset_attached() 1364 sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'") 1365 sage: attach(t) 1366 hello world 1367 sage: attached_files() == [t] 1368 True 1369 1370 """ 1371 return list(sorted(attached.keys())) 1372 1373 def detach(filename): 1374 """ 1375 Detach that file with the given filename, if it was attached with 1376 the attach command. 1377 1378 INPUT: 1379 1380 - ``filename`` -- string 1381 1382 EXAMPLES:: 1383 1384 1385 sage: sage.misc.reset.reset_attached() 1386 sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'") 1387 sage: attach(t) 1388 hello world 1389 sage: attached_files() == [t] 1390 True 1391 sage: detach(t) 1392 sage: attached_files() 1393 [] 1394 """ 1395 if attached.has_key(filename): 1396 del attached[filename] 1397 -
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 filename.endswith('.sage') or filename.endswith('.py') or filename.endswith('.pyx'): 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://"):