Can't get my Application running after adding a tkinter interface - python-3.x

Both my application's "motor" in Python 3.7.0 and my tkinter interface work without a hitch by themselves. The problem starts when I put the two together.
The following is a very simplified version of the beginning of my application, but it illustrates the basic problem:
from tkinter import *
request={} # this get more than just one piece of info.
def init():
global request
request['dir'] = text1.get()
# The real interface has:
# 2 Entry Widgets: file extention and keyword.
# 2 Buttons: Select Directory and Organize Files.
# this here is minimal interface
w = Tk()
text1 = StringVar()
Label(text=' Folder ').grid(row=0,column=0)
Entry(textvariable = text1).grid(row=0,column=1) # gets the input
Button(text='Organize', command=init).grid(row=4,column=0)
w.mainloop()
# End of interface.
# ---------- Script starts here ----------------
# here I import several built-in and several personal modules like phps and helpers
# this modules have a whole bunch of functions.
# ----------- VARIABLE ASSIGNMENT ------------- ##
# Here is where I need the interface and the script to connect.
# Path to the directory that will be looped through
BaseDir=request[0]+'/*'
extRequired=request[1] # txt or docs, etc.
# a part of the basename e.g. my new filename keyword = "my new"
Keyword=request[2]
# more vars ....
## ----------- SEARCH DIRECTORY ------------- ##
files=glob.glob(BaseDir)
for file in files:
# EXTRACT file INFO
info=phps.pathinfo(file) # phps is a module I made.
# EXCLUDE Directories
if not os.path.isdir(file):
# SERACH for the Keyword
Keyword_Exist = info['basename'].find(Keyword)
# IS the KEYWORD in the String?
if Keyword_Exist > -1 and info["ext"]==extRequired:
RawfName = info["filename"][3:]
## USE RawfName in the WRITE CONTENT TO FILE Section.
## ----------- GET FILE ------------- ##
lines=open(file).readlines()
# etc ....
If you run the snippet, type a directory's name in the input box, and click on the button, nothing seems to happen, but it does. If you
close the interface, you'll see the user input needed to run the for loop appear on Python's shell, but the loop didn't run.
Any ideas on how I can get this two separate scripts working together?
I basically want to keep the interface open, run the application which starts by looping through files according to the user's input, have it do what it needs to, and then prestent a report to the user on a new window. The user can close this pop-up, and may do another operation without having to restart the application.
Thanks in advance.

I had to reread your question and your comments but I think I understand now what you are trying to do.
If you want to have a pop-up then Toplevel() is what you need. It will open a new window over the main window.
Here we can apply the for loop to add labels to the top level window.
You can do whatever you want here but as long as you do not close the mainloop() then you can have as many pop-ups as you need using Toplevel() without losing any data in the dict.
Let me know if the below helps or if it is something else you actual are trying to do:
from tkinter import *
w = Tk()
request={}
def init():
top = Toplevel(w)
request['dir'] = text1.get()
for key, value in request.items():
Label(top, text=value).pack()
text1 = StringVar()
Label(text=' Folder ').grid(row=0,column=0)
Entry(textvariable = text1).grid(row=0,column=1)
Button(text='Organize', command=init).grid(row=4,column=0)
w.mainloop()

Related

Reload UI, Rather Than Recreating

import sys
import webbrowser
import hou
from PySide2 import QtCore, QtUiTools, QtWidgets, QtGui
# Calling UI File & Some Modification
class someWidget(QtWidgets.QWidget):
def __init__(self):
super(someWidget,self).__init__()
ui_file = 'C:/Users/XY_Ab/Documents/houdini18.5/Folder_CGI/someUI.ui'
self.ui = QtUiTools.QUiLoader().load(ui_file, parentWidget=self)
self.setParent(hou.qt.mainWindow(), QtCore.Qt.Window)
self.setFixedSize(437, 42)
self.setWindowTitle("Requesting For Help")
window_C = someWidget()
window_C.show()
So, I have created this small script that shows the UI, I have connected this to Houdini Menu Bar. Now The Problem is if I click the menu item multiple times it will create another instance of the same UI & the previous one stays back, What I want is something called "If Window Exist Delete It, Crate New One" sort of thing.
Can someone guide me? I am fairly new to python in Houdini and Qt so a little explanation will be hugely helpful. Also, why can't I use from PySide6 import?? Why do I have to use from PySide2?? Because otherwise Houdini is throwing errors.
For the same thing what used to do in maya is
# Check To See If Window Exists
if cmds.window(winID, exists=True):
cmds.deleteUI(winID)
Trying to do the same thing inside Houdini.
I don't have Maya or Houdini, so I can't help you too much.
According to https://www.sidefx.com/docs/houdini/hom/cb/qt.html
It looks like you can access Houdini's main window. The main reason the window is duplicated or deleted is how python retains the reference to window_C. You might be able to retain the reference to just show the same widget over and over again by accessing the main Houdini window.
In the examples below we are using references a different way. You probably do not need your code that has
self.setParent(hou.qt.mainWindow(), QtCore.Qt.Window)
Create the widget once and keep showing the same widget over and over.
import hou
# Create the widget class
class someWidget(QtWidgets.QWidget):
def __init__(self, parent=None, flags=QtCore.Qt.Window): # Note: added parent as an option
super(someWidget,self).__init__(parent, flags)
...
MAIN_WINDOW = hou.ui.mainQtWindow()
try:
MAIN_WINDOW.window_C.show()
except AttributeError:
# Widget has not been created yet!
# Save the widget reference to an object that will always exist and is accessible
# parent shouldn't really matter, because we are saving the reference to an object
# that will exist the life of the application
MAIN_WINDOW.window_C = someWidget(parent=MAIN_WINDOW)
MAIN_WINDOW.window_C.show()
To delete the previous window and create a new window.
import hou
# Create the widget class
class someWidget(QtWidgets.QWidget):
def __init__(self, parent=None, flags=QtCore.Qt.Window): # Note: added parent as an option
super(someWidget,self).__init__(parent, flags)
...
MAIN_WINDOW = hou.ui.mainQtWindow()
# Hide the previous window
try:
MAIN_WINDOW.window_C.close()
MAIN_WINDOW.window_C.deleteLater() # This is needed if you parent the widget
except AttributeError:
pass
# Create the new Widget and override the previous widget's reference
# Python's garbage collection should automatically delete the previous widget.
# You do not need to have a parent!
# If you do have a parent then deleteLater above is needed!
MAIN_WINDOW.window_C = someWidget() # Note: We do not parent this widget!
MAIN_WINDOW.window_C.show()
Another resource shows you can access the previous widget from the page level variable. https://echopraxia.co.uk/blog/pyqt-in-houdinimaya-basic This is possible, but seems odd to me. The module should only be imported once, so the page level variable "my_window" should never exist. However, it sounds like the Houdini plugin system either reloads the python script or re-runs the import. If that is the case every time you show a new window from the import of the script, you are creating a new window. If the previous window is not closed and deleted properly, Houdini could have an ever growing memory issue.
try:
my_window.close()
except (NameError, Exception):
pass # Normal python would always throw a NameError, because my_window is never defined
my_window = MyWindow()
#This is optional you can resize the window if youd like.
my_window.resize(471,577)
my_window.show()
PySide6
https://www.sidefx.com/docs/houdini/hom/cb/qt.html
The bottom of the page shows how to use PyQt5. The same would apply for PySide6. Houdini just happens to come with PySide2.

Running a bot with selenium which likes posts automatically

I'm trying to run a bot which likes every post on the instagram feed automatically.
I got the bot to the point, where it:
--> opens Google Chrome
--> Logs-in and
--> Likes the first post.
However the liking of the first post only works when I code the bot directly in the terminal without classes and creating a bot as an object. Or it works with Solution 2 - see my code snippet - but then after the like the browser closes immediately.
I already tried a lot of things:
--> Make sure that there is enough time between each step
--> Make sure that all the xpath are named the right way
--> Avoid syntax mistakes like "find__elements__by__(...)
But now I ran out of ideas..
Here is my Code:
# Import Selenium and Webdriver to connect and interact with the Browser
from selenium import webdriver
# Import time package and sleep function in order to let the website load when it opens
from time import sleep
# Import username and password
from secrets import username, password
# Create the LikingBot Class
class LikingBot():
def __init__(self):
# Past the Directory where the chromediver is in order to run it
self.driver = webdriver.Chrome('/Users/anwender/Coding/Python_Projects/Automation/Chrome_Webdriver/chromedriver')
# --> Type "python3 -i main.py" in the Terminal and start developing
def login(self):
# 1) Go to Instagram main website
self.driver.get('https://www.instagram.com/')
# 1.1) Give the Website time to load; otherwise the following steps wont work
sleep(2)
# 2) Select the Email Login Box
email_login = self.driver.find_element_by_xpath('//*[#id="react-root"]/section/main/article/div[2]/div[1]/div/form/div[2]/div/label/input')
# 3) Interact with the Email Login Box and type in the Email address or the Username
email_login.send_keys(username)
# 4) Repeat step 2) & 3) with the Password Box
password_login = self.driver.find_element_by_xpath('//*[#id="react-root"]/section/main/article/div[2]/div[1]/div/form/div[3]/div/label/input')
password_login.send_keys(password)
# 5) Click Log In Button
login_btn = self.driver.find_element_by_xpath('//*[#id="react-root"]/section/main/article/div[2]/div[1]/div/form/div[4]/button')
login_btn.click()
sleep(5)
# 6) Click Activate Messages Button if it pops up
activate_btn = self.driver.find_element_by_xpath('/html/body/div[4]/div/div/div[3]/button[1]')
activate_btn.click()
# Writing the automatic liking function
def auto_like(self):
"""
Here are the elements for the automation liking. It seems like every article has the same xpath of the
button. So the goal is to iterate through the articles with a for Loop, while the other attributes stay
the same!
//*[#id="react-root"]/section/main/section/div[2]/div[1]/div/article[1]/div[2]/section[1]/span[1]/button
//*[#id="react-root"]/section/main/section/div[2]/div[1]/div/article[2]/div[2]/section[1]/span[1]/button
//*[#id="react-root"]/section/main/section/div[2]/div[1]/div/article[3]/div[2]/section[1]/span[1]/button
//*[#id="react-root"]/section/main/section/div[2]/div[1]/div/article[..]/div[2]/section[1]/span[1]/button
"""
sleep(2)
# Start iteration
article_iteration = 1
# First Solution
'''
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
like_buttons stores the xpath of the first like button. However it is not working even the xpath is absolutely right.
like_buttons = self.driver.find_element_by_xpath('//*[#id="react-root"]/section/main/section/div[2]/div[1]/div/article['+str(article_iteration)+']/div[2]/section[1]/span[1]/button')
like_buttons.click()
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'''
# Second Solution
'''
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
This like_buttons variable stores the same button element but takes the class name. It is working but after the like the browser closes.
like_buttons = self.driver.find_element_by_class_name('wpO6b ')
like_buttons.click()
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'''
# Write the liking loop
'''
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
while True:
like_buttons.click()
article_iteration += 1
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'''
# Initialize Bot
bot = LikingBot()
bot.login()
bot.auto_like()
Any help is appreciated & hopefully someone can help!

jupyter notebook buffers when writing to file until closed? How to see results without closing jupyter notebook?

I am new to python programming, had taught myself quickbasic back in high school and trying to self teach myself python now using the only tools I have available right now - a chromebook running crouton with a jupyter notebook install on linux (which may be my first set of mistakes, teaching myself and learning using an "interesting" set up, but here I am). Anyhow, I am regularly finding interesting links on the web on my phone and emailing myself them to review later, and I figured I would create a python program to sort the list of URLs and output them to file.
I included the code below, which does work, but the problem I have is with jupyter notebook itself, and I googled a bit to try to find an answer but was unsuccessful so far. Here is the actual issue:
When I write to file in jupyter notebook, it does not show up in local filesystem until I close out the jupyter notebook. This is less than ideal, as I like to use the jupyter notebook for quick testing and bug fixing instead of using idle or bash, so having to close out of jupyter notebook just to see what is output to file is not helpful. Is there a way to flush buffer or something so as to be able to open the text file in a text editor and see the results - without having to quit out of the jupyter notebook?
-if needed, here is the program:
##################################################################
# #
# parse_my_search.py - I save URLs to a text file for later #
# viewing and/or bookmarking. These lists grow rather quickly, #
# so this is a program to sort them by certain subject or #
# websites and make sure that I have no duplicates. #
# #
##################################################################
import os.path
from os import listdir
URL_set = {} # set - used to remove duplicates when sorting/organizing
URL_list = [] # list - used to allow duplicates when sorting/organizing
temp_list = [] # list - temporary usage, discard or reassign to [] when not used
input_file = "" # file to read in, get the URLs, and then close
output_file = 'python.txt'
# file name for output. Will probably change this to a list to write the
# output files to. This should NOT overwrite
# the existing file, but it should open a python file (as in, a text
# file with extention '.txt' which has the URLs that include the word
# 'python' in it), a youtube file (any/all youtube URLs), and an 'else'
# file that is the catch-all for anything that is not in the first two
# files. NOTE: this has not been done yet, only opens single file
input_file = 'My_searches.txt'
while True:
try:
#for elem in os.listdir('.'):
# print(elem)
#print(os.listdir('.'), end=" ")
#print(onlyfiles)
#print("enter filename")
#input_file = input()
read_from = open(input_file)
break
except OSError as err:
print("OS error: {0}".format(err))
ItemsReadInFromFile = read_from.readlines()
for item in ItemsReadInFromFile:
URL_list.append(item.strip('\n'))
# using list comprehension to
# perform removal of empty strings
URL_list = [i for i in URL_list if i]
# removing duplicates:
URL_set = set(URL_list)
URL_list = list(URL_set)
URL_list.sort() # this will change the list/ is destructive. No need to do the following:
# URL_list = URL_list.sort()
# In fact, doing so returns 'None'
# sorting for python
write_to = open(output_file, 'w+')
for item in URL_list:
if 'python' in item.lower():
item += ('\n')
write_to.write(item)
# this is a test that the program works to this point
print("so far so good", input_file)
read_from.close()
I figured out the answer today, and it turns out that it was not jupyter at all but instead was due to after writing the data not closing the file at the end of the program. This is why jupyter did not have the data written to file and showing in a text editor (until jupyter was closed), the file was still open.
Insert facepalm here.
A rookie mistake, and a little embarassing, however I am happy that I figured it out. This can now be closed

closing a tab > go to the previous edited one

When closing a tab in sublimetext3, it always brings me back to the left one, whereas on sublimetext2, I was brought to the previously opened-one(not necessarily the left one).
That behavior was really handy in sublimetext2, because it created a kind of history that was easy to go-back through, just by closing tabs successively.
Is there a setting for that in sublimetext3 ?
Steps to reproduce
I have 3 tabs open, and the 3rd-one is active:
I now go and edit the 2nd-one:
I'm done and decide to close the 2nd-tab:
FAIL: i'm not back to the previously edited one: the 3rd-one
There is no setting to do that. However since it can be done with a plugin, and I like to keep my plugin writing skills up to scratch, I've written it for you.
It's called FocusMostRecentTabCloser and the code is both below and in this GitHub Gist.
To use it save it as FocusMostRecentTabCloser.py somewhere in your Packages directory structure and assign keys to the focus_most_recent_tab_closer command. e.g.
{"keys": ["ctrl+k", "ctrl+w"], "command": "focus_most_recent_tab_closer"},
I have not tested it extensively and it requires Sublime Text 3 build 3024 or later (but that's quite old now).
Reply with a comment if there are any bugs and I'll see what I can do.
# MIT License
import sublime
import sublime_plugin
import time
LAST_FOCUS_TIME_KEY = "focus_most_recent_tab_closer_last_focused_time"
class FocusMostRecentTabCloserCommand(sublime_plugin.TextCommand):
""" Closes the focused view and focuses the next most recent. """
def run(self, edit):
most_recent = []
target_view = None
window = self.view.window()
if not window.views():
return
for view in window.views():
if view.settings().get(LAST_FOCUS_TIME_KEY):
most_recent.append(view)
most_recent.sort(key=lambda x: x.settings().get(LAST_FOCUS_TIME_KEY))
most_recent.reverse()
# Target the most recent but one view - the most recent view
# is the one that is currently focused and about to be closed.
if len(most_recent) > 1:
target_view = most_recent[1]
# Switch focus to the target view, this must be done before
# close() is called or close() will shift focus to the left
# automatically and that buffer will be activated and muck
# up the most recently focused times.
if target_view:
window.focus_view(target_view)
self.view.close()
# If closing a view which requires a save prompt, the close()
# call above will automatically focus the view which requires
# the save prompt. The code below makes sure that the correct
# view gets focused after the save prompt closes.
if target_view and window.active_view().id() != target_view.id():
window.focus_view(target_view)
class FocusMostRecentTabCloserListener(sublime_plugin.EventListener):
def on_activated(self, view):
""" Stores the time the view is focused in the view's settings. """
view.settings().set(LAST_FOCUS_TIME_KEY, time.time())

how structure a python3/tkinter project

I'm developing a small application using tkinter and PAGE 4.7 for design UI.
I had designed my interface and generated python source code. I got two files:
gm_ui_support.py: here declare tk variables
gm_ui.py : here declare widget for UI
I'm wondering how this files are supposed to be use, one of my goals is to be able to change the UI as many times as I need recreating this files, so if I put my code inside any of this files will be overwritten each time.
So, my question is:
Where I have to put my own code? I have to extend gm_ui_support? I have to create a 3th class? I do directly at gm_ui_support?
Due the lack of answer I'm going to explain my solution:
It seems that is not possible to keep both files unmodified, so I edit gm_ui_support.py (declaration of tk variables and events callback). Each time I make a change that implies gm_ui_support.py I copy changes manually.
To minimize changes on gm_ui_support I create a new file called gm_control.py where I keep a status dict with all variables (logical and visual) and have all available actions.
Changes on gm_ui_support.py:
I create a generic function (sync_control) that fills my tk variables using a dict
At initialize time it creates my class and invoke sync_control (to get default values defined in control)
On each callback I get extract parameter from event and invoke logical action on control class (that changes state dict), after call to sync_control to show changes.
Sample:
gm_ui_support.py
def sync_control():
for k in current_gm_control.state:
gv = 'var_'+k
if gv in globals():
#print ('********** found '+gv)
if type(current_gm_control.state[k]) is list:
full="("
for v in current_gm_state.state[k]:
if len(full)>1: full=full+','
full=full+"'"+v+"'"
full=full+")"
eval("%s.set(%s)" % (gv, full))
else:
eval("%s.set('%s')" % (gv, current_gm_state.state[k]))
else:
pass
def set_Tk_var():
global current_gm_state
current_gm_control=gm_control.GM_Control()
global var_username
var_username = StringVar()
...
sync_control()
...
def on_select_project(event):
w = event.widget
index = int(w.curselection()[0])
value = w.get(index)
current_gm_control.select_project(value)
sync_state()
...

Resources