diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index ec709cb99..ac7c6b60a 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -11,7 +11,6 @@ steps: matrix: setup: python: - - "3.8" - "3.9" - "3.10" - "3.11" @@ -24,7 +23,7 @@ steps: - "test" adjustments: - with: - python: "3.8" + python: "3.9" connection: "urllib3" nox_session: "test_otel" - with: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52298bd59..0bc43d985 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] nox-session: [""] runs-on: ["ubuntu-latest"] diff --git a/docs/reference/getting-started.md b/docs/reference/getting-started.md index 54fce4ec3..7a5d82c16 100644 --- a/docs/reference/getting-started.md +++ b/docs/reference/getting-started.md @@ -11,7 +11,7 @@ This page guides you through the installation process of the Python client, show ### Requirements [_requirements] -* [Python](https://www.python.org/) 3.8 or newer +* [Python](https://www.python.org/) 3.9 or newer * [`pip`](https://pip.pypa.io/en/stable/), installed by default alongside Python diff --git a/elasticsearch/_otel.py b/elasticsearch/_otel.py index f37ca24cd..71a0702e7 100644 --- a/elasticsearch/_otel.py +++ b/elasticsearch/_otel.py @@ -67,7 +67,7 @@ def span( *, endpoint_id: str | None, path_parts: Mapping[str, str], - ) -> Generator[OpenTelemetrySpan, None, None]: + ) -> Generator[OpenTelemetrySpan]: if not self.enabled or self.tracer is None: yield OpenTelemetrySpan(None) return @@ -88,7 +88,7 @@ def span( ) @contextlib.contextmanager - def helpers_span(self, span_name: str) -> Generator[OpenTelemetrySpan, None, None]: + def helpers_span(self, span_name: str) -> Generator[OpenTelemetrySpan]: if not self.enabled or self.tracer is None: yield OpenTelemetrySpan(None) return @@ -101,7 +101,7 @@ def helpers_span(self, span_name: str) -> Generator[OpenTelemetrySpan, None, Non yield OpenTelemetrySpan(otel_span) @contextlib.contextmanager - def use_span(self, span: OpenTelemetrySpan) -> Generator[None, None, None]: + def use_span(self, span: OpenTelemetrySpan) -> Generator[None]: if not self.enabled or self.tracer is None or span.otel_span is None: yield return diff --git a/elasticsearch/dsl/document_base.py b/elasticsearch/dsl/document_base.py index b5e373741..2e4bfae3c 100644 --- a/elasticsearch/dsl/document_base.py +++ b/elasticsearch/dsl/document_base.py @@ -171,7 +171,7 @@ def __init__(self, name: str, bases: Tuple[type, ...], attrs: Dict[str, Any]): # # ignore attributes # field10: ClassVar[string] = "a regular class variable" annotations = attrs.get("__annotations__", {}) - fields = set([n for n in attrs if isinstance(attrs[n], Field)]) + fields = {n for n in attrs if isinstance(attrs[n], Field)} fields.update(annotations.keys()) field_defaults = {} for name in fields: diff --git a/examples/fastapi-apm/dockerfiles/Dockerfile.app b/examples/fastapi-apm/dockerfiles/Dockerfile.app index 47a52b894..40809ceba 100644 --- a/examples/fastapi-apm/dockerfiles/Dockerfile.app +++ b/examples/fastapi-apm/dockerfiles/Dockerfile.app @@ -1,4 +1,4 @@ -FROM python:3.8 +FROM python:3.9 EXPOSE 9292 WORKDIR / diff --git a/examples/fastapi-apm/dockerfiles/Dockerfile.ping b/examples/fastapi-apm/dockerfiles/Dockerfile.ping index 46b81cc78..97e24af2d 100644 --- a/examples/fastapi-apm/dockerfiles/Dockerfile.ping +++ b/examples/fastapi-apm/dockerfiles/Dockerfile.ping @@ -1,4 +1,4 @@ -FROM python:3.8 +FROM python:3.9 WORKDIR / RUN python -m pip install \ --no-cache \ diff --git a/noxfile.py b/noxfile.py index 66ee963e6..d5a6099e7 100644 --- a/noxfile.py +++ b/noxfile.py @@ -44,14 +44,14 @@ def pytest_argv(): ] -@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]) +@nox.session(python=["3.9", "3.10", "3.11", "3.12", "3.13"]) def test(session): session.install("-e", ".[dev]", env=INSTALL_ENV, silent=False) session.run(*pytest_argv(), *session.posargs) -@nox.session(python=["3.8", "3.13"]) +@nox.session(python=["3.9", "3.13"]) def test_otel(session): session.install( ".[dev]", diff --git a/pyproject.toml b/pyproject.toml index 0c66e2f50..845d52493 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "elasticsearch" description = "Python client for Elasticsearch" readme = "README.md" license = "Apache-2.0" -requires-python = ">=3.8" +requires-python = ">=3.9" authors = [ { name = "Elastic Client Library Maintainers", email = "client-libs@elastic.co" }, ] @@ -21,7 +21,6 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/test_elasticsearch/test_async/test_server/test_helpers.py b/test_elasticsearch/test_async/test_server/test_helpers.py index 0bb781304..a235784be 100644 --- a/test_elasticsearch/test_async/test_server/test_helpers.py +++ b/test_elasticsearch/test_async/test_server/test_helpers.py @@ -542,9 +542,10 @@ async def test_scroll_error(self, async_client, scan_teardown): bulk.append({"value": x}) await async_client.bulk(operations=bulk, refresh=True) - with patch.object( - async_client, "options", return_value=async_client - ), patch.object(async_client, "scroll", MockScroll()): + with ( + patch.object(async_client, "options", return_value=async_client), + patch.object(async_client, "scroll", MockScroll()), + ): data = [ x async for x in helpers.async_scan( @@ -558,9 +559,10 @@ async def test_scroll_error(self, async_client, scan_teardown): assert len(data) == 3 assert data[-1] == {"scroll_data": 42} - with patch.object( - async_client, "options", return_value=async_client - ), patch.object(async_client, "scroll", MockScroll()): + with ( + patch.object(async_client, "options", return_value=async_client), + patch.object(async_client, "scroll", MockScroll()), + ): with pytest.raises(ScanError): data = [ x @@ -576,9 +578,10 @@ async def test_scroll_error(self, async_client, scan_teardown): assert data[-1] == {"scroll_data": 42} async def test_initial_search_error(self, async_client, scan_teardown): - with patch.object( - async_client, "options", return_value=async_client - ), patch.object(async_client, "clear_scroll", new_callable=AsyncMock): + with ( + patch.object(async_client, "options", return_value=async_client), + patch.object(async_client, "clear_scroll", new_callable=AsyncMock), + ): with patch.object( async_client, "search", @@ -634,15 +637,16 @@ async def test_initial_search_error(self, async_client, scan_teardown): assert mock_scroll.calls == [] async def test_no_scroll_id_fast_route(self, async_client, scan_teardown): - with patch.object( - async_client, "options", return_value=async_client - ), patch.object(async_client, "scroll") as scroll_mock, patch.object( - async_client, - "search", - MockResponse(ObjectApiResponse(body={"no": "_scroll_id"}, meta=None)), - ), patch.object( - async_client, "clear_scroll" - ) as clear_mock: + with ( + patch.object(async_client, "options", return_value=async_client), + patch.object(async_client, "scroll") as scroll_mock, + patch.object( + async_client, + "search", + MockResponse(ObjectApiResponse(body={"no": "_scroll_id"}, meta=None)), + ), + patch.object(async_client, "clear_scroll") as clear_mock, + ): data = [ x async for x in helpers.async_scan(async_client, index="test_index") ] @@ -661,9 +665,10 @@ async def test_logger( bulk.append({"value": x}) await async_client.bulk(operations=bulk, refresh=True) - with patch.object( - async_client, "options", return_value=async_client - ), patch.object(async_client, "scroll", MockScroll()): + with ( + patch.object(async_client, "options", return_value=async_client), + patch.object(async_client, "scroll", MockScroll()), + ): _ = [ x async for x in helpers.async_scan( @@ -680,9 +685,10 @@ async def test_logger( ] caplog.clear() - with patch.object( - async_client, "options", return_value=async_client - ), patch.object(async_client, "scroll", MockScroll()): + with ( + patch.object(async_client, "options", return_value=async_client), + patch.object(async_client, "scroll", MockScroll()), + ): with pytest.raises(ScanError): _ = [ x @@ -706,11 +712,12 @@ async def test_clear_scroll(self, async_client, scan_teardown): bulk.append({"value": x}) await async_client.bulk(operations=bulk, refresh=True) - with patch.object( - async_client, "options", return_value=async_client - ), patch.object( - async_client, "clear_scroll", wraps=async_client.clear_scroll - ) as spy: + with ( + patch.object(async_client, "options", return_value=async_client), + patch.object( + async_client, "clear_scroll", wraps=async_client.clear_scroll + ) as spy, + ): _ = [ x async for x in helpers.async_scan( @@ -748,20 +755,21 @@ async def test_clear_scroll(self, async_client, scan_teardown): async def test_scan_auth_kwargs_forwarded( self, async_client, scan_teardown, kwargs ): - with patch.object( - async_client, "options", return_value=async_client - ) as options, patch.object( - async_client, - "search", - return_value=MockResponse( - ObjectApiResponse( - body={ - "_scroll_id": "scroll_id", - "_shards": {"successful": 5, "total": 5, "skipped": 0}, - "hits": {"hits": [{"search_data": 1}]}, - }, - meta=None, - ) + with ( + patch.object(async_client, "options", return_value=async_client) as options, + patch.object( + async_client, + "search", + return_value=MockResponse( + ObjectApiResponse( + body={ + "_scroll_id": "scroll_id", + "_shards": {"successful": 5, "total": 5, "skipped": 0}, + "hits": {"hits": [{"search_data": 1}]}, + }, + meta=None, + ) + ), ), ): with patch.object( @@ -801,20 +809,21 @@ async def test_scan_auth_kwargs_forwarded( async def test_scan_auth_kwargs_favor_scroll_kwargs_option( self, async_client, scan_teardown ): - with patch.object( - async_client, "options", return_value=async_client - ) as options, patch.object( - async_client, - "search", - return_value=MockResponse( - ObjectApiResponse( - body={ - "_scroll_id": "scroll_id", - "_shards": {"successful": 5, "total": 5, "skipped": 0}, - "hits": {"hits": [{"search_data": 1}]}, - }, - meta=None, - ) + with ( + patch.object(async_client, "options", return_value=async_client) as options, + patch.object( + async_client, + "search", + return_value=MockResponse( + ObjectApiResponse( + body={ + "_scroll_id": "scroll_id", + "_shards": {"successful": 5, "total": 5, "skipped": 0}, + "hits": {"hits": [{"search_data": 1}]}, + }, + meta=None, + ) + ), ), ): with patch.object( @@ -878,21 +887,23 @@ async def test_scan_auth_kwargs_favor_scroll_kwargs_option( ], ) async def test_scan_from_keyword_is_aliased(async_client, scan_kwargs): - with patch.object(async_client, "options", return_value=async_client), patch.object( - async_client, - "search", - return_value=MockResponse( - ObjectApiResponse( - body={ - "_scroll_id": "dummy_id", - "_shards": {"successful": 5, "total": 5}, - "hits": {"hits": []}, - }, - meta=None, - ) - ), - ) as search_mock, patch.object( - async_client, "clear_scroll", return_value=MockResponse(None) + with ( + patch.object(async_client, "options", return_value=async_client), + patch.object( + async_client, + "search", + return_value=MockResponse( + ObjectApiResponse( + body={ + "_scroll_id": "dummy_id", + "_shards": {"successful": 5, "total": 5}, + "hits": {"hits": []}, + }, + meta=None, + ) + ), + ) as search_mock, + patch.object(async_client, "clear_scroll", return_value=MockResponse(None)), ): [ x diff --git a/test_elasticsearch/test_server/test_helpers.py b/test_elasticsearch/test_server/test_helpers.py index 6ed43e2af..74b9f0ef8 100644 --- a/test_elasticsearch/test_server/test_helpers.py +++ b/test_elasticsearch/test_server/test_helpers.py @@ -515,9 +515,10 @@ def test_scroll_error(sync_client): bulk.append({"value": x}) sync_client.bulk(operations=bulk, refresh=True) - with patch.object(sync_client, "options", return_value=sync_client), patch.object( - sync_client, "scroll" - ) as scroll_mock: + with ( + patch.object(sync_client, "options", return_value=sync_client), + patch.object(sync_client, "scroll") as scroll_mock, + ): scroll_mock.side_effect = mock_scroll_responses data = list( helpers.scan( @@ -547,21 +548,25 @@ def test_scroll_error(sync_client): def test_initial_search_error(sync_client): - with patch.object( - sync_client, - "search", - return_value=ObjectApiResponse( - meta=None, - raw={ - "_scroll_id": "dummy_id", - "_shards": {"successful": 4, "total": 5, "skipped": 0}, - "hits": {"hits": [{"search_data": 1}]}, - }, + with ( + patch.object( + sync_client, + "search", + return_value=ObjectApiResponse( + meta=None, + raw={ + "_scroll_id": "dummy_id", + "_shards": {"successful": 4, "total": 5, "skipped": 0}, + "hits": {"hits": [{"search_data": 1}]}, + }, + ), ), - ), patch.object(sync_client, "options", return_value=sync_client): - with patch.object(sync_client, "scroll") as scroll_mock, patch.object( - sync_client, "clear_scroll" - ) as clear_scroll_mock: + patch.object(sync_client, "options", return_value=sync_client), + ): + with ( + patch.object(sync_client, "scroll") as scroll_mock, + patch.object(sync_client, "clear_scroll") as clear_scroll_mock, + ): scroll_mock.side_effect = mock_scroll_responses data = list( helpers.scan( @@ -579,9 +584,10 @@ def test_initial_search_error(sync_client): scroll_id="dummy_id", ) - with patch.object(sync_client, "scroll") as scroll_mock, patch.object( - sync_client, "clear_scroll" - ) as clear_scroll_mock: + with ( + patch.object(sync_client, "scroll") as scroll_mock, + patch.object(sync_client, "clear_scroll") as clear_scroll_mock, + ): scroll_mock.side_effect = mock_scroll_responses with pytest.raises(ScanError): data = list( @@ -599,15 +605,16 @@ def test_initial_search_error(sync_client): def test_no_scroll_id_fast_route(sync_client): - with patch.object( - sync_client, - "search", - return_value=ObjectApiResponse(meta=None, raw={"no": "_scroll_id"}), - ) as search_mock, patch.object(sync_client, "scroll") as scroll_mock, patch.object( - sync_client, "clear_scroll" - ) as clear_scroll_mock, patch.object( - sync_client, "options", return_value=sync_client - ) as options: + with ( + patch.object( + sync_client, + "search", + return_value=ObjectApiResponse(meta=None, raw={"no": "_scroll_id"}), + ) as search_mock, + patch.object(sync_client, "scroll") as scroll_mock, + patch.object(sync_client, "clear_scroll") as clear_scroll_mock, + patch.object(sync_client, "options", return_value=sync_client) as options, + ): data = list(helpers.scan(sync_client, index="test_index")) assert data == [] @@ -636,32 +643,37 @@ def test_no_scroll_id_fast_route(sync_client): def test_scan_auth_kwargs_forwarded(sync_client, kwargs): ((key, val),) = kwargs.items() - with patch.object( - sync_client, "options", return_value=sync_client - ) as options, patch.object( - sync_client, - "search", - return_value=ObjectApiResponse( - meta=None, - raw={ - "_scroll_id": "scroll_id", - "_shards": {"successful": 5, "total": 5, "skipped": 0}, - "hits": {"hits": [{"search_data": 1}]}, - }, + with ( + patch.object(sync_client, "options", return_value=sync_client) as options, + patch.object( + sync_client, + "search", + return_value=ObjectApiResponse( + meta=None, + raw={ + "_scroll_id": "scroll_id", + "_shards": {"successful": 5, "total": 5, "skipped": 0}, + "hits": {"hits": [{"search_data": 1}]}, + }, + ), ), - ), patch.object( - sync_client, - "scroll", - return_value=ObjectApiResponse( - meta=None, - raw={ - "_scroll_id": "scroll_id", - "_shards": {"successful": 5, "total": 5, "skipped": 0}, - "hits": {"hits": []}, - }, + patch.object( + sync_client, + "scroll", + return_value=ObjectApiResponse( + meta=None, + raw={ + "_scroll_id": "scroll_id", + "_shards": {"successful": 5, "total": 5, "skipped": 0}, + "hits": {"hits": []}, + }, + ), + ), + patch.object( + sync_client, + "clear_scroll", + return_value=ObjectApiResponse(meta=None, raw={}), ), - ), patch.object( - sync_client, "clear_scroll", return_value=ObjectApiResponse(meta=None, raw={}) ): data = list(helpers.scan(sync_client, index="test_index", **kwargs)) @@ -676,32 +688,37 @@ def test_scan_auth_kwargs_forwarded(sync_client, kwargs): def test_scan_auth_kwargs_favor_scroll_kwargs_option(sync_client): - with patch.object( - sync_client, "options", return_value=sync_client - ) as options_mock, patch.object( - sync_client, - "search", - return_value=ObjectApiResponse( - raw={ - "_scroll_id": "scroll_id", - "_shards": {"successful": 5, "total": 5, "skipped": 0}, - "hits": {"hits": [{"search_data": 1}]}, - }, - meta=None, - ), - ) as search_mock, patch.object( - sync_client, - "scroll", - return_value=ObjectApiResponse( - raw={ - "_scroll_id": "scroll_id", - "_shards": {"successful": 5, "total": 5, "skipped": 0}, - "hits": {"hits": []}, - }, - meta=None, + with ( + patch.object(sync_client, "options", return_value=sync_client) as options_mock, + patch.object( + sync_client, + "search", + return_value=ObjectApiResponse( + raw={ + "_scroll_id": "scroll_id", + "_shards": {"successful": 5, "total": 5, "skipped": 0}, + "hits": {"hits": [{"search_data": 1}]}, + }, + meta=None, + ), + ) as search_mock, + patch.object( + sync_client, + "scroll", + return_value=ObjectApiResponse( + raw={ + "_scroll_id": "scroll_id", + "_shards": {"successful": 5, "total": 5, "skipped": 0}, + "hits": {"hits": []}, + }, + meta=None, + ), + ) as scroll_mock, + patch.object( + sync_client, + "clear_scroll", + return_value=ObjectApiResponse(raw={}, meta=None), ), - ) as scroll_mock, patch.object( - sync_client, "clear_scroll", return_value=ObjectApiResponse(raw={}, meta=None) ): data = list( helpers.scan( @@ -735,9 +752,11 @@ def test_log_warning_on_shard_failures(sync_client): bulk.append({"value": x}) sync_client.bulk(operations=bulk, refresh=True) - with patch("elasticsearch.helpers.actions.logger") as logger_mock, patch.object( - sync_client, "options", return_value=sync_client - ), patch.object(sync_client, "scroll") as scroll_mock: + with ( + patch("elasticsearch.helpers.actions.logger") as logger_mock, + patch.object(sync_client, "options", return_value=sync_client), + patch.object(sync_client, "scroll") as scroll_mock, + ): scroll_mock.side_effect = mock_scroll_responses list( helpers.scan( @@ -773,9 +792,12 @@ def test_clear_scroll(sync_client): bulk.append({"value": x}) sync_client.bulk(operations=bulk, refresh=True) - with patch.object(sync_client, "options", return_value=sync_client), patch.object( - sync_client, "clear_scroll", wraps=sync_client.clear_scroll - ) as clear_scroll_mock: + with ( + patch.object(sync_client, "options", return_value=sync_client), + patch.object( + sync_client, "clear_scroll", wraps=sync_client.clear_scroll + ) as clear_scroll_mock, + ): list(helpers.scan(sync_client, index="test_index", size=2)) clear_scroll_mock.assert_called_once() @@ -790,19 +812,22 @@ def test_clear_scroll(sync_client): def test_shards_no_skipped_field(sync_client): # Test that scan doesn't fail if 'hits.skipped' isn't available. - with patch.object(sync_client, "options", return_value=sync_client), patch.object( - sync_client, - "search", - return_value=ObjectApiResponse( - raw={ - "_scroll_id": "dummy_id", - "_shards": {"successful": 5, "total": 5}, - "hits": {"hits": [{"search_data": 1}]}, - }, - meta=None, + with ( + patch.object(sync_client, "options", return_value=sync_client), + patch.object( + sync_client, + "search", + return_value=ObjectApiResponse( + raw={ + "_scroll_id": "dummy_id", + "_shards": {"successful": 5, "total": 5}, + "hits": {"hits": [{"search_data": 1}]}, + }, + meta=None, + ), ), - ), patch.object(sync_client, "scroll") as scroll_mock, patch.object( - sync_client, "clear_scroll" + patch.object(sync_client, "scroll") as scroll_mock, + patch.object(sync_client, "clear_scroll"), ): scroll_mock.side_effect = [ ObjectApiResponse( @@ -841,18 +866,22 @@ def test_shards_no_skipped_field(sync_client): ], ) def test_scan_from_keyword_is_aliased(sync_client, scan_kwargs): - with patch.object(sync_client, "options", return_value=sync_client), patch.object( - sync_client, - "search", - return_value=ObjectApiResponse( - raw={ - "_scroll_id": "dummy_id", - "_shards": {"successful": 5, "total": 5}, - "hits": {"hits": []}, - }, - meta=None, - ), - ) as search_mock, patch.object(sync_client, "clear_scroll"): + with ( + patch.object(sync_client, "options", return_value=sync_client), + patch.object( + sync_client, + "search", + return_value=ObjectApiResponse( + raw={ + "_scroll_id": "dummy_id", + "_shards": {"successful": 5, "total": 5}, + "hits": {"hits": []}, + }, + meta=None, + ), + ) as search_mock, + patch.object(sync_client, "clear_scroll"), + ): list(helpers.scan(sync_client, index="test_index", **scan_kwargs)) assert search_mock.call_args[1]["from_"] == 1 assert "from" not in search_mock.call_args[1] diff --git a/utils/dsl-generator.py b/utils/dsl-generator.py index f18991dfc..196c2d6bf 100644 --- a/utils/dsl-generator.py +++ b/utils/dsl-generator.py @@ -333,8 +333,7 @@ def get_python_type(self, schema_type, for_response=False): if schema_type["name"]["name"].endswith("RangeQuery"): return '"wrappers.Range[Any]"', None elif schema_type["name"]["name"].endswith("ScoreFunction"): - # When dropping Python 3.8, use `removesuffix("Function")` instead - name = schema_type["name"]["name"][:-8] + name = schema_type["name"]["name"].removesuffix("Function") return f'"function.{name}"', None elif schema_type["name"]["name"].endswith("DecayFunction"): return '"function.DecayFunction"', None @@ -928,7 +927,7 @@ def generate_field_py(schema, filename): ), ) - with open(filename, "wt") as f: + with open(filename, "w") as f: f.write(field_py.render(classes=classes)) print(f"Generated {filename}.") @@ -942,7 +941,7 @@ def generate_query_py(schema, filename): for p in query_container["properties"]: classes += schema.property_to_python_class(p) - with open(filename, "wt") as f: + with open(filename, "w") as f: f.write(query_py.render(classes=classes, parent="Query")) print(f"Generated {filename}.") @@ -957,7 +956,7 @@ def generate_aggs_py(schema, filename): if "containerProperty" not in p or not p["containerProperty"]: classes += schema.property_to_python_class(p) - with open(filename, "wt") as f: + with open(filename, "w") as f: f.write(aggs_py.render(classes=classes, parent="Agg")) print(f"Generated {filename}.") @@ -978,7 +977,7 @@ def generate_response_init_py(schema, filename): for_types_py=False, for_response=True, ) - with open(filename, "wt") as f: + with open(filename, "w") as f: f.write( response_init_py.render(response=search_response, ubq_response=ubq_response) ) @@ -1009,7 +1008,7 @@ def generate_types_py(schema, filename): continue classes_list.append(k) - with open(filename, "wt") as f: + with open(filename, "w") as f: f.write(types_py.render(classes=classes_list)) print(f"Generated {filename}.")