diff --git a/.github/actions/update-docs/action.yml b/.github/actions/update-docs/action.yml index 7ad9ab442..c748666bf 100644 --- a/.github/actions/update-docs/action.yml +++ b/.github/actions/update-docs/action.yml @@ -27,8 +27,8 @@ runs: - name: Install Python and set up Poetry uses: bakdata/ci-templates/actions/python-setup-poetry@v1.5.2 with: + python-version: "3.11" poetry-version: "1.5.1" - python-version: "3.10" - name: Install docs dependencies shell: bash diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c7f214209..3b8b2f627 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,7 +21,7 @@ jobs: os: - ubuntu-22.04 - windows-2022 - python-version: ["3.10", "3.11", "3.12"] + python-version: ["3.11", "3.12"] runs-on: ${{ matrix.os }} steps: @@ -32,8 +32,8 @@ jobs: - name: Install Python and set up Poetry uses: bakdata/ci-templates/actions/python-setup-poetry@v1.5.3 with: - poetry-version: "1.7.1" python-version: ${{ matrix.python-version }} + poetry-version: "1.7.1" - name: Check Poetry lock file consistency run: poetry lock --check @@ -43,7 +43,7 @@ jobs: - name: Lint (ruff) run: | - if [[ "$RUNNER_OS" == "Linux" && "${{ matrix.python-version }}" == "3.10" ]] + if [[ "$RUNNER_OS" == "Linux" && "${{ matrix.python-version }}" == "3.11" ]] then poetry run ruff check . --config pyproject.toml --output-format=github --no-fix else @@ -55,7 +55,7 @@ jobs: - name: Typing (pyright) run: | - if [[ "$RUNNER_OS" == "Linux" && "${{ matrix.python-version }}" == "3.10" ]] + if [[ "$RUNNER_OS" == "Linux" && "${{ matrix.python-version }}" == "3.11" ]] then echo "::add-matcher::.github/pyright-matcher.json" poetry run pre-commit run pyright --all-files @@ -93,6 +93,7 @@ jobs: needs: [test] uses: bakdata/ci-templates/.github/workflows/python-poetry-publish-snapshot.yaml@1.40.4 with: + python-version: "3.11" poetry-version: "1.7.1" secrets: pypi-token: ${{ secrets.TEST_PYPI_TOKEN }} diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index fd66ef0cd..1a9d4a2df 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -9,6 +9,7 @@ jobs: uses: bakdata/ci-templates/.github/workflows/python-poetry-publish-pypi.yaml@1.40.4 with: publish-to-test: false + python-version: "3.11" poetry-version: "1.7.1" secrets: pypi-token: "${{ secrets.PYPI_TOKEN }}" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 88a40d1c8..3acaeccd7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -19,6 +19,7 @@ jobs: name: Release with: release-type: ${{ inputs.release-type }} + python-version: "3.11" poetry-version: "1.7.1" changelog: true changelog-config: "./.github/changelog-config.json" diff --git a/hooks/gen_docs/__init__.py b/hooks/gen_docs/__init__.py index 5a0d63a28..fda5d4d19 100644 --- a/hooks/gen_docs/__init__.py +++ b/hooks/gen_docs/__init__.py @@ -1,10 +1,10 @@ """Documentation generation.""" from collections.abc import Iterator -from enum import Enum +from enum import StrEnum -class IterableStrEnum(str, Enum): +class IterableStrEnum(StrEnum): """Polyfill that also introduces dict-like behavior. Introduces constructors that return a ``Iterator`` object diff --git a/hooks/gen_docs/gen_docs_env_vars.py b/hooks/gen_docs/gen_docs_env_vars.py index 4b1297d0c..3b3e02a56 100644 --- a/hooks/gen_docs/gen_docs_env_vars.py +++ b/hooks/gen_docs/gen_docs_env_vars.py @@ -9,7 +9,7 @@ from dataclasses import dataclass from pathlib import Path from textwrap import fill -from typing import Any +from typing import Any, Self from pydantic_core import PydanticUndefined from pytablewriter import MarkdownTableWriter @@ -70,9 +70,7 @@ class EnvVar: corresponding_setting_name: str | None @classmethod - def from_record( - cls, record: dict[str, Any] - ) -> EnvVar: # TODO: typing.Self for Python 3.11+ + def from_record(cls, record: dict[str, Any]) -> Self: """Construct an ``EnvVar`` instance from a specific dict. Reads a dict that contains keys equivalent to the diff --git a/kpops/api/options.py b/kpops/api/options.py index 22fda2542..19c352e1a 100644 --- a/kpops/api/options.py +++ b/kpops/api/options.py @@ -1,6 +1,6 @@ from __future__ import annotations -from enum import Enum +from enum import StrEnum from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -8,7 +8,7 @@ from kpops.pipeline import ComponentFilterPredicate -class FilterType(str, Enum): +class FilterType(StrEnum): INCLUDE = "include" EXCLUDE = "exclude" diff --git a/kpops/component_handlers/kafka_connect/kafka_connect_handler.py b/kpops/component_handlers/kafka_connect/kafka_connect_handler.py index dcfd41b75..3cd27c867 100644 --- a/kpops/component_handlers/kafka_connect/kafka_connect_handler.py +++ b/kpops/component_handlers/kafka_connect/kafka_connect_handler.py @@ -1,7 +1,7 @@ from __future__ import annotations import logging -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Self from kpops.component_handlers.kafka_connect.connect_wrapper import ConnectWrapper from kpops.component_handlers.kafka_connect.exception import ( @@ -12,11 +12,6 @@ from kpops.utils.dict_differ import render_diff if TYPE_CHECKING: - try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] - except ImportError: - from typing_extensions import Self - from kpops.component_handlers.kafka_connect.model import KafkaConnectorConfig from kpops.config import KpopsConfig diff --git a/kpops/component_handlers/kafka_connect/model.py b/kpops/component_handlers/kafka_connect/model.py index 93ff76043..d975deaba 100644 --- a/kpops/component_handlers/kafka_connect/model.py +++ b/kpops/component_handlers/kafka_connect/model.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import Any import pydantic @@ -21,7 +21,7 @@ ) -class KafkaConnectorType(str, Enum): +class KafkaConnectorType(StrEnum): SINK = "sink" SOURCE = "source" diff --git a/kpops/component_handlers/topic/model.py b/kpops/component_handlers/topic/model.py index 5c0cf024d..db1fcf7fa 100644 --- a/kpops/component_handlers/topic/model.py +++ b/kpops/component_handlers/topic/model.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import Any from pydantic import BaseModel, ConfigDict @@ -28,7 +28,7 @@ class TopicResponse(BaseModel): ) -class KafkaTopicConfigSource(str, Enum): +class KafkaTopicConfigSource(StrEnum): DYNAMIC_TOPIC_CONFIG = "DYNAMIC_TOPIC_CONFIG" DEFAULT_CONFIG = "DEFAULT_CONFIG" STATIC_BROKER_CONFIG = "STATIC_BROKER_CONFIG" @@ -68,7 +68,7 @@ class TopicConfigResponse(BaseModel): ) -class KafkaBrokerConfigSource(str, Enum): +class KafkaBrokerConfigSource(StrEnum): STATIC_BROKER_CONFIG = "STATIC_BROKER_CONFIG" DYNAMIC_BROKER_CONFIG = "DYNAMIC_BROKER_CONFIG" DEFAULT_CONFIG = "DEFAULT_CONFIG" diff --git a/kpops/components/base_components/base_defaults_component.py b/kpops/components/base_components/base_defaults_component.py index 89b8d212c..06ce7702d 100644 --- a/kpops/components/base_components/base_defaults_component.py +++ b/kpops/components/base_components/base_defaults_component.py @@ -7,7 +7,7 @@ from dataclasses import asdict from functools import cached_property from pathlib import Path -from typing import Any, TypeVar +from typing import Any, Self, TypeVar import pydantic import typer @@ -34,11 +34,6 @@ from kpops.utils.types import JsonType from kpops.utils.yaml import load_yaml_file, substitute_nested -try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] -except ImportError: - from typing_extensions import Self - log = logging.getLogger("BaseDefaultsComponent") diff --git a/kpops/components/base_components/kafka_connector.py b/kpops/components/base_components/kafka_connector.py index 5453c004b..731032879 100644 --- a/kpops/components/base_components/kafka_connector.py +++ b/kpops/components/base_components/kafka_connector.py @@ -3,7 +3,7 @@ import logging from abc import ABC from functools import cached_property -from typing import Any, Literal, NoReturn +from typing import Any, Literal, NoReturn, Self import pydantic from pydantic import Field, PrivateAttr, ValidationInfo, computed_field, field_validator @@ -27,11 +27,6 @@ from kpops.utils.docstring import describe_attr from kpops.utils.pydantic import CamelCaseConfigModel -try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] -except ImportError: - from typing_extensions import Self - log = logging.getLogger("KafkaConnector") diff --git a/kpops/components/base_components/models/from_section.py b/kpops/components/base_components/models/from_section.py index df6d7bd1e..aefa0c252 100644 --- a/kpops/components/base_components/models/from_section.py +++ b/kpops/components/base_components/models/from_section.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import StrEnum from typing import Any, NewType from pydantic import ConfigDict, Field, model_validator @@ -8,7 +8,7 @@ from kpops.utils.pydantic import DescConfigModel -class InputTopicTypes(str, Enum): +class InputTopicTypes(StrEnum): """Input topic types. - INPUT: input topic diff --git a/kpops/components/common/topic.py b/kpops/components/common/topic.py index 94dd7838e..ec0f99170 100644 --- a/kpops/components/common/topic.py +++ b/kpops/components/common/topic.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections.abc import Iterable -from enum import Enum +from enum import StrEnum from typing import Annotated, Any import pydantic @@ -11,7 +11,7 @@ from kpops.utils.pydantic import DescConfigModel, to_str -class OutputTopicTypes(str, Enum): +class OutputTopicTypes(StrEnum): """Types of output topic. - OUTPUT: output topic diff --git a/kpops/components/streams_bootstrap/base.py b/kpops/components/streams_bootstrap/base.py index d59d97fc3..03405b14a 100644 --- a/kpops/components/streams_bootstrap/base.py +++ b/kpops/components/streams_bootstrap/base.py @@ -3,7 +3,7 @@ import logging import re from abc import ABC -from typing import TYPE_CHECKING +from typing import Self import pydantic from pydantic import Field @@ -17,12 +17,6 @@ from kpops.manifests.strimzi.kafka_topic import StrimziKafkaTopic from kpops.utils.docstring import describe_attr -if TYPE_CHECKING: - try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] - except ImportError: - from typing_extensions import Self - STREAMS_BOOTSTRAP_HELM_REPO = HelmRepoConfig( repository_name="bakdata-streams-bootstrap", url="https://bakdata.github.io/streams-bootstrap/", diff --git a/kpops/components/streams_bootstrap_v2/base.py b/kpops/components/streams_bootstrap_v2/base.py index 95f3281e2..59124ecf4 100644 --- a/kpops/components/streams_bootstrap_v2/base.py +++ b/kpops/components/streams_bootstrap_v2/base.py @@ -2,7 +2,7 @@ import logging from abc import ABC -from typing import TYPE_CHECKING, Any +from typing import Any, Self import pydantic from pydantic import AliasChoices, ConfigDict, Field @@ -20,12 +20,6 @@ exclude_defaults, ) -if TYPE_CHECKING: - try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] - except ImportError: - from typing_extensions import Self - STREAMS_BOOTSTRAP_HELM_REPO = HelmRepoConfig( repository_name="bakdata-streams-bootstrap", url="https://bakdata.github.io/streams-bootstrap/", diff --git a/kpops/components/streams_bootstrap_v2/streams/model.py b/kpops/components/streams_bootstrap_v2/streams/model.py index e733bb91c..2274f2ac5 100644 --- a/kpops/components/streams_bootstrap_v2/streams/model.py +++ b/kpops/components/streams_bootstrap_v2/streams/model.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any +from typing import Any, Self import pydantic from pydantic import BaseModel, ConfigDict, Field, model_validator @@ -194,9 +194,7 @@ class StreamsAppAutoScaling(CamelCaseConfigModel, DescConfigModel): model_config = ConfigDict(extra="allow") @model_validator(mode="after") - def validate_mandatory_fields_are_set( - self: StreamsAppAutoScaling, - ) -> StreamsAppAutoScaling: # TODO: typing.Self for Python 3.11+ + def validate_mandatory_fields_are_set(self) -> Self: if self.enabled and (self.consumer_group is None or self.lag_threshold is None): msg = ( "If app.autoscaling.enabled is set to true, " @@ -228,9 +226,7 @@ class PersistenceConfig(BaseModel): ) @model_validator(mode="after") - def validate_mandatory_fields_are_set( - self: PersistenceConfig, - ) -> PersistenceConfig: # TODO: typing.Self for Python 3.11+ + def validate_mandatory_fields_are_set(self) -> Self: if self.enabled and self.size is None: msg = ( "If app.persistence.enabled is set to true, " diff --git a/kpops/const/file_type.py b/kpops/const/file_type.py index 3e170be96..b0ff54312 100644 --- a/kpops/const/file_type.py +++ b/kpops/const/file_type.py @@ -1,11 +1,11 @@ from __future__ import annotations -from enum import Enum +from enum import StrEnum FILE_EXTENSION = ".yaml" -class KpopsFileType(str, Enum): +class KpopsFileType(StrEnum): """Enum representing different types of KPOps file naming conventions. Attributes: diff --git a/kpops/manifests/kubernetes.py b/kpops/manifests/kubernetes.py index f2d842ed3..f442e6b63 100644 --- a/kpops/manifests/kubernetes.py +++ b/kpops/manifests/kubernetes.py @@ -1,10 +1,11 @@ from collections.abc import Iterator -from typing import Any +from typing import Any, Self import pydantic import yaml from pydantic import ConfigDict, Field from typing_extensions import override +from yaml.loader import Loader from kpops.utils.pydantic import CamelCaseConfigModel, by_alias @@ -56,10 +57,8 @@ class KubernetesManifest(CamelCaseConfigModel): model_config = ConfigDict(extra="allow") @classmethod - def from_yaml( - cls, /, content: str - ) -> Iterator["KubernetesManifest"]: # TODO: typing.Self for Python 3.11+ - manifests: Iterator[dict[str, Any]] = yaml.load_all(content, yaml.Loader) + def from_yaml(cls, /, content: str) -> Iterator[Self]: + manifests: Iterator[dict[str, Any]] = yaml.load_all(content, Loader) for manifest in manifests: yield cls(**manifest) diff --git a/kpops/manifests/strimzi/kafka_topic.py b/kpops/manifests/strimzi/kafka_topic.py index 4b9a4b667..43c4536e0 100644 --- a/kpops/manifests/strimzi/kafka_topic.py +++ b/kpops/manifests/strimzi/kafka_topic.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import Any, Self from pydantic import ConfigDict, Field, model_validator @@ -11,12 +11,6 @@ from kpops.utils.docstring import describe_attr from kpops.utils.pydantic import CamelCaseConfigModel -if TYPE_CHECKING: - try: - from typing import Self # pyright: ignore[reportAttributeAccessIssue] - except ImportError: - from typing_extensions import Self - class TopicSpec(CamelCaseConfigModel): """Specification of a Kafka topic. diff --git a/kpops/utils/dict_differ.py b/kpops/utils/dict_differ.py index 67b6d98c4..51d29bf7a 100644 --- a/kpops/utils/dict_differ.py +++ b/kpops/utils/dict_differ.py @@ -3,8 +3,8 @@ from collections.abc import Mapping, MutableMapping from dataclasses import dataclass from difflib import Differ -from enum import Enum -from typing import TYPE_CHECKING, Any, Generic, TypeVar +from enum import StrEnum +from typing import TYPE_CHECKING, Any, Generic, NamedTuple, TypeVar import typer import yaml @@ -16,7 +16,7 @@ differ = Differ() -class DiffType(str, Enum): +class DiffType(StrEnum): ADD = "add" CHANGE = "change" REMOVE = "remove" @@ -30,8 +30,7 @@ def from_str(label: str) -> DiffType: _N = TypeVar("_N") -@dataclass -class Change(Generic[_O, _N]): # Generic NamedTuple requires Python 3.11+ +class Change(NamedTuple, Generic[_O, _N]): old_value: _O new_value: _N @@ -41,11 +40,11 @@ def factory( ) -> Change[_O | None, _N | None]: match type: case DiffType.ADD: - return Change(None, change) + return Change(None, change) # pyright: ignore[reportReturnType] case DiffType.REMOVE: - return Change(change, None) + return Change(change, None) # pyright: ignore[reportReturnType] case DiffType.CHANGE if isinstance(change, tuple): - return Change(*change) # pyright: ignore[reportUnknownArgumentType] + return Change(*change) # pyright: ignore[reportReturnType] msg = f"{type} is not part of {DiffType}" raise ValueError(msg) diff --git a/poetry.lock b/poetry.lock index a773e4d0c..ff88f7e8c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "aiofiles" @@ -34,10 +34,8 @@ files = [ ] [package.dependencies] -exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" -typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] @@ -252,20 +250,6 @@ files = [ {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, ] -[[package]] -name = "exceptiongroup" -version = "1.0.4" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"}, - {file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "faker" version = "22.0.0" @@ -1279,11 +1263,9 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2" -tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -1799,17 +1781,6 @@ files = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - [[package]] name = "typepy" version = "1.3.1" @@ -1951,5 +1922,5 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" -python-versions = ">=3.10, <3.13" -content-hash = "e307ba934678d208018611cc9567ef9bfa779fc7c024308d2c6fc6d01a32cafe" +python-versions = ">=3.11, <3.13" +content-hash = "82d4f691096d3aaa7cea1e1469b5ebec3daca4d649376c493af809d1978198e6" diff --git a/pyproject.toml b/pyproject.toml index 96e6897d8..d54d7c29e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ classifiers = [ kpops = "kpops.cli.main:app" [tool.poetry.dependencies] -python = ">=3.10, <3.13" +python = ">=3.11, <3.13" anyio = "^4.3.0" pydantic = "^2.5.3" pydantic-settings = "^2.0.3" @@ -73,11 +73,8 @@ reportUnknownLambdaType = "warning" reportUnknownVariableType = "warning" reportUnknownMemberType = "warning" -reportIncompatibleVariableOverride = false -reportIncompatibleMethodOverride = false -# FIXME: causes issues on Python 3.10 -# reportIncompatibleVariableOverride = "warning" -# reportIncompatibleMethodOverride = "warning" +reportIncompatibleVariableOverride = "warning" +reportIncompatibleMethodOverride = "warning" [tool.ruff] output-format = "grouped"