From cf427e8b0b0da4d0e456f960f66d8a9e51b87886 Mon Sep 17 00:00:00 2001 From: Alexander Kukushkin Date: Wed, 19 Feb 2025 17:04:19 +0100 Subject: [PATCH] Bump pyright to 1.1.394 (#3283) --- .github/workflows/tests.yaml | 6 +++--- patroni/api.py | 7 +++++-- patroni/config_generator.py | 6 ++++-- patroni/dcs/etcd.py | 7 +++++-- patroni/postgresql/config.py | 3 ++- patroni/validator.py | 7 +++++-- pyrightconfig.json | 2 +- tests/test_config_generator.py | 5 ++++- 8 files changed, 29 insertions(+), 14 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index e2ad5765..eceef1fc 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -188,17 +188,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Python 3.12 + - name: Set up Python 3.13 uses: actions/setup-python@v5 with: - python-version: 3.12 + python-version: 3.13 - name: Install dependencies run: python -m pip install -r requirements.txt psycopg2-binary psycopg - uses: jakebailey/pyright-action@v2 with: - version: 1.1.391 + version: 1.1.394 ydiff: name: Test compatibility with the latest version of ydiff diff --git a/patroni/api.py b/patroni/api.py index 678e4cd1..73d9b1c9 100644 --- a/patroni/api.py +++ b/patroni/api.py @@ -1609,13 +1609,16 @@ class RestApiServer(ThreadingMixIn, HTTPServer, Thread): if hostname in ('', '*'): hostname = None - info = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) + # Filter out unexpected results when python is compiled with --disable-ipv6 and running on IPv6 system. + info = [(a[0], a[4][0], a[4][1]) + for a in socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) + if isinstance(a[4][0], str) and isinstance(a[4][1], int)] # in case dual stack is not supported we want IPv4 to be preferred over IPv6 info.sort(key=lambda x: x[0] == socket.AF_INET, reverse=not dual_stack) self.address_family = info[0][0] try: - HTTPServer.__init__(self, info[0][-1][:2], RestApiHandler) + HTTPServer.__init__(self, (info[0][1], info[0][2]), RestApiHandler) except socket.error: logger.error( "Couldn't start a service on '%s:%s', please check your `restapi.listen` configuration", hostname, port) diff --git a/patroni/config_generator.py b/patroni/config_generator.py index 6cf8a90f..d44395ca 100644 --- a/patroni/config_generator.py +++ b/patroni/config_generator.py @@ -59,8 +59,10 @@ def get_address() -> Tuple[str, str]: hostname = None try: hostname = socket.gethostname() - return hostname, sorted(socket.getaddrinfo(hostname, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0), - key=lambda x: x[0])[0][4][0] + # Filter out unexpected results when python is compiled with --disable-ipv6 and running on IPv6 system. + addrs = [(a[0], a[4][0]) for a in socket.getaddrinfo(hostname, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0) + if isinstance(a[4][0], str)] + return hostname, sorted(addrs, key=lambda x: x[0])[0][1] except Exception as err: logging.warning('Failed to obtain address: %r', err) return NO_VALUE_MSG, NO_VALUE_MSG diff --git a/patroni/dcs/etcd.py b/patroni/dcs/etcd.py index 5b9365a8..a5b55e7e 100644 --- a/patroni/dcs/etcd.py +++ b/patroni/dcs/etcd.py @@ -45,7 +45,8 @@ class EtcdError(DCSError): pass -_AddrInfo = Tuple[socket.AddressFamily, socket.SocketKind, int, str, Union[Tuple[str, int], Tuple[str, int, int, int]]] +_AddrInfo = Tuple[socket.AddressFamily, socket.SocketKind, int, str, + Union[Tuple[str, int], Tuple[str, int, int, int], Tuple[int, bytes]]] class DnsCachingResolver(Thread): @@ -350,7 +351,9 @@ class AbstractEtcdClientWithFailover(abc.ABC, etcd.Client): def _get_machines_cache_from_dns(self, host: str, port: int) -> List[str]: """One host might be resolved into multiple ip addresses. We will make list out of it""" if self.protocol == 'http': - ret = [uri(self.protocol, res[-1][:2]) for res in self._dns_resolver.resolve(host, port)] + # Filter out unexpected results when python is compiled with --disable-ipv6 and running on IPv6 system. + ret = [uri(self.protocol, (res[4][0], res[4][1])) for res in self._dns_resolver.resolve(host, port) + if isinstance(res[4][0], str) and isinstance(res[4][1], int)] if ret: return list(set(ret)) return [uri(self.protocol, (host, port))] diff --git a/patroni/postgresql/config.py b/patroni/postgresql/config.py index df137e00..fbb7a4cb 100644 --- a/patroni/postgresql/config.py +++ b/patroni/postgresql/config.py @@ -593,7 +593,8 @@ class ConfigHandler(object): if 'host' in self.local_replication_address and not self.local_replication_address['host'].startswith('/'): addresses.update({sa[0] + '/32': 'host' for _, _, _, _, sa in socket.getaddrinfo( self.local_replication_address['host'], self.local_replication_address['port'], - 0, socket.SOCK_STREAM, socket.IPPROTO_TCP)}) + 0, socket.SOCK_STREAM, socket.IPPROTO_TCP) if isinstance(sa[0], str)}) + # Filter out unexpected results when python is compiled with --disable-ipv6 and running on IPv6 system. with self.config_writer(self._pg_hba_conf) as f: for address, t in addresses.items(): diff --git a/patroni/validator.py b/patroni/validator.py index e493408c..781bed9d 100644 --- a/patroni/validator.py +++ b/patroni/validator.py @@ -138,11 +138,14 @@ def validate_host_port(host_port: str, listen: bool = False, multiple_hosts: boo hosts = hosts.split(",") else: hosts = [hosts] + + # If host is set to "*" get all hostnames and/or IP addresses that the host would be able to listen to if "*" in hosts: if len(hosts) != 1: raise ConfigParseError("expecting '*' alone") - # If host is set to "*" get all hostnames and/or IP addresses that the host would be able to listen to - hosts = [p[-1][0] for p in socket.getaddrinfo(None, port, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)] + # Filter out unexpected results when python is compiled with --disable-ipv6 and running on IPv6 system. + hosts = [a[4][0] for a in socket.getaddrinfo(None, port, 0, socket.SOCK_STREAM, 0, socket.AI_PASSIVE) + if isinstance(a[4][0], str)] for host in hosts: # Check if "socket.IF_INET" or "socket.IF_INET6" is being used and instantiate a socket with the identified # protocol diff --git a/pyrightconfig.json b/pyrightconfig.json index 4ccc9a9e..ba415795 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -19,7 +19,7 @@ "reportMissingImports": true, "reportMissingTypeStubs": false, - "pythonVersion": "3.12", + "pythonVersion": "3.13", "pythonPlatform": "All", "typeCheckingMode": "strict" diff --git a/tests/test_config_generator.py b/tests/test_config_generator.py index dd1bd5ef..197531ec 100644 --- a/tests/test_config_generator.py +++ b/tests/test_config_generator.py @@ -352,7 +352,10 @@ class TestGenerateConfig(unittest.TestCase): self.assertIn('Unexpected exception', e.exception.code) def test_get_address(self): - with patch('socket.getaddrinfo', Mock(side_effect=Exception)), \ + with patch('socket.getaddrinfo', Mock(side_effect=[[(2, 1, 6, '', ('127.0.0.1', 0))], + Exception])), \ + patch('socket.gethostname', Mock(return_value='foo')), \ patch('logging.warning') as mock_warning: + self.assertEqual(get_address(), ('foo', '127.0.0.1')) self.assertEqual(get_address(), (NO_VALUE_MSG, NO_VALUE_MSG)) self.assertIn('Failed to obtain address: %r', mock_warning.call_args_list[0][0])