Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ on:
permissions:
contents: read

env:
TARGET_PYTHON_VERSION: "3.14"

jobs:
changes:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -60,7 +63,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
package: ${{ fromJSON(needs.changes.outputs.packages) }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
Expand All @@ -82,15 +85,15 @@ jobs:
run: uv build

- name: Type checking
if: matrix.python-version == '3.13'
if: matrix.python-version == env.TARGET_PYTHON_VERSION
working-directory: ${{ matrix.package }}
run: poe mypy

- name: Test with pytest
working-directory: ${{ matrix.package }}
run: poe cov

- if: matrix.python-version == '3.13'
- if: matrix.python-version == env.TARGET_PYTHON_VERSION
name: Upload coverage to Codecov
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
with:
Expand All @@ -108,7 +111,7 @@ jobs:
- name: Install uv and set the python version
uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v7
with:
python-version: "3.13"
python-version: ${{ env.TARGET_PYTHON_VERSION }}
enable-cache: false # caching is done automatically in `pre-commit/action`

- name: Run pre-commit
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ on:
permissions:
contents: read

env:
TARGET_PYTHON_VERSION: "3.14"

jobs:
release-please:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -54,7 +57,7 @@ jobs:
- name: Install uv and set the python version
uses: astral-sh/setup-uv@6ee6290f1cbc4156c0bdd66691b2c144ef8df19a # v7
with:
python-version: "3.13"
python-version: ${{ env.TARGET_PYTHON_VERSION }}

- name: Install dependencies
working-directory: ${{ matrix.path }}
Expand Down
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.10
9 changes: 6 additions & 3 deletions hooks/openfeature-hooks-opentelemetry/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies = [
"opentelemetry-api",
"opentelemetry-semantic-conventions>=0.50b0",
]
requires-python = ">=3.9"
requires-python = ">=3.10"

[project.urls]
Homepage = "https://github.com/open-feature/python-sdk-contrib"
Expand All @@ -30,7 +30,7 @@ dev = [
"coverage[toml]>=7.10.0,<8.0.0",
"mypy>=1.18.0,<2.0.0",
"poethepoet>=0.37.0",
"pytest>=8.4.0,<9.0.0",
"pytest>=9.0.0,<10.0.0",
]

[tool.uv.build-backend]
Expand All @@ -42,7 +42,7 @@ namespace = true
mypy_path = "src"
files = "src"

python_version = "3.9" # should be identical to the minimum supported version
python_version = "3.10" # should be identical to the minimum supported version
namespace_packages = true
explicit_package_bases = true
local_partial_types = true # will become the new default from version 2
Expand All @@ -53,6 +53,9 @@ pretty = true
strict = true
disallow_any_generics = false

[tool.pytest]
strict = true

[tool.poe.tasks]
test = "pytest tests"
test-cov = "coverage run -m pytest tests"
Expand Down
11 changes: 7 additions & 4 deletions providers/openfeature-provider-aws-ssm/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies = [
"boto3>=1.28.0",
"cachebox>=5.1.0,<6.0.0",
]
requires-python = ">=3.9"
requires-python = ">=3.10"

[project.optional-dependencies]
async = ["aioboto3>=12.3.0"]
Expand All @@ -36,8 +36,8 @@ dev = [
"coverage[toml]>=7.10.0,<8.0.0",
"mypy>=1.18.0,<2.0.0",
"poethepoet>=0.37.0",
"pytest>=8.4.0,<9.0.0",
"pytest-asyncio>=0.23.0",
"pytest>=9.0.0,<10.0.0",
"pytest-asyncio>=1.3.0,<2.0.0",
"moto[ssm]>=5.0.0,<6.0.0",
]

Expand All @@ -50,7 +50,7 @@ namespace = true
mypy_path = "src"
files = "src"

python_version = "3.9" # should be identical to the minimum supported version
python_version = "3.10" # should be identical to the minimum supported version
namespace_packages = true
explicit_package_bases = true
local_partial_types = true # will become the new default from version 2
Expand All @@ -66,6 +66,9 @@ omit = [
"tests/**",
]

[tool.pytest]
strict = true

[tool.poe.tasks]
test = "pytest tests"
test-cov = "coverage run -m pytest tests"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,6 @@ class AwsSsmProviderConfig:
"""

config: Optional["Config"] = None
endpoint_url: Optional[str] = None
endpoint_url: str | None = None
enable_decryption: bool = False
cache_config: Optional[CacheConfig] = field(default_factory=CacheConfig)
cache_config: CacheConfig | None = field(default_factory=CacheConfig)
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import json
from typing import Any, Union
from typing import Any

from openfeature.exception import ParseError, TypeMismatchError

Expand Down Expand Up @@ -65,7 +65,7 @@ def parse_float(value: str) -> float:
raise TypeMismatchError(f"Cannot parse '{value}' as float") from e


def parse_object(value: str) -> Union[dict[str, Any], list[Any]]:
def parse_object(value: str) -> dict[str, Any] | list[Any]:
"""
Parse a string value as a JSON object.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from collections.abc import Mapping, Sequence
from typing import Any, Callable, Optional, TypeVar, Union, cast
from collections.abc import Callable, Mapping, Sequence
from typing import Any, TypeVar, cast

from cachebox import BaseCacheImpl, LRUCache, TTLCache

Expand All @@ -17,7 +17,7 @@
class AwsSsmProvider(AbstractProvider):
"""Provider for AWS Systems Manager Parameter Store."""

def __init__(self, config: Optional[AwsSsmProviderConfig] = None) -> None:
def __init__(self, config: AwsSsmProviderConfig | None = None) -> None:
"""
Initialize the AWS SSM Provider.

Expand All @@ -31,7 +31,7 @@ def __init__(self, config: Optional[AwsSsmProviderConfig] = None) -> None:
enable_decryption=self.config.enable_decryption,
)

self.cache: Optional[BaseCacheImpl] = None
self.cache: BaseCacheImpl | None = None
if self.config.cache_config:
cache_config = self.config.cache_config
if cache_config.cache_type == "lru":
Expand All @@ -48,7 +48,7 @@ def get_metadata(self) -> Metadata:
"""
return Metadata(name="aws-ssm")

def _get_cached_value(self, flag_key: str) -> Optional[Any]:
def _get_cached_value(self, flag_key: str) -> Any | None:
"""
Get value from cache if available.

Expand Down Expand Up @@ -76,7 +76,7 @@ def _set_cache_value(self, flag_key: str, value: Any) -> None:
def _resolve_with_cache(
self,
flag_key: str,
parser: Optional[Callable[[str], T]] = None,
parser: Callable[[str], T] | None = None,
) -> FlagResolutionDetails[T]:
"""
Base resolution logic with caching for synchronous operations.
Expand Down Expand Up @@ -108,7 +108,7 @@ def _resolve_with_cache(
async def _resolve_with_cache_async(
self,
flag_key: str,
parser: Optional[Callable[[str], T]] = None,
parser: Callable[[str], T] | None = None,
) -> FlagResolutionDetails[T]:
"""
Base resolution logic with caching for asynchronous operations.
Expand Down Expand Up @@ -141,7 +141,7 @@ def resolve_boolean_details(
self,
flag_key: str,
default_value: bool,
evaluation_context: Optional[EvaluationContext] = None,
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[bool]:
"""
Resolve a boolean flag.
Expand All @@ -160,7 +160,7 @@ def resolve_string_details(
self,
flag_key: str,
default_value: str,
evaluation_context: Optional[EvaluationContext] = None,
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[str]:
"""
Resolve a string flag.
Expand All @@ -179,7 +179,7 @@ def resolve_integer_details(
self,
flag_key: str,
default_value: int,
evaluation_context: Optional[EvaluationContext] = None,
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[int]:
"""
Resolve an integer flag.
Expand All @@ -198,7 +198,7 @@ def resolve_float_details(
self,
flag_key: str,
default_value: float,
evaluation_context: Optional[EvaluationContext] = None,
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[float]:
"""
Resolve a float flag.
Expand All @@ -216,11 +216,9 @@ def resolve_float_details(
def resolve_object_details(
self,
flag_key: str,
default_value: Union[Sequence[FlagValueType], Mapping[str, FlagValueType]],
evaluation_context: Optional[EvaluationContext] = None,
) -> FlagResolutionDetails[
Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]
]:
default_value: Sequence[FlagValueType] | Mapping[str, FlagValueType],
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[Sequence[FlagValueType] | Mapping[str, FlagValueType]]:
"""
Resolve an object flag.

Expand All @@ -239,7 +237,7 @@ async def resolve_boolean_details_async(
self,
flag_key: str,
default_value: bool,
evaluation_context: Optional[EvaluationContext] = None,
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[bool]:
"""
Resolve a boolean flag asynchronously.
Expand All @@ -258,7 +256,7 @@ async def resolve_string_details_async(
self,
flag_key: str,
default_value: str,
evaluation_context: Optional[EvaluationContext] = None,
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[str]:
"""
Resolve a string flag asynchronously.
Expand All @@ -277,7 +275,7 @@ async def resolve_integer_details_async(
self,
flag_key: str,
default_value: int,
evaluation_context: Optional[EvaluationContext] = None,
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[int]:
"""
Resolve an integer flag asynchronously.
Expand All @@ -296,7 +294,7 @@ async def resolve_float_details_async(
self,
flag_key: str,
default_value: float,
evaluation_context: Optional[EvaluationContext] = None,
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[float]:
"""
Resolve a float flag asynchronously.
Expand All @@ -314,11 +312,9 @@ async def resolve_float_details_async(
async def resolve_object_details_async(
self,
flag_key: str,
default_value: Union[Sequence[FlagValueType], Mapping[str, FlagValueType]],
evaluation_context: Optional[EvaluationContext] = None,
) -> FlagResolutionDetails[
Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]
]:
default_value: Sequence[FlagValueType] | Mapping[str, FlagValueType],
evaluation_context: EvaluationContext | None = None,
) -> FlagResolutionDetails[Sequence[FlagValueType] | Mapping[str, FlagValueType]]:
"""
Resolve an object flag asynchronously.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Any, Optional
from typing import TYPE_CHECKING, Any

import boto3
from botocore.config import Config
Expand All @@ -25,8 +25,8 @@ class SsmService:

def __init__(
self,
config: Optional[Config] = None,
endpoint_url: Optional[str] = None,
config: Config | None = None,
endpoint_url: str | None = None,
enable_decryption: bool = False,
) -> None:
"""
Expand All @@ -38,8 +38,8 @@ def __init__(
enable_decryption: Whether to decrypt SecureString parameters
"""
self.enable_decryption = enable_decryption
self._client: Optional[SSMClient] = None
self._async_session: Optional[aioboto3.Session] = None
self._client: SSMClient | None = None
self._async_session: aioboto3.Session | None = None
self._client_kwargs: dict[str, Any] = {}
if endpoint_url:
self._client_kwargs["endpoint_url"] = endpoint_url
Expand Down
4 changes: 2 additions & 2 deletions providers/openfeature-provider-aws-ssm/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections.abc import Awaitable, Callable, Generator, Iterator
from contextlib import contextmanager
from dataclasses import dataclass
from typing import TypeVar, Union
from typing import TypeVar

import aiobotocore.endpoint
import boto3
Expand All @@ -25,7 +25,7 @@
class _PatchedAWSResponseContent:
"""Patched version of `botocore.awsrequest.AWSResponse.content`."""

content: Union[bytes, Awaitable[bytes]]
content: bytes | Awaitable[bytes]

def decode(self, encoding: str) -> str:
assert isinstance(self.content, bytes)
Expand Down
1 change: 0 additions & 1 deletion providers/openfeature-provider-env-var/.python-version

This file was deleted.

Loading
Loading