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

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).

Related

gradio refresh interface when selecting File

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()

QListWidget item text is not returning with If statement

I have a QListWidget. I am running this function on itemClicked, and this function is also called from different part of my program. So this function has optional argument cutrrentItemText. for some reason my code is not working. Check below example.
def loadSomething(self,currentItemText=None):
if not currentItemText:
item = self.listWidget.currentItem()
currentItemText = item.text()
print currentItemText
#result from above code
<PySide2.QtWidgets.QListWidgetItem object at 0x7f910b112e60>
instead of item text it assigns item object. Here is code without if statement which is working like charm.
def loadSomething(self,currentItemText=None):
#if not currentItemText:
item = self.listWidget.currentItem()
currentItemText = item.text()
print currentItemText
#result of this give currentItems text
I am wondering where I am making mistake. Can any one tell me whats wrong in this code??
Note: I am trying this in Foundry nuke. Trying a custom python panel.
Update:
In my main widget init i have this to connect itemClicked event
self.listWidget.itemClicked.connect( self.loadSomething )
Resolved:
I just realized, itemClicked event sends current item object while call back. so first argument should be item,
def loadSomething(self,item,currentItemText=None)
above change worked
Try this code (I tested it in NukeX 12.0v3 on Catalina):
from PySide2 import QtWidgets, QtGui
import nuke
def loadSomething(currentItemText=None):
if not currentItemText:
item = QListWidget.currentItem()
currentItemText = item.text()
print currentItemText
loadSomething(currentItemText="Some")

No error...search function still not working

I made a code for a program that will show pictures that are accessible from the main menu. In my menu, there is a search option that opens a new window in which you can search through the database (that's a list) and if the entered words are in the list it will activate a function. the search function is shown in this part of code:
def search():
def compare(words):
key=words.get()
print(key)
for i in base:
if i==key:
if key=="apple":
AppleFunction()
if key=="pear":
PearFunction()
else:
messagebox.showerror("Eror!","Wrong entry, please correct!")
return
searchWindow=Toplevel(main)
searchWindow.geometry("425x125+225+145")
searchWindow.resizable(False,False)
searchWindow.config(bg=mycolor)
searchWindow.title("Search")
searchWindow.iconbitmap(r"f.ico")
words=Entry(searchWindow)
words.config(font="Times", width=20)
text1=Label(searchWindow, text="Search by key words:", wraplength=250, justify="center")
text1.pack(pady=5)
text1.config(bg=mycolor, font="Times")
words.pack(pady=5)
picture1=PhotoImage(file="ttt.gif")
searchButton=Button(searchWindow, image=picture1, height=19)
searchButton.config(bg=mycolor)
searchButton.bind("<Button>", compare(words))
searchButton.pack(pady=5)
searchWindow.mainloop()
return
It is all made with Tkinter module. I tried with global variables and arguments with functions, but there was no error. Although there is no error, the program still doesn't work. Can someone help me solve the problem?
So, I solved the problem by making the Entry global and giving the inner function that compares the strings the "event" argument. Here is the correct code:
def search():
def compare(event):
key=str(words.get())
for i in base:
if i==key:
if key=="Apple":
AppleFunction()
elif key=="Pear":
PearFunction()
else:
messagebox.showerror("Error!","Wrong entry, please correct!")
return
searchWindow=Toplevel(main)
searchWindow.geometry("425x125+225+145")
searchWindow.resizable(False,False)
searchWindow.config(bg=mycolor)
searchWindow.title("Tražilica")
searchWindow.iconbitmap(r"f.ico")
text1=Label(searchWindow, text="Search by key words:", wraplength=250, justify="center")
text1.pack(pady=5)
text1.config(bg=mycolor, font="Times")
global words
words=Entry(searchWindow)
words.config(font="Times", width=20)
words.pack(pady=5)
picture1=PhotoImage(file="ttt.gif")
searchButtton=Button(searchWindow, image=picture1, height=19)
searchButtton.config(bg=mycolor)
searchButtton.bind("<Button>", trazi)
searchButttonb.pack(pady=5)
searchWindow.mainloop()
return
Although, when I exit the program, it shows me the error message that I created for a case when the string doesn't match and opens a random new empty Tkinter window which shouldn't be happening because while the program was running it has found by keywords correctly what I was looking for and gave me the correct picture. Also, There was this error on the Console (but not in Shell):
invalid command name ".!toplevel.!button"
while executing
"$w cget -relief"
(procedure "tk::ButtonDown" line 9)
invoked from within
"tk::ButtonDown .!toplevel.!button"
(command bound to event)

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.

Simple, versatile and re-usable entry dialog (sometimes referred to as input dialog) in PyGTK

I am searching for a simple dialog with a text entry widget asking the user for some input. The dialog should be easy to run (like the gtk.MessageDialog variants) and as flexible.
There are of course some examples but they are either not flexible enough or too complicated to construct for my taste.
I hate re-inventing the wheel... or a dialog.
Based on an example I found (thanks Ardoris!), I came up with a dialog subclass... hope it helps someone out there!
#!/usr/bin/env python
import gtk
class EntryDialog(gtk.MessageDialog):
def __init__(self, *args, **kwargs):
'''
Creates a new EntryDialog. Takes all the arguments of the usual
MessageDialog constructor plus one optional named argument
"default_value" to specify the initial contents of the entry.
'''
if 'default_value' in kwargs:
default_value = kwargs['default_value']
del kwargs['default_value']
else:
default_value = ''
super(EntryDialog, self).__init__(*args, **kwargs)
entry = gtk.Entry()
entry.set_text(str(default_value))
entry.connect("activate",
lambda ent, dlg, resp: dlg.response(resp),
self, gtk.RESPONSE_OK)
self.vbox.pack_end(entry, True, True, 0)
self.vbox.show_all()
self.entry = entry
def set_value(self, text):
self.entry.set_text(text)
def run(self):
result = super(EntryDialog, self).run()
if result == gtk.RESPONSE_OK:
text = self.entry.get_text()
else:
text = None
return text
The run() method returns either the text entered in the entry box if the user presses <Enter> or clicks Ok. If Cancel is clicked or <Esc> pressed, the run() method returns None.
Except for that, the dialog should behave as any other gtk.MessageDialog instance.
Maybe that is not very general as it assumes you will always have Ok as an option, but that is what I need in 99% of my use cases anyway.
There isn't one available in GTK+. You've got two options:
Create a dialog, pack the Entry and any other content you need (probably the best way in my opinion)
Retrieve the content_area of the MessageDialog and append an Entry to it.
Something along the lines of:
#!/usr/bin/env python
import gtk
messagedialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK, message_format="Hello")
action_area = messagedialog.get_content_area()
entry = gtk.Entry()
action_area.pack_start(entry)
messagedialog.show_all()
messagedialog.run()
messagedialog.destroy()
Though it does probably need more refinement to get the Entry to display nicely.
Here's the function I wrote, based on the previous answers here. It's a function instead of a class, which means you can use it in one line.
def get_text(parent, message, default=''):
"""
Display a dialog with a text entry.
Returns the text, or None if canceled.
"""
d = gtk.MessageDialog(parent,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_QUESTION,
gtk.BUTTONS_OK_CANCEL,
message)
entry = gtk.Entry()
entry.set_text(default)
entry.show()
d.vbox.pack_end(entry)
entry.connect('activate', lambda _: d.response(gtk.RESPONSE_OK))
d.set_default_response(gtk.RESPONSE_OK)
r = d.run()
text = entry.get_text().decode('utf8')
d.destroy()
if r == gtk.RESPONSE_OK:
return text
else:
return None

Categories