Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nIaxN-0008HA-9O for psycopg@arkaria.postgresql.org; Fri, 11 Feb 2022 18:47:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1nIaxM-0000DX-1t for psycopg@arkaria.postgresql.org; Fri, 11 Feb 2022 18:47:44 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nIaxL-000091-Oi for psycopg@lists.postgresql.org; Fri, 11 Feb 2022 18:47:43 +0000 Received: from mail-vk1-xa2f.google.com ([2607:f8b0:4864:20::a2f]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1nIaxE-0001Hq-E3 for psycopg@postgresql.org; Fri, 11 Feb 2022 18:47:43 +0000 Received: by mail-vk1-xa2f.google.com with SMTP id w207so4969209vkd.2 for ; Fri, 11 Feb 2022 10:47:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=rm+IJHZR0q3H7aCvKkDK3L2LRK5Go4MEFEu/rhqeHTU=; b=pWMWXjcyxrijwmw1R1DcoQfx4HgGwIAditfh0tcS3ohJV3GF5Kr6fUQ0+Vc9VJTSyo Xqyxvv0NYsQd7HXJEJUfTCsHtF0gUNLs4vmp2t7ZdtBr2NLiLKKjIubC8ZNwwFvBuPoo kHNaWxvJw8Dpsv7fgzmljeOgFbFeOMvfLJk5JQ9NMlIv1E6UYLonKIAmZQemMk54hnM7 HKIvcEFf1IglIBTgXVHXYI6BBDwv8BYat6FFpq+gZuBIjugtbC5S/qevJtTrhQG/jSA1 S1FIZZXo+VXBx2tzvON0YbxY2/vkcs3F/6PQIl2NTRIYMRy8tkRDvkBIcgR2Pt2oAM99 zgbg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=rm+IJHZR0q3H7aCvKkDK3L2LRK5Go4MEFEu/rhqeHTU=; b=jpBGlzaztGyG/OpDHY1HVYWfwJtgDaKI0Unq5CBd8b/1C16cQOxLnQozAmWu2wK33b RdB9Erxyf6up6EO6YtpX2/+GvbaS0RtOFV8d5rNumlg3UKF7EaAODphRE89Ve7nwu2cY CrY+oGmk1f1vXg6nSISiXAwEoEudpv+OPj6/IRIilcHlRd72njxaAzV4kRYWUBSkyVL4 j5+EF82S51g1W09NL4TsTDLb03/SE9M/pkJp9kmD6FoJuL+FqcJnS9Hvs4zfdJC9ECmw na0KMImMgQhRW6M9xFuc5KtNoCtZHb66pdFcCcUoFzsK9/e/301SUM0FDNuiio73L0Lk zXsA== X-Gm-Message-State: AOAM533iAlxQDXeByeUdgAQJOl1ptMplLL/fkbkYCz8PSte7pk9ZpDoG 3jqeqKdLk0xCe+ys5BUXotlpNLLyxpjg1X8+9Eq/6yxtmlo= X-Google-Smtp-Source: ABdhPJzzWiz7N3rl1Rz9UmUgjFEboOAf7+9hIc9Hc3We+s5B0pAIsS+uku7O8uhsylQ7MXrK/Z6Xm3TbfxeXVEayHN4= X-Received: by 2002:a05:6122:511:: with SMTP id x17mr871589vko.24.1644605253889; Fri, 11 Feb 2022 10:47:33 -0800 (PST) MIME-Version: 1.0 References: <11dedb1fce0dbbd6f125736347685fd5@paolodestefani.it> In-Reply-To: <11dedb1fce0dbbd6f125736347685fd5@paolodestefani.it> From: Daniele Varrazzo Date: Fri, 11 Feb 2022 19:47:22 +0100 Message-ID: Subject: Re: exception psycopg.Error from psycopg2 to psycopg 3 To: Paolo De Stefani Cc: Psycopg Content-Type: text/plain; charset="UTF-8" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Fri, 11 Feb 2022 at 18:34, Paolo De Stefani wrote: Hi Paolo, Yes, I can see some inconsistency there. At the moment I suggest you use `e.diag.sqlstate`, which works as expected and is available in psycopg2 too. In [8]: try: cnn.execute(""" ...: do $$ ...: begin ...: RAISE EXCEPTION 'Error wrong database' USING HINT = 'You need to use a different database', ERRCODE = 'PA002'; ...: end$$ ...: language plpgsql ...: """) ...: except Exception as e: ex = e In [10]: ex.diag.sqlstate Out[10]: 'PA002' In [11]: ex.sqlstate None What is happening is that, in psycopg 3, Error.sqlstate is a class property and is only set for the known classes - the ones listed at . The attribute `e.diag.sqlstate` instead comes from the error message received from the server. When the error is received, the matching class is looked up by sqlstate, with the basic dbapi exceptions as fallback if the code is not known, and the server result is passed to the exception state, so that `e.diag` is populated with all the details (such as the message, the hint etc). The cases I had in mind where 1) known exceptions where Error.sqlstate and e.diag.sqlstate would match, and 2) non-server exceptions (e.g. on connection, or raised by Python code) where Error.sqlstate and e.diag.sqlstate are both None. I didn't think about the case 3) where a sqlstate exists, but psycopg doesn't know it. In this case, the result of the current implementation is to raise an exception with the sqlstate left to None on the class but available in diag. ISTM that setting e.sqlstate = e.diag.sqlstate would be an improvement. The docs describe indeed that sqlstate is expected to be None on the DBAPI classes (https://www.psycopg.org/psycopg3/docs/api/errors.html#psycopg.Error.sqlstate) but that wasn't written thinking about the inconsistency above. It makes more sense that Error.sqlstate is whatever state received, if any. Does it sound right? -- Daniele