From: Daniele Varrazzo Date: Thu, 8 May 2025 17:09:08 +0000 (+0200) Subject: fix: return the compiled port if PQport returns an empty string X-Git-Tag: 3.2.8~14^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c030b438c72d4307d8f0dd67d7dbd7de1ad7e385;p=thirdparty%2Fpsycopg.git fix: return the compiled port if PQport returns an empty string Looking at the docs this seems the default value when an empty string is specified, as opposite as the value in the PGPORT env var. See . This change is an improvement on top of 40dfa0b, where we allowed PGport to return NULL. This is likely a libpq bug (reported in ) but now it's in the wild so we better support it rather than dying of assert or by int()'ing an empty string. --- diff --git a/docs/news.rst b/docs/news.rst index bac2f5f51..e253078ff 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -24,6 +24,8 @@ Psycopg 3.2.8 (unreleased) - Don't process further connection attempts after Ctrl-C (:ticket:`#1077`). - Fix cursors to correctly iterate over rows even if their row factory returns `None` (:ticket:`#1073`). +- Fix `ConnectionInfo.port` when the port is specified as an empty string + (:ticket:`#1078`). Current release diff --git a/psycopg/psycopg/_connection_info.py b/psycopg/psycopg/_connection_info.py index 0db591310..cf6896cf2 100644 --- a/psycopg/psycopg/_connection_info.py +++ b/psycopg/psycopg/_connection_info.py @@ -9,6 +9,7 @@ from __future__ import annotations from pathlib import Path from datetime import tzinfo +from . import errors as e from . import pq from ._tz import get_tzinfo from .conninfo import make_conninfo @@ -40,7 +41,21 @@ class ConnectionInfo: @property def port(self) -> int: """The port of the active connection. See :pq:`PQport()`.""" - return int(self._get_pgconn_attr("port")) + if sport := self._get_pgconn_attr("port"): + return int(sport) + return self._get_compiled_port() + + def _get_compiled_port(sef) -> int: + # As per docs: an empty string means the build default, not e.g. + # something configured by PGPORT + # https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-PORT + for info in pq.Conninfo().get_defaults(): + if info.keyword == b"port": + if info.compiled: + return int(info.compiled) + break + + raise e.InternalError("couldn't find the connection port") @property def dbname(self) -> str: diff --git a/tests/test_connection_info.py b/tests/test_connection_info.py index e7b45909b..ea731ee0e 100644 --- a/tests/test_connection_info.py +++ b/tests/test_connection_info.py @@ -44,6 +44,17 @@ def test_port(conn): conn.info.port +@pytest.mark.skipif(psycopg.pq.__impl__ != "python", reason="can't monkeypatch C") +def test_blank_port(conn, monkeypatch): + monkeypatch.setenv("PGPORT", "9999") + monkeypatch.setattr( + psycopg.pq._pq_ctypes, "PQport", lambda self: b"" # type: ignore[attr-defined] + ) + assert conn.pgconn.port == b"" + # assume 5432 is the compiled value + assert conn.info.port == 5432 + + def test_get_params(conn, dsn): info = conn.info.get_parameters() for k, v in conninfo_to_dict(dsn).items():