InMemoryFlag declares a state field with an ENABLED/DISABLED enum, and as far as I can tell nothing ever reads it. Asking because "the field is there for API compatibility and honouring it was never promised" is a perfectly good answer, and I would rather have it recorded than assume a bug.
What I see
openfeature/provider/in_memory_provider.py:
class InMemoryFlag(typing.Generic[T_co]):
class State(StrEnum):
ENABLED = "ENABLED"
DISABLED = "DISABLED"
default_variant: str
variants: dict[str, T_co]
flag_metadata: FlagMetadata = field(default_factory=dict)
state: State = State.ENABLED # line 47
...
def resolve(self, evaluation_context):
if self.context_evaluator:
return self.context_evaluator(self, evaluation_context or EvaluationContext())
return FlagResolutionDetails(
value=self.variants[self.default_variant],
reason=Reason.STATIC,
variant=self.default_variant,
flag_metadata=self.flag_metadata,
)
grep -n state in_memory_provider.py returns exactly one line — the declaration above. State.DISABLED does not appear anywhere else in the package.
So a flag constructed with state=State.DISABLED resolves to its own defaultVariant with reason STATIC, as though it were enabled.
Why I think it may be worth changing
For comparison, across the other in-memory reference providers:
| SDK |
field |
behaviour on a disabled flag |
| JavaScript |
disabled: boolean |
caller's default, reason: DISABLED, no error code |
| Java |
disabled (isDisabled) |
caller's default, reason: DISABLED, no error code |
| Go |
State enum |
caller's default + reason: DISABLED, but also a GENERAL error — reported as go-sdk#552, fixed by #574 |
| Python |
state enum |
resolves as if enabled |
Two of the four substitute the caller's default with reason: DISABLED and no error; Go agreed that was the right answer when it was raised. That is convention rather than specification — I could find no numbered requirement saying what a provider owes a disabled flag — so this is not a conformance claim, just a consistency observation.
Also worth noting the two shapes in the ecosystem: state: ENABLED|DISABLED in Go, Python and flagd's flag format, versus disabled: boolean in JavaScript, Java and Appendix B's test-flags.json. Not something to fix here, but it is why the field probably exists in this shape.
Questions
- Is
state intended to be honoured by resolve(), or is it carried for configuration compatibility only?
- If it should be honoured — is the intended behaviour the caller's default with
reason: DISABLED and no error code, matching JavaScript and Java?
- Would you rather the field were removed than implemented, if honouring it is not wanted? A declared field that is never read seems the more surprising of the two states.
Context
Found while building the cross-language provider conformance suite proposed in open-feature/spec#417. A new gated @disabled-flags capability is left undeclared for the Python in-memory suites on the strength of this, and the four scenarios skip rather than fail — so nothing is blocked. Recording the question so the reason for that gate is not just in my head.
InMemoryFlagdeclares astatefield with anENABLED/DISABLEDenum, and as far as I can tell nothing ever reads it. Asking because "the field is there for API compatibility and honouring it was never promised" is a perfectly good answer, and I would rather have it recorded than assume a bug.What I see
openfeature/provider/in_memory_provider.py:grep -n state in_memory_provider.pyreturns exactly one line — the declaration above.State.DISABLEDdoes not appear anywhere else in the package.So a flag constructed with
state=State.DISABLEDresolves to its owndefaultVariantwith reasonSTATIC, as though it were enabled.Why I think it may be worth changing
For comparison, across the other in-memory reference providers:
disabled: booleanreason: DISABLED, no error codedisabled(isDisabled)reason: DISABLED, no error codeStateenumreason: DISABLED, but also aGENERALerror — reported as go-sdk#552, fixed by #574stateenumTwo of the four substitute the caller's default with
reason: DISABLEDand no error; Go agreed that was the right answer when it was raised. That is convention rather than specification — I could find no numbered requirement saying what a provider owes a disabled flag — so this is not a conformance claim, just a consistency observation.Also worth noting the two shapes in the ecosystem:
state: ENABLED|DISABLEDin Go, Python and flagd's flag format, versusdisabled: booleanin JavaScript, Java and Appendix B'stest-flags.json. Not something to fix here, but it is why the field probably exists in this shape.Questions
stateintended to be honoured byresolve(), or is it carried for configuration compatibility only?reason: DISABLEDand no error code, matching JavaScript and Java?Context
Found while building the cross-language provider conformance suite proposed in open-feature/spec#417. A new gated
@disabled-flagscapability is left undeclared for the Python in-memory suites on the strength of this, and the four scenarios skip rather than fail — so nothing is blocked. Recording the question so the reason for that gate is not just in my head.