I'm wrapping a remote XML-based API from python 2.7. The API throws errors by sending along a <statusCode>
element as well as a <statusDescription>
element. Right now, I catch this condition and raise a single exception type. Something like:
class ApiError(Exception):
pass
def process_response(response):
if not response.success:
raise ApiError(response.statusDescription)
This works fine, except I now want to handle errors in a more sophisticated fashion. Since I have the statusCode
element, I would like to raise a specific subclass of ApiError based on the statusCode. Effectively, I want my wrapper to be extended like this:
class ApiError(Exception):
def __init__(self, description, code):
# How do I change self to be a different type?
if code == 123:
return NotFoundError(description, code)
elif code == 456:
return NotWorkingError(description, code)
class NotFoundError(ApiError):
pass
class NotWorkingError(ApiError):
pass
def process_response(response):
if not response.success:
raise ApiError(response.statusDescription, response.statusCode)
def uses_the_api():
try:
response = call_remote_api()
except NotFoundError, e:
handle_not_found(e)
except NotWorkingError, e:
handle_not_working(e)
The machinery for tying specific statusCode
's to specific subclasses is straightforward. But what I want is for that to be buried inside of ApiError somewhere. Specifically, I don't want to change process_response except to pass in the value statusCode
.
I've looked at metaclasses, but not sure they help the situation, since __new__
gets write-time arguments, not run-time arguments. Similarly unhelpful is hacking around __init__
since it isn't intended to return an instance. So, how do I instantiate a specific subclass based on arguments passed to __init__
?