def preparse_worksheet_cell(s, globals): """ Preparse the contents of a worksheet cell in the notebook, respecting the user using ``preparser(False)`` to turn off the preparser. This function calls :func:`~sage.repl.preparse.preparse_file` which also reloads attached files. It also does displayhook formatting by calling the :func:`~sagenb.notebook.interfaces.format.displayhook_hack` function. INPUT: - ``s`` - a string containing code - ``globals`` - a string:object dictionary; passed directly to :func:`~sage.repl.preparse.preparse_file` OUTPUT: - a string """ if do_preparse(): s = preparse_file(s, globals=globals) s = displayhook_hack(s) if _automatic_names: s = automatic_name_filter(s) return s
def get_data(self, filename): """exec_module is already defined for us, we just have to provide a way of getting the source code of the module""" filename = os.path.abspath(filename) with open(filename) as f: contents = f.read() from sage.repl.preparse import handle_encoding_declaration, preparse_file #contents = handle_encoding_declaration(contents, out) parsed = preparse_file(contents) print(f'🐰 Importing {filename} via Sage preparser') header = '''from sage.all import * ''' return header + parsed
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 sage_eval(source, locals=None, cmds='', preparse=True): r""" Obtain a Sage object from the input string by evaluating it using Sage. This means calling eval after preparsing and with globals equal to everything included in the scope of ``from sage.all import *``.). INPUT: - ``source`` - a string or object with a _sage_ method - ``locals`` - evaluate in namespace of sage.all plus the locals dictionary - ``cmds`` - string; sequence of commands to be run before source is evaluated. - ``preparse`` - (default: True) if True, preparse the string expression. EXAMPLES: This example illustrates that preparsing is applied. :: sage: eval('2^3') 1 sage: sage_eval('2^3') 8 However, preparsing can be turned off. :: sage: sage_eval('2^3', preparse=False) 1 Note that you can explicitly define variables and pass them as the second option:: sage: x = PolynomialRing(RationalField(),"x").gen() sage: sage_eval('x^2+1', locals={'x':x}) x^2 + 1 This example illustrates that evaluation occurs in the context of ``from sage.all import *``. Even though bernoulli has been redefined in the local scope, when calling ``sage_eval`` the default value meaning of bernoulli is used. Likewise for QQ below. :: sage: bernoulli = lambda x : x^2 sage: bernoulli(6) 36 sage: eval('bernoulli(6)') 36 sage: sage_eval('bernoulli(6)') 1/42 :: sage: QQ = lambda x : x^2 sage: QQ(2) 4 sage: sage_eval('QQ(2)') 2 sage: parent(sage_eval('QQ(2)')) Rational Field This example illustrates setting a variable for use in evaluation. :: sage: x = 5 sage: eval('4/3 + x', {'x': 25}) # py2 26 sage: eval('4//3 + x', {'x': 25}) # py3 26 sage: sage_eval('4/3 + x', locals={'x': 25}) 79/3 You can also specify a sequence of commands to be run before the expression is evaluated:: sage: sage_eval('p', cmds='K.<x> = QQ[]\np = x^2 + 1') x^2 + 1 If you give commands to execute and a dictionary of variables, then the dictionary will be modified by assignments in the commands:: sage: vars = {} sage: sage_eval('None', cmds='y = 3', locals=vars) sage: vars['y'], parent(vars['y']) (3, Integer Ring) You can also specify the object to evaluate as a tuple. A 2-tuple is assumed to be a pair of a command sequence and an expression; a 3-tuple is assumed to be a triple of a command sequence, an expression, and a dictionary holding local variables. (In this case, the given dictionary will not be modified by assignments in the commands.) :: sage: sage_eval(('f(x) = x^2', 'f(3)')) 9 sage: vars = {'rt2': sqrt(2.0)} sage: sage_eval(('rt2 += 1', 'rt2', vars)) 2.41421356237309 sage: vars['rt2'] 1.41421356237310 This example illustrates how ``sage_eval`` can be useful when evaluating the output of other computer algebra systems. :: sage: R.<x> = PolynomialRing(RationalField()) sage: gap.eval('R:=PolynomialRing(Rationals,["x"]);') 'Rationals[x]' sage: ff = gap.eval('x:=IndeterminatesOfPolynomialRing(R);; f:=x^2+1;'); ff 'x^2+1' sage: sage_eval(ff, locals={'x':x}) x^2 + 1 sage: eval(ff) Traceback (most recent call last): ... RuntimeError: Use ** for exponentiation, not '^', which means xor in Python, and has the wrong precedence. Here you can see eval simply will not work but ``sage_eval`` will. TESTS: We get a nice minimal error message for syntax errors, that still points to the location of the error (in the input string):: sage: sage_eval('RR(22/7]') Traceback (most recent call last): ... File "<string>", line 1 RR(Integer(22)/Integer(7)] ^ SyntaxError: unexpected EOF while parsing :: sage: sage_eval('None', cmds='$x = $y[3] # Does Perl syntax work?') Traceback (most recent call last): ... File "<string>", line 1 $x = $y[Integer(3)] # Does Perl syntax work? ^ SyntaxError: invalid syntax """ if isinstance(source, (list, tuple)): cmds = source[0] if len(source) > 2: locals = copy(source[2]) source = source[1] if not isinstance(source, six.string_types): raise TypeError("source must be a string.") if locals is None: locals = {} import sage.all if len(cmds): cmd_seq = cmds + '\n_sage_eval_returnval_ = ' + source if preparse: cmd_seq = preparser.preparse_file(cmd_seq) else: if preparse: source = preparser.preparse(source) if len(cmds): exec(cmd_seq, sage.all.__dict__, locals) return locals['_sage_eval_returnval_'] else: return eval(source, sage.all.__dict__, locals)
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): 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): """ 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 execute(self): if self.calculation_time is not None: if self.is_uptodate(): return from tempfile import mkdtemp from shutil import rmtree oldwkdir = os.getcwd() old_stdout = sys.stdout if (test_ipython()): out = dualStdout(old_stdout=old_stdout) else: out = StringIO() wkdir = mkdtemp(suffix='pe') os.chdir(wkdir) codedir = os.path.join(wkdir, '.code') os.mkdir(codedir) code_filename = os.path.join(codedir, '_code.py') with open(code_filename, 'w') as f: f.write( '# -*- coding: utf-8 -*-\nfrom sage.all import *\nfrom pemongo import *\n' + preparse_file(self.code)) self.file_set = {} sys.stdout = out # import the code and collect results, finally cleanup try: mod = None # import the code module into mod and maybe collect exception try: mod = import_(code_filename) except Exception as e: from traceback import format_exc print('Exception:{}\r\n'.format(e)) print(format_exc() + '\r\n') # collect result, if applicable try: self.result = dict(mod.result) except AttributeError: self.result = {} # collect files onlyfiles = [ f for f in os.listdir(wkdir) if os.path.isfile(os.path.join(wkdir, f)) ] for i, filename in enumerate(onlyfiles): if os.path.getsize(os.path.join( wkdir, filename)) > self.MAX_FILESIZE_BYTES: raise RuntimeException('Too big file ' + filename) else: # the following is bad for large files. We however set a limit. with open(os.path.join(wkdir, filename), 'rb') as f: self.file_set[filename] = f.read() # cleanup finally: os.chdir(oldwkdir) sys.stdout = old_stdout rmtree(wkdir) # collect stdout self.output = out.getvalue() #.decode('utf-8') self.calculation_time = time.time()
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)