Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore!: drop Python 3.8 support #441

Merged
merged 4 commits into from
Feb 11, 2025
Merged
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
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
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"]

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
Expand All @@ -44,7 +44,7 @@ jobs:
- name: Run E2E tests with behave
run: hatch run e2e

- if: matrix.python-version == '3.11'
- if: matrix.python-version == '3.13'
name: Upload coverage to Codecov
uses: codecov/codecov-action@13ce06bfc6bbe3ecf90edbbf1bc32fe5978ca1d3 # v5.3.1
with:
Expand All @@ -61,7 +61,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5
with:
python-version: "3.11"
python-version: "3.13"
cache: "pip"

- name: Run pre-commit
Expand All @@ -77,7 +77,7 @@ jobs:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5
with:
python-version: "3.11"
python-version: "3.13"

- name: Initialize CodeQL
uses: github/codeql-action/init@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
default_stages: [commit]
default_stages: [pre-commit]
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.6
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

### System Requirements

Python 3.8 and above are required.
Python 3.9 and above are required.

### Target version(s)

Python 3.8 and above are supported by the SDK.
Python 3.9 and above are supported by the SDK.

### Installation and Dependencies

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</a>

<a href="https://www.python.org/downloads/">
<img alt="Min python version" src="https://img.shields.io/badge/python->=3.8-blue.svg" />
<img alt="Min python version" src="https://img.shields.io/badge/python->=3.9-blue.svg" />
</a>

<a href="https://www.repostatus.org/#wip">
Expand All @@ -51,7 +51,7 @@

### Requirements

- Python 3.8+
- Python 3.9+

### Install

Expand Down
6 changes: 3 additions & 3 deletions openfeature/_event_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import threading
from collections import defaultdict
from typing import TYPE_CHECKING, Dict, List
from typing import TYPE_CHECKING

from openfeature.event import (
EventDetails,
Expand All @@ -17,10 +17,10 @@


_global_lock = threading.RLock()
_global_handlers: Dict[ProviderEvent, List[EventHandler]] = defaultdict(list)
_global_handlers: dict[ProviderEvent, list[EventHandler]] = defaultdict(list)

_client_lock = threading.RLock()
_client_handlers: Dict[OpenFeatureClient, Dict[ProviderEvent, List[EventHandler]]] = (
_client_handlers: dict[OpenFeatureClient, dict[ProviderEvent, list[EventHandler]]] = (
defaultdict(lambda: defaultdict(list))
)

Expand Down
6 changes: 3 additions & 3 deletions openfeature/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
NoOpTransactionContextPropagator()
)

_hooks: typing.List[Hook] = []
_hooks: list[Hook] = []


def get_client(
Expand Down Expand Up @@ -96,7 +96,7 @@ def set_transaction_context(evaluation_context: EvaluationContext) -> None:
)


def add_hooks(hooks: typing.List[Hook]) -> None:
def add_hooks(hooks: list[Hook]) -> None:
global _hooks
_hooks = _hooks + hooks

Expand All @@ -106,7 +106,7 @@ def clear_hooks() -> None:
_hooks = []


def get_hooks() -> typing.List[Hook]:
def get_hooks() -> list[Hook]:
return _hooks


Expand Down
24 changes: 12 additions & 12 deletions openfeature/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@
typing.Awaitable[FlagResolutionDetails[typing.Union[dict, list]]],
],
]
TypeMap = typing.Dict[
TypeMap = dict[
FlagType,
typing.Union[
typing.Type[bool],
typing.Type[int],
typing.Type[float],
typing.Type[str],
typing.Tuple[typing.Type[dict], typing.Type[list]],
type[bool],
type[int],
type[float],
type[str],
tuple[type[dict], type[list]],
],
]

Expand All @@ -101,7 +101,7 @@ def __init__(
domain: typing.Optional[str],
version: typing.Optional[str],
context: typing.Optional[EvaluationContext] = None,
hooks: typing.Optional[typing.List[Hook]] = None,
hooks: typing.Optional[list[Hook]] = None,
) -> None:
self.domain = domain
self.version = version
Expand All @@ -118,7 +118,7 @@ def get_provider_status(self) -> ProviderStatus:
def get_metadata(self) -> ClientMetadata:
return ClientMetadata(domain=self.domain)

def add_hooks(self, hooks: typing.List[Hook]) -> None:
def add_hooks(self, hooks: list[Hook]) -> None:
self.hooks = self.hooks + hooks

def get_boolean_value(
Expand Down Expand Up @@ -423,12 +423,12 @@ def _establish_hooks_and_provider(
default_value: typing.Any,
evaluation_context: typing.Optional[EvaluationContext],
flag_evaluation_options: typing.Optional[FlagEvaluationOptions],
) -> typing.Tuple[
) -> tuple[
FeatureProvider,
HookContext,
HookHints,
typing.List[Hook],
typing.List[Hook],
list[Hook],
list[Hook],
]:
if evaluation_context is None:
evaluation_context = EvaluationContext()
Expand Down Expand Up @@ -477,7 +477,7 @@ def _before_hooks_and_merge_context(
self,
flag_type: FlagType,
hook_context: HookContext,
merged_hooks: typing.List[Hook],
merged_hooks: list[Hook],
hook_hints: HookHints,
evaluation_context: typing.Optional[EvaluationContext],
) -> EvaluationContext:
Expand Down
10 changes: 5 additions & 5 deletions openfeature/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from dataclasses import dataclass, field
from enum import Enum
from typing import Callable, Dict, List, Optional, Union
from typing import Callable, Optional, Union

from openfeature.exception import ErrorCode

Expand All @@ -18,19 +18,19 @@ class ProviderEvent(Enum):

@dataclass
class ProviderEventDetails:
flags_changed: Optional[List[str]] = None
flags_changed: Optional[list[str]] = None
message: Optional[str] = None
error_code: Optional[ErrorCode] = None
metadata: Dict[str, Union[bool, str, int, float]] = field(default_factory=dict)
metadata: dict[str, Union[bool, str, int, float]] = field(default_factory=dict)


@dataclass
class EventDetails(ProviderEventDetails):
provider_name: str = ""
flags_changed: Optional[List[str]] = None
flags_changed: Optional[list[str]] = None
message: Optional[str] = None
error_code: Optional[ErrorCode] = None
metadata: Dict[str, Union[bool, str, int, float]] = field(default_factory=dict)
metadata: dict[str, Union[bool, str, int, float]] = field(default_factory=dict)

@classmethod
def from_provider_event_details(
Expand Down
2 changes: 1 addition & 1 deletion openfeature/flag_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class FlagEvaluationDetails(typing.Generic[T_co]):

@dataclass
class FlagEvaluationOptions:
hooks: typing.List[Hook] = field(default_factory=list)
hooks: list[Hook] = field(default_factory=list)
hook_hints: HookHints = field(default_factory=dict)


Expand Down
4 changes: 2 additions & 2 deletions openfeature/hook/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ def __setattr__(self, key: str, value: typing.Any) -> None:
float,
str,
datetime,
typing.List[typing.Any],
typing.Dict[str, typing.Any],
list[typing.Any],
dict[str, typing.Any],
],
]

Expand Down
14 changes: 7 additions & 7 deletions openfeature/hook/_hook_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def error_hooks(
flag_type: FlagType,
hook_context: HookContext,
exception: Exception,
hooks: typing.List[Hook],
hooks: list[Hook],
hints: typing.Optional[HookHints] = None,
) -> None:
kwargs = {"hook_context": hook_context, "exception": exception, "hints": hints}
Expand All @@ -26,7 +26,7 @@ def after_all_hooks(
flag_type: FlagType,
hook_context: HookContext,
details: FlagEvaluationDetails[typing.Any],
hooks: typing.List[Hook],
hooks: list[Hook],
hints: typing.Optional[HookHints] = None,
) -> None:
kwargs = {"hook_context": hook_context, "details": details, "hints": hints}
Expand All @@ -39,7 +39,7 @@ def after_hooks(
flag_type: FlagType,
hook_context: HookContext,
details: FlagEvaluationDetails[typing.Any],
hooks: typing.List[Hook],
hooks: list[Hook],
hints: typing.Optional[HookHints] = None,
) -> None:
kwargs = {"hook_context": hook_context, "details": details, "hints": hints}
Expand All @@ -51,7 +51,7 @@ def after_hooks(
def before_hooks(
flag_type: FlagType,
hook_context: HookContext,
hooks: typing.List[Hook],
hooks: list[Hook],
hints: typing.Optional[HookHints] = None,
) -> EvaluationContext:
kwargs = {"hook_context": hook_context, "hints": hints}
Expand All @@ -68,7 +68,7 @@ def before_hooks(

def _execute_hooks(
flag_type: FlagType,
hooks: typing.List[Hook],
hooks: list[Hook],
hook_method: HookType,
**kwargs: typing.Any,
) -> list:
Expand All @@ -91,10 +91,10 @@ def _execute_hooks(

def _execute_hooks_unchecked(
flag_type: FlagType,
hooks: typing.List[Hook],
hooks: list[Hook],
hook_method: HookType,
**kwargs: typing.Any,
) -> typing.List[typing.Optional[EvaluationContext]]:
) -> list[typing.Optional[EvaluationContext]]:
"""
Execute a single hook without checking whether an exception is thrown. This is
used in the before and after hooks since any exception will be caught in the
Expand Down
4 changes: 2 additions & 2 deletions openfeature/provider/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def shutdown(self) -> None: ...

def get_metadata(self) -> Metadata: ...

def get_provider_hooks(self) -> typing.List[Hook]: ...
def get_provider_hooks(self) -> list[Hook]: ...

def resolve_boolean_details(
self,
Expand Down Expand Up @@ -134,7 +134,7 @@ def shutdown(self) -> None:
def get_metadata(self) -> Metadata:
pass

def get_provider_hooks(self) -> typing.List[Hook]:
def get_provider_hooks(self) -> list[Hook]:
return []

@abstractmethod
Expand Down
4 changes: 2 additions & 2 deletions openfeature/provider/_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

class ProviderRegistry:
_default_provider: FeatureProvider
_providers: typing.Dict[str, FeatureProvider]
_provider_status: typing.Dict[FeatureProvider, ProviderStatus]
_providers: dict[str, FeatureProvider]
_provider_status: dict[FeatureProvider, ProviderStatus]

def __init__(self) -> None:
self._default_provider = NoOpProvider()
Expand Down
6 changes: 3 additions & 3 deletions openfeature/provider/in_memory_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class State(StrEnum):
DISABLED = "DISABLED"

default_variant: str
variants: typing.Dict[str, T_co]
variants: dict[str, T_co]
flag_metadata: FlagMetadata = field(default_factory=dict)
state: State = State.ENABLED
context_evaluator: typing.Optional[
Expand All @@ -51,7 +51,7 @@ def resolve(
)


FlagStorage = typing.Dict[str, InMemoryFlag[typing.Any]]
FlagStorage = dict[str, InMemoryFlag[typing.Any]]

V = typing.TypeVar("V")

Expand All @@ -65,7 +65,7 @@ def __init__(self, flags: FlagStorage) -> None:
def get_metadata(self) -> Metadata:
return InMemoryMetadata()

def get_provider_hooks(self) -> typing.List[Hook]:
def get_provider_hooks(self) -> list[Hook]:
return []

def resolve_boolean_details(
Expand Down
2 changes: 1 addition & 1 deletion openfeature/provider/no_op_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class NoOpProvider(AbstractProvider):
def get_metadata(self) -> Metadata:
return NoOpMetadata()

def get_provider_hooks(self) -> typing.List[Hook]:
def get_provider_hooks(self) -> list[Hook]:
return []

def resolve_boolean_details(
Expand Down
9 changes: 7 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ keywords = [
"toggles",
]
dependencies = []
requires-python = ">=3.8"
requires-python = ">=3.9"

[project.urls]
Homepage = "https://github.com/open-feature/python-sdk"
Expand Down Expand Up @@ -66,21 +66,26 @@ packages = ["openfeature"]

[tool.mypy]
files = "openfeature"

python_version = "3.9" # 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
pretty = true
strict = true
disallow_any_generics = false

[tool.pytest.ini_options]
asyncio_default_fixture_loop_scope = "function"

[tool.ruff]
exclude = [
".git",
".venv",
"__pycache__",
"venv",
]
target-version = "py38"
target-version = "py39"

[tool.ruff.lint]
select = [
Expand Down