Expecting string, bytes, or os.PathLike or integer, not StringVar - python

I'm working on a project that monitors two selected folders and automatically moves files created or edited within the last twenty-four hours from Folder_A to Folder_B. It also will check the two folders manually when the user clicks the scan button. So far it will select the two folders, but when I click the scan button I get this error. How would I go about fixing the error?
My code is below the error. Please be understanding that I am still really new to python, so there might be quite a few really stupid mistakes in here.
import tkinter as tk
from tkinter import *
from tkinter import filedialog
import os,time
import datetime
import shutil
import datetime as dt
def browse_button():
# Allow user to select a directory and store it in global var
# called origin_path
global origin_path
filename = filedialog.askdirectory()
origin_path.set(filename)
print(filename)
def browse_button2():
# Allow user to select a directory and store it in global var
# called receiving_path
global receiving_path
filename = filedialog.askdirectory()
receiving_path.set(filename)
print(filename)
def submitFunction() :
for root, dirs,files in os.walk(origin_path.get()):
for fname in files:
path = os.path.join(fname, root)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
shutil.move(path, receiving_path)
print('Submit button is clicked.')
root = Tk()
origin_path = StringVar()
receiving_path = StringVar()
#First Browse Button Label
lbl1 = Label(master=root,textvariable=origin_path)
lbl1.grid(row=0, column=1)
#Second Browse Button Label
lbl1_2 = Label(master=root,textvariable=receiving_path)
lbl1_2.grid(row=1, column=1)
lbl1_3 = Label(master=root)
lbl1_3.grid(row=2, column=1)
button = Button(text="Browse", command=browse_button)
button.grid(row=0, column=3)
button2 = Button(text="Browse", command=browse_button2)
button2.grid(row=1, column=3)
scan_btn=Button(text="Scan", command = lambda:submitFunction())
scan_btn.grid(row=2, column=7)
mainloop()
now = dt.datetime.now()
ago = now-dt.timedelta(hours=24)
strftime = "%H:%M %m/%d/%Y"
created = 'origin_path'
dest = 'receiving_path'
file_path = 'file:///'+os.getcwd()+'/' + ''
print("Last modified: %s" % time.ctime(os.path.getmtime(file_path)))
print("Created: %s" % time.ctime(os.path.getctime(file_path)))
for root, dirs,files in os.walk(origin_path.get()):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
if mtime > ago:
print("True: ", fname, " at ", mtime.strftime("%H:%M %m/%d/%Y"))
shutil.move(path, dest)
def find_info(): #this first func. works fine.for root, dirs, files in os.walk(created):
for root, dirs, files in os,walk(origin_path.get()):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
if mtime > ago:
print(True)
else:
print(False)
print (find_info())
print (move())
print (os.listdir(dest))
print (os.listdir(created))
Here's the error:
C:/Users/quirk/PycharmProjects/Trial_2
C:/Users/quirk/PycharmProjects/Trial_2/.idea
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\Projects\File_transfer.py", line 63, in <lambda>
scan_btn=Button(text="Scan", command = lambda:submitFunction())
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\Projects\File_transfer.py", line 39, in submitFunction
shutil.move(path, receiving_path)
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\lib\shutil.py", line 791, in move
if os.path.isdir(dst):
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\lib\genericpath.py", line 42, in isdir
st = os.stat(s)
TypeError: stat: path should be string, bytes, os.PathLike or integer, not StringVar

As the message says, receiving_path is a StringVar object, not a string. To fetch the string value, you need to use .get():
shutil.move(path, receiving_path.get())

Related

Python: Regex file search with shutil using an excel file

I have a program I am writing for an internal employee that takes a CSV file and searches a file server for the files listed in the CSV then copys each file to a folder in the desktop. The issue I am running into with my current code is that the CSV must hold the exact names but instead I need to regex search this and copy the files with file names like the ones in the CSV.
file name in excel looks like: D6957-QR-1452
file name on server looks like: WM_QRLabels_D6957-QR-1452_11.5x11.5_M.pdf
from tkinter import filedialog, messagebox
import openpyxl
import tkinter as tk
from pathlib import Path
import shutil
import os
desktop = Path.home() / "Desktop/Comps"
tk.messagebox.showinfo("Select a directory","Select a directory" )
folder = filedialog.askdirectory()
root = tk.Tk()
root.title("Title")
lbl = tk.Label(
root, text="Open the excel file that includes files to search for")
lbl.pack()
frame = tk.Frame(root)
frame.pack()
scrollbar = tk.Scrollbar(frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
listbox = tk.Listbox(frame, yscrollcommand=scrollbar.set)
def load_file():
wb_path = filedialog.askopenfilename(filetypes=[('Excel files', '.xlsx')])
wb = openpyxl.load_workbook(wb_path)
global sheet
sheet = wb.active
listbox.pack()
file_names = [cell.value for row in sheet.rows for cell in row]
for file_name in file_names:
listbox.insert('end', file_name)
return file_names # <--- return your list
def search_folder(folder, file_name):
# Create an empty list to store the found file paths
found_files = []
for root, dirs, files in os.walk(folder):
for file in files:
if file in file_name:
found_files.append(os.path.join(root, file))
shutil.copy2(file, desktop)
return found_files
excelBtn = tk.Button(root, text="Open Excel File",
command=None)
excelBtn.pack()
zipBtn = tk.Button(root, text="Copy to Desktop",
command=search_folder(folder, load_file()))
zipBtn.pack()
root.mainloop()
Program is able to find and copy exact file names but unable to file *like* files.
Change your search_folder method to something like this:
def search_folder(folder, file_name):
# Create an empty list to store the found file paths
found_files = []
for root, dirs, files in os.walk(folder):
for file in files:
for file_pattern in file_name:
if file.find(file_pattern) > -1:
replaced_backslashes = re.sub(r"\\+", "/", os.path.join(root, file), 0, re.MULTILINE)
found_files.append(replaced_backslashes)
shutil.copy2(file, desktop)
return found_files
Basically, for every file we iterate over the file_name array to test all the patterns.
For the test we use find method, that in case it matches, returns the position of the found substring.
That is, if searching for 'foo', all these files would be returned:
zazfoo
foobar
zazfoobar
foo

How to make a new .py file

I want to make new file but first choose directory.
This code works but a directory is already set
new_file = input("File name\n")
new_file = new_file.lower().replace(".", "").replace(" ", "_")
print(new_file)
open_file = open('D:\Python projects\%s.py' % new_file, 'w')
Also tried like this but not happen
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
root.withdraw()
file_path = filedialog.askopenfilename()
new_file = input("Name file\n")
open_file = open(f"{file_path}\%s.py" % new_file, 'w')
askdirectory should work. file_path = filedialog.askdirectory

Python expecting expected str, bytes or os.PathLike object, not StringVar

Okay, so I'm working on a project that monitors two selected folders and automatically moves files created or edited within the last twenty-four hours from Folder_A to Folder_B. It also will check the two folders manually when the user clicks the scan button. So far it will select the two folders, but when I click the scan button I get this error. How would I go about fixing the error? My code is below the error. Please be understanding that I am still really new to python, so there might be quite a few really stupid mistakes in here.
File
"C:\Users\--\AppData\Local\Programs\Python\Python310\Projects\File_transfer.py", line 63, in <module>
scan_btn=Button(text="Scan", command = submitFunction())
File "C:\Users\--\AppData\Local\Programs\Python\Python310\Projects\File_transfer.py", line 34, in submitFunction
for root, dirs,files in os.walk(origin_path):
File "C:\Users\quirk\AppData\Local\Programs\Python\Python310\lib\os.py", line 342, in walk
return _walk(fspath(top), topdown, onerror, followlinks)
TypeError: expected str, bytes or os.PathLike object, not StringVar
My code for the project:
import tkinter
import tkinter as tk
from tkinter import *
from tkinter import filedialog
import os,time
import datetime
import shutil
import datetime as dt
def browse_button():
# Allow user to select a directory and store it in global var
# called origin_path
global origin_path
filename = filedialog.askdirectory()
origin_path.set(filename)
print(filename)
def browse_button2():
# Allow user to select a directory and store it in global var
# called receiving_path
global receiving_path
filename = filedialog.askdirectory()
receiving_path.set(filename)
print(filename)
def submitFunction() :
for root, dirs,files in os.walk(origin_path):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
shutil.move(path, dest)
print('Submit button is clicked.')
root = Tk()
origin_path = StringVar()
receiving_path = StringVar()
#First Browse Button Label
lbl1 = Label(master=root,textvariable=origin_path)
lbl1.grid(row=0, column=1)
#Second Browse Button Label
lbl1_2 = Label(master=root,textvariable=receiving_path)
lbl1_2.grid(row=1, column=1)
lbl1_3 = Label(master=root)
lbl1_3.grid(row=2, column=1)
button = Button(text="Browse", command=browse_button)
button.grid(row=0, column=3)
button2 = Button(text="Browse", command=browse_button2)
button2.grid(row=1, column=3)
scan_btn=Button(text="Scan", command = lambda:submitFunction())
scan_btn.grid(row=2, column=7)
mainloop()
now = dt.datetime.now()
ago = now-dt.timedelta(hours=24)
strftime = "%H:%M %m/%d/%Y"
created = 'origin_path'
dest = 'receiving_path'
file_path = 'file:///'+os.getcwd()+'/' + ''
print("Last modified: %s" % time.ctime(os.path.getmtime(file_path)))
print("Created: %s" % time.ctime(os.path.getctime(file_path)))
for root, dirs,files in os.walk(origin_path):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
if mtime > ago:
print("True: ", fname, " at ", mtime.strftime("%H:%M %m/%d/%Y"))
shutil.move(path, dest)
def find_info(): #this first func. works fine.for root, dirs, files in os.walk(created):
for root, dirs, files in os,walk(origin_path):
for fname in files:
path = os.path.join(root, fname)
st = os.stat(path)
mtime = dt.datetime.fromtimestamp(st.st_mtime)
if mtime > ago:
print(True)
else:
print(False)
print (find_info())
print (move())
print (os.listdir(dest))
print (os.listdir(created))
The problem is that you are calling os.walk with a tkinter StringVar, but os.walk does not accept StringVars; it only accepts objects of type str, bytes, or os.PathLike (e.g. pathlib Path objects).
You can fix the error by using os.walk(origin_path.get()) instead of os.walk(origin_path). This gets the string from the StringVar and passes that to os.walk, instead of passing the StringVar to os.walk directly.

How to call multiple buttons together in Tkinter

I'm trying to create a window with 3 buttons. When a user clicks on one of the buttons, the assigned function is called. Here is my code, I tried everything from what I read in the documentation, but I can't seem to get over it!
I also added the functions called by the program, they work perfectly, just adding them for reference. Also, the buttons() function is called only one time and it's a simple call without argument.
def buttons():
root.geometry('1000x1000')
btncreation = tkinter.Button(root, text='Order by Creation',
command=creation)
btncreation.pack()
btnmodified = tkinter.Button(root, text='Order by Last Modified',
command=lastmodified)
btnmodified.pack()
btnaccessed = tkinter.Button(root, text='Order by Last Accessed',
command=lastaccessed)
btnaccessed.pack()
def creation():
lst.sort(key=os.path.getctime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
def lastmodified():
lst.sort(key=os.path.getmtime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
Functions called by buttons:
def lastaccessed():
lst.sort(key=os.path.getatime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
Also, please, please, refrain from formatting answers on my question. I just want some honest to god help and not 5 comments on how to "better format my question". If you need more info, I'll be glad to give it. But I'm not answering salty comments on the formatting :)
import os
import tkinter.filedialog
import pathlib
from os import rename
from tkinter import simpledialog
import getpass
import tkinter as tk
root = tkinter.Tk()
# File types list
ftypes = [
('Python code files', '*.py'),
('Perl code files', '*.pl;*.pm'),
('Java code files', '*.java'),
('C++ code files', '*.cpp;*.h'),
('Text files on mac', '*.rtf'),
('Text files', '*.txt'),
("PDF files", "*.pdf"),
('All files', '*'),
]
# The function renames and relocates selected files depending on the sorting selected
def creation():
lst.sort(key=os.path.getctime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
def lastmodified():
lst.sort(key=os.path.getmtime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
def lastaccessed():
lst.sort(key=os.path.getatime)
num = 1
for line in lst:
dst = newpath + name + str(num) + suffix
rename(line, dst)
num += 1
def hide(root):
root.withdraw()
def show(root):
root.update()
root.deiconify()
def buttons():
root.geometry('1000x1000')
btncreation = tkinter.Button(root, text='Order by Creation',
command=creation)
btncreation.pack()
btnmodified = tkinter.Button(root, text='Order by Last Modified',
command=lastmodified)
btnmodified.pack()
btnaccessed = tkinter.Button(root, text='Order by Last Accessed',
command=lastaccessed)
btnaccessed.pack()
hide(root)
# Window to select files to order
filez = tkinter.filedialog.askopenfilenames(title='Select files to rename (must be all of the same type!)')
# List populated with file names
lst = list(filez)
# Saves the extension of the selected files
suffix = pathlib.Path(lst[0]).suffix
# Window to get user input on file naming
# Asks user for file names, while loop won't break if no name is given
USER_INP = simpledialog.askstring(title="File Names",
prompt="Name your files:")
while USER_INP == '':
USER_INP = simpledialog.askstring(title="File Names",
prompt="Name your files:")
# Gets username for path use
username = getpass.getuser()
name = USER_INP
# Asks user for folder name, while loop won't break if no name is given
USER_INP2 = simpledialog.askstring(title="Folder Name",
prompt="Name your folder:")
while USER_INP2 == '':
USER_INP2 = simpledialog.askstring(title="Folder Name",
prompt="Name your folder:")
foldername = USER_INP2
# Creates new folder for ordered files, if folder exists, it uses it
newpath = r'/Users/' + username + '/Desktop/' + foldername + '/'
if not os.path.exists(newpath):
os.makedirs(newpath)
buttons()
root.mainloop()
You can start by using hide(root) but before or after calling buttons() say, show(root), so:
# Rest of your code
hide(root)
# Rest of your code
show(root)
buttons()

Receiving error (NoneType 'to_csv') while attempting to implement script into a GUI

I'm trying to build a small program that combines csv files. I've made a GUI where a user selects directories of the location of the csv files and where they want the final combined csv file to be outputted. I'm using this script to merge csv files at the moment.
from pathlib import Path
import pandas as pd
def add_dataset(old, new, **kwargs):
if old is None:
return new
else:
return pd.merge(old, new, **kwargs)
combined_csv = None
for csv in Path(r'C:\Users\Personal\Python\Combine').glob('*.csv'):
dataset = pd.read_csv(csv, index_col=0, parse_dates=[0])
combined_csv = add_dataset(combined_csv, dataset, on='DateTime', how='outer')
combined_csv.to_csv(r'C:\Users\Personal\Python\Combine\combined.csv')
The script that I've built for the GUI is this:
from tkinter import *
from tkinter import filedialog
from pathlib import Path
import pandas as pd
import os
root = Tk()
root.geometry("400x200")
# Setting up the 'Browse Directory' dialogs
def selectDirectory():
global dirname
global folder_path
dirname = filedialog.askdirectory(parent=root,initialdir="/",title='Please select a directory')
folder_path.set(dirname)
print(dirname)
def selectOutputDirectory():
global dirname_combine
global folder_pathcombine
dirname_combine = filedialog.askdirectory(parent=root,initialdir="/",title='Please select a directory')
folder_pathcombine.set(dirname_combine)
print(dirname_combine)
# Printing the locations out as a label
folder_path = StringVar()
lbl1 = Label(master=root, textvariable = folder_path)
lbl1.grid(row=0,column=2)
folder_pathcombine = StringVar()
lbl2 = Label(master=root, textvariable = folder_pathcombine)
lbl2.grid(row=1,column=2)
def add_dataset(old, new, **kwargs):
if old is None:
return new
else:
return pd.merge(old, new, **kwargs)
def runscript():
combined_csv = None
path = r'%s' % folder_path
combine = r'%s' % folder_pathcombine
for csv in Path(r'%s' % path).glob('*.csv'):
dataset = pd.read_csv(csv, index_col = 0, parse_dates=[0], delimiter = ',')
combined_csv = add_dataset(combined_csv, dataset, on='DateTime', how='inner')
combined_csv.to_csv(r'%s\combined.csv' % combine)
# Assigning commands to buttons to select folders
selectFolder = Button(root, text = "Select directory", command = selectDirectory)
selectFolder.grid(row=0,column=0)
selectcombine = Button(root, text = "Select output directory", command = selectOutputDirectory)
selectcombine.grid(row=1, column=0)
run = Button(root, text = "Run script", command = runscript)
run.grid(row=3, column=0)
root.mainloop()
The problem I'm having is correctly implementing the script for the merging in the GUI script. The merge script works fine by itself but when I implemented it into the GUI script I get the error "AttributeError: 'NoneType' object has no attribute 'to_csv'". I think my function is setup in correctly in the GUI so I was reading the following documentation. https://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/functions.html
I read that the "None" error occurs when there is no value being returned. So in this case I think it's not writing the variable "Combined" to a csv because nothing exists it in.
The complete error message is this:
runfile('C:/Users/Personal/Python//test.py', wdir='C:/Users/Personal/Python/Combine')
C:/Users/Personal/Python/Combine
C:/Users/Personal/Python/Combine
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\tkinter\__init__.py", line 1702, in __call__
return self.func(*args)
File "C:/Users/Personal/Python/Combine/gui.py", line 54, in runscript
combined_csv.to_csv(r'%s\combined.csv' % combine)
AttributeError: 'NoneType' object has no attribute 'to_csv'
Any help fixing the error would be greatly appreciated, as well as any advice on how to improve my code. I'm relatively new to Python and looking to improve. Thanks!
The problem is that you are using StringVar in the following statements inside runscript():
path = r'%s' % folder_path
combine = r'%s' % folder_pathcombine
Therefore no file will be found in the for loop below the above statements and combine_csv is not updated.
You should use .get() on the StringVar as below:
path = r'%s' % folder_path.get()
combine = r'%s' % folder_pathcombine.get()

Categories

Resources