[IPython-user] pysh variable substituion and scope

Krishna Mohan Gundu gkmohan at gmail.com
Sun Jun 4 05:09:40 CDT 2006

On 6/3/06, Fernando Perez <fperez.net at gmail.com> wrote:
> On 6/3/06, Krishna Mohan Gundu <gkmohan at gmail.com> wrote:
> > Hello All,
> >
> > It looks like during variable substituion the scope is limited to the
> > global scope rather than the scope of the calling function. Can the
> > current behavior be modified to include the proper scope? In the
> > following example
> >
> > ===
> > gvar = 0
> >
> > def pysh_test(lvar):
> >    echo "$gvar $lvar"
> >
> > pysh_test(0)
> > ===
> >
> > gvar is substitued but lvar cannot be found in the scope
> Well, here you are relying on a convenience of ipython which
> automatically rewrites your interactive input in the definition:
> longs[~]|1> def foo():
>         |.>     echo "hi"
> line out:     _ip.system('echo "hi"')
>         |.>
> But the code:
> def foo():
>     echo "hi"
> is NOT valid python by itself.  IPython's convenience on-the-fly
> rewriting can only go so far.  For uses like these, simply write valid
> python code in the first place, and you can have much better control
> of what's going on.

After long hard fight (~ 8hrs) of reading through python reference
manuals and going through ipython code (I learnt a lot no regrets), I
find that this is pretty easy to implement (Actually I only changed
three lines of code in iplib.py). The basic problem is that in
interactive mode, for whatever reason, a local namespace is not stored
and hence whenever the execution is in a code block, a call to eval
(through Itpl) with only global namespace fails to recognize local
variables. The fix is to pass the local namespace as well to Itpl.
This can be done either by saving the local namespace in ip or
extracting the local namespace from the stack in ipsystem(). Both are
easy to implement but the latter is simpler. The diff is attached
inline if anyone is interested.

I understand that this falls into the territory of supporting
non-python type code. But I feel if it affords convenience I am all
for it. My basic complaint against python is that its file handling
and input/output redirection through pipes is tedious like C (although
much better than C). I need something that is more shell like. Not
having this ability in the middle of a function call does not sound
good to me. Although this is not an efficient method, I am willing to
lose speed over convenience. Any insight in this regard is welcome.


--- iplib.py    2006-06-03 16:41:45.000000000 -0700
+++ iplib_new2.py       2006-06-04 02:11:31.000000000 -0700
@@ -437,11 +437,11 @@
         # Functions to call the underlying shell.

         # utility to expand user variables via Itpl
-        self.var_expand = lambda cmd: str(ItplNS(cmd.replace('#','\#'),
-                                                 self.user_ns))
+        self.var_expand = lambda cmd,lvars=None:
+                                                 self.user_ns,lvars))
         # The first is similar to os.system, but it doesn't return a value,
         # and it allows interpolation of variables in the user's namespace.
-        self.system = lambda cmd: shell(self.var_expand(cmd),
+        self.system = lambda cmd,lvars=None: shell(self.var_expand(cmd,lvars),
                                         header='IPython system call: ',
         # These are for getoutput and getoutputerror:
@@ -896,7 +896,8 @@
     def ipsystem(self,arg_s):
         """Make a system call, using IPython."""

-        self.system(arg_s)
+        lvars = sys._getframe(0).f_back.f_locals
+        self.system(arg_s,lvars)

     def complete(self,text):
         """Return a sorted list of all possible completions on text.

More information about the IPython-user mailing list