splitio-client 10.0.1__tar.gz → 10.1.0rc2__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 (120) hide show
  1. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/PKG-INFO +3 -2
  2. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/setup.py +4 -2
  3. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/client.py +82 -44
  4. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/config.py +21 -1
  5. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/factory.py +9 -2
  6. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/optional/loaders.py +12 -0
  7. splitio_client-10.1.0rc2/splitio/version.py +1 -0
  8. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio_client.egg-info/PKG-INFO +3 -2
  9. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio_client.egg-info/requires.txt +4 -0
  10. splitio_client-10.0.1/splitio/version.py +0 -1
  11. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/README.md +0 -0
  12. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/setup.cfg +0 -0
  13. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/__init__.py +0 -0
  14. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/__init__.py +0 -0
  15. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/auth.py +0 -0
  16. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/commons.py +0 -0
  17. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/events.py +0 -0
  18. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/impressions.py +0 -0
  19. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/segments.py +0 -0
  20. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/splits.py +0 -0
  21. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/api/telemetry.py +0 -0
  22. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/__init__.py +0 -0
  23. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/client.py +0 -0
  24. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/input_validator.py +0 -0
  25. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/key.py +0 -0
  26. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/listener.py +0 -0
  27. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/localhost.py +0 -0
  28. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/manager.py +0 -0
  29. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/client/util.py +0 -0
  30. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/__init__.py +0 -0
  31. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/cache/__init__.py +0 -0
  32. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/cache/lru.py +0 -0
  33. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/evaluator.py +0 -0
  34. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/filters.py +0 -0
  35. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/hashfns/__init__.py +0 -0
  36. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/hashfns/legacy.py +0 -0
  37. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/hashfns/murmur3py.py +0 -0
  38. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/impressions/__init__.py +0 -0
  39. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/impressions/adapters.py +0 -0
  40. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/impressions/impressions.py +0 -0
  41. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/impressions/manager.py +0 -0
  42. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/impressions/strategies.py +0 -0
  43. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/impressions/unique_keys_tracker.py +0 -0
  44. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/splitters.py +0 -0
  45. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/engine/telemetry.py +0 -0
  46. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/exceptions.py +0 -0
  47. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/factories.py +0 -0
  48. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/impressions.py +0 -0
  49. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/key.py +0 -0
  50. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/__init__.py +0 -0
  51. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/datatypes.py +0 -0
  52. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/events.py +0 -0
  53. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/__init__.py +0 -0
  54. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/condition.py +0 -0
  55. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/__init__.py +0 -0
  56. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/base.py +0 -0
  57. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/keys.py +0 -0
  58. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/misc.py +0 -0
  59. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/numeric.py +0 -0
  60. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/semver.py +0 -0
  61. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/sets.py +0 -0
  62. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/string.py +0 -0
  63. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/utils/__init__.py +0 -0
  64. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/matchers/utils/utils.py +0 -0
  65. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/grammar/partitions.py +0 -0
  66. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/impressions.py +0 -0
  67. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/notification.py +0 -0
  68. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/segments.py +0 -0
  69. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/splits.py +0 -0
  70. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/telemetry.py +0 -0
  71. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/models/token.py +0 -0
  72. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/optional/__init__.py +0 -0
  73. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/push/__init__.py +0 -0
  74. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/push/manager.py +0 -0
  75. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/push/parser.py +0 -0
  76. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/push/processor.py +0 -0
  77. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/push/splitsse.py +0 -0
  78. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/push/sse.py +0 -0
  79. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/push/status_tracker.py +0 -0
  80. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/push/workers.py +0 -0
  81. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/recorder/__init__.py +0 -0
  82. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/recorder/recorder.py +0 -0
  83. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/spec.py +0 -0
  84. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/storage/__init__.py +0 -0
  85. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/storage/adapters/__init__.py +0 -0
  86. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/storage/adapters/cache_trait.py +0 -0
  87. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/storage/adapters/redis.py +0 -0
  88. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/storage/adapters/util.py +0 -0
  89. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/storage/inmemmory.py +0 -0
  90. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/storage/pluggable.py +0 -0
  91. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/storage/redis.py +0 -0
  92. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/__init__.py +0 -0
  93. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/event.py +0 -0
  94. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/impression.py +0 -0
  95. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/manager.py +0 -0
  96. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/segment.py +0 -0
  97. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/split.py +0 -0
  98. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/synchronizer.py +0 -0
  99. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/telemetry.py +0 -0
  100. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/unique_keys.py +0 -0
  101. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/sync/util.py +0 -0
  102. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/__init__.py +0 -0
  103. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/events_sync.py +0 -0
  104. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/impressions_sync.py +0 -0
  105. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/segment_sync.py +0 -0
  106. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/split_sync.py +0 -0
  107. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/telemetry_sync.py +0 -0
  108. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/unique_keys_sync.py +0 -0
  109. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/util/__init__.py +0 -0
  110. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/util/asynctask.py +0 -0
  111. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/tasks/util/workerpool.py +0 -0
  112. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/util/__init__.py +0 -0
  113. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/util/backoff.py +0 -0
  114. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/util/decorators.py +0 -0
  115. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/util/storage_helper.py +0 -0
  116. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/util/threadutil.py +0 -0
  117. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio/util/time.py +0 -0
  118. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio_client.egg-info/SOURCES.txt +0 -0
  119. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio_client.egg-info/dependency_links.txt +0 -0
  120. {splitio_client-10.0.1 → splitio_client-10.1.0rc2}/splitio_client.egg-info/top_level.txt +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: splitio_client
3
- Version: 10.0.1
3
+ Version: 10.1.0rc2
4
4
  Summary: Split.io Python Client
5
5
  Home-page: https://github.com/splitio/python-client
6
6
  Author: Patricio Echague, Sebastian Arrubia
7
7
  Author-email: pato@split.io, sebastian@split.io
8
8
  License: Apache License 2.0
9
- Download-URL: https://github.com/splitio/python-client/tarball/10.0.1
9
+ Download-URL: https://github.com/splitio/python-client/tarball/10.1.0rc2
10
10
  Description: # Split Python SDK
11
11
  ![Build Status](https://github.com/splitio/python-client/actions/workflows/ci.yml/badge.svg?branch=master)
12
12
 
@@ -98,3 +98,4 @@ Provides-Extra: redis
98
98
  Provides-Extra: uwsgi
99
99
  Provides-Extra: cpphash
100
100
  Provides-Extra: asyncio
101
+ Provides-Extra: kerberos
@@ -16,7 +16,8 @@ TESTS_REQUIRES = [
16
16
  'attrs==22.1.0',
17
17
  'pytest-asyncio==0.21.0',
18
18
  'aiohttp>=3.8.4',
19
- 'aiofiles>=23.1.0'
19
+ 'aiofiles>=23.1.0',
20
+ 'requests-kerberos>=0.15.0'
20
21
  ]
21
22
 
22
23
  INSTALL_REQUIRES = [
@@ -46,7 +47,8 @@ setup(
46
47
  'redis': ['redis>=2.10.5'],
47
48
  'uwsgi': ['uwsgi>=2.0.0'],
48
49
  'cpphash': ['mmh3cffi==0.2.1'],
49
- 'asyncio': ['aiohttp>=3.8.4', 'aiofiles>=23.1.0']
50
+ 'asyncio': ['aiohttp>=3.8.4', 'aiofiles>=23.1.0'],
51
+ 'kerberos': ['requests-kerberos>=0.15.0']
50
52
  },
51
53
  setup_requires=['pytest-runner', 'pluggy==1.0.0;python_version<"3.8"'],
52
54
  classifiers=[
@@ -5,7 +5,11 @@ import urllib
5
5
  import abc
6
6
  import logging
7
7
  import json
8
+ import threading
9
+ from urllib3.util import parse_url
8
10
 
11
+ from splitio.optional.loaders import HTTPKerberosAuth, OPTIONAL
12
+ from splitio.client.config import AuthenticateScheme
9
13
  from splitio.optional.loaders import aiohttp
10
14
  from splitio.util.time import get_current_epoch_time_ms
11
15
 
@@ -67,6 +71,24 @@ class HttpClientException(Exception):
67
71
  """
68
72
  Exception.__init__(self, message)
69
73
 
74
+ class HTTPAdapterWithProxyKerberosAuth(requests.adapters.HTTPAdapter):
75
+ """HTTPAdapter override for Kerberos Proxy auth"""
76
+
77
+ def __init__(self, principal=None, password=None):
78
+ requests.adapters.HTTPAdapter.__init__(self)
79
+ self._principal = principal
80
+ self._password = password
81
+
82
+ def proxy_headers(self, proxy):
83
+ headers = {}
84
+ if self._principal is not None:
85
+ auth = HTTPKerberosAuth(principal=self._principal, password=self._password)
86
+ else:
87
+ auth = HTTPKerberosAuth()
88
+ negotiate_details = auth.generate_request_header(None, parse_url(proxy).host, is_preemptive=True)
89
+ headers['Proxy-Authorization'] = negotiate_details
90
+ return headers
91
+
70
92
  class HttpClientBase(object, metaclass=abc.ABCMeta):
71
93
  """HttpClient wrapper template."""
72
94
 
@@ -91,11 +113,16 @@ class HttpClientBase(object, metaclass=abc.ABCMeta):
91
113
  self._telemetry_runtime_producer = telemetry_runtime_producer
92
114
  self._metric_name = metric_name
93
115
 
116
+ def _get_headers(self, extra_headers, sdk_key):
117
+ headers = _build_basic_headers(sdk_key)
118
+ if extra_headers is not None:
119
+ headers.update(extra_headers)
120
+ return headers
94
121
 
95
122
  class HttpClient(HttpClientBase):
96
123
  """HttpClient wrapper."""
97
124
 
98
- def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
125
+ def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None, authentication_scheme=None, authentication_params=None):
99
126
  """
100
127
  Class constructor.
101
128
 
@@ -110,8 +137,12 @@ class HttpClient(HttpClientBase):
110
137
  :param telemetry_url: Optional alternative telemetry URL.
111
138
  :type telemetry_url: str
112
139
  """
140
+ _LOGGER.debug("Initializing httpclient")
113
141
  self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
114
142
  self._urls = _construct_urls(sdk_url, events_url, auth_url, telemetry_url)
143
+ self._authentication_scheme = authentication_scheme
144
+ self._authentication_params = authentication_params
145
+ self._lock = threading.RLock()
115
146
 
116
147
  def get(self, server, path, sdk_key, query=None, extra_headers=None): # pylint: disable=too-many-arguments
117
148
  """
@@ -131,23 +162,22 @@ class HttpClient(HttpClientBase):
131
162
  :return: Tuple of status_code & response text
132
163
  :rtype: HttpResponse
133
164
  """
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
165
+ with self._lock:
166
+ start = get_current_epoch_time_ms()
167
+ with requests.Session() as session:
168
+ self._set_authentication(session)
169
+ try:
170
+ response = session.get(
171
+ _build_url(server, path, self._urls),
172
+ params=query,
173
+ headers=self._get_headers(extra_headers, sdk_key),
174
+ timeout=self._timeout
175
+ )
176
+ self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
177
+ return HttpResponse(response.status_code, response.text, response.headers)
178
+
179
+ except Exception as exc: # pylint: disable=broad-except
180
+ raise HttpClientException('requests library is throwing exceptions') from exc
151
181
 
152
182
  def post(self, server, path, sdk_key, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
153
183
  """
@@ -169,25 +199,37 @@ class HttpClient(HttpClientBase):
169
199
  :return: Tuple of status_code & response text
170
200
  :rtype: HttpResponse
171
201
  """
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)
202
+ with self._lock:
203
+ start = get_current_epoch_time_ms()
204
+ with requests.Session() as session:
205
+ self._set_authentication(session)
206
+ try:
207
+ response = session.post(
208
+ _build_url(server, path, self._urls),
209
+ json=body,
210
+ params=query,
211
+ headers=self._get_headers(extra_headers, sdk_key),
212
+ timeout=self._timeout,
213
+ )
214
+ self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
215
+ return HttpResponse(response.status_code, response.text, response.headers)
216
+ except Exception as exc: # pylint: disable=broad-except
217
+ raise HttpClientException('requests library is throwing exceptions') from exc
218
+
219
+ def _set_authentication(self, session):
220
+ if self._authentication_scheme == AuthenticateScheme.KERBEROS_SPNEGO:
221
+ _LOGGER.debug("Using Kerberos Spnego Authentication")
222
+ if self._authentication_params != [None, None]:
223
+ session.auth = HTTPKerberosAuth(principal=self._authentication_params[0], password=self._authentication_params[1], mutual_authentication=OPTIONAL)
224
+ else:
225
+ session.auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL)
226
+ elif self._authentication_scheme == AuthenticateScheme.KERBEROS_PROXY:
227
+ _LOGGER.debug("Using Kerberos Proxy Authentication")
228
+ if self._authentication_params != [None, None]:
229
+ session.mount('https://', HTTPAdapterWithProxyKerberosAuth(principal=self._authentication_params[0], password=self._authentication_params[1]))
230
+ else:
231
+ session.mount('https://', HTTPAdapterWithProxyKerberosAuth())
188
232
 
189
- except Exception as exc: # pylint: disable=broad-except
190
- raise HttpClientException('requests library is throwing exceptions') from exc
191
233
 
192
234
  def _record_telemetry(self, status_code, elapsed):
193
235
  """
@@ -203,8 +245,8 @@ class HttpClient(HttpClientBase):
203
245
  if 200 <= status_code < 300:
204
246
  self._telemetry_runtime_producer.record_successful_sync(self._metric_name, get_current_epoch_time_ms())
205
247
  return
206
- self._telemetry_runtime_producer.record_sync_error(self._metric_name, status_code)
207
248
 
249
+ self._telemetry_runtime_producer.record_sync_error(self._metric_name, status_code)
208
250
 
209
251
  class HttpClientAsync(HttpClientBase):
210
252
  """HttpClientAsync wrapper."""
@@ -243,10 +285,8 @@ class HttpClientAsync(HttpClientBase):
243
285
  :return: Tuple of status_code & response text
244
286
  :rtype: HttpResponse
245
287
  """
246
- headers = _build_basic_headers(apikey)
247
- if extra_headers is not None:
248
- headers.update(extra_headers)
249
288
  start = get_current_epoch_time_ms()
289
+ headers = self._get_headers(extra_headers, apikey)
250
290
  try:
251
291
  url = _build_url(server, path, self._urls)
252
292
  _LOGGER.debug("GET request: %s", url)
@@ -286,9 +326,7 @@ class HttpClientAsync(HttpClientBase):
286
326
  :return: Tuple of status_code & response text
287
327
  :rtype: HttpResponse
288
328
  """
289
- headers = _build_basic_headers(apikey)
290
- if extra_headers is not None:
291
- headers.update(extra_headers)
329
+ headers = self._get_headers(extra_headers, apikey)
292
330
  start = get_current_epoch_time_ms()
293
331
  try:
294
332
  headers['Accept-Encoding'] = 'gzip'
@@ -333,4 +371,4 @@ class HttpClientAsync(HttpClientBase):
333
371
 
334
372
  async def close_session(self):
335
373
  if not self._session.closed:
336
- await self._session.close()
374
+ await self._session.close()
@@ -1,6 +1,7 @@
1
1
  """Default settings for the Split.IO SDK Python client."""
2
2
  import os.path
3
3
  import logging
4
+ from enum import Enum
4
5
 
5
6
  from splitio.engine.impressions import ImpressionsMode
6
7
  from splitio.client.input_validator import validate_flag_sets
@@ -8,6 +9,12 @@ from splitio.client.input_validator import validate_flag_sets
8
9
  _LOGGER = logging.getLogger(__name__)
9
10
  DEFAULT_DATA_SAMPLING = 1
10
11
 
12
+ class AuthenticateScheme(Enum):
13
+ """Authentication Scheme."""
14
+ NONE = 'NONE'
15
+ KERBEROS_SPNEGO = 'KERBEROS_SPNEGO'
16
+ KERBEROS_PROXY = 'KERBEROS_PROXY'
17
+
11
18
  DEFAULT_CONFIG = {
12
19
  'operationMode': 'standalone',
13
20
  'connectionTimeout': 1500,
@@ -59,7 +66,10 @@ DEFAULT_CONFIG = {
59
66
  'storageWrapper': None,
60
67
  'storagePrefix': None,
61
68
  'storageType': None,
62
- 'flagSetsFilter': None
69
+ 'flagSetsFilter': None,
70
+ 'httpAuthenticateScheme': AuthenticateScheme.NONE,
71
+ 'kerberosPrincipalUser': None,
72
+ 'kerberosPrincipalPassword': None
63
73
  }
64
74
 
65
75
  def _parse_operation_mode(sdk_key, config):
@@ -148,4 +158,14 @@ def sanitize(sdk_key, config):
148
158
  else:
149
159
  processed['flagSetsFilter'] = sorted(validate_flag_sets(processed['flagSetsFilter'], 'SDK Config')) if processed['flagSetsFilter'] is not None else None
150
160
 
161
+ if config.get('httpAuthenticateScheme') is not None:
162
+ try:
163
+ authenticate_scheme = AuthenticateScheme(config['httpAuthenticateScheme'].upper())
164
+ except (ValueError, AttributeError):
165
+ authenticate_scheme = AuthenticateScheme.NONE
166
+ _LOGGER.warning('You passed an invalid HttpAuthenticationScheme, HttpAuthenticationScheme should be ' \
167
+ 'one of the following values: `none`, `kerberos_proxy` or `kerberos_spnego`. '
168
+ ' Defaulting to `none` mode.')
169
+ processed["httpAuthenticateScheme"] = authenticate_scheme
170
+
151
171
  return processed
@@ -7,8 +7,8 @@ from enum import Enum
7
7
  from splitio.optional.loaders import asyncio
8
8
  from splitio.client.client import Client, ClientAsync
9
9
  from splitio.client import input_validator
10
+ from splitio.client.config import sanitize as sanitize_config, DEFAULT_DATA_SAMPLING, AuthenticateScheme
10
11
  from splitio.client.manager import SplitManager, SplitManagerAsync
11
- from splitio.client.config import sanitize as sanitize_config, DEFAULT_DATA_SAMPLING
12
12
  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
@@ -508,12 +508,19 @@ def _build_in_memory_factory(api_key, cfg, sdk_url=None, events_url=None, # pyl
508
508
  telemetry_evaluation_producer = telemetry_producer.get_telemetry_evaluation_producer()
509
509
  telemetry_init_producer = telemetry_producer.get_telemetry_init_producer()
510
510
 
511
+ authentication_params = None
512
+ if cfg.get("httpAuthenticateScheme") in [AuthenticateScheme.KERBEROS_SPNEGO, AuthenticateScheme.KERBEROS_PROXY]:
513
+ authentication_params = [cfg.get("kerberosPrincipalUser"),
514
+ cfg.get("kerberosPrincipalPassword")]
515
+
511
516
  http_client = HttpClient(
512
517
  sdk_url=sdk_url,
513
518
  events_url=events_url,
514
519
  auth_url=auth_api_base_url,
515
520
  telemetry_url=telemetry_api_base_url,
516
- timeout=cfg.get('connectionTimeout')
521
+ timeout=cfg.get('connectionTimeout'),
522
+ authentication_scheme = cfg.get("httpAuthenticateScheme"),
523
+ authentication_params = authentication_params
517
524
  )
518
525
 
519
526
  sdk_metadata = util.get_metadata(cfg)
@@ -14,5 +14,17 @@ except ImportError:
14
14
  asyncio = missing_asyncio_dependencies
15
15
  aiofiles = missing_asyncio_dependencies
16
16
 
17
+ try:
18
+ from requests_kerberos import HTTPKerberosAuth, OPTIONAL
19
+ except ImportError:
20
+ def missing_auth_dependencies(*_, **__):
21
+ """Fail if missing dependencies are used."""
22
+ raise NotImplementedError(
23
+ 'Missing kerberos auth dependency. '
24
+ 'Please use `pip install splitio_client[kerberos]` to install the sdk with kerberos auth support'
25
+ )
26
+ HTTPKerberosAuth = missing_auth_dependencies
27
+ OPTIONAL = missing_auth_dependencies
28
+
17
29
  async def _anext(it):
18
30
  return await it.__anext__()
@@ -0,0 +1 @@
1
+ __version__ = '10.1.0rc2'
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: splitio-client
3
- Version: 10.0.1
3
+ Version: 10.1.0rc2
4
4
  Summary: Split.io Python Client
5
5
  Home-page: https://github.com/splitio/python-client
6
6
  Author: Patricio Echague, Sebastian Arrubia
7
7
  Author-email: pato@split.io, sebastian@split.io
8
8
  License: Apache License 2.0
9
- Download-URL: https://github.com/splitio/python-client/tarball/10.0.1
9
+ Download-URL: https://github.com/splitio/python-client/tarball/10.1.0rc2
10
10
  Description: # Split Python SDK
11
11
  ![Build Status](https://github.com/splitio/python-client/actions/workflows/ci.yml/badge.svg?branch=master)
12
12
 
@@ -98,3 +98,4 @@ Provides-Extra: redis
98
98
  Provides-Extra: uwsgi
99
99
  Provides-Extra: cpphash
100
100
  Provides-Extra: asyncio
101
+ Provides-Extra: kerberos
@@ -13,6 +13,9 @@ aiofiles>=23.1.0
13
13
  [cpphash]
14
14
  mmh3cffi==0.2.1
15
15
 
16
+ [kerberos]
17
+ requests-kerberos>=0.15.0
18
+
16
19
  [redis]
17
20
  redis>=2.10.5
18
21
 
@@ -29,6 +32,7 @@ attrs==22.1.0
29
32
  pytest-asyncio==0.21.0
30
33
  aiohttp>=3.8.4
31
34
  aiofiles>=23.1.0
35
+ requests-kerberos>=0.15.0
32
36
 
33
37
  [uwsgi]
34
38
  uwsgi>=2.0.0
@@ -1 +0,0 @@
1
- __version__ = '10.0.1'