Beispiel #1
0
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
Beispiel #3
0
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)