splitio-client 9.6.2__tar.gz → 10.0.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.
Files changed (149) hide show
  1. splitio_client-10.0.0/PKG-INFO +100 -0
  2. {splitio_client-9.6.2 → splitio_client-10.0.0}/README.md +1 -1
  3. {splitio_client-9.6.2 → splitio_client-10.0.0}/setup.cfg +4 -2
  4. {splitio_client-9.6.2 → splitio_client-10.0.0}/setup.py +12 -8
  5. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/__init__.py +1 -1
  6. splitio_client-10.0.0/splitio/api/__init__.py +46 -0
  7. splitio_client-10.0.0/splitio/api/auth.py +109 -0
  8. splitio_client-10.0.0/splitio/api/client.py +336 -0
  9. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/api/commons.py +17 -5
  10. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/api/events.py +71 -25
  11. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/api/impressions.py +98 -26
  12. splitio_client-10.0.0/splitio/api/segments.py +130 -0
  13. splitio_client-10.0.0/splitio/api/splits.py +121 -0
  14. splitio_client-10.0.0/splitio/api/telemetry.py +187 -0
  15. splitio_client-10.0.0/splitio/client/client.py +1039 -0
  16. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/config.py +0 -1
  17. splitio_client-10.0.0/splitio/client/factory.py +1311 -0
  18. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/input_validator.py +163 -64
  19. splitio_client-10.0.0/splitio/client/listener.py +122 -0
  20. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/localhost.py +31 -0
  21. splitio_client-10.0.0/splitio/client/manager.py +198 -0
  22. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/util.py +1 -0
  23. splitio_client-10.0.0/splitio/engine/evaluator.py +185 -0
  24. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/hashfns/legacy.py +1 -0
  25. splitio_client-10.0.0/splitio/engine/impressions/__init__.py +138 -0
  26. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/impressions/adapters.py +184 -13
  27. splitio_client-10.0.0/splitio/engine/impressions/impressions.py +41 -0
  28. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/impressions/manager.py +4 -2
  29. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/impressions/strategies.py +15 -28
  30. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/impressions/unique_keys_tracker.py +87 -22
  31. splitio_client-10.0.0/splitio/engine/telemetry.py +687 -0
  32. splitio_client-10.0.0/splitio/models/__init__.py +6 -0
  33. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/condition.py +2 -0
  34. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/__init__.py +15 -3
  35. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/base.py +1 -0
  36. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/keys.py +2 -5
  37. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/misc.py +4 -2
  38. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/numeric.py +4 -0
  39. splitio_client-10.0.0/splitio/models/grammar/matchers/semver.py +260 -0
  40. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/sets.py +8 -0
  41. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/matchers/string.py +7 -0
  42. splitio_client-10.0.0/splitio/models/grammar/matchers/utils/utils.py +168 -0
  43. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/notification.py +1 -0
  44. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/splits.py +38 -1
  45. splitio_client-10.0.0/splitio/models/telemetry.py +1954 -0
  46. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/token.py +1 -0
  47. splitio_client-10.0.0/splitio/optional/loaders.py +21 -0
  48. splitio_client-10.0.0/splitio/push/__init__.py +13 -0
  49. splitio_client-10.0.0/splitio/push/manager.py +534 -0
  50. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/push/parser.py +7 -3
  51. splitio_client-10.0.0/splitio/push/processor.py +190 -0
  52. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/push/splitsse.py +140 -39
  53. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/push/sse.py +103 -11
  54. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/push/status_tracker.py +183 -37
  55. splitio_client-10.0.0/splitio/push/workers.py +371 -0
  56. splitio_client-10.0.0/splitio/recorder/recorder.py +431 -0
  57. splitio_client-10.0.0/splitio/spec.py +1 -0
  58. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/__init__.py +4 -3
  59. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/adapters/cache_trait.py +102 -37
  60. splitio_client-10.0.0/splitio/storage/adapters/redis.py +976 -0
  61. splitio_client-10.0.0/splitio/storage/inmemmory.py +1906 -0
  62. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/pluggable.py +1182 -389
  63. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/redis.py +892 -185
  64. splitio_client-10.0.0/splitio/sync/event.py +129 -0
  65. splitio_client-10.0.0/splitio/sync/impression.py +191 -0
  66. splitio_client-10.0.0/splitio/sync/manager.py +323 -0
  67. splitio_client-10.0.0/splitio/sync/segment.py +639 -0
  68. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/split.py +466 -150
  69. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/synchronizer.py +592 -76
  70. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/telemetry.py +82 -5
  71. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/unique_keys.py +80 -19
  72. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/events_sync.py +44 -15
  73. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/impressions_sync.py +75 -19
  74. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/segment_sync.py +36 -10
  75. splitio_client-10.0.0/splitio/tasks/split_sync.py +69 -0
  76. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/telemetry_sync.py +45 -16
  77. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/unique_keys_sync.py +74 -19
  78. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/util/asynctask.py +154 -2
  79. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/util/workerpool.py +94 -1
  80. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/storage_helper.py +28 -0
  81. splitio_client-10.0.0/splitio/version.py +1 -0
  82. splitio_client-10.0.0/splitio_client.egg-info/PKG-INFO +100 -0
  83. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio_client.egg-info/SOURCES.txt +7 -2
  84. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio_client.egg-info/requires.txt +13 -6
  85. splitio_client-9.6.2/PKG-INFO +0 -21
  86. splitio_client-9.6.2/splitio/api/__init__.py +0 -15
  87. splitio_client-9.6.2/splitio/api/auth.py +0 -61
  88. splitio_client-9.6.2/splitio/api/client.py +0 -149
  89. splitio_client-9.6.2/splitio/api/segments.py +0 -74
  90. splitio_client-9.6.2/splitio/api/splits.py +0 -68
  91. splitio_client-9.6.2/splitio/api/telemetry.py +0 -104
  92. splitio_client-9.6.2/splitio/client/client.py +0 -541
  93. splitio_client-9.6.2/splitio/client/factory.py +0 -725
  94. splitio_client-9.6.2/splitio/client/listener.py +0 -65
  95. splitio_client-9.6.2/splitio/client/manager.py +0 -104
  96. splitio_client-9.6.2/splitio/engine/evaluator.py +0 -201
  97. splitio_client-9.6.2/splitio/engine/impressions/__init__.py +0 -50
  98. splitio_client-9.6.2/splitio/engine/impressions/impressions.py +0 -61
  99. splitio_client-9.6.2/splitio/engine/telemetry.py +0 -354
  100. splitio_client-9.6.2/splitio/models/telemetry.py +0 -1025
  101. splitio_client-9.6.2/splitio/push/manager.py +0 -250
  102. splitio_client-9.6.2/splitio/push/processor.py +0 -90
  103. splitio_client-9.6.2/splitio/push/segmentworker.py +0 -67
  104. splitio_client-9.6.2/splitio/push/splitworker.py +0 -128
  105. splitio_client-9.6.2/splitio/recorder/recorder.py +0 -169
  106. splitio_client-9.6.2/splitio/storage/adapters/redis.py +0 -487
  107. splitio_client-9.6.2/splitio/storage/inmemmory.py +0 -804
  108. splitio_client-9.6.2/splitio/sync/event.py +0 -67
  109. splitio_client-9.6.2/splitio/sync/impression.py +0 -97
  110. splitio_client-9.6.2/splitio/sync/manager.py +0 -177
  111. splitio_client-9.6.2/splitio/sync/segment.py +0 -334
  112. splitio_client-9.6.2/splitio/tasks/split_sync.py +0 -40
  113. splitio_client-9.6.2/splitio/version.py +0 -1
  114. splitio_client-9.6.2/splitio_client.egg-info/PKG-INFO +0 -21
  115. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/__init__.py +0 -0
  116. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/client/key.py +0 -0
  117. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/__init__.py +0 -0
  118. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/cache/__init__.py +0 -0
  119. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/cache/lru.py +0 -0
  120. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/filters.py +0 -0
  121. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/hashfns/__init__.py +0 -0
  122. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/hashfns/murmur3py.py +0 -0
  123. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/engine/splitters.py +0 -0
  124. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/exceptions.py +0 -0
  125. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/factories.py +0 -0
  126. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/impressions.py +0 -0
  127. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/key.py +0 -0
  128. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/datatypes.py +0 -0
  129. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/events.py +0 -0
  130. {splitio_client-9.6.2/splitio/models → splitio_client-10.0.0/splitio/models/grammar}/__init__.py +0 -0
  131. {splitio_client-9.6.2/splitio/models/grammar → splitio_client-10.0.0/splitio/models/grammar/matchers/utils}/__init__.py +0 -0
  132. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/grammar/partitions.py +0 -0
  133. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/impressions.py +0 -0
  134. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/models/segments.py +0 -0
  135. {splitio_client-9.6.2/splitio/push → splitio_client-10.0.0/splitio/optional}/__init__.py +0 -0
  136. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/recorder/__init__.py +0 -0
  137. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/adapters/__init__.py +0 -0
  138. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/storage/adapters/util.py +0 -0
  139. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/__init__.py +0 -0
  140. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/sync/util.py +0 -0
  141. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/__init__.py +0 -0
  142. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/tasks/util/__init__.py +0 -0
  143. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/__init__.py +0 -0
  144. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/backoff.py +0 -0
  145. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/decorators.py +0 -0
  146. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/threadutil.py +0 -0
  147. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio/util/time.py +0 -0
  148. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio_client.egg-info/dependency_links.txt +0 -0
  149. {splitio_client-9.6.2 → splitio_client-10.0.0}/splitio_client.egg-info/top_level.txt +0 -0
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.1
2
+ Name: splitio_client
3
+ Version: 10.0.0
4
+ Summary: Split.io Python Client
5
+ Home-page: https://github.com/splitio/python-client
6
+ Author: Patricio Echague, Sebastian Arrubia
7
+ Author-email: pato@split.io, sebastian@split.io
8
+ License: Apache License 2.0
9
+ Download-URL: https://github.com/splitio/python-client/tarball/10.0.0
10
+ Description: # Split Python SDK
11
+ ![Build Status](https://github.com/splitio/python-client/actions/workflows/ci.yml/badge.svg?branch=master)
12
+
13
+ ## Overview
14
+ 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.
15
+
16
+ [![Twitter Follow](https://img.shields.io/twitter/follow/splitsoftware.svg?style=social&label=Follow&maxAge=1529000)](https://twitter.com/intent/follow?screen_name=splitsoftware)
17
+
18
+ ## Compatibility
19
+ This SDK is compatible with **Python 3.7 and higher**.
20
+
21
+ ## Getting started
22
+ Below is a simple example that describes the instantiation and most basic usage of our SDK:
23
+
24
+ Run `pip install splitio_client`
25
+
26
+
27
+ ```python
28
+ from splitio import get_factory
29
+ from splitio.exceptions import TimeoutException
30
+ factory = get_factory('YOUR_SDK_TYPE_API_KEY', config=config)
31
+ try:
32
+ factory.block_until_ready(5) # wait up to 5 seconds
33
+ split = factory.client()
34
+ treatment = split.get_treatment('CUSTOMER_ID', 'FEATURE_FLAG_NAME')
35
+ if treatment == "on":
36
+ # insert code here to show on treatment
37
+ elif treatment == "off":
38
+ # insert code here to show off treatment
39
+ else:
40
+ # insert your control treatment code here
41
+ except TimeoutException:
42
+ # Now the user can choose whether to abort the whole execution, or just keep going
43
+ # without a ready client, which if configured properly, should become ready at some point.
44
+ pass
45
+ ```
46
+
47
+ 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.
48
+
49
+ ## Submitting issues
50
+ 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.
51
+
52
+ ## Contributing
53
+ Please see [Contributors Guide](CONTRIBUTORS-GUIDE.md) to find all you need to submit a Pull Request (PR).
54
+
55
+ ## License
56
+ Licensed under the Apache License, Version 2.0. See: [Apache License](http://www.apache.org/licenses/).
57
+
58
+ ## About Split
59
+
60
+ 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.
61
+
62
+ To learn more about Split, contact hello@split.io, or get started with feature flags for free at https://www.split.io/signup.
63
+
64
+ Split has built and maintains SDKs for:
65
+
66
+ * .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK)
67
+ * Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK)
68
+ * Angular [Github](https://github.com/splitio/angular-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/6495326064397-Angular-utilities)
69
+ * GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK)
70
+ * iOS [Github](https://github.com/splitio/ios-client) [Docs](https://help.split.io/hc/en-us/articles/360020401491-iOS-SDK)
71
+ * Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK)
72
+ * JavaScript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK)
73
+ * JavaScript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK)
74
+ * Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK)
75
+ * PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK)
76
+ * Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK)
77
+ * React [Github](https://github.com/splitio/react-client) [Docs](https://help.split.io/hc/en-us/articles/360038825091-React-SDK)
78
+ * React Native [Github](https://github.com/splitio/react-native-client) [Docs](https://help.split.io/hc/en-us/articles/4406066357901-React-Native-SDK)
79
+ * Redux [Github](https://github.com/splitio/redux-client) [Docs](https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK)
80
+ * Ruby [Github](https://github.com/splitio/ruby-client) [Docs](https://help.split.io/hc/en-us/articles/360020673251-Ruby-SDK)
81
+
82
+ For a comprehensive list of open source projects visit our [Github page](https://github.com/splitio?utf8=%E2%9C%93&query=%20only%3Apublic%20).
83
+
84
+ **Learn more about Split:**
85
+
86
+ 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.
87
+
88
+ Platform: UNKNOWN
89
+ Classifier: Environment :: Console
90
+ Classifier: Intended Audience :: Developers
91
+ Classifier: Programming Language :: Python
92
+ Classifier: Programming Language :: Python :: 2
93
+ Classifier: Programming Language :: Python :: 3
94
+ Classifier: Topic :: Software Development :: Libraries
95
+ Description-Content-Type: text/markdown
96
+ Provides-Extra: test
97
+ Provides-Extra: redis
98
+ Provides-Extra: uwsgi
99
+ Provides-Extra: cpphash
100
+ Provides-Extra: asyncio
@@ -7,7 +7,7 @@ This SDK is designed to work with Split, the platform for controlled rollouts, w
7
7
  [![Twitter Follow](https://img.shields.io/twitter/follow/splitsoftware.svg?style=social&label=Follow&maxAge=1529000)](https://twitter.com/intent/follow?screen_name=splitsoftware)
8
8
 
9
9
  ## Compatibility
10
- This SDK is compatible with **Python 3 and higher**.
10
+ This SDK is compatible with **Python 3.7 and higher**.
11
11
 
12
12
  ## Getting started
13
13
  Below is a simple example that describes the instantiation and most basic usage of our SDK:
@@ -2,7 +2,10 @@
2
2
  universal = 1
3
3
 
4
4
  [metadata]
5
- description-file = README.md
5
+ name = splitio_client
6
+ description = 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.
7
+ long_description = file: README.md
8
+ long_description_content_type = text/markdown
6
9
 
7
10
  [flake8]
8
11
  max-line-length = 100
@@ -12,7 +15,6 @@ exclude = tests/*
12
15
  test = pytest
13
16
 
14
17
  [tool:pytest]
15
- ignore_glob = ./splitio/_OLD/*
16
18
  addopts = --verbose --cov=splitio --cov-report xml
17
19
  python_classes = *Tests
18
20
 
@@ -7,18 +7,21 @@ from setuptools import setup, find_packages
7
7
  TESTS_REQUIRES = [
8
8
  'flake8',
9
9
  'pytest==7.0.1',
10
- 'pytest-mock==3.12.0',
11
- 'coverage==6.2',
12
- 'pytest-cov',
13
- 'importlib-metadata==4.2',
10
+ 'pytest-mock==3.11.1',
11
+ 'coverage',
12
+ 'pytest-cov==4.1.0',
13
+ 'importlib-metadata==6.7',
14
14
  'tomli==1.2.3',
15
15
  'iniconfig==1.1.1',
16
- 'attrs==22.1.0'
16
+ 'attrs==22.1.0',
17
+ 'pytest-asyncio==0.21.0',
18
+ 'aiohttp>=3.8.4',
19
+ 'aiofiles>=23.1.0'
17
20
  ]
18
21
 
19
22
  INSTALL_REQUIRES = [
20
- 'requests>=2.9.1',
21
- 'pyyaml>=5.4',
23
+ 'requests',
24
+ 'pyyaml',
22
25
  'docopt>=0.6.2',
23
26
  'enum34;python_version<"3.4"',
24
27
  'bloom-filter2>=2.0.0'
@@ -43,8 +46,9 @@ setup(
43
46
  'redis': ['redis>=2.10.5'],
44
47
  'uwsgi': ['uwsgi>=2.0.0'],
45
48
  'cpphash': ['mmh3cffi==0.2.1'],
49
+ 'asyncio': ['aiohttp>=3.8.4', 'aiofiles>=23.1.0']
46
50
  },
47
- setup_requires=['pytest-runner', 'pluggy==1.0.0;python_version<"3.7"'],
51
+ setup_requires=['pytest-runner', 'pluggy==1.0.0;python_version<"3.8"'],
48
52
  classifiers=[
49
53
  'Environment :: Console',
50
54
  'Intended Audience :: Developers',
@@ -1,3 +1,3 @@
1
- from splitio.client.factory import get_factory
1
+ from splitio.client.factory import get_factory, get_factory_async
2
2
  from splitio.client.key import Key
3
3
  from splitio.version import __version__
@@ -0,0 +1,46 @@
1
+ """Split API module."""
2
+
3
+
4
+ class APIException(Exception):
5
+ """Exception to raise when an API call fails."""
6
+
7
+ def __init__(self, custom_message, status_code=None):
8
+ """Constructor."""
9
+ Exception.__init__(self, custom_message)
10
+ self._status_code = status_code if status_code else -1
11
+
12
+ @property
13
+ def status_code(self):
14
+ """Return HTTP status code."""
15
+ return self._status_code
16
+
17
+ class APIUriException(APIException):
18
+ """Exception to raise when an API call fails due to 414 http error."""
19
+
20
+ def __init__(self, custom_message, status_code=None):
21
+ """Constructor."""
22
+ APIException.__init__(self, custom_message, status_code)
23
+
24
+ def headers_from_metadata(sdk_metadata, client_key=None):
25
+ """
26
+ Generate a dict with headers required by data-recording API endpoints.
27
+ :param sdk_metadata: SDK Metadata object, generated at sdk initialization time.
28
+ :type sdk_metadata: splitio.client.util.SdkMetadata
29
+ :param client_key: client key.
30
+ :type client_key: str
31
+ :return: A dictionary with headers.
32
+ :rtype: dict
33
+ """
34
+
35
+ metadata = {
36
+ 'SplitSDKVersion': sdk_metadata.sdk_version,
37
+ 'SplitSDKMachineIP': sdk_metadata.instance_ip,
38
+ 'SplitSDKMachineName': sdk_metadata.instance_name
39
+ } if sdk_metadata.instance_ip != 'NA' and sdk_metadata.instance_ip != 'unknown' else {
40
+ 'SplitSDKVersion': sdk_metadata.sdk_version,
41
+ }
42
+
43
+ if client_key is not None:
44
+ metadata['SplitSDKClientKey'] = client_key
45
+
46
+ return metadata
@@ -0,0 +1,109 @@
1
+ """Auth API module."""
2
+
3
+ import logging
4
+ import json
5
+
6
+ from splitio.api import APIException, headers_from_metadata
7
+ from splitio.api.commons import headers_from_metadata, record_telemetry
8
+ from splitio.spec import SPEC_VERSION
9
+ from splitio.util.time import get_current_epoch_time_ms
10
+ from splitio.api.client import HttpClientException
11
+ from splitio.models.token import from_raw
12
+ from splitio.models.telemetry import HTTPExceptionsAndLatencies
13
+
14
+ _LOGGER = logging.getLogger(__name__)
15
+
16
+
17
+ class AuthAPI(object): # pylint: disable=too-few-public-methods
18
+ """Class that uses an httpClient to communicate with the SDK Auth Service API."""
19
+
20
+ def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer):
21
+ """
22
+ Class constructor.
23
+
24
+ :param client: HTTP Client responsble for issuing calls to the backend.
25
+ :type client: HttpClient
26
+ :param sdk_key: User sdk key.
27
+ :type sdk_key: string
28
+ :param sdk_metadata: SDK version & machine name & IP.
29
+ :type sdk_metadata: splitio.client.util.SdkMetadata
30
+ """
31
+ self._client = client
32
+ self._sdk_key = sdk_key
33
+ self._metadata = headers_from_metadata(sdk_metadata)
34
+ self._telemetry_runtime_producer = telemetry_runtime_producer
35
+ self._client.set_telemetry_data(HTTPExceptionsAndLatencies.TOKEN, self._telemetry_runtime_producer)
36
+
37
+ def authenticate(self):
38
+ """
39
+ Perform authentication.
40
+
41
+ :return: Json representation of an authentication.
42
+ :rtype: splitio.models.token.Token
43
+ """
44
+ try:
45
+ response = self._client.get(
46
+ 'auth',
47
+ 'v2/auth?s=' + SPEC_VERSION,
48
+ self._sdk_key,
49
+ extra_headers=self._metadata,
50
+ )
51
+ if 200 <= response.status_code < 300:
52
+ payload = json.loads(response.body)
53
+ return from_raw(payload)
54
+
55
+ else:
56
+ if (response.status_code >= 400 and response.status_code < 500):
57
+ self._telemetry_runtime_producer.record_auth_rejections()
58
+ raise APIException(response.body, response.status_code)
59
+ except HttpClientException as exc:
60
+ _LOGGER.error('Exception raised while authenticating')
61
+ _LOGGER.debug('Exception information: ', exc_info=True)
62
+ raise APIException('Could not perform authentication.') from exc
63
+
64
+ class AuthAPIAsync(object): # pylint: disable=too-few-public-methods
65
+ """Async Class that uses an httpClient to communicate with the SDK Auth Service API."""
66
+
67
+ def __init__(self, client, sdk_key, sdk_metadata, telemetry_runtime_producer):
68
+ """
69
+ Class constructor.
70
+
71
+ :param client: HTTP Client responsble for issuing calls to the backend.
72
+ :type client: HttpClient
73
+ :param sdk_key: User sdk key.
74
+ :type sdk_key: string
75
+ :param sdk_metadata: SDK version & machine name & IP.
76
+ :type sdk_metadata: splitio.client.util.SdkMetadata
77
+ """
78
+ self._client = client
79
+ self._sdk_key = sdk_key
80
+ self._metadata = headers_from_metadata(sdk_metadata)
81
+ self._telemetry_runtime_producer = telemetry_runtime_producer
82
+ self._client.set_telemetry_data(HTTPExceptionsAndLatencies.TOKEN, self._telemetry_runtime_producer)
83
+
84
+ async def authenticate(self):
85
+ """
86
+ Perform authentication.
87
+
88
+ :return: Json representation of an authentication.
89
+ :rtype: splitio.models.token.Token
90
+ """
91
+ try:
92
+ response = await self._client.get(
93
+ 'auth',
94
+ 'v2/auth?s=' + SPEC_VERSION,
95
+ self._sdk_key,
96
+ extra_headers=self._metadata,
97
+ )
98
+ if 200 <= response.status_code < 300:
99
+ payload = json.loads(response.body)
100
+ return from_raw(payload)
101
+
102
+ else:
103
+ if (response.status_code >= 400 and response.status_code < 500):
104
+ await self._telemetry_runtime_producer.record_auth_rejections()
105
+ raise APIException(response.body, response.status_code)
106
+ except HttpClientException as exc:
107
+ _LOGGER.error('Exception raised while authenticating')
108
+ _LOGGER.debug('Exception information: ', exc_info=True)
109
+ raise APIException('Could not perform authentication.') from exc
@@ -0,0 +1,336 @@
1
+ """Synchronous HTTP Client for split API."""
2
+ from collections import namedtuple
3
+ import requests
4
+ import urllib
5
+ import abc
6
+ import logging
7
+ import json
8
+
9
+ from splitio.optional.loaders import aiohttp
10
+ from splitio.util.time import get_current_epoch_time_ms
11
+
12
+ SDK_URL = 'https://sdk.split.io/api'
13
+ EVENTS_URL = 'https://events.split.io/api'
14
+ AUTH_URL = 'https://auth.split.io/api'
15
+ TELEMETRY_URL = 'https://telemetry.split.io/api'
16
+
17
+ _LOGGER = logging.getLogger(__name__)
18
+
19
+
20
+ HttpResponse = namedtuple('HttpResponse', ['status_code', 'body', 'headers'])
21
+
22
+ def _build_url(server, path, urls):
23
+ """
24
+ Build URL according to server specified.
25
+
26
+ :param server: Server for whith the request is being made.
27
+ :type server: str
28
+ :param path: URL path to be appended to base host.
29
+ :type path: str
30
+
31
+ :return: A fully qualified URL.
32
+ :rtype: str
33
+ """
34
+ url = urls[server]
35
+ url += '/' if urls[server][:-1] != '/' else ''
36
+ return urllib.parse.urljoin(url, path)
37
+
38
+ def _construct_urls(sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
39
+ return {
40
+ 'sdk': sdk_url if sdk_url is not None else SDK_URL,
41
+ 'events': events_url if events_url is not None else EVENTS_URL,
42
+ 'auth': auth_url if auth_url is not None else AUTH_URL,
43
+ 'telemetry': telemetry_url if telemetry_url is not None else TELEMETRY_URL,
44
+ }
45
+
46
+ def _build_basic_headers(sdk_key):
47
+ """
48
+ Build basic headers with auth.
49
+
50
+ :param sdk_key: API token used to identify backend calls.
51
+ :type sdk_key: str
52
+ """
53
+ return {
54
+ 'Content-Type': 'application/json',
55
+ 'Authorization': "Bearer %s" % sdk_key
56
+ }
57
+
58
+ class HttpClientException(Exception):
59
+ """HTTP Client exception."""
60
+
61
+ def __init__(self, message):
62
+ """
63
+ Class constructor.
64
+
65
+ :param message: Information on why this exception happened.
66
+ :type message: str
67
+ """
68
+ Exception.__init__(self, message)
69
+
70
+ class HttpClientBase(object, metaclass=abc.ABCMeta):
71
+ """HttpClient wrapper template."""
72
+
73
+ @abc.abstractmethod
74
+ def get(self, server, path, apikey):
75
+ """http get request"""
76
+
77
+ @abc.abstractmethod
78
+ def post(self, server, path, apikey):
79
+ """http post request"""
80
+
81
+ def set_telemetry_data(self, metric_name, telemetry_runtime_producer):
82
+ """
83
+ Set the data needed for telemetry call
84
+
85
+ :param metric_name: metric name for telemetry
86
+ :type metric_name: str
87
+
88
+ :param telemetry_runtime_producer: telemetry recording instance
89
+ :type telemetry_runtime_producer: splitio.engine.telemetry.TelemetryRuntimeProducer
90
+ """
91
+ self._telemetry_runtime_producer = telemetry_runtime_producer
92
+ self._metric_name = metric_name
93
+
94
+
95
+ class HttpClient(HttpClientBase):
96
+ """HttpClient wrapper."""
97
+
98
+ def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
99
+ """
100
+ Class constructor.
101
+
102
+ :param timeout: How many milliseconds to wait until the server responds.
103
+ :type timeout: int
104
+ :param sdk_url: Optional alternative sdk URL.
105
+ :type sdk_url: str
106
+ :param events_url: Optional alternative events URL.
107
+ :type events_url: str
108
+ :param auth_url: Optional alternative auth URL.
109
+ :type auth_url: str
110
+ :param telemetry_url: Optional alternative telemetry URL.
111
+ :type telemetry_url: str
112
+ """
113
+ self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
114
+ self._urls = _construct_urls(sdk_url, events_url, auth_url, telemetry_url)
115
+
116
+ def get(self, server, path, sdk_key, query=None, extra_headers=None): # pylint: disable=too-many-arguments
117
+ """
118
+ Issue a get request.
119
+
120
+ :param server: Whether the request is for SDK server, Events server or Auth server.
121
+ :typee server: str
122
+ :param path: path to append to the host url.
123
+ :type path: str
124
+ :param sdk_key: sdk key.
125
+ :type sdk_key: str
126
+ :param query: Query string passed as dictionary.
127
+ :type query: dict
128
+ :param extra_headers: key/value pairs of possible extra headers.
129
+ :type extra_headers: dict
130
+
131
+ :return: Tuple of status_code & response text
132
+ :rtype: HttpResponse
133
+ """
134
+ headers = _build_basic_headers(sdk_key)
135
+ if extra_headers is not None:
136
+ headers.update(extra_headers)
137
+
138
+ start = get_current_epoch_time_ms()
139
+ try:
140
+ response = requests.get(
141
+ _build_url(server, path, self._urls),
142
+ params=query,
143
+ headers=headers,
144
+ timeout=self._timeout
145
+ )
146
+ self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
147
+ return HttpResponse(response.status_code, response.text, response.headers)
148
+
149
+ except Exception as exc: # pylint: disable=broad-except
150
+ raise HttpClientException('requests library is throwing exceptions') from exc
151
+
152
+ def post(self, server, path, sdk_key, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
153
+ """
154
+ Issue a POST request.
155
+
156
+ :param server: Whether the request is for SDK server or Events server.
157
+ :typee server: str
158
+ :param path: path to append to the host url.
159
+ :type path: str
160
+ :param sdk_key: sdk key.
161
+ :type sdk_key: str
162
+ :param body: body sent in the request.
163
+ :type body: str
164
+ :param query: Query string passed as dictionary.
165
+ :type query: dict
166
+ :param extra_headers: key/value pairs of possible extra headers.
167
+ :type extra_headers: dict
168
+
169
+ :return: Tuple of status_code & response text
170
+ :rtype: HttpResponse
171
+ """
172
+ headers = _build_basic_headers(sdk_key)
173
+
174
+ if extra_headers is not None:
175
+ headers.update(extra_headers)
176
+
177
+ start = get_current_epoch_time_ms()
178
+ try:
179
+ response = requests.post(
180
+ _build_url(server, path, self._urls),
181
+ json=body,
182
+ params=query,
183
+ headers=headers,
184
+ timeout=self._timeout
185
+ )
186
+ self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
187
+ return HttpResponse(response.status_code, response.text, response.headers)
188
+
189
+ except Exception as exc: # pylint: disable=broad-except
190
+ raise HttpClientException('requests library is throwing exceptions') from exc
191
+
192
+ def _record_telemetry(self, status_code, elapsed):
193
+ """
194
+ Record Telemetry info
195
+
196
+ :param status_code: http request status code
197
+ :type status_code: int
198
+
199
+ :param elapsed: response time elapsed.
200
+ :type status_code: int
201
+ """
202
+ self._telemetry_runtime_producer.record_sync_latency(self._metric_name, elapsed)
203
+ if 200 <= status_code < 300:
204
+ self._telemetry_runtime_producer.record_successful_sync(self._metric_name, get_current_epoch_time_ms())
205
+ return
206
+ self._telemetry_runtime_producer.record_sync_error(self._metric_name, status_code)
207
+
208
+
209
+ class HttpClientAsync(HttpClientBase):
210
+ """HttpClientAsync wrapper."""
211
+
212
+ def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
213
+ """
214
+ Class constructor.
215
+ :param timeout: How many milliseconds to wait until the server responds.
216
+ :type timeout: int
217
+ :param sdk_url: Optional alternative sdk URL.
218
+ :type sdk_url: str
219
+ :param events_url: Optional alternative events URL.
220
+ :type events_url: str
221
+ :param auth_url: Optional alternative auth URL.
222
+ :type auth_url: str
223
+ :param telemetry_url: Optional alternative telemetry URL.
224
+ :type telemetry_url: str
225
+ """
226
+ self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
227
+ self._urls = _construct_urls(sdk_url, events_url, auth_url, telemetry_url)
228
+ self._session = aiohttp.ClientSession()
229
+
230
+ async def get(self, server, path, apikey, query=None, extra_headers=None): # pylint: disable=too-many-arguments
231
+ """
232
+ Issue a get request.
233
+ :param server: Whether the request is for SDK server, Events server or Auth server.
234
+ :typee server: str
235
+ :param path: path to append to the host url.
236
+ :type path: str
237
+ :param apikey: api token.
238
+ :type apikey: str
239
+ :param query: Query string passed as dictionary.
240
+ :type query: dict
241
+ :param extra_headers: key/value pairs of possible extra headers.
242
+ :type extra_headers: dict
243
+ :return: Tuple of status_code & response text
244
+ :rtype: HttpResponse
245
+ """
246
+ headers = _build_basic_headers(apikey)
247
+ if extra_headers is not None:
248
+ headers.update(extra_headers)
249
+ start = get_current_epoch_time_ms()
250
+ try:
251
+ url = _build_url(server, path, self._urls)
252
+ _LOGGER.debug("GET request: %s", url)
253
+ _LOGGER.debug("query params: %s", query)
254
+ _LOGGER.debug("headers: %s", headers)
255
+ async with self._session.get(
256
+ url,
257
+ params=query,
258
+ headers=headers,
259
+ timeout=self._timeout
260
+ ) as response:
261
+ body = await response.text()
262
+ _LOGGER.debug("Response:")
263
+ _LOGGER.debug(response)
264
+ _LOGGER.debug(body)
265
+ await self._record_telemetry(response.status, get_current_epoch_time_ms() - start)
266
+ return HttpResponse(response.status, body, response.headers)
267
+
268
+ except aiohttp.ClientError as exc: # pylint: disable=broad-except
269
+ raise HttpClientException('aiohttp library is throwing exceptions') from exc
270
+
271
+ async def post(self, server, path, apikey, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
272
+ """
273
+ Issue a POST request.
274
+ :param server: Whether the request is for SDK server or Events server.
275
+ :typee server: str
276
+ :param path: path to append to the host url.
277
+ :type path: str
278
+ :param apikey: api token.
279
+ :type apikey: str
280
+ :param body: body sent in the request.
281
+ :type body: str
282
+ :param query: Query string passed as dictionary.
283
+ :type query: dict
284
+ :param extra_headers: key/value pairs of possible extra headers.
285
+ :type extra_headers: dict
286
+ :return: Tuple of status_code & response text
287
+ :rtype: HttpResponse
288
+ """
289
+ headers = _build_basic_headers(apikey)
290
+ if extra_headers is not None:
291
+ headers.update(extra_headers)
292
+ start = get_current_epoch_time_ms()
293
+ try:
294
+ headers['Accept-Encoding'] = 'gzip'
295
+ _LOGGER.debug("POST request: %s", _build_url(server, path, self._urls))
296
+ _LOGGER.debug("query params: %s", query)
297
+ _LOGGER.debug("headers: %s", headers)
298
+ _LOGGER.debug("payload: ")
299
+ _LOGGER.debug(str(json.dumps(body)).encode('utf-8'))
300
+ async with self._session.post(
301
+ _build_url(server, path, self._urls),
302
+ params=query,
303
+ headers=headers,
304
+ json=body,
305
+ timeout=self._timeout
306
+ ) as response:
307
+ body = await response.text()
308
+ _LOGGER.debug("Response:")
309
+ _LOGGER.debug(response)
310
+ _LOGGER.debug(body)
311
+ await self._record_telemetry(response.status, get_current_epoch_time_ms() - start)
312
+ return HttpResponse(response.status, body, response.headers)
313
+
314
+ except aiohttp.ClientError as exc: # pylint: disable=broad-except
315
+ raise HttpClientException('aiohttp library is throwing exceptions') from exc
316
+
317
+ async def _record_telemetry(self, status_code, elapsed):
318
+ """
319
+ Record Telemetry info
320
+
321
+ :param status_code: http request status code
322
+ :type status_code: int
323
+
324
+ :param elapsed: response time elapsed.
325
+ :type status_code: int
326
+ """
327
+ await self._telemetry_runtime_producer.record_sync_latency(self._metric_name, elapsed)
328
+ if 200 <= status_code < 300:
329
+ await self._telemetry_runtime_producer.record_successful_sync(self._metric_name, get_current_epoch_time_ms())
330
+ return
331
+
332
+ await self._telemetry_runtime_producer.record_sync_error(self._metric_name, status_code)
333
+
334
+ async def close_session(self):
335
+ if not self._session.closed:
336
+ await self._session.close()