Skip to content

in-memory provider cannot update its flag set or emit PROVIDER_CONFIGURATION_CHANGED #620

Description

@aepfli

Summary

openfeature.provider.in_memory_provider.InMemoryProvider has no way to update its flag set. Appendix A requires one:

The provider must support a means of updating the flag set, resulting in the emission of PROVIDER_CONFIGURATION_CHANGED events.

  • The change event should consider all flags changed; a union of all previous and all new flag keys should be supplied in the flags changed field.

The provider copies the mapping in its constructor and exposes nothing to change it afterwards:

class InMemoryProvider(AbstractProvider):
    _flags: FlagStorage

    def __init__(self, flags: FlagStorage) -> None:
        self._flags = flags.copy()

Because it is a copy, a caller cannot even mutate the dict it passed in as a workaround.

What makes this a small fix

Unlike some SDKs, only half the machinery is missing. AbstractProvider already supplies emit_provider_configuration_changed, and the registry already calls attach() to wire the emitter up. All that is absent is a method that swaps the mapping and emits.

Comparison with the other SDKs

SDK update method emits PROVIDER_CONFIGURATION_CHANGED
JavaScript putConfiguration() yes
Java updateFlag() yes
Python none no
Go none no — go-sdk#530

Why it matters beyond the missing method

Appendix A also says:

E2E tests must utilize in-memory provider defined within the SDK and must be self-contained.

So the gap propagates: the SDK's own Appendix B suite cannot cover configuration-change events, because the provider it is required to use cannot produce one. Any consumer wanting to test their own reaction to PROVIDER_CONFIGURATION_CHANGED has to write their own provider.

Suggested shape

def update_flags(self, flags: FlagStorage) -> None:
    changed = sorted(set(self._flags) | set(flags))
    self._flags = dict(flags)
    self.emit_provider_configuration_changed(
        ProviderEventDetails(flags_changed=changed)
    )

A working implementation is ControllableInMemoryProvider in the linked PR. It subclasses this provider rather than replacing it — every resolution decision is still the SDK's — so it should port over as a method with no behaviour change. Happy to open a PR here instead if that shape looks right.

How it surfaced

Building the Python implementation of the cross-language provider conformance suite (spec#417). The suite's in-memory self-test has to leave the @configuration-change capability undeclared and report the scenario as skipped.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions