diff --git a/NEWS b/NEWS index 54237b84..5c577498 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ What's new in psycopg 2.8 New features: +- Added `~psycopg2.errors` module. Every PostgreSQL error is converted into + a specific exception class (:ticket:`#682`). - Added `~psycopg2.extensions.encrypt_password()` function (:ticket:`#576`). - `~psycopg2.extras.DictCursor` and `~psycopg2.extras.RealDictCursor` rows maintain columns order (:ticket:`#177`). diff --git a/doc/src/errors.rst b/doc/src/errors.rst new file mode 100644 index 00000000..a4bd48a3 --- /dev/null +++ b/doc/src/errors.rst @@ -0,0 +1,58 @@ +`psycopg2.errors` -- Exception classes mapping PostgreSQL errors +================================================================ + +.. sectionauthor:: Daniele Varrazzo + +.. index:: + single: Error; Class + +.. module:: psycopg2.errors + +.. versionadded:: 2.8 + +This module contains the classes psycopg raises upon receiving an error from +the database with a :sql:`SQLSTATE` value attached. The module is generated +from the PostgreSQL source code and includes classes for every error defined +by PostgreSQL in versions between 9.1 and 11. + +Every class in the module is named after what referred as "condition name" `in +the documentation`__, converted to CamelCase: e.g. the error 22012, +``division_by_zero`` is exposed by this module as the class `!DivisionByZero`. + +.. __: https://www.postgresql.org/docs/current/static/errcodes-appendix.html#ERRCODES-TABLE + +Every exception class is a subclass of one of the :ref:`standard DB-API +exception ` and expose the `~psycopg2.Error` interface. +Each class' superclass is what used to be raised by psycopg in versions before +the introduction of this module, so everything should be compatible with +previously written code catching one the DB-API class: if your code used to +catch `!IntegrityError` to detect a duplicate entry, it will keep on working +even if a more specialised subclass such as `UniqueViolation` is raised. + +The new classes allow a more idiomatic way to check and process a specific +error among the many the database may return. For instance, in order to check +that a table is locked, the following code could have been used previously: + +.. code-block:: python + + try: + cur.execute("LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE NOWAIT") + except psycopg2.OperationalError as e: + if e.pgcode == psycopg2.errorcodes.LOCK_NOT_AVAILABLE: + locked = True + else: + raise + +While this method is still available, the specialised class allows for a more +idiomatic error handler: + +.. code-block:: python + + try: + cur.execute("LOCK TABLE mytable IN ACCESS EXCLUSIVE MODE NOWAIT") + except psycopg2.errors.LockNotAvailable: + locked = True + +For completeness, the module also exposes all the DB-API-defined classes and +:ref:`a few psycopg-specific exceptions ` previously +exposed by the `!extensions` module. One stop shop for all your mistakes... diff --git a/doc/src/extensions.rst b/doc/src/extensions.rst index 34d53a7e..48bcdc29 100644 --- a/doc/src/extensions.rst +++ b/doc/src/extensions.rst @@ -431,12 +431,19 @@ details. .. index:: single: Exceptions; Additional +.. _extension-exceptions: + Additional exceptions --------------------- The module exports a few exceptions in addition to the :ref:`standard ones ` defined by the |DBAPI|_. +.. note:: + From psycopg 2.8 these error classes are also exposed by the + `psycopg2.errors` module. + + .. exception:: QueryCanceledError (subclasses `~psycopg2.OperationalError`) diff --git a/doc/src/index.rst b/doc/src/index.rst index 7ae073d7..4e920cb6 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -42,6 +42,7 @@ Psycopg 2 is both Unicode and Python 3 friendly. advanced extensions extras + errors sql tz pool diff --git a/doc/src/module.rst b/doc/src/module.rst index 1c998252..ef73b586 100644 --- a/doc/src/module.rst +++ b/doc/src/module.rst @@ -250,13 +250,14 @@ available through the following exceptions: .. extension:: - Psycopg may raise a few other, more specialized, exceptions: currently - `~psycopg2.extensions.QueryCanceledError` and - `~psycopg2.extensions.TransactionRollbackError` are defined. These - exceptions are not exposed by the main `!psycopg2` module but are - made available by the `~psycopg2.extensions` module. All the - additional exceptions are subclasses of standard |DBAPI| exceptions, so - trapping them specifically is not required. + Psycopg actually raises a different exception for each :sql:`SQLSTATE` + error returned by the database: the classes are available in the + `psycopg2.errors` module. Every exception class is a subclass of one of + the exception classes defined here though, so they don't need to be + trapped specifically: trapping `!Error` or `!DatabaseError` is usually + what needed to write a generic error handler; trapping a specific error + such as `!NotNullViolation` can be useful to write specific exception + handlers. This is the exception inheritance layout: @@ -270,8 +271,6 @@ This is the exception inheritance layout: \|__ `DatabaseError` \|__ `DataError` \|__ `OperationalError` - \| \|__ `psycopg2.extensions.QueryCanceledError` - \| \|__ `psycopg2.extensions.TransactionRollbackError` \|__ `IntegrityError` \|__ `InternalError` \|__ `ProgrammingError`