If I have an Error module defined containing my application defined exceptions as something like:
class Error(Exception):
pass
class NoSchemaVersion(Error):
def __init__(self):
self.code = 1
self.msg = "No schema version specified"
pass
class NoMsgType(Error):
def __init__(self):
self.code = 2
self.msg = "No message type specified"
pass
How do I would I handle specific exceptions when they are raised. I tried something like:
import Error
errors = Error.Error()
try:
<do some stuff>
except errors.NoMsgType:
<stuff>
but I get the message:
AttributeError: 'Error' object has no attribute 'NoMsgType'
What am I doing wrong?
Error.Error() (stored in error) constructs a new value of the Error class, but NoMsgType is a separate class that isn't actually part of Error, and so error.NoMsgType doesn't exist. To catch a NoMsgType, you should just write except Error.NoMsgType:.
I gues you need to do simething like this:
try:
somecode
except Error.NoMsgType:
morecode
Related
i have custom exception for inserting data:
class ErrorOnInsert(BaseException):
"""Exception raised for errors in insert data to db
Attributes:
resource -- resource name
message -- explanation of the error
"""
def __init__(self, resource: str):
self.message = 'Failed to insert data for {}!'.format(resource)
super().__init__(self.message)
exception is used in this insert function to mongo:
def _add(self, data: RunnerRating):
try:
dict_data = data.as_dict()
self.collection[self.document_name].insert_one(
dict_data)
self.list_data.add(data)
except ErrorOnInsert(self.document_name) as e:
raise e
and i try to test the exception with self.repo._add(None) but it shows error something like this:
FAILED tests/integration/test_repo.py::RatingRepoTest::test_add -
TypeError: catching classes that do not inherit from BaseException is
not allowed
Your syntax looks like it's a catch with a pattern match (which isn't a thing in Python).
Are you maybe looking for
def _add(self, data: RunnerRating):
try:
dict_data = data.as_dict()
self.collection[self.document_name].insert_one(dict_data)
self.list_data.add(data)
except Exception as e:
raise ErrorOnInsert(self.document_name) from e
I have a python class in which I open files and read out data. If some creteria are not met, I raise an error, but before that I specify the error by giving the object an attribute: self.Error = specification. But since the error raising undos everything in the try block I can't access it. This happens in the __init__ function, so the created object doesn't even exist..
Here's the necessary code:
class MyClass:
def __init__(self):
#do something
if this_or_that:
self.Error = specification
raise MyCostumError
try:
object = MyClass()
except MyCostumError:
print(object.Error)
I get: NameError: name 'object' is not defined
Just for clarification:
I have defined MyCostumError, the variable names are just for better understanding: I use good ones and they are defined and I need the clarification, because an Error can be raised in different lines.
So here's my question:
Is there something like try/except, but when an error is raised it does NOT undo everything. Or am I just stupid and there is a much easier method for a achieving this?
If you are raising an exception in the initializer, you should not rely on the object to be created to get some error information to the caller. This is where you should use the exception to pass that information:
class MyCustomError(Exception):
pass
class MyClass:
def __init__(self):
#do something
if this_or_that:
raise MyCustomError(specification) # put the spec in the exception itself
try:
object = MyClass()
except MyCustomError as e:
print(e) # the spec is in the exception object
You are trying to reference to an object that cannot exist. Let me explain:
If an error occurs when you try to initialise an object, that object will not be initialised. So if you try to acced to it when it is not initialised, you will get an error.
try:
object = MyClass() #initialising object successful, object existing.
except: #initialising failed, object does not exist.
print(object.Error) #nameError, since object was never created.
Try/except doesn't undo anything, just stops doing something if an error occurs.
Error raising doesn't undo anything. Have a look at the docs.
As your output states, the object is not defined, this is because when you raise an error in the __init__, it is seen as the initialosor of your class failing, and this does not return an object.
I think this is what you're looking for:
class MyClass:
def __init__(self):
# do initialisation stuff
def other_method(self):
# do something
if this_or_that:
self.Error = specification
raise MyCustomError(specification)
object = MyClass()
try:
object.other_method()
except MyCustomError as e:
print(e)
print(object.Error)
It's not a beautiful solution but it should work:
errorcode = None
class MyClass:
def __init__(self):
global errorcode
#do something
if this_or_that:
errorcode = specification
raise MyCostumError
try:
object = MyClass()
except MyCostumError:
print(errorcode)
Given your question I think the following should fit your use case well.
class MyClass:
def __init__(self):
# Do something
try:
if this_or_that:
self.Error = specification
raise MyCostumError
except MyCustomError as e:
# Handle your custom error however you like
object = MyClass()
In the above case you should be able to mitigate the risk of instantiation failing due to custom exception/error raising failing by handling this behaviour within MyClass.__init__ itself.
This is also a much cleaner solution in terms of keeping logic relating to instantiation of MyClass objects contained within the __init__ function of the class - i.e. you won't have to worry about wrapping instantiations of this class in try/except blocks each time they are present in your code.
I am currently working through Learning Python by Mark Lutz and David Ascher and I have come across a section of code that keeps bringing up errors. I am aware that that book was written with Python 2 in mind unlike the Pyhton 3 I am using. I was wondering if anyone knew a solution to my problem as I have looked everywhere but I have been unable to find a solution .
.........................
MyBad = 'oops'
def stuff( ):
raise MyBad
try:
stuff( )
except MyBad:
print('got it')
Basically, MyBad is not an exception, and the raise statement can only be used with exceptions.
To make MyBad an exception, you must make it extend a subclass of Exception. For instance, the following will work:
class MyBad(Exception):
pass
def stuff( ):
raise MyBad
try:
stuff( )
except MyBad:
print('got it')
Output:
got it
However, it's better to raise an instance of an exception class, rather than the class itself, because it allows the use of parameters, usually describing the error. The following example illustrates this:
class MyBad(Exception):
def __init__(self, message):
super().__init__()
self.message = message
def stuff(message):
raise MyBad(message)
try:
stuff("Your bad")
except MyBad as error:
print('got it (message: {})'.format(error.message))
Output:
got it (Your bad)
You cannot raise a custom exception without creating a class (at least an empty one).
You can add custom text as you want by using also an __init__ function instead of pass:
class MyBad(Exception):
pass
# def __init__(self, txt):
# print(txt)
def stuff( ):
raise MyBad('test')
try:
stuff( )
except MyBad:
print('got it')
If you use pass, you will have :
got it
If you use the __init__() in comment, you will have
test and got it
I'm working with an external service which reports errors by code.
I have the list of error codes and the associated messages. Say, the following categories exist: authentication error, server error.
What is the smartest way to implement these errors in Python so I can always lookup an error by code and get the corresponding exception object?
Here's my straightforward approach:
class AuthError(Exception):
pass
class ServerError(Exception):
pass
map = {
1: AuthError,
2: ServerError
}
def raise_code(code, message):
""" Raise an exception by code """
raise map[code](message)
Would like to see better solutions :)
Your method is correct, except that map should be renamed something else (e.g. ERROR_MAP) so it does not shadow the builtin of the same name.
You might also consider making the function return the exception rather than raising it:
def error(code, message):
""" Return an exception by code """
return ERROR_MAP[code](message)
def foo():
raise error(code, message)
By placing the raise statement inside foo, you'd raise the error closer to where the error occurred and there would be one or two less lines to trace through if the stack trace is printed.
Another approach is to create a polymorphic base class which, being instantiated, actually produces a subclass that has the matching code.
This is implemented by traversing __subclasses__() of the parent class and comparing the error code to the one defined in the class. If found, use that class instead.
Example:
class CodeError(Exception):
""" Base class """
code = None # Error code
def __new__(cls, code, *args):
# Pick the appropriate class
for E in cls.__subclasses__():
if E.code == code:
C = E
break
else:
C = cls # fall back
return super(CodeError, cls).__new__(C, code, *args)
def __init__(self, code, message):
super(CodeError, self).__init__(message)
# Subclasses with error codes
class AuthError(CodeError):
code = 1
class ServerError(CodeError):
code = 2
CodeError(1, 'Wrong password') #-> AuthError
CodeError(2, 'Failed') #-> ServerError
With this approach, it's trivial to associate error message presets, and even map one class to multiple codes with a dict.
A temporary exception class is defined dynamically using 'type' in a python script meant to be used as module. When an instance of this class is caught in importing script it doesn't recognize the class.
Below is code snippet
# the throwing module, defines dynamically
def bad_function():
ExceptionClass = type( "FooBar", (Exception,),
{ "__init__": lambda self, msg: Exception.__init__(self, msg) })
raise ExceptionClass("ExceptionClass")
the using code
import libt0
try:
libt0.bad_function()
#except libt0.FooBar as e:
#print e
except Exception as e:
print e
print e.__class__
can it be explained why libt0.FooBase is not visible to this script? observer output of last line.
It's not clear how you expect FooBar to exist without doing something like this
def bad_function():
ExceptionClass = type( "FooBar", (Exception,),
{ "__init__": lambda self, msg: Exception.__init__(self, msg) })
globals()['FooBar'] = ExceptionClass
raise ExceptionClass("ExceptionClass")
You created the class inside a function, so it doesn't exist as a name in the module's global namespace. In fact, it doesn't exist at all except while bad_function is executing. It's the same reason why this fails:
# file1.py
def good_function():
x = 2
# file2.py
import file1
print file1.x
Your exception class is just a local variable inside bad_function.