diff --git a/open_feature/hooks/hook_support.py b/open_feature/_internal/hook_support.py similarity index 91% rename from open_feature/hooks/hook_support.py rename to open_feature/_internal/hook_support.py index 039afe7b..88a88fd2 100644 --- a/open_feature/hooks/hook_support.py +++ b/open_feature/_internal/hook_support.py @@ -2,12 +2,9 @@ import typing from functools import reduce -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.flag_evaluation.flag_evaluation_details import FlagEvaluationDetails -from open_feature.flag_evaluation.flag_type import FlagType -from open_feature.hooks.hook import Hook -from open_feature.hooks.hook_context import HookContext -from open_feature.hooks.hook_type import HookType +from open_feature.evaluation_context import EvaluationContext +from open_feature.flag_evaluation import FlagEvaluationDetails, FlagType +from open_feature.hook import Hook, HookContext, HookType def error_hooks( diff --git a/open_feature/open_feature_api.py b/open_feature/api.py similarity index 85% rename from open_feature/open_feature_api.py rename to open_feature/api.py index cc07c8e4..db90da37 100644 --- a/open_feature/open_feature_api.py +++ b/open_feature/api.py @@ -1,9 +1,9 @@ import typing -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.exception.exceptions import GeneralError -from open_feature.hooks.hook import Hook -from open_feature.open_feature_client import OpenFeatureClient +from open_feature.client import OpenFeatureClient +from open_feature.evaluation_context import EvaluationContext +from open_feature.exception import GeneralError +from open_feature.hook import Hook from open_feature.provider.metadata import Metadata from open_feature.provider.no_op_provider import NoOpProvider from open_feature.provider.provider import AbstractProvider diff --git a/open_feature/open_feature_client.py b/open_feature/client.py similarity index 94% rename from open_feature/open_feature_client.py rename to open_feature/client.py index fcaf9588..6f5221c6 100644 --- a/open_feature/open_feature_client.py +++ b/open_feature/client.py @@ -2,22 +2,23 @@ import typing from dataclasses import dataclass -from open_feature import open_feature_api as api -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.exception.error_code import ErrorCode -from open_feature.exception.exceptions import ( +from open_feature import api +from open_feature.evaluation_context import EvaluationContext +from open_feature.exception import ( + ErrorCode, GeneralError, OpenFeatureError, TypeMismatchError, ) -from open_feature.flag_evaluation.flag_evaluation_details import FlagEvaluationDetails -from open_feature.flag_evaluation.flag_evaluation_options import FlagEvaluationOptions -from open_feature.flag_evaluation.flag_type import FlagType -from open_feature.flag_evaluation.reason import Reason -from open_feature.flag_evaluation.resolution_details import FlagResolutionDetails -from open_feature.hooks.hook import Hook -from open_feature.hooks.hook_context import HookContext -from open_feature.hooks.hook_support import ( +from open_feature.flag_evaluation import ( + FlagEvaluationDetails, + FlagEvaluationOptions, + FlagType, + Reason, + FlagResolutionDetails, +) +from open_feature.hook import Hook, HookContext +from open_feature.hook.hook_support import ( after_all_hooks, after_hooks, before_hooks, diff --git a/open_feature/evaluation_context/evaluation_context.py b/open_feature/evaluation_context.py similarity index 100% rename from open_feature/evaluation_context/evaluation_context.py rename to open_feature/evaluation_context.py diff --git a/open_feature/exception/exceptions.py b/open_feature/exception.py similarity index 92% rename from open_feature/exception/exceptions.py rename to open_feature/exception.py index bfab67b4..e8a4768d 100644 --- a/open_feature/exception/exceptions.py +++ b/open_feature/exception.py @@ -1,6 +1,15 @@ import typing +from enum import Enum -from open_feature.exception.error_code import ErrorCode + +class ErrorCode(Enum): + PROVIDER_NOT_READY = "PROVIDER_NOT_READY" + FLAG_NOT_FOUND = "FLAG_NOT_FOUND" + PARSE_ERROR = "PARSE_ERROR" + TYPE_MISMATCH = "TYPE_MISMATCH" + TARGETING_KEY_MISSING = "TARGETING_KEY_MISSING" + INVALID_CONTEXT = "INVALID_CONTEXT" + GENERAL = "GENERAL" class OpenFeatureError(Exception): diff --git a/open_feature/exception/__init__.py b/open_feature/exception/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/open_feature/exception/error_code.py b/open_feature/exception/error_code.py deleted file mode 100644 index 96c59546..00000000 --- a/open_feature/exception/error_code.py +++ /dev/null @@ -1,11 +0,0 @@ -from enum import Enum - - -class ErrorCode(Enum): - PROVIDER_NOT_READY = "PROVIDER_NOT_READY" - FLAG_NOT_FOUND = "FLAG_NOT_FOUND" - PARSE_ERROR = "PARSE_ERROR" - TYPE_MISMATCH = "TYPE_MISMATCH" - TARGETING_KEY_MISSING = "TARGETING_KEY_MISSING" - INVALID_CONTEXT = "INVALID_CONTEXT" - GENERAL = "GENERAL" diff --git a/open_feature/flag_evaluation.py b/open_feature/flag_evaluation.py new file mode 100644 index 00000000..a291b332 --- /dev/null +++ b/open_feature/flag_evaluation.py @@ -0,0 +1,60 @@ +from __future__ import annotations +import typing +from dataclasses import dataclass, field + +from open_feature._backports.strenum import StrEnum +from open_feature.exception import ErrorCode + +if typing.TYPE_CHECKING: # resolves a circular dependency in type annotations + from open_feature.hook import Hook + + +class FlagType(StrEnum): + BOOLEAN = "BOOLEAN" + STRING = "STRING" + OBJECT = "OBJECT" + FLOAT = "FLOAT" + INTEGER = "INTEGER" + + +class Reason(StrEnum): + CACHED = "CACHED" + DEFAULT = "DEFAULT" + DISABLED = "DISABLED" + ERROR = "ERROR" + STATIC = "STATIC" + SPLIT = "SPLIT" + TARGETING_MATCH = "TARGETING_MATCH" + UNKNOWN = "UNKNOWN" + + +T = typing.TypeVar("T", covariant=True) + + +@dataclass +class FlagEvaluationDetails(typing.Generic[T]): + flag_key: str + value: T + variant: typing.Optional[str] = None + reason: typing.Optional[Reason] = None + error_code: typing.Optional[ErrorCode] = None + error_message: typing.Optional[str] = None + + +@dataclass +class FlagEvaluationOptions: + hooks: typing.List[Hook] = field(default_factory=list) + hook_hints: dict = field(default_factory=dict) + + +U = typing.TypeVar("U", covariant=True) + + +@dataclass +class FlagResolutionDetails(typing.Generic[U]): + value: U + error_code: typing.Optional[ErrorCode] = None + error_message: typing.Optional[str] = None + reason: typing.Optional[Reason] = None + variant: typing.Optional[str] = None + flag_metadata: typing.Optional[str] = None diff --git a/open_feature/flag_evaluation/__init__.py b/open_feature/flag_evaluation/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/open_feature/flag_evaluation/flag_evaluation_details.py b/open_feature/flag_evaluation/flag_evaluation_details.py deleted file mode 100644 index 2bf9fceb..00000000 --- a/open_feature/flag_evaluation/flag_evaluation_details.py +++ /dev/null @@ -1,17 +0,0 @@ -import typing -from dataclasses import dataclass - -from open_feature.exception.error_code import ErrorCode -from open_feature.flag_evaluation.reason import Reason - -T = typing.TypeVar("T", covariant=True) - - -@dataclass -class FlagEvaluationDetails(typing.Generic[T]): - flag_key: str - value: T - variant: typing.Optional[str] = None - reason: typing.Optional[Reason] = None - error_code: typing.Optional[ErrorCode] = None - error_message: typing.Optional[str] = None diff --git a/open_feature/flag_evaluation/flag_evaluation_options.py b/open_feature/flag_evaluation/flag_evaluation_options.py deleted file mode 100644 index 1a35542d..00000000 --- a/open_feature/flag_evaluation/flag_evaluation_options.py +++ /dev/null @@ -1,10 +0,0 @@ -import typing -from dataclasses import dataclass, field - -from open_feature.hooks.hook import Hook - - -@dataclass -class FlagEvaluationOptions: - hooks: typing.List[Hook] = field(default_factory=list) - hook_hints: dict = field(default_factory=dict) diff --git a/open_feature/flag_evaluation/flag_type.py b/open_feature/flag_evaluation/flag_type.py deleted file mode 100644 index 5408edf6..00000000 --- a/open_feature/flag_evaluation/flag_type.py +++ /dev/null @@ -1,9 +0,0 @@ -from enum import Enum - - -class FlagType(Enum): - BOOLEAN = "BOOLEAN" - STRING = "STRING" - OBJECT = "OBJECT" - FLOAT = "FLOAT" - INTEGER = "INTEGER" diff --git a/open_feature/flag_evaluation/reason.py b/open_feature/flag_evaluation/reason.py deleted file mode 100644 index e2b61eb1..00000000 --- a/open_feature/flag_evaluation/reason.py +++ /dev/null @@ -1,12 +0,0 @@ -from open_feature._backports.strenum import StrEnum - - -class Reason(StrEnum): - CACHED = "CACHED" - DEFAULT = "DEFAULT" - DISABLED = "DISABLED" - ERROR = "ERROR" - STATIC = "STATIC" - SPLIT = "SPLIT" - TARGETING_MATCH = "TARGETING_MATCH" - UNKNOWN = "UNKNOWN" diff --git a/open_feature/flag_evaluation/resolution_details.py b/open_feature/flag_evaluation/resolution_details.py deleted file mode 100644 index 80c255cd..00000000 --- a/open_feature/flag_evaluation/resolution_details.py +++ /dev/null @@ -1,17 +0,0 @@ -import typing -from dataclasses import dataclass - -from open_feature.exception.error_code import ErrorCode -from open_feature.flag_evaluation.reason import Reason - -T = typing.TypeVar("T", covariant=True) - - -@dataclass -class FlagResolutionDetails(typing.Generic[T]): - value: T - error_code: typing.Optional[ErrorCode] = None - error_message: typing.Optional[str] = None - reason: typing.Optional[Reason] = None - variant: typing.Optional[str] = None - flag_metadata: typing.Optional[str] = None diff --git a/open_feature/hooks/hook.py b/open_feature/hook/__init__.py similarity index 78% rename from open_feature/hooks/hook.py rename to open_feature/hook/__init__.py index f6f44d36..1287aa2a 100644 --- a/open_feature/hooks/hook.py +++ b/open_feature/hook/__init__.py @@ -1,9 +1,28 @@ +from __future__ import annotations +import typing from abc import abstractmethod +from dataclasses import dataclass +from enum import Enum -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.flag_evaluation.flag_evaluation_details import FlagEvaluationDetails -from open_feature.flag_evaluation.flag_type import FlagType -from open_feature.hooks.hook_context import HookContext +from open_feature.evaluation_context import EvaluationContext +from open_feature.flag_evaluation import FlagEvaluationDetails, FlagType + + +class HookType(Enum): + BEFORE = "before" + AFTER = "after" + FINALLY_AFTER = "finally_after" + ERROR = "error" + + +@dataclass +class HookContext: + flag_key: str + flag_type: FlagType + default_value: typing.Any + evaluation_context: EvaluationContext + client_metadata: typing.Optional[dict] = None + provider_metadata: typing.Optional[dict] = None class Hook: diff --git a/open_feature/hook/hook_support.py b/open_feature/hook/hook_support.py new file mode 100644 index 00000000..88a88fd2 --- /dev/null +++ b/open_feature/hook/hook_support.py @@ -0,0 +1,130 @@ +import logging +import typing +from functools import reduce + +from open_feature.evaluation_context import EvaluationContext +from open_feature.flag_evaluation import FlagEvaluationDetails, FlagType +from open_feature.hook import Hook, HookContext, HookType + + +def error_hooks( + flag_type: FlagType, + hook_context: HookContext, + exception: Exception, + hooks: typing.List[Hook], + hints: typing.Optional[typing.Mapping] = None, +): + kwargs = {"hook_context": hook_context, "exception": exception, "hints": hints} + _execute_hooks( + flag_type=flag_type, hooks=hooks, hook_method=HookType.ERROR, **kwargs + ) + + +def after_all_hooks( + flag_type: FlagType, + hook_context: HookContext, + hooks: typing.List[Hook], + hints: typing.Optional[typing.Mapping] = None, +): + kwargs = {"hook_context": hook_context, "hints": hints} + _execute_hooks( + flag_type=flag_type, hooks=hooks, hook_method=HookType.FINALLY_AFTER, **kwargs + ) + + +def after_hooks( + flag_type: FlagType, + hook_context: HookContext, + details: FlagEvaluationDetails, + hooks: typing.List[Hook], + hints: typing.Optional[typing.Mapping] = None, +): + kwargs = {"hook_context": hook_context, "details": details, "hints": hints} + _execute_hooks_unchecked( + flag_type=flag_type, hooks=hooks, hook_method=HookType.AFTER, **kwargs + ) + + +def before_hooks( + flag_type: FlagType, + hook_context: HookContext, + hooks: typing.List[Hook], + hints: typing.Optional[typing.Mapping] = None, +) -> EvaluationContext: + kwargs = {"hook_context": hook_context, "hints": hints} + executed_hooks = _execute_hooks_unchecked( + flag_type=flag_type, hooks=hooks, hook_method=HookType.BEFORE, **kwargs + ) + filtered_hooks = list(filter(lambda hook: hook is not None, executed_hooks)) + + if filtered_hooks: + return reduce(lambda a, b: a.merge(b), filtered_hooks) + + return EvaluationContext() + + +def _execute_hooks( + flag_type: FlagType, hooks: typing.List[Hook], hook_method: HookType, **kwargs +) -> list: + """ + Run multiple hooks of any hook type. All of these hooks will be run through an + exception check. + + :param flag_type: particular type of flag + :param hooks: a list of hooks + :param hook_method: the type of hook that is being run + :param kwargs: arguments that need to be provided to the hook method + :return: a list of results from the applied hook methods + """ + if hooks: + filtered_hooks = list( + filter( + lambda hook: hook.supports_flag_value_type(flag_type=flag_type), hooks + ) + ) + return [ + _execute_hook_checked(hook, hook_method, **kwargs) + for hook in filtered_hooks + ] + return [] + + +def _execute_hooks_unchecked( + flag_type: FlagType, hooks, hook_method: HookType, **kwargs +) -> list: + """ + 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 + client. + + :param flag_type: particular type of flag + :param hooks: a list of hooks + :param hook_method: the type of hook that is being run + :param kwargs: arguments that need to be provided to the hook method + :return: a list of results from the applied hook methods + """ + if hooks: + filtered_hooks = list( + filter( + lambda hook: hook.supports_flag_value_type(flag_type=flag_type), hooks + ) + ) + return [getattr(hook, hook_method.value)(**kwargs) for hook in filtered_hooks] + + return [] + + +def _execute_hook_checked(hook: Hook, hook_method: HookType, **kwargs): + """ + 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. + + :param hook: a list of hooks + :param hook_method: the type of hook that is being run + :param kwargs: arguments that need to be provided to the hook method + :return: the result of the hook method + """ + try: + return getattr(hook, hook_method.value)(**kwargs) + except Exception: # noqa + logging.error(f"Exception when running {hook_method.value} hooks") diff --git a/open_feature/hooks/__init__.py b/open_feature/hooks/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/open_feature/hooks/hook_context.py b/open_feature/hooks/hook_context.py deleted file mode 100644 index 7969a050..00000000 --- a/open_feature/hooks/hook_context.py +++ /dev/null @@ -1,15 +0,0 @@ -import typing -from dataclasses import dataclass - -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.flag_evaluation.flag_type import FlagType - - -@dataclass -class HookContext: - flag_key: str - flag_type: FlagType - default_value: typing.Any - evaluation_context: EvaluationContext - client_metadata: typing.Optional[dict] = None - provider_metadata: typing.Optional[dict] = None diff --git a/open_feature/hooks/hook_type.py b/open_feature/hooks/hook_type.py deleted file mode 100644 index f00b558a..00000000 --- a/open_feature/hooks/hook_type.py +++ /dev/null @@ -1,8 +0,0 @@ -from enum import Enum - - -class HookType(Enum): - BEFORE = "before" - AFTER = "after" - FINALLY_AFTER = "finally_after" - ERROR = "error" diff --git a/open_feature/provider/in_memory_provider.py b/open_feature/provider/in_memory_provider.py index 68e79fa1..02237db0 100644 --- a/open_feature/provider/in_memory_provider.py +++ b/open_feature/provider/in_memory_provider.py @@ -2,11 +2,10 @@ import typing from open_feature._backports.strenum import StrEnum -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.exception.error_code import ErrorCode -from open_feature.flag_evaluation.reason import Reason -from open_feature.flag_evaluation.resolution_details import FlagResolutionDetails -from open_feature.hooks.hook import Hook +from open_feature.evaluation_context import EvaluationContext +from open_feature.exception import ErrorCode +from open_feature.flag_evaluation import FlagResolutionDetails, Reason +from open_feature.hook import Hook from open_feature.provider.metadata import Metadata from open_feature.provider.provider import AbstractProvider diff --git a/open_feature/provider/no_op_provider.py b/open_feature/provider/no_op_provider.py index b5795cf1..4c5fecc3 100644 --- a/open_feature/provider/no_op_provider.py +++ b/open_feature/provider/no_op_provider.py @@ -1,9 +1,8 @@ import typing -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.flag_evaluation.reason import Reason -from open_feature.flag_evaluation.resolution_details import FlagResolutionDetails -from open_feature.hooks.hook import Hook +from open_feature.evaluation_context import EvaluationContext +from open_feature.flag_evaluation import FlagResolutionDetails, Reason +from open_feature.hook import Hook from open_feature.provider.metadata import Metadata from open_feature.provider.no_op_metadata import NoOpMetadata from open_feature.provider.provider import AbstractProvider diff --git a/open_feature/provider/provider.py b/open_feature/provider/provider.py index 3659f5a9..ea31177d 100644 --- a/open_feature/provider/provider.py +++ b/open_feature/provider/provider.py @@ -1,9 +1,9 @@ import typing from abc import abstractmethod -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.flag_evaluation.resolution_details import FlagResolutionDetails -from open_feature.hooks.hook import Hook +from open_feature.evaluation_context import EvaluationContext +from open_feature.flag_evaluation import FlagResolutionDetails +from open_feature.hook import Hook from open_feature.provider.metadata import Metadata diff --git a/readme.md b/readme.md index bb79e364..6cfc244b 100644 --- a/readme.md +++ b/readme.md @@ -66,11 +66,11 @@ pip install requirements.txt In order to use the sdk there is some minor configuration. Follow the script below: ```python -from open_feature import open_feature_api +from open_feature import api from open_feature.provider.no_op_provider import NoOpProvider -open_feature_api.set_provider(NoOpProvider()) -open_feature_client = open_feature_api.get_client() +api.set_provider(NoOpProvider()) +open_feature_client = api.get_client() ``` ### Basics: @@ -91,7 +91,7 @@ You can also bind a provider to a specific client by name instead of setting tha ```python -open_feature_api.set_provider(NoOpProvider()) +api.set_provider(NoOpProvider()) ``` Each provider class may have further setup required i.e. secret keys, environment variables etc @@ -103,7 +103,7 @@ In OpenFeature, we refer to this as [`targeting`](https://openfeature.dev/specif If the flag system you're using supports targeting, you can provide the input data using the `EvaluationContext`. ```python -from open_feature.open_feature_api import ( +from open_feature.api import ( get_client, get_provider, set_provider @@ -142,7 +142,7 @@ See [here](https://openfeature.dev/ecosystem) for a catalog of available provide A hook is a mechanism that allows for adding arbitrary behavior at well-defined points of the flag evaluation life-cycle. Use cases include validating the resolved flag value, modifying or adding data to the evaluation context, logging, telemetry, and tracking. ```python -from open_feature.hooks.hook import Hook +from open_feature.hook import Hook class MyHook(Hook): def after(self, hook_context: HookContext, details: FlagEvaluationDetails, hints: dict): @@ -150,7 +150,7 @@ class MyHook(Hook): # set global hooks at the API-level -from open_feature.open_feature_api import add_hooks +from open_feature.api import add_hooks add_hooks([MyHook()]) # or configure them in the client diff --git a/tests/conftest.py b/tests/conftest.py index af8467ff..c417272c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,6 @@ import pytest -from open_feature import open_feature_api as api +from open_feature import api from open_feature.provider.no_op_provider import NoOpProvider diff --git a/tests/evaluation_context/test_evaluation_context.py b/tests/evaluation_context/test_evaluation_context.py index a110ae41..ac3dcf60 100644 --- a/tests/evaluation_context/test_evaluation_context.py +++ b/tests/evaluation_context/test_evaluation_context.py @@ -1,4 +1,4 @@ -from open_feature.evaluation_context.evaluation_context import EvaluationContext +from open_feature.evaluation_context import EvaluationContext def test_empty_evaluation_context_can_be_merged_with_non_empty_context(): diff --git a/tests/features/data.py b/tests/features/data.py index f65b86c9..b4da35df 100644 --- a/tests/features/data.py +++ b/tests/features/data.py @@ -1,6 +1,5 @@ -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.flag_evaluation.reason import Reason -from open_feature.flag_evaluation.resolution_details import FlagResolutionDetails +from open_feature.evaluation_context import EvaluationContext +from open_feature.flag_evaluation import FlagResolutionDetails, Reason from open_feature.provider.in_memory_provider import InMemoryFlag diff --git a/tests/features/steps/steps.py b/tests/features/steps/steps.py index fec472f0..702036ed 100644 --- a/tests/features/steps/steps.py +++ b/tests/features/steps/steps.py @@ -2,12 +2,11 @@ from behave import given, then, when -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.exception.error_code import ErrorCode -from open_feature.flag_evaluation.flag_evaluation_details import FlagEvaluationDetails -from open_feature.flag_evaluation.reason import Reason -from open_feature.open_feature_api import get_client, set_provider -from open_feature.open_feature_client import OpenFeatureClient +from open_feature.api import get_client, set_provider +from open_feature.client import OpenFeatureClient +from open_feature.evaluation_context import EvaluationContext +from open_feature.exception import ErrorCode +from open_feature.flag_evaluation import FlagEvaluationDetails, Reason from open_feature.provider.in_memory_provider import InMemoryProvider from tests.features.data import IN_MEMORY_FLAGS diff --git a/open_feature/evaluation_context/__init__.py b/tests/hook/__init__.py similarity index 100% rename from open_feature/evaluation_context/__init__.py rename to tests/hook/__init__.py diff --git a/tests/hooks/conftest.py b/tests/hook/conftest.py similarity index 82% rename from tests/hooks/conftest.py rename to tests/hook/conftest.py index 1fed4353..2671e7fd 100644 --- a/tests/hooks/conftest.py +++ b/tests/hook/conftest.py @@ -2,7 +2,7 @@ import pytest -from open_feature.evaluation_context.evaluation_context import EvaluationContext +from open_feature.evaluation_context import EvaluationContext @pytest.fixture() diff --git a/tests/hooks/test_hook_support.py b/tests/hook/test_hook_support.py similarity index 90% rename from tests/hooks/test_hook_support.py rename to tests/hook/test_hook_support.py index 28914c4b..7b748349 100644 --- a/tests/hooks/test_hook_support.py +++ b/tests/hook/test_hook_support.py @@ -1,9 +1,8 @@ from unittest.mock import ANY -from open_feature.flag_evaluation.flag_evaluation_details import FlagEvaluationDetails -from open_feature.flag_evaluation.flag_type import FlagType -from open_feature.hooks.hook_context import HookContext -from open_feature.hooks.hook_support import ( +from open_feature.flag_evaluation import FlagEvaluationDetails, FlagType +from open_feature.hook import HookContext +from open_feature.hook.hook_support import ( after_all_hooks, after_hooks, before_hooks, diff --git a/tests/hooks/__init__.py b/tests/hooks/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/provider/test_in_memory_provider.py b/tests/provider/test_in_memory_provider.py index 40969115..61f4d562 100644 --- a/tests/provider/test_in_memory_provider.py +++ b/tests/provider/test_in_memory_provider.py @@ -1,8 +1,7 @@ from numbers import Number -from open_feature.exception.error_code import ErrorCode -from open_feature.flag_evaluation.reason import Reason -from open_feature.flag_evaluation.resolution_details import FlagResolutionDetails +from open_feature.exception import ErrorCode +from open_feature.flag_evaluation import FlagResolutionDetails, Reason from open_feature.provider.in_memory_provider import InMemoryProvider, InMemoryFlag diff --git a/tests/test_open_feature_api.py b/tests/test_api.py similarity index 91% rename from tests/test_open_feature_api.py rename to tests/test_api.py index 9a976f72..270f7760 100644 --- a/tests/test_open_feature_api.py +++ b/tests/test_api.py @@ -2,11 +2,7 @@ import pytest -from open_feature.evaluation_context.evaluation_context import EvaluationContext -from open_feature.hooks.hook import Hook -from open_feature.exception.error_code import ErrorCode -from open_feature.exception.exceptions import GeneralError -from open_feature.open_feature_api import ( +from open_feature.api import ( get_client, get_provider, set_provider, @@ -17,6 +13,9 @@ add_hooks, clear_hooks, ) +from open_feature.evaluation_context import EvaluationContext +from open_feature.exception import ErrorCode, GeneralError +from open_feature.hook import Hook from open_feature.provider.metadata import Metadata from open_feature.provider.no_op_provider import NoOpProvider diff --git a/tests/test_open_feature_client.py b/tests/test_client.py similarity index 92% rename from tests/test_open_feature_client.py rename to tests/test_client.py index b8171ba4..65615a32 100644 --- a/tests/test_open_feature_client.py +++ b/tests/test_client.py @@ -2,12 +2,11 @@ import pytest -from open_feature.open_feature_api import add_hooks, clear_hooks -from open_feature.exception.error_code import ErrorCode -from open_feature.exception.exceptions import OpenFeatureError -from open_feature.flag_evaluation.reason import Reason -from open_feature.hooks.hook import Hook -from open_feature.open_feature_client import OpenFeatureClient +from open_feature.api import add_hooks, clear_hooks +from open_feature.client import OpenFeatureClient +from open_feature.exception import ErrorCode, OpenFeatureError +from open_feature.flag_evaluation import Reason +from open_feature.hook import Hook from open_feature.provider.no_op_provider import NoOpProvider diff --git a/tests/test_open_feature_flag_evaluation.py b/tests/test_flag_evaluation.py similarity index 86% rename from tests/test_open_feature_flag_evaluation.py rename to tests/test_flag_evaluation.py index ee408d90..8baca90e 100644 --- a/tests/test_open_feature_flag_evaluation.py +++ b/tests/test_flag_evaluation.py @@ -1,6 +1,5 @@ -from open_feature.exception.error_code import ErrorCode -from open_feature.flag_evaluation.flag_evaluation_details import FlagEvaluationDetails -from open_feature.flag_evaluation.reason import Reason +from open_feature.exception import ErrorCode +from open_feature.flag_evaluation import FlagEvaluationDetails, Reason def test_evaulation_details_reason_should_be_a_string():