Skip to content

Commit

Permalink
fix(python): Add exporter metadata to the evaluation context
Browse files Browse the repository at this point in the history
Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
  • Loading branch information
thomaspoignant committed Jan 24, 2025
1 parent 56c6775 commit b84fb73
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 26 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ repos:
entry: golangci-lint run --enable-only=gci --fix

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.11.0
rev: 24.10.0
hooks:
- id: black
language_version: python3.12
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import json
from http import HTTPStatus
from threading import Thread
from typing import List, Optional, Type, Union
from urllib.parse import urljoin

import pylru
import urllib3
import websocket
from gofeatureflag_python_provider.data_collector_hook import DataCollectorHook
from gofeatureflag_python_provider.metadata import GoFeatureFlagMetadata
from gofeatureflag_python_provider.options import BaseModel, GoFeatureFlagOptions
from gofeatureflag_python_provider.request_flag_evaluation import (
RequestFlagEvaluation,
convert_evaluation_context,
)
from gofeatureflag_python_provider.response_flag_evaluation import (
JsonType,
ResponseFlagEvaluation,
)
from http import HTTPStatus
from openfeature.evaluation_context import EvaluationContext
from openfeature.exception import (
ErrorCode,
Expand All @@ -17,21 +24,11 @@
)
from openfeature.flag_evaluation import FlagResolutionDetails, Reason
from openfeature.hook import Hook
from openfeature.provider.metadata import Metadata
from openfeature.provider import AbstractProvider
from openfeature.provider.metadata import Metadata
from pydantic import PrivateAttr, ValidationError

from gofeatureflag_python_provider.data_collector_hook import DataCollectorHook
from gofeatureflag_python_provider.metadata import GoFeatureFlagMetadata
from gofeatureflag_python_provider.options import BaseModel, GoFeatureFlagOptions
from gofeatureflag_python_provider.request_flag_evaluation import (
RequestFlagEvaluation,
convert_evaluation_context,
)
from gofeatureflag_python_provider.response_flag_evaluation import (
JsonType,
ResponseFlagEvaluation,
)
from threading import Thread
from typing import List, Optional, Type, Union

AbstractProviderMetaclass = type(AbstractProvider)
BaseModelMetaclass = type(BaseModel)
Expand Down Expand Up @@ -196,6 +193,16 @@ def generic_go_feature_flag_resolver(
"/v1/feature/{}/eval".format(flag_key),
)

# add exporter metadata to the context if it exists
if self.options.exporter_metadata:
goff_request.gofeatureflag["exporterMetadata"] = (
self.options.exporter_metadata
)
goff_request.gofeatureflag["exporterMetadata"]["openfeature"] = True
goff_request.gofeatureflag["exporterMetadata"][
"provider"
] = "python"

response = self._http_client.request(
method="POST",
url=url,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import hashlib
import json
from typing import Optional, Any

from gofeatureflag_python_provider.options import BaseModel
from openfeature.evaluation_context import EvaluationContext
from openfeature.exception import (
TargetingKeyMissingError,
InvalidContextError,
)
from pydantic import SkipValidation

from gofeatureflag_python_provider.options import BaseModel
from typing import Optional, Any, Dict


class GoFeatureFlagEvaluationContext(BaseModel):
Expand Down Expand Up @@ -56,3 +54,4 @@ def convert_evaluation_context(
class RequestFlagEvaluation(BaseModel):
user: GoFeatureFlagEvaluationContext
defaultValue: SkipValidation[Any] = None
gofeatureflag: Optional[Dict] = {}
6 changes: 3 additions & 3 deletions openfeature/providers/python-provider/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,50 @@ def test_url_parsing(mock_request):
assert got == want


@patch("urllib3.poolmanager.PoolManager.request")
def test_should_call_evaluation_api_with_exporter_metadata(
mock_request: Mock,
):
flag_key = "bool_targeting_match"
default_value = False
mock_request.side_effect = [
Mock(
status="200", data=_read_mock_file(flag_key)
), # first call to get the flag
Mock(status="200", data={}), # second call to send the data
Mock(status="200", data={}),
]
goff_provider = GoFeatureFlagProvider(
options=GoFeatureFlagOptions(
endpoint="https://gofeatureflag.org/",
data_flush_interval=100,
disable_cache_invalidation=True,
exporter_metadata={"version": "1.0.0", "name": "myapp", "id": 123},
)
)
api.set_provider(goff_provider)
client = api.get_client(domain="test-client")

client.get_boolean_details(
flag_key=flag_key,
default_value=default_value,
evaluation_context=_default_evaluation_ctx,
)

api.shutdown()
got = json.loads(mock_request.call_args.kwargs["body"])["gofeatureflag"]
want = {
"exporterMetadata": {
"version": "1.0.0",
"name": "myapp",
"id": 123,
"provider": "python",
"openfeature": True,
},
}
assert got == want


def _read_mock_file(flag_key: str) -> str:
# This hacky if is here to make test run inside pycharm and from the root of the project
if os.getcwd().endswith("/tests"):
Expand Down

0 comments on commit b84fb73

Please sign in to comment.