This is not the full code, only snippets of which I'm trying to get to work.
I should warn, I'm still in the learning phases of Python, so if you see anything funky, that's why.
I'm using Tkinter to design a GUI and I want to have a single button press start a handful of commands all at once.
To elaborate on what this program does, it starts an iperf client and then captures telnet readings at the same time. I had a great proof of concept in bash working, but with tkinter I can only seem to get one to start right after the first one has already finished. Using the lambda method below the compiler still complains:
TypeError: () takes exactly 1 argument (0 given)
self.iperfr = Button(frame, text="---Run---",command = lambda x:self.get_info() & self.telnetcap())
self.iperfr.pack(side=BOTTOM)
def get_info():
iperf= self.iperfc.get()
time = self.timeiperf.get()
iperfcommand= 'iperf -c 127.0.0.1 -y c -i 1 {}'.format(iperf)+ ' -t {}'.format(time)
print iperfcommand
os.system(iperfcommand)
def telnetcap():
n=0
time = self.timeiperf.get()
child=pexpect.spawn('telnet 192.168.2.1');
child.logfile = open("/home/alex/Desktop/Test", "w")
child.expect('Login:');
child.sendline('telnet');
child.expect('Password:');
child.sendline('password');
while (n<time):
child.expect('>');
child.sendline('sh');
child.expect('#') ;
child.sendline ('sysinfo');
child.expect ('#');
child.sendline ('iostat');
child.expect ('#');
child.sendline ('exit');
n=n+1
print n
At this point I feel like it might be easier to actually just call my original bash script from within this Python GUI. It seems so trivial, but I'm pulling my hair out trying to get it to work. The simple "&" in bash did exactly what I wanted it to do. Is there a Python version of this?
Thanks!
Thanks Martineau for pointing me in the right direction. Threading was definitely the way to go. By assigning my "run_all" button to a function designated to start individual threads it works great.
def run_all(self):
thread.start_new_thread(self.telnetcap, ())
thread.start_new_thread(self.get_info, ())
Related
I've got a python script for (Foundry) Nuke that listens to commands and for every command received executes a Write node. I've noticed that if I don't do nuke.scriptOpen(my_renderScript) before nuke.execute(writeNode,1,1) and then after do nuke.scriptClose(my_renderScript), then the write command seems to execute but nothing is written to file, despite me changing knob values before I call execute again.
The reason I want to not use scriptOpen and scriptClose every time I execute -the same node- is for performance. I'm new to nuke, so correct me if I'm wrong, but it's inefficient to unload and reload a script every time you want to run a node inside it, right?
[EDIT] Here's a simple test script. Waits for command line input and runs the function, then repeats. If I move the script open and script close outside the looping / recursive function, then it will only write to file once, the first time. On subsequent commands it will "run", and nuke will output "Total render time: " in the console (render time will be 10x faster since it's not writing / doing anything) and pretend it succeeded.
# Nuke12.2.exe -nukex -i -t my_nukePython.py render.nk
# Then it asks for user input. The input should be:
# "0,1,0,1", "1024x1024", "C:/0000.exr", "C:/Output/", "myOutput####.png", 1, 1
# then just keep spamming it and see.
import nuke
import os
import sys
import colorsys
renderScript = sys.argv[1]
nuke.scriptOpen(renderScript)
readNode = nuke.toNode("Read1")
gradeNode = nuke.toNode("CustomGroup1")
writeNode = nuke.toNode("Write1")
def runRenderCommand():
cmdArgs = input("enter render command: ")
print cmdArgs
if len(cmdArgs) != 7:
print "Computer says no. Try again."
runRenderCommand()
nuke.scriptOpen(renderScript)
colorArr = cmdArgs[0].split(",")
imageProcessingRGB = [float(colorArr[0]), float(colorArr[1]), float(colorArr[2]), float(colorArr[3])]
previewImageSize = cmdArgs[1]
inputFileLocation = cmdArgs[2]
outputFileLocation = cmdArgs[3]
outputFileName = cmdArgs[4]
startFrameToExecute = cmdArgs[5]
endFrameToExecute = cmdArgs[6]
readNode.knob("file").setValue(inputFileLocation)
writeNode.knob("file").setValue(outputFileLocation+outputFileName)
gradeNode.knob("white").setValue(imageProcessingRGB)
print gradeNode.knob("white").getValue()
nuke.execute(writeNode.name(),20,20,1)
runRenderCommand()
nuke.scriptClose(renderScript)
runRenderCommand()
The problem was between the chair and the screen. Turns out my example works. My actual code that I didn't include for the example, was a bit more complex and involved websockets.
But anyway, it turns out I don't know how python scoping sintax works ^__^
I was making exactly this error in understanding how the global keyword should be used:
referenced before assignment error in python
So now it indeed works without opening and closing the nuke file every time. Funny how local scope declaration in python in this case in my code made it look like there's no errors at all... This is why nothing's sacred in scripting languages :)
Is there a way to delete this question on grounds that the problem turns out was completely unrelated to the question?
Well that took an unexpected turn. So yes I had the global problem. BUT ALSO I WAS RIGHT in my original question! Turns out depending on the nodes you're running, nuke can think that nothing has changed (probably the internal hash doesn't change) and therefore it doesn't need to execute the write command. In my case I was giving it new parameters, but the parameters were the same (telling it to render the same frame again)
If I add this global counter to the write node frame count (even though the source image only has 1 frame), then it works.
nuke.execute(m_writeNode.name(),startFrameToExecute+m_count,endFrameToExecute+m_count, continueOnError = False)
m_count+=1
So I gotta figure out how to make it render the write node without changing frames, as later on I might want to use actual frames not just bogus count increments.
I'm trying to start a dbus timer from python.
At the moment I was able to launch it through this script:
import dbus
from subprocess import call
def scheduleWall( time, message ):
call(['systemd-run --on-active='+str(time) +' --unit=scheduled-message --description="'+ message +'" wall "'+ message +'"'], shell=True)
I'd like to not use "call", but try to use "StartTransientUnit", but I wasn't able to understand the format of the call at all! I'm rather new to dbus and python.
def scheduleWall( time, message ):
try:
bus = dbus.SystemBus()
systemd1 = bus.get_object("org.freedesktop.systemd1"," /org/freedesktop/systemd1")
manager = dbus.Interface(systemd1, 'org.freedesktop.systemd1.Manager')
obj = manager.StartTransientUnit('scheduled-message.timer','fail',[????],[????])
except:
pass
Is startTransientUnit the right method to call? how should I call it?
TL;DR: stick to systemd-run :)
I don’t think StartTransientUnit is quite the right method – you need to create two transient units, after all: the timer unit, and the service unit that it will start (which will run wall later). Perhaps you can use StartTransientUnit for the timer, but at least not for the service. You also need to set all the properties that the two units need (OnActiveSec= for the timer, ExecStart= for the service, probably some more…) – you can see how systemd-run does it by running busctl monitor org.freedesktop.systemd1 and then doing systemctl run --on-active 1s /bin/true in another terminal. (The main calls seem to be UnitNew and JobNew.)
I’ll admit, to me this seems rather complicated, and if systemd-run already exists to do the job for you, why not use it? The only change I would make is to eliminate the shell part and pass an array of arguments instead of a single space-separated string, with something like this (untested):
subprocess.run(['systemd-run', '--on-active', str(time), ' --unit', 'scheduled-message', '--description', message, 'wall', message)
I am trying to display RSS data on an LED sign using a Raspberry PI. I've based my code on a script that I found for the sign when I first bought it. It's a simple script that allows you to send a message and a colour to the sign and it will scroll across until a keyboard interrupt.
sudo python scroll "Hello World" 1 #red
sudo python scroll "Hello World" 2 #green
sudo python scroll "Hello World" 3 #red and green (orange)
The difference between this script and the one that I am working on is that all the all the data is processed before the loop and then the showmatrix() function is used to show the string on the screen and the shiftmatrix() function is used to scroll the image across.
In order to constantly download the RSS data I have put the following code inside the loop:
#grab emails
newmails = int(feedparser.parse("https://" + USERNAME + ":" + PASSWORD +"#mail.google.com/gmail/feed/atom")["feed"]["fullcount"])
textinput = "You have " + str(newmails) + " new emails"
# append extra characters to text input to allow for wrap-around
textinput+=" :: "
I then use the same functions as before to display this data on the sign:
# Continually output to the display until Ctrl-C
#
# loop around each column in the dotarray
for col in range(len(dotarray[0])):
for row in range(8):
# copy the current dotarray column values to the first column in the matrix
matrix[row][0]=(dotarray[row][col])
# now that we have updated the matrix lets show it
showmatrix()
# shift the matrix left ready for the next column
shiftmatrix()
As the RSS data download takes so long (at last a second), the output loop doesn't run for that time and the sign goes blank. Is there a way of running the feedparser function at the same time so there is no delay?
Am I correct in thinking that multithreading is the way forward? I had a look into couroutines but that got me nowhere.
Yes, os.fork(), youcan make the function run in a different process or the threading module to make it run in another thread.
If the function uses global variables you need to use the threading module and make it run in another thread and if not i'd suggest to do it anyway, less resource wasteful (assuming the function doesnt allocate alot of memory or otherwise uses alot of resources), you code should look something like this:
class displayThread(threading.Thread)
*init function if you need to pass info to the tread, otherwise dont write one but if you do
make sure to call Thread.__init__() first in your function*
def run(): //Overrides the run function
*display what you want on the display*
class downloadThread(threading.Thread)
*init function if you need to pass info to the tread, otherwise dont write one but if you do
make sure to call Thread.__init__() first in your function*
def run(): //Overrides the run function
*download what you want*
and your main script should look like:
thread1 = displayThread
thread2 = downloadThread
thread1.start()
thread2.start()
thread2.join() //waits for download to finish while the display in being updated by the other thread
and if you want to stop the display thread (assuming it goes on forever) you will have to add something like:
os.kill(thread1.getpid(), signal.SIGKILL)
after the .join() and do what you want with the downloaded info.
The multi process version is very similar and you should be able to understand how to make it from my example and the os.fork() docs, if you are having trouble with it - let me know and i'll edit this.
I am new to Python. I am using Netbeans IDE 6.8. When I run the code below- using RUN FILE- it does not seem to produce any output. On the other hand when I debug the code, the output shows the value of counter- 6.
Is this a problem with the program below or one of quirks of Netbeans.
Here is the code:
class Counter:
pass
def cInit():
# Create counter
ctr = Counter()
ctr.value = 0
# Define and call a recursive function that modifies counter
def inner(n):
if (n > 0): inner(n-1)
ctr.value = ctr.value + 1
inner(5)
# Get counter
return ctr.value
if __name__ == "__main__":
print "Hello World";
d = cInit()
print d
This is a classic "bug" of netbeans and other IDEs. For terminal programs, they open a terminal, run the program under it, and then close it. This of course, means that your output window disappears.
There are two ways to fix it, depending on your IDE. Some IDEs have an option to wait for a key press after program completion, it'll be buried in your options panel somewhere. The other is to put a raw_input() command at the end of your code, so that the terminal pauses and waits for user input before closing. That may get very annoying for your end users if they run the thing on the command line, since they may not want it to pause in the middle of a pipeline.
There is nothing wrong with your code, it works fine when run under the Python REPL. This may be a Netbeans quirk -- does print work in other files?
As a side note -- if this is something to do with Netbeans, don't expect any official fix anytime soon -- Oracle killed Python support in Netbeans 7
I have written this short script (which I've stripped away some minor detail for size) and I'm getting a very simple error, yet, I don't understand why! I'm very new to Python, so maybe someone can explain the issue and why it's not working?
The error seems to fall when I wish to print the full custom serial write string back to the console, it doesn't seem to recognise the Args I sent to the function.
Perhaps I have misunderstood something very simple. Should be simple for anyone even with the tiniest of Python understanding
Cheers
The Code:
#! /usr/bin/env python
# IMPORTS APPEAR HERE ***
ser = serial.Serial(
port='/dev/ttyUSB0',
baudrate=115200,
parity='N',
stopbits=1,
bytesize=8
)
# Sets motor number
motor_no = "2"
# Lets create our main GUI class
class ArialApp(object):
# Default init stuff
def __init__(self):
# Create a builder object and create the objects from the .glade file
self.builder = gtk.Builder()
self.builder.add_from_file("../res/main.glade")
self.builder.connect_signals(self)
# Open the serial connection to the encoder and keep it open
ser.open()
# Custom function for sending commands down the serial. Needed to wrap defaults
# arround the custom 'serial.write' command.
self.send_command('A')
# Code removed for space.....
# Custom method for sending commands down serial with default ammendments
def send_command(self, nanotech):
# Send the command with the #, then motor number which should be global, then the command
# sent the the method followed by a return
ser.write("#" + motor_no + nanotech + '\r\n')
# Print to the console the full command sent down the pipe
# [[[ ERROR GOES HERE ]]]
print "#" + motor_no + nanotech + '\r\n'
# Just to show its in here...
if __name__ == "__main__":
app = ArialApp()
gtk.main()
The error:
File "main.py", line 62, in ArialApp
print "#" + motor_no + commands + '\r\n'
NameError: name 'commands' is not defined
Finally, just to shed some context on the situation:
I am writing a small GUI app in Glade and Python / PyGTK to control a stepper motor over serial using the PySerial module. However, I would like to package up my own "write" function so I can append default values to the 'send' down the cable. For example, the motor number and always appending returns on the end of the instructions. Other things like reading back the response straight away in the same function would be useful to gauge responses too, so, wrapping it up into a custom function seemed like the sensible thing to do.
Any advice or help on the above would be appreciated.
Thank-you kindly.
Andy
UPDATE: I have addresses the original issue of not including "self" and I've managed to get Stack to accept the tabs I normally use so its cleaner to look at. Also wanted to note the only code I removed was simple variable setting. However, the issue persists!
It could be because you're missing the self argument:
def send_command(self, commands):
you've got an indentation error in def send_command(commands):
and your first parameter should be "self" :
class ArialApp(object):
<snap>
def send_command(self, commands):
ser.write("#" + motor_no + commands + '\r\n')
Firstly, you should use more than a single space for indentation. White space is significant in Python, and it's very hard to see that you've got it right if you're only using one space. Four is the usually accepted amount.
The main issue with your send_command method is that you've forgotten that the first argument to any method in Python is (by convention) self. So the signature should be:
def send_command(self, commands):
However, the code you have shown would not give the error you state: it would instead give this:
TypeError: send_command() takes exactly 1 argument (2 given)
In addition, in your method it's not commands which is not defined, but motor_no. This is why it's always important to show the actual code you're running, cut down enough to actually reproduce the error.