stdin reading blocking when running sbt with python subprocess.Popen() - python

I'm launching sbt via Popen(), and my python process stdin reading is not working.
Here is an example:
On the first line I'm launching Popen, on the second line I'm trying to browse throught the history with an arrow key. This does not work for some time, printing ^[[A.
$ python
Python 2.7.10 (default, Jul 13 2015, 12:05:58)
[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess; f = open("/dev/null", "rw"); subprocess.Popen(["sbt"], stdout=f, stderr=f, stdin=f)
<subprocess.Popen object at 0x10fc03950>
>>> ^[[A^[[A^[[A^[[A^[[A^[[A^[[A^[[A^[[Aimport subprocess; f = open("/dev/null", "rw"); subprocess.Popen(["sbt"], stdout=f, stderr=f, stdin=f)
This seems to only happen with sbt.
Any idea why and how to bypass this behavior ?
Thanks

My guess is that sbt is misbehaving when there is no pseudo-tty to interact with the user (probably because of jline).
Hence, let's use a python module to run the commands in a pseudo-tty. Install pexpect via pip (pip3 install pexpect for Python 3.x).
Then, run the following:
import pexpect, sys
f = open("sbt.log", "w+")
# Use `spawnu` for Python3, `spawn` otherwise
sbt = pexpect.spawnu("sbt -Dsbt.log.noformat=true \"version\" \"another-command\"", logfile=f)
# Do whatever is needed while sbt is running
# Force the process to expect EOF and file to be written
sbt.expect(pexpect.EOF)
Tested in Python 3.4.3 (Gentoo Linux) and works.

Related

Why doesn't python send output to stdout?

Here's a minimum working example (MWE), saved as mwe.py:
import sys
def f(n):
print("Testing print()...")
sys.stdout.write("Calculating f({})...".format(n))
When run from the command line I get no output whatsoever:
username#hostname:~/mydir$ python mwe.py 'f(99)'
username#hostname:~/mydir$
When run from within python
I get output (some info removed):
username#hostname:~/mydir$ python
Python 3.5.4 (default, DATE, HH:MM:SS)
[GCC X.X.X Compatible Apple LLVM X.X.X (clang-X.X.X)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from mwe import f
>>> f(99)
Testing print()...
Calculating f(99)...
>>>
Why do these output statements work within python but not from the command line?
python mwe.py 'f(99)' doesn't mean "run the f function from mwe.py with argument 99". If you wanted to do that from the command line, you could execute
python -c 'import mwe; mwe.f(99)'
python mwe.py 'f(99)' means "run the script mwe.py with sys.argv[1] set to the string "f(99)"". The script mwe.py doesn't examine sys.argv or print anything at all; it just defines a function and ends.
This: python mwe.py 'f(99)' just shouldn't work. In this case, 'f(99)' is just passed as an argument to the program.
Try using python -c 'import mwe; mwe.f(99) instead. (also read more about command line usage of python by typing python -h)

Shebang for scripts not working

I am using PythonAnyhwere for my django production environment. I have a script which should run on scheduled basis.
Since I installed django in a virtualenv, the script starts like
#!/usr/bin/env python
activate_this = '/home/myname/.virtualenvs/myenv/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))
The error I get for this is
/usr/bin/env python: no such Python interpreter
No problem. So I changed it to
#!/usr/bin/env python2.7
Then I got
/usr/bin/env python2.7: no such Python interpreter
or
/usr/bin/env python3.4: no such Python interpreter
I said ok, what if I don't have a shebang line at all?
Error in log:
line 1: activate_this: command not found
line 2: syntax error near unexpected token `activate_this,'
line 2: `execfile(activate_this, dict(__file__=activate_this))'
What is the way then?
You can know where your Python interpreter by typing
$ which python
Also you try something like this (or maybe without env):
$ env python
Python 3.5.0 (default, Sep 20 2015, 11:28:25)
[GCC 5.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.path
<module 'posixpath' from '/usr/lib/python3.5/posixpath.py'>
And then change lib to bin and omit /posixpath.py part

Where can I find the first text that loads in the Python shell and change it?

This text loads when I open IDLE or load Python in cmd:
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600
32 bit (Intel)] on win32 Type "copyright", "credits" or "license()"
for more information.
Where can I find the file and change the text or make a script load instead?
I don't know of any way to change the default text without modifying/recompiling the python binary, but it seems you can use the environment variable PYTHONSTARTUP in order to add additional text via a python file with print commands. You can also change the prompt strings in this file. For example:
in my .bashrc:
export PYTHONSTARTUP=/home/jake/.mypythonstartup
/home/jake/.mypythonstartup:
import sys
print("Welcome, master!")
sys.ps1 = "How may I serve you? "
sys.ps2 = " ... "
Result:
$ python
Python 2.7.5 (default, Mar 9 2014, 22:15:05)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
Welcome, master!
How may I serve you? def test():
... print("test")
...
How may I serve you? test()
test
How may I serve you?
Documentation on PYTHONSTARTUP can be found here: https://docs.python.org/3/tutorial/appendix.html#the-interactive-startup-file
Based on a quick snoop around the idlelib source code, you could do something like:
from code import interact
interact("Welcome master.")
In use:
$ python idle2.py
Welcome master.
>>> print 'foo'
foo
You could also use the command line flags to run a command then enter interactive mode:
$ python -ic "print 'Welcome master.'"
Welcome master.
>>>

Why does python subprocess zip fail but running at shell works?

I'm on Mac OS X using Python 2.7; using subprocess.call with zip fails yet running the same command at the shell succeeds. Here's a copy of my terminal:
$ python
Python 2.7.2 (default, Oct 11 2012, 20:14:37)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> subprocess.call(['zip', 'example.zip', 'example/*'])
zip warning: name not matched: example/*
zip error: Nothing to do! (example.zip)
12
>>> quit()
$ zip example.zip example/*
adding: example/file.gz (deflated 0%)
I've also tried with full paths and had the same result.
Because running a command in the shell is not the same thing as running it with subprocess.call(); the shell expanded the example/* wildcard.
Either expand the list of files with os.listdir() or the glob module yourself, or run the command through the shell from Python; with the shell=True argument to subprocess.call() (but make the first argument a whitespace-separated string).
Using glob.glob() is probably the best option here:
import glob
import subprocess
subprocess.call(['zip', 'example.zip'] + glob.glob('example/*'))
Martijn's advice to use glob.glob is good for general shell wildcards, but in this case it looks as if you want to add all files in a directory to the ZIP archive. If that's right, you might be able to use the -r option to zip:
directory = 'example'
subprocess.call(['zip', '-r', 'example.zip', directory])
Try shell=True. subprocess.call('zip example.zip example/*', shell=True) would work.

Can python shell have some pre-input?

When testing in python shell, I always have to type some import like:
Python 2.5.4 (r254:67916, Jun 24 2010, 15:23:27)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>import sys
>>>import datetime
Can someone help me to automatically finish these? It means I run some command to enter python shell it has already done import for me, and a python shell waiting for me to continue type command.
Thanks.
Try:
python -i -c "import sys; import datetime;"
More info:
-i : inspect interactively after running script; forces a prompt even
if stdin does not appear to be a terminal; also PYTHONINSPECT=x
&
-c cmd : program passed in as string (terminates option list)
Create a file with the commands you want to execute during startup, and set the environment variable PYTHONSTARTUP to the location of that file. The interactive interpreter will then load and execute that file. See http://docs.python.org/tutorial/interpreter.html#the-interactive-startup-file
On a sidenote, you might want to consider ipython as an improved Python shell when working in interactive mode.

Categories