splitio-client 10.1.0rc3__tar.gz → 10.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- splitio_client-10.2.0/LICENSE.txt +13 -0
- splitio_client-10.2.0/PKG-INFO +125 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/setup.cfg +1 -1
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/client.py +27 -24
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/factory.py +15 -15
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/evaluator.py +2 -1
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/impressions/__init__.py +20 -20
- splitio_client-10.2.0/splitio/engine/impressions/impressions.py +55 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/impressions.py +8 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/splits.py +17 -5
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/recorder/recorder.py +8 -8
- splitio_client-10.2.0/splitio/version.py +1 -0
- splitio_client-10.2.0/splitio_client.egg-info/PKG-INFO +125 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio_client.egg-info/SOURCES.txt +1 -0
- splitio_client-10.1.0rc3/PKG-INFO +0 -101
- splitio_client-10.1.0rc3/splitio/engine/impressions/impressions.py +0 -41
- splitio_client-10.1.0rc3/splitio/version.py +0 -1
- splitio_client-10.1.0rc3/splitio_client.egg-info/PKG-INFO +0 -101
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/README.md +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/setup.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/auth.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/client.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/commons.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/events.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/impressions.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/segments.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/splits.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/api/telemetry.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/config.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/input_validator.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/key.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/listener.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/localhost.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/manager.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/client/util.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/cache/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/cache/lru.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/filters.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/hashfns/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/hashfns/legacy.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/hashfns/murmur3py.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/impressions/adapters.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/impressions/manager.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/impressions/strategies.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/impressions/unique_keys_tracker.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/splitters.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/engine/telemetry.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/exceptions.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/factories.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/impressions.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/key.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/datatypes.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/events.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/condition.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/base.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/keys.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/misc.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/numeric.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/semver.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/sets.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/string.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/utils/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/matchers/utils/utils.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/grammar/partitions.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/notification.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/segments.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/telemetry.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/models/token.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/optional/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/optional/loaders.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/push/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/push/manager.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/push/parser.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/push/processor.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/push/splitsse.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/push/sse.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/push/status_tracker.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/push/workers.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/recorder/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/spec.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/storage/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/storage/adapters/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/storage/adapters/cache_trait.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/storage/adapters/redis.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/storage/adapters/util.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/storage/inmemmory.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/storage/pluggable.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/storage/redis.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/event.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/impression.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/manager.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/segment.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/split.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/synchronizer.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/telemetry.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/unique_keys.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/sync/util.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/events_sync.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/impressions_sync.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/segment_sync.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/split_sync.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/telemetry_sync.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/unique_keys_sync.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/util/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/util/asynctask.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/tasks/util/workerpool.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/util/__init__.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/util/backoff.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/util/decorators.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/util/storage_helper.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/util/threadutil.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio/util/time.py +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio_client.egg-info/dependency_links.txt +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio_client.egg-info/requires.txt +0 -0
- {splitio_client-10.1.0rc3 → splitio_client-10.2.0}/splitio_client.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright © 2025 Split Software, Inc.
|
|
2
|
+
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
See the License for the specific language governing permissions and
|
|
13
|
+
limitations under the License.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: splitio_client
|
|
3
|
+
Version: 10.2.0
|
|
4
|
+
Summary: Split.io Python Client
|
|
5
|
+
Home-page: https://github.com/splitio/python-client
|
|
6
|
+
Download-URL: https://github.com/splitio/python-client/tarball/10.2.0
|
|
7
|
+
Author: Patricio Echague, Sebastian Arrubia
|
|
8
|
+
Author-email: pato@split.io, sebastian@split.io
|
|
9
|
+
License: Apache License 2.0
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 2
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.txt
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Requires-Dist: pyyaml
|
|
20
|
+
Requires-Dist: docopt>=0.6.2
|
|
21
|
+
Requires-Dist: enum34; python_version < "3.4"
|
|
22
|
+
Requires-Dist: bloom-filter2>=2.0.0
|
|
23
|
+
Provides-Extra: test
|
|
24
|
+
Requires-Dist: flake8; extra == "test"
|
|
25
|
+
Requires-Dist: pytest==7.0.1; extra == "test"
|
|
26
|
+
Requires-Dist: pytest-mock==3.11.1; extra == "test"
|
|
27
|
+
Requires-Dist: coverage; extra == "test"
|
|
28
|
+
Requires-Dist: pytest-cov==4.1.0; extra == "test"
|
|
29
|
+
Requires-Dist: importlib-metadata==6.7; extra == "test"
|
|
30
|
+
Requires-Dist: tomli==1.2.3; extra == "test"
|
|
31
|
+
Requires-Dist: iniconfig==1.1.1; extra == "test"
|
|
32
|
+
Requires-Dist: attrs==22.1.0; extra == "test"
|
|
33
|
+
Requires-Dist: pytest-asyncio==0.21.0; extra == "test"
|
|
34
|
+
Requires-Dist: aiohttp>=3.8.4; extra == "test"
|
|
35
|
+
Requires-Dist: aiofiles>=23.1.0; extra == "test"
|
|
36
|
+
Requires-Dist: requests-kerberos>=0.15.0; extra == "test"
|
|
37
|
+
Provides-Extra: redis
|
|
38
|
+
Requires-Dist: redis>=2.10.5; extra == "redis"
|
|
39
|
+
Provides-Extra: uwsgi
|
|
40
|
+
Requires-Dist: uwsgi>=2.0.0; extra == "uwsgi"
|
|
41
|
+
Provides-Extra: cpphash
|
|
42
|
+
Requires-Dist: mmh3cffi==0.2.1; extra == "cpphash"
|
|
43
|
+
Provides-Extra: asyncio
|
|
44
|
+
Requires-Dist: aiohttp>=3.8.4; extra == "asyncio"
|
|
45
|
+
Requires-Dist: aiofiles>=23.1.0; extra == "asyncio"
|
|
46
|
+
Provides-Extra: kerberos
|
|
47
|
+
Requires-Dist: requests-kerberos>=0.15.0; extra == "kerberos"
|
|
48
|
+
|
|
49
|
+
# Split Python SDK
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
## Overview
|
|
53
|
+
This SDK is designed to work with Split, the platform for controlled rollouts, which serves features to your users via a Split feature flag to manage your complete customer experience.
|
|
54
|
+
|
|
55
|
+
[](https://twitter.com/intent/follow?screen_name=splitsoftware)
|
|
56
|
+
|
|
57
|
+
## Compatibility
|
|
58
|
+
This SDK is compatible with **Python 3.7 and higher**.
|
|
59
|
+
|
|
60
|
+
## Getting started
|
|
61
|
+
Below is a simple example that describes the instantiation and most basic usage of our SDK:
|
|
62
|
+
|
|
63
|
+
Run `pip install splitio_client`
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from splitio import get_factory
|
|
68
|
+
from splitio.exceptions import TimeoutException
|
|
69
|
+
factory = get_factory('YOUR_SDK_TYPE_API_KEY', config=config)
|
|
70
|
+
try:
|
|
71
|
+
factory.block_until_ready(5) # wait up to 5 seconds
|
|
72
|
+
split = factory.client()
|
|
73
|
+
treatment = split.get_treatment('CUSTOMER_ID', 'FEATURE_FLAG_NAME')
|
|
74
|
+
if treatment == "on":
|
|
75
|
+
# insert code here to show on treatment
|
|
76
|
+
elif treatment == "off":
|
|
77
|
+
# insert code here to show off treatment
|
|
78
|
+
else:
|
|
79
|
+
# insert your control treatment code here
|
|
80
|
+
except TimeoutException:
|
|
81
|
+
# Now the user can choose whether to abort the whole execution, or just keep going
|
|
82
|
+
# without a ready client, which if configured properly, should become ready at some point.
|
|
83
|
+
pass
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Please refer to [our official docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK) to learn about all the functionality provided by our SDK and the configuration options available for tailoring it to your current application setup.
|
|
87
|
+
|
|
88
|
+
## Submitting issues
|
|
89
|
+
The Split team monitors all issues submitted to this [issue tracker](https://github.com/splitio/python-client/issues). We encourage you to use this issue tracker to submit any bug reports, feedback, and feature enhancements. We'll do our best to respond in a timely manner.
|
|
90
|
+
|
|
91
|
+
## Contributing
|
|
92
|
+
Please see [Contributors Guide](CONTRIBUTORS-GUIDE.md) to find all you need to submit a Pull Request (PR).
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
Licensed under the Apache License, Version 2.0. See: [Apache License](http://www.apache.org/licenses/).
|
|
96
|
+
|
|
97
|
+
## About Split
|
|
98
|
+
|
|
99
|
+
Split is the leading Feature Delivery Platform for engineering teams that want to confidently deploy features as fast as they can develop them. Split’s fine-grained management, real-time monitoring, and data-driven experimentation ensure that new features will improve the customer experience without breaking or degrading performance. Companies like Twilio, Salesforce, GoDaddy and WePay trust Split to power their feature delivery.
|
|
100
|
+
|
|
101
|
+
To learn more about Split, contact hello@split.io, or get started with feature flags for free at https://www.split.io/signup.
|
|
102
|
+
|
|
103
|
+
Split has built and maintains SDKs for:
|
|
104
|
+
|
|
105
|
+
* .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK)
|
|
106
|
+
* Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK)
|
|
107
|
+
* Angular [Github](https://github.com/splitio/angular-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/6495326064397-Angular-utilities)
|
|
108
|
+
* GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK)
|
|
109
|
+
* iOS [Github](https://github.com/splitio/ios-client) [Docs](https://help.split.io/hc/en-us/articles/360020401491-iOS-SDK)
|
|
110
|
+
* Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK)
|
|
111
|
+
* JavaScript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK)
|
|
112
|
+
* JavaScript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK)
|
|
113
|
+
* Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK)
|
|
114
|
+
* PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK)
|
|
115
|
+
* Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK)
|
|
116
|
+
* React [Github](https://github.com/splitio/react-client) [Docs](https://help.split.io/hc/en-us/articles/360038825091-React-SDK)
|
|
117
|
+
* React Native [Github](https://github.com/splitio/react-native-client) [Docs](https://help.split.io/hc/en-us/articles/4406066357901-React-Native-SDK)
|
|
118
|
+
* Redux [Github](https://github.com/splitio/redux-client) [Docs](https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK)
|
|
119
|
+
* Ruby [Github](https://github.com/splitio/ruby-client) [Docs](https://help.split.io/hc/en-us/articles/360020673251-Ruby-SDK)
|
|
120
|
+
|
|
121
|
+
For a comprehensive list of open source projects visit our [Github page](https://github.com/splitio?utf8=%E2%9C%93&query=%20only%3Apublic%20).
|
|
122
|
+
|
|
123
|
+
**Learn more about Split:**
|
|
124
|
+
|
|
125
|
+
Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](http://help.split.io) for more detailed information.
|
|
@@ -3,7 +3,7 @@ import logging
|
|
|
3
3
|
|
|
4
4
|
from splitio.engine.evaluator import Evaluator, CONTROL, EvaluationDataFactory, AsyncEvaluationDataFactory
|
|
5
5
|
from splitio.engine.splitters import Splitter
|
|
6
|
-
from splitio.models.impressions import Impression, Label
|
|
6
|
+
from splitio.models.impressions import Impression, Label, ImpressionDecorated
|
|
7
7
|
from splitio.models.events import Event, EventWrapper
|
|
8
8
|
from splitio.models.telemetry import get_latency_bucket_index, MethodExceptionsAndLatencies
|
|
9
9
|
from splitio.client import input_validator
|
|
@@ -22,7 +22,8 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes
|
|
|
22
22
|
'impression': {
|
|
23
23
|
'label': Label.EXCEPTION,
|
|
24
24
|
'change_number': None,
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
|
+
'impressions_disabled': False
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
_NON_READY_EVAL_RESULT = {
|
|
@@ -31,7 +32,8 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes
|
|
|
31
32
|
'impression': {
|
|
32
33
|
'label': Label.NOT_READY,
|
|
33
34
|
'change_number': None
|
|
34
|
-
}
|
|
35
|
+
},
|
|
36
|
+
'impressions_disabled': False
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
def __init__(self, factory, recorder, labels_enabled=True):
|
|
@@ -116,14 +118,15 @@ class ClientBase(object): # pylint: disable=too-many-instance-attributes
|
|
|
116
118
|
|
|
117
119
|
def _build_impression(self, key, bucketing, feature, result):
|
|
118
120
|
"""Build an impression based on evaluation data & it's result."""
|
|
119
|
-
return
|
|
120
|
-
matching_key=key,
|
|
121
|
+
return ImpressionDecorated(
|
|
122
|
+
Impression(matching_key=key,
|
|
121
123
|
feature_name=feature,
|
|
122
124
|
treatment=result['treatment'],
|
|
123
125
|
label=result['impression']['label'] if self._labels_enabled else None,
|
|
124
126
|
change_number=result['impression']['change_number'],
|
|
125
127
|
bucketing_key=bucketing,
|
|
126
|
-
time=utctime_ms())
|
|
128
|
+
time=utctime_ms()),
|
|
129
|
+
disabled=result['impressions_disabled'])
|
|
127
130
|
|
|
128
131
|
def _build_impressions(self, key, bucketing, results):
|
|
129
132
|
"""Build an impression based on evaluation data & it's result."""
|
|
@@ -296,8 +299,8 @@ class Client(ClientBase): # pylint: disable=too-many-instance-attributes
|
|
|
296
299
|
result = self._FAILED_EVAL_RESULT
|
|
297
300
|
|
|
298
301
|
if result['impression']['label'] != Label.SPLIT_NOT_FOUND:
|
|
299
|
-
|
|
300
|
-
self._record_stats([(
|
|
302
|
+
impression_decorated = self._build_impression(key, bucketing, feature, result)
|
|
303
|
+
self._record_stats([(impression_decorated, attributes)], start, method)
|
|
301
304
|
|
|
302
305
|
return result['treatment'], result['configurations']
|
|
303
306
|
|
|
@@ -571,23 +574,23 @@ class Client(ClientBase): # pylint: disable=too-many-instance-attributes
|
|
|
571
574
|
self._telemetry_evaluation_producer.record_exception(method)
|
|
572
575
|
results = {n: self._FAILED_EVAL_RESULT for n in features}
|
|
573
576
|
|
|
574
|
-
|
|
577
|
+
imp_decorated_attrs = [
|
|
575
578
|
(i, attributes) for i in self._build_impressions(key, bucketing, results)
|
|
576
|
-
if i.label != Label.SPLIT_NOT_FOUND
|
|
579
|
+
if i.Impression.label != Label.SPLIT_NOT_FOUND
|
|
577
580
|
]
|
|
578
|
-
self._record_stats(
|
|
581
|
+
self._record_stats(imp_decorated_attrs, start, method)
|
|
579
582
|
|
|
580
583
|
return {
|
|
581
584
|
feature: (results[feature]['treatment'], results[feature]['configurations'])
|
|
582
585
|
for feature in results
|
|
583
586
|
}
|
|
584
587
|
|
|
585
|
-
def _record_stats(self,
|
|
588
|
+
def _record_stats(self, impressions_decorated, start, operation):
|
|
586
589
|
"""
|
|
587
590
|
Record impressions.
|
|
588
591
|
|
|
589
|
-
:param
|
|
590
|
-
:type
|
|
592
|
+
:param impressions_decorated: Generated impressions
|
|
593
|
+
:type impressions_decorated: list[tuple[splitio.models.impression.ImpressionDecorated, dict]]
|
|
591
594
|
|
|
592
595
|
:param start: timestamp when get_treatment or get_treatments was called
|
|
593
596
|
:type start: int
|
|
@@ -596,7 +599,7 @@ class Client(ClientBase): # pylint: disable=too-many-instance-attributes
|
|
|
596
599
|
:type operation: str
|
|
597
600
|
"""
|
|
598
601
|
end = get_current_epoch_time_ms()
|
|
599
|
-
self._recorder.record_treatment_stats(
|
|
602
|
+
self._recorder.record_treatment_stats(impressions_decorated, get_latency_bucket_index(end - start),
|
|
600
603
|
operation, 'get_' + operation.value)
|
|
601
604
|
|
|
602
605
|
def track(self, key, traffic_type, event_type, value=None, properties=None):
|
|
@@ -763,8 +766,8 @@ class ClientAsync(ClientBase): # pylint: disable=too-many-instance-attributes
|
|
|
763
766
|
result = self._FAILED_EVAL_RESULT
|
|
764
767
|
|
|
765
768
|
if result['impression']['label'] != Label.SPLIT_NOT_FOUND:
|
|
766
|
-
|
|
767
|
-
await self._record_stats([(
|
|
769
|
+
impression_decorated = self._build_impression(key, bucketing, feature, result)
|
|
770
|
+
await self._record_stats([(impression_decorated, attributes)], start, method)
|
|
768
771
|
return result['treatment'], result['configurations']
|
|
769
772
|
|
|
770
773
|
async def get_treatments(self, key, feature_flag_names, attributes=None):
|
|
@@ -960,23 +963,23 @@ class ClientAsync(ClientBase): # pylint: disable=too-many-instance-attributes
|
|
|
960
963
|
await self._telemetry_evaluation_producer.record_exception(method)
|
|
961
964
|
results = {n: self._FAILED_EVAL_RESULT for n in features}
|
|
962
965
|
|
|
963
|
-
|
|
966
|
+
imp_decorated_attrs = [
|
|
964
967
|
(i, attributes) for i in self._build_impressions(key, bucketing, results)
|
|
965
|
-
if i.label != Label.SPLIT_NOT_FOUND
|
|
968
|
+
if i.Impression.label != Label.SPLIT_NOT_FOUND
|
|
966
969
|
]
|
|
967
|
-
await self._record_stats(
|
|
970
|
+
await self._record_stats(imp_decorated_attrs, start, method)
|
|
968
971
|
|
|
969
972
|
return {
|
|
970
973
|
feature: (res['treatment'], res['configurations'])
|
|
971
974
|
for feature, res in results.items()
|
|
972
975
|
}
|
|
973
976
|
|
|
974
|
-
async def _record_stats(self,
|
|
977
|
+
async def _record_stats(self, impressions_decorated, start, operation):
|
|
975
978
|
"""
|
|
976
979
|
Record impressions for async calls
|
|
977
980
|
|
|
978
|
-
:param
|
|
979
|
-
:type
|
|
981
|
+
:param impressions_decorated: Generated impressions decorated
|
|
982
|
+
:type impressions_decorated: list[tuple[splitio.models.impression.Impression, dict]]
|
|
980
983
|
|
|
981
984
|
:param start: timestamp when get_treatment or get_treatments was called
|
|
982
985
|
:type start: int
|
|
@@ -985,7 +988,7 @@ class ClientAsync(ClientBase): # pylint: disable=too-many-instance-attributes
|
|
|
985
988
|
:type operation: str
|
|
986
989
|
"""
|
|
987
990
|
end = get_current_epoch_time_ms()
|
|
988
|
-
await self._recorder.record_treatment_stats(
|
|
991
|
+
await self._recorder.record_treatment_stats(impressions_decorated, get_latency_bucket_index(end - start),
|
|
989
992
|
operation, 'get_' + operation.value)
|
|
990
993
|
|
|
991
994
|
async def track(self, key, traffic_type, event_type, value=None, properties=None):
|
|
@@ -13,7 +13,7 @@ from splitio.client import util
|
|
|
13
13
|
from splitio.client.listener import ImpressionListenerWrapper, ImpressionListenerWrapperAsync
|
|
14
14
|
from splitio.engine.impressions.impressions import Manager as ImpressionsManager
|
|
15
15
|
from splitio.engine.impressions import set_classes, set_classes_async
|
|
16
|
-
from splitio.engine.impressions.strategies import StrategyDebugMode
|
|
16
|
+
from splitio.engine.impressions.strategies import StrategyDebugMode, StrategyNoneMode
|
|
17
17
|
from splitio.engine.telemetry import TelemetryStorageProducer, TelemetryStorageConsumer, \
|
|
18
18
|
TelemetryStorageProducerAsync, TelemetryStorageConsumerAsync
|
|
19
19
|
from splitio.engine.impressions.manager import Counter as ImpressionsCounter
|
|
@@ -553,10 +553,10 @@ def _build_in_memory_factory(api_key, cfg, sdk_url=None, events_url=None, # pyl
|
|
|
553
553
|
unique_keys_tracker = UniqueKeysTracker(_UNIQUE_KEYS_CACHE_SIZE)
|
|
554
554
|
unique_keys_synchronizer, clear_filter_sync, unique_keys_task, \
|
|
555
555
|
clear_filter_task, impressions_count_sync, impressions_count_task, \
|
|
556
|
-
imp_strategy = set_classes('MEMORY', cfg['impressionsMode'], apis, imp_counter, unique_keys_tracker)
|
|
556
|
+
imp_strategy, none_strategy = set_classes('MEMORY', cfg['impressionsMode'], apis, imp_counter, unique_keys_tracker)
|
|
557
557
|
|
|
558
558
|
imp_manager = ImpressionsManager(
|
|
559
|
-
imp_strategy, telemetry_runtime_producer)
|
|
559
|
+
imp_strategy, none_strategy, telemetry_runtime_producer)
|
|
560
560
|
|
|
561
561
|
synchronizers = SplitSynchronizers(
|
|
562
562
|
SplitSynchronizer(apis['splits'], storages['splits']),
|
|
@@ -681,10 +681,10 @@ async def _build_in_memory_factory_async(api_key, cfg, sdk_url=None, events_url=
|
|
|
681
681
|
unique_keys_tracker = UniqueKeysTrackerAsync(_UNIQUE_KEYS_CACHE_SIZE)
|
|
682
682
|
unique_keys_synchronizer, clear_filter_sync, unique_keys_task, \
|
|
683
683
|
clear_filter_task, impressions_count_sync, impressions_count_task, \
|
|
684
|
-
imp_strategy = set_classes_async('MEMORY', cfg['impressionsMode'], apis, imp_counter, unique_keys_tracker)
|
|
684
|
+
imp_strategy, none_strategy = set_classes_async('MEMORY', cfg['impressionsMode'], apis, imp_counter, unique_keys_tracker)
|
|
685
685
|
|
|
686
686
|
imp_manager = ImpressionsManager(
|
|
687
|
-
imp_strategy, telemetry_runtime_producer)
|
|
687
|
+
imp_strategy, none_strategy, telemetry_runtime_producer)
|
|
688
688
|
|
|
689
689
|
synchronizers = SplitSynchronizers(
|
|
690
690
|
SplitSynchronizerAsync(apis['splits'], storages['splits']),
|
|
@@ -775,10 +775,10 @@ def _build_redis_factory(api_key, cfg):
|
|
|
775
775
|
unique_keys_tracker = UniqueKeysTracker(_UNIQUE_KEYS_CACHE_SIZE)
|
|
776
776
|
unique_keys_synchronizer, clear_filter_sync, unique_keys_task, \
|
|
777
777
|
clear_filter_task, impressions_count_sync, impressions_count_task, \
|
|
778
|
-
imp_strategy = set_classes('REDIS', cfg['impressionsMode'], redis_adapter, imp_counter, unique_keys_tracker)
|
|
778
|
+
imp_strategy, none_strategy = set_classes('REDIS', cfg['impressionsMode'], redis_adapter, imp_counter, unique_keys_tracker)
|
|
779
779
|
|
|
780
780
|
imp_manager = ImpressionsManager(
|
|
781
|
-
imp_strategy,
|
|
781
|
+
imp_strategy, none_strategy,
|
|
782
782
|
telemetry_runtime_producer)
|
|
783
783
|
|
|
784
784
|
synchronizers = SplitSynchronizers(None, None, None, None,
|
|
@@ -858,10 +858,10 @@ async def _build_redis_factory_async(api_key, cfg):
|
|
|
858
858
|
unique_keys_tracker = UniqueKeysTrackerAsync(_UNIQUE_KEYS_CACHE_SIZE)
|
|
859
859
|
unique_keys_synchronizer, clear_filter_sync, unique_keys_task, \
|
|
860
860
|
clear_filter_task, impressions_count_sync, impressions_count_task, \
|
|
861
|
-
imp_strategy = set_classes_async('REDIS', cfg['impressionsMode'], redis_adapter, imp_counter, unique_keys_tracker)
|
|
861
|
+
imp_strategy, none_strategy = set_classes_async('REDIS', cfg['impressionsMode'], redis_adapter, imp_counter, unique_keys_tracker)
|
|
862
862
|
|
|
863
863
|
imp_manager = ImpressionsManager(
|
|
864
|
-
imp_strategy,
|
|
864
|
+
imp_strategy, none_strategy,
|
|
865
865
|
telemetry_runtime_producer)
|
|
866
866
|
|
|
867
867
|
synchronizers = SplitSynchronizers(None, None, None, None,
|
|
@@ -936,10 +936,10 @@ def _build_pluggable_factory(api_key, cfg):
|
|
|
936
936
|
unique_keys_tracker = UniqueKeysTracker(_UNIQUE_KEYS_CACHE_SIZE)
|
|
937
937
|
unique_keys_synchronizer, clear_filter_sync, unique_keys_task, \
|
|
938
938
|
clear_filter_task, impressions_count_sync, impressions_count_task, \
|
|
939
|
-
imp_strategy = set_classes('PLUGGABLE', cfg['impressionsMode'], pluggable_adapter, imp_counter, unique_keys_tracker, storage_prefix)
|
|
939
|
+
imp_strategy, none_strategy = set_classes('PLUGGABLE', cfg['impressionsMode'], pluggable_adapter, imp_counter, unique_keys_tracker, storage_prefix)
|
|
940
940
|
|
|
941
941
|
imp_manager = ImpressionsManager(
|
|
942
|
-
imp_strategy,
|
|
942
|
+
imp_strategy, none_strategy,
|
|
943
943
|
telemetry_runtime_producer)
|
|
944
944
|
|
|
945
945
|
synchronizers = SplitSynchronizers(None, None, None, None,
|
|
@@ -1017,10 +1017,10 @@ async def _build_pluggable_factory_async(api_key, cfg):
|
|
|
1017
1017
|
unique_keys_tracker = UniqueKeysTrackerAsync(_UNIQUE_KEYS_CACHE_SIZE)
|
|
1018
1018
|
unique_keys_synchronizer, clear_filter_sync, unique_keys_task, \
|
|
1019
1019
|
clear_filter_task, impressions_count_sync, impressions_count_task, \
|
|
1020
|
-
imp_strategy = set_classes_async('PLUGGABLE', cfg['impressionsMode'], pluggable_adapter, imp_counter, unique_keys_tracker, storage_prefix)
|
|
1020
|
+
imp_strategy, none_strategy = set_classes_async('PLUGGABLE', cfg['impressionsMode'], pluggable_adapter, imp_counter, unique_keys_tracker, storage_prefix)
|
|
1021
1021
|
|
|
1022
1022
|
imp_manager = ImpressionsManager(
|
|
1023
|
-
imp_strategy,
|
|
1023
|
+
imp_strategy, none_strategy,
|
|
1024
1024
|
telemetry_runtime_producer)
|
|
1025
1025
|
|
|
1026
1026
|
synchronizers = SplitSynchronizers(None, None, None, None,
|
|
@@ -1123,7 +1123,7 @@ def _build_localhost_factory(cfg):
|
|
|
1123
1123
|
manager.start()
|
|
1124
1124
|
|
|
1125
1125
|
recorder = StandardRecorder(
|
|
1126
|
-
ImpressionsManager(StrategyDebugMode(), telemetry_runtime_producer),
|
|
1126
|
+
ImpressionsManager(StrategyDebugMode(), StrategyNoneMode(), telemetry_runtime_producer),
|
|
1127
1127
|
storages['events'],
|
|
1128
1128
|
storages['impressions'],
|
|
1129
1129
|
telemetry_evaluation_producer,
|
|
@@ -1192,7 +1192,7 @@ async def _build_localhost_factory_async(cfg):
|
|
|
1192
1192
|
await manager.start()
|
|
1193
1193
|
|
|
1194
1194
|
recorder = StandardRecorderAsync(
|
|
1195
|
-
ImpressionsManager(StrategyDebugMode(), telemetry_runtime_producer),
|
|
1195
|
+
ImpressionsManager(StrategyDebugMode(), StrategyNoneMode(), telemetry_runtime_producer),
|
|
1196
1196
|
storages['events'],
|
|
1197
1197
|
storages['impressions'],
|
|
1198
1198
|
telemetry_evaluation_producer,
|
|
@@ -67,7 +67,8 @@ class Evaluator(object): # pylint: disable=too-few-public-methods
|
|
|
67
67
|
'impression': {
|
|
68
68
|
'label': label,
|
|
69
69
|
'change_number': _change_number
|
|
70
|
-
}
|
|
70
|
+
},
|
|
71
|
+
'impressions_disabled': feature.impressions_disabled if feature else None
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
def _treatment_for_flag(self, flag, key, bucketing, attributes, ctx):
|
|
@@ -53,24 +53,24 @@ def set_classes(storage_mode, impressions_mode, api_adapter, imp_counter, unique
|
|
|
53
53
|
api_impressions_adapter = api_adapter['impressions']
|
|
54
54
|
sender_adapter = InMemorySenderAdapter(api_telemetry_adapter)
|
|
55
55
|
|
|
56
|
+
none_strategy = StrategyNoneMode()
|
|
57
|
+
unique_keys_synchronizer = UniqueKeysSynchronizer(sender_adapter, unique_keys_tracker)
|
|
58
|
+
unique_keys_task = UniqueKeysSyncTask(unique_keys_synchronizer.send_all)
|
|
59
|
+
clear_filter_sync = ClearFilterSynchronizer(unique_keys_tracker)
|
|
60
|
+
impressions_count_sync = ImpressionsCountSynchronizer(api_impressions_adapter, imp_counter)
|
|
61
|
+
impressions_count_task = ImpressionsCountSyncTask(impressions_count_sync.synchronize_counters)
|
|
62
|
+
clear_filter_task = ClearFilterSyncTask(clear_filter_sync.clear_all)
|
|
63
|
+
unique_keys_tracker.set_queue_full_hook(unique_keys_task.flush)
|
|
64
|
+
|
|
56
65
|
if impressions_mode == ImpressionsMode.NONE:
|
|
57
66
|
imp_strategy = StrategyNoneMode()
|
|
58
|
-
unique_keys_synchronizer = UniqueKeysSynchronizer(sender_adapter, unique_keys_tracker)
|
|
59
|
-
unique_keys_task = UniqueKeysSyncTask(unique_keys_synchronizer.send_all)
|
|
60
|
-
clear_filter_sync = ClearFilterSynchronizer(unique_keys_tracker)
|
|
61
|
-
impressions_count_sync = ImpressionsCountSynchronizer(api_impressions_adapter, imp_counter)
|
|
62
|
-
impressions_count_task = ImpressionsCountSyncTask(impressions_count_sync.synchronize_counters)
|
|
63
|
-
clear_filter_task = ClearFilterSyncTask(clear_filter_sync.clear_all)
|
|
64
|
-
unique_keys_tracker.set_queue_full_hook(unique_keys_task.flush)
|
|
65
67
|
elif impressions_mode == ImpressionsMode.DEBUG:
|
|
66
68
|
imp_strategy = StrategyDebugMode()
|
|
67
69
|
else:
|
|
68
70
|
imp_strategy = StrategyOptimizedMode()
|
|
69
|
-
impressions_count_sync = ImpressionsCountSynchronizer(api_impressions_adapter, imp_counter)
|
|
70
|
-
impressions_count_task = ImpressionsCountSyncTask(impressions_count_sync.synchronize_counters)
|
|
71
71
|
|
|
72
72
|
return unique_keys_synchronizer, clear_filter_sync, unique_keys_task, clear_filter_task, \
|
|
73
|
-
impressions_count_sync, impressions_count_task, imp_strategy
|
|
73
|
+
impressions_count_sync, impressions_count_task, imp_strategy, none_strategy
|
|
74
74
|
|
|
75
75
|
def set_classes_async(storage_mode, impressions_mode, api_adapter, imp_counter, unique_keys_tracker, prefix=None):
|
|
76
76
|
"""
|
|
@@ -118,21 +118,21 @@ def set_classes_async(storage_mode, impressions_mode, api_adapter, imp_counter,
|
|
|
118
118
|
api_impressions_adapter = api_adapter['impressions']
|
|
119
119
|
sender_adapter = InMemorySenderAdapterAsync(api_telemetry_adapter)
|
|
120
120
|
|
|
121
|
+
none_strategy = StrategyNoneMode()
|
|
122
|
+
unique_keys_synchronizer = UniqueKeysSynchronizerAsync(sender_adapter, unique_keys_tracker)
|
|
123
|
+
unique_keys_task = UniqueKeysSyncTaskAsync(unique_keys_synchronizer.send_all)
|
|
124
|
+
clear_filter_sync = ClearFilterSynchronizerAsync(unique_keys_tracker)
|
|
125
|
+
impressions_count_sync = ImpressionsCountSynchronizerAsync(api_impressions_adapter, imp_counter)
|
|
126
|
+
impressions_count_task = ImpressionsCountSyncTaskAsync(impressions_count_sync.synchronize_counters)
|
|
127
|
+
clear_filter_task = ClearFilterSyncTaskAsync(clear_filter_sync.clear_all)
|
|
128
|
+
unique_keys_tracker.set_queue_full_hook(unique_keys_task.flush)
|
|
129
|
+
|
|
121
130
|
if impressions_mode == ImpressionsMode.NONE:
|
|
122
131
|
imp_strategy = StrategyNoneMode()
|
|
123
|
-
unique_keys_synchronizer = UniqueKeysSynchronizerAsync(sender_adapter, unique_keys_tracker)
|
|
124
|
-
unique_keys_task = UniqueKeysSyncTaskAsync(unique_keys_synchronizer.send_all)
|
|
125
|
-
clear_filter_sync = ClearFilterSynchronizerAsync(unique_keys_tracker)
|
|
126
|
-
impressions_count_sync = ImpressionsCountSynchronizerAsync(api_impressions_adapter, imp_counter)
|
|
127
|
-
impressions_count_task = ImpressionsCountSyncTaskAsync(impressions_count_sync.synchronize_counters)
|
|
128
|
-
clear_filter_task = ClearFilterSyncTaskAsync(clear_filter_sync.clear_all)
|
|
129
|
-
unique_keys_tracker.set_queue_full_hook(unique_keys_task.flush)
|
|
130
132
|
elif impressions_mode == ImpressionsMode.DEBUG:
|
|
131
133
|
imp_strategy = StrategyDebugMode()
|
|
132
134
|
else:
|
|
133
135
|
imp_strategy = StrategyOptimizedMode()
|
|
134
|
-
impressions_count_sync = ImpressionsCountSynchronizerAsync(api_impressions_adapter, imp_counter)
|
|
135
|
-
impressions_count_task = ImpressionsCountSyncTaskAsync(impressions_count_sync.synchronize_counters)
|
|
136
136
|
|
|
137
137
|
return unique_keys_synchronizer, clear_filter_sync, unique_keys_task, clear_filter_task, \
|
|
138
|
-
impressions_count_sync, impressions_count_task, imp_strategy
|
|
138
|
+
impressions_count_sync, impressions_count_task, imp_strategy, none_strategy
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Split evaluator module."""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
class ImpressionsMode(Enum):
|
|
5
|
+
"""Impressions tracking mode."""
|
|
6
|
+
|
|
7
|
+
OPTIMIZED = "OPTIMIZED"
|
|
8
|
+
DEBUG = "DEBUG"
|
|
9
|
+
NONE = "NONE"
|
|
10
|
+
|
|
11
|
+
class Manager(object): # pylint:disable=too-few-public-methods
|
|
12
|
+
"""Impression manager."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, strategy, none_strategy, telemetry_runtime_producer):
|
|
15
|
+
"""
|
|
16
|
+
Construct a manger to track and forward impressions to the queue.
|
|
17
|
+
|
|
18
|
+
:param listener: Optional impressions listener that will capture all seen impressions.
|
|
19
|
+
:type listener: splitio.client.listener.ImpressionListenerWrapper
|
|
20
|
+
|
|
21
|
+
:param strategy: Impressions stragetgy instance
|
|
22
|
+
:type strategy: (BaseStrategy)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
self._strategy = strategy
|
|
26
|
+
self._none_strategy = none_strategy
|
|
27
|
+
self._telemetry_runtime_producer = telemetry_runtime_producer
|
|
28
|
+
|
|
29
|
+
def process_impressions(self, impressions_decorated):
|
|
30
|
+
"""
|
|
31
|
+
Process impressions.
|
|
32
|
+
|
|
33
|
+
Impressions are analyzed to see if they've been seen before and counted.
|
|
34
|
+
|
|
35
|
+
:param impressions_decorated: List of impression objects with attributes
|
|
36
|
+
:type impressions_decorated: list[tuple[splitio.models.impression.ImpressionDecorated, dict]]
|
|
37
|
+
|
|
38
|
+
:return: processed and deduped impressions.
|
|
39
|
+
:rtype: tuple(list[tuple[splitio.models.impression.Impression, dict]], list(int))
|
|
40
|
+
"""
|
|
41
|
+
for_listener_all = []
|
|
42
|
+
for_log_all = []
|
|
43
|
+
for_counter_all = []
|
|
44
|
+
for_unique_keys_tracker_all = []
|
|
45
|
+
for impression_decorated, att in impressions_decorated:
|
|
46
|
+
if impression_decorated.disabled:
|
|
47
|
+
for_log, for_listener, for_counter, for_unique_keys_tracker = self._none_strategy.process_impressions([(impression_decorated.Impression, att)])
|
|
48
|
+
else:
|
|
49
|
+
for_log, for_listener, for_counter, for_unique_keys_tracker = self._strategy.process_impressions([(impression_decorated.Impression, att)])
|
|
50
|
+
for_listener_all.extend(for_listener)
|
|
51
|
+
for_log_all.extend(for_log)
|
|
52
|
+
for_counter_all.extend(for_counter)
|
|
53
|
+
for_unique_keys_tracker_all.extend(for_unique_keys_tracker)
|
|
54
|
+
|
|
55
|
+
return for_log_all, len(impressions_decorated) - len(for_log_all), for_listener_all, for_counter_all, for_unique_keys_tracker_all
|
|
@@ -16,6 +16,14 @@ Impression = namedtuple(
|
|
|
16
16
|
]
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
+
ImpressionDecorated = namedtuple(
|
|
20
|
+
'ImpressionDecorated',
|
|
21
|
+
[
|
|
22
|
+
'Impression',
|
|
23
|
+
'disabled'
|
|
24
|
+
]
|
|
25
|
+
)
|
|
26
|
+
|
|
19
27
|
# pre-python3.7 hack to make previous_time optional
|
|
20
28
|
Impression.__new__.__defaults__ = (None,)
|
|
21
29
|
|
|
@@ -10,7 +10,7 @@ _LOGGER = logging.getLogger(__name__)
|
|
|
10
10
|
|
|
11
11
|
SplitView = namedtuple(
|
|
12
12
|
'SplitView',
|
|
13
|
-
['name', 'traffic_type', 'killed', 'treatments', 'change_number', 'configs', 'default_treatment', 'sets']
|
|
13
|
+
['name', 'traffic_type', 'killed', 'treatments', 'change_number', 'configs', 'default_treatment', 'sets', 'impressions_disabled']
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
_DEFAULT_CONDITIONS_TEMPLATE = {
|
|
@@ -73,7 +73,8 @@ class Split(object): # pylint: disable=too-many-instance-attributes
|
|
|
73
73
|
traffic_allocation=None,
|
|
74
74
|
traffic_allocation_seed=None,
|
|
75
75
|
configurations=None,
|
|
76
|
-
sets=None
|
|
76
|
+
sets=None,
|
|
77
|
+
impressions_disabled=None
|
|
77
78
|
):
|
|
78
79
|
"""
|
|
79
80
|
Class constructor.
|
|
@@ -96,6 +97,8 @@ class Split(object): # pylint: disable=too-many-instance-attributes
|
|
|
96
97
|
:type traffic_allocation_seed: int
|
|
97
98
|
:pram sets: list of flag sets
|
|
98
99
|
:type sets: list
|
|
100
|
+
:pram impressions_disabled: track impressions flag
|
|
101
|
+
:type impressions_disabled: boolean
|
|
99
102
|
"""
|
|
100
103
|
self._name = name
|
|
101
104
|
self._seed = seed
|
|
@@ -125,6 +128,7 @@ class Split(object): # pylint: disable=too-many-instance-attributes
|
|
|
125
128
|
|
|
126
129
|
self._configurations = configurations
|
|
127
130
|
self._sets = set(sets) if sets is not None else set()
|
|
131
|
+
self._impressions_disabled = impressions_disabled if impressions_disabled is not None else False
|
|
128
132
|
|
|
129
133
|
@property
|
|
130
134
|
def name(self):
|
|
@@ -186,6 +190,11 @@ class Split(object): # pylint: disable=too-many-instance-attributes
|
|
|
186
190
|
"""Return the flag sets of the split."""
|
|
187
191
|
return self._sets
|
|
188
192
|
|
|
193
|
+
@property
|
|
194
|
+
def impressions_disabled(self):
|
|
195
|
+
"""Return impressions_disabled of the split."""
|
|
196
|
+
return self._impressions_disabled
|
|
197
|
+
|
|
189
198
|
def get_configurations_for(self, treatment):
|
|
190
199
|
"""Return the mapping of treatments to configurations."""
|
|
191
200
|
return self._configurations.get(treatment) if self._configurations else None
|
|
@@ -214,7 +223,8 @@ class Split(object): # pylint: disable=too-many-instance-attributes
|
|
|
214
223
|
'algo': self.algo.value,
|
|
215
224
|
'conditions': [c.to_json() for c in self.conditions],
|
|
216
225
|
'configurations': self._configurations,
|
|
217
|
-
'sets': list(self._sets)
|
|
226
|
+
'sets': list(self._sets),
|
|
227
|
+
'impressionsDisabled': self._impressions_disabled
|
|
218
228
|
}
|
|
219
229
|
|
|
220
230
|
def to_split_view(self):
|
|
@@ -232,7 +242,8 @@ class Split(object): # pylint: disable=too-many-instance-attributes
|
|
|
232
242
|
self.change_number,
|
|
233
243
|
self._configurations if self._configurations is not None else {},
|
|
234
244
|
self._default_treatment,
|
|
235
|
-
list(self._sets) if self._sets is not None else []
|
|
245
|
+
list(self._sets) if self._sets is not None else [],
|
|
246
|
+
self._impressions_disabled
|
|
236
247
|
)
|
|
237
248
|
|
|
238
249
|
def local_kill(self, default_treatment, change_number):
|
|
@@ -288,5 +299,6 @@ def from_raw(raw_split):
|
|
|
288
299
|
traffic_allocation=raw_split.get('trafficAllocation'),
|
|
289
300
|
traffic_allocation_seed=raw_split.get('trafficAllocationSeed'),
|
|
290
301
|
configurations=raw_split.get('configurations'),
|
|
291
|
-
sets=set(raw_split.get('sets')) if raw_split.get('sets') is not None else []
|
|
302
|
+
sets=set(raw_split.get('sets')) if raw_split.get('sets') is not None else [],
|
|
303
|
+
impressions_disabled=raw_split.get('impressionsDisabled') if raw_split.get('impressionsDisabled') is not None else False
|
|
292
304
|
)
|