I have a program in Python. I would like when the program starts for it to ask me to enter root password, in a GUI dialog. I run the program then it shows the below error:
couldn't connect to display ": 0.0"
If I delete all lines with pkexec stuff inside upgrade.py then it works perfectly. Also if I run in gnome-terminal with the command sudo python3 /home/user/Python/upgrade.py then it works too. Maybe it's a problem with sudo? Exactly the same happens with GTK for Python.
Python code:
from tkinter import *
#!/usr/bin/python3
import os
import subprocess
import sys
euid = os.geteuid()
if euid != 0:
print ("Script not started as root. Running sudo..")
args = ['pkexec', sys.executable] + sys.argv + [os.environ]
# the next line replaces the currently-running process with the sudo
os.execlpe('pkexec', *args)
print ('Running. Your euid is', euid)
root = Tk()
root.title('Update system')
#root.geometry("290x100")
def button_add1():
callProcess = subprocess.Popen(['ls', '-la'], shell=True)
subprocess.run(['pkexec', 'ls', '-la'], check=True)
def button_add4():
root.destroy()
# Define Buttons
button_1 = Button(root, text="Upgrade system", padx=40, pady=20, command=button_add1)
button_4 = Button(root, text="Quit", padx=40, pady=20, command=button_add4)
# Put the buttons on the screen
button_1.grid(row=0, column=0)
button_4.grid(row=0, column=4)
root.mainloop()
Please I don't want like something this... Simplest method of asking user for password using graphical dialog in Python?
I would like authentication like programs such as Synaptic, Gparted, Bleachbit
I have already asked on Stackoverflow but they said, It is related on system policy configuration and nothing related to Python or tkinter. This question is now migrated back to Stack Overflow!
I tried my code on Debian and Linux Mint.
You mustn't try to run the GUI as root. You should isolate the smallest possible component and only run that as privileged. See https://wiki.archlinux.org/index.php/Running_GUI_applications_as_root and the note in the pkexec manual page which specifically explains that it will not allow you to take over the invoking user's $DISPLAY.
Here's a rough sketch, but it's untested right now.
#!/usr/bin/python3
# ^ this needs to be the absolutely first line of the file
from tkinter import * # FIXME: probably avoid import *
# import os # no longer used
import subprocess
# import sys # no longer used
print ('Running. Your euid is whatever it is.')
root = Tk()
root.title('Update system')
#root.geometry("290x100")
def button_add1():
subprocess.run(['ls', '-la'], check=True)
subprocess.run(['pkexec', 'ls', '-la'], check=True)
def button_add4():
root.destroy()
# Define Buttons
button_1 = Button(root, text="Upgrade system", padx=40, pady=20, command=button_add1)
button_4 = Button(root, text="Quit", padx=40, pady=20, command=button_add4)
# Put the buttons on the screen
button_1.grid(row=0, column=0)
button_4.grid(row=0, column=4)
root.mainloop()
If (as in your code before your edit) you want to run multiple commands behind one pkexec, you can do that with something like
subprocess.run(
['pkexec', 'sh', '-c', 'apt-get update && apt-get upgrade -y'],
check=True)
As an aside, if your example code is representative, you can replace from tkinter import * with from tkinter import Tk to avoid the import * antipattern.
Related
this is my first time here so if I break some unwritten rules please don't shoot me
I've been trying build an app for editing, reading and opening .ahk files. The last one gives me problems.
this code kind of does what I want except it fires the command immediately after opening the app.
from tkinter import *
from tkinter import filedialog
import os
import threading
root = Tk()
def openfile():
os.system( r'\Users\merijn\PycharmProjects\infoprojectP3\venv\Scripts\ahkScript1.ahk')
def func():
print("hello")
btn1 = Button(text='programma', command=threading.Thread(target=openfile).start())
btn2 = Button(text='ander ding', command=func)
btn1.pack()
btn2.pack()
root.mainloop()
Any help would be much appreciated!
Change the following line (it just assigns the result of threading.Thread(...) to command option):
Button(text="run program1", command=threading.Thread(target=lambda: os.system(r'\Users\merijn\PycharmProjects\infoprojectP3\venv\Scripts\ahkScript1.ahk').start()))
to
Button(text="run program1", command=lambda: threading.Thread(target=lambda: os.system(r'\Users\merijn\PycharmProjects\infoprojectP3\venv\Scripts\ahkScript1.ahk')).start())
or
Button(text="run program1", command=lambda: threading.Thread(target=os.system, args=[r'\Users\merijn\PycharmProjects\infoprojectP3\venv\Scripts\ahkScript1.ahk']).start())
Same for buttons of run program2 and run program3.
Update: based on your updated code, you need to change the following line:
btn1 = Button(text='programma', command=threading.Thread(target=openfile).start())
to
btn1 = Button(text='programma', command=lambda: threading.Thread(target=openfile).start())
So I'm trying to use a Tkinter window as an output log. My main program is a command line interface, so if the output from the "side programs" that run fills up the python console, it can ruin the user experience.
I have the Tkinter output log program in a seperate file, which I import into my main file. This is the gyst of the Tkinter file I created:
import time
from datetime import datetime
root = Tk()
root.configure(background='black')
root.geometry('700x460')
console = Listbox(root, width=40000, height=30000, font=('Lucida Console', 14), relief=FLAT, bg='black',
fg='white',
borderwidth=0, highlightbackground='black', selectbackground='black',
selectforeground='white')
console.pack()
def log(what_to_log):
now = datetime.now()
console.insert('[' + now.strftime("%H:%M:%S") + ']: ' + what_to_log)
root.mainloop()
So I import it into my main program like so:
# this is the file with the Tkinter code
import Logs
Logs.log('Test')
The issue is that the main program doesn't continue running after importing Logs, it just stops, and continues to run the mainloop in the Logs file.
So my question is, how could I get both files to continue running, while also being able to update the Tkinter listbox via the log function??
You should not execute root.mainloop() as it will block your console application. Use root.update() at the end of log() to force tkinter to update the list box. Also there is syntax error in console.log(...).
Below is a modified Logs.py:
from tkinter import *
from datetime import datetime
root = Tk()
root.configure(background='black')
root.geometry('700x460')
console = Listbox(root, font=('Lucida Console', 14), relief=FLAT, bg='black', fg='white',
borderwidth=0, highlightbackground='black', selectbackground='black',
selectforeground='white')
console.pack(fill='both', expand=1)
def log(what_to_log):
now = datetime.now()
console.insert('end', '['+now.strftime("%H:%M:%S")+']: '+what_to_log)
console.see('end') # make sure last log is visible
root.update() # force tkinter to update
Here is what I coded...
import tkinter as tk
import subprocess
import sys
import time
import os
import tkinter.font as font
from tkinter.ttk import *
app = tk.Tk()
app.geometry("400x400")
app.configure(bg='gray')
photo = tk.PhotoImage(file=r"C:\Users\ex\ex_button_active.png")
myFont = font.Font(family='Helvetica', size=20, weight='normal')
tk.Label(app, text='EX', bg='gray', font=(
'Verdana', 15)).pack(side=tk.TOP, pady=10)
app.iconbitmap(r'C:\Users\ex\ex_icon.ico')
start = time.time()
cmd = sys.executable + " -c 'import time; time.sleep(2)' &"
subprocess.check_call(cmd, shell=True)
assert (time.time() - start) < 1
p = subprocess.Popen(cmd, shell=True)
def ex_activation():
#Python Code
#Python Code...
def ex_stop():
sys.exit(ex_activation) #This area is basically where I have a button to terminate the other script running.
#I have tried sys.exit() and had the same result
ex_activation_button = tk.Button(app,
bg='black',
image=photo,
width=120,
height=120,
command=ex_activation)
ex_stop_button = tk.Button(app,
bg='Gray',
text='ex',
width=12,
command=ex_stop
height=3)
ex_stop_button['font'] = myFont
app.title("Example")
ex_activation_button.pack(side=tk.TOP)
ex_stop_button.pack(side=tk.LEFT)
app.mainloop()
I am looking for a way to get my program to stop the program the other button runs. I realized that this maybe be a "self destruct button" but I don't know how to do this with the script the other button runs. Any help greatly appreciated! I tried killing the code by putting the def ex_activation in the p.kill
This did not work...
If the other python script is made to run forever (has some kind of while True:), you can't run it on the command line as you did, because it will freeze your window while that script is running.
In order to run a python script on background you will need to do it with the subprocess library. (Find out here)
I also found an answer of another question that uses check_ouput() in order to know when the python program has finished. This can also be useful if you want to send a status to the tkinter app: you can print("33% Complete"), for example. You could add this in tkinter's main loop, so you always know if your program is running or not.
And last but not least, to kill that process (using the stop button), you should do it using os, and looking for the subprocess' ID. Here you can also find a good example.
I would try something like this:
cmd = "exec python file.py"
p = subprocess.Popen(cmd, shell=True)
# Continue running tkinter tasks.
tk.update()
tk.update_idletasks() # These both lines should be inside a while True
# Stop secondary program
p.kill()
EDIT
Example code using your question's code. WARNING: I have changed the png file location for testing, commented the app icon, and tested ONLY on Windows.
It's important to remove the mainloop() on the main file and put update...() in order to catch the keyboardInterrupt that (I don't know why) is killing both parent and child process.
I invite you to try it and be as happy as I have been when it was working after half an hour of testing!!
File 1: daemon.py - this file will run forever.
from time import sleep
from sys import exit
while True:
try:
print("hello")
sleep(1)
except KeyboardInterrupt:
print("bye")
exit()
File 2: tkinterapp.py - The name is self-explainatory
import tkinter as tk
import subprocess
import sys
import time
import os
import tkinter.font as font
from tkinter.ttk import *
app = tk.Tk()
app.geometry("400x400")
app.configure(bg='gray')
photo = tk.PhotoImage(file=r"C:\Users\royal\github\RandomSketches\baixa.png")
myFont = font.Font(family='Helvetica', size=20, weight='normal')
tk.Label(app, text='EX', bg='gray', font=(
'Verdana', 15)).pack(side=tk.TOP, pady=10)
# app.iconbitmap(r'C:\Users\ex\ex_icon.ico')
def ex_activation():
global pro
print("running!")
pro = subprocess.Popen("python daemon.py", shell=True)
def ex_stop():
global pro
print("stopping!")
os.kill(pro.pid, 0)
ex_activation_button = tk.Button(app,
bg='black',
image=photo,
width=120,
height=120,
command=ex_activation)
ex_stop_button = tk.Button(app,
bg='Gray',
text='ex',
width=12,
command=ex_stop, # BE CAREFUL You were missing a "," here !!!
height=3)
ex_stop_button['font'] = myFont
app.title("Example")
ex_activation_button.pack(side=tk.TOP)
ex_stop_button.pack(side=tk.LEFT)
# app.mainloop()
while True:
try:
app.update()
app.update_idletasks()
except KeyboardInterrupt:
pass
I've made a GUI with Tkinter and i linked a script to a button. I've also created a browse file option in my GUI and when i select a file i store it's path into a variable named "file". What i'm trying to do is click the button and run the script using the path i stored into the variable "file", but i get a 'no such file or directory error'. The solution must be pretty obvious but i just can't figure it out. Here's my GUI code:
from tkinter import *
from tkinter import filedialog
from tkinter import ttk
from tkinter import messagebox
import subprocess
window = Tk()
#modify window
window.title("Random Title")
window.geometry("600x400")
tab_control = ttk.Notebook(window)
#Creating tabs
tab1 = ttk.Frame(tab_control)
tab2 = ttk.Frame(tab_control)
#Modifying tabs
tab_control.add(tab1, text='Issue')
tab_control.add(tab2, text='Verify')
file = ""
var = StringVar()
var.set("")
w = Entry(tab2,textvariable=var)
w.grid(column=1,row=0)
#Creating button & actions
def issue():
subprocess.call('./issue_script.sh', shell=True)
messagebox.showinfo('Issue Certificate', 'Certificate issued successfully!')
btn = Button(tab1, text="Issue Certificate", command=issue)
btn.grid(column=1, row=5)
def browse():
file = filedialog.askopenfilename(filetypes = (("all files","*.*"),("Text files","*.txt")))
var.set(file)
print(file)
btn2 = Button(tab2, text="Browse", command=browse)
btn2.grid(column=3, row=0)
def verify():
subprocess.call(['./verify_script.sh', file], shell=True)
btn = Button(tab2, text="Verify Certificate", command=verify)
btn.grid(column=1, row=5)
tab_control.pack(expand=1, fill='both')
#event loop
window.mainloop()
I've also added a print(file) command so that i see what is stored in the variable and i get the correct result(the path i selected). Maybe the error is in the line i call the script subprocess.call(['./verify_script.sh', file], shell=True) or in the script itself. Here's the script code:
#!/bin/bash
echo "Verifying certificate..."
cd
python3 cert-issuer/cert-verifier/cert_verifier/verifier.py $1
I actually made it work, but i don't know why it does.
All i changed was instead of calling my script like this
subprocess.call(['./verify_script.sh', var.get()], shell=True)
i omitted the shell=True command and the argument passes correctly into the script.
So i called subprocess.call(['./verify_script.sh', var.get()]) and it works just fine but i can't think why. Any explanation is much appreciated.
I am trying to run a .py file from another python code using the following sequence.
from tkinter import *
import os
import sys
def open_SS():
print('processing')
os.system('cd /home/pi/Desktop/Backup')
os.system('python p.py')
def close_window():
master.destroy()
master = Tk()
master.minsize(width=500, height=300)
Button(master, text='Exit', command=close_window).grid(row=12, column=6, sticky=W, pady=4)
Button(master, text='SS', command=open_SS).grid(row=12, column=8, sticky=W, pady=4)
mainloop( )
The Exit button does the command, but the 'SS' button does not, the word 'processing' does get printed, just the running of the p.py file. I tried running those two os.system commands on a command terminal and it works fine. p.py is supposed to input GPIO signals to a Raspberry Pi.
from tkinter import *
import os
import sys
master = Tk()
def open_SS():
print('processing')
os.system("python /home/pi/Desktop/Backup/p.py")
btn=Button(master,text="click here")
btn.grid(row=0,column=1)
btn.bind("<Button>",open_SS)