Ticket #7482: sagenb_7482.4.patch

File sagenb_7482.4.patch, 8.5 KB (added by mpatel, 11 years ago)

Rebased vs. #7514's "part3.2". Replaces sagenb patch.

  • sagenb/misc/support.py

    # HG changeset patch
    # User William Stein <wstein@gmail.com>
    # Date 1258514927 28800
    # Node ID 487a2d494bb4a87aae1909f12d2af6f303c370a5
    # Parent  4581c4cb69348e86f83863378af8e3ae4671905f
    trac 7482 -- provide a mode so that undeclared variables magically spring into existence and object oriented notation is not necessary
    
    diff --git a/sagenb/misc/support.py b/sagenb/misc/support.py
    a b AUTHORS: 
    1010
    1111import inspect
    1212import os
     13import base64
    1314import string
    1415import sys
    1516import __builtin__
    def help(obj): 
    9596
    9697       This a wrapper around the built-in help. If formats the output
    9798       as HTML without word wrap, which looks better in the notebook.
    98    
     99
    99100    INPUT:
    100101   
    101102    -  ``obj`` - a Python object, module, etc.
    def completions(s, globs, format=False,  
    150151   
    151152    - ``system`` - a string (default: 'None'); system prefix for the
    152153      completions
     154
     155    OUTPUT:
     156
     157    - a list of strings, if ``format`` is False, or a string
    153158    """
    154159    if system not in ['sage', 'python']:
    155160        prepend = system + '.'
    except ImportError: 
    538543        """
    539544        return False
    540545
     546
     547########################################################################
     548#
     549# Automatic Creation of Variable Names
     550#
     551# See the docstring for automatic_names below for an explanation of how
     552# this works.
     553#
     554########################################################################
     555
     556_automatic_names = False
     557# We wrap everything in a try/catch, in case this is being imported
     558# without the sage library present, e.g., in FEMhub.
     559try:
     560    from sage.symbolic.all import Expression, SR
     561    class AutomaticVariable(Expression):
     562        """
     563        An automatically created symbolic variable with an additional
     564        :meth:`__call__` method designed so that doing self(foo,...)
     565        results in foo.self(...).
     566        """
     567        def __call__(self, *args, **kwds):
     568            """
     569            Call method such that self(foo, ...) is transformed into
     570            foo.self(...).  Note that self(foo=...,...) is not
     571            transformed, it is treated as a normal symbolic
     572            substitution.
     573            """
     574            if len(args) == 0:
     575                return Expression.__call__(self, **kwds)
     576            return args[0].__getattribute__(str(self))(*args[1:], **kwds)
     577
     578    def automatic_name_eval(s, globals, max_names=10000):
     579        """
     580        Exec the string ``s`` in the scope of the ``globals``
     581        dictionary, and if any :exc:`NameError`\ s are raised, try to
     582        fix them by defining the variable that caused the error to be
     583        raised, then eval again.  Try up to ``max_names`` times.
     584       
     585        INPUT:
     586
     587           - ``s`` -- a string
     588           - ``globals`` -- a dictionary
     589           - ``max_names`` -- a positive integer (default: 10000)
     590        """
     591        # This entire automatic naming system really boils down to
     592        # this bit of code below.  We simply try to exec the string s
     593        # in the globals namespace, defining undefined variables and
     594        # functions until everything is defined.
     595        for _ in range(max_names):
     596            try:
     597                exec s in globals
     598                return
     599            except NameError, msg:
     600                # Determine if we hit a NameError that is probably
     601                # caused by a variable or function not being defined:
     602                if len(msg.args) == 0: raise  # not NameError with
     603                                              # specific variable name
     604                v = msg.args[0].split("'")
     605                if len(v) < 2: raise  # also not NameError with
     606                                      # specific variable name We did
     607                                      # find an undefined variable: we
     608                                      # simply define it and try
     609                                      # again.
     610                nm = v[1]
     611                globals[nm] = AutomaticVariable(SR, SR.var(nm))
     612        raise NameError, "Too many automatic variable names and functions created (limit=%s)"%max_names
     613
     614    def automatic_name_filter(s):
     615        """
     616        Wrap the string ``s`` in a call that will cause evaluation of
     617        ``s`` to automatically create undefined variable names.
     618
     619        INPUT:
     620
     621           - ``s`` -- a string
     622
     623        OUTPUT:
     624
     625           - a string
     626        """
     627        return '_support_.automatic_name_eval(_support_.base64.b64decode("%s"),globals())'%base64.b64encode(s)
     628
     629    def automatic_names(state=None):
     630        """
     631        Turn automatic creation of variables and functional calling of
     632        methods on or off.  Returns the current ``state`` if no
     633        argument is given.
     634
     635        This ONLY works in the Sage notebook.  It is not supported on
     636        the command line.
     637
     638        INPUT:
     639
     640        - ``state`` -- a boolean (default: None); whether to turn
     641          automatic variable creation and functional calling on or off
     642
     643        OUTPUT:
     644
     645        - a boolean, if ``state`` is None; otherwise, None
     646
     647        EXAMPLES::
     648
     649            sage: automatic_names(True)      # not tested
     650            sage: x + y + z                  # not tested
     651            x + y + z
     652
     653        Here, ``trig_expand``, ``y``, and ``theta`` are all
     654        automatically created::
     655       
     656            sage: trig_expand((2*x + 4*y + sin(2*theta))^2)   # not tested
     657            4*(sin(theta)*cos(theta) + x + 2*y)^2
     658           
     659        IMPLEMENTATION: Here's how this works, internally.  We define
     660        an :class:`AutomaticVariable` class derived from
     661        :class:`~sage.symbolic.all.Expression`.  An instance of
     662        :class:`AutomaticVariable` is a specific symbolic variable,
     663        but with a special :meth:`~AutomaticVariable.__call__` method.
     664        We overload the call method so that ``foo(bar, ...)`` gets
     665        transformed to ``bar.foo(...)``.  At the same time, we still
     666        want expressions like ``f^2 - b`` to work, i.e., we don't want
     667        to have to figure out whether a name appearing in a
     668        :exc:`NameError` is meant to be a symbolic variable or a
     669        function name. Instead, we just make an object that is both!
     670
     671        This entire approach is very simple---we do absolutely no
     672        parsing of the actual input.  The actual real work amounts to
     673        only a few lines of code.  The primary catch to this approach
     674        is that if you evaluate a big block of code in the notebook,
     675        and the first few lines take a long time, and the next few
     676        lines define 10 new variables, the slow first few lines will
     677        be evaluated 10 times.  Of course, the advantage of this
     678        approach is that even very subtle code that might inject
     679        surprisingly named variables into the namespace will just work
     680        correctly, which would be impossible to guarantee with static
     681        parsing, no matter how sophisticated it is.  Finally, given
     682        the target audience: people wanting to simplify use of Sage
     683        for Calculus for undergrads, I think this is an acceptable
     684        tradeoff, especially given that this implementation is so
     685        simple.
     686        """
     687        global _automatic_names
     688        if state is None:
     689            return _automatic_names
     690        _automatic_names = bool(state)
     691       
     692except ImportError:
     693    pass
     694
    541695from sagenb.interfaces.format import displayhook_hack
     696
    542697def preparse_worksheet_cell(s, globals):
    543698    """
    544699    Preparse the contents of a worksheet cell in the notebook,
    545700    respecting the user using ``preparser(False)`` to turn off the
    546     preparser.  This function calls ``preparse_file`` which also
    547     reloads attached files.  It also does displayhook formatting by
    548     calling the format.displayhook_hack function.
     701    preparser.  This function calls
     702    :func:`~sage.misc.preparser.preparse_file` which also reloads
     703    attached files.  It also does displayhook formatting by calling
     704    the :func:`~sagenb.notebook.interfaces.format.displayhook_hack`
     705    function.
    549706
    550707    INPUT:
    551708
    552         - `s` -- string containing code
     709    - ``s`` - a string containing code
     710
     711    - ``globals`` - a string:object dictionary; passed directly to
     712      :func:`~sage.misc.preparser.preparse_file`
    553713
    554714    OUTPUT:
    555715
    556         - string
     716        - a string
    557717    """
    558718    if do_preparse():
    559719        s = preparse_file(s, globals=globals)
    560     return displayhook_hack(s)
     720    s = displayhook_hack(s)
     721    if _automatic_names:
     722        s = automatic_name_filter(s)
     723    return s