So I'm (of course) writing a library that interacts with an API, and the API can sometimes return errors. I came up with a context manager to catch dynamic errors, but I'd like to do something a little quicker:
class APIError(Exception):
def __getattr__(self, name):
setattr(self, name, type(name, (APIError,), {}))
return getattr(self, name)
What I'd then like to do is something like this:
try:
...
except APIError.knownerrorcode:
...handle...
However, this doesn't work - the __getattr__
doesn't apply to the class itself. The workaround is to do this:
try:
...
except APIError().knownerrorcode:
...handle...
but this is ugly and normally wouldn't make sense - you can't catch exception instances, only classes, but APIError() obviously creates an instance.
To solve that problem, I added APIError = APIError()
after the class declaration, and then the second example worked fine. However, after that change, this failed:
try:
...
except APIError:
...handle...
because APIError is now an instance and cannot be directly caught. The following doesn't work properly either:
class APIError(Exception):
@classmethod
def __getattr__(cls, name):
setattr(cls, name, type(name, (cls,), {}))
return getattr(cls, name)
because the decorator converts it into a normal method:
>>> APIError.knownerrorcode
Traceback (most recent call last):
File "<pyshell#75>", line 1, in <module>
APIError.knownerrorcode
AttributeError: type object 'APIError' has no attribute 'knownerrorcode'
>>> APIError.__getattr__('knownerrorcode')
<class '__main__.knownerrorcode'>
I've also tried metaclasses:
class meta(type):
def __getattr__(self, name):
setattr(self, name, type(name, (APIError,), {}))
return getattr(self, name)
class APIError(Exception, meta):
pass
but the second declaration results in a TypeError:
Traceback (most recent call last):
File "<pyshell#66>", line 1, in <module>
class APIError(Exception, meta):
TypeError: multiple bases have instance lay-out conflict
So, my question is: How can I define a __getattr__
on a class, so that the class can be caught as an exception and all attributes of the class return subclasses of the root?