From 6b7ec49282ba2342a1e5ddeb0f3387c2c0684ad6 Mon Sep 17 00:00:00 2001 From: Polina Bungina <27892524+hughcapet@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:45:10 +0200 Subject: [PATCH] Release v3.3.1 (#3087) * Update release notes * Bump version * Bump pyright version and solve reported issues --------- Co-authored-by: Alexander Kukushkin --- .github/workflows/tests.yaml | 2 +- docs/releases.rst | 27 +++++++++++++++++++++++++++ patroni/log.py | 22 ++++++++++++++++------ patroni/postgresql/config.py | 3 ++- patroni/postgresql/mpp/citus.py | 3 ++- patroni/version.py | 2 +- pyrightconfig.json | 2 +- tests/test_log.py | 2 +- 8 files changed, 51 insertions(+), 12 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 37b94f9c6..c2f96b4da 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -186,7 +186,7 @@ jobs: - uses: jakebailey/pyright-action@v2 with: - version: 1.1.356 + version: 1.1.367 docs: runs-on: ubuntu-latest diff --git a/docs/releases.rst b/docs/releases.rst index 571048941..c0fedf85b 100644 --- a/docs/releases.rst +++ b/docs/releases.rst @@ -3,6 +3,33 @@ Release notes ============= +Version 3.3.1 +------------- + +Released 2024-06-17 + +**Stability improvements** + +- Compatibility with Python 3.12 (Alexander Kukushkin) + + Handle a new attribute added to ``logging.LogRecord``. + + +**Bugfixes** + +- Fix infinite recursion in ``replicatefrom`` tags handling (Alexander Kukushkin) + + As a part of this fix, also improve ``is_physical_slot()`` check and adjust documentation. + +- Fix wrong role reporting in standby clusters (Alexander Kukushkin) + +`synchronous_standby_names` and synchronous replication only work on a real primary node and in the case of cascading replication are simply ignored by Postgres. Before this fix, `patronictl list` and `GET /cluster` were falsely reporting some nodes as synchronous. + +- Fix availability of the ``allow_in_place_tablespaces`` GUC (Polina Bungina) + + ``allow_in_place_tablespaces`` was not only added to PostgreSQL 15 but also backpatched to PostgreSQL 10-14. + + Version 3.3.0 ------------- diff --git a/patroni/log.py b/patroni/log.py index 3a7b55e77..2f383b0c3 100644 --- a/patroni/log.py +++ b/patroni/log.py @@ -62,6 +62,15 @@ def error_exception(self: logging.Logger, msg: object, *args: Any, **kwargs: Any self.error(msg, *args, exc_info=exc_info, **kwargs) +def _type(value: Any) -> str: + """Get type of the *value*. + + :param value: any arbitrary value. + :returns: a string with a type name. + """ + return value.__class__.__name__ + + class QueueHandler(logging.Handler): """Queue-based logging handler. @@ -292,7 +301,7 @@ def _get_plain_formatter(self, logformat: type_logformat, dateformat: Optional[s """ if not isinstance(logformat, str): - _LOGGER.warning('Expected log format to be a string when log type is plain, but got "%s"', type(logformat)) + _LOGGER.warning('Expected log format to be a string when log type is plain, but got "%s"', _type(logformat)) logformat = PatroniLogger.DEFAULT_FORMAT return logging.Formatter(logformat, dateformat) @@ -330,13 +339,13 @@ def _get_json_formatter(self, logformat: type_logformat, dateformat: Optional[st else: _LOGGER.warning( 'Expected renamed log field to be a string, but got "%s"', - type(renamed_field) + _type(renamed_field) ) else: _LOGGER.warning( 'Expected each item of log format to be a string or dictionary, but got "%s"', - type(field) + _type(field) ) if len(log_fields) > 0: @@ -346,11 +355,12 @@ def _get_json_formatter(self, logformat: type_logformat, dateformat: Optional[st else: jsonformat = PatroniLogger.DEFAULT_FORMAT rename_fields = {} - _LOGGER.warning('Expected log format to be a string or a list, but got "%s"', type(logformat)) + _LOGGER.warning('Expected log format to be a string or a list, but got "%s"', _type(logformat)) try: from pythonjsonlogger import jsonlogger - if hasattr(jsonlogger, 'RESERVED_ATTRS') and 'taskName' not in jsonlogger.RESERVED_ATTRS: + if hasattr(jsonlogger, 'RESERVED_ATTRS') \ + and 'taskName' not in jsonlogger.RESERVED_ATTRS: # pyright: ignore [reportUnnecessaryContains] # compatibility with python 3.12, that added a new attribute to LogRecord jsonlogger.RESERVED_ATTRS += ('taskName',) @@ -380,7 +390,7 @@ def _get_formatter(self, config: Dict[str, Any]) -> logging.Formatter: static_fields = config.get('static_fields', {}) if dateformat is not None and not isinstance(dateformat, str): - _LOGGER.warning('Expected log dateformat to be a string, but got "%s"', type(dateformat)) + _LOGGER.warning('Expected log dateformat to be a string, but got "%s"', _type(dateformat)) dateformat = None if logtype == 'json': diff --git a/patroni/postgresql/config.py b/patroni/postgresql/config.py index 046e66079..77d31cb60 100644 --- a/patroni/postgresql/config.py +++ b/patroni/postgresql/config.py @@ -893,7 +893,8 @@ def escape(value: Any) -> str: return re.sub(r'([:\\])', r'\\\1', str(value)) # 'host' could be several comma-separated hostnames, in this case we need to write on pgpass line per host - hosts = map(escape, filter(None, map(str.strip, (record.get('host') or '*').split(',')))) + hosts = map(escape, filter(None, map(str.strip, + (record.get('host', '') or '*').split(',')))) # pyright: ignore [reportUnknownArgumentType] record = {n: escape(record.get(n) or '*') for n in ('port', 'user', 'password')} return '\n'.join('{host}:{port}:*:{user}:{password}'.format(**record, host=host) for host in hosts) diff --git a/patroni/postgresql/mpp/citus.py b/patroni/postgresql/mpp/citus.py index 295537df7..e287ea67b 100644 --- a/patroni/postgresql/mpp/citus.py +++ b/patroni/postgresql/mpp/citus.py @@ -428,7 +428,8 @@ def adjust_postgres_gucs(self, parameters: Dict[str, Any]) -> None: # citus extension must be on the first place in shared_preload_libraries shared_preload_libraries = list(filter( lambda el: el and el != 'citus', - [p.strip() for p in parameters.get('shared_preload_libraries', '').split(',')])) + map(str.strip, parameters.get('shared_preload_libraries', '').split(','))) + ) # pyright: ignore [reportUnknownArgumentType] parameters['shared_preload_libraries'] = ','.join(['citus'] + shared_preload_libraries) # if not explicitly set Citus overrides max_prepared_transactions to max_connections*2 diff --git a/patroni/version.py b/patroni/version.py index 46b5acc04..c8c040845 100644 --- a/patroni/version.py +++ b/patroni/version.py @@ -2,4 +2,4 @@ :var __version__: the current Patroni version. """ -__version__ = '3.3.0' +__version__ = '3.3.1' diff --git a/pyrightconfig.json b/pyrightconfig.json index 91bed7137..4ccc9a9e7 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -19,7 +19,7 @@ "reportMissingImports": true, "reportMissingTypeStubs": false, - "pythonVersion": "3.11", + "pythonVersion": "3.12", "pythonPlatform": "All", "typeCheckingMode": "strict" diff --git a/tests/test_log.py b/tests/test_log.py index 90f3deff4..3d4e79ab7 100644 --- a/tests/test_log.py +++ b/tests/test_log.py @@ -187,7 +187,7 @@ def test_invalid_dateformat(self): self.assertEqual(captured_log_level, 'WARNING') self.assertRegex( captured_log_message, - fr'Expected log dateformat to be a string, but got "{type(config["dateformat"])}"' + r'Expected log dateformat to be a string, but got "int"' ) def test_invalid_plain_format(self):