I need to discard the change user made when an exception occurred, to go back to the value when input is valid.
For example I have 2 field check_in & check_out as Date type. I need to check the check_in must be smaller than check_out. When the check_in is bigger than check_out, an exception dialog shows. When the user closes the exception dialog, I need to discard the change for check_in.
#api.onchange('check_in', 'check_out')
def validate_check_in(self):
for rec in self:
if rec.check_in > rec.check_out:
raise ValidationError("Not valid check in and check out")
I don't know the method of discarding the changes. However, I do have a workaround in case you haven't got one.
By using _origin, you can get the original values before the onchange is triggered. So, when the exception is going to occur, you can just set the value(s) back to its original state, which is almost similar to discard.
The code should be something like this.
#api.onchange('check_in', 'check_out')
def validate_check_in(self):
for rec in self:
if rec.check_in > rec.check_out:
rec.check_in = rec._origin.check_in # Added for the workaround
raise ValidationError("Not valid check in and check out")
If you don't like this solution, please wait a bit longer in case there's someone who knows how to discard because I also want to know that.
Related
I'm new to python, and i want to make a simple bank account class, where i want to make a withdraw method, that checks if founds are sufficient and then raises an exception if not.
def withdraw(self, amount):
self.amount -= amount
if amount < self.amount:
raise Exception("Insufficent founds")
print(f"{amount} was withdrawn new balance is {self.amount}")
this is what i have so far, and the logic is working, but i think it would be better with a
try:
# method logic
except Exception:
#handle exception and continue program
my issue is that i can't trigger the exception upon a statement like:
if amount < self.amount:
what do you do in python, when you want to throw an exception upon a certain event, and then continue the program?
The purpose of an exception is for a function to indicate to its caller that it was unable to do whatever thing it is intended to do.
So if you have a function called withdraw, and its purpose is to withdraw funds, if for any reason it cannot withdraw funds, it is appropriate for that function to raise an exception.
If the function identifies a situation where it might be able to withdraw funds, and it performs some extra steps (like prompting the user) and then succeeds, there is no need for any exception. The function still did what it was intended to do. Having the withdraw function take on an extra responsibility of asking for approval seems like a poor design to me, though.
One way to help understand what exceptions you need to raise is to work top down instead of bottom up. That is, start by writing the highest level of what you want your program to do, and then work your way down to the specific details.
If your goal is to simulate an ATM machine, for example, you might start with a top-level function like this:
def main():
while running:
account = select_account()
operation = select_operation()
if operation == 'withdraw':
amount = select_amount()
try:
account.withdraw(amount)
except InsufficientFundsError:
print('Your account has insufficient funds.')
elif operation == 'deposit':
amount = select_amount()
account.deposit(amount)
elif operation == 'done':
running = False
If you start with this "client" code that will use your class, it makes the design for the "service" code (your Account class) much easier. Now you know how you want to be able to use your object, so it's just a matter of writing an object that can be used that way.
When you write a call to a function like account.withdraw(amount), you need to think: How could this fail? What do I want to do if it fails? For example, if the failure reason is that there are insufficient funds, you want to print a message, but you probably don't want to abort the program. But if when you call select_account() the account doesn't exist, then maybe it's OK to fail in a different way. If you fail to handle a possible exception, then the default thing that happens is that your program crashes. That's a good thing: it means that you've found some code that you forgot to write, and if that happens, it's much better for your program to stop running completely than to continue on doing the wrong thing.
A try/except only gets specific errors in python and prevents crashes so the program can keep running (or not if you break). If you don't specify a python's exception it will treat any exception it occurs.
try:
# something
except:
pass #(do nothing)
However if you wan't to treat only specific errors, meaning to catch/ignore only it but others will have other treatments (or even crash on screen) you specify:
div = 0
try:
print(10/div)
except ZeroDivisionError:
print("div can't be zero, change variable")
return # this exits the function
#break # if it is inside a loop
Basically, when you treat an exception the program doesn't stop, it just act like a "known bug" so doesn't crash.
what you could do is exit the function inside your if, but you'd have to do that check before the operation:
def withdraw(self, amount):
if amount < self.amount:
print("Insufficent funds")
return
self.amount -= amount
print(f"{amount} was withdrawn new balance is {self.amount}")
An edit: a better approach would be instead of printing the "insuficient funds" to either write into a log file or returning an output to the program calling this class/function.
i'm in a situation where i take the user input and do some math operations.. The user selects an item from a combobox, and inputs a number in the line edit next to it. When he clicks ok, it returns (comboboxselectedvalue)+(lineeditvalue), it works, most of the time, my problem is, when the user leaves the lineedit in blank, it returns an error:
ValueError: invalid literal for int() with base 10: ''
cb1 = self.lineEdit.text()
zb1=self.comboBox.currentText()
az1 = int(cb1)
print(zb1+az1)
How can i set the value of line edits to 0 when nothing is typed in and left in blank? I have 20 line edits and 20 combo boxes..
Your code is going to raise an exception whenever the user enters anything that's not a number—including nothing at all.
The nicest way to handle this is by validating the entry (and pre-filling it with something valid, like 0), so they can't click OK with something invalid in the box.
But if you want to handle this in the "engine" code instead of in the GUI, you can; it just won't be as nice a user experience.
It sounds like what you want to do is treat an empty box as 0. What about a non-empty but non-numeric entry? Should that also be treated as 0? If so, this is easy; the exception already catches exactly what you want to catch, so you just need to handle it.
try:
az1 = int(cb1)
except ValueError:
az1 = 0
If, on the other hand, you want to treat non-numeric entries different from empty, it's a bit more complicated; the exception lumps them both in together, so you'd need an if test either instead of or in addition to the exception. If, say, you wanted non-numeric text to abort the program as it currently does, but an empty box to mean 0, you could write:
try:
az1 = int(cb1)
except ValueError:
if not az1:
az1 = 0
else:
raise
Or, more briefly:
az1 = int(cb1) if cb1 else 0
in a class I have method called "place(dictionary)" that check every object in dictionary and add it in a class variable if no exception were raised.
Based on a boolean variable called ignore_invalid I want to choose to continuing the loop with the next object in the dictionary simply avoiding to add the one that had raised an exception OR blocking the loop re-raising the exception.
The code is something like this:
class MyOwnException1()
[...]
class MyOwnException2()
[...]
[..my class definition..]
def place(self, elements, ignore_invalid=False):
for coordinates in elements:
try:
if method_checker1(coordinates):
raise MyOwnException1("...")
elif method_checker2(coordinates):
raise MyOwnException2("...")
else:
print "Current coordinates are valid. Adding them."
# adding the current coordinates
[..]
except (MyOwnException1, MyOwnException2) as my_exception:
print my_exception
if not ignore_invalid:
print "Stop the loop"
raise
else:
print "Continue the loop with next coordinates"
continue
This code is giving me error on the raise lines: seems I can't use the "raise" and "continue" in the same "except".
What is the best way to do that?
EDIT: my IDE had a bug in the output console; after an exception, also if ignore_invalid was true, it stopped to reproduce output.
Here a stupid and semplified example of what I did (that run correctly)
http://pastebin.com/FU2PVkhb
When you raise your exception in except block, then it will stop the loop. When you set ignore_invalid=True, then the loop will continue running.
That's what I understand based on what you asked. Anyway,you need to give your error traceback here.
While I can't reproduce the error you're getting, you can avoid this and make it much more readable if you avoid throwing the exceptions in the first place:
def place(self, elements, ignore_invalid=False):
for coordinates in elements:
if not ignore_invalid:
if method_checker1(coordinates):
raise MyOwnException1("...")
elif method_checker2(coordinates):
raise MyOwnException2("...")
print "Current coordinates are valid. Adding them."
# adding the current coordinates
#...
Of course, this is only functionally equivalent if your method_checkers are pure
Currently using the wxPython framework and my code looks like this:
Event bind:
self.frequency_grid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.on_cell_changed)
Function that handles changed cells:
def on_cell_changed(self, event):
self.current_grid = event.GetEventObject()
try:
new_value= self.get_cell_value()
if new_value < 0:
raise AttributeError
#allow the cell to update
except AttributeError:
event.Veto()
wx.MessageBox(_("Positive values only."), "", wx.OK|wx.ICON_WARNING)
except:
wx.MessageBox(_("Invalid value for cell."), "", wx.OK|wx.ICON_WARNING)
event.Veto()
The function get_cell_value() reads the value from the current cell and converts it to an integer simply by using int(). If the user enters a character like 'a' into the cell, obviously this function fails and the exception is raised. In this case the messagebox comes out telling the user the cell has an invalid value. This is what I call the automatically caused exception, and the final exception block is executed.
In the case of negative values, I manually raise an AttributeError (just wanted to see something different from ValueError which is what happens when user inputs characters).
In this case however, the wxPython sends the EVT_GRID_CELL_CHANGE event twice, so there must be something different about manually raised exceptions.
I've separately raised a ticket about the duplicated events at http://trac.wxwidgets.org/ticket/16333 but just trying to understand how the first scenario doesn't make wxPython send 2 events compared to the second scenario.
Don't use except: if you really want to catch any possible error(even system memory or anything else non-related).
To make your code look better, I'd suggest to cast value to int with try...except block, then check for negative values.
try:
value = int(text)
except:
return MessageBox('Enter digit')
if value < 0:
return MessageBox('Enter positive digit')
There is no difference in the Exceptions, but you are processing them in a different way, at a different place in the code.
I suspect it's the veto() call that causes the extra event. But why not validate the input in one place only? i.e have your get_cell_value() function should make sure it's an integer >0.
Also, this structure is both a recipe for circular events, and a painfully annoying UI. People should be able to make a typo and go back and correct it without an annoying dialog popping up.
Maybe provide an indicator of a problem, like making the cell background red, but only go the dialog route once the user tries to move on to the next step.
After a bit more tracing, I found that creating the MessageBox causes the EVT_GRID_CELL_CHANGING event to occur, which then leads to the EVT_GRID_CELL_CHANGED event to occur, which is why I saw duplicated events.
The reason why I did not see duplicated events during the entry of a character was because a Veto() was called in the event handler for the EVT_GRID_CELL_CHANGING if an int() conversion was invalid because my handler for that event gets the grid input and tries to convert it.
In conclusion, there is no difference in Python exception handling, but however, a better wxPython demo should be implemented to prevent the duplicated message box during the demo and show other users how to better use the grid mechanism.
I am learning Python and have stumbled upon a concept I can't readily digest: the optional else block within the try construct.
According to the documentation:
The try ... except statement has an optional else clause, which, when
present, must follow all except clauses. It is useful for code that
must be executed if the try clause does not raise an exception.
What I am confused about is why have the code that must be executed if the try clause does not raise an exception within the try construct -- why not simply have it follow the try/except at the same indentation level? I think it would simplify the options for exception handling. Or another way to ask would be what the code that is in the else block would do that would not be done if it were simply following the try statement, independent of it. Maybe I am missing something, do enlighten me.
This question is somewhat similar to this one but I could not find there what I am looking for.
The else block is only executed if the code in the try doesn't raise an exception; if you put the code outside of the else block, it'd happen regardless of exceptions. Also, it happens before the finally, which is generally important.
This is generally useful when you have a brief setup or verification section that may error, followed by a block where you use the resources you set up in which you don't want to hide errors. You can't put the code in the try because errors may go to except clauses when you want them to propagate. You can't put it outside of the construct, because the resources definitely aren't available there, either because setup failed or because the finally tore everything down. Thus, you have an else block.
One use case can be to prevent users from defining a flag variable to check whether any exception was raised or not(as we do in for-else loop).
A simple example:
lis = range(100)
ind = 50
try:
lis[ind]
except:
pass
else:
#Run this statement only if the exception was not raised
print "The index was okay:",ind
ind = 101
try:
lis[ind]
except:
pass
print "The index was okay:",ind # this gets executes regardless of the exception
# This one is similar to the first example, but a `flag` variable
# is required to check whether the exception was raised or not.
ind = 10
try:
print lis[ind]
flag = True
except:
pass
if flag:
print "The index was okay:",ind
Output:
The index was okay: 50
The index was okay: 101
The index was okay: 10