Python: Run multiple commands simultaneously [duplicate] - android

This question already has answers here:
Executing multiple functions simultaneously
(6 answers)
Closed 6 years ago.
I have two android devices connected to my Linux machine and I need to be able to take a screenshot on both at the exact same time. How can I achieve this in python?
This is what I have so far:
import time, datetime
from threading import Thread
from Queue import Queue
def get_screenshot(deviceid):
print deviceid
print datetime.datetime.now()
# Logic to get screenshot goes here
deviceids = ["blabla1", "blabla2"]
q = Queue()
for d in deviceids:
t = Thread(target=get_screenshot, args=(d,))
t.setDaemon(True)
t.start()
for d in deviceids:
q.put(d)
q.join()
The output looks like this:
blabla1
2016-10-02 12:55:17.146964
blabla2
2016-10-02 12:55:17.147141
The problem is:
1. Is the approach correct?
2. Why the difference of 1ms? Can that be avoided?
3. This program does not exit. I need to Ctrl+Z out of it.

import datetime
from threading import Thread
def get_screenshot(deviceid):
print("%s %s" %(deviceid, datetime.datetime.now()))
deviceids = ["blabla1", "blabla2"]
for d in deviceids:
t = Thread(target=get_screenshot, args=(d,))
t.start()
You don't need a queue.
0.2 ms wasted on thread creation and starting.
It's because you put strings into the Queue and than join that queue - the queue 'waits for strings' and hangs. Do you really need to join your threads? You may write your screenshots to files in the thread function. Python program automatically closes when all it's threads are finished.

Related

Passing string in stdin

I want to create an AVD (Android Virtual Device) through command line in python. For that, I need to pass a string n to the stdin. I have tried the following
emulator_create = str(subprocess.check_output([android,'create', 'avd', '-n', emulator_name, '-t', target_id, '-b', abi],stdin=PIPE))
emulator_create.communicate("n")
but it raises the following error
raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command '['/home/fahim/Android/Sdk/tools/android', 'create', 'avd', '-n', 'samsung_1', '-t', '5', '-b', 'android-tv/x86']' returned non-zero exit status 1
Process finished with exit code 1
What can I do?
There's something not working with your example. subprocess.check_output() returns the output from the child process you want to execute, not a handle to this process. In other words you get a string object (or maybe a bytes object) which you cannot use to manipulate the child process.
Probably what happens is that your script, using subprocess.check_output(), will execute the child process and wait until it is finished before continuing. But since you are never able to communicate with it, it will finish with a non-zero return value which will raise the subprocess.CalledProcessError
Now, using grep as an example of a command that waits on the standard input to execute something (since I don't have an Android Virtual Device creator installed) you could do this:
#!/usr/bin/env python2.7
import subprocess
external_command = ['/bin/grep', 'StackOverflow']
input_to_send = '''Almost every body uses Facebook
You can also say that about Google
But you can find an answer on StackOverflow
Even if you're an old programmer
'''
child_process = subprocess.Popen(args=external_command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
universal_newlines=True)
stdout_from_child, stderr_from_child = child_process.communicate(input_to_send)
print "Output from child process:", stdout_from_child
child_process.wait()
It will print "Output from child process: But you can find an answer on StackOverflow", which is the output from grep.
In this example, I have
Used the class subprocess.Popen to create an handle to the child process
Setting arguments stdin and stdout with the value subprocess.PIPE to enables us to communicate later on with this process.
Used its .communicate() method to send a string to its standard input. In the same step, I retrieved its standard output and standard error output.
Printed the standard output retrieved in the last step (just so to show that it is actually working)
Waited that this child process is finished
In Python 3.5, it's even simpler:
#!/usr/bin/env python3.5
import subprocess
external_command = ['/bin/grep', 'StackOverflow']
input_to_send = '''Almost every body uses Facebook
You can also say that about Google
But you can find an answer on StackOverflow
Even if you're an old programmer
'''
completed_process_result = subprocess.run(args=external_command,
input=input_to_send,
stdout=subprocess.PIPE,
universal_newlines=True)
print("Output from child process:", completed_process_result.stdout)
In this example, I have:
Used the module function subprocess.run() to execute the command.
The input argument is the string we send to the standard input of the child process
The return value is used later on to retreive the output of the child process
Now you have to adapt this code to your situation.

error with pymtp to work on python 3

I want to access a android device from python to download some photos.
libmtp works from the CLI.
Than pymtp. It's been around for a while but it's designed for python 2 and i'm using python 3. Meanwhile fixed several minor issues but i'm stuck at an error from function get_filelisting
specially this section:
ret = []
next = files
while next:
ret.append(next.contents)
if (next(next.contents) is None):
break
next = next(next.contents)
The error is related to the "next".
That section looks strange to me, i've been coding in python for a while but i'm new to ctypes. Tried a lot of variants, they all failed. The "next" could be confusing with python buildin function so i renamed it to nextpointer and came to this code:
ret = []
nextpointer = files
while nextpointer:
ret.append(nextpointer.contents)
nextpointer = nextpointer.contents.next
It seems to work but did it work by accident ? does it have any design flaws ? Could anyone with experience on python ctypes confirm this a solution ? Any suggestion welcome.
From python2.7 documentation
next(iterator[, default])
Retrieve the next item from the iterator by calling its next() method. If default is given, it is returned if the iterator is
exhausted, otherwise StopIteration is raised.
from python3 documentation
next(iterator[, default])
Retrieve the next item from the iterator by calling its __next__() method. If default is given, it is returned if the iterator is
exhausted, otherwise StopIteration is raised.
Notice that next() method was removed from python3 but the function still exists.
This is all I can say about the next function and .next()/__next__() methods.
I downloaded the pymtp module and get_filelisting() is slightly different from what you posted in your ported code, here it is:
ret = []
next = files
while next:
ret.append(next.contents)
if (next.contents.next == None):
break
next = next.contents.next
If none of this helped you (which probably didn't :D), the version of pymtp library that I am using is 0.0.6 download using pip.

Nest ETA update not working: No write permission(s) for field(s): eta

I'm building an Application that integrates with your Nest devices (both the thermostat and the Nest Protect, but this issue is about the thermostat).
What I'm trying to do is set my thermostat's ETA to be in x minutes (2 hours for example so 120 minutes).
This is my code that I'm executing:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
final String path = buildStructureFieldPath(structureID, Keys.STRUCTURE.ETA);
Structure.ETA eta = new Structure.ETA.Builder()
.setTripID(tripId)
.setEstimatedArrivalWindowBegin(sdf.format(estimatedArrivalBegin))
.setEstimatedArrivalWindowEnd(sdf.format(estimatedArrivalEnd))
.build();
sendRequest(path, eta.toJSON().toString(), listener);
The path is /structures/MY_STRUCTURE_ID/eta
Unfortunately that's not working. I'm always getting an error code -2 and error message: No write permission(s) for field(s): eta
And that's were it gets strange. No permission, but I did request the permission and I did an authenticate, which is successful, before launching the update call.
In the two attached screenshots you can see first my Nest Developer Account where you can find the ETA write permission and in the second you can see the logging from within my app (using the NestAPI as can be found on GitHub, just added the ETA feature myself).
Anyone have any idea on how to solve this issue?
Can you print out the exact JSON blob you're sending and post it here? (the value of eta.toJSON().toString())
Best guess is that it isn't formatted exactly correctly and as such is maybe attempting to write in such a way that doesn't adhere to the api-reference.
This is the format that it needs to match:
"eta": {
"trip_id": "myTripHome1024" ,
"estimated_arrival_window_begin": "2015-10-31T22:42:59.000Z" ,
"estimated_arrival_window_end": "2015-10-31T23:59:59.000Z"
}
Single line:
{"eta":{"trip_id":"myTripHome1024","estimated_arrival_window_begin":"2015-10-31T22:42:59.000Z","estimated_arrival_window_end": "2015-10-31T23:59:59.000Z"}}
To pinpoint exactly which field may be erroneous, try sending just one change at a time for each ie: structures/ID/eta/trip_id, etc for the others.
Useful JSON Validator: http://jsonlint.com/
You could also try to send it to /structures/MY_STRUCTURE_ID.json?auth=[TOKEN] instead of /structures/MY_STRUCTURE_ID/eta.

monkeyrunner hangs when making a connection to the device

Here's what I need to do. I have 2 devices which I need to test using monkeyrunner. It is an automated test using python and monkeyrunner. I want to execute the test simultaneously for the 2 devices so I thought of using thread.
here's the code
import threading
import datetime import os, sys
import ConfigParser from com.android.monkeyrunner
import MonkeyRunner, MonkeyDevice,MonkeyImage from datetime
import datetime import hashlib from java.net
import SocketException from com.ziclix.python.sql
import zxJDBC
def UseThread(data1, data2, data3, devID, Code, ScreenshotRef,
logFile):
device = MonkeyRunner.waitForConnection(10, devID)
'threaded code'
'initialization'
file = open(os.path.dirname(os.path.realpath(file)) +
'\Samples.txt','r') while 1:
while 1:
line = file.readline()
if not line:
print 'Done!'
break
else:
line
val=line.split('\t')
data1 = val[0]
data2 = val[1]
data3 = val[2]
threads = []
for Code in cp.options('p'):
devID = cp.get('product',Code).strip()
ScreenshotRef = cp.get('source','ScreenshotRef') + '\\' + prodCode.upper()
logFile = outputFolder + '\\' + prodCode.upper() + '\\logs.txt'
t=threading.Thread(target=UseThread,args=(data1, data2, data3, devID, prodCode, ScreenshotRef, logFile))
threads.append(t)
t.start()
for i in range(0,len(threads)):
threads[i].join()
The problem is this. When the while loops finish one run and proceed to 2nd run, the code hangs in the part when monkeyrunner is waiting for connection. To be exact, this is the part where it stops
device = MonkeyRunner.waitForConnection(10, devID)
the message says "Monkey command wake".
I assume that the problem has something to do with the connection, not with the thread because I tried to print something before that line which makes a connection and it works.
Is there an issue making a connection when you have already made one? do I need to close the previous connection first?
MonkeyRunner waitForConnection works only for one device. You cannot run this twice. You can run from another instance

Accessing LogCat from Android via Python

Is it possible to read information being sent over LogCat in python?
I have a program that is written in java.
Every draw frame it sends tag:"Fps: " message: number
I would like this message to fire an event that I can catch in my python script so I can draw a fps-meter.
Take a look at subprocess. The following code was adapted from Stefaan Lippens
import Queue
import subprocess
import threading
class AsynchronousFileReader(threading.Thread):
'''
Helper class to implement asynchronous reading of a file
in a separate thread. Pushes read lines on a queue to
be consumed in another thread.
'''
def __init__(self, fd, queue):
assert isinstance(queue, Queue.Queue)
assert callable(fd.readline)
threading.Thread.__init__(self)
self._fd = fd
self._queue = queue
def run(self):
'''The body of the tread: read lines and put them on the queue.'''
for line in iter(self._fd.readline, ''):
self._queue.put(line)
def eof(self):
'''Check whether there is no more content to expect.'''
return not self.is_alive() and self._queue.empty()
# You'll need to add any command line arguments here.
process = subprocess.Popen(["logcat"], stdout=subprocess.PIPE)
# Launch the asynchronous readers of the process' stdout.
stdout_queue = Queue.Queue()
stdout_reader = AsynchronousFileReader(process.stdout, stdout_queue)
stdout_reader.start()
# Check the queues if we received some output (until there is nothing more to get).
while not stdout_reader.eof():
while not stdout_queue.empty():
line = stdout_queue.get()
if is_fps_line(line):
update_fps(line)
Of course, you'll need to write the is_fps_line and update_fps functions yourself.
I would redirect adb logcat to your python script. This would look like:
$ adb logcat | python yourscript.py
Now you can read from logcat on sys.stdin and parse it however you like.

Categories

Resources