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
10 changes: 10 additions & 0 deletions devcycle_python_sdk/api/local_bucketing.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from devcycle_python_sdk.models.user import DevCycleUser
from devcycle_python_sdk.models.variable import Variable, determine_variable_type
from devcycle_python_sdk.models.event import FlushPayload
from devcycle_python_sdk.models.config_metadata import ConfigMetadata

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -140,6 +141,7 @@ def __console_log_func(message_ptr) -> None:
"generateBucketedConfigForUserUTF8"
)
self.VariableForUserProtobuf = self._get_export("variableForUser_PB")
self.getConfigMetadata = self._get_export("getConfigMetadata")

# Extract variable type enum values from WASM
self.variable_type_map = {
Expand Down Expand Up @@ -357,6 +359,14 @@ def store_config(self, config_json: str) -> None:
config_addr = self._new_assembly_script_byte_array(data)
self.setConfigDataUTF8(self.wasm_store, self.sdk_key_addr, config_addr)

def get_config_metadata(self) -> Optional[ConfigMetadata]:
with self.wasm_lock:
config_addr = self.getConfigMetadata(self.wasm_store, self.sdk_key_addr)
config_bytes = self._read_assembly_script_string(config_addr)
config_data = json.loads(config_bytes.encode("utf-8"))

return ConfigMetadata.from_json(config_data)

def set_platform_data(self, platform_json: str) -> None:
with self.wasm_lock:
data = platform_json.encode("utf-8")
Expand Down
Binary file modified devcycle_python_sdk/bucketing-lib.release.wasm
Binary file not shown.
4 changes: 3 additions & 1 deletion devcycle_python_sdk/local_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ def variable(self, user: DevCycleUser, key: str, default_value: Any) -> Variable
key, default_value, DefaultReasonDetails.MISSING_CONFIG
)

context = HookContext(key, user, default_value)
config_metadata = self.local_bucketing.get_config_metadata()

context = HookContext(key, user, default_value, config_metadata)
variable = Variable.create_default_variable(
key=key, default_value=default_value
)
Expand Down
4 changes: 4 additions & 0 deletions devcycle_python_sdk/managers/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from wsgiref.handlers import format_date_time
from devcycle_python_sdk.options import DevCycleLocalOptions
from devcycle_python_sdk.managers.sse_manager import SSEManager
from devcycle_python_sdk.models.config_metadata import ConfigMetadata

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -108,6 +109,9 @@ def _get_config(self, last_modified: Optional[float] = None):
)
self._polling_enabled = False

def get_config_metadata(self) -> Optional[ConfigMetadata]:
return self._local_bucketing.get_config_metadata()

def run(self):
while self._polling_enabled:
try:
Expand Down
32 changes: 32 additions & 0 deletions devcycle_python_sdk/models/config_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from devcycle_python_sdk.models.environment_metadata import EnvironmentMetadata
from devcycle_python_sdk.models.project_metadata import ProjectMetadata
from typing import Dict, Any, Optional
import json


class ConfigMetadata:
def __init__(
self,
project: ProjectMetadata,
environment: EnvironmentMetadata,
):
self.project = project
self.environment = environment

def to_json(self) -> str:
return json.dumps(self, default=lambda o: o.__dict__)

@staticmethod
def from_json(json_obj: Optional[Dict[str, Any]]) -> Optional["ConfigMetadata"]:
if json_obj is None:
return None
project = ProjectMetadata.from_json(json_obj.get("project"))
environment = EnvironmentMetadata.from_json(json_obj.get("environment"))

if project is None or environment is None:
return None

return ConfigMetadata(
project=project,
environment=environment,
)
22 changes: 22 additions & 0 deletions devcycle_python_sdk/models/environment_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from typing import Dict, Any, Optional


class EnvironmentMetadata:
def __init__(
self,
id: str,
key: str,
):
self.id = id
self.key = key

@staticmethod
def from_json(
json_obj: Optional[Dict[str, Any]],
) -> Optional["EnvironmentMetadata"]:
if json_obj is None:
return None
return EnvironmentMetadata(
id=json_obj["id"],
key=json_obj["key"],
)
12 changes: 10 additions & 2 deletions devcycle_python_sdk/models/eval_hook_context.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
from typing import Any
from typing import Any, Optional

from devcycle_python_sdk.models.user import DevCycleUser
from devcycle_python_sdk.models.config_metadata import ConfigMetadata


class HookContext:
def __init__(self, key: str, user: DevCycleUser, default_value: Any):
def __init__(
self,
key: str,
user: DevCycleUser,
default_value: Any,
config_metadata: Optional[ConfigMetadata] = None,
):
self.key = key
self.default_value = default_value
self.user = user
self.config_metadata = config_metadata
20 changes: 20 additions & 0 deletions devcycle_python_sdk/models/project_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import Dict, Any, Optional


class ProjectMetadata:
def __init__(
self,
id: str,
key: str,
):
self.id = id
self.key = key

@staticmethod
def from_json(json_obj: Optional[Dict[str, Any]]) -> Optional["ProjectMetadata"]:
if json_obj is None:
return None
return ProjectMetadata(
id=json_obj["id"],
key=json_obj["key"],
)
2 changes: 1 addition & 1 deletion devcycle_python_sdk/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def __init__(

if self.event_request_chunk_size > self.max_event_queue_size:
logger.warning(
f"DevCycle: event_request_chunk_size: {self.event_request_chunk_size} must be smaller than max_event_queue_size: { self.max_event_queue_size}"
f"DevCycle: event_request_chunk_size: {self.event_request_chunk_size} must be smaller than max_event_queue_size: {self.max_event_queue_size}"
)
self.event_request_chunk_size = 100

Expand Down
12 changes: 9 additions & 3 deletions devcycle_python_sdk/protobuf/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,17 @@ def create_nullable_custom_data(val: Optional[dict]) -> pb2.NullableCustomData:
if value is None:
values[key] = pb2.CustomDataValue(type=pb2.CustomDataType.Null) # type: ignore
elif isinstance(value, bool):
values[key] = pb2.CustomDataValue(type=pb2.CustomDataType.Bool, boolValue=value) # type: ignore
values[key] = pb2.CustomDataValue(
type=pb2.CustomDataType.Bool, boolValue=value
) # type: ignore
elif isinstance(value, str):
values[key] = pb2.CustomDataValue(type=pb2.CustomDataType.Str, stringValue=value) # type: ignore
values[key] = pb2.CustomDataValue(
type=pb2.CustomDataType.Str, stringValue=value
) # type: ignore
elif isinstance(value, (int, float)):
values[key] = pb2.CustomDataValue(type=pb2.CustomDataType.Num, doubleValue=value) # type: ignore
values[key] = pb2.CustomDataValue(
type=pb2.CustomDataType.Num, doubleValue=value
) # type: ignore
else:
logger.warning(
f"Custom Data contains data type that can't be written, will be ignored. Key: {key}, Type: {str(type(value))}"
Expand Down
76 changes: 34 additions & 42 deletions devcycle_python_sdk/protobuf/variableForUserParams_pb2.py

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

Loading
Loading