open-feature / open-feature/python-sdk

Is InMemoryFlag.state intended to be honoured? DISABLED is never read

Open
#627 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

question
Dominant language
Python
Stars
111
Forks
44
Avg merge
2h 37m
Merged PRs (30d)
14

Description

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

  1. Is state intended to be honoured by resolve(), or is it carried for configuration compatibility only?
  2. If it should be honoured — is the intended behaviour the caller's default with reason: DISABLED and no error code, matching JavaScript and Java?
  3. 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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in openfeature/provider/in_memory_provider.py at InMemoryFlag.state and resolve(), then compare the documented cross-language disabled-flag behavior described in the issue. Confirm whether Python should honor DISABLED or retain the field for compatibility only. Done means the intended behavior is decided and recorded, with the relevant in-memory provider behavior or tests updated if maintainers choose a change.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.