simultaneous Tkinter and Shell commands - python

I have made a programm with some simple Tkinter windows, for example a 'Hello' label. Is it possible to type and give commands in Python Shell simultaneously? I tried but Python Shell doesn't appear '>>>' to give commands,so when i type and press Enter , the cursor goes to the next line,instead of running the string. I hope you get my point

You want to see the open window and simultaniously execute commands behind >>>.
Two solutions I see:
remove xxx.mainloop() when you execute it with the Python Shell. I did it like this conditionally.
import sys
if 'idlelib' not in sys.modules:
xxx.mainloop()
start the mainloop in another thread. You should not do this in production code because Tkinter is not threadsafe.
import threading
t = threading.Thread(target = xxx.mainloop)
t.start()
These are two solution I could think of because 1. may not always work.

Related

Python subprocess.run C Program not working

I am trying to write the codes to run a C executable using Python.
The C program can be run in the terminal just by calling ./myprogram and it will prompt a selection menu, as shown below:
1. Login
2. Register
Now, using Python and subprocess, I write the following codes:
import subprocess
subprocess.run(["./myprogram"])
The Python program runs but it shows nothing (No errors too!). Any ideas why it is happening?
When I tried:
import subprocess
subprocess.run(["ls"])
All the files in that particular directory are showing. So I assume this is right.
You have to open the subprocess like this:
import subprocess
cmd = subprocess.Popen(['./myprogram'], stdin=subprocess.PIPE)
This means that cmd will have a .stdin you can write to; print by default sends output to your Python script's stdout, which has no connection with the subprocess' stdin. So do that:
cmd.stdin.write('1\n') # tell myprogram to select 1
and then quite probably you should:
cmd.stdin.flush() # don't let your input stay in in-memory-buffers
or
cmd.stdin.close() # if you're done with writing to the subprocess.
PS If your Python script is a long-running process on a *nix system and you notice your subprocess has ended but is still displayed as a Z (zombie) process, please check that answer.
Maybe flush stdout?
print("", flush=True,end="")

RPi - Python Curses program running at boot does not have keyboard focus

I am trying to write a program that will run when my raspberry pi starts up and will allow me to immediately begin typing things with my keyboard and have it be picked up by the program. I don't want to have to manually start the program when the pi starts. I need to use curses (or a similar unbuffered keyboard input library) because I display what I am typing on a 2x16 I2C LCD, but I also need everything that I am typing to be recorded to a text file.
Right now, I am auto-starting the program at boot by putting a line in rc.local. This works, and the I2C display is correctly showing program output, but it does not respond to keyboard input, and the keyboard input is instead displayed (when I connect the pie to a screen, the goal is to run headless) on an odd console layout that exits when I press enter and says -bash: 'whatever I just typed' command not found.
I have already tried:
Setting a timer at the beginning of the program to wait until the pi has fully booted before initializing the curses window and keyboard capture
Creating a seperate python program to wait until the pi has fully booted and then running the main script by importing it
Neither of these methods works though, I get the same problem with slight differences.
To be clear, the program works flawlessly if I run it manually from the command line. But there is no keyboard input to the program (or at least not where it is supposed to be inputted) when I autostart the script with rc.local.
My code:
#!/usr/bin/python
import I2C_LCD_driver, datetime, sys
from time import *
from subprocess import call
mylcd = I2C_LCD_driver.lcd()
for x in range(30): #waits for raspberry pi to boot up
mylcd.lcd_display_string("Booting Up: "+str(x), 1)
sleep(1)
import curses
key = curses.initscr()
curses.cbreak()
curses.noecho()
key.keypad(1)
key.nodelay(1)
escape=0
while escape==0:
#variable initialization
while 1:
k=key.getch()
if k>-1: #runs when you hit any key. getch() returns -1 until a key is pressed
if k==27: #exits the program when you hit Esc
break
elif k==269:
# a couple other special Function key cases are here
else:
inpt=chr(k)
mylcd.lcd_display_string(inpt,2,step) #writes the last character to the display
#some more code that handles writing the text to the LCD, which works flawlessly when run manually.
file.write("%s\r\n" % entry)
file.close()
mylcd.lcd_display_string("Saved ",2)
mylcd.lcd_display_string("F1 New F2 PwrOff",1)
while 1:
k=key.getch()
if k>-1:
if k==265: #do it again! with F1
mylcd.lcd_clear()
break
elif k==266: #shut down with F2
escape=1
break
curses.nocbreak()
key.keypad(0)
curses.echo()
curses.endwin()
call("sudo shutdown -h now", shell=True)
The line that I have in /etc/rc.local is as follows if that is important:
sudo python3 journal.py &
and it is followed by the 'exit 0' line.
Thanks for any help you can provide. I know this is a very specific problem and will be tedious to reproduce, but if anyone knows anything about autostarting functions I would be very appreciative of any tips.
Ok, literally all I had to do (which I did find after some more research on stackexchange, this is the thread that contained the answer I was looking for) was run my program from ~/.bashrc instead of /etc/rc.local. This method works perfectly, exactly what I wanted.
This should be because of how you called the program:
python3 journal.py &
You may want to check out JOB CONTROL of bash (or your shell) man page:
Only foreground
processes are allowed to read from ... the terminal. Background processes which
attempt to read from ... the
terminal are sent a SIGTTIN ... signal by the kernel's terminal
driver, which, unless caught, suspends the process.
In short, once curses (or anything for that matter) try to read from stdin your process is likely stopped (after it may have already written to your display). Keep it in the foreground to be able to have it use stdin (and by extension keyboard).
Side note: Not sure about distro and details of implementation of rc.local in your case, but aren't init scripts normally run with uid/gid 0 already (without wrapping individual calls through sudo?)

Print output from python to C# application

I have made a C# app which calls a python script.
C# app uses Process object to call python script.
I also have redirected the sub-process standard output so I can process the output from python script.
But the problem is:
The output(via print function) from python will always arrive at once when the script terminates.
I want the output to arrive in real time while script running.
I can say I have tried almost all of method can get from google, like add flush of sys.out, redirect sysout in python, C# event driven message receiving or just using while to wait message etc,.
How to flush output of print function?
PyInstaller packaged application works fine in Console mode, crashes in Window mode
I am very wondering that like PyCharm or other python IDE, they run python script inside, but they can print the output one by one without hacking original python script, how they do that?
The python version is 2.7.
Hope to have advise.
Thank you!
I just use very stupid but working method to resolve it:
using thread to periodically flush the sys.out, the code piece is like this:
import sys
import os
import threading
import time
run_thread = False
def flush_print():
while run_thread:
# print 'something'
sys.stdout.flush()
time.sleep(1)
in main function:
if __name__ == '__main__':
thread = threading.Thread(target=flush_print)
run_thread = True
thread.start()
# my big functions with some prints, the function will block until completed
run_thread = False
thread.join()
Apparently this is ugly, but I have no better method to make work done .

How to display two different outputs in python console

Is there a way to split the output console?
I would like to display one section on top (the main program) and the bottom part will display a progress bar for example.
(excuse my horrible design skills)
Any ideas will be greatly appreciated :)
If there is one python app that outputs - using curses library as #Rawing suggested: https://docs.python.org/3.5/howto/curses.html . It's prebuilt and at hand.
If there are more apps that output data there are several ways to do so. First, you can use byobu or alike and have split terminal with outputs from different apps visible on the same screen. Second, you can have a broadcaster app that collects data from worker apps (or threads) and displays them later with curses (see above).
More, you can dump data to a file and then using Linux watch command show contents at regular intervals:
watch cat file
There are lots of other methods too.
if you need two or multiple consoles for the output of your python script then you can do this if you are on windows.
Use win32console module to open a second console for your thread or subprocess output.
Here is a sample code:
import win32console
import multiprocessing
def subprocess(queue):
win32console.FreeConsole() #Frees subprocess from using main console
win32console.AllocConsole() #Creates new console and all input and output of subprocess goes to this new console
while True:
print(queue.get())
#prints any output produced by main script passed to subprocess using queue
if __name__ == "__main__":
queue = multiprocessing.Queue()
multiprocessing.Process(target=subprocess, args=[queue]).start()
while True:
print("Hello World in main console")
queue.put("Hello work in sub process console")
#sends above string to subprocess and it prints it into its console
#and whatever else you want to do in ur main process
You can also do this with threading. You have to use queue module if you want the queue functionality as threading module doesn't have queue
Here is the win32console module documentation

Want to resize terminal windows in python, working but not quite right

I'm attempted to resize the terminal window on launch of a python script to ensure the display will be static size. It's working but not quite what I expected. I've tried a few methods:
import sys
sys.stdout.write("\x1b[8;40;120t")
and
import subprocess
subprocess.call(["echo","-e","\x1b[8;40;120t"])
and even just
print "\x1b[8;40;80t"
They all work and resize the real terminal. However, if my terminal is, let's say 25x80 to start, the script starts, it resizes, then exits. It will not execute the rest of the script. I wrapped it in a try/Except and nothing is thrown. Nothing in the syslogs and python -v script.py shows nothing odd. If I execute the script again or at a term size of 40x120 (my target size)..the script runs just fine. Why is exeecuting the ANSI escape exiting python? Furthermore if I run this interactively it works with no issues.
Using Python 2.6.6.
I tried to run the following script, and it "works" (Linux Debian / Python 2.6 / gnome-terminal):
print "\x1b[8;40;80t"
print "ok"
The window is resized and the script execution continue.
If you confirm in your case the program stops after resizing, my guess would be Python received a signal SIGWINCH when the window is resized.
You should try to add a specific signal handler. Something like that:
def resizeHandler(signum, frame):
print "resize-window signal caught"
signal.signal(signal.SIGWINCH, resizeHandler)
You need to put the terminal in cbreak mode for this. Using the term package (easy_install term) this could look like this:
from term import opentty, cbreakmode
with opentty() as tty:
if tty is not None:
with cbreakmode(tty, min=0):
tty.write('\033[8;26;81t');
print 'terminal resized'

Categories

Resources