Posts: 17
Threads: 8
Joined: Mar 2024
Jul-11-2024, 03:26 PM
(This post was last modified: Jul-11-2024, 03:26 PM by CAD79.)
For an application I'm creating, a combobox displays all customer names that are inside the active customer orders directory. In the customer order, there is mechanical, electrical etc and sales, which has the order acknowledgement. All customer sales order acknowledgment files have OA at the end of the file, but the start of the name may differ from the customer directory name. For example:
Customer directory name: 937298 Sea World
OA file: 937298 SeaWorld OA.pdf
As you can see, there is no space, which is different (sometimes the naming can be very different, this is just a minor example). Implementing a naming convention would be an option, but would require people to actually listen, and it would be better in the long run to be able to just find and print the order acknowledgement by using the OA at the end of the file. Is there a way I can do this? I was originally using the .get() function which would just use the customer name from the directory, but this is inconsistent due to inconsistent naming. How can I find the file I want by just using OA.pdf at the end of the file? Thank you. Here is my code:
import os
import tkinter as tk
from tkinter import ttk
class JobFileAutomation:
def __init__(self):
customer_path = os.listdir('Y:/orders/C-Active Orders/')
self.root = tk.Tk()
self.root.geometry('400x100')
self.root.title('Job File Creator')
self.root.iconbitmap('E:/jobFile.ico')
self.mainframe = tk.Frame(self.root, background='white')
self.mainframe.pack(fill='both', expand=True)
self.customer_label = ttk.Label(self.mainframe, text='Select customer: ', background='white')
self.customer_label.grid(row=0, column=0, padx=70)
self.customer_selection = ttk.Combobox(self.mainframe, values=customer_path, width=40)
self.customer_selection.grid(row=1, column=0, padx=10, pady=10)
create_button = ttk.Button(self.mainframe, text='Create', command=self.create_job_file)
create_button.grid(row=1, column=3)
self.root.mainloop()
return
def create_job_file(self):
customer_name = self.customer_selection.get()
# name of file path
oa_file = f"Y:/orders/C-Active Orders/{customer_name}/1-Sales/{customer_name} OA.pdf"
os.startfile(oa_file, "print")
print(customer_name)
if __name__ == '__main__':
JobFileAutomation() Edit: never mind, I got it. Being a C++/Arduino programmer has hard wired my brain into thinking these problems will be difficult to solve
Posts: 6,798
Threads: 20
Joined: Feb 2020
Jul-11-2024, 04:22 PM
(This post was last modified: Jul-11-2024, 08:33 PM by deanhystad.)
Looks like a job for glob.
This program finds all files in the current directory that have a filename that ends with "e"
from pathlib import Path
print(*Path(".").glob("*e.*")) Output: console.py employee.csv enhancedsprite.py image.png interactiveconsole.py mtsbinfile.py paddle.png table.json
If you want to only select png files the pattern for glob would be "*.png".
from pathlib import Path
print(*Path(".").glob("*e.png")) Output: image.png paddle.png
Maybe some of my files are uppper case and I want to get those too.
from pathlib import Path
print(*Path(".").glob("*[eE].[pP][nN][gG]")) Output: image.png paddle.png WALLE.PNG
You should take a look at pathlib. I find it superior to os for doing anything related to directories and files. Info about pathlib and glob.
https://docs.python.org/3/library/pathlib.html.
If there are no OA files it doesn't make sense to create a window for selecting OA files and creating job files. The code below scans for OA files before making the GUI. If OA files are found, it creates controls for selecting files and creating job files. If no OA files are found it displays an informative message.
import tkinter as tk
from tkinter import ttk
from pathlib import Path
class JobFileAutomation(tk.Tk):
"""A GUI for creating job files."""
def __init__(self, order_dir: str = "Y:/orders/C-Active Orders"):
super().__init__()
self.title("Job File")
icon_file = Path(__file__) / "jobFile.ico" # Look for icon in same folder as source file.
if icon_file.exists():
self.iconbitmap(icon_file)
frame = tk.Frame(self, background="white")
frame.pack(fill="both", expand=True)
# Scan customer folders for OA files. Add OA files to dictionary.
self.oa_files = {}
for customer in Path(order_dir).iterdir():
if customer.is_dir():
oa_files = list(customer.glob(f"1-Sales/*{customer.name}*OA.pdf"))
if len(oa_files) > 0:
self.oa_files[customer.name] = oa_files[0]
if self.oa_files:
# Create combobox for selecting customer oa file.
ttk.Label(frame, text="Customer", background=frame["bg"]).grid(row=0, column=0, padx=(10, 2), pady=10)
customer_names = list(self.oa_files)
self.customer = tk.StringVar(frame, customer_names[0])
ttk.Combobox(frame, textvariable=self.customer, values=customer_names).grid(
row=0, column=1, padx=(0, 10), pady=10
)
# Press button to create job file from OA file.
ttk.Button(frame, text="Create Job File", command=self.create_job_file).grid(
row=1, column=0, columnspan=2, padx=10, pady=(0, 10), sticky="ew"
)
else:
tk.Label(frame, text="Did not find any customer OA files.", bg=frame["bg"]).grid(
row=0, column=0, padx=70, pady=50
)
def create_job_file(self):
"""For now, just print path to stdout."""
print(self.oa_files[self.customer.get()].absolute())
if __name__ == "__main__":
JobFileAutomation().mainloop() I changed JobFileAutomation to be tk window instead of a tk window factory. Python classes support inheritance, may as well take advantage of it.
Notice the class has only 2 instance variables; the StringVar used to get the customer selection, and the dictionary mapping customer names to OA files. These are the only things used outside the __init__(). Don't create instance variables for things you only use once.
Posts: 1,094
Threads: 143
Joined: Jul 2017
Jul-11-2024, 06:15 PM
(This post was last modified: Jul-11-2024, 06:54 PM by Pedroski55.)
Not sure I understand the question correctly:
Quote:How can I find the file I want by just using OA.pdf at the end of the file?
How do we know exactly which file you are looking for?
import re
fn = 'C:\\937298 Sea World\937298 SeaWorld OA.pdf'
g = re.compile(r'[\S\s]*OA\.pdf')
res = g.search(fn) Gives:
Output: res.group()
'C:\\937298 Sea World\937298 SeaWorld OA.pdf'
And why must Windoze have a backslash?
Posts: 6,798
Threads: 20
Joined: Feb 2020
Because CP/M used a forward a slash?
I think it is because DOS utilities used "/" where UNIX would use "-" in the command line. When folders were added to DOS, and it suddenly needed a file delimiter, "/" was already taken, so "\" was used. I don't think escape sequences in strings were ever considered. Who needs "\n" when print automatically does a carriage return/linefeed. Nobody was ever going to run C on a microcomputer.
Pedroski55 likes this post
Posts: 17
Threads: 8
Joined: Mar 2024
Jul-12-2024, 09:28 AM
(This post was last modified: Jul-12-2024, 09:28 AM by CAD79.)
(Jul-11-2024, 04:22 PM)deanhystad Wrote: Looks like a job for glob.
This program finds all files in the current directory that have a filename that ends with "e"
from pathlib import Path
print(*Path(".").glob("*e.*")) Output: console.py employee.csv enhancedsprite.py image.png interactiveconsole.py mtsbinfile.py paddle.png table.json
If you want to only select png files the pattern for glob would be "*.png".
from pathlib import Path
print(*Path(".").glob("*e.png")) Output: image.png paddle.png
Maybe some of my files are uppper case and I want to get those too.
from pathlib import Path
print(*Path(".").glob("*[eE].[pP][nN][gG]")) Output: image.png paddle.png WALLE.PNG
You should take a look at pathlib. I find it superior to os for doing anything related to directories and files. Info about pathlib and glob.
https://docs.python.org/3/library/pathlib.html.
If there are no OA files it doesn't make sense to create a window for selecting OA files and creating job files. The code below scans for OA files before making the GUI. If OA files are found, it creates controls for selecting files and creating job files. If no OA files are found it displays an informative message.
import tkinter as tk
from tkinter import ttk
from pathlib import Path
class JobFileAutomation(tk.Tk):
"""A GUI for creating job files."""
def __init__(self, order_dir: str = "Y:/orders/C-Active Orders"):
super().__init__()
self.title("Job File")
icon_file = Path(__file__) / "jobFile.ico" # Look for icon in same folder as source file.
if icon_file.exists():
self.iconbitmap(icon_file)
frame = tk.Frame(self, background="white")
frame.pack(fill="both", expand=True)
# Scan customer folders for OA files. Add OA files to dictionary.
self.oa_files = {}
for customer in Path(order_dir).iterdir():
if customer.is_dir():
oa_files = list(customer.glob(f"1-Sales/*{customer.name}*OA.pdf"))
if len(oa_files) > 0:
self.oa_files[customer.name] = oa_files[0]
if self.oa_files:
# Create combobox for selecting customer oa file.
ttk.Label(frame, text="Customer", background=frame["bg"]).grid(row=0, column=0, padx=(10, 2), pady=10)
customer_names = list(self.oa_files)
self.customer = tk.StringVar(frame, customer_names[0])
ttk.Combobox(frame, textvariable=self.customer, values=customer_names).grid(
row=0, column=1, padx=(0, 10), pady=10
)
# Press button to create job file from OA file.
ttk.Button(frame, text="Create Job File", command=self.create_job_file).grid(
row=1, column=0, columnspan=2, padx=10, pady=(0, 10), sticky="ew"
)
else:
tk.Label(frame, text="Did not find any customer OA files.", bg=frame["bg"]).grid(
row=0, column=0, padx=70, pady=50
)
def create_job_file(self):
"""For now, just print path to stdout."""
print(self.oa_files[self.customer.get()].absolute())
if __name__ == "__main__":
JobFileAutomation().mainloop() I changed JobFileAutomation to be tk window instead of a tk window factory. Python classes support inheritance, may as well take advantage of it.
Notice the class has only 2 instance variables; the StringVar used to get the customer selection, and the dictionary mapping customer names to OA files. These are the only things used outside the __init__(). Don't create instance variables for things you only use once.
Thank you, your input was very useful! I'm trying to wrap my head around that code first then I'm going to implement it into the real code. It definitely looks better, and the GUI is a little cleaner, I just need to make the combo box a little wider to fit in all the customer names as some of them are pretty long!
Also, there are always OA files on the record; there are about 35 orders currently active, which all have OA files. If the window didn't open up from not having found any OA files, we'd go out of business, haha
Posts: 6,798
Threads: 20
Joined: Feb 2020
Jul-12-2024, 02:09 PM
(This post was last modified: Jul-12-2024, 02:09 PM by deanhystad.)
Get the max length of the strings in values and use that as the width. If customer_names is the list of values for the combobox, either of these will return the length of the longest name.
length = len(max(customer_names, key=len))
length = max(len(customer) for customer in customer_names) Also, there are always OA files on the record; there are about 35 orders currently active, which all have OA files. If the window didn't open up from not having found any OA files, we'd go out of business, haha It is poor practice to make assumptions about things that will "always be" or "never be". I have a shelf of notebooks that I've filled over the years cataloging bugs in software I've written. I bet half the notes are about something my customer swore could "never happen", but yet it happened
|