Ticket #378: trac_378-load_attach_path.2.patch

File trac_378-load_attach_path.2.patch, 12.3 KB (added by mpatel, 12 years ago)

More examples. Handle absolute paths. Replaces previous.

  • sage/misc/all.py

    # HG changeset patch
    # User Mitesh Patel <qed777@gmail.com>
    # Date 1266709537 28800
    # Node ID 054a69ffd6067d1790350cb6cc2a8c1a4836a0be
    # Parent  0914acb8ba5e89e591daf0de70366b7beab828ab
    #378: Configurable load + attach path
    
    diff --git a/sage/misc/all.py b/sage/misc/all.py
    a b from mathml import mathml 
    6161
    6262from defaults import set_default_variable_name
    6363
    64 from preparser import preparse, implicit_multiplication, BackslashOperator, attached_files, detach
     64from preparser import preparse, implicit_multiplication, BackslashOperator, attached_files, detach, load_attach_path
    6565
    6666from interpreter import preparser
    6767
  • sage/misc/preparser.py

    diff --git a/sage/misc/preparser.py b/sage/misc/preparser.py
    a b class BackslashOperator: 
    13631363def is_loadable_filename(filename):
    13641364    """
    13651365    Returns whether a file can be loaded into Sage.  This checks only
    1366     whether its name ends in one of the supported extensions .py,
    1367     .pyx, .sage, and .spyx.
     1366    whether its name ends in one of the supported extensions ``.py``,
     1367    ``.pyx``, ``.sage``, ``.spyx``, and ``.m``.  Note: :func:`load`
     1368    assumes the latter signifies a Magma file.
    13681369
    13691370    INPUT:
    13701371
    def is_loadable_filename(filename): 
    13821383        False
    13831384        sage: sage.misc.preparser.is_loadable_filename('foo.sage')
    13841385        True
     1386        sage: sage.misc.preparser.is_loadable_filename('foo.m')
     1387        True
    13851388    """
    1386     # Loop over list of supported code file extensions for the load function.   
    1387     for ext in ['.py', '.pyx', '.sage', '.spyx']:
    1388         if filename.endswith(ext):
    1389             return True
     1389    if filename.endswith(('.py', '.pyx', '.sage', '.spyx', '.m')):
     1390        return True
    13901391    return False
    13911392
     1393
     1394# Set up the initial search path for loading and attaching files.  A
     1395# user can modify the path with the function load_attach_path.
     1396_load_attach_path = ['.']
     1397if 'SAGE_LOAD_ATTACH_PATH' in os.environ:
     1398    _load_attach_path.extend(os.environ['SAGE_LOAD_ATTACH_PATH'].split(':'))
     1399    if '' in _load_attach_path:
     1400        _load_attach_path.remove('')
     1401
     1402
    13921403def load(filename, globals, attach=False):
    13931404    """
    13941405    Executes a file in the scope given by ``globals``.  The
    13951406    ``filename`` itself is also evaluated in the scope.  If the name
    1396     starts with http://, it is treated as a URL and downloaded.
     1407    starts with ``http://``, it is treated as a URL and downloaded.
    13971408
    13981409    .. note:: For Cython files, the situation is more complicated --
    1399        the module is first compiled to a temporary module t and
     1410       the module is first compiled to a temporary module ``t`` and
    14001411       executed via::
    14011412
    14021413           from t import *
    def load(filename, globals, attach=False 
    14451456        sage: sage.misc.preparser.load('a.foo',globals())
    14461457        Traceback (most recent call last):
    14471458        ...
    1448         ValueError: argument (='a.foo') to load or attach must have extension py, sage, or pyx
     1459        ValueError: argument (='a.foo') to load or attach must have extension py, pyx, sage, spyx, or m
    14491460
    14501461    A filename given as an expression get evaluated.  This ensures
    14511462    that ``load DATA+'foo.sage'`` works in the Notebook, say::
    def load(filename, globals, attach=False 
    14641475        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
    14651476        sage: sage.misc.preparser.load(t, globals(), attach=True)
    14661477        hello world
    1467         sage: t in sage.misc.preparser.attached
     1478        sage: os.path.normpath(t) in sage.misc.preparser.attached
    14681479        True
    14691480
    14701481    You can't attach remote URLs (yet)::
    def load(filename, globals, attach=False 
    14731484        Traceback (most recent call last):
    14741485        ...
    14751486        NotImplementedError: you can't attach a URL
     1487
     1488    The default search path for loading and attaching files is the
     1489    current working directory, i.e., ``'.'``.  But you can modify the
     1490    path with :func:`load_attach_path`::
     1491
     1492        sage: sage.misc.reset.reset_attached(); load_attach_path(reset=True)
     1493        sage: load_attach_path()
     1494        ['.']
     1495        sage: t_dir = tmp_dir()
     1496        sage: fullpath = os.path.join(t_dir, 'test.py')
     1497        sage: open(fullpath, 'w').write("print 37 * 3")
     1498        sage: load_attach_path(t_dir)
     1499        sage: attach('test.py')
     1500        111
     1501        sage: sage.misc.reset.reset_attached(); load_attach_path(reset=True) # clean up
     1502
     1503    or by setting the environment variable ``SAGE_LOAD_ATTACH_PATH``
     1504    to a colon-separated list before starting Sage::
     1505
     1506        $ export SAGE_LOAD_ATTACH_PATH="/path/to/my/library:/path/to/utils"
     1507        $ sage
     1508        sage: load_attach_path()          # not tested
     1509        ['.', '/path/to/my/library', '/path/to/utils']
    14761510    """
    14771511    try:
    14781512        filename = eval(filename, globals)
    def load(filename, globals, attach=False 
    14851519            for file in v:
    14861520                load(file, globals, attach=attach)
    14871521            return
    1488        
     1522
    14891523    filename = filename.strip()
    14901524   
    14911525    if filename.lower().startswith('http://'):
    def load(filename, globals, attach=False 
    14931527            # But see http://en.wikipedia.org/wiki/HTTP_ETag for how
    14941528            # we will do this.
    14951529            # http://www.diveintopython.org/http_web_services/etags.html
    1496             raise NotImplementedError, "you can't attach a URL"
     1530            raise NotImplementedError("you can't attach a URL")
    14971531        from remote_file import get_remote_file
    14981532        filename = get_remote_file(filename, verbose=False)
    14991533
    1500     if filename.endswith('.py'):
    1501         execfile(filename, globals)
    1502     elif filename.endswith('.sage'):
    1503         exec(preparse_file(open(filename).read()), globals)
    1504     elif filename.endswith('.spyx') or filename.endswith('.pyx'):
     1534    if not is_loadable_filename(filename):
     1535        raise ValueError('argument (=%r) to load or attach must have extension py, pyx, sage, spyx, or m' % filename)
     1536
     1537    fpath = filename
     1538    if not os.path.isabs(fpath):
     1539        global _load_attach_path
     1540        for path in _load_attach_path:
     1541            fpath = os.path.join(path, filename)
     1542            if os.path.exists(fpath):
     1543                break
     1544
     1545    if not os.path.exists(fpath):
     1546        if os.path.isabs(filename):
     1547            raise IOError('did not find file %r to load or attach' % filename)
     1548        else:
     1549            raise IOError('did not find file %r in load / attach search path' % filename)
     1550
     1551    if fpath.endswith('.py'):
     1552        execfile(fpath, globals)
     1553    elif fpath.endswith('.sage'):
     1554        exec(preparse_file(open(fpath).read()), globals)
     1555    elif fpath.endswith('.spyx') or fpath.endswith('.pyx'):
    15051556        import interpreter
    1506         exec(interpreter.load_cython(filename), globals)
    1507     elif filename.endswith('.m'):
     1557        exec(interpreter.load_cython(fpath), globals)
     1558    elif fpath.endswith('.m'):
    15081559        # Assume magma for now, though maybe .m is used by maple and
    15091560        # mathematica too, and we should really analyze the file
    15101561        # further.
    1511         s = globals['magma'].load(filename)
     1562        s = globals['magma'].load(fpath)
    15121563        i = s.find('\n'); s = s[i+1:]
    15131564        print s
     1565
     1566    if attach:
     1567        # TODO: Use the MD5 hash of the file, instead.
     1568        fpath = os.path.abspath(fpath)
     1569        attached[fpath] = os.path.getmtime(fpath)
     1570
     1571
     1572def load_attach_path(path=None, replace=False, reset=False):
     1573    """
     1574    Get or modify the current search path for loading and attaching
     1575    files.
     1576
     1577    INPUT:
     1578
     1579    - ``path`` - string or list of strings (default: None); path(s) to
     1580      append to or replace the current path
     1581
     1582    - ``replace`` - boolean (default: False); if ``path`` is not None,
     1583      whether to *replace* the search path instead of *appending* to
     1584      it
     1585
     1586    - ``reset`` - boolean (default: False); whether to reset the
     1587      search path to ``'.'``.  This overrides the other arguments.
     1588
     1589    OUTPUT:
     1590
     1591    - None or a *reference* to the current list of search paths
     1592
     1593    EXAMPLES:
     1594
     1595    First, we extend the example given in :func:`load`'s docstring::
     1596
     1597        sage: sage.misc.reset.reset_attached(); load_attach_path(reset=True)
     1598        sage: load_attach_path()
     1599        ['.']
     1600        sage: t_dir = tmp_dir()
     1601        sage: fullpath = os.path.join(t_dir, 'test.py')
     1602        sage: open(fullpath, 'w').write("print 37 * 3")
     1603        sage: attach('test.py')
     1604        Traceback (most recent call last):
     1605        ...
     1606        IOError: did not find file 'test.py' in load / attach search path
     1607        sage: load_attach_path(t_dir)
     1608        sage: attach('test.py')
     1609        111
     1610        sage: attached_files() == [fullpath]
     1611        True       
     1612        sage: sage.misc.reset.reset_attached(); load_attach_path(reset=True)
     1613        sage: load_attach_path() == ['.']
     1614        True
     1615        sage: load('test.py')
     1616        Traceback (most recent call last):
     1617        ...
     1618        IOError: did not find file 'test.py' in load / attach search path
     1619
     1620    The function returns a reference to the path list::
     1621
     1622        sage: load_attach_path(reset=True); load_attach_path()
     1623        ['.']
     1624        sage: load_attach_path('/path/to/my/sage/scripts'); load_attach_path()
     1625        ['.', '/path/to/my/sage/scripts']
     1626        sage: load_attach_path(['good', 'bad', 'ugly'], replace=True); load_attach_path()
     1627        ['good', 'bad', 'ugly']
     1628        sage: p = load_attach_path(); p.pop(); p[0] = 'weird'; load_attach_path()
     1629        'ugly'
     1630        ['weird', 'bad']
     1631        sage: load_attach_path(reset=True); load_attach_path()
     1632        ['.']
     1633
     1634    At startup, Sage adds colon-separated paths in the environment
     1635    variable ``SAGE_LOAD_ATTACH_PATH``::
     1636
     1637        sage: load_attach_path(reset=True); load_attach_path()
     1638        ['.']
     1639        sage: os.environ['SAGE_LOAD_ATTACH_PATH'] = '/veni/vidi:vici:'
     1640        sage: reload(sage.misc.preparser)    # Simulate startup
     1641        <module 'sage.misc.preparser' from '...'>
     1642        sage: load_attach_path()
     1643        ['.', '/veni/vidi', 'vici']
     1644        sage: del os.environ['SAGE_LOAD_ATTACH_PATH']
     1645        sage: load_attach_path(reset=True)
     1646    """
     1647    global _load_attach_path
     1648
     1649    if reset is True:
     1650        _load_attach_path = ['.']
     1651
     1652    elif path is None:
     1653        return _load_attach_path
     1654
    15141655    else:
    1515         raise ValueError, "argument (='%s') to load or attach must have extension py, sage, or pyx"%filename
     1656        if isinstance(path, basestring):
     1657            path = [path]
    15161658
    1517     if attach and os.path.exists(filename):
    1518         attached[filename] = os.path.getmtime(filename)
     1659        if replace:
     1660            _load_attach_path = path
     1661        else:
     1662            for p in path:
     1663                if p not in _load_attach_path:
     1664                    _load_attach_path.append(p)
    15191665
    15201666
    15211667import base64   
    def attached_files(): 
    15981744
    15991745        sage: sage.misc.reset.reset_attached()
    16001746        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     1747        sage: t = os.path.normpath(t)
    16011748        sage: attach(t)
    16021749        hello world
    16031750        sage: attached_files() == [t]
    16041751        True
    1605    
    16061752    """
    16071753    return list(sorted(attached.keys()))
    16081754
    def detach(filename): 
    16181764
    16191765        sage: sage.misc.reset.reset_attached()
    16201766        sage: t=tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     1767        sage: t = os.path.normpath(t)
    16211768        sage: attach(t)
    16221769        hello world
    16231770        sage: attached_files() == [t]
    def detach(filename): 
    16261773        sage: attached_files()
    16271774        []
    16281775    """
    1629     if attached.has_key(filename):
    1630         del attached[filename]
     1776    attached.pop(filename, None)
  • sage/misc/reset.pyx

    diff --git a/sage/misc/reset.pyx b/sage/misc/reset.pyx
    a b def reset_attached(): 
    128128   
    129129        sage: sage.misc.reset.reset_attached()
    130130        sage: t = tmp_filename()+'.py'; open(t,'w').write("print 'hello world'")
     131        sage: t = os.path.normpath(t)
    131132        sage: attach(t)
    132133        hello world
    133134        sage: attached_files() == [t]
  • sage/misc/session.pyx

    diff --git a/sage/misc/session.pyx b/sage/misc/session.pyx
    a b def attach(*files): 
    380380        sage: sage.misc.reset.reset_attached()
    381381        sage: t1=tmp_filename()+'.py'; open(t1,'w').write("print 'hello world'")
    382382        sage: t2=tmp_filename()+'.py'; open(t2,'w').write("print 'hi there xxx'")
     383        sage: t1, t2 = map(os.path.normpath, (t1, t2))
    383384        sage: attach(t1, t2)
    384385        hello world
    385386        hi there xxx