Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c65fd01
added models, events config data and events metadata
chillaq Jan 7, 2026
661d248
updated metadata to recent spec
chillaq Jan 8, 2026
5d814b5
added events manager and events delivery
chillaq Jan 9, 2026
a37d3b9
added internal sdk task
chillaq Jan 12, 2026
e019bb3
polish
chillaq Jan 13, 2026
a5aa01d
Merge pull request #608 from splitio/FME-12219-sdk-events-models
chillaq Jan 13, 2026
59a5530
polish
chillaq Jan 13, 2026
b92badd
Merge pull request #610 from splitio/FME-12220-sdk-events-manager
chillaq Jan 13, 2026
7c91986
polish
chillaq Jan 13, 2026
27792de
Merge pull request #611 from splitio/FME-12221-sdk-event-task
chillaq Jan 13, 2026
6e3ea36
Updated split storage
chillaq Jan 13, 2026
0989330
Merge pull request #612 from splitio/FME-12222-sdk-events-split-storage
chillaq Jan 13, 2026
b00410d
updated segments and rb segments storages
chillaq Jan 14, 2026
00227ce
Merge pull request #613 from splitio/FME-12223-sdk-events-segments
chillaq Jan 14, 2026
8171606
update factory class for ready and timedout events
chillaq Jan 14, 2026
6d344a6
updated client and factory classes
chillaq Jan 16, 2026
c14e651
Merge pull request #614 from splitio/FME-12227-sdk-events-factory
chillaq Jan 16, 2026
02027af
Merge pull request #615 from splitio/FME-12224-sdk-event-client
chillaq Jan 16, 2026
f0d85ba
updated sdk ready firing after subscription and integration tests
chillaq Jan 16, 2026
983a740
avoid fire events if no items added or removed from storage
chillaq Jan 20, 2026
0df687f
Merge pull request #616 from splitio/FME-12225-sdk-events-integration
chillaq Jan 20, 2026
7194c0a
added async classes
chillaq Jan 21, 2026
f2ad152
finish tests
chillaq Jan 21, 2026
4327a30
updated localhost classes and tests
chillaq Jan 22, 2026
e7f721a
fixed typo for segment event type
chillaq Jan 22, 2026
b92aa3c
Merge branch 'feature/sdk-events' into FME-12276-async-classes
chillaq Jan 22, 2026
11d56fd
fixed typo for segment update type
chillaq Jan 22, 2026
f2608fa
Merge branch 'FME-12276-async-classes' into FME-12226-events-localhost
chillaq Jan 22, 2026
e06630f
Merge pull request #617 from splitio/FME-12276-async-classes
chillaq Jan 22, 2026
06950f0
Merge pull request #618 from splitio/FME-12226-events-localhost
chillaq Jan 22, 2026
8f29ba9
ignored fetching rbs if list is empty
chillaq Jan 22, 2026
3849e9b
Merge pull request #619 from splitio/FME-12322-fix-redis-prefix
chillaq Jan 22, 2026
09dd7e5
removed name param from creat_task, supported only after 3.8
chillaq Jan 22, 2026
15ca507
updated changes
chillaq Jan 27, 2026
27e2592
fixed test
chillaq Jan 27, 2026
2244773
polishing
chillaq Jan 27, 2026
3a9d2a7
fixed calling fire event function
chillaq Jan 27, 2026
43dfb55
updated license and added notice
chillaq Jan 27, 2026
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
Next Next commit
added models, events config data and events metadata
  • Loading branch information
chillaq committed Jan 7, 2026
commit c65fd014fa7d971e50c1ac6c5da81ddb91aaddc7
Empty file added splitio/events/__init__.py
Empty file.
124 changes: 124 additions & 0 deletions splitio/events/events_manager_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
"""Events Manager Configuration."""
from splitio.models.events import SdkEvent, SdkInternalEvent

class EventsManagerConfig(object):
"""Events Manager Configurations class."""

def __init__(self):
"""
Construct Events Manager Configuration instance.
"""
self._require_all = self._get_require_all()
self._prerequisites = self._get_prerequisites()
self._require_any = self._get_require_any()
self._suppressed_by = self._get_suppressed_by()
self._execution_limits = self._get_execution_limits()
self._evaluation_order = self._get_sorted_events()

@property
def require_all(self):
"""Return require all dict"""
return self._require_all

@property
def prerequisites(self):
"""Return prerequisites dict"""
return self._prerequisites

@property
def require_any(self):
"""Return require_any dict"""
return self._require_any

@property
def suppressed_by(self):
"""Return suppressed_by dict"""
return self._suppressed_by

@property
def execution_limits(self):
"""Return execution_limits dict"""
return self._execution_limits

@property
def prerequisites(self):
"""Return require all dict"""
return self._prerequisites

@property
def evaluation_order(self):
"""Return evaluation_order dict"""
return self._evaluation_order

@property
def sorted_events(self):
"""Return sorted_events dict"""
return self._sorted_events

def _get_require_all(self):
"""Return require all dict"""
return {
SdkEvent.SDK_READY: {SdkInternalEvent.SDK_READY}
}

def _get_prerequisites(self):
"""Return prerequisites dict"""
return {
SdkEvent.SDK_UPDATE: {SdkEvent.SDK_READY}
}

def _get_require_any(self):
"""Return require_any dict"""
return {
SdkEvent.SDK_UPDATE: {SdkInternalEvent.FLAG_KILLED_NOTIFICATION, SdkInternalEvent.FLAGS_UPDATED,
SdkInternalEvent.RB_SEGMENTS_UPDATED, SdkInternalEvent.SEGMENTS_UPDATED},
SdkEvent.SDK_READY_TIMED_OUT: {SdkInternalEvent.SDK_TIMED_OUT}
}

def _get_suppressed_by(self):
"""Return suppressed_by dict"""
return {
SdkEvent.SDK_READY_TIMED_OUT: {SdkEvent.SDK_READY}
}

def _get_execution_limits(self):
"""Return execution_limits dict"""
return {
SdkEvent.SDK_READY: 1,
SdkEvent.SDK_READY_TIMED_OUT: -1,
SdkEvent.SDK_UPDATE: -1
}

def _get_sorted_events(self):
"""Return dorted events set"""
sorted_events = []
for sdk_event in [SdkEvent.SDK_READY, SdkEvent.SDK_READY_TIMED_OUT, SdkEvent.SDK_UPDATE]:
sorted_events = self._dfs_recursive(sdk_event, sorted_events)

return sorted_events


def _dfs_recursive(self, sdk_event, added):
"""Return sorted events set based on the dependency rules"""
if sdk_event in added:
return added

for dependent_event in self._get_dependencies(sdk_event):
added = self._dfs_recursive(dependent_event, added)

added.append(sdk_event)
return added

def _get_dependencies(self, sdk_event):
"""Return dependencies set from prerequisites and suppressed events for a given event"""
dependencies = set()
for prerequisites_event_name, prerequisites_event_value in self.prerequisites.items():
if prerequisites_event_name == sdk_event:
for prereq_event in prerequisites_event_value:
dependencies.add(prereq_event)

for suppressed_event_name, suppressed_event_value in self.suppressed_by.items():
if sdk_event in suppressed_event_value:
dependencies.add(suppressed_event_name)

return dependencies
46 changes: 46 additions & 0 deletions splitio/events/events_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""Events Metadata."""
from splitio.models.events import SdkEvent, SdkInternalEvent

class EventsMetadata(object):
"""Events Metadata class."""

def __init__(self, metadata):
"""
Construct Events Metadata instance.
"""
self._metadata = self._sanitize(metadata)

def get_data(self):
"""Return metadata dict"""
return self._metadata

def get_keys(self):
"""Return metadata dict keys"""
return self._metadata.keys()

def get_values(self):
"""Return metadata dict values"""
return self._metadata.values()

def contain_key(self, key):
"""Return True if key is contained in metadata"""
return key in self._metadata.keys()

def _sanitize(self, data):
"""Return sanitized metadata dict with values either int, bool, str or list """
santized_data = {}
for item_name, item_value in data.items():
if self._value_is_valid(item_value):
santized_data[item_name] = item_value

return santized_data

def _value_is_valid(self, value):
"""Return bool if values is int, bool, str or list[str] """
if (value is not None) and (isinstance(value, int) or isinstance(value, bool) or isinstance(value, str)):
return True

if isinstance(value, set):
return any([isinstance(item, str) for item in value])

return False
22 changes: 21 additions & 1 deletion splitio/models/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
The dto is implemented as a namedtuple for performance matters.
"""
from collections import namedtuple

from enum import Enum

Event = namedtuple('Event', [
'key',
Expand All @@ -19,3 +19,23 @@
'event',
'size',
])

class SdkEvent(Enum):
"""Public SDK events"""

SDK_READY = 'SDK_READY'
SDK_READY_TIMED_OUT = 'SDK_READY_TIMED_OUT'
SDK_UPDATE = 'SDK_UPDATE'

class SdkInternalEvent(Enum):
"""Internal SDK events"""

SDK_READY = 'SDK_READY'
SDK_TIMED_OUT = 'SDK_TIMED_OUT'
FLAGS_UPDATED = 'FLAGS_UPDATED'
FLAG_KILLED_NOTIFICATION = 'FLAG_KILLED_NOTIFICATION'
SEGMENTS_UPDATED = 'SEGMENTS_UPDATED'
RB_SEGMENTS_UPDATED = 'RB_SEGMENTS_UPDATED'
LARGE_SEGMENTS_UPDATED = 'LARGE_SEGMENTS_UPDATED'


43 changes: 43 additions & 0 deletions tests/events/test_events_manager_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""EventsManagerConfig test module."""
import pytest

from splitio.events.events_manager_config import EventsManagerConfig
from splitio.models.events import SdkEvent, SdkInternalEvent

class EventsManagerConfigTests(object):
"""Tests for EventsManagerConfig."""

def test_build_instance(self):
config = EventsManagerConfig()

assert len(config.require_all[SdkEvent.SDK_READY]) == 1
assert SdkInternalEvent.SDK_READY in config.require_all[SdkEvent.SDK_READY]

assert SdkEvent.SDK_READY in config.prerequisites[SdkEvent.SDK_UPDATE]

assert config.execution_limits[SdkEvent.SDK_READY_TIMED_OUT] == -1
assert config.execution_limits[SdkEvent.SDK_UPDATE] == -1
assert config.execution_limits[SdkEvent.SDK_READY] == 1

assert len(config.require_any[SdkEvent.SDK_READY_TIMED_OUT]) == 1
assert SdkInternalEvent.SDK_TIMED_OUT in config.require_any[SdkEvent.SDK_READY_TIMED_OUT]

assert len(config.require_any[SdkEvent.SDK_UPDATE]) == 4
assert SdkInternalEvent.FLAG_KILLED_NOTIFICATION in config.require_any[SdkEvent.SDK_UPDATE]
assert SdkInternalEvent.FLAGS_UPDATED in config.require_any[SdkEvent.SDK_UPDATE]
assert SdkInternalEvent.RB_SEGMENTS_UPDATED in config.require_any[SdkEvent.SDK_UPDATE]
assert SdkInternalEvent.SEGMENTS_UPDATED in config.require_any[SdkEvent.SDK_UPDATE]

assert len(config.suppressed_by[SdkEvent.SDK_READY_TIMED_OUT]) == 1
assert SdkEvent.SDK_READY in config.suppressed_by[SdkEvent.SDK_READY_TIMED_OUT]

order = 0
assert len(config.evaluation_order) == 3
for sdk_event in config.evaluation_order:
order += 1
if order == 1:
assert sdk_event == SdkEvent.SDK_READY_TIMED_OUT
if order == 2:
assert sdk_event == SdkEvent.SDK_READY
if order == 3:
assert sdk_event == SdkEvent.SDK_UPDATE
28 changes: 28 additions & 0 deletions tests/events/test_events_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""EventsMetadata test module."""
import pytest

from splitio.events.events_metadata import EventsMetadata
from splitio.models.events import SdkEvent, SdkInternalEvent

class EventsMetadataTests(object):
"""Tests for EventsMetadata."""

def test_build_instance(self):
data = { "updatedFlags": { "feature1" }, "sdkTimeout": 10 , "boolValue": True, "strValue": "value" }
metadata = EventsMetadata(data)

assert len(metadata.get_keys()) == 4
assert metadata.get_data()["updatedFlags"].pop() == "feature1"
assert len(metadata.get_data()["updatedFlags"]) == 0
assert metadata.get_data()["sdkTimeout"] == 10
assert metadata.get_data()["boolValue"] == True
assert metadata.get_data()["strValue"] == "value"
assert metadata.contain_key("updatedFlags")
assert not metadata.contain_key("not_exist")
assert len(metadata.get_values()) == 4

def test_sanitize_none_input(self):
data = { "updatedFlags": { "feature1" }, "sdkTimeout": None, "strValue": [1, 2, 3] }
metadata = EventsMetadata(data)
assert len(metadata.get_keys()) == 1
assert metadata.get_data()["updatedFlags"].pop() == "feature1"