def load(filename, globals, attach=False): r""" Execute a file in the scope given by ``globals``. If the name starts with ``http://`` or ``https://``, 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 denoting a filename or URL. - ``globals`` -- a string:object dictionary; the context in which to execute the file contents. - ``attach`` -- a boolean (default: False); whether to add the file to the list of attached files. Loading an executable Sage script from the command prompt will run whatever code is inside an if __name__ == "__main__": section, as the condition on ``__name__`` will hold true (code run from the command prompt is considered to be running in the ``__main__`` module.) EXAMPLES: Note that ``.py`` files are *not* preparsed:: sage: t = tmp_filename(ext='.py') sage: with open(t, 'w') as f: ....: _ = f.write("print(('hi', 2^3)); z = -2^7") sage: z = 1 sage: sage.repl.load.load(t, globals()) ('hi', 1) sage: z -7 A ``.sage`` file *is* preparsed:: sage: t = tmp_filename(ext='.sage') sage: with open(t, 'w') as f: ....: _ = f.write("print(('hi', 2^3)); z = -2^7") sage: z = 1 sage: sage.repl.load.load(t, globals()) ('hi', 8) sage: z -128 Cython files are *not* preparsed:: sage: t = tmp_filename(ext='.pyx') sage: with open(t, 'w') as f: ....: _ = f.write("print(('hi', 2^3)); z = -2^7") sage: z = 1 sage: sage.repl.load.load(t, globals()) Compiling ... ('hi', 1) sage: z -7 If the file is not a Cython, Python, or Sage file, a ``ValueError`` is raised:: sage: sage.repl.load.load(tmp_filename(ext=".foo"), globals()) Traceback (most recent call last): ... ValueError: unknown file extension '.foo' for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m) We load a file given at a remote URL (not tested for security reasons):: sage: sage.repl.load.load('https://www.sagemath.org/files/loadtest.py', globals()) # not tested hi from the net 5 We can load files using secure http (https):: sage: sage.repl.load.load('https://raw.githubusercontent.com/sagemath/sage-patchbot/3.0.0/sage_patchbot/util.py', globals()) # optional - internet We attach a file:: sage: t = tmp_filename(ext='.py') sage: with open(t, 'w') as f: ....: _ = f.write("print('hello world')") sage: sage.repl.load.load(t, globals(), attach=True) hello world sage: t in attached_files() True You cannot attach remote URLs (yet):: sage: sage.repl.load.load('https://www.sagemath.org/files/loadtest.py', globals(), attach=True) # optional - internet Traceback (most recent call last): ... NotImplementedError: you cannot 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: fname = 'test.py' sage: fullpath = os.path.join(t_dir, fname) sage: with open(fullpath, 'w') as f: ....: _ = f.write("print(37 * 3)") sage: load_attach_path(t_dir, replace=True) sage: attach(fname) 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'] TESTS: Make sure that load handles filenames with spaces in the name or path:: sage: t = tmp_filename(ext=' b.sage') sage: with open(t, 'w') as f: ....: _ = f.write("print(2)") sage: sage.repl.load.load(t, globals()) 2 Non-existing files with spaces give correct messages:: sage: sage.repl.load.load("this file should not exist", globals()) Traceback (most recent call last): ... OSError: did not find file 'this file should not exist' to load or attach """ if attach: from sage.repl.attach import add_attached_file if isinstance(filename, bytes): # For Python 3 in particular, convert bytes filenames to str since the # rest of this functions operate on filename as a str filename = bytes_to_str(filename, FS_ENCODING, 'surrogateescape') filename = os.path.expanduser(filename) if filename.lower().startswith(('http://', 'https://')): if attach: # But see https://en.wikipedia.org/wiki/HTTP_ETag for how # we will do this. # http://www.diveintopython.net/http_web_services/etags.html raise NotImplementedError("you cannot attach a URL") from sage.misc.remote_file import get_remote_file filename = get_remote_file(filename, verbose=False) 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.isfile(fpath): break else: raise IOError('did not find file %r to load or attach' % filename) ext = os.path.splitext(fpath)[1].lower() if ext == '.py': if attach: add_attached_file(fpath) with open(fpath) as f: code = compile(f.read(), fpath, 'exec') exec(code, globals) elif ext == '.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) with open(fpath) as f: exec(preparse_file(f.read()) + "\n", globals) elif ext == '.spyx' or ext == '.pyx': if attach: add_attached_file(fpath) exec(load_cython(fpath), globals) elif ext == '.f' or ext == '.f90': from sage.misc.inline_fortran import fortran with open(fpath) as f: fortran(f.read(), globals) elif ext == '.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') print(s[i + 1:]) else: raise ValueError('unknown file extension %r for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m)' % ext)
def load(filename, globals, attach=False): r""" Executes a file in the scope given by ``globals``. 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 denoting a filename or URL. - ``globals`` -- a string:object dictionary; the context in which to execute the file 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: with open(t, 'w') as f: ....: _ = f.write("print(('hi', 2^3)); z = -2^7") sage: z = 1 sage: sage.repl.load.load(t, globals()) ('hi', 1) sage: z -7 A ``.sage`` file *is* preparsed:: sage: t = tmp_filename(ext='.sage') sage: with open(t, 'w') as f: ....: _ = f.write("print(('hi', 2^3)); z = -2^7") sage: z = 1 sage: sage.repl.load.load(t, globals()) ('hi', 8) sage: z -128 Cython files are *not* preparsed:: sage: t = tmp_filename(ext='.pyx') sage: with open(t, 'w') as f: ....: _ = f.write("print(('hi', 2^3)); z = -2^7") sage: z = 1 sage: sage.repl.load.load(t, globals()) Compiling ... ('hi', 1) sage: z -7 If the file isn't a Cython, Python, or a Sage file, a ValueError is raised:: sage: sage.repl.load.load(tmp_filename(ext=".foo"), globals()) Traceback (most recent call last): ... ValueError: unknown file extension '.foo' for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m) 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: with open(t, 'w') as f: ....: _ = f.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: fname = 'test.py' sage: fullpath = os.path.join(t_dir, fname) sage: with open(fullpath, 'w') as f: ....: _ = f.write("print(37 * 3)") sage: load_attach_path(t_dir) sage: attach(fname) 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'] TESTS: Make sure that load handles filenames with spaces in the name or path:: sage: t = tmp_filename(ext=' b.sage') sage: with open(t, 'w') as f: ....: _ = f.write("print(2)") sage: sage.repl.load.load(t, globals()) 2 Non-existing files with spaces give correct messages:: sage: sage.repl.load.load("this file should not exist", globals()) Traceback (most recent call last): ... IOError: did not find file 'this file should not exist' to load or attach """ if attach: from sage.repl.attach import add_attached_file if isinstance(filename, bytes): # For Python 3 in particular, convert bytes filenames to str since the # rest of this functions operate on filename as a str filename = bytes_to_str(filename, FS_ENCODING, 'surrogateescape') filename = os.path.expanduser(filename) if filename.lower().startswith(('http://', 'https://')): if attach: # But see https://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 sage.misc.remote_file import get_remote_file filename = get_remote_file(filename, verbose=False) 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.isfile(fpath): break else: raise IOError('did not find file %r to load or attach' % filename) ext = os.path.splitext(fpath)[1].lower() if ext == '.py': if attach: add_attached_file(fpath) with open(fpath) as f: code = compile(f.read(), fpath, 'exec') exec(code, globals) elif ext == '.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) with open(fpath) as f: exec(preparse_file(f.read()) + "\n", globals) elif ext == '.spyx' or ext == '.pyx': if attach: add_attached_file(fpath) exec(load_cython(fpath), globals) elif ext == '.f' or ext == '.f90': from sage.misc.inline_fortran import fortran with open(fpath) as f: fortran(f.read(), globals) elif ext == '.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) else: raise ValueError('unknown file extension %r for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m)' % ext)
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)
def load(filename, globals, attach=False): r""" Executes a file in the scope given by ``globals``. 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 denoting a filename or URL. - ``globals`` -- a string:object dictionary; the context in which to execute the file 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()) # optional - python2 hi 0 sage: z # optional - python2 -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(tmp_filename(ext=".foo"), globals()) Traceback (most recent call last): ... ValueError: unknown file extension '.foo' for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m) 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'] TESTS: 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 Non-existing files with spaces give correct messages:: sage: sage.repl.load.load("this file should not exist", globals()) Traceback (most recent call last): ... IOError: did not find file 'this file should not exist' to load or attach """ if attach: from sage.repl.attach import add_attached_file filename = os.path.expanduser(filename) 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 sage.misc.remote_file import get_remote_file filename = get_remote_file(filename, verbose=False) 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.isfile(fpath): break else: raise IOError('did not find file %r to load or attach' % filename) ext = os.path.splitext(fpath)[1].lower() if ext == '.py': if attach: add_attached_file(fpath) with open(fpath) as f: code = compile(f.read(), fpath, 'exec') exec(code, globals) elif ext == '.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 ext == '.spyx' or ext == '.pyx': if attach: add_attached_file(fpath) exec(load_cython(fpath), globals) elif ext == '.f' or ext == '.f90': from sage.misc.inline_fortran import fortran with open(fpath) as f: fortran(f.read(), globals) elif ext == '.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) else: raise ValueError( 'unknown file extension %r for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m)' % ext)
def load(filename, globals, attach=False): r""" Executes a file in the scope given by ``globals``. 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 denoting a filename or URL. - ``globals`` -- a string:object dictionary; the context in which to execute the file 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(tmp_filename(ext=".foo"), globals()) Traceback (most recent call last): ... ValueError: unknown file extension '.foo' for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m) 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'] TESTS: 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 Non-existing files with spaces give correct messages:: sage: sage.repl.load.load("this file should not exist", globals()) Traceback (most recent call last): ... IOError: did not find file 'this file should not exist' to load or attach Evaluating a filename is deprecated:: sage: sage.repl.load.load("tmp_filename(ext='.py')", globals()) doctest:...: DeprecationWarning: using unevaluated expressions as argument to load() is dangerous and deprecated See http://trac.sagemath.org/17654 for details. Test filenames separated by spaces (deprecated):: sage: t = tmp_filename(ext='.py') sage: with open(t, 'w') as f: ....: f.write("print 'hello'\n") sage: sage.repl.load.load(t + " " + t, globals()) hello hello doctest:...: DeprecationWarning: using multiple filenames separated by spaces as load() argument is dangerous and deprecated See http://trac.sagemath.org/17654 for details. """ if attach: from sage.repl.attach import add_attached_file filename = os.path.expanduser(filename) if not os.path.exists(filename): try: # Try *evaluating* the filename filename = eval(filename, globals).strip() except Exception: # 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: try: for f in v: load(f, globals, attach=attach) except IOError: # Splitting the filename didn't work, pretend it # didn't happen :-) pass else: # Only show deprecation message if the filename # splitting worked. from sage.misc.superseded import deprecation deprecation(17654, 'using multiple filenames separated by spaces as load() argument is dangerous and deprecated') return else: from sage.misc.superseded import deprecation deprecation(17654, 'using unevaluated expressions as argument to load() is dangerous and deprecated') 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 sage.misc.remote_file import get_remote_file filename = get_remote_file(filename, verbose=False) 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.isfile(fpath): break else: raise IOError('did not find file %r to load or attach' % filename) ext = os.path.splitext(fpath)[1].lower() if ext == '.py': if attach: add_attached_file(fpath) with open(fpath) as f: code = compile(f.read(), fpath, 'exec') exec(code, globals) elif ext == '.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 ext == '.spyx' or ext == '.pyx': if attach: add_attached_file(fpath) exec(load_cython(fpath), globals) elif ext == '.f' or ext == '.f90': from sage.misc.inline_fortran import fortran with open(fpath) as f: fortran(f.read(), globals) elif ext == '.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) else: raise ValueError('unknown file extension %r for load or attach (supported extensions: .py, .pyx, .sage, .spyx, .f, .f90, .m)' % ext)