I was looking at Python: Exception in the separated module works wrong which uses a multi-purpose GnuLibError class to 'stand in' for a variety of different errors. Each sub-error has its own ID number and error format string.
I figured it would be better written as a hierarchy of Exception classes, and set out to do so:
class GNULibError(Exception):
    sub_exceptions = 0  # patched with dict of subclasses once subclasses are created
    err_num = 0
    err_format = None
    def __new__(cls, *args):
        print("new {}".format(cls)) # DEBUG
        if len(args) and args[0] in GNULibError.sub_exceptions:
            print("  factory -> {} {}".format(GNULibError.sub_exceptions[args[0]], args[1:])) # DEBUG
            return super(GNULibError, cls).__new__(GNULibError.sub_exceptions[args[0]], *(args[1:]))
        else:
            print("  plain {} {}".format(cls, args)) # DEBUG
            return super(GNULibError, cls).__new__(cls, *args)
    def __init__(self, *args):
        cls = type(self)
        print("init {} {}".format(cls, args)) # DEBUG
        self.args = args
        if cls.err_format is None:
            self.message = str(args)
        else:
            self.message = "[GNU Error {}] ".format(cls.err_num) + cls.err_format.format(*args)
    def __str__(self):
        return self.message
    def __repr__(self):
        return '{}{}'.format(type(self).__name__, self.args)
class GNULibError_Directory(GNULibError):
    err_num = 1
    err_format = "destination directory does not exist: {}"
class GNULibError_Config(GNULibError):
    err_num = 2
    err_format = "configure file does not exist: {}"
class GNULibError_Module(GNULibError):
    err_num = 3
    err_format = "selected module does not exist: {}"
class GNULibError_Cache(GNULibError):
    err_num = 4
    err_format = "{} is expected to contain gl_M4_BASE({})"
class GNULibError_Sourcebase(GNULibError):
    err_num = 5
    err_format = "missing sourcebase argument: {}"
class GNULibError_Docbase(GNULibError):
    err_num = 6
    err_format = "missing docbase argument: {}"
class GNULibError_Testbase(GNULibError):
    err_num = 7
    err_format = "missing testsbase argument: {}"
class GNULibError_Libname(GNULibError):
    err_num = 8
    err_format = "missing libname argument: {}"
# patch master class with subclass reference
# (TO DO: auto-detect all available subclasses instead of hardcoding them)
GNULibError.sub_exceptions = {
    1: GNULibError_Directory,
    2: GNULibError_Config,
    3: GNULibError_Module,
    4: GNULibError_Cache,
    5: GNULibError_Sourcebase,
    6: GNULibError_Docbase,
    7: GNULibError_Testbase,
    8: GNULibError_Libname
}
This starts out with GNULibError as a factory class - if you call it with an error number belonging to a recognized subclass, it returns an object belonging to that subclass, otherwise it returns itself as a default error type.
Based on this code, the following should be exactly equivalent (but aren't):
e = GNULibError(3, 'missing.lib')
f = GNULibError_Module('missing.lib')
print e  # -> '[GNU Error 3] selected module does not exist: 3'
print f  # -> '[GNU Error 3] selected module does not exist: missing.lib'
I added some strategic print statements, and the error seems to be in GNULibError.__new__:
>>> e = GNULibError(3, 'missing.lib')
new <class '__main__.GNULibError'>
  factory -> <class '__main__.GNULibError_Module'> ('missing.lib',)  # good...
init <class '__main__.GNULibError_Module'> (3, 'missing.lib')        # NO!
                                            ^
                                           why?
I call the subclass constructor as subclass.__new__(*args[1:]) - this should drop the 3, the subclass type ID - and yet its __init__ is still getting the 3 anyway! How can I trim the argument list that gets passed to subclass.__init__?