openfeature-provider-flagd 0.2.5__py3-none-any.whl → 0.2.6__py3-none-any.whl

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.
@@ -5,13 +5,13 @@ from openfeature.contrib.provider.flagd.resolvers.process.connector.file_watcher
5
5
  )
6
6
  from openfeature.evaluation_context import EvaluationContext
7
7
  from openfeature.event import ProviderEventDetails
8
- from openfeature.exception import FlagNotFoundError, ParseError
8
+ from openfeature.exception import ErrorCode, FlagNotFoundError, GeneralError, ParseError
9
9
  from openfeature.flag_evaluation import FlagResolutionDetails, Reason
10
10
 
11
11
  from ..config import Config
12
12
  from .process.connector import FlagStateConnector
13
13
  from .process.connector.grpc_watcher import GrpcWatcher
14
- from .process.flags import FlagStore
14
+ from .process.flags import Flag, FlagStore
15
15
  from .process.targeting import targeting
16
16
 
17
17
  T = typing.TypeVar("T")
@@ -128,26 +128,30 @@ class InProcessResolver:
128
128
  )
129
129
 
130
130
  if not flag.targeting:
131
- variant, value = flag.default
132
- return FlagResolutionDetails(
133
- value, variant=variant, flag_metadata=metadata, reason=Reason.STATIC
134
- )
131
+ return _default_resolve(flag, metadata, Reason.STATIC)
135
132
 
136
- variant = targeting(flag.key, flag.targeting, evaluation_context)
133
+ try:
134
+ variant = targeting(flag.key, flag.targeting, evaluation_context)
135
+ if variant is None:
136
+ return _default_resolve(flag, metadata, Reason.DEFAULT)
137
137
 
138
- if variant is None:
139
- variant, value = flag.default
140
- return FlagResolutionDetails(
141
- value, variant=variant, flag_metadata=metadata, reason=Reason.DEFAULT
142
- )
143
- if not isinstance(variant, (str, bool)):
144
- raise ParseError(
145
- "Parsed JSONLogic targeting did not return a string or bool"
146
- )
138
+ # convert to string to support shorthand (boolean in python is with capital T hence the special case)
139
+ if isinstance(variant, bool):
140
+ variant = str(variant).lower()
141
+ elif not isinstance(variant, str):
142
+ variant = str(variant)
143
+
144
+ if variant not in flag.variants:
145
+ raise GeneralError(
146
+ f"Resolved variant {variant} not in variants config."
147
+ )
148
+
149
+ except ReferenceError:
150
+ raise ParseError(f"Invalid targeting {targeting}") from ReferenceError
147
151
 
148
152
  variant, value = flag.get_variant(variant)
149
153
  if value is None:
150
- raise ParseError(f"Resolved variant {variant} not in variants config.")
154
+ raise GeneralError(f"Resolved variant {variant} not in variants config.")
151
155
 
152
156
  return FlagResolutionDetails(
153
157
  value,
@@ -155,3 +159,24 @@ class InProcessResolver:
155
159
  reason=Reason.TARGETING_MATCH,
156
160
  flag_metadata=metadata,
157
161
  )
162
+
163
+
164
+ def _default_resolve(
165
+ flag: Flag,
166
+ metadata: typing.Mapping[str, typing.Union[float, int, str, bool]],
167
+ reason: Reason,
168
+ ) -> FlagResolutionDetails:
169
+ variant, value = flag.default
170
+ if variant is None:
171
+ return FlagResolutionDetails(
172
+ value,
173
+ variant=variant,
174
+ reason=Reason.ERROR,
175
+ error_code=ErrorCode.FLAG_NOT_FOUND,
176
+ flag_metadata=metadata,
177
+ )
178
+ if variant not in flag.variants:
179
+ raise GeneralError(f"Resolved variant {variant} not in variants config.")
180
+ return FlagResolutionDetails(
181
+ value, variant=variant, flag_metadata=metadata, reason=reason
182
+ )
@@ -72,30 +72,22 @@ class Flag:
72
72
  key: str
73
73
  state: str
74
74
  variants: typing.Mapping[str, typing.Any]
75
- default_variant: typing.Union[bool, str]
75
+ default_variant: typing.Optional[typing.Union[bool, str]] = None
76
76
  targeting: typing.Optional[dict] = None
77
77
  metadata: typing.Optional[
78
78
  typing.Mapping[str, typing.Union[float, int, str, bool]]
79
79
  ] = None
80
80
 
81
81
  def __post_init__(self) -> None:
82
- if not self.state or not isinstance(self.state, str):
82
+ if not self.state or not (self.state == "ENABLED" or self.state == "DISABLED"):
83
83
  raise ParseError("Incorrect 'state' value provided in flag config")
84
84
 
85
85
  if not self.variants or not isinstance(self.variants, dict):
86
86
  raise ParseError("Incorrect 'variants' value provided in flag config")
87
87
 
88
- if not self.default_variant or not isinstance(
89
- self.default_variant, (str, bool)
90
- ):
88
+ if self.default_variant and not isinstance(self.default_variant, (str, bool)):
91
89
  raise ParseError("Incorrect 'defaultVariant' value provided in flag config")
92
90
 
93
- if self.targeting and not isinstance(self.targeting, dict):
94
- raise ParseError("Incorrect 'targeting' value provided in flag config")
95
-
96
- if self.default_variant not in self.variants:
97
- raise ParseError("Default variant does not match set of variants")
98
-
99
91
  if self.metadata:
100
92
  if not isinstance(self.metadata, dict):
101
93
  raise ParseError("Flag metadata is not a valid json object")
@@ -106,6 +98,8 @@ class Flag:
106
98
  def from_dict(cls, key: str, data: dict) -> "Flag":
107
99
  if "defaultVariant" in data:
108
100
  data["default_variant"] = data["defaultVariant"]
101
+ if data["default_variant"] == "":
102
+ data["default_variant"] = None
109
103
  del data["defaultVariant"]
110
104
 
111
105
  data.pop("source", None)
@@ -119,13 +113,16 @@ class Flag:
119
113
  raise ParseError from err
120
114
 
121
115
  @property
122
- def default(self) -> tuple[str, typing.Any]:
116
+ def default(self) -> tuple[typing.Optional[str], typing.Any]:
123
117
  return self.get_variant(self.default_variant)
124
118
 
125
119
  def get_variant(
126
- self, variant_key: typing.Union[str, bool]
127
- ) -> tuple[str, typing.Any]:
120
+ self, variant_key: typing.Union[str, bool, None]
121
+ ) -> tuple[typing.Optional[str], typing.Any]:
128
122
  if isinstance(variant_key, bool):
129
123
  variant_key = str(variant_key).lower()
130
124
 
125
+ if not variant_key:
126
+ return None, None
127
+
131
128
  return variant_key, self.variants.get(variant_key)
@@ -5,6 +5,7 @@ from json_logic import builtins, jsonLogic
5
5
  from json_logic.types import JsonValue
6
6
 
7
7
  from openfeature.evaluation_context import EvaluationContext
8
+ from openfeature.exception import ParseError
8
9
 
9
10
  from .custom_ops import (
10
11
  ends_with,
@@ -27,6 +28,9 @@ def targeting(
27
28
  targeting: dict,
28
29
  evaluation_context: typing.Optional[EvaluationContext] = None,
29
30
  ) -> JsonValue:
31
+ if not isinstance(targeting, dict):
32
+ raise ParseError(f"Invalid 'targeting' value in flag: {targeting}")
33
+
30
34
  json_logic_context = evaluation_context.attributes if evaluation_context else {}
31
35
  json_logic_context["$flagd"] = {"flagKey": key, "timestamp": int(time.time())}
32
36
  json_logic_context["targetingKey"] = (
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation.proto
5
- # Protobuf Python Version: 6.31.0
5
+ # Protobuf Python Version: 5.29.0
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -11,8 +11,8 @@ from google.protobuf import symbol_database as _symbol_database
11
11
  from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 31,
14
+ 5,
15
+ 29,
16
16
  0,
17
17
  '',
18
18
  'openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation.proto'
@@ -5,7 +5,7 @@ import warnings
5
5
 
6
6
  from openfeature.schemas.protobuf.flagd.evaluation.v1 import evaluation_pb2 as openfeature_dot_schemas_dot_protobuf_dot_flagd_dot_evaluation_dot_v1_dot_evaluation__pb2
7
7
 
8
- GRPC_GENERATED_VERSION = '1.73.1'
8
+ GRPC_GENERATED_VERSION = '1.71.2'
9
9
  GRPC_VERSION = grpc.__version__
10
10
  _version_not_supported = False
11
11
 
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: openfeature/schemas/protobuf/flagd/sync/v1/sync.proto
5
- # Protobuf Python Version: 6.31.0
5
+ # Protobuf Python Version: 5.29.0
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -11,8 +11,8 @@ from google.protobuf import symbol_database as _symbol_database
11
11
  from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 31,
14
+ 5,
15
+ 29,
16
16
  0,
17
17
  '',
18
18
  'openfeature/schemas/protobuf/flagd/sync/v1/sync.proto'
@@ -5,7 +5,7 @@ import warnings
5
5
 
6
6
  from openfeature.schemas.protobuf.flagd.sync.v1 import sync_pb2 as openfeature_dot_schemas_dot_protobuf_dot_flagd_dot_sync_dot_v1_dot_sync__pb2
7
7
 
8
- GRPC_GENERATED_VERSION = '1.73.1'
8
+ GRPC_GENERATED_VERSION = '1.71.2'
9
9
  GRPC_VERSION = grpc.__version__
10
10
  _version_not_supported = False
11
11
 
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: openfeature/schemas/protobuf/schema/v1/schema.proto
5
- # Protobuf Python Version: 6.31.0
5
+ # Protobuf Python Version: 5.29.0
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -11,8 +11,8 @@ from google.protobuf import symbol_database as _symbol_database
11
11
  from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 31,
14
+ 5,
15
+ 29,
16
16
  0,
17
17
  '',
18
18
  'openfeature/schemas/protobuf/schema/v1/schema.proto'
@@ -5,7 +5,7 @@ import warnings
5
5
 
6
6
  from openfeature.schemas.protobuf.schema.v1 import schema_pb2 as openfeature_dot_schemas_dot_protobuf_dot_schema_dot_v1_dot_schema__pb2
7
7
 
8
- GRPC_GENERATED_VERSION = '1.73.1'
8
+ GRPC_GENERATED_VERSION = '1.71.2'
9
9
  GRPC_VERSION = grpc.__version__
10
10
  _version_not_supported = False
11
11
 
@@ -2,7 +2,7 @@
2
2
  # Generated by the protocol buffer compiler. DO NOT EDIT!
3
3
  # NO CHECKED-IN PROTOBUF GENCODE
4
4
  # source: openfeature/schemas/protobuf/sync/v1/sync_service.proto
5
- # Protobuf Python Version: 6.31.0
5
+ # Protobuf Python Version: 5.29.0
6
6
  """Generated protocol buffer code."""
7
7
  from google.protobuf import descriptor as _descriptor
8
8
  from google.protobuf import descriptor_pool as _descriptor_pool
@@ -11,8 +11,8 @@ from google.protobuf import symbol_database as _symbol_database
11
11
  from google.protobuf.internal import builder as _builder
12
12
  _runtime_version.ValidateProtobufRuntimeVersion(
13
13
  _runtime_version.Domain.PUBLIC,
14
- 6,
15
- 31,
14
+ 5,
15
+ 29,
16
16
  0,
17
17
  '',
18
18
  'openfeature/schemas/protobuf/sync/v1/sync_service.proto'
@@ -5,7 +5,7 @@ import warnings
5
5
 
6
6
  from openfeature.schemas.protobuf.sync.v1 import sync_service_pb2 as openfeature_dot_schemas_dot_protobuf_dot_sync_dot_v1_dot_sync__service__pb2
7
7
 
8
- GRPC_GENERATED_VERSION = '1.73.1'
8
+ GRPC_GENERATED_VERSION = '1.71.2'
9
9
  GRPC_VERSION = grpc.__version__
10
10
  _version_not_supported = False
11
11
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openfeature-provider-flagd
3
- Version: 0.2.5
3
+ Version: 0.2.6
4
4
  Summary: OpenFeature provider for the flagd flag evaluation engine
5
5
  Project-URL: Homepage, https://github.com/open-feature/python-sdk-contrib
6
6
  Author-email: OpenFeature <openfeature-core@groups.io>
@@ -215,7 +215,7 @@ Requires-Dist: grpcio>=1.68.1
215
215
  Requires-Dist: mmh3>=4.1.0
216
216
  Requires-Dist: openfeature-sdk>=0.6.0
217
217
  Requires-Dist: panzi-json-logic>=1.0.1
218
- Requires-Dist: protobuf>=4.29.2
218
+ Requires-Dist: protobuf>=5.26.1
219
219
  Requires-Dist: pyyaml>=6.0.1
220
220
  Requires-Dist: semver<4,>=3
221
221
  Description-Content-Type: text/markdown
@@ -6,31 +6,31 @@ openfeature/contrib/provider/flagd/provider.py,sha256=qGLWvpYEfvf5RrvYb2vTvzc8CD
6
6
  openfeature/contrib/provider/flagd/sync_metadata_hook.py,sha256=fd3uRtwDhVlCW9vZhS35p9qENkl6wDHwlFH-L48aPDM,456
7
7
  openfeature/contrib/provider/flagd/resolvers/__init__.py,sha256=CzsnsfxJCaD_S1gBf15kkJBVD-gVLKIwDi4W1nE-dXw,181
8
8
  openfeature/contrib/provider/flagd/resolvers/grpc.py,sha256=dIRuCgHrqCwPzpXdfL1cEPss08-LwZcy_gIUe0xLeqY,15380
9
- openfeature/contrib/provider/flagd/resolvers/in_process.py,sha256=Oqj3Ak-zqjvWnlnsg5ElXXHn-YIPZRItbyfzakCd8O0,5433
9
+ openfeature/contrib/provider/flagd/resolvers/in_process.py,sha256=R3fy2AE4iLOzFv0KExH0chTIeZsMipXGLaxGN-nSvUU,6328
10
10
  openfeature/contrib/provider/flagd/resolvers/protocol.py,sha256=Wc7oUH6ytPuKg8Lj_3y-_LLkQkuvsow9IiSfmlM8I2o,1402
11
11
  openfeature/contrib/provider/flagd/resolvers/process/custom_ops.py,sha256=bZX1At0dRxhghhWz4g-8N-YPobcVfYSv9PTsYh-lZDc,4549
12
- openfeature/contrib/provider/flagd/resolvers/process/flags.py,sha256=znDHo84b4-vQswoHSo0807AvK84mqhiJjlC-_vMehdE,4759
13
- openfeature/contrib/provider/flagd/resolvers/process/targeting.py,sha256=qjYgfoJK9B1ghh19cUq7f-VEql7Hh1J7sh0BhnNc_h0,905
12
+ openfeature/contrib/provider/flagd/resolvers/process/flags.py,sha256=PPD99ebcRlZ08rbzqP6TY-433rW5xyMvmLTavSib2FU,4689
13
+ openfeature/contrib/provider/flagd/resolvers/process/targeting.py,sha256=DQdtBMzLCoNAwtV25fRonVlR3JjE4Fds7StckZ2LnFs,1067
14
14
  openfeature/contrib/provider/flagd/resolvers/process/connector/__init__.py,sha256=hyYYxRYEnSho5F28M2hbhhtkG4DQTwJjD36ddI0Xs7M,289
15
15
  openfeature/contrib/provider/flagd/resolvers/process/connector/file_watcher.py,sha256=abj6DhAyu2nP-P5EAHB9GyceJMym21rO8tKr8nQhmKM,4241
16
16
  openfeature/contrib/provider/flagd/resolvers/process/connector/grpc_watcher.py,sha256=wfcG2aks5Za0bptnNfEagQuuR7rEUwELG6uPqSApIsY,10622
17
- openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2.py,sha256=-K4_Kmx2JRgLAZG2jf5LqmDjY7ewrJKHGebqv3RqPwE,7527
17
+ openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2.py,sha256=YPBimdlVBCfnVqxq9uek3H4nyaIR0MhggCAaR0XtIt4,7527
18
18
  openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2.pyi,sha256=afh-fdsmyfS62C-iq7EQsqr_5yZP_QxJXp81Q0Lcllk,18333
19
- openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2_grpc.py,sha256=CMBqGsCqTVaAgKwJ8Ht7Or7PfjPQsVVoA-kg-5XjHNI,17189
19
+ openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2_grpc.py,sha256=1wiz2MWh4OuUCeqaC3ihMzvY_NXZmIDghihymLCb35A,17189
20
20
  openfeature/schemas/protobuf/flagd/evaluation/v1/evaluation_pb2_grpc.pyi,sha256=tQm-QOlsMdhdN_7i5LsrtLtBPu4qpL0qzTE7DbSvXFs,7731
21
- openfeature/schemas/protobuf/flagd/sync/v1/sync_pb2.py,sha256=m3-pL_dTFAGUzDVhOl-HjcfykIOqMP61spiq41W-UHU,3528
21
+ openfeature/schemas/protobuf/flagd/sync/v1/sync_pb2.py,sha256=OIhVrNkhXtwuCdvbahXiOx-mQ3XVVPx5gh0UHzKN0_M,3528
22
22
  openfeature/schemas/protobuf/flagd/sync/v1/sync_pb2.pyi,sha256=Qsqe0vz5AJRAAjARXhjiaPKyIFbLttr4gTWae2zyJfM,5967
23
- openfeature/schemas/protobuf/flagd/sync/v1/sync_pb2_grpc.py,sha256=sJEO2Qr_tohCDpg2_W5V6gtlpmOAgCcG4l0K0kGUIEM,8335
23
+ openfeature/schemas/protobuf/flagd/sync/v1/sync_pb2_grpc.py,sha256=llMjiiVc-lM7LgKo_qsOkHNZYviVAikGA7nA2qwKwgs,8335
24
24
  openfeature/schemas/protobuf/flagd/sync/v1/sync_pb2_grpc.pyi,sha256=APjDd-Yo6i6FE_kOusWhTqk-8B_0wIEMXcImCuGpQt8,3782
25
- openfeature/schemas/protobuf/schema/v1/schema_pb2.py,sha256=LIQjZ-jrzHULHYpFefuB0KRgtp0c9xwjXl0VDxrZsuY,7255
25
+ openfeature/schemas/protobuf/schema/v1/schema_pb2.py,sha256=dfGpiAYJ2VuRBrctH7s21KkdrIr9rzIaWibUZ3So3g4,7255
26
26
  openfeature/schemas/protobuf/schema/v1/schema_pb2.pyi,sha256=14Z6i0kRpCAQO8aCpc4Qwre1OJ7_d_ZIPq8V1vTuYzU,18369
27
- openfeature/schemas/protobuf/schema/v1/schema_pb2_grpc.py,sha256=81k5RwIA-FlPPu9lT3Q9xIbS12thbJx2f-M2akSX-Z8,16227
27
+ openfeature/schemas/protobuf/schema/v1/schema_pb2_grpc.py,sha256=2IPt3a8K4vczpNerePAJO8v7tlLWijgraXYnrzpULRE,16227
28
28
  openfeature/schemas/protobuf/schema/v1/schema_pb2_grpc.pyi,sha256=EJ55jvso2Uzx50XryC7fsKGEOBi1bMOGCXaShl1TcJ4,7067
29
- openfeature/schemas/protobuf/sync/v1/sync_service_pb2.py,sha256=pK8BPYQQmWihQYd-4jI84htTqmp6Jf7kk_w4MGG8Qgg,3327
29
+ openfeature/schemas/protobuf/sync/v1/sync_service_pb2.py,sha256=Sw0kLvO0wIRXsaFic8qmTuScMdf1-1WOHGWP4FOIB_s,3327
30
30
  openfeature/schemas/protobuf/sync/v1/sync_service_pb2.pyi,sha256=o3YpW_5iQJWjU7IFEsyspeqLyBDC4C_psBNErwziumE,7986
31
- openfeature/schemas/protobuf/sync/v1/sync_service_pb2_grpc.py,sha256=8eKM7pR4wMzDlD9vNVH5C4uYq6nbnJGozFAIjWawWGQ,6185
31
+ openfeature/schemas/protobuf/sync/v1/sync_service_pb2_grpc.py,sha256=gk-VooxRZ-GBWOWsDK1j985OVmdghW-4Wiuv-6YD_84,6185
32
32
  openfeature/schemas/protobuf/sync/v1/sync_service_pb2_grpc.pyi,sha256=4NoAkGicVNxx4yVK5_JvvPn1OGlRdPhqM2wCpkwCjEI,3024
33
- openfeature_provider_flagd-0.2.5.dist-info/METADATA,sha256=Xhd43YdbELLg_g94p-st3WC9S7ss9dnxTMtjJ9_5XAo,21635
34
- openfeature_provider_flagd-0.2.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
35
- openfeature_provider_flagd-0.2.5.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
36
- openfeature_provider_flagd-0.2.5.dist-info/RECORD,,
33
+ openfeature_provider_flagd-0.2.6.dist-info/METADATA,sha256=8KC1l9D9AhkkqQlDpEbmpE-wox9cq0j7O9tnB8Vb2b8,21635
34
+ openfeature_provider_flagd-0.2.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
35
+ openfeature_provider_flagd-0.2.6.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
36
+ openfeature_provider_flagd-0.2.6.dist-info/RECORD,,