I've scoured the internet on this one and haven't come up with anything, so please excuse me if this is a dumb question, but...
I've written a Tkinter class that takes a .xlsx file as input for one of its processes. You press a button and it uses TKFileDialog.askopenfile() to pop the familiar-looking file input dialog. However, if a user hits cancel, the input is NoneType, the file doesn't open, and the TKinter window terminates with a TypeError.
def GUIDocPullRename(self):
indir = self.e1.get()
Tab = askopenfile()
try:
tBook = xlrd.open_workbook(Tab)
except TypeError:
self.text.insert(END, "Canceled")
#Insert method-ender here
I want to insert something in the exception catch that stops the GUIDocPullRename from continuing, but allows the parent TKinter process to continue running so the user can specify another file without having to re-run the whole program. Is it possible or am I just being a silly newb?
Error is this, when the try/except is excluded:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1470, in __call__
return self.func(*args)
File "P:/Administrative/IT/Scripting/BillsPython/PdfMerger.py", line 102, in GUIDocPullRename
tBook = xlrd.open_workbook(Tab)
File "C:\Python27\lib\site-packages\xlrd\__init__.py", line 394, in open_workbook
f = open(filename, "rb")
TypeError: coercing to Unicode: need string or buffer, NoneType found
Related
I have a user submitted data validation interface for a scientific site in django, and I want the user to be able to submit files of scientific data that will aid them in resolving simple problems with their data before they're allowed to make a formal submission (to reduce workload on the curators who actually load the data into our database).
The validation interface re-uses the loading code, which is good for code re-use. It has a "validate mode" that doesn't change the database. Everything is in an atomic transaction block and it gets rolled back in any case when it runs in validate mode.
I'm in the middle of a refactor to alleviate a problem. The problem is that the user has to submit the files multiple times, each time, getting the next error. So I've been refining the code to be able to "buffer" the exceptions in an array and only really stop if any error makes further processing impossible. So far, it's working great.
Since unexpected errors are expected in this interface (because the data is complex and lab users are continually finding new ways to screw up the data), I am catching and buffering any exception and intend to write custom exception classes for each case as I encounter them.
The problem is that when I'm adding new features and encounter a new error, the tracebacks in the buffered exceptions aren't being fully preserved, which makes it annoying to debug - even when I change the code to raise and immediately catch the exception so I can add it to the buffer with the traceback. For example, in my debugging, I may get an exception from a large block of code, and I can't tell what line it is coming from.
I have worked around this problem by saving the traceback as a string inside the buffered exception object, which just feels wrong. I had to play around in the shell to get it to work. Here is my simple test case to demonstrate what's happening. It's reproducible for me, but apparently not for others who try this toy example - and I don't know why:
import traceback
class teste(Exception):
"""This is an exception class I'm going to raise to represent some unanticipated exception - for which I will want a traceback."""
pass
def buf(exc, args):
"""This represents my method I call to buffer an exception, but for this example, I just return the exception and keep it in main in a variable. The actual method in my code appends to a data member array in the loader object."""
try:
raise exc(*args)
except Exception as e:
# This is a sanity check that prints the trace that I will want to get from the buffered exception object later
print("STACK:")
traceback.print_stack()
# This is my workaround where I save the trace as a string in the exception object
e.past_tb = "".join(traceback.format_stack())
return e
The above example raises the exception inside buf. (My original code supports both raising the exception for the first time and buffering an already raised and caught exception. In both cases, I wasn't getting a saved full traceback, so I'm only providing the one example case (where I raise it inside the buf method).
And here's what I see when I use the above code in the shell. This first call shows my sanity check - the whole stack, which is what I want to be able to access later:
In [5]: es = buf(teste, ["This is a test"])
STACK:
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/manage.py", line 22, in <module>
main()
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/django/core/management/base.py", line 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/django/core/management/commands/shell.py", line 100, in handle
return getattr(self, shell)(options)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/django/core/management/commands/shell.py", line 36, in ipython
start_ipython(argv=[])
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/__init__.py", line 126, in start_ipython
return launch_new_instance(argv=argv, **kwargs)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/traitlets/config/application.py", line 846, in launch_instance
app.start()
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/terminal/ipapp.py", line 356, in start
self.shell.mainloop()
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/terminal/interactiveshell.py", line 566, in mainloop
self.interact()
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/terminal/interactiveshell.py", line 557, in interact
self.run_cell(code, store_history=True)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 2914, in run_cell
result = self._run_cell(
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 2960, in _run_cell
return runner(coro)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/core/async_helpers.py", line 78, in _pseudo_sync_runner
coro.send(None)
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3185, in run_cell_async
has_raised = await self.run_ast_nodes(code_ast.body, cell_name,
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3377, in run_ast_nodes
if (await self.run_code(code, result, async_=asy)):
File "/Users/rleach/PROJECT-local/TRACEBASE/tracebase/.venv/lib/python3.9/site-packages/IPython/core/interactiveshell.py", line 3457, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-5-92f4a0db918d>", line 1, in <module>
es = buf(teste, ["This is a test"])
File "<ipython-input-2-86e515dc1ec1>", line 6, in buf
traceback.print_stack()
But this is what I see when I want to see the original traceback from the es object (i.e. the buffered exception) later. It only has the last item from the traceback. This is exactly what I see in the original source code - a single item for the line of code inside the buffer method:
In [8]: traceback.print_exception(type(es), es, es.__traceback__)
Traceback (most recent call last):
File "<ipython-input-2-86e515dc1ec1>", line 3, in buf
raise exc(*args)
teste: This is a test
My workaround suffices for now, but I'd like to have a proper traceback object.
I debugged the issue by re-cloning our repo in a second directory to make sure I hadn't messed up my sandbox. I guess I should try this on another computer too - my office mac. But can anyone point me in the right direction to debug this issue? What could be the cause for losing the full traceback?
Python has a really weird way of building exception tracebacks. You might expect it to build the traceback when the exception is created, or when it's raised, but that's not how it works.
Python builds a traceback as an exception propagates. Every time the exception propagates up to a new stack frame, a traceback entry for that stack frame is added to the exception's traceback.
This means that an exception's traceback only goes as far as the exception itself propagates. If you catch it (and don't reraise it), the traceback only goes up to the point where it got caught.
Unfortunately, your workaround is about as good as it gets. You're not really losing the full traceback, because a full traceback was never created. If you want full stack info, you need to record it yourself, with something like the traceback.format_stack() function you're currently using.
Cannot seem to figure out the below Tkinter message. Usually doing a quick
search will provide answers but this time I seem to miffed the search engines as to
what might be causing the below error. Curious to know if I am missing a Python package or line 25 below is used in an older version of Python and it has been updated to
a newer command.
I am importing the following packages into the script:
from tkinter import *
from tkinter import filedialog
The function is suppose to save any typed text put into a text area. It does save the file but the file is empty.
Thanks,
Kurt
C:\Users\kurt>python --version
Python 3.10.4
def saveFiles():
filename = filedialog.asksaveasfile(
mode='w',
title="Save a File",
defaultextension=".txt"
)
filename.config(mode='w') ------------> **This is line 25**
pathh.insert(END, filename)
data = str(txtarea.get(1.0, END))
filename.write(data)
filename.close()
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.1264.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 1921, in __call__
return self.func(*args)
File "c:\Users\kurt\Documents\Scripts\TKinter\fileExplorerReadFile.py", line 25, in saveFiles
filename.config(mode='w')
AttributeError: '_io.TextIOWrapper' object has no attribute 'config'
The error is saying that the object returned by the asksaveasfile method doesn't have a config method.
tkinter.filedialog.asksaveasfile(mode='w', **options)ΒΆ
Create a SaveAs dialog and return a file object opened in write-only mode.
When you call the asksaveasfile method, it automatically returns a file object in write mode already so there is no need for any further configuration to write to the file. If you were to omit the line throwing the error, your code should work the way you intended.
I am making a password management system in Tkinter but while deleting an entry I am getting this error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Users/user/opt/anaconda3/lib/python3.8/tkinter/__init__.py", line 1883, in __call__
return self.func(*args)
File "/Users/user/opt/anaconda3/lib/python3.8/site-packages/tkmacosx/basewidget.py", line 1094, in cmd
self.cnf['command']()
File "main.py", line 149, in delete
i.destroy()
File "main.py", line 169, in destroy
self.showButton.destroy()
File "/Users/user/opt/anaconda3/lib/python3.8/site-packages/tkmacosx/variables.py", line 55, in _patch
return fn(self)
File "/Users/user/opt/anaconda3/lib/python3.8/site-packages/tkmacosx/basewidget.py", line 1313, in destroy
main_win = self.winfo_toplevel()
File "/Users/user/opt/anaconda3/lib/python3.8/tkinter/__init__.py", line 1223, in winfo_toplevel
return self._nametowidget(self.tk.call(
_tkinter.TclError: bad window path name ".!button2"
this is a snippet from the code where I am getting an error:
def delete(self):
row = self.deleteButton.grid_info()['row'] # this will get the row you want to delete
ask = messagebox.askquestion("Are You Sure", "are you sure you want to delete this?")
if ask == "yes":
for i in objects: # TODO: cannot delete more than one entry after logging in.
i.destroy()
file = open('app_manager.txt', 'r')
lines = file.readlines()
file.close()
del lines[row - 6] # this will delete the data-entry from 'app_manager.txt'
file = open("app_manager.txt", "w")
for line in lines:
file.write(line)
file.close()
readfile()
NOTE: I can delete one entry but if I try and delete another entry then it shows the error I mentioned above.
If you need full code to inspect then this is the link:
https://github.com/vendz/Account-Storage-System/blob/master/main.py
The problem was with from tkmacosx import Button so instead use from tkinter import Button.
EDIT: problem with tkmacosx is now resolved. do update the package
I am writing a program in python, and part of the program reads lines from a file and prints them. However, while it is printing, if I press a random key I get a KeyboardInterrupt error. This is because I have a try and except case, however, some output shows up that I do not want to show up. This is my code that executes inside the main function:
for line in output.stdout:
line = str(line)
print(line)
This is my code that contains the try and except.
if __name__ == '__main__':
try:
if os.path.exists('drop.json') == True:
drops()
except KeyboardInterrupt:
sys.stderr.close()
except (BrokenPipeError, IOError):
if os.path.exists('drop.txt') == True:
file = open("drop.txt","a+")
file.write('BrokenPipeError | IOError Exception occurred')
file.close()
except Exception as e:
if os.path.exists('drop.txt') == True:
file = open("drops.txt","a+")
file.write(' interrupted: {}'.format(str(e)))
file.close()
While the file is being printed, if I press a random key, it stops the program and outputs this error message which I do not want. The preferred behavior is for the printing to end, the program to stop, and there to be no further output at all. This is the error message that shows up when I press a random key:
Traceback (most recent call last):
File "drop.py", line 100, in <module> drops()
File "drop.py", line 321, in drops print(line)
BrokenPipeError: [Err 56] Broken pipe
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "drop.py", line 756, in <module>file = open ("drop.txt","a+")
File "boot.py", line 68, in decoding
def decoding(do_setlocale=True):
KeyboardInterrupt
Instead of all these error messages showing up, if I press a random key during the printing of lines, I would the printing to end, the program to stop, and no error messages to be displayed. I would really appreciate if anyone could help me out here. Thanks a lot :)
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python32\lib\tkinter\__init__.py", line 1456, in __call__
return self.func(*args)
File "C:\Users\littl_000\Documents\Python\pd\PD GUI.py", line 185, in playmove
grid.after_idle(automove(""))
File "C:\Python32\lib\tkinter\__init__.py", line 534, in after_idle
return self.after('idle', func, *args)
File "C:\Python32\lib\tkinter\__init__.py", line 516, in after
self.tk.call('after', ms)
_tkinter.TclError: wrong # args: should be "after idle script script ..."
The code is just, grid.after_idle(automove(""))
It worked before but it was spaghetti code where I called a function within another function, the automove moves some dots on a grid ( lots of dots very quickly, its a maths problem) and I'm using the after idle so that the tkinter window doesn't crash when I try to move it even when this loop is running, it can take minutes. I have no idea what this error means however, and it doesnt seem to work when i use main.update_idletasks()
after_idle takes a reference to a function. When you do this:
grid.after_idle(automove(""))
... you are immediately calling automove, and the result of that function is what is getting passed to after_idle. The above is exactly the same as:
result = automove("")
grid.after_idle(result)
Most likely automove("") is returning None, which is why after_idle is throwing the error that it is throwing.
If you need to pass arguments, you can include them as additional arguments to after_idle:
grid.after_idle(automove, "")