Python Forum
Combine console script + GUI (tkinter)
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Combine console script + GUI (tkinter)
#1
Hello,
I have two python scripts. First is quickstart.py ans second is dater.py. My goal is to run first script and then inside call second script. I tried with sub-process but without success. The main problem is that window from tkinter runs twice. What does it mean? I am setting Start date and End date in calendar, then clicking Apply and at the end clicking X for closing windows. Right after close I am getting another same window which I need to close to go further with script. How to handle that?

import os
import base64
import subprocess

from functions import batch_vat
from dater import *
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

# If modifying these scopes, delete the file token.json.
SCOPES = ["https://www.googleapis.com/auth/gmail.readonly"]


def main():
  """Shows basic usage of the Gmail API.
  Lists the user's Gmail labels.
  """
  creds = None
  # The file token.json stores the user's access and refresh tokens, and is
  # created automatically when the authorization flow completes for the first
  # time.
  if os.path.exists("token.json"):
    creds = Credentials.from_authorized_user_file("token.json", SCOPES)
  # If there are no (valid) credentials available, let the user log in.
  if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
      creds.refresh(Request())
    else:
      flow = InstalledAppFlow.from_client_secrets_file(
          "credentials.json", SCOPES
      )
      creds = flow.run_local_server(port=0)
    # Save the credentials for the next run
    with open("token.json", "w") as token:
      token.write(creds.to_json())

  
  subprocess.run(["python", "dater.py"])

  start_date = start
  end_date = end
  
  #start_date = input("Start date[year/month/day]: ")
  #end_date = input("End date[year/month/day]: ")

  transformed_start_date = start_date.replace("/", "_")
  transformed_end_date = end_date.replace("/", "_")

  # Directory 
  directory = f"{transformed_start_date}-{transformed_end_date}"
  
  # Parent Directory path 
  parent_dir = "C:/Users/Dawid/Desktop/orlen"

  # Path 
  path = os.path.join(parent_dir, directory)
  #print(path)
  os.mkdir(path)
  print("## INFO ## Created directory", directory)
  #source = os. getcwd()
  #shutil.copy(f"{source}/read.py", f"{path}/read.py")
  

  
  try:
    # Call the Gmail API
    service = build("gmail", "v1", credentials=creds)
    results = service.users().messages().list(userId="me", labelIds="Label_1748439073231171664", q=f"after:{start_date} before:{end_date}").execute()
    messages = results.get("messages", [])

    #print(messages)

    #print(json.dumps(messages, indent = 1))

    licznik = 1

    for message in messages:
        message_id = message["id"]
        #print("Message ID = ", message_id)

        msg = service.users().messages().get(userId='me', id=message_id).execute()
        attachment_id = msg["payload"]["parts"][0]["body"]["attachmentId"]
        #print("Attachment ID: ", attachment_id)

        att = service.users().messages().attachments().get(userId='me', messageId=message_id, id=attachment_id).execute()
        attachment_data = att["data"]
        #print(json.dumps(attachment_data, indent = 1))

        file_data = base64.urlsafe_b64decode(attachment_data.encode('UTF-8'))
        
        filename = f"paliwo{licznik}.pdf"
        #print(filename)
        
        #path = os.path.join(store_dir + '\\' 'Downloaded files' + '\\' + filename)

        with open(f"{path}/{filename}", 'wb') as f:
            f.write(file_data)
            f.close()

        licznik = licznik + 1
    
    current_dir = os. getcwd()
    path_for_batch_vat=f"{current_dir}\\{directory}"
    print("## INFO ## Changing context to", path_for_batch_vat)
    os.chdir(path_for_batch_vat)
    print("## INFO ## Running VAT calculations")
    batch_vat(path_for_batch_vat)
        

  except HttpError as error:
    # TODO(developer) - Handle errors from gmail API.
    print(f"An error occurred: {error}")

if __name__ == "__main__":
  main()
from tkinter import *
import ttkbootstrap as tb

def get_dates():
    global start
    global end
    start = start_date.entry.get()
    end = end_date.entry.get()
    print("## INFO ## Start date: ", start)
    print("## INFO ## End date: ", end)
    return start, end
    
root = tb.Window(themename="solar")

root.title("Date picker!")
root.geometry("300x300")

start_date = tb.DateEntry(root, dateformat="%Y/%m/%d", firstweekday=0)
start_date_label = tb.Label(root, text="Start date:")

start_date.grid(column=1, row=0)
start_date_label.grid(column=0, row=0, pady=50, padx=20)


end_date = tb.DateEntry(root, dateformat="%Y/%m/%d", firstweekday=0)
end_date_label = tb.Label(root, text="End date:")

end_date.grid(column=1, row=1)
end_date_label.grid(column=0, row=1, padx=20)


my_button = tb.Button(root, text="Apply", command=get_dates, width=20)
my_button.place(x=80, y=200)


root.mainloop()
Reply
#2
dater.py creates a window when it is imported in your script. A second dater.py is created when you run(["python", "dater.py"]).

I would import dater.py and create an instance from the script instead of running it as a subprocess. Creating the window from your script will make it easier to get the selected dates than trying to get the subprocess to return information.

Either way you need to modify dater to behave like a dialog. Currently dater is a window. There is no way for your dater window to return date information to your script. When the dater window is visible, the window blocks your script from running. That's fine, because you want your script to wait until it has the date information. But when the window is closed, all the date information gets deleted along with the window. By the time your script knows the window is closed, it is too late to ask for the dates.

Writing dialogs is more difficult than a window. You might want to consider folding your script into your window code instead of having a script that calls a dialog.
Reply
#3
This is a low rent way of doing what you want with the dialog.
import ttkbootstrap as ttk

def get_dates(start=None, end=None, format="%Y/%m/%d"):
    """Draw dialog for selecting start and end dates."""
    root = ttk.Window()
    root.title("Enter Dates")

    # If window is destroyed we cannot get the date values.
    # Override what the close button does.
    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
    frame = ttk.Frame(root)
    frame.pack(padx=10, pady=10)

    ttk.Label(frame, text="Start Date").grid(row=0, column=0, pady=(0, 10))
    start = ttk.DateEntry(frame, start_date=start, dateformat=format)
    start.grid(row=0, column=1, pady=(0, 10))

    ttk.Label(frame, text="End Date").grid(row=1, column=0, pady=(0, 10))
    end = ttk.DateEntry(frame, start_date=end, dateformat=format)
    end.grid(row=1, column=1, pady=(0, 10))

    done = ttk.Button(frame, text="Done", command=root.quit)
    done.grid(row=2, column=0, columnspan=2, sticky="news")

    # Wait until the done button or close decoration are pressed.
    root.mainloop()

    # Get dates before destroying the window.
    start = start.entry.get()
    end = end.entry.get()
    root.destroy()
    return start, end

print(get_dates())
The script that used the dialog is just a print() statement, but I think you can see how the dialog would get used in a longer script.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Make console show after script was built with Pyinstaller --NOCONSOLE? H84Gabor 0 1,216 May-05-2022, 12:32 PM
Last Post: H84Gabor
  Encountering `importlib_metadata.PackageNotFoundError` trying to run console script gretchenfrage 0 5,629 Jul-08-2021, 09:26 PM
Last Post: gretchenfrage
  IPython console vs Spyder script losc 3 2,741 Apr-30-2020, 04:57 AM
Last Post: deanhystad
  Problem running script within console koepjo 3 9,915 Mar-26-2020, 07:11 AM
Last Post: koepjo
  Is there any way to convert a python script (with Tkinter module), to a .exe (Windows moste 3 4,014 May-12-2019, 12:02 PM
Last Post: snippsat
  Spyder : Clear IPython Console whenever I re-run the script smallabc 0 5,272 Mar-04-2018, 08:05 AM
Last Post: smallabc
  Dict KeyError in cgi-bin script, works fine via console dbsoundman 2 3,919 Jul-21-2017, 08:03 PM
Last Post: dbsoundman

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020