Ticket #7502: 7502-lazy-import.patch

File 7502-lazy-import.patch, 7.1 KB (added by robertwb, 12 years ago)
  • new file sage/misc/lazy_import.py

    # HG changeset patch
    # User Robert Bradshaw <robertwb@math.washington.edu>
    # Date 1258708100 28800
    # Node ID 338c8a033ad60e64223bb57d2ce8e4dd819a036b
    # Parent  ee7dca3c711b08e7a8c2972bf2ce3e09163040c0
    Lazy import.
    
    diff -r ee7dca3c711b -r 338c8a033ad6 sage/misc/lazy_import.py
    - +  
     1#*****************************************************************************
     2#       Copyright (C) 2009 Robert Bradshaw <robertwb@math.washington.edu>
     3#
     4#  Distributed under the terms of the GNU General Public License (GPL)
     5#
     6#    This code is distributed in the hope that it will be useful,
     7#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     8#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     9#    General Public License for more details.
     10#
     11#  The full text of the GPL is available at:
     12#
     13#                  http://www.gnu.org/licenses/
     14#*****************************************************************************
     15
     16r"""
     17This module allows one to lazily import callable objects into the global
     18namespace, where the actual import is delayed until the object is actually
     19called or inspected. This is useful for modules that are expensive to import
     20or may cause circular references, though there is some overhead in its use.
     21
     22EXAMPLES::
     23
     24    sage: from sage.misc.lazy_import import lazy_import
     25    sage: lazy_import('sage.rings.all', 'ZZ')
     26    sage: type(ZZ)
     27    <class 'sage.misc.lazy_import.LazyImport'>
     28    sage: ZZ(4.0)
     29    4
     30
     31AUTHOR:
     32
     33 - Robert Bradshaw
     34"""
     35
     36import inspect
     37import sageinspect
     38
     39class LazyImport(object):
     40    """
     41    EXAMPLES::
     42   
     43        sage: from sage.misc.lazy_import import LazyImport
     44        sage: my_integer = LazyImport('sage.rings.all', 'Integer')
     45        sage: my_integer(4)
     46        4
     47        sage: my_integer('101', base=2)
     48        5
     49        sage: my_integer(3/2)
     50        Traceback (most recent call last):
     51        ...
     52        TypeError: no conversion of this rational to integer
     53    """
     54    def __init__(self, module, name):
     55        """
     56        EXAMPLES::
     57       
     58            sage: from sage.misc.lazy_import import LazyImport
     59            sage: my_isprime = LazyImport('sage.all', 'is_prime')
     60            sage: my_isprime(5)
     61            True
     62            sage: my_isprime(55)
     63            False
     64        """
     65        self._module = module
     66        self._name = name
     67        self._object = None
     68   
     69    def _get_object(self):
     70        """
     71        Return the wrapped object, importing it if necessary.
     72       
     73        EXAMPLE::
     74       
     75            sage: from sage.misc.lazy_import import LazyImport
     76            sage: my_integer_ring = LazyImport('sage.rings.all', 'ZZ')
     77            sage: my_integer_ring._object is None
     78            True
     79            sage: my_integer_ring._get_object()
     80            Integer Ring
     81            sage: my_integer_ring._object is None
     82            False
     83        """
     84        if self._object is None:
     85            self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
     86        return self._object
     87   
     88    def _sage_doc_(self):
     89        """
     90        Return the docstring of the wrapped object for introspection.
     91       
     92        EXAMPLES::
     93       
     94            sage: from sage.misc.lazy_import import LazyImport
     95            sage: my_isprime = LazyImport('sage.all', 'is_prime')
     96            sage: my_isprime._sage_doc_() is is_prime.__doc__
     97            True
     98        """
     99        return sageinspect.sage_getdoc(self._get_object())
     100   
     101    def _sage_src_(self):
     102        """
     103        Returns the source of the wrapped object for introspection.
     104       
     105        EXAMPLES::
     106
     107            sage: from sage.misc.lazy_import import LazyImport
     108            sage: my_isprime = LazyImport('sage.all', 'is_prime')
     109            sage: 'def is_prime(' in my_isprime._sage_src_()
     110            True
     111        """
     112        return sageinspect.sage_getsource(self._get_object())
     113   
     114    def _sage_argspec_(self):
     115        """
     116        Returns the argspec of the wrapped object for introspection.
     117       
     118        EXAMPLES::
     119       
     120            sage: from sage.misc.lazy_import import LazyImport
     121            sage: rm = LazyImport('sage.all', 'random_matrix')
     122            sage: rm._sage_argspec_()
     123            (['R', 'nrows', 'ncols', 'sparse', 'density'],
     124             'args',
     125             'kwds',
     126             (None, False, 1))
     127        """
     128        return sageinspect.sage_getargspec(self._get_object())
     129   
     130    def __getattr__(self, attr):
     131        """
     132        Attribute lookup on self defers to attribute lookup on the wrapped object.
     133       
     134        EXAMPLES::
     135           
     136            sage: from sage.misc.lazy_import import LazyImport
     137            sage: my_integer = LazyImport('sage.rings.all', 'Integer')
     138            sage: my_integer.sqrt is Integer.sqrt
     139            True
     140        """
     141        return getattr(self._get_object(), attr)
     142   
     143    def __call__(self, *args, **kwds):
     144        """
     145        Calling self calls the wrapped object.
     146       
     147        EXAMPLES::
     148       
     149            sage: from sage.misc.lazy_import import LazyImport
     150            sage: my_isprime = LazyImport('sage.all', 'is_prime')
     151            sage: my_isprime(12)
     152            False
     153            sage: my_isprime(13)
     154            True
     155        """
     156        return self._get_object()(*args, **kwds)
     157
     158def lazy_import(module, names, _as=None):
     159    """
     160    Create a lazy import object and inject it into the callers global
     161    namespace. For the purposes of introspection and calling, this
     162    like performing a lazy "from module import name" where the import
     163    is delayed until the object actually is used or inspected.
     164   
     165    EXAMPLES::
     166   
     167        sage: from sage.misc.lazy_import import lazy_import
     168        sage: lazy_import('sage.rings.all', 'ZZ')
     169        sage: type(ZZ)
     170        <class 'sage.misc.lazy_import.LazyImport'>
     171        sage: ZZ(4.0)
     172        4
     173        sage: lazy_import('sage.rings.all', 'RDF', 'my_RDF')
     174        sage: my_RDF(1/2)
     175        0.5
     176        sage: my_RDF._get_object() is RDF
     177        True
     178       
     179        sage: lazy_import('sage.all', ['QQ', 'RR'], ['my_QQ', 'my_RR'])
     180        sage: my_QQ._get_object() is QQ
     181        True
     182        sage: my_RR._get_object() is RR
     183        True
     184    """
     185    if _as is None:
     186        _as = names
     187    if isinstance(names, str):
     188        names = [names]
     189        _as = [_as]
     190    calling_globals = inspect.currentframe().f_back.f_globals
     191    for name, alias in zip(names, _as):
     192        if alias is None:
     193            alias = name
     194        calling_globals[alias] = LazyImport(module, name)
  • sage/misc/sageinspect.py

    diff -r ee7dca3c711b -r 338c8a033ad6 sage/misc/sageinspect.py
    a b  
    352352    if not callable(obj):
    353353        raise TypeError, "obj is not a code object"
    354354   
     355    if hasattr(obj, '_sage_argspec_'):
     356        return obj._sage_argspec_()
    355357    if inspect.isfunction(obj):
    356358        func_obj = obj
    357359    elif inspect.ismethod(obj):