From a0ad5ffcd7c1bf6163a503b72d191d9d0082f1be 2008-08-12 15:53:45 From: gvaroquaux Date: 2008-08-12 15:53:45 Subject: [PATCH] Merge with upstream. --- diff --git a/IPython/Shell.py b/IPython/Shell.py index 9d182bc..0f65813 100644 --- a/IPython/Shell.py +++ b/IPython/Shell.py @@ -510,7 +510,7 @@ class MatplotlibShellBase: Given Python's MRO, this should be used as the FIRST class in the inheritance hierarchy, so that it overrides the relevant methods.""" - def _matplotlib_config(self,name,user_ns): + def _matplotlib_config(self,name,user_ns,user_global_ns=None): """Return items needed to setup the user's shell with matplotlib""" # Initialize matplotlib to interactive mode always @@ -564,7 +564,8 @@ class MatplotlibShellBase: self.pylab.draw_if_interactive = flag_calls(self.pylab.draw_if_interactive) # Build a user namespace initialized with matplotlib/matlab features. - user_ns = IPython.ipapi.make_user_ns(user_ns) + user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns, + user_global_ns) # Import numpy as np/pyplot as plt are conventions we're trying to # somewhat standardize on. Making them available to users by default @@ -584,7 +585,7 @@ class MatplotlibShellBase: Welcome to pylab, a matplotlib-based Python environment. For more information, type 'help(pylab)'. """ - return user_ns,b + return user_ns,user_global_ns,b def mplot_exec(self,fname,*where,**kw): """Execute a matplotlib script. @@ -624,7 +625,7 @@ class MatplotlibShell(MatplotlibShellBase,InteractiveShell): def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), user_ns=None,user_global_ns=None,**kw): - user_ns,b2 = self._matplotlib_config(name,user_ns) + user_ns,user_global_ns,b2 = self._matplotlib_config(name,user_ns,user_global_ns) InteractiveShell.__init__(self,name,usage,rc,user_ns,user_global_ns, banner2=b2,**kw) diff --git a/IPython/ipapi.py b/IPython/ipapi.py index 2c73611..7026df3 100644 --- a/IPython/ipapi.py +++ b/IPython/ipapi.py @@ -567,17 +567,7 @@ def make_user_ns(user_ns = None): classes in ipython. """ - if user_ns is None: - # Set __name__ to __main__ to better match the behavior of the - # normal interpreter. - user_ns = {'__name__' :'__main__', - '__builtins__' : __builtin__, - } - else: - user_ns.setdefault('__name__','__main__') - user_ns.setdefault('__builtins__',__builtin__) - - return user_ns + raise NotImplementedError def make_user_global_ns(ns = None): @@ -587,8 +577,56 @@ def make_user_global_ns(ns = None): embedded applications, where there is a distinction between the user's interactive namespace and the global one where ipython is running.""" - if ns is None: ns = {} - return ns + raise NotImplementedError + +# Record the true objects in order to be able to test if the user has overridden +# these API functions. +_make_user_ns = make_user_ns +_make_user_global_ns = make_user_global_ns + + +def make_user_namespaces(user_ns = None,user_global_ns = None): + """Return a valid local and global user interactive namespaces. + + This builds a dict with the minimal information needed to operate as a + valid IPython user namespace, which you can pass to the various embedding + classes in ipython. The default implementation returns the same dict for + both the locals and the globals to allow functions to refer to variables in + the namespace. Customized implementations can return different dicts. The + locals dictionary can actually be anything following the basic mapping + protocol of a dict, but the globals dict must be a true dict, not even + a subclass. It is recommended that any custom object for the locals + namespace synchronize with the globals dict somehow. + + Raises TypeError if the provided globals namespace is not a true dict. + """ + + if user_ns is None: + if make_user_ns is not _make_user_ns: + # Old API overridden. + # FIXME: Issue DeprecationWarning, or just let the old API live on? + user_ns = make_user_ns(user_ns) + else: + # Set __name__ to __main__ to better match the behavior of the + # normal interpreter. + user_ns = {'__name__' :'__main__', + '__builtins__' : __builtin__, + } + else: + user_ns.setdefault('__name__','__main__') + user_ns.setdefault('__builtins__',__builtin__) + + if user_global_ns is None: + if make_user_global_ns is not _make_user_global_ns: + # Old API overridden. + user_global_ns = make_user_global_ns(user_global_ns) + else: + user_global_ns = user_ns + if type(user_global_ns) is not dict: + raise TypeError("user_global_ns must be a true dict; got %r" + % type(user_global_ns)) + + return user_ns, user_global_ns def make_session(user_ns = None, shellclass = None): diff --git a/IPython/iplib.py b/IPython/iplib.py index 1162e9f..64713eb 100644 --- a/IPython/iplib.py +++ b/IPython/iplib.py @@ -207,7 +207,7 @@ class InteractiveShell(object,Magic): isthreaded = False def __init__(self,name,usage=None,rc=Struct(opts=None,args=None), - user_ns = None,user_global_ns=None,banner2='', + user_ns=None,user_global_ns=None,banner2='', custom_exceptions=((),None),embedded=False): # log system @@ -254,7 +254,8 @@ class InteractiveShell(object,Magic): # the locals argument. But we do carry a user_global_ns namespace # given as the exec 'globals' argument, This is useful in embedding # situations where the ipython shell opens in a context where the - # distinction between locals and globals is meaningful. + # distinction between locals and globals is meaningful. For + # non-embedded contexts, it is just the same object as the user_ns dict. # FIXME. For some strange reason, __builtins__ is showing up at user # level as a dict instead of a module. This is a manual fix, but I @@ -284,14 +285,12 @@ class InteractiveShell(object,Magic): # These routines return properly built dicts as needed by the rest of # the code, and can also be used by extension writers to generate # properly initialized namespaces. - user_ns = IPython.ipapi.make_user_ns(user_ns) - user_global_ns = IPython.ipapi.make_user_global_ns(user_global_ns) - + user_ns, user_global_ns = IPython.ipapi.make_user_namespaces(user_ns, + user_global_ns) + # Assign namespaces # This is the namespace where all normal user variables live self.user_ns = user_ns - # Embedded instances require a separate namespace for globals. - # Normally this one is unused by non-embedded instances. self.user_global_ns = user_global_ns # A namespace to keep track of internal data structures to prevent # them from cluttering user-visible stuff. Will be updated later @@ -2071,16 +2070,7 @@ want to merge them back into the new files.""" % locals() try: try: self.hooks.pre_runcode_hook() - # Embedded instances require separate global/local namespaces - # so they can see both the surrounding (local) namespace and - # the module-level globals when called inside another function. - if self.embedded: - exec code_obj in self.user_global_ns, self.user_ns - # Normal (non-embedded) instances should only have a single - # namespace for user code execution, otherwise functions won't - # see interactive top-level globals. - else: - exec code_obj in self.user_ns + exec code_obj in self.user_global_ns, self.user_ns finally: # Reset our crash handler in place sys.excepthook = old_excepthook