gradio refresh interface when selecting File - python

I'm trying to create a gradio User Interface which does the following
on the left panel I have a File control, that allows the selection of a local file (eg. a .csv)
when a file is selected a "Process" button should be made visible
when the "Process" button is pressed, a function is called, reading the contents of the file, and processing it in some ways, resulting in a string
the resulting string is shown in a TextArea in the right column
I'm stuck implementing point 2. I can select the file, but can't make the Process button become visible.
This is my code so far (not yet implementing points 3. a:
import gradio as gr
def file_selected(file_input):
print("yes, file_selected is invoked")
print(process_button)
process_button.visible=True
demo.render()
return process_button
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Data")
file_input = gr.File(label="Select File")
process_button = gr.Button("Process", visible=False)
with gr.Column(scale=2, min_width=600):
gr.Markdown("### Output")
result_display = gr.TextArea(default="", label="Result", lines=10, visible=False)
file_input.change(fn=file_selected, inputs=file_input, outputs=process_button)
if __name__ == "__main__":
demo.launch()
I see that at file selection the message is printed (and print(process_button) prints "button" so I'm sure this variable is not None), but the button doesn't appear on the page.
edited: fixed some errors not directly related to the problem.

There were many problems with the code (I fixed those not related with the main issue in the original post), but in the end what solved my problem (making the button visible) was that instead to rerender,
def file_selected():
...
process_button.visible=True
demo.render()
I just had to return the process_button.update
def file_selected(file_input):
...
return gr.update(visible=True)
(Actually this was documented in gradio's online docs; sorry, I didn't notice it before)
This is the complete working code:
import gradio as gr
def file_selected(file_input):
print("yes, file_selected is invoked")
print(process_button)
return gr.update(visible=True)
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Data")
file_input = gr.File(label="Select File")
process_button = gr.Button("Process", visible=False)
with gr.Column(scale=2, min_width=600):
gr.Markdown("### Output")
result_display = gr.TextArea(default="", label="Result", lines=10, visible=False)
file_input.change(fn=file_selected, inputs=file_input, outputs=process_button)
if __name__ == "__main__":
demo.launch()

Related

How to make botcity generate the command correctly?

I'm using BotCity for automation but the system doesn't work.
After listing the image and indicating the action on the UI tab, BotCity does not create the code on the 'CODE' tab, how can I solve this problem?
from botcity.core import DesktopBot
from botcity.maestro import *
class Bot(DesktopBot):
def action(self, execution=None):
self.browse("https://www.facebook.com/groups/xxxxxx")
#in this field, the code should be created after the image is selected, but that doesn't happen, even if I leave the course selected in this line
def not_found(self, label):
print(f"Element not found: {label}")
if __name__ == '__main__':
Bot.main()

Passing a URL through the entry widget (TKinter // Python 3+)

I have been trying to put together a few lines of code that takes a youtube music video URL and converts it to mp3/mp4 + 720p, and then downloads it to my DropBox music folder.
When I'm trying to pass a URL through a TKinter widget (entry bar) I am hitting an error about how the the entry object has no attribute 'type', or that the URL is invalid. Is it something to do with not adding quotation marks to the youtube link or something?
If anyone has any insight I would greatly appreciate it. I assume I'm missing something very obvious, but I can't seem to figure out what exactly.
#!/usr/bin/env python
import sys
import os
import tkinter
from pytube import *
from tkinter import *
top=tkinter.Tk()
yt_variable = StringVar()
def helloCallBack():
#Select youtube link you want to upload and print contents
yt = YouTube(yt_entry)
print(yt.get_videos())
print(yt.filename)
#Set parameters for youtube video
video = yt.get('mp4', '720p')
print(yt.videos)
print("success")
#Select download location for youtube video
video.download('C:/Users/coope/Dropbox/BrokenBow/Music/')
print("Downloaded " + str(yt.filename) + " to " + str(video.download) + " successfully!")
return
yt_label=tkinter.Label(top,text='Paste Link + Press Go')
yt_label.pack()
yt_button=tkinter.Button(top,text='Go',command= helloCallBack)
yt_button.pack()
yt_entry=tkinter.Entry(top, textvariable=yt_variable)
yt_entry.get()
yt_entry.pack()
top.mainloop()
Briefly, you have the following:
yt_entry=tkinter.Entry(top, textvariable=yt_variable)
yt_entry.get()
yt = YouTube(yt_entry)
You are expecting this to create an Entry widget, retrieve its contents, and send that retrieved value to the YouTube() constructor. It does not work like that. You are actually creating an Entry widget, immediately retrieving its contents, throwing away those contents (which will be empty anyway, since by that point you haven't had a chance to put anything into that field), and then attempting to send the Entry widget itself to the YouTube() constructor.
On top of that, you give the Entry widget a textvariable, but then you never use it.
Instead, retrieve the contents of that Entry widget (via its textvariable) within the callback. You can even do it in the YouTube() constructor call.
...
top=tkinter.Tk()
yt_variable = StringVar()
def helloCallBack():
...
yt = YouTube(yt_variable.get())
...
...
yt_entry=tkinter.Entry(top, textvariable=yt_variable)
yt_entry.pack()
top.mainloop()
Since you're not doing anything special with that Entry widget, there's no need for a textvariable at all.
...
top=tkinter.Tk()
def helloCallBack():
...
yt = YouTube(yt_entry.get())
...
...
yt_entry=tkinter.Entry(top,)
yt_entry.pack()
top.mainloop()
Also, there's no need for a bare return at the end of a function. It will return regardless once there's nothing more to do, with a default return value of None (the same as what gets returned with a bare return statement, or with return None).

How to record multiple checkboxes in wxPython?

I am trying to get my program to record if the user clicked on checkbox(es) so I know what things to delete. The problem is that I don't have all the variables names for all the checkboxes so I can't just do GetValue(). In the code below, I have a set number of things but in the actual program, it pulls user info from file.
import wx
class supper(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Delete Stocks',size=(300,300))
nexus=wx.Panel(self)
again=30
newfp='GOOG AAPL'.split()
#Need to see if user checked box and which one
for i in newfp:
self.checkbox=(wx.CheckBox(nexus,-1,i,(30,again),(160,-1)))
self.Bind(wx.EVT_CHECKBOX, self.lol,self.checkbox)
again+=30
anothercancel=wx.Button(nexus,label='Cancel',pos=(50,250),size=(60,40))
self.Bind(wx.EVT_BUTTON,self.acancel,anothercancel)
anotherok=wx.Button(nexus,label='OK',pos=(200,250),size=(60,40))
self.Bind(wx.EVT_BUTTON,self.okalready,anotherok)
def acancel(self,event):
self.Destroy()
#Couldn't figure out how to see what check was clicked
def okalready(self,event):
for i in newfp:
valuechecker=self.checkbox.GetValue()
if self.checkbox.Get()==True:
print 'You clicked this %s one'%i
self.Destroy()
def lol(self,event):
pass
if __name__=='__main__':
ok=wx.PySimpleApp()
people=supper(parent=None,id=-1)
people.Show()
ok.MainLoop()
This isn't the whole thing so there might be a variable that is not defined here. Thanks in advance! Look forward to the answers!
just keep them in a list ...
self.checkboxes = []
for i in newfp:
self.checkboxes.append(wx.CheckBox(nexus,-1,i,(30,again),(160,-1)))
self.checkboxes[-1].Bind(wx.EVT_CHECKBOX, self.lol)
again+=30
then to check which boxes are checked when you click ok you can use this
def okalready(self,event):
for i,cb in enumerate(self.checkboxes):
print "CB:%d = %s"%(i,cb.GetValue())
print "Checked:",[cb.GetLabel() for cb in self.checkboxes if cb.GetValue()]
self.Destroy()

Why is a website's response in python's `urllib.request` different to a request sent directly from a web-browser?

I have a program that takes a URL and gets a response from the server using urllib.request. It all works fine, but I tested it a little more and realised that when I put in a URL such as http://google.com into my browser, I got a different page (which had a doodle and a science fair promotion etc.) but with my program it was just plain Google with nothing special on it.
It is probably due to redirection, but if the request from my program goes through the same router and DNS, surely the output should be exactly the same?
Here is the code:
"""
This is a simple browsing widget that handles user requests, with the
added condition that all proxy settings are ignored. It outputs in the
default web browser.
"""
# This imports some necessary libraries.
import tkinter as tk
import webbrowser
from tempfile import NamedTemporaryFile
import urllib.request
def parse(data):
"""
Removes junk from the data so it can be easily processed.
:rtype : list
:param data: A long string of compressed HTML.
"""
data = data.decode(encoding='UTF-8') # This makes data workable.
lines = data.splitlines() # This clarifies the lines for writing.
return lines
class Browser(object):
"""This creates an object for getting a direct server response."""
def __init__(self, master):
"""
Sets up a direct browsing session and a GUI to manipulate it.
:param master: Any Tk() window in which the GUI is displayable.
"""
# This creates a frame within which widgets can be stored.
frame = tk.Frame(master)
frame.pack()
# Here we create a handler that ignores proxies.
proxy_handler = urllib.request.ProxyHandler(proxies=None)
self.opener = urllib.request.build_opener(proxy_handler)
# This sets up components for the GUI.
tk.Label(frame, text='Full Path').grid(row=0)
self.url = tk.Entry(frame) # This takes the specified path.
self.url.grid(row=0, column=1)
tk.Button(frame, text='Go', command=self.browse).grid(row=0, column=2)
# This binds the return key to calling the method self.browse.
master.bind('<Return>', self.browse)
def navigate(self, query):
"""
Gets raw data from the queried server, ready to be processed.
:rtype : str
:param query: The request entered into 'self.url'.
"""
# This contacts the domain and parses it's response.
response = self.opener.open(query)
html = response.read()
return html
def browse(self, event=None):
"""
Wraps all functionality together for data reading and writing.
:param event: The argument from whatever calls the method.
"""
# This retrieves the input given by the user.
location = self.url.get()
print('\nUser inputted:', location)
# This attempts to access the server and gives any errors.
try:
raw_data = self.navigate(location)
except Exception as e:
print(e)
# This executes assuming there are no errors.
else:
clean_data = parse(raw_data)
# This creates and executes a temporary HTML file.
with NamedTemporaryFile(suffix='.html', delete=False) as cache:
cache.writelines(line.encode('UTF-8') for line in clean_data)
webbrowser.open_new_tab(cache.name)
print('Done.')
def main():
"""Using a main function means not doing everything globally."""
# This creates a window that is always in the foreground.
root = tk.Tk()
root.wm_attributes('-topmost', 1)
root.title('DirectQuery')
# This starts the program.
Browser(root)
root.mainloop()
# This allows for execution as well as for importing.
if __name__ == '__main__':
main()
Note: I don't know if it is something to do with the fact that it is instructed to ignore proxies? My computer doesn't have any proxy settings turned on by the way. Also, if there is a way that I can get the same response/output as a web browser such as chrome would, I would love to hear it.
In order to answer your general question you need to understand how the web site in question operates, so this isn't really a Python question. Web sites frequently detect the browser's "make and model" with special detection code, often (as indicated in the comment on your question) starting with the User-Agent: HTTP header.
It would therefor make sense for Google's home page not to include any JavaScript-based functionality if the User-Agent identifies itself as a program.

Extending QGIS Plugin builder result with a Combobox fails in referencing the new object

I have extended the UI file resulting from the Plugin builder with Qt Creator.
Just added some checkboxes and a combobox, named layercombo to the form.
The application is named jacktest.py. It uses an intermediate file jackdialog.py (generated from the plugin builder, left unchanged).
Compiled the UI file and the resource file. Then added some code to the plugin and tested this. It's no problem to get the available layer names in a QMessagebox. But how to add these to the combobox ?
Should be simple, but no option succeeds in referencing the combobox.
Error message: AttributeError: jacktest instance has no attribute 'layercombo'.
Result from my latest try:
# run method that performs all the real work
def run(self):
# create and show the dialog
dlg = jacktestDialog()
# show the dialog
dlg.show()
result = dlg.exec_()
for layer in self.iface.legendInterface().layers():
if layer.type() == QgsMapLayer.VectorLayer:
QMessageBox.information( self.iface.mainWindow(), "Info", layer.name())
self.layercombo.Items.Insert(0, layer.name())
# See if OK was pressed
if result == 1:
# do something useful (delete the line containing pass and
# substitute with your code
pass
You are trying to reference the current class (which is not your dialog) when you are setting the layercombo items
Replace:
self.layercombo.Items.Insert(0, layer.name())
with
dlg.ui.layercombo.Items.Insert(0, layer.name())
but you code still won't work correctly as exec_() is blocking and waits until it returns so you are adding items to an invisible dialog.
Try this instead:
# create and show the dialog
dlg = jacktestDialog()
# show the dialog
for layer in self.iface.legendInterface().layers():
if layer.type() == QgsMapLayer.VectorLayer:
QMessageBox.information( self.iface.mainWindow(), "Info", layer.name())
dlg.ui.layercombo.Items.Insert(0, layer.name())
result = dlg.exec_()
Went on in developing a Signal within the run module (code: def run (self):)
QObject.connect(dlg.ui.layercombo,SIGNAL('currentIndexChanged (int)'),self.select_one)
and the code of select_one is:
def select_one(self):
comboindex = dlg.ui.layercombo.currentIndex()
QMessageBox.information(self.iface.mainWindow(), "Info", comboindex)
Error message:
comboindex = dlg.ui.layercombo.currentIndex()
NameError: global name 'dlg' is not defined
Suppose I have to reference dlg as a parameter in the function call, but this is not working until now.

Categories