Pass integer input argument for Popen.communicate() - python-2.7

I am pretty new to python and I am stuck with something now. I am using python 2.7.
I am trying to automate a command in shell for which I wrote a python script. I have to input an integer value to the shell for which I am using Popen.communicate(input='2'). Though input is passed, it is passed as a string and the subprocess needs it as a numeric value. When I try to pass it as a numberic value like Popen.communicate(input=2) it throws the following error :
TypeError: 'int' object has no attribute '__getitem__'
So is there any way to send the input as a numeric value ??
Here is the code I use :
import sys
from subprocess import Popen, PIPE, STDOUT
cmd = ["sudo", "./sbt", "project java-examples", "run"]
proc = Popen(cmd, bufsize=4096, shell=False, stdout=PIPE, stdin=PIPE, stderr=STDOUT)
string = proc.communicate(input='2')
print string[0]
proc.stdin.close()
Edit :
Sorry that I didn't mentioned this at the first place.
My java application has multiple main classes hence the compiler ask which class to be executed, and I need to enter the same number every time,which is why I am trying to automate it. When I am passing a string value it throws numberformatexception.

Finally I found the solution for this.
Well the solution to this was pretty simple
when I changed
string = proc.communicate(input='2')
to
string = proc.communicate(input='2\n')
it worked fine.

The ./sbt process you are calling needs to be able to read a string and convert it into a integer. It is not possible to send native Python types to a child process with only Popen.
Another potential solution would be to serialize the data into JSON, YAML, XML, python pickle format, etc - choose your standard. However as you are passing a single integer this would seem very much overkill.

Pipes are byte streams in Unix. There is no numeric input -- there is only "string" input (there are no numbers or anything else -- there are only bytes).
If your child java process expects a number as its ascii representation then .communicate(input='2') is correct already if the subprocess reads from stdin (System.in). If the java process reads from the console directly (System.console().readLine()) then stdin=PIPE won't work (you might need to provide a pty in this case e.g., using pexpect).
For example, to read an integer from stdin and print it back in Java:
import java.util.Scanner;
public class ReadInteger
{
public static void main(String args[])
{
Scanner in = new Scanner(System.in);
int i = in.nextInt();
System.out.println("got " + i);
}
}
To pass an integer from Python process to the Java process via a pipe:
#!/usr/bin/env python2
from subprocess import Popen, PIPE
p = Popen(['java', '-ea', 'ReadInteger'], stdin=PIPE, stdout=PIPE)
output = p.communicate(input='2')[0]
print 'from java {' + output.strip() + '}'
It works (the output is from java {got 2}).
It stops working if the child process reads from the console instead:
public class ReadIntegerConsole
{
public static void main(String args[])
{
int i = Integer.parseInt(System.console().readLine());
System.out.println("got " + i);
}
}
The same python script leads to NullPointerException (and the output is from java {}) because System.console() is null here (stdin is redirected). It works if we provide a pseudo-tty:
#!/usr/bin/env python2
import pexpect # $ pip install pexpect
child = pexpect.spawn('java -ea ReadIntegerConsole')
child.setecho(False)
child.sendline('2')
child.expect(pexpect.EOF)
child.close()
print "from java {" + child.before.strip() + "}"
It works (the output is from java {got 2}).

Related

SyntaxError: invalid syntax using pipes.quote

Trying to create a shell script on a raspi3 in python to start a webcam. Getting a syntax error when trying to run the script.
Keep in mind I am new to Python but I have tried each individually to see what prints out, only getting this when I combine the script..
from gpiozero import Button
from pipes import quote
import time
import os
print("your script has started")
camOutput = 'output_http.so -w ./www'
camInput = 'input_raspicam.so -hf'
camStart = '/home/pi/projects/mjpg-streamer/mjpg_streamer -o'.format(quote(camOutput)).'-i'.format(quote(camInput))
print("your script is loaded")
stopButton = Button(26) #shutdown
camButton = Button(25) #web cam
ledButton = Button(24) #top led
while True:
if stopButton.is_pressed:
time.sleep(1)
if stopButton.is_pressed:
os.system("shutdown now -h")
time.sleep(1)
camStart = '/home/pi/projects/mjpg-streamer/mjpg_streamer -o'.format(quote(camOutput)).'-i'.format(quote(camInput))
^
SyntaxError: invalid syntax```
In Python, the dot operator is not used to concatenate strings, only to access properties and methods of an object. Thus, putting a string literal after a dot, such as .'-i', is a syntax error.
You probably want to do something like this, using the format method to replace the {} placeholders with the provided values:
camStart = '/..../mjpg_streamer -o {} -i {}'.format(quote(camOutput),quote(camInput))

How to use regular expressions to pull something from a terminal output?

I'm attempting to use the re module to look through some terminal output. When I ping a server through terminal using ping -n 1 host (I'm using Windows), it gives me much more information than I want. I want just the amount of time that it takes to get a reply from the server, which in this case is always denoted by an integer and then the letters 'ms'. The error I get explains that the output from the terminal is not a string, so I cannot use regular expressions on it.
from os import system as system_call
import re
def ping(host):
return system_call("ping -n 1 " + host) == 0
host = input("Select a host to ping: ")
regex = re.compile(r"\w\wms")
final_ping = regex.search(ping(host))
print(final_ping)
system returns 0, not anything too useful. However, if we were to do subprocess, we can get teh output, and store it to a variable, out, then we can regex search that.
import subprocess
import re
def ping(host):
ping = subprocess.Popen(["ping", "-n", "1", host], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, error = ping.communicate()
return str(out)
host = input("Select a host to ping: ")
final_ping = re.findall("\d+ms",ping(host))[0]
print(final_ping)
Output:
22ms
There are two problems with your code:
Your ping function doesn't return the terminal output. It only returns a bool that reports if the ping succeeded. The ping output is directly forwarded to the terminal that runs the Python script.
Python 3 differentiates between strings (for text, consisting of Unicode codepoints) and bytes (for any data, consisting of bytes). As Python cannot know that ping only outputs ASCII text, you will get a bytes object if you don't specify which text encoding is in use.
It would be the best to use the subprocess module instead of os.system. This is also suggested by the Python documentation.
One possible way is to use subprocess.check_output with the encoding parameter to get a string instead of bytes:
from subprocess import check_output
import sys
def ping(host):
return check_output(
"ping -n 1 " + host,
shell=True,
encoding=sys.getdefaultencoding()
)
...
EDIT: The encoding parameter is only supported since Python 3.6. If you are using an older version, try this:
from subprocess import check_output
import sys
def ping(host):
return check_output(
"ping -n 1 " + host,
shell=True
).decode()
...

Python-Console (Anaconda 4.2.0 (64-bit)): Input is not taken as string but "variable"? [duplicate]

I am getting an error when I try to run this simple script:
input_variable = input("Enter your name: ")
print("your name is" + input_variable)
Let's say I type in "dude", the error I am getting is:
line 1, in <module>
input_variable = input("Enter your name: ")
File "<string>", line 1, in <module>
NameError: name 'dude' is not defined
I am running Mac OS X 10.9.1 and I am using the Python Launcher app that came with the install of Python 3.3 to run the script.
TL;DR
input function in Python 2.7, evaluates whatever your enter, as a Python expression. If you simply want to read strings, then use raw_input function in Python 2.7, which will not evaluate the read strings.
If you are using Python 3.x, raw_input has been renamed to input. Quoting the Python 3.0 release notes,
raw_input() was renamed to input(). That is, the new input() function reads a line from sys.stdin and returns it with the trailing newline stripped. It raises EOFError if the input is terminated prematurely. To get the old behavior of input(), use eval(input())
In Python 2.7, there are two functions which can be used to accept user inputs. One is input and the other one is raw_input. You can think of the relation between them as follows
input = eval(raw_input)
Consider the following piece of code to understand this better
>>> dude = "thefourtheye"
>>> input_variable = input("Enter your name: ")
Enter your name: dude
>>> input_variable
'thefourtheye'
input accepts a string from the user and evaluates the string in the current Python context. When I type dude as input, it finds that dude is bound to the value thefourtheye and so the result of evaluation becomes thefourtheye and that gets assigned to input_variable.
If I enter something else which is not there in the current python context, it will fail will the NameError.
>>> input("Enter your name: ")
Enter your name: dummy
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'dummy' is not defined
Security considerations with Python 2.7's input:
Since whatever user types is evaluated, it imposes security issues as well. For example, if you have already loaded os module in your program with import os, and then the user types in
os.remove("/etc/hosts")
this will be evaluated as a function call expression by python and it will be executed. If you are executing Python with elevated privileges, /etc/hosts file will be deleted. See, how dangerous it could be?
To demonstrate this, let's try to execute input function again.
>>> dude = "thefourtheye"
>>> input("Enter your name: ")
Enter your name: input("Enter your name again: ")
Enter your name again: dude
Now, when input("Enter your name: ") is executed, it waits for the user input and the user input is a valid Python function invocation and so that is also invoked. That is why we are seeing Enter your name again: prompt again.
So, you are better off with raw_input function, like this
input_variable = raw_input("Enter your name: ")
If you need to convert the result to some other type, then you can use appropriate functions to convert the string returned by raw_input. For example, to read inputs as integers, use the int function, like shown in this answer.
In python 3.x, there is only one function to get user inputs and that is called input, which is equivalent to Python 2.7's raw_input.
You are running Python 2, not Python 3. For this to work in Python 2, use raw_input.
input_variable = raw_input ("Enter your name: ")
print ("your name is" + input_variable)
Since you are writing for Python 3.x, you'll want to begin your script with:
#!/usr/bin/env python3
If you use:
#!/usr/bin/env python
It will default to Python 2.x. These go on the first line of your script, if there is nothing that starts with #! (aka the shebang).
If your scripts just start with:
#! python
Then you can change it to:
#! python3
Although this shorter formatting is only recognized by a few programs, such as the launcher, so it is not the best choice.
The first two examples are much more widely used and will help ensure your code will work on any machine that has Python installed.
I also encountered this issue with a module that was supposed to be compatible for python 2.7 and 3.7
what i found to fix the issue was importing:
from six.moves import input
this fixed the usability for both interpreters
you can read more about the six library here
You should use raw_input because you are using python-2.7. When you use input() on a variable (for example: s = input('Name: ')), it will execute the command ON the Python environment without saving what you wrote on the variable (s) and create an error if what you wrote is not defined.
raw_input() will save correctly what you wrote on the variable (for example: f = raw_input('Name : ')), and it will not execute it in the Python environment without creating any possible error:
input_variable = raw_input('Enter Your Name : ')
print("Your Name Is : " + (input_variable))
input_variable = input ("Enter your name: ")
print ("your name is" + input_variable)
You have to enter input in either single or double quotes
Ex:'dude' -> correct
dude -> not correct
For python 3 and above
s = raw_input()
it will solve the problem on pycharm IDE
if you are solving on online site exactly hackerrank then use:
s = input()
We are using the following that works both python 2 and python 3
#Works in Python 2 and 3:
try: input = raw_input
except NameError: pass
print(input("Enter your name: "))
There are two ways to fix these issues,
1st is simple without code change that is
run your script by Python3,
if you still want to run on python2 then
after running your python script, when you are entering the input keep in mind
if you want to enter string then just start typing down with "input goes with double-quote" and it will work in python2.7 and
if you want to enter character then use the input with a single quote like 'your input goes here'
if you want to enter number not an issue you simply type the number
2nd way is with code changes
use the below import and run with any version of python
from six.moves import input
Use raw_input() function instead of input() function in your code with any import
sanitise your code with str() function like str(input()) and then assign to any variable
As error implies: name 'dude' is not defined
i.e. for python 'dude' become variable here and it's not having any value of python defined type assignedso only its crying like baby so if we define a 'dude' variable and assign any value and pass to it, it will work but that's not what we want as we don't know what user will enter and moreover we want to capture the user input.
Fact about these method:
input() function: This function takes the value and type of the input you enter as it is without modifying it type. raw_input()
function: This function explicitly converts the input you give into type string,
Note: The vulnerability in input() method lies in the fact that
the variable accessing the value of input can be accessed by anyone
just by using the name of variable or method.
Try using raw_input rather than input if you simply want to read strings.
print("Enter your name: ")
x = raw_input()
print("Hello, "+x)
You could either do:
x = raw_input("enter your name")
print "your name is %s " % x
or:
x = str(input("enter your name"))
print "your name is %s" % x
For anyone else that may run into this issue, turns out that even if you include #!/usr/bin/env python3 at the beginning of your script, the shebang is ignored if the file isn't executable.
To determine whether or not your file is executable:
run ./filename.py from the command line
if you get -bash: ./filename.py: Permission denied, run chmod a+x filename.py
run ./filename.py again
If you've included import sys; print(sys.version) as Kevin suggested, you'll now see that the script is being interpreted by python3
Good contributions the previous ones.
import sys; print(sys.version)
def ingreso(nombre):
print('Hi ', nombre, type(nombre))
def bienvenida(nombre):
print("Hi "+nombre+", bye ")
nombre = raw_input("Enter your name: ")
ingreso(nombre)
bienvenida(nombre)
#Works in Python 2 and 3:
try: input = raw_input
except NameError: pass
print(input("Your name: "))
Enter your name: Joe
('Hi ', 'Joe', &lttype 'str'&gt)
Hi Joe, bye
Your name: Joe
Joe
Thanks!
You can change which python you're using with your IDE, if you've already downloaded python 3.x it shouldn't be too hard to switch. But your script works fine on python 3.x, I would just change
print ("your name is" + input_variable)
to
print ("your name is", input_variable)
Because with the comma it prints with a whitespace in between your name is and whatever the user inputted. AND: if you're using 2.7 just use raw_input instead of input.
Here is an input function which is compatible with both Python 2.7 and Python 3+:
(Slightly modified answer by #Hardian) to avoid UnboundLocalError: local variable 'input' referenced before assignment error
def input_compatible(prompt=None):
try:
input_func = raw_input
except NameError:
input_func = input
return input_func(prompt)
Also here is another alternative without a try block:
def input_compatible(prompt=None):
input_func = raw_input if "raw_input" in __builtins__.__dict__ else input
return input_func(prompt)

Evaluating code after parsing it

I'm trying to create a tool written in Python that executes R scripts (from files), injecting values into variables before executing them and reading output variables after that.
The rinterface documentation mentions the parse function, but there is no indication about how to execute the result. The C interface contains an eval function but it doesn't seem available in Python.
Here's a very basic example of what I want to do :
import rpy2.rinterface as ri
ri.initr()
with open('script.r', 'r') as myFile:
script = myFile.read()
expr = ri.parse(script)
# prepare
ri.globalenv['input'] = ri.IntSexpVector((1, 2, 3, 4))
# execute
#??????????????????
# what to do here ?
#??????????????????
# fetch results
# The script is supposed to store results into a global var named 'output'
result = ri.globalenv['output']
Thanks
There are several ways.
One is:
from rpy2.robjects.packages import importr
base = importr('base')
base.eval(expr)

How do I retrieve program output in Python?

I'm not a Perl user, but from this question deduced that it's exceedingly easy to retrieve the standard output of a program executed through a Perl script using something akin to:
$version = `java -version`;
How would I go about getting the same end result in Python? Does the above line retrieve standard error (equivalent to C++ std::cerr) and standard log (std::clog) output as well? If not, how can I retrieve those output streams as well?
Thanks,
Geoff
For python 2.5: sadly, no. You need to use subprocess:
import subprocess
proc = subprocess.Popen(['java', '-version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
Docs are at http://docs.python.org/library/subprocess.html
In Python 2.7+
from subprocess import check_output as qx
output = qx(['java', '-version'])
The answer to Capturing system command output as a string question has implementation for Python < 2.7.
As others have mentioned you want to use the Python subprocess module for this.
If you really want something that's more succinct you can create a function like:
#!/usr/bin/env python
import subprocess, shlex
def captcmd(cmd):
proc = subprocess.Popen(shlex.split(cmd), \
stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
out, err = proc.communicate()
ret = proc.returncode
return (ret, out, err)
... then you can call that as:
ok, o, e = captcmd('ls -al /foo /bar ...')
print o
if not ok:
print >> sys.stderr, "There was an error (%d):\n" % ok
print >> sys.stderr, e
... or whatever.
Note: I'm using shlex.split() as a vastly safer alternative to shell=True
Naturally you could write this to suit your own tastes. Of course for every call you have to either provide three names into which it can unpack the result tuple or you'd have to pull the desired output from the result using normal indexing (captcmd(...)[1] for the output, for example). Naturally you could write a variation of this function to combine stdout and stderr and to discard the result code. Those "features" would make it more like the Perl backtick expressions. (Do that and take out the shlex.split() call and you have something that's as crude and unsafe as what Perl does, in fact).