def do_prefilter_paste(line, continuation): """ Alternate prefilter for input. INPUT: line -- a single line; must *not* have any newlines in it continuation -- whether the input line is really part of the previous line, because of open parens or backslash. """ if '\n' in line: raise RuntimeError, "bug in function that calls do_prefilter_paste -- there can be no newlines in the input" global attached # This is so it's OK to have lots of blank space at the # beginning of any non-continuation line. if continuation: # strip ...'s that appear in examples L = line.lstrip() if L[:3] == '...': line = L[3:] else: line = line.lstrip() line = line.rstrip() if not line.startswith('attach ') and not line.startswith( 'load ') and not line.startswith('%run '): for F in attached.keys(): tm = attached[F] if os.path.exists(F) and os.path.getmtime(F) > tm: # Reload F. try: if F.endswith('.py'): _ip.runlines('%%run -i "%s"' % F) elif F.endswith('.sage'): _ip.runlines('%%run -i "%s"' % preparse_file_named(F)) elif F.endswith('.spyx') or F.endswith('.pyx'): X = load_cython(F) __IPYTHON__.push(X) else: line = 'load("%s")' % F t = os.path.getmtime(F) attached[F] = t except IOError: del attached[F] # Get rid of leading sage: so that pasting of examples from the documentation # works. This is like MAGMA's SetLinePrompt(false). for prompt in ['sage:', '>>>']: if not continuation: while True: strip = False if line[:3] == prompt: line = line[3:].lstrip() strip = True elif line[:5] == prompt: line = line[5:].lstrip() strip = True if not strip: break else: line = line.lstrip() # 'quit' alone on a line to quit. if line.lower() in ['quit', 'exit', 'quit;', 'exit;']: line = '%quit' ################################################################# # An interactive load command, like iload in MAGMA. ################################################################# if line[:6] == 'iload ': import sage.misc.log as log try: name = str(eval(line[6:])) except: name = str(line[6:].strip()) try: F = open(name) except IOError: raise ImportError, 'Could not open file "%s"' % name print 'Interactively loading "%s"' % name n = len(__IPYTHON__.input_hist) for L in F.readlines(): L = L.rstrip() Llstrip = L.lstrip() raw_input('sage: %s' % L.rstrip()) __IPYTHON__.input_hist_raw.append(L) if Llstrip[:5] == 'load ' or Llstrip[:7] == 'attach ' \ or Llstrip[:6] == 'iload ': log.offset -= 1 L = do_prefilter_paste(L, False) if len(L.strip()) > 0: _ip.runlines(L) L = '' else: L = preparser_ipython.preparse_ipython(L, not continuation) __IPYTHON__.input_hist.append(L) __IPYTHON__.push(L) log.offset += 1 return '' ################################################################# # A "load" command, like \r file in PARI or load "file" in MAGMA ################################################################# if line[:5] == 'load ': # The -i so the file is run with the same environment, # e.g., including the "from sage import *" try: name = str(eval(line[5:])).strip() except: name = str(line[5:].strip()) if name.lower().startswith('http://'): name = remote_file.get_remote_file(name) if isinstance(name, str): if not os.path.exists(name): raise ImportError, "File '%s' not found (be sure to give .sage, .py, or .pyx extension)" % name elif name.endswith('.py'): try: line = '%run -i "' + name + '"' except IOError, s: print s raise ImportError, "Error loading '%s'" % name elif name.endswith('.sage'): try: line = '%run -i "' + preparse_file_named(name) + '"' except IOError, s: print s raise ImportError, "Error loading '%s'" % name line = "" elif name.endswith('.spyx') or name.endswith('.pyx'): line = load_cython(name) else: line = 'load("%s")' % name
def do_prefilter_paste(line, continuation): """ Alternate prefilter for input. INPUT: line -- a single line; must *not* have any newlines in it continuation -- whether the input line is really part of the previous line, because of open parens or backslash. """ if '\n' in line: raise RuntimeError, "bug in function that calls do_prefilter_paste -- there can be no newlines in the input" global attached # This is so it's OK to have lots of blank space at the # beginning of any non-continuation line. if continuation: # strip ...'s that appear in examples L = line.lstrip() if L[:3] == '...': line = L[3:] else: line = line.lstrip() line = line.rstrip() if not line.startswith('attach ') and not line.startswith('load ') and not line.startswith('%run '): for F in attached.keys(): tm = attached[F] if os.path.exists(F) and os.path.getmtime(F) > tm: # Reload F. try: if F.endswith('.py'): _ip.runlines('%%run -i "%s"'%F) elif F.endswith('.sage'): _ip.runlines('%%run -i "%s"'%preparse_file_named(F)) elif F.endswith('.spyx') or F.endswith('.pyx'): X = load_cython(F) __IPYTHON__.push(X) else: line = 'load("%s")'%F t = os.path.getmtime(F) attached[F] = t except IOError: del attached[F] # Get rid of leading sage: so that pasting of examples from the documentation # works. This is like MAGMA's SetLinePrompt(false). for prompt in ['sage:', '>>>']: if not continuation: while True: strip = False if line[:3] == prompt: line = line[3:].lstrip() strip = True elif line[:5] == prompt: line = line[5:].lstrip() strip = True if not strip: break else: line = line.lstrip() # 'quit' alone on a line to quit. if line.lower() in ['quit', 'exit', 'quit;', 'exit;']: line = '%quit' ################################################################# # An interactive load command, like iload in MAGMA. ################################################################# if line[:6] == 'iload ': import sage.misc.log as log try: name = str(eval(line[6:])) except: name = str(line[6:].strip()) try: F = open(name) except IOError: raise ImportError, 'Could not open file "%s"'%name print 'Interactively loading "%s"'%name n = len(__IPYTHON__.input_hist) for L in F.readlines(): L = L.rstrip() Llstrip = L.lstrip() raw_input('sage: %s'%L.rstrip()) __IPYTHON__.input_hist_raw.append(L) if Llstrip[:5] == 'load ' or Llstrip[:7] == 'attach ' \ or Llstrip[:6] == 'iload ': log.offset -= 1 L = do_prefilter_paste(L, False) if len(L.strip()) > 0: _ip.runlines(L) L = '' else: L = preparser_ipython.preparse_ipython(L, not continuation) __IPYTHON__.input_hist.append(L) __IPYTHON__.push(L) log.offset += 1 return '' ################################################################# # A "load" command, like \r file in PARI or load "file" in MAGMA ################################################################# if line[:5] == 'load ': # The -i so the file is run with the same environment, # e.g., including the "from sage import *" try: name = str(eval(line[5:])).strip() except: name = str(line[5:].strip()) if name.lower().startswith('http://'): name = remote_file.get_remote_file(name) if isinstance(name, str): if not os.path.exists(name): raise ImportError, "File '%s' not found (be sure to give .sage, .py, or .pyx extension)"%name elif name.endswith('.py'): try: line = '%run -i "' + name + '"' except IOError, s: print s raise ImportError, "Error loading '%s'"%name elif name.endswith('.sage'): try: line = '%run -i "' + preparse_file_named(name) + '"' except IOError, s: print s raise ImportError, "Error loading '%s'"%name line = "" elif name.endswith('.spyx') or name.endswith('.pyx'): line = load_cython(name) else: line = 'load("%s")'%name
def load(filename, globals, attach=False): """ Executes a file in the scope given by ``globals``. The ``filename`` itself is also evaluated in the scope. If the name starts with ``http://``, it is treated as a URL and downloaded. .. NOTE:: For Cython files, the situation is more complicated -- the module is first compiled to a temporary module ``t`` and executed via:: from t import * INPUT: - ``filename`` -- a string; a .py, .sage, .pyx, etc., filename, URL, or expression that evaluates to one - ``globals`` -- a string:object dictionary; the context in which to evaluate the ``filename`` and exec its contents - ``attach`` -- a boolean (default: False); whether to add the file to the list of attached files EXAMPLES: Note that ``.py`` files are *not* preparsed:: sage: t = tmp_filename(ext='.py') sage: open(t,'w').write("print 'hi', 2/3; z = -2/7") sage: z = 1 sage: sage.repl.load.load(t, globals()) hi 0 sage: z -1 A ``.sage`` file *is* preparsed:: sage: t = tmp_filename(ext='.sage') sage: open(t,'w').write("print 'hi', 2/3; z = -2/7") sage: z = 1 sage: sage.repl.load.load(t, globals()) hi 2/3 sage: z -2/7 Cython files are *not* preparsed:: sage: t = tmp_filename(ext='.pyx') sage: open(t,'w').write("print 'hi', 2/3; z = -2/7") sage: z = 1 sage: sage.repl.load.load(t, globals()) Compiling ... hi 0 sage: z -1 If the file isn't a Cython, Python, or a Sage file, a ValueError is raised:: sage: sage.repl.load.load('a.foo',globals()) Traceback (most recent call last): ... ValueError: argument (='a.foo') to load or attach must have extension py, pyx, sage, spyx, or m A filename given as an expression get evaluated. This ensures that ``load DATA+'foo.sage'`` works in the Notebook, say:: sage: t=tmp_filename(ext='.py'); open(t,'w').write("print 'hello world'") sage: sage.repl.load.load(t, globals()) hello world We load a file given at a remote URL:: sage: sage.repl.load.load('http://wstein.org/loadtest.py', globals()) # optional - internet hi from the net 5 We can load files using secure http (https):: sage: sage.repl.load.load('https://github.com/jasongrout/minimum_rank/raw/minimum_rank_1_0_0/minrank.py', globals()) # optional - internet We attach a file:: sage: t = tmp_filename(ext='.py') sage: open(t,'w').write("print 'hello world'") sage: sage.repl.load.load(t, globals(), attach=True) hello world sage: t in attached_files() True You can't attach remote URLs (yet):: sage: sage.repl.load.load('http://wstein.org/loadtest.py', globals(), attach=True) # optional - internet Traceback (most recent call last): ... NotImplementedError: you can't attach a URL The default search path for loading and attaching files is the current working directory, i.e., ``'.'``. But you can modify the path with :func:`load_attach_path`:: sage: sage.repl.attach.reset(); reset_load_attach_path() sage: load_attach_path() ['.'] sage: t_dir = tmp_dir() sage: fullpath = os.path.join(t_dir, 'test.py') sage: open(fullpath, 'w').write("print 37 * 3") sage: load_attach_path(t_dir) sage: attach('test.py') 111 sage: sage.repl.attach.reset(); reset_load_attach_path() # clean up or by setting the environment variable ``SAGE_LOAD_ATTACH_PATH`` to a colon-separated list before starting Sage:: $ export SAGE_LOAD_ATTACH_PATH="/path/to/my/library:/path/to/utils" $ sage sage: load_attach_path() # not tested ['.', '/path/to/my/library', '/path/to/utils'] Make sure that load handles filenames with spaces in the name or path:: sage: t = tmp_filename(ext=' b.sage'); open(t,'w').write("print 2") sage: sage.repl.load.load(t, globals()) 2 """ if attach: from sage.repl.attach import add_attached_file try: filename = eval(filename, globals) except Exception: # First check if the file exists. The filename may have spaces in # its name, but more importantly modified_attached_files calls load # with the absolute file path and that may contain spaces in the path # As a side effect, this also allows file names with spaces in # them, but currently I don't see a way to disallow this case. if not os.path.exists(filename) and not os.path.isabs(filename): # handle multiple input files separated by spaces, which was # maybe a bad idea, but which we have to handle for backwards # compatibility. v = filename.split() if len(v) > 1: for file in v: load(file, globals, attach=attach) return filename = filename.strip() if filename.lower().startswith(('http://', 'https://')): if attach: # But see http://en.wikipedia.org/wiki/HTTP_ETag for how # we will do this. # http://www.diveintopython.net/http_web_services/etags.html raise NotImplementedError("you can't attach a URL") from remote_file import get_remote_file filename = get_remote_file(filename, verbose=False) if not is_loadable_filename(filename): raise ValueError('argument (=%r) to load or attach must have extension py, pyx, sage, spyx, or m' % filename) fpath = os.path.expanduser(filename) if os.path.isabs(fpath): if not os.path.exists(fpath): raise IOError('did not find file %r to load or attach' % filename) else: from sage.repl.attach import load_attach_path for path in load_attach_path(): fpath = os.path.join(path, filename) fpath = os.path.expanduser(fpath) if os.path.exists(fpath): break else: raise IOError('did not find file %r in load / attach search path' \ % filename) if fpath.endswith('.py'): if attach: add_attached_file(fpath) with open(fpath) as f: code = compile(f.read(), fpath, 'exec') exec(code, globals) elif fpath.endswith('.sage'): from sage.repl.attach import load_attach_mode from sage.repl.preparse import preparse_file_named, preparse_file load_debug_mode, attach_debug_mode = load_attach_mode() if (attach and attach_debug_mode) or ((not attach) and load_debug_mode): # Preparse to a file to enable tracebacks with # code snippets. Use preparse_file_named to make # the file name appear in the traceback as well. # See Trac 11812. if attach: add_attached_file(fpath) with open(preparse_file_named(fpath)) as f: code = compile(f.read(), preparse_file_named(fpath), 'exec') exec(code, globals) else: # Preparse in memory only for speed. if attach: add_attached_file(fpath) exec(preparse_file(open(fpath).read()) + "\n", globals) elif fpath.endswith('.spyx') or fpath.endswith('.pyx'): if attach: add_attached_file(fpath) exec(load_cython(fpath), globals) elif fpath.endswith('.m'): # Assume magma for now, though maybe .m is used by maple and # mathematica too, and we should really analyze the file # further. s = globals['magma'].load(fpath) i = s.find('\n'); s = s[i+1:] print(s)