]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
fix: return the compiled port if PQport returns an empty string
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 8 May 2025 17:09:08 +0000 (19:09 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Fri, 9 May 2025 13:10:50 +0000 (15:10 +0200)
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
<https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-PORT>.

This change is an improvement on top of 40dfa0b, where we allowed PGport
to return NULL. This is likely a libpq bug (reported in
<https://www.postgresql.org/message-id/CA%2Bmi_8YTS8WPZPO0PAb2aaGLwHuQ0DEQRF0ZMnvWss4y9FwDYQ%40mail.gmail.com>)
but now it's in the wild so we better support it rather than dying of
assert or by int()'ing an empty string.

docs/news.rst
psycopg/psycopg/_connection_info.py
tests/test_connection_info.py

index bac2f5f5128e0f8dd19f117665491fefa690e834..e253078ffd8522f174b3104fd17d0f35732848ac 100644 (file)
@@ -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
index 0db591310c25bda6261d2bd97a7ffdc0367b26a6..cf6896cf2ff8ac56e7e6f733b8ced0404145c2bb 100644 (file)
@@ -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:
index e7b45909bab338fc168b935715f6a2aeab32840d..ea731ee0edf21f7d494a92a552a8a2a40d9ca3b7 100644 (file)
@@ -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():