]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Add ConnectionInfo.dsn property
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Mon, 2 Aug 2021 09:59:20 +0000 (11:59 +0200)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Tue, 3 Aug 2021 10:57:53 +0000 (11:57 +0100)
docs/api/connections.rst
psycopg/psycopg/conninfo.py
tests/test_conninfo.py

index 3e1ca25cb54fce9b1a9cea14c77f8e15510ec70e..cb3db196db9dbf5954149ae4c5dfa4479b11bc1c 100644 (file)
@@ -358,6 +358,11 @@ Connection support objects
 
     The object is usually returned by `Connection.info`.
 
+    .. autoattribute:: dsn
+
+        .. note:: The `get_parameters()` method returns the same information
+            as a dict.
+
     .. autoattribute:: status
 
         The status can be one of a number of values. However, only two of
index 9dfff13397a480b54fcfbb838a49d01dff1a8fc5..9700c356fa50ccd9aed7b6f63ca108428ea78805 100644 (file)
@@ -161,8 +161,9 @@ class ConnectionInfo:
         """Return the connection parameters values.
 
         Return all the parameters set to a non-default value, which might come
-        either from the connection string or from environment variables. Don't
-        report the password (you can read it using the `password` attribute).
+        either from the connection string and parameters passed to
+        `~Connection.connect()` or from environment variables. The password
+        is never returned (you can read it using the `password` attribute).
         """
         pyenc = self._pyenc
 
@@ -184,6 +185,18 @@ class ConnectionInfo:
             and i.val != defaults.get(i.keyword)
         }
 
+    @property
+    def dsn(self) -> str:
+        """Return the conneciton string to connect to the database.
+
+        The string contains all the parameters set to a non-default value,
+        which might come either from the connection string and parameters
+        passed to `~Connection.connect()` or from environment variables. The
+        password is never returned (you can read it using the `password`
+        attribute).
+        """
+        return make_conninfo(**self.get_parameters())
+
     @property
     def status(self) -> pq.ConnStatus:
         """The status of the connection. See :pq:`PQstatus`."""
index 563e7d451b7c359f029a4076f8fc866f8ad08dc8..100e1e9957f0cf1493b9ed97bae046b491268ec9 100644 (file)
@@ -167,6 +167,13 @@ class TestConnectionInfo:
             else:
                 assert k not in info
 
+    def test_dsn(self, conn, dsn):
+        dsn = conn.info.dsn
+        assert "password" not in dsn
+        for k, v in conninfo_to_dict(dsn).items():
+            if k != "password":
+                assert f"{k}=" in dsn
+
     def test_get_params_env(self, dsn, monkeypatch):
         dsn = conninfo_to_dict(dsn)
         dsn.pop("application_name", None)
@@ -181,6 +188,18 @@ class TestConnectionInfo:
                 conn.info.get_parameters()["application_name"] == "hello test"
             )
 
+    def test_dsn_env(self, dsn, monkeypatch):
+        dsn = conninfo_to_dict(dsn)
+        dsn.pop("application_name", None)
+
+        monkeypatch.delenv("PGAPPNAME", raising=False)
+        with psycopg.connect(**dsn) as conn:
+            assert "application_name=" not in conn.info.dsn
+
+        monkeypatch.setenv("PGAPPNAME", "hello test")
+        with psycopg.connect(**dsn) as conn:
+            assert "application_name='hello test'" in conn.info.dsn
+
     def test_status(self, conn):
         assert conn.info.status.name == "OK"
         conn.close()
@@ -199,6 +218,14 @@ class TestConnectionInfo:
         assert "password" not in info.get_parameters()
         assert info.get_parameters()["dbname"] == info.dbname
 
+    def test_dsn_no_password(self, dsn):
+        dsn2 = make_conninfo(dsn, password="the-pass-word")
+        pgconn = psycopg.pq.PGconn.connect_start(dsn2.encode("utf8"))
+        info = ConnectionInfo(pgconn)
+        assert info.password == "the-pass-word"
+        assert "password" not in info.dsn
+        assert f"dbname={info.dbname}" in info.dsn
+
     def test_parameter_status(self, conn):
         assert conn.info.parameter_status("nosuchparam") is None
         tz = conn.info.parameter_status("TimeZone")