splitio-client 10.6.0__tar.gz → 10.7.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.6.0/LICENSE.txt → splitio_client-10.7.0/LICENSE +34 -1
- splitio_client-10.6.0/NOTICE.txt → splitio_client-10.7.0/NOTICE +2 -2
- {splitio_client-10.6.0 → splitio_client-10.7.0}/PKG-INFO +4 -4
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/client.py +26 -14
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/splits.py +17 -11
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/config.py +39 -10
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/factory.py +15 -6
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/evaluator.py +7 -1
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/impressions/adapters.py +8 -8
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/events/events_delivery.py +2 -2
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/events/events_manager_config.py +2 -5
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/events.py +0 -2
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/push/manager.py +7 -4
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/push/splitsse.py +9 -4
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/push/sse.py +51 -13
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/storage/pluggable.py +2 -5
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/storage/redis.py +2 -2
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/manager.py +7 -4
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/synchronizer.py +2 -2
- splitio_client-10.7.0/splitio/version.py +1 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio_client.egg-info/PKG-INFO +4 -4
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio_client.egg-info/SOURCES.txt +2 -2
- splitio_client-10.6.0/splitio/version.py +0 -1
- {splitio_client-10.6.0 → splitio_client-10.7.0}/README.md +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/setup.cfg +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/setup.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/auth.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/commons.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/events.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/impressions.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/segments.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/api/telemetry.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/client.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/input_validator.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/key.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/listener.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/localhost.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/manager.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/client/util.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/cache/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/cache/lru.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/filters.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/hashfns/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/hashfns/legacy.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/hashfns/murmur3py.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/impressions/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/impressions/impressions.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/impressions/manager.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/impressions/strategies.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/impressions/unique_keys_tracker.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/splitters.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/engine/telemetry.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/events/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/events/events_manager.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/events/events_metadata.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/events/events_task.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/exceptions.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/factories.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/impressions.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/key.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/datatypes.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/fallback_config.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/fallback_treatment.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/condition.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/base.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/keys.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/misc.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/numeric.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/prerequisites.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/rule_based_segment.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/semver.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/sets.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/string.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/utils/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/matchers/utils/utils.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/grammar/partitions.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/impressions.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/notification.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/rule_based_segments.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/segments.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/splits.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/telemetry.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/models/token.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/optional/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/optional/loaders.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/push/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/push/parser.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/push/processor.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/push/status_tracker.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/push/workers.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/recorder/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/recorder/recorder.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/spec.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/storage/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/storage/adapters/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/storage/adapters/cache_trait.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/storage/adapters/redis.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/storage/adapters/util.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/storage/inmemmory.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/event.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/impression.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/segment.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/split.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/telemetry.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/unique_keys.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/sync/util.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/events_sync.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/impressions_sync.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/segment_sync.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/split_sync.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/telemetry_sync.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/unique_keys_sync.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/util/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/util/asynctask.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/tasks/util/workerpool.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/util/__init__.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/util/backoff.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/util/decorators.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/util/storage_helper.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/util/threadutil.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio/util/time.py +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio_client.egg-info/dependency_links.txt +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio_client.egg-info/requires.txt +0 -0
- {splitio_client-10.6.0 → splitio_client-10.7.0}/splitio_client.egg-info/top_level.txt +0 -0
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
2
3
|
Version 2.0, January 2004
|
|
3
4
|
http://www.apache.org/licenses/
|
|
5
|
+
|
|
4
6
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
5
8
|
1. Definitions.
|
|
9
|
+
|
|
6
10
|
"License" shall mean the terms and conditions for use, reproduction,
|
|
7
11
|
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
8
13
|
"Licensor" shall mean the copyright owner or entity authorized by
|
|
9
14
|
the copyright owner that is granting the License.
|
|
15
|
+
|
|
10
16
|
"Legal Entity" shall mean the union of the acting entity and all
|
|
11
17
|
other entities that control, are controlled by, or are under common
|
|
12
18
|
control with that entity. For the purposes of this definition,
|
|
@@ -14,19 +20,24 @@ Apache License
|
|
|
14
20
|
direction or management of such entity, whether by contract or
|
|
15
21
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
16
22
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
17
24
|
"You" (or "Your") shall mean an individual or Legal Entity
|
|
18
25
|
exercising permissions granted by this License.
|
|
26
|
+
|
|
19
27
|
"Source" form shall mean the preferred form for making modifications,
|
|
20
28
|
including but not limited to software source code, documentation
|
|
21
29
|
source, and configuration files.
|
|
30
|
+
|
|
22
31
|
"Object" form shall mean any form resulting from mechanical
|
|
23
32
|
transformation or translation of a Source form, including but
|
|
24
33
|
not limited to compiled object code, generated documentation,
|
|
25
34
|
and conversions to other media types.
|
|
35
|
+
|
|
26
36
|
"Work" shall mean the work of authorship, whether in Source or
|
|
27
37
|
Object form, made available under the License, as indicated by a
|
|
28
38
|
copyright notice that is included in or attached to the work
|
|
29
39
|
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
30
41
|
"Derivative Works" shall mean any work, whether in Source or Object
|
|
31
42
|
form, that is based on (or derived from) the Work and for which the
|
|
32
43
|
editorial revisions, annotations, elaborations, or other modifications
|
|
@@ -34,6 +45,7 @@ Apache License
|
|
|
34
45
|
of this License, Derivative Works shall not include works that remain
|
|
35
46
|
separable from, or merely link (or bind by name) to the interfaces of,
|
|
36
47
|
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
37
49
|
"Contribution" shall mean any work of authorship, including
|
|
38
50
|
the original version of the Work and any modifications or additions
|
|
39
51
|
to that Work or Derivative Works thereof, that is intentionally
|
|
@@ -47,15 +59,18 @@ Apache License
|
|
|
47
59
|
Licensor for the purpose of discussing and improving the Work, but
|
|
48
60
|
excluding communication that is conspicuously marked or otherwise
|
|
49
61
|
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
50
63
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
51
64
|
on behalf of whom a Contribution has been received by Licensor and
|
|
52
65
|
subsequently incorporated within the Work.
|
|
66
|
+
|
|
53
67
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
54
68
|
this License, each Contributor hereby grants to You a perpetual,
|
|
55
69
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
56
70
|
copyright license to reproduce, prepare Derivative Works of,
|
|
57
71
|
publicly display, publicly perform, sublicense, and distribute the
|
|
58
72
|
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
59
74
|
3. Grant of Patent License. Subject to the terms and conditions of
|
|
60
75
|
this License, each Contributor hereby grants to You a perpetual,
|
|
61
76
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
@@ -71,19 +86,24 @@ Apache License
|
|
|
71
86
|
or contributory patent infringement, then any patent licenses
|
|
72
87
|
granted to You under this License for that Work shall terminate
|
|
73
88
|
as of the date such litigation is filed.
|
|
89
|
+
|
|
74
90
|
4. Redistribution. You may reproduce and distribute copies of the
|
|
75
91
|
Work or Derivative Works thereof in any medium, with or without
|
|
76
92
|
modifications, and in Source or Object form, provided that You
|
|
77
93
|
meet the following conditions:
|
|
94
|
+
|
|
78
95
|
(a) You must give any other recipients of the Work or
|
|
79
96
|
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
80
98
|
(b) You must cause any modified files to carry prominent notices
|
|
81
99
|
stating that You changed the files; and
|
|
100
|
+
|
|
82
101
|
(c) You must retain, in the Source form of any Derivative Works
|
|
83
102
|
that You distribute, all copyright, patent, trademark, and
|
|
84
103
|
attribution notices from the Source form of the Work,
|
|
85
104
|
excluding those notices that do not pertain to any part of
|
|
86
105
|
the Derivative Works; and
|
|
106
|
+
|
|
87
107
|
(d) If the Work includes a "NOTICE" text file as part of its
|
|
88
108
|
distribution, then any Derivative Works that You distribute must
|
|
89
109
|
include a readable copy of the attribution notices contained
|
|
@@ -100,12 +120,14 @@ Apache License
|
|
|
100
120
|
or as an addendum to the NOTICE text from the Work, provided
|
|
101
121
|
that such additional attribution notices cannot be construed
|
|
102
122
|
as modifying the License.
|
|
123
|
+
|
|
103
124
|
You may add Your own copyright statement to Your modifications and
|
|
104
125
|
may provide additional or different license terms and conditions
|
|
105
126
|
for use, reproduction, or distribution of Your modifications, or
|
|
106
127
|
for any such Derivative Works as a whole, provided Your use,
|
|
107
128
|
reproduction, and distribution of the Work otherwise complies with
|
|
108
129
|
the conditions stated in this License.
|
|
130
|
+
|
|
109
131
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
110
132
|
any Contribution intentionally submitted for inclusion in the Work
|
|
111
133
|
by You to the Licensor shall be under the terms and conditions of
|
|
@@ -113,10 +135,12 @@ Apache License
|
|
|
113
135
|
Notwithstanding the above, nothing herein shall supersede or modify
|
|
114
136
|
the terms of any separate license agreement you may have executed
|
|
115
137
|
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
116
139
|
6. Trademarks. This License does not grant permission to use the trade
|
|
117
140
|
names, trademarks, service marks, or product names of the Licensor,
|
|
118
141
|
except as required for reasonable and customary use in describing the
|
|
119
142
|
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
120
144
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
121
145
|
agreed to in writing, Licensor provides the Work (and each
|
|
122
146
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
@@ -126,6 +150,7 @@ Apache License
|
|
|
126
150
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
127
151
|
appropriateness of using or redistributing the Work and assume any
|
|
128
152
|
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
129
154
|
8. Limitation of Liability. In no event and under no legal theory,
|
|
130
155
|
whether in tort (including negligence), contract, or otherwise,
|
|
131
156
|
unless required by applicable law (such as deliberate and grossly
|
|
@@ -137,6 +162,7 @@ Apache License
|
|
|
137
162
|
work stoppage, computer failure or malfunction, or any and all
|
|
138
163
|
other commercial damages or losses), even if such Contributor
|
|
139
164
|
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
140
166
|
9. Accepting Warranty or Additional Liability. While redistributing
|
|
141
167
|
the Work or Derivative Works thereof, You may choose to offer,
|
|
142
168
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
@@ -147,8 +173,11 @@ Apache License
|
|
|
147
173
|
defend, and hold each Contributor harmless for any liability
|
|
148
174
|
incurred by, or claims asserted against, such Contributor by reason
|
|
149
175
|
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
150
177
|
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
151
179
|
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
152
181
|
To apply the Apache License to your work, attach the following
|
|
153
182
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
154
183
|
replaced with your own identifying information. (Don't include
|
|
@@ -157,11 +186,15 @@ Apache License
|
|
|
157
186
|
file or class name and description of purpose be included on the
|
|
158
187
|
same "printed page" as the copyright notice for easier
|
|
159
188
|
identification within third-party archives.
|
|
189
|
+
|
|
160
190
|
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
161
192
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
162
193
|
you may not use this file except in compliance with the License.
|
|
163
194
|
You may obtain a copy of the License at
|
|
195
|
+
|
|
164
196
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
165
198
|
Unless required by applicable law or agreed to in writing, software
|
|
166
199
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
167
200
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
Harness Feature Management
|
|
1
|
+
Harness Feature Management Python SDK Copyright 2024-2026 Harness Inc.
|
|
2
2
|
|
|
3
3
|
This product includes software developed at Harness Inc. (https://harness.io/).
|
|
4
4
|
|
|
5
|
-
This product includes software originally developed by Split Software, Inc. (https://www.split.io/). Copyright
|
|
5
|
+
This product includes software originally developed by Split Software, Inc. (https://www.split.io/). Copyright 2016-2024 Split Software, Inc.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: splitio_client
|
|
3
|
-
Version: 10.
|
|
3
|
+
Version: 10.7.0
|
|
4
4
|
Summary: Split.io Python Client
|
|
5
5
|
Home-page: https://github.com/splitio/python-client
|
|
6
|
-
Download-URL: https://github.com/splitio/python-client/tarball/10.
|
|
6
|
+
Download-URL: https://github.com/splitio/python-client/tarball/10.7.0
|
|
7
7
|
Author: Patricio Echague, Sebastian Arrubia
|
|
8
8
|
Author-email: pato@split.io, sebastian@split.io
|
|
9
9
|
License: Apache License 2.0
|
|
@@ -20,8 +20,8 @@ Provides-Extra: uwsgi
|
|
|
20
20
|
Provides-Extra: cpphash
|
|
21
21
|
Provides-Extra: asyncio
|
|
22
22
|
Provides-Extra: kerberos
|
|
23
|
-
License-File: LICENSE
|
|
24
|
-
License-File: NOTICE
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
License-File: NOTICE
|
|
25
25
|
|
|
26
26
|
# Split Python SDK
|
|
27
27
|

|
|
@@ -92,7 +92,7 @@ class HTTPAdapterWithProxyKerberosAuth(requests.adapters.HTTPAdapter):
|
|
|
92
92
|
class HttpClientBase(object, metaclass=abc.ABCMeta):
|
|
93
93
|
"""HttpClient wrapper template."""
|
|
94
94
|
|
|
95
|
-
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
|
|
95
|
+
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None, proxies={}):
|
|
96
96
|
"""
|
|
97
97
|
Class constructor.
|
|
98
98
|
|
|
@@ -110,6 +110,7 @@ class HttpClientBase(object, metaclass=abc.ABCMeta):
|
|
|
110
110
|
_LOGGER.debug("Initializing httpclient")
|
|
111
111
|
self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
|
|
112
112
|
self._urls = _construct_urls(sdk_url, events_url, auth_url, telemetry_url)
|
|
113
|
+
self._proxies = proxies
|
|
113
114
|
|
|
114
115
|
@abc.abstractmethod
|
|
115
116
|
def get(self, server, path, apikey):
|
|
@@ -161,7 +162,7 @@ class HttpClientBase(object, metaclass=abc.ABCMeta):
|
|
|
161
162
|
class HttpClient(HttpClientBase):
|
|
162
163
|
"""HttpClient wrapper."""
|
|
163
164
|
|
|
164
|
-
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
|
|
165
|
+
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None, proxies={}):
|
|
165
166
|
"""
|
|
166
167
|
Class constructor.
|
|
167
168
|
|
|
@@ -176,8 +177,8 @@ class HttpClient(HttpClientBase):
|
|
|
176
177
|
:param telemetry_url: Optional alternative telemetry URL.
|
|
177
178
|
:type telemetry_url: str
|
|
178
179
|
"""
|
|
179
|
-
HttpClientBase.__init__(self, timeout, sdk_url, events_url, auth_url, telemetry_url)
|
|
180
|
-
|
|
180
|
+
HttpClientBase.__init__(self, timeout, sdk_url, events_url, auth_url, telemetry_url, proxies)
|
|
181
|
+
|
|
181
182
|
def get(self, server, path, sdk_key, query=None, extra_headers=None): # pylint: disable=too-many-arguments
|
|
182
183
|
"""
|
|
183
184
|
Issue a get request.
|
|
@@ -197,21 +198,24 @@ class HttpClient(HttpClientBase):
|
|
|
197
198
|
:rtype: HttpResponse
|
|
198
199
|
"""
|
|
199
200
|
start = get_current_epoch_time_ms()
|
|
201
|
+
if self._proxies.get('https'):
|
|
202
|
+
_LOGGER.debug("proxy %s", urllib.parse.urlsplit(self._proxies['https']).hostname)
|
|
200
203
|
try:
|
|
201
204
|
response = requests.get(
|
|
202
205
|
_build_url(server, path, self._urls),
|
|
203
206
|
params=query,
|
|
204
207
|
headers=self._get_headers(extra_headers, sdk_key),
|
|
205
|
-
timeout=self._timeout
|
|
208
|
+
timeout=self._timeout,
|
|
209
|
+
proxies=self._proxies
|
|
206
210
|
)
|
|
207
211
|
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
|
|
208
212
|
return HttpResponse(response.status_code, response.text, response.headers)
|
|
209
213
|
|
|
210
214
|
except requests.exceptions.ChunkedEncodingError as exc:
|
|
211
215
|
_LOGGER.error("IncompleteRead exception detected: %s", exc)
|
|
212
|
-
return HttpResponse(400, "", {})
|
|
213
|
-
|
|
214
|
-
except Exception as exc: # pylint: disable=broad-except
|
|
216
|
+
return HttpResponse(400, "", {})
|
|
217
|
+
|
|
218
|
+
except Exception as exc: # pylint: disable=broad-except
|
|
215
219
|
raise HttpClientException(_EXC_MSG.format(source='request')) from exc
|
|
216
220
|
|
|
217
221
|
def post(self, server, path, sdk_key, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
|
|
@@ -242,6 +246,7 @@ class HttpClient(HttpClientBase):
|
|
|
242
246
|
params=query,
|
|
243
247
|
headers=self._get_headers(extra_headers, sdk_key),
|
|
244
248
|
timeout=self._timeout,
|
|
249
|
+
proxies=self._proxies
|
|
245
250
|
)
|
|
246
251
|
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
|
|
247
252
|
return HttpResponse(response.status_code, response.text, response.headers)
|
|
@@ -251,7 +256,7 @@ class HttpClient(HttpClientBase):
|
|
|
251
256
|
class HttpClientAsync(HttpClientBase):
|
|
252
257
|
"""HttpClientAsync wrapper."""
|
|
253
258
|
|
|
254
|
-
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
|
|
259
|
+
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None, proxies={}):
|
|
255
260
|
"""
|
|
256
261
|
Class constructor.
|
|
257
262
|
:param timeout: How many milliseconds to wait until the server responds.
|
|
@@ -265,8 +270,12 @@ class HttpClientAsync(HttpClientBase):
|
|
|
265
270
|
:param telemetry_url: Optional alternative telemetry URL.
|
|
266
271
|
:type telemetry_url: str
|
|
267
272
|
"""
|
|
268
|
-
HttpClientBase.__init__(self, timeout, sdk_url, events_url, auth_url, telemetry_url)
|
|
273
|
+
HttpClientBase.__init__(self, timeout, sdk_url, events_url, auth_url, telemetry_url, proxies)
|
|
269
274
|
self._session = aiohttp.ClientSession()
|
|
275
|
+
self._proxy = None
|
|
276
|
+
if len(self._proxies) > 0:
|
|
277
|
+
http_key = next(iter(self._proxies))
|
|
278
|
+
self._proxy = self._proxies[http_key]
|
|
270
279
|
|
|
271
280
|
async def get(self, server, path, apikey, query=None, extra_headers=None): # pylint: disable=too-many-arguments
|
|
272
281
|
"""
|
|
@@ -291,11 +300,13 @@ class HttpClientAsync(HttpClientBase):
|
|
|
291
300
|
_LOGGER.debug("GET request: %s", url)
|
|
292
301
|
_LOGGER.debug("query params: %s", query)
|
|
293
302
|
_LOGGER.debug("headers: %s", headers)
|
|
303
|
+
_LOGGER.debug("proxy: %s", urllib.parse.urlsplit(self._proxy).hostname)
|
|
294
304
|
async with self._session.get(
|
|
295
305
|
url,
|
|
296
306
|
params=query,
|
|
297
307
|
headers=headers,
|
|
298
|
-
timeout=self._timeout
|
|
308
|
+
timeout=self._timeout,
|
|
309
|
+
proxy=self._proxy
|
|
299
310
|
) as response:
|
|
300
311
|
body = await response.text()
|
|
301
312
|
_LOGGER.debug("Response:")
|
|
@@ -306,8 +317,8 @@ class HttpClientAsync(HttpClientBase):
|
|
|
306
317
|
|
|
307
318
|
except aiohttp.ClientPayloadError as exc:
|
|
308
319
|
_LOGGER.error("ContentLengthError exception detected: %s", exc)
|
|
309
|
-
return HttpResponse(400, "", {})
|
|
310
|
-
|
|
320
|
+
return HttpResponse(400, "", {})
|
|
321
|
+
|
|
311
322
|
except aiohttp.ClientError as exc: # pylint: disable=broad-except
|
|
312
323
|
raise HttpClientException(_EXC_MSG.format(source='aiohttp')) from exc
|
|
313
324
|
|
|
@@ -343,7 +354,8 @@ class HttpClientAsync(HttpClientBase):
|
|
|
343
354
|
params=query,
|
|
344
355
|
headers=headers,
|
|
345
356
|
json=body,
|
|
346
|
-
timeout=self._timeout
|
|
357
|
+
timeout=self._timeout,
|
|
358
|
+
proxy=self._proxy
|
|
347
359
|
) as response:
|
|
348
360
|
body = await response.text()
|
|
349
361
|
_LOGGER.debug("Response:")
|
|
@@ -104,24 +104,27 @@ class SplitsAPI(SplitsAPIBase): # pylint: disable=too-few-public-methods
|
|
|
104
104
|
if 200 <= response.status_code < 300:
|
|
105
105
|
if self._spec_version == _SPEC_1_1:
|
|
106
106
|
return util.convert_to_new_spec(json.loads(response.body))
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
self.clear_storage = self._last_proxy_check_timestamp != 0
|
|
109
109
|
self._last_proxy_check_timestamp = 0
|
|
110
|
-
|
|
110
|
+
parsed = json.loads(response.body)
|
|
111
|
+
if 'rbs' not in parsed:
|
|
112
|
+
parsed['rbs'] = {"d": [], "s": -1, "t": -1}
|
|
113
|
+
return parsed
|
|
111
114
|
|
|
112
115
|
else:
|
|
113
116
|
if response.status_code == 414:
|
|
114
117
|
_LOGGER.error('Error fetching feature flags; the amount of flag sets provided are too big, causing uri length error.')
|
|
115
|
-
|
|
118
|
+
|
|
116
119
|
if self._client.is_sdk_endpoint_overridden() and response.status_code == 400 and self._spec_version == SPEC_VERSION:
|
|
117
120
|
_LOGGER.warning('Detected proxy response error, changing spec version from %s to %s and re-fetching.', self._spec_version, _SPEC_1_1)
|
|
118
121
|
self._spec_version = _SPEC_1_1
|
|
119
|
-
self._last_proxy_check_timestamp = utctime_ms()
|
|
122
|
+
self._last_proxy_check_timestamp = utctime_ms()
|
|
120
123
|
return self.fetch_splits(change_number, None, FetchOptions(fetch_options.cache_control_headers, fetch_options.change_number,
|
|
121
124
|
None, fetch_options.sets, self._spec_version))
|
|
122
|
-
|
|
125
|
+
|
|
123
126
|
raise APIException(response.body, response.status_code)
|
|
124
|
-
|
|
127
|
+
|
|
125
128
|
except HttpClientException as exc:
|
|
126
129
|
_LOGGER.error('Error fetching feature flags because an exception was raised by the HTTPClient')
|
|
127
130
|
_LOGGER.debug('Error: ', exc_info=True)
|
|
@@ -178,24 +181,27 @@ class SplitsAPIAsync(SplitsAPIBase): # pylint: disable=too-few-public-methods
|
|
|
178
181
|
if 200 <= response.status_code < 300:
|
|
179
182
|
if self._spec_version == _SPEC_1_1:
|
|
180
183
|
return util.convert_to_new_spec(json.loads(response.body))
|
|
181
|
-
|
|
184
|
+
|
|
182
185
|
self.clear_storage = self._last_proxy_check_timestamp != 0
|
|
183
186
|
self._last_proxy_check_timestamp = 0
|
|
184
|
-
|
|
187
|
+
parsed = json.loads(response.body)
|
|
188
|
+
if 'rbs' not in parsed:
|
|
189
|
+
parsed['rbs'] = {"d": [], "s": -1, "t": -1}
|
|
190
|
+
return parsed
|
|
185
191
|
|
|
186
192
|
else:
|
|
187
193
|
if response.status_code == 414:
|
|
188
194
|
_LOGGER.error('Error fetching feature flags; the amount of flag sets provided are too big, causing uri length error.')
|
|
189
|
-
|
|
195
|
+
|
|
190
196
|
if self._client.is_sdk_endpoint_overridden() and response.status_code == 400 and self._spec_version == SPEC_VERSION:
|
|
191
197
|
_LOGGER.warning('Detected proxy response error, changing spec version from %s to %s and re-fetching.', self._spec_version, _SPEC_1_1)
|
|
192
198
|
self._spec_version = _SPEC_1_1
|
|
193
|
-
self._last_proxy_check_timestamp = utctime_ms()
|
|
199
|
+
self._last_proxy_check_timestamp = utctime_ms()
|
|
194
200
|
return await self.fetch_splits(change_number, None, FetchOptions(fetch_options.cache_control_headers, fetch_options.change_number,
|
|
195
201
|
None, fetch_options.sets, self._spec_version))
|
|
196
202
|
|
|
197
203
|
raise APIException(response.body, response.status_code)
|
|
198
|
-
|
|
204
|
+
|
|
199
205
|
except HttpClientException as exc:
|
|
200
206
|
_LOGGER.error('Error fetching feature flags because an exception was raised by the HTTPClient')
|
|
201
207
|
_LOGGER.debug('Error: ', exc_info=True)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import os.path
|
|
3
3
|
import logging
|
|
4
4
|
from enum import Enum
|
|
5
|
+
from urllib.parse import urlsplit
|
|
5
6
|
|
|
6
7
|
from splitio.engine.impressions import ImpressionsMode
|
|
7
8
|
from splitio.client.input_validator import validate_flag_sets, validate_fallback_treatment, validate_regex_name
|
|
@@ -71,7 +72,8 @@ DEFAULT_CONFIG = {
|
|
|
71
72
|
'httpAuthenticateScheme': AuthenticateScheme.NONE,
|
|
72
73
|
'kerberosPrincipalUser': None,
|
|
73
74
|
'kerberosPrincipalPassword': None,
|
|
74
|
-
'fallbackTreatments': FallbackTreatmentsConfiguration(None)
|
|
75
|
+
'fallbackTreatments': FallbackTreatmentsConfiguration(None),
|
|
76
|
+
'proxyUrl': None,
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
def _parse_operation_mode(sdk_key, config):
|
|
@@ -170,38 +172,65 @@ def sanitize(sdk_key, config):
|
|
|
170
172
|
' Defaulting to `none` mode.')
|
|
171
173
|
processed["httpAuthenticateScheme"] = authenticate_scheme
|
|
172
174
|
|
|
173
|
-
processed = _sanitize_fallback_config(config, processed)
|
|
174
|
-
|
|
175
|
+
processed = _sanitize_fallback_config(config, processed)
|
|
176
|
+
|
|
175
177
|
if config.get("redisErrors") is not None:
|
|
176
178
|
_LOGGER.warning('Parameter `redisErrors` is deprecated as it is no longer supported in redis lib.' \
|
|
177
179
|
' Will ignore this value.')
|
|
178
|
-
|
|
179
180
|
processed["redisErrors"] = None
|
|
181
|
+
|
|
182
|
+
processed = _sanitize_proxy(config, processed)
|
|
183
|
+
|
|
180
184
|
return processed
|
|
181
185
|
|
|
186
|
+
def _sanitize_proxy(config, processed):
|
|
187
|
+
if config.get("proxyUrl") is None:
|
|
188
|
+
return processed
|
|
189
|
+
|
|
190
|
+
if not isinstance(config.get("proxyUrl"), str):
|
|
191
|
+
_LOGGER.warning('Config: proxyUrl parameter must be of type str.')
|
|
192
|
+
processed["proxyUrl"] = None
|
|
193
|
+
return processed
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
parsed = urlsplit(config.get("proxyUrl"))
|
|
197
|
+
if parsed.hostname is None:
|
|
198
|
+
_LOGGER.warning('Config: could not parse hostname from proxyUrl parameter.')
|
|
199
|
+
processed["proxyUrl"] = None
|
|
200
|
+
return processed
|
|
201
|
+
|
|
202
|
+
if parsed.port is not None:
|
|
203
|
+
p = int(parsed.port)
|
|
204
|
+
except Exception:
|
|
205
|
+
_LOGGER.warning('Config: proxy hostname should be a valid hostname and proxy port should be of int type.')
|
|
206
|
+
processed["proxyUrl"] = None
|
|
207
|
+
return processed
|
|
208
|
+
|
|
209
|
+
return processed
|
|
210
|
+
|
|
182
211
|
def _sanitize_fallback_config(config, processed):
|
|
183
212
|
if config.get('fallbackTreatments') is None:
|
|
184
213
|
return processed
|
|
185
|
-
|
|
214
|
+
|
|
186
215
|
if not isinstance(config['fallbackTreatments'], FallbackTreatmentsConfiguration):
|
|
187
216
|
_LOGGER.warning('Config: fallbackTreatments parameter should be of `FallbackTreatmentsConfiguration` class.')
|
|
188
217
|
processed['fallbackTreatments'] = None
|
|
189
|
-
return processed
|
|
190
|
-
|
|
218
|
+
return processed
|
|
219
|
+
|
|
191
220
|
sanitized_global_fallback_treatment = config['fallbackTreatments'].global_fallback_treatment
|
|
192
221
|
if config['fallbackTreatments'].global_fallback_treatment is not None and not validate_fallback_treatment(config['fallbackTreatments'].global_fallback_treatment):
|
|
193
222
|
_LOGGER.warning('Config: global fallbacktreatment parameter is discarded.')
|
|
194
223
|
sanitized_global_fallback_treatment = None
|
|
195
|
-
|
|
224
|
+
|
|
196
225
|
sanitized_flag_fallback_treatments = {}
|
|
197
226
|
if config['fallbackTreatments'].by_flag_fallback_treatment is not None:
|
|
198
227
|
for feature_name in config['fallbackTreatments'].by_flag_fallback_treatment.keys():
|
|
199
228
|
if not validate_regex_name(feature_name) or not validate_fallback_treatment(config['fallbackTreatments'].by_flag_fallback_treatment[feature_name]):
|
|
200
229
|
_LOGGER.warning('Config: fallback treatment parameter for feature flag %s is discarded.', feature_name)
|
|
201
230
|
continue
|
|
202
|
-
|
|
231
|
+
|
|
203
232
|
sanitized_flag_fallback_treatments[feature_name] = config['fallbackTreatments'].by_flag_fallback_treatment[feature_name]
|
|
204
233
|
|
|
205
234
|
processed['fallbackTreatments'] = FallbackTreatmentsConfiguration(sanitized_global_fallback_treatment, sanitized_flag_fallback_treatments)
|
|
206
235
|
|
|
207
|
-
return processed
|
|
236
|
+
return processed
|
|
@@ -3,6 +3,7 @@ import logging
|
|
|
3
3
|
import threading
|
|
4
4
|
from collections import Counter
|
|
5
5
|
from enum import Enum
|
|
6
|
+
from urllib.parse import urlparse
|
|
6
7
|
import queue
|
|
7
8
|
|
|
8
9
|
from splitio.optional.loaders import asyncio
|
|
@@ -284,7 +285,6 @@ class SplitFactory(SplitFactoryBase): # pylint: disable=too-many-instance-attri
|
|
|
284
285
|
|
|
285
286
|
if not ready:
|
|
286
287
|
self._telemetry_init_producer.record_bur_time_out()
|
|
287
|
-
self._internal_events_queue.put(SdkInternalEventNotification(SdkInternalEvent.SDK_TIMED_OUT, None))
|
|
288
288
|
raise TimeoutException('SDK Initialization: time of %d exceeded' % timeout)
|
|
289
289
|
|
|
290
290
|
def destroy(self, destroyed_event=None):
|
|
@@ -439,7 +439,6 @@ class SplitFactoryAsync(SplitFactoryBase): # pylint: disable=too-many-instance-
|
|
|
439
439
|
_LOGGER.error("Exception initializing SDK")
|
|
440
440
|
_LOGGER.debug(str(e))
|
|
441
441
|
await self._telemetry_init_producer.record_bur_time_out()
|
|
442
|
-
await self._internal_events_queue.put(SdkInternalEventNotification(SdkInternalEvent.SDK_TIMED_OUT, None))
|
|
443
442
|
raise TimeoutException('SDK Initialization: time of %d exceeded' % timeout)
|
|
444
443
|
|
|
445
444
|
async def destroy(self, destroyed_event=None):
|
|
@@ -552,12 +551,18 @@ def _build_in_memory_factory(api_key, cfg, sdk_url=None, events_url=None, # pyl
|
|
|
552
551
|
authentication_params = authentication_params
|
|
553
552
|
)
|
|
554
553
|
else:
|
|
554
|
+
proxies = {}
|
|
555
|
+
if cfg.get('proxyUrl'):
|
|
556
|
+
proxies['https'] = cfg.get("proxyUrl")
|
|
557
|
+
proxies['http'] = cfg.get("proxyUrl")
|
|
558
|
+
|
|
555
559
|
http_client = HttpClient(
|
|
556
560
|
sdk_url=sdk_url,
|
|
557
561
|
events_url=events_url,
|
|
558
562
|
auth_url=auth_api_base_url,
|
|
559
563
|
telemetry_url=telemetry_api_base_url,
|
|
560
564
|
timeout=cfg.get('connectionTimeout'),
|
|
565
|
+
proxies=proxies
|
|
561
566
|
)
|
|
562
567
|
|
|
563
568
|
sdk_metadata = util.get_metadata(cfg)
|
|
@@ -631,7 +636,7 @@ def _build_in_memory_factory(api_key, cfg, sdk_url=None, events_url=None, # pyl
|
|
|
631
636
|
|
|
632
637
|
sdk_ready_flag = threading.Event() if not preforked_initialization else None
|
|
633
638
|
manager = Manager(sdk_ready_flag, synchronizer, apis['auth'], cfg['streamingEnabled'],
|
|
634
|
-
sdk_metadata, telemetry_runtime_producer, streaming_api_base_url, api_key[-4:])
|
|
639
|
+
sdk_metadata, telemetry_runtime_producer, streaming_api_base_url, api_key[-4:], cfg.get('proxyUrl'))
|
|
635
640
|
|
|
636
641
|
storages['events'].set_queue_full_hook(tasks.events_task.flush)
|
|
637
642
|
storages['impressions'].set_queue_full_hook(tasks.impressions_task.flush)
|
|
@@ -686,13 +691,17 @@ async def _build_in_memory_factory_async(api_key, cfg, sdk_url=None, events_url=
|
|
|
686
691
|
telemetry_runtime_producer = telemetry_producer.get_telemetry_runtime_producer()
|
|
687
692
|
telemetry_evaluation_producer = telemetry_producer.get_telemetry_evaluation_producer()
|
|
688
693
|
telemetry_init_producer = telemetry_producer.get_telemetry_init_producer()
|
|
694
|
+
proxies = {}
|
|
695
|
+
if cfg.get('proxyUrl'):
|
|
696
|
+
proxies['https'] = cfg.get('proxyUrl')
|
|
689
697
|
|
|
690
698
|
http_client = HttpClientAsync(
|
|
691
699
|
sdk_url=sdk_url,
|
|
692
700
|
events_url=events_url,
|
|
693
701
|
auth_url=auth_api_base_url,
|
|
694
702
|
telemetry_url=telemetry_api_base_url,
|
|
695
|
-
timeout=cfg.get('connectionTimeout')
|
|
703
|
+
timeout=cfg.get('connectionTimeout'),
|
|
704
|
+
proxies=proxies
|
|
696
705
|
)
|
|
697
706
|
|
|
698
707
|
sdk_metadata = util.get_metadata(cfg)
|
|
@@ -763,7 +772,7 @@ async def _build_in_memory_factory_async(api_key, cfg, sdk_url=None, events_url=
|
|
|
763
772
|
synchronizer = SynchronizerAsync(synchronizers, tasks)
|
|
764
773
|
|
|
765
774
|
manager = ManagerAsync(synchronizer, apis['auth'], cfg['streamingEnabled'],
|
|
766
|
-
sdk_metadata, telemetry_runtime_producer, streaming_api_base_url, api_key[-4:])
|
|
775
|
+
sdk_metadata, telemetry_runtime_producer, streaming_api_base_url, api_key[-4:], proxy=proxies.get('https'))
|
|
767
776
|
|
|
768
777
|
storages['events'].set_queue_full_hook(tasks.events_task.flush)
|
|
769
778
|
storages['impressions'].set_queue_full_hook(tasks.impressions_task.flush)
|
|
@@ -1413,4 +1422,4 @@ def _get_total_and_invalid_flag_sets(config_raw):
|
|
|
1413
1422
|
total_flag_sets = len(config_raw.get('flagSetsFilter'))
|
|
1414
1423
|
invalid_flag_sets = total_flag_sets - len(input_validator.validate_flag_sets(config_raw.get('flagSetsFilter'), 'Telemetry Init'))
|
|
1415
1424
|
|
|
1416
|
-
return total_flag_sets, invalid_flag_sets
|
|
1425
|
+
return total_flag_sets, invalid_flag_sets
|
|
@@ -64,7 +64,13 @@ class Evaluator(object): # pylint: disable=too-few-public-methods
|
|
|
64
64
|
else:
|
|
65
65
|
label, _treatment = self._check_prerequisites(feature, bucketing, key, attrs, ctx, label, _treatment)
|
|
66
66
|
label, _treatment = self._get_treatment(feature, bucketing, key, attrs, ctx, label, _treatment)
|
|
67
|
-
|
|
67
|
+
if _treatment == CONTROL:
|
|
68
|
+
fallback_treatment = self._fallback_treatment_calculator.resolve(feature_name, label)
|
|
69
|
+
label = fallback_treatment.label
|
|
70
|
+
_treatment = fallback_treatment.treatment
|
|
71
|
+
config = fallback_treatment.config
|
|
72
|
+
else:
|
|
73
|
+
config = feature.get_configurations_for(_treatment)
|
|
68
74
|
|
|
69
75
|
return {
|
|
70
76
|
'treatment': _treatment,
|
|
@@ -125,7 +125,7 @@ class RedisSenderAdapter(ImpressionsSenderAdapter):
|
|
|
125
125
|
|
|
126
126
|
except RedisAdapterException:
|
|
127
127
|
_LOGGER.error('Something went wrong when trying to add mtks to redis')
|
|
128
|
-
_LOGGER.
|
|
128
|
+
_LOGGER.debug('Error: ', exc_info=True)
|
|
129
129
|
return False
|
|
130
130
|
|
|
131
131
|
def flush_counters(self, to_send):
|
|
@@ -152,7 +152,7 @@ class RedisSenderAdapter(ImpressionsSenderAdapter):
|
|
|
152
152
|
|
|
153
153
|
except RedisAdapterException:
|
|
154
154
|
_LOGGER.error('Something went wrong when trying to add counters to redis')
|
|
155
|
-
_LOGGER.
|
|
155
|
+
_LOGGER.debug('Error: ', exc_info=True)
|
|
156
156
|
return False
|
|
157
157
|
|
|
158
158
|
def _expire_keys(self, queue_key, key_default_ttl, total_keys, inserted):
|
|
@@ -198,7 +198,7 @@ class RedisSenderAdapterAsync(ImpressionsSenderAdapter):
|
|
|
198
198
|
|
|
199
199
|
except RedisAdapterException:
|
|
200
200
|
_LOGGER.error('Something went wrong when trying to add mtks to redis')
|
|
201
|
-
_LOGGER.
|
|
201
|
+
_LOGGER.debug('Error: ', exc_info=True)
|
|
202
202
|
return False
|
|
203
203
|
|
|
204
204
|
async def flush_counters(self, to_send):
|
|
@@ -225,7 +225,7 @@ class RedisSenderAdapterAsync(ImpressionsSenderAdapter):
|
|
|
225
225
|
|
|
226
226
|
except RedisAdapterException:
|
|
227
227
|
_LOGGER.error('Something went wrong when trying to add counters to redis')
|
|
228
|
-
_LOGGER.
|
|
228
|
+
_LOGGER.debug('Error: ', exc_info=True)
|
|
229
229
|
return False
|
|
230
230
|
|
|
231
231
|
async def _expire_keys(self, queue_key, key_default_ttl, total_keys, inserted):
|
|
@@ -274,7 +274,7 @@ class PluggableSenderAdapter(ImpressionsSenderAdapter):
|
|
|
274
274
|
|
|
275
275
|
except RedisAdapterException:
|
|
276
276
|
_LOGGER.error('Something went wrong when trying to add mtks to storage adapter')
|
|
277
|
-
_LOGGER.
|
|
277
|
+
_LOGGER.debug('Error: ', exc_info=True)
|
|
278
278
|
return False
|
|
279
279
|
|
|
280
280
|
def flush_counters(self, to_send):
|
|
@@ -297,7 +297,7 @@ class PluggableSenderAdapter(ImpressionsSenderAdapter):
|
|
|
297
297
|
|
|
298
298
|
except RedisAdapterException:
|
|
299
299
|
_LOGGER.error('Something went wrong when trying to add counters to storage adapter')
|
|
300
|
-
_LOGGER.
|
|
300
|
+
_LOGGER.debug('Error: ', exc_info=True)
|
|
301
301
|
return False
|
|
302
302
|
|
|
303
303
|
def _expire_keys(self, queue_key, key_default_ttl, total_keys, inserted):
|
|
@@ -346,7 +346,7 @@ class PluggableSenderAdapterAsync(ImpressionsSenderAdapter):
|
|
|
346
346
|
|
|
347
347
|
except RedisAdapterException:
|
|
348
348
|
_LOGGER.error('Something went wrong when trying to add mtks to storage adapter')
|
|
349
|
-
_LOGGER.
|
|
349
|
+
_LOGGER.debug('Error: ', exc_info=True)
|
|
350
350
|
return False
|
|
351
351
|
|
|
352
352
|
async def flush_counters(self, to_send):
|
|
@@ -369,7 +369,7 @@ class PluggableSenderAdapterAsync(ImpressionsSenderAdapter):
|
|
|
369
369
|
|
|
370
370
|
except RedisAdapterException:
|
|
371
371
|
_LOGGER.error('Something went wrong when trying to add counters to storage adapter')
|
|
372
|
-
_LOGGER.
|
|
372
|
+
_LOGGER.debug('Error: ', exc_info=True)
|
|
373
373
|
return False
|
|
374
374
|
|
|
375
375
|
async def _expire_keys(self, queue_key, key_default_ttl, total_keys, inserted):
|