SQLAlchemyError should sub-class (built-in) StandardError, not (built-in) Exception

Issue #2160 resolved
Former user created an issue

SQL Alchemy exceptions are sub-classed from Python's built-in {{{Exception}}} class, and while there is nothing wrong with that I intend to present an argument for changing the root built-in to {{{StandardError}}}.

(The root of core SQL Alchemy exceptions is SQLAlchemyError)

Until Python v2.5 all exceptions were derived from {{{Exception}}}, including what I shall term 'special' exceptions: those that implement system functionality (e.g. {{{SystemExit}}}, {{{KeyboardInterrupt}}}) or language features (e.g. {{{StopIteration}}}, {{{GeneratorExit}}}). Ordinary built-in exceptions are derived from {{{StandardError}}}.

Thus there is a semi-implicit convention that errors are derived from {{{StandardError}}}, and other flow-control exceptions from Exception itself (or at least, not from {{{StandardError}}} or a descendant of it). This convention is observed by tools like PyLint out of the box. Citing the documentation for StopIteration:

... This is derived from Exception rather than {{{StandardError}}}, since this is not considered an error in its normal application.

I believe it follows from this that {{{SQLAlchemyError}}} should sub-class {{{StandardError}}}, not Exception. This would allow projects that observe the convention described above to catch {{{SQLAlchemy}}} errors in their usual way: "{{{except StandardError}}}" without also catching {{{SystemExit}}} etc.

The change required is minimal (modify {{{SQLAlchemyError}}} to inherit from {{{StandardError}}}), and is extremely unlikely to cause problems for existing projects, since {{{StandardError}}} is itself derived from Exception.

Regarding my opening qualifier ("Until Python v2.5..."): Python v2.5 introduced {{{BaseException}}} to presumably because many projects followed their tutorial and defined their own errors by sub-classing Exception rather than {{{StandardError}}}. System exceptions (non-errors) were changed to inherit from the new {{{BaseException}}}, and thus avoid problems associated with using "{{{except Exception}}}" in a project.

This is certainly a welcome change, but I would still prefer to see errors inherit from {{{StandardError}}}.

Not all exceptions are errors, but all errors are exceptions.

Comments (6)

  1. Mike Bayer repo owner

    Note that we support Python 2.4 and up. Such a change would need to take this into account.

    I did a quick poll of some other well known projects, all of which are widely considered to be well-written and "Pythonic":

    • Sphinx - SphinxError subclasses Exception
    • Jinja2 - TemplateError subclasses Exception
    • Django - in django/core/exceptions.py, ObjectDoesNotExist, MultipleObjectsReturned, SuspiciousOperation, and a whole bunch more all subclass Exception
    • Pyramid - pyramid/exceptions.py - ExceptionResponse subclasses Exception
    • Storm ORM - storm/exceptions.py - StormError subclasses Exception

    I will note that pep-0249 states that DBAPI Error should subclass StandardError. Otherwise I didn't find any projects that are going the StandardError approach.

    However as I go through these, it seems like this is a convention that really hasn't been adopted in any widespread way.
    The documentation page you link doesn't say much at all for StandardError as far as its purpose. More concerning, that very page seems to encourage subclassing Exception:

    The built-in exception classes can be sub-classed to define new exceptions; programmers are encouraged to at least derive new exceptions from the Exception class and not `BaseException`. More information on defining exceptions is available in the Python Tutorial under User-defined Exceptions.
    

    No mention in that sentence of the role of StandardError. Only the vague phrase "at least" seems to suggest there may be something wrong with subclassing Exception directly. Over in the cited tutorial section, http://docs.python.org/release/2.6.5/tutorial/errors.html#tut-userexceptions, no mention at all of StandardError - the documentation clearly recommends Exception:

    Programs may name their own exceptions by creating a new exception class (see Classes for more about Python classes). Exceptions should typically be derived from the Exception class, either directly or indirectly.
    

    I linked over to the 2.7 docs http://docs.python.org/release/2.7/tutorial/errors.html#tut-userexceptions - has not been updated.
    Checked 3.2: http://docs.python.org/release/3.2/tutorial/errors.html#tut-userexceptions - no mention of StandardError, same verbiage regarding "typically be derived from Exception".

    I also looked for PEPs regarding this - I know I had seem some that discuss exceptions. I found http://www.python.org/dev/peps/pep-0352/ - "Required Superclass for Exceptions" - does not mention StandardError.

    Then I found pep 3100 - "Miscellaneous Python 3.0 Plans" - http://www.python.org/dev/peps/pep-3100/:

    To be removed:
    
    `StandardError`: this is a relic from the original exception hierarchy; subclass Exception instead. [done](done)
    

    I was originally going to say this would be a Python dev issue, as they've seriously failed to document this convention - but the above PEP makes it seem like this is a convention that has already been killed off.

    I'd be comfortable considering a change like this if it were a widely used, well documented pattern that major libraries have agreed upon, rather than a so-called "semi-implicit convention". But given the language in pep-3100 it appears this convention may already be dead before it ever got started.

  2. Former user Account Deleted

    (FYI: I created this ticket)

    SystemExit and KeyboardInterrupt have only subclassed BaseException since it was introduced in Python v2.5.

    In Python v2.4, SystemExit sub-classes Exception, and KeyboardInterrupt sub-classes StandardError.

    So in Python v2.5+ the problems associated with catching Exception do not present themselves. In Python v2.4 catching Exception should be considered bad practice, and I would expect to see Python v2.4 projects catch StandardError as a consequence.

    I guess its your call. :-)

  3. Mike Bayer repo owner

    When I look at the hierarchy diagram, it seems to me that the point of StandardError was specifically to mark exceptions that are part of the standard lib - like even if this class were not being killed off, it wouldn't even be appropriate to subclass from an external app. Its hard to say with no docs regarding its rationale.

  4. Mike Bayer repo owner

    OK it appears like nobody else has any opinions on this so given that StandardError seems like a legacy thing that isn't in modern usage, closing this.

  5. Log in to comment