Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
7 changes: 3 additions & 4 deletions openfeature/api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import typing

from openfeature import _event_support
from openfeature.client import OpenFeatureClient
Expand Down Expand Up @@ -40,13 +39,13 @@


def get_client(
domain: typing.Optional[str] = None, version: typing.Optional[str] = None
domain: str | None = None, version: str | None = None
) -> OpenFeatureClient:
return OpenFeatureClient(domain=domain, version=version)


def set_provider(
provider: FeatureProvider, domain: typing.Optional[str] = None
provider: FeatureProvider, domain: str | None = None
) -> None:
if domain is None:
provider_registry.set_default_provider(provider)
Expand All @@ -59,7 +58,7 @@ def clear_providers() -> None:
_event_support.clear()


def get_provider_metadata(domain: typing.Optional[str] = None) -> Metadata:
def get_provider_metadata(domain: str | None = None) -> Metadata:
return provider_registry.get_provider(domain).get_metadata()


Expand Down
198 changes: 92 additions & 106 deletions openfeature/client.py

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions openfeature/evaluation_context/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@
__all__ = ["EvaluationContext", "get_evaluation_context", "set_evaluation_context"]

# https://openfeature.dev/specification/sections/evaluation-context#requirement-312
EvaluationContextAttribute = typing.Union[
bool,
int,
float,
str,
datetime,
Sequence["EvaluationContextAttribute"],
Mapping[str, "EvaluationContextAttribute"],
]
EvaluationContextAttribute: typing.TypeAlias = (
bool
| int
| float
| str
| datetime
| Sequence["EvaluationContextAttribute"]
| Mapping[str, "EvaluationContextAttribute"]
)


@dataclass
class EvaluationContext:
targeting_key: typing.Optional[str] = None
targeting_key: str | None = None
attributes: Mapping[str, EvaluationContextAttribute] = field(default_factory=dict)

def merge(self, ctx2: EvaluationContext) -> EvaluationContext:
Expand Down
17 changes: 8 additions & 9 deletions openfeature/event.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import typing
from collections.abc import Callable
from dataclasses import dataclass, field
from enum import Enum
Expand All @@ -19,21 +18,21 @@ class ProviderEvent(Enum):

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


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

Expand Down
19 changes: 9 additions & 10 deletions openfeature/exception.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import annotations

import typing
from collections.abc import Callable, Mapping

from openfeature._backports.strenum import StrEnum
Expand All @@ -26,7 +25,7 @@ class OpenFeatureError(Exception):
"""

def __init__(
self, error_code: ErrorCode, error_message: typing.Optional[str] = None
self, error_code: ErrorCode, error_message: str | None = None
):
"""
Constructor for the generic OpenFeatureError.
Expand All @@ -43,7 +42,7 @@ class ProviderNotReadyError(OpenFeatureError):
This exception should be raised when the provider is not ready to be used.
"""

def __init__(self, error_message: typing.Optional[str] = None):
def __init__(self, error_message: str | None = None):
"""
Constructor for the ProviderNotReadyError. The error code for this type of
exception is ErrorCode.PROVIDER_NOT_READY.
Expand All @@ -58,7 +57,7 @@ class ProviderFatalError(OpenFeatureError):
This exception should be raised when the provider encounters a fatal error.
"""

def __init__(self, error_message: typing.Optional[str] = None):
def __init__(self, error_message: str | None = None):
"""
Constructor for the ProviderFatalError. The error code for this type of
exception is ErrorCode.PROVIDER_FATAL.
Expand All @@ -74,7 +73,7 @@ class FlagNotFoundError(OpenFeatureError):
key provided by the user.
"""

def __init__(self, error_message: typing.Optional[str] = None):
def __init__(self, error_message: str | None = None):
"""
Constructor for the FlagNotFoundError. The error code for
this type of exception is ErrorCode.FLAG_NOT_FOUND.
Expand All @@ -90,7 +89,7 @@ class GeneralError(OpenFeatureError):
feature python sdk.
"""

def __init__(self, error_message: typing.Optional[str] = None):
def __init__(self, error_message: str | None = None):
"""
Constructor for the GeneralError. The error code for this type of exception
is ErrorCode.GENERAL.
Expand All @@ -106,7 +105,7 @@ class ParseError(OpenFeatureError):
be parsed into a FlagEvaluationDetails object.
"""

def __init__(self, error_message: typing.Optional[str] = None):
def __init__(self, error_message: str | None = None):
"""
Constructor for the ParseError. The error code for this type of exception
is ErrorCode.PARSE_ERROR.
Expand All @@ -122,7 +121,7 @@ class TypeMismatchError(OpenFeatureError):
not match the type requested by the user.
"""

def __init__(self, error_message: typing.Optional[str] = None):
def __init__(self, error_message: str | None = None):
"""
Constructor for the TypeMismatchError. The error code for this type of
exception is ErrorCode.TYPE_MISMATCH.
Expand All @@ -138,7 +137,7 @@ class TargetingKeyMissingError(OpenFeatureError):
but one was not provided in the evaluation context.
"""

def __init__(self, error_message: typing.Optional[str] = None):
def __init__(self, error_message: str | None = None):
"""
Constructor for the TargetingKeyMissingError. The error code for this type of
exception is ErrorCode.TARGETING_KEY_MISSING.
Expand All @@ -154,7 +153,7 @@ class InvalidContextError(OpenFeatureError):
requirements.
"""

def __init__(self, error_message: typing.Optional[str]):
def __init__(self, error_message: str | None):
"""
Constructor for the InvalidContextError. The error code for this type of
exception is ErrorCode.INVALID_CONTEXT.
Expand Down
36 changes: 18 additions & 18 deletions openfeature/flag_evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ class Reason(StrEnum):
UNKNOWN = "UNKNOWN"


FlagMetadata = Mapping[str, typing.Union[bool, int, float, str]]
FlagValueType = typing.Union[
bool,
int,
float,
str,
Sequence["FlagValueType"],
Mapping[str, "FlagValueType"],
]
FlagMetadata = Mapping[str, bool | int | float | str]
FlagValueType: typing.TypeAlias = (
bool
| int
| float
| str
| Sequence["FlagValueType"]
| Mapping[str, "FlagValueType"]
)

T_co = typing.TypeVar("T_co", covariant=True)

Expand All @@ -59,13 +59,13 @@ class Reason(StrEnum):
class FlagEvaluationDetails(typing.Generic[T_co]):
flag_key: str
value: T_co
variant: typing.Optional[str] = None
variant: str | None = None
flag_metadata: FlagMetadata = field(default_factory=dict)
reason: typing.Optional[typing.Union[str, Reason]] = None
error_code: typing.Optional[ErrorCode] = None
error_message: typing.Optional[str] = None
reason: str | Reason | None = None
error_code: ErrorCode | None = None
error_message: str | None = None

def get_exception(self) -> typing.Optional[OpenFeatureError]:
def get_exception(self) -> OpenFeatureError | None:
if self.error_code:
return ErrorCode.to_exception(self.error_code, self.error_message or "")
return None
Expand All @@ -83,10 +83,10 @@ class FlagEvaluationOptions:
@dataclass
class FlagResolutionDetails(typing.Generic[U_co]):
value: U_co
error_code: typing.Optional[ErrorCode] = None
error_message: typing.Optional[str] = None
reason: typing.Optional[typing.Union[str, Reason]] = None
variant: typing.Optional[str] = None
error_code: ErrorCode | None = None
error_message: str | None = None
reason: str | Reason | None = None
variant: str | None = None
flag_metadata: FlagMetadata = field(default_factory=dict)

def raise_for_error(self) -> None:
Expand Down
26 changes: 13 additions & 13 deletions openfeature/hook/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ def __init__( # noqa: PLR0913
flag_type: FlagType,
default_value: FlagValueType,
evaluation_context: EvaluationContext,
client_metadata: typing.Optional[ClientMetadata] = None,
provider_metadata: typing.Optional[Metadata] = None,
hook_data: typing.Optional[HookData] = None,
client_metadata: ClientMetadata | None = None,
provider_metadata: Metadata | None = None,
hook_data: HookData | None = None,
):
self.flag_key = flag_key
self.flag_type = flag_type
Expand All @@ -69,23 +69,23 @@ def __setattr__(self, key: str, value: typing.Any) -> None:


# https://openfeature.dev/specification/sections/hooks/#requirement-421
HookHintValue = typing.Union[
bool,
int,
float,
str,
datetime,
Sequence["HookHintValue"],
Mapping[str, "HookHintValue"],
]
HookHintValue: typing.TypeAlias = (
bool
| int
| float
| str
| datetime
| Sequence["HookHintValue"]
| Mapping[str, "HookHintValue"]
)

HookHints = Mapping[str, HookHintValue]


class Hook:
def before(
self, hook_context: HookContext, hints: HookHints
) -> typing.Optional[EvaluationContext]:
) -> EvaluationContext | None:
"""
Runs before flag is resolved.

Expand Down
16 changes: 8 additions & 8 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,
exception: Exception,
hooks_and_context: list[tuple[Hook, HookContext]],
hints: typing.Optional[HookHints] = None,
hints: HookHints | None = None,
) -> None:
kwargs = {"exception": exception, "hints": hints}
_execute_hooks(
Expand All @@ -28,7 +28,7 @@ def after_all_hooks(
flag_type: FlagType,
details: FlagEvaluationDetails[typing.Any],
hooks_and_context: list[tuple[Hook, HookContext]],
hints: typing.Optional[HookHints] = None,
hints: HookHints | None = None,
) -> None:
kwargs = {"details": details, "hints": hints}
_execute_hooks(
Expand All @@ -43,7 +43,7 @@ def after_hooks(
flag_type: FlagType,
details: FlagEvaluationDetails[typing.Any],
hooks_and_context: list[tuple[Hook, HookContext]],
hints: typing.Optional[HookHints] = None,
hints: HookHints | None = None,
) -> None:
kwargs = {"details": details, "hints": hints}
_execute_hooks_unchecked(
Expand All @@ -57,7 +57,7 @@ def after_hooks(
def before_hooks(
flag_type: FlagType,
hooks_and_context: list[tuple[Hook, HookContext]],
hints: typing.Optional[HookHints] = None,
hints: HookHints | None = None,
) -> EvaluationContext:
kwargs = {"hints": hints}
executed_hooks = _execute_hooks_unchecked(
Expand All @@ -79,7 +79,7 @@ def _execute_hooks(
hooks_and_context: list[tuple[Hook, HookContext]],
hook_method: HookType,
**kwargs: typing.Any,
) -> list[typing.Optional[EvaluationContext]]:
) -> list[EvaluationContext | None]:
"""
Run multiple hooks of any hook type. All of these hooks will be run through an
exception check.
Expand All @@ -102,7 +102,7 @@ def _execute_hooks_unchecked(
hooks_and_context: list[tuple[Hook, HookContext]],
hook_method: HookType,
**kwargs: typing.Any,
) -> list[typing.Optional[EvaluationContext]]:
) -> list[EvaluationContext | None]:
"""
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 All @@ -123,7 +123,7 @@ def _execute_hooks_unchecked(

def _execute_hook_checked(
hook: Hook, hook_method: HookType, **kwargs: typing.Any
) -> typing.Optional[EvaluationContext]:
) -> EvaluationContext | None:
"""
Try and run a single hook and catch any exception thrown. This is used in the
after all and error hooks since any error thrown at this point needs to be caught.
Expand All @@ -135,7 +135,7 @@ def _execute_hook_checked(
"""
try:
return typing.cast(
"typing.Optional[EvaluationContext]",
"EvaluationContext | None",
getattr(hook, hook_method.value)(**kwargs),
)
except Exception: # pragma: no cover
Expand Down
Loading
Loading