Skip to content
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
4 changes: 2 additions & 2 deletions openfeature/_event_support.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from __future__ import annotations

import threading
import typing
from collections import defaultdict
from typing import TYPE_CHECKING

from openfeature.event import (
EventDetails,
Expand All @@ -12,7 +12,7 @@
)
from openfeature.provider import FeatureProvider, ProviderStatus

if TYPE_CHECKING:
if typing.TYPE_CHECKING:
from openfeature.client import OpenFeatureClient


Expand Down
42 changes: 20 additions & 22 deletions openfeature/client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
import typing
from collections.abc import Awaitable, Sequence
from collections.abc import Awaitable, Mapping, Sequence
from dataclasses import dataclass
from itertools import chain

Expand Down Expand Up @@ -345,11 +345,11 @@ def get_object_value(
self,
flag_key: str,
default_value: typing.Union[
Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
Sequence[FlagValueType], Mapping[str, FlagValueType]
],
evaluation_context: typing.Optional[EvaluationContext] = None,
flag_evaluation_options: typing.Optional[FlagEvaluationOptions] = None,
) -> typing.Union[Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]:
) -> typing.Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]:
return self.get_object_details(
flag_key,
default_value,
Expand All @@ -361,11 +361,11 @@ async def get_object_value_async(
self,
flag_key: str,
default_value: typing.Union[
Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
Sequence[FlagValueType], Mapping[str, FlagValueType]
],
evaluation_context: typing.Optional[EvaluationContext] = None,
flag_evaluation_options: typing.Optional[FlagEvaluationOptions] = None,
) -> typing.Union[Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]:
) -> typing.Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]:
details = await self.get_object_details_async(
flag_key,
default_value,
Expand All @@ -378,12 +378,12 @@ def get_object_details(
self,
flag_key: str,
default_value: typing.Union[
Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
Sequence[FlagValueType], Mapping[str, FlagValueType]
],
evaluation_context: typing.Optional[EvaluationContext] = None,
flag_evaluation_options: typing.Optional[FlagEvaluationOptions] = None,
) -> FlagEvaluationDetails[
typing.Union[Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]
typing.Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]
]:
return self.evaluate_flag_details(
FlagType.OBJECT,
Expand All @@ -397,12 +397,12 @@ async def get_object_details_async(
self,
flag_key: str,
default_value: typing.Union[
Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
Sequence[FlagValueType], Mapping[str, FlagValueType]
],
evaluation_context: typing.Optional[EvaluationContext] = None,
flag_evaluation_options: typing.Optional[FlagEvaluationOptions] = None,
) -> FlagEvaluationDetails[
typing.Union[Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]
typing.Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]
]:
return await self.evaluate_flag_details_async(
FlagType.OBJECT,
Expand Down Expand Up @@ -472,7 +472,7 @@ def _establish_hooks_and_provider(
)
]
# after, error, finally: Provider, Invocation, Client, API
reversed_merged_hooks_and_context = merged_hooks_and_context[:]
reversed_merged_hooks_and_context = merged_hooks_and_context.copy()
reversed_merged_hooks_and_context.reverse()

return (
Expand Down Expand Up @@ -567,10 +567,10 @@ async def evaluate_flag_details_async(
self,
flag_type: FlagType,
flag_key: str,
default_value: typing.Mapping[str, "FlagValueType"],
default_value: Mapping[str, "FlagValueType"],
evaluation_context: typing.Optional[EvaluationContext] = None,
flag_evaluation_options: typing.Optional[FlagEvaluationOptions] = None,
) -> FlagEvaluationDetails[typing.Mapping[str, "FlagValueType"]]: ...
) -> FlagEvaluationDetails[Mapping[str, "FlagValueType"]]: ...

async def evaluate_flag_details_async(
self,
Expand Down Expand Up @@ -743,10 +743,10 @@ def evaluate_flag_details(
self,
flag_type: FlagType,
flag_key: str,
default_value: typing.Mapping[str, "FlagValueType"],
default_value: Mapping[str, "FlagValueType"],
evaluation_context: typing.Optional[EvaluationContext] = None,
flag_evaluation_options: typing.Optional[FlagEvaluationOptions] = None,
) -> FlagEvaluationDetails[typing.Mapping[str, "FlagValueType"]]: ...
) -> FlagEvaluationDetails[Mapping[str, "FlagValueType"]]: ...

def evaluate_flag_details(
self,
Expand Down Expand Up @@ -874,9 +874,7 @@ async def _create_provider_evaluation_async(
default_value: FlagValueType,
evaluation_context: typing.Optional[EvaluationContext] = None,
) -> FlagEvaluationDetails[FlagValueType]:
get_details_callables_async: typing.Mapping[
FlagType, ResolveDetailsCallableAsync
] = {
get_details_callables_async: Mapping[FlagType, ResolveDetailsCallableAsync] = {
FlagType.BOOLEAN: provider.resolve_boolean_details_async,
FlagType.INTEGER: provider.resolve_integer_details_async,
FlagType.FLOAT: provider.resolve_float_details_async,
Expand Down Expand Up @@ -931,7 +929,7 @@ def _create_provider_evaluation(
:return: a FlagEvaluationDetails object with the fully evaluated flag from a
provider
"""
get_details_callables: typing.Mapping[FlagType, ResolveDetailsCallable] = {
get_details_callables: Mapping[FlagType, ResolveDetailsCallable] = {
FlagType.BOOLEAN: provider.resolve_boolean_details,
FlagType.INTEGER: provider.resolve_integer_details,
FlagType.FLOAT: provider.resolve_float_details,
Expand Down Expand Up @@ -986,9 +984,9 @@ def _typecheck_flag_value(
FlagType.FLOAT: float,
FlagType.INTEGER: int,
}
_type = type_map.get(flag_type)
if not _type:
py_type = type_map.get(flag_type)
if not py_type:
return GeneralError(error_message="Unknown flag type")
if not isinstance(value, _type):
return TypeMismatchError(f"Expected type {_type} but got {type(value)}")
if not isinstance(value, py_type):
return TypeMismatchError(f"Expected type {py_type} but got {type(value)}")
return None
8 changes: 3 additions & 5 deletions openfeature/evaluation_context/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import typing
from collections.abc import Sequence
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field
from datetime import datetime

Expand All @@ -17,16 +17,14 @@
str,
datetime,
Sequence["EvaluationContextAttribute"],
typing.Mapping[str, "EvaluationContextAttribute"],
Mapping[str, "EvaluationContextAttribute"],
]


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

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

import typing
from collections.abc import Callable
from dataclasses import dataclass, field
from enum import Enum
from typing import Callable, Optional, Union

from openfeature.exception import ErrorCode

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

@dataclass
class ProviderEventDetails:
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)
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(
default_factory=dict
)


@dataclass
class EventDetails(ProviderEventDetails):
provider_name: str = ""
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)
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(
default_factory=dict
)

@classmethod
def from_provider_event_details(
Expand Down
4 changes: 2 additions & 2 deletions openfeature/exception.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import typing
from collections.abc import Mapping
from collections.abc import Callable, Mapping

from openfeature._backports.strenum import StrEnum

Expand Down Expand Up @@ -174,7 +174,7 @@ class ErrorCode(StrEnum):
INVALID_CONTEXT = "INVALID_CONTEXT"
GENERAL = "GENERAL"

__exceptions__: Mapping[str, typing.Callable[[str], OpenFeatureError]] = {
__exceptions__: Mapping[str, Callable[[str], OpenFeatureError]] = {
PROVIDER_NOT_READY: ProviderNotReadyError,
PROVIDER_FATAL: ProviderFatalError,
FLAG_NOT_FOUND: FlagNotFoundError,
Expand Down
6 changes: 3 additions & 3 deletions openfeature/flag_evaluation.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import typing
from collections.abc import Sequence
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field

from openfeature._backports.strenum import StrEnum
Expand Down Expand Up @@ -42,14 +42,14 @@ class Reason(StrEnum):
UNKNOWN = "UNKNOWN"


FlagMetadata = typing.Mapping[str, typing.Union[bool, int, float, str]]
FlagMetadata = Mapping[str, typing.Union[bool, int, float, str]]
FlagValueType = typing.Union[
bool,
int,
float,
str,
Sequence["FlagValueType"],
typing.Mapping[str, "FlagValueType"],
Mapping[str, "FlagValueType"],
]

T_co = typing.TypeVar("T_co", covariant=True)
Expand Down
9 changes: 4 additions & 5 deletions openfeature/hook/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from __future__ import annotations

import typing
from collections.abc import MutableMapping, Sequence
from collections.abc import Mapping, MutableMapping, Sequence
from datetime import datetime
from enum import Enum
from typing import TYPE_CHECKING

from openfeature.evaluation_context import EvaluationContext
from openfeature.flag_evaluation import FlagEvaluationDetails, FlagType, FlagValueType

if TYPE_CHECKING:
if typing.TYPE_CHECKING:
from openfeature.client import ClientMetadata
from openfeature.provider.metadata import Metadata

Expand Down Expand Up @@ -77,10 +76,10 @@ def __setattr__(self, key: str, value: typing.Any) -> None:
str,
datetime,
Sequence["HookHintValue"],
typing.Mapping[str, "HookHintValue"],
Mapping[str, "HookHintValue"],
]

HookHints = typing.Mapping[str, HookHintValue]
HookHints = Mapping[str, HookHintValue]


class Hook:
Expand Down
26 changes: 11 additions & 15 deletions openfeature/provider/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import typing
from abc import abstractmethod
from collections.abc import Sequence
from collections.abc import Callable, Mapping, Sequence
from enum import Enum

from openfeature.evaluation_context import EvaluationContext
Expand All @@ -29,9 +29,7 @@ class ProviderStatus(Enum):
class FeatureProvider(typing.Protocol): # pragma: no cover
def attach(
self,
on_emit: typing.Callable[
[FeatureProvider, ProviderEvent, ProviderEventDetails], None
],
on_emit: Callable[[FeatureProvider, ProviderEvent, ProviderEventDetails], None],
) -> None: ...

def detach(self) -> None: ...
Expand Down Expand Up @@ -104,22 +102,22 @@ def resolve_object_details(
self,
flag_key: str,
default_value: typing.Union[
Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
Sequence[FlagValueType], Mapping[str, FlagValueType]
],
evaluation_context: typing.Optional[EvaluationContext] = None,
) -> FlagResolutionDetails[
typing.Union[Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]
typing.Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]
]: ...

async def resolve_object_details_async(
self,
flag_key: str,
default_value: typing.Union[
Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
Sequence[FlagValueType], Mapping[str, FlagValueType]
],
evaluation_context: typing.Optional[EvaluationContext] = None,
) -> FlagResolutionDetails[
typing.Union[Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]
typing.Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]
]: ...


Expand All @@ -130,9 +128,7 @@ def __init__(self, *args: typing.Any, **kwargs: typing.Any) -> None:

def attach(
self,
on_emit: typing.Callable[
[FeatureProvider, ProviderEvent, ProviderEventDetails], None
],
on_emit: Callable[[FeatureProvider, ProviderEvent, ProviderEventDetails], None],
) -> None:
self._on_emit = on_emit

Expand Down Expand Up @@ -226,23 +222,23 @@ def resolve_object_details(
self,
flag_key: str,
default_value: typing.Union[
Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
Sequence[FlagValueType], Mapping[str, FlagValueType]
],
evaluation_context: typing.Optional[EvaluationContext] = None,
) -> FlagResolutionDetails[
typing.Union[Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]
typing.Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]
]:
pass

async def resolve_object_details_async(
self,
flag_key: str,
default_value: typing.Union[
Sequence[FlagValueType], typing.Mapping[str, FlagValueType]
Sequence[FlagValueType], Mapping[str, FlagValueType]
],
evaluation_context: typing.Optional[EvaluationContext] = None,
) -> FlagResolutionDetails[
typing.Union[Sequence[FlagValueType], typing.Mapping[str, FlagValueType]]
typing.Union[Sequence[FlagValueType], Mapping[str, FlagValueType]]
]:
return self.resolve_object_details(flag_key, default_value, evaluation_context)

Expand Down
Loading