nmgeek nmgeek - 11 months ago 41
Bash Question

Syntax error in a correct python script when redirected to stdin

Using the bash shell on Ubuntu Linux and Python 2.7.6, if I run the python script below with the command,

python test.py

I get this output:


If I, instead, use redirection of stdin like this,

python -i < test.py

The output is,

>>> outer
>>> >>> ... ... ... File "<stdin>", line 4
print i
SyntaxError: invalid syntax

So, clearly, I shouldn't use the -i option with shell redirection, ie with the '<' character in the command. This combination apparently leads to some manipulation of white space which, by the time python parses the input, is a python syntax error.

Unfortunately, I run into the same problem when running python scripts in the Django python shell and the command to run the Django python shell has no way to disable interactive python mode and no way to pass the name of a python script file.

Furthermore, I believe this worked on a different Linux box or earlier on the same Linux box so I wonder if there is some environment setting that would fix it.

Is there a way to change the behavior of python's interactive mode or is there a way to disable interactive mode in the Django shell so I can run general python scripts without false syntax errors? Or am I simply suffering from a bug in Django or python??

Incidentally, this issue sounds very much like the problem described in http://stackoverflow.com/a/13703413/2950621 but the accepted answer says to alter empty lines in the script. Yet my script has no empty lines.

The python script follows. (I wrote it to flag when the indented lines are not executed):

print 'outer'
i = 1
if True:
print 'inner'
i = 2
print i

I suppose some readers might suspect a hidden character is to blame. Here is the octal dump so you can see there is nothing but what you see above (not even a tab):

$ od -a test.py
0000000 p r i n t sp ' o u t e r ' nl i sp
0000020 = sp 1 nl i f sp T r u e : nl sp p r
0000040 i n t sp ' i n n e r ' nl sp i sp =
0000060 sp 2 nl p r i n t sp i nl

Answer Source

You're having the opposite of the problem in the linked question. The -i makes python read the script in interactive mode (the ">>> " and "... " are prompts), and in interactive mode, you to press return (i.e. enter a blank line) to exit an indented section. The linked question involved blank lines in the middle of an indented section, which confused the interpreter. You have the opposite: you end an indented section without a blank line. That's perfectly ok in non-intereactive mode, but in interactive mode it's a no-no.

Solution: either put blank lines at the end of indented sections (and never in the middle), don't tell the interpreter to read it in interactive mode. I'm not sure what you're actually trying to accomplish with the -i flag, but note that python -i test.py (without the redirect) will run the script in non-interactive mode and then enter interactive mode and read from stdin.