From a55a91ad17e0adc3bf0b06d9ae6ad4b74583f0c1 Mon Sep 17 00:00:00 2001 From: "d.kovalenko" Date: Sat, 6 Jun 2026 00:18:14 +0300 Subject: [PATCH 1/4] PostgresNode can obtain an explicit host address If it is not defined it will use os_ops.host as usual. --- src/node.py | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/node.py b/src/node.py index 83b9b079..2cb7a39e 100644 --- a/src/node.py +++ b/src/node.py @@ -161,6 +161,7 @@ class PostgresNode(object): _C_PM_PID__IS_NOT_DETECTED = -1 _name: typing.Optional[str] + _host: str _port: typing.Optional[int] _bin_dir: str _should_free_port: bool @@ -175,7 +176,9 @@ def __init__(self, bin_dir: typing.Optional[str] = None, prefix=None, os_ops: typing.Optional[OsOperations] = None, - port_manager: typing.Optional[PortManager] = None): + port_manager: typing.Optional[PortManager] = None, + host: typing.Optional[str] = None, + ): """ PostgresNode constructor. @@ -186,11 +189,13 @@ def __init__(self, bin_dir: path to node's binary directory. os_ops: None or correct OS operation object. port_manager: None or correct port manager object. + host: None or valid address of node host. """ assert port is None or type(port) is int assert bin_dir is None or type(bin_dir) is str assert os_ops is None or isinstance(os_ops, OsOperations) assert port_manager is None or isinstance(port_manager, PortManager) + assert host is None or type(host) is str # private if os_ops is None: @@ -219,6 +224,16 @@ def __init__(self, # basic self._name = name or generate_app_name() + if host is not None: + assert type(host) is str + self._host = host + else: + self._host = self._os_ops.host + assert type(self._host) is str + + if self._host == "": + raise RuntimeError("PostgresNode host is empty.") + if port is not None: assert type(port) is int assert port_manager is None @@ -317,6 +332,7 @@ def clone_with_new_name_and_base_dir(self, name: str, base_dir: str): assert isinstance(self._port_manager, PortManager) assert self._os_ops is not None assert isinstance(self._os_ops, OsOperations) + assert type(self._host) is str node = PostgresNode( name=name, @@ -324,7 +340,9 @@ def clone_with_new_name_and_base_dir(self, name: str, base_dir: str): bin_dir=self._bin_dir, prefix=self._prefix, os_ops=self._os_ops, - port_manager=self._port_manager) + port_manager=self._port_manager, + host=self._host, + ) return node @@ -348,9 +366,9 @@ def name(self) -> str: @property def host(self) -> str: - assert self._os_ops is not None - assert isinstance(self._os_ops, OsOperations) - return self._os_ops.host + assert self._host is not None + assert type(self._host) is str + return self._host @property def port(self) -> int: @@ -467,7 +485,7 @@ def source_walsender(self): assert type(self.master) is PostgresNode # master should be on the same host - assert self.master.host == self.host + assert self.master.host == self._host with self.master.connect() as con: for row in con.execute(sql, self.name): @@ -838,7 +856,7 @@ def get_auth_method(t): self.append_conf(fsync=fsync, max_worker_processes=MAX_WORKER_PROCESSES, log_statement=log_statement, - listen_addresses=self.host, + listen_addresses=self._host, port=self.port) # yapf:disable # common replication settings @@ -1453,7 +1471,7 @@ def _psql( raise Exception("Input data must be None or bytes.") if host is None: - host = self.host + host = self._host if port is None: port = self.port @@ -1580,7 +1598,7 @@ def tmpfile(): _params = [ self._get_bin_path("pg_dump"), "-p", str(self.port), - "-h", self.host, + "-h", self._host, "-f", filename, "-U", username or self._os_ops.username, "-d", dbname or default_dbname(), @@ -1612,7 +1630,7 @@ def restore(self, filename, dbname=None, username=None): _params = [ self._get_bin_path("pg_restore"), "-p", str(self.port), - "-h", self.host, + "-h", self._host, "-U", username, "-d", dbname, filename @@ -1888,7 +1906,7 @@ def pgbench(self, _params = [ self._get_bin_path("pgbench"), "-p", str(self.port), - "-h", self.host, + "-h", self._host, "-U", username or self._os_ops.username ] + options # yapf: disable @@ -1961,7 +1979,7 @@ def pgbench_run(self, dbname=None, username=None, options=[], **kwargs): _params = [ self._get_bin_path("pgbench"), "-p", str(self.port), - "-h", self.host, + "-h", self._host, "-U", username or self._os_ops.username ] + options # yapf: disable From cf307554da760c27967ac85e8cee7d18ffa05443 Mon Sep 17 00:00:00 2001 From: "d.kovalenko" Date: Sun, 7 Jun 2026 10:27:19 +0300 Subject: [PATCH 2/4] flake8 --- src/node.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/node.py b/src/node.py index 2cb7a39e..148cae89 100644 --- a/src/node.py +++ b/src/node.py @@ -169,15 +169,16 @@ class PostgresNode(object): _port_manager: typing.Optional[PortManager] _manually_started_pm_pid: typing.Optional[int] - def __init__(self, - name=None, - base_dir=None, - port: typing.Optional[int] = None, - bin_dir: typing.Optional[str] = None, - prefix=None, - os_ops: typing.Optional[OsOperations] = None, - port_manager: typing.Optional[PortManager] = None, - host: typing.Optional[str] = None, + def __init__( + self, + name=None, + base_dir=None, + port: typing.Optional[int] = None, + bin_dir: typing.Optional[str] = None, + prefix=None, + os_ops: typing.Optional[OsOperations] = None, + port_manager: typing.Optional[PortManager] = None, + host: typing.Optional[str] = None, ): """ PostgresNode constructor. @@ -230,7 +231,7 @@ def __init__(self, else: self._host = self._os_ops.host assert type(self._host) is str - + if self._host == "": raise RuntimeError("PostgresNode host is empty.") From c683ee0e65ac1e0c7213891b43658018ffefae09 Mon Sep 17 00:00:00 2001 From: "d.kovalenko" Date: Sun, 7 Jun 2026 10:28:11 +0300 Subject: [PATCH 3/4] TestTestgresCommon::test_node_constructor__host is added --- tests/test_testgres_common.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test_testgres_common.py b/tests/test_testgres_common.py index e48e0a8a..348b4aa0 100644 --- a/tests/test_testgres_common.py +++ b/tests/test_testgres_common.py @@ -132,7 +132,42 @@ def test_version_management(self, node_svc: PostgresNodeService): assert (isinstance(node.version, PgVer)) assert (node.version == PgVer(version)) + def test_node_constructor__host(self): + C_HOST = "AbCdE" + + unique_id = uuid.uuid4().hex + + node = PostgresNode( + host=C_HOST, + ) + assert node.host == C_HOST + assert isinstance(node.os_ops, OsOperations) + + tmpdir = node.os_ops.get_tempdir() + nodedir2 = node.os_ops.build_path(tmpdir, "node2--" + unique_id) + + C_NODE2_NAME = "node2" + + node2 = node.clone_with_new_name_and_base_dir( + name=C_NODE2_NAME, + base_dir=nodedir2, + ) + assert node2 is not None + assert node2 is not node + + assert node2.name == C_NODE2_NAME + assert node2.base_dir == nodedir2 + assert node2.host == C_HOST + assert node2.port != node.port + assert node2.os_ops is node.os_ops + assert node2.port_manager is node.port_manager + + assert node2.os_ops.path_exists(nodedir2) + return + def test_node_repr(self, node_svc: PostgresNodeService): + assert isinstance(node_svc, PostgresNodeService) + with __class__.helper__get_node(node_svc).init() as node: pattern = r"PostgresNode\(name='.+', port=.+, base_dir='.+'\)" assert re.match(pattern, str(node)) is not None From fdc41a780decb10ea832170ddb7988ffcd0de0f4 Mon Sep 17 00:00:00 2001 From: "d.kovalenko" Date: Sun, 7 Jun 2026 10:48:22 +0300 Subject: [PATCH 4/4] TestTestgresCommon::test_node_constructor__host is updated --- tests/test_testgres_common.py | 41 +++++++++++++++++------------------ 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/tests/test_testgres_common.py b/tests/test_testgres_common.py index 348b4aa0..855d24c8 100644 --- a/tests/test_testgres_common.py +++ b/tests/test_testgres_common.py @@ -137,32 +137,31 @@ def test_node_constructor__host(self): unique_id = uuid.uuid4().hex - node = PostgresNode( - host=C_HOST, - ) - assert node.host == C_HOST - assert isinstance(node.os_ops, OsOperations) + with PostgresNode(host=C_HOST) as node: + assert node._host == C_HOST + assert node.host == C_HOST + assert isinstance(node.os_ops, OsOperations) - tmpdir = node.os_ops.get_tempdir() - nodedir2 = node.os_ops.build_path(tmpdir, "node2--" + unique_id) + tmpdir = node.os_ops.get_tempdir() + nodedir2 = node.os_ops.build_path(tmpdir, "node2--" + unique_id) - C_NODE2_NAME = "node2" + C_NODE2_NAME = "node2" - node2 = node.clone_with_new_name_and_base_dir( - name=C_NODE2_NAME, - base_dir=nodedir2, - ) - assert node2 is not None - assert node2 is not node + with node.clone_with_new_name_and_base_dir( + name=C_NODE2_NAME, + base_dir=nodedir2, + ) as node2: + assert node2 is not None + assert node2 is not node - assert node2.name == C_NODE2_NAME - assert node2.base_dir == nodedir2 - assert node2.host == C_HOST - assert node2.port != node.port - assert node2.os_ops is node.os_ops - assert node2.port_manager is node.port_manager + assert node2._host == C_HOST + assert node2.host == C_HOST - assert node2.os_ops.path_exists(nodedir2) + assert node2._name == C_NODE2_NAME + assert node2._base_dir == nodedir2 + assert node2._port != node._port + assert node2._os_ops is node._os_ops + assert node2._port_manager is node._port_manager return def test_node_repr(self, node_svc: PostgresNodeService):