Skip to content

feat: expose variation ID and data update status listeners#14

Open
WuJiayi0307 wants to merge 5 commits into
featbit:masterfrom
WuJiayi0307:feat/openfeature-provider
Open

feat: expose variation ID and data update status listeners#14
WuJiayi0307 wants to merge 5 commits into
featbit:masterfrom
WuJiayi0307:feat/openfeature-provider

Conversation

@WuJiayi0307

@WuJiayi0307 WuJiayi0307 commented Jul 22, 2026

Copy link
Copy Markdown

Summary

This PR now contains only the FeatBit Python SDK capabilities required by the standalone OpenFeature provider:

  • expose the stable variation ID as EvalDetail.variation_id
  • add thread-safe data-update status listeners through add_listener() / remove_listener()
  • preserve backward compatibility for existing EvalDetail construction, JSON output, and custom status-provider implementations
  • update the package version to 1.1.8

The OpenFeature provider implementation has been moved to the dedicated repository:
https://github.com/featbit/openfeature-provider-python-server

Status mapping support

The provider repository maps FeatBit SDK states as follows:

  • OK → OpenFeature READY
  • INTERRUPTEDSTALE
  • OFFFATAL
  • shutdown → NOT_READY

Validation

  • FeatBit SDK: 58 passed
  • Provider repository: 52 passed
  • Flake8: passed in both repositories
  • Wheel and source distributions: built successfully
  • Isolated install smoke test: OpenFeature Client → Provider → real FeatBit offline Evaluator returned v2, variant variation-v2, status READY

The SDK PR remains compatible with Python 3.6–3.12. The standalone provider requires Python 3.10+.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The SDK now exposes stable variation IDs in evaluation details and supports data-update status listeners. Packaging, README examples, release metadata, singleton declarations, and tests are updated accordingly.

SDK behavior and validation

Layer / File(s) Summary
Variation detail contract
fbclient/common_types.py, tests/test_fbclient.py
EvalDetail exposes optional variation IDs, successful evaluations populate them, and tests cover backward compatibility and result states.
Status listener runtime
fbclient/interfaces.py, fbclient/status.py, tests/test_data_update_status_provider.py
Status listeners can be registered and removed, receive state changes, and cannot block other listeners when exceptions occur.
Client accessor declarations
fbclient/__init__.py
Singleton accessors retain only the global declarations required for assignment.
Distribution and usage surfaces
MANIFEST.in, README.md, release/*
Source packaging, Python compatibility documentation, API examples, and release metadata are updated for version 1.1.8.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FBClient
  participant DataUpdateStatusProviderImpl
  participant StatusListener
  FBClient->>DataUpdateStatusProviderImpl: update_state(new State)
  DataUpdateStatusProviderImpl->>DataUpdateStatusProviderImpl: snapshot state and listeners
  DataUpdateStatusProviderImpl-->>StatusListener: invoke callback(State)
  StatusListener-->>DataUpdateStatusProviderImpl: callback completes or raises
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.48% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two main user-facing changes: exposing variation IDs and adding data update status listeners.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
tests/test_fbclient.py (1)

32-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Lock down the unchanged JSON contract.

This verifies constructor compatibility but not the stated backward-compatible JSON output. Assert that to_json_dict() remains unchanged even when variation_id is provided.

Proposed test addition
     assert detail_with_id.variation_id == "variation-id"
+    assert detail_with_id.to_json_dict() == legacy_detail.to_json_dict()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_fbclient.py` around lines 32 - 39, Extend
test_eval_detail_variation_id_is_backward_compatible to call to_json_dict() on
detail_with_id and assert its serialized dictionary remains identical to the
established legacy JSON contract, excluding variation_id. Keep the existing
constructor and variation_id assertions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@featbit_openfeature/provider.py`:
- Around line 84-94: Update shutdown so _flag_change_listener is cleared only
after _client.flag_tracker.remove_flag_change_notifier(listener) succeeds; if
removal raises, retain the listener reference so cleanup can be retried and
subsequent initialization cannot register a duplicate listener.

In `@README.md`:
- Line 21: Update the README installation sentence to say “Install the SDK using
pip” instead of “install the sdk in using pip,” while preserving the Python
compatibility statement.

In `@release/description.md`:
- Around line 4-6: Update the release-note section in description.md to use the
standard heading “Breaking changes” and the text “No breaking changes,” or
remove the empty section entirely.

---

Nitpick comments:
In `@tests/test_fbclient.py`:
- Around line 32-39: Extend test_eval_detail_variation_id_is_backward_compatible
to call to_json_dict() on detail_with_id and assert its serialized dictionary
remains identical to the established legacy JSON contract, excluding
variation_id. Keep the existing constructor and variation_id assertions
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 457f6a3b-e2e5-43ec-a493-af734f3ee36a

📥 Commits

Reviewing files that changed from the base of the PR and between 0ad40d8 and e09df9d.

📒 Files selected for processing (22)
  • .github/workflows/code-quality.yaml
  • MANIFEST.in
  • README.md
  • docs/openfeature.md
  • fbclient/__init__.py
  • fbclient/common_types.py
  • featbit_openfeature/__init__.py
  • featbit_openfeature/impl/__init__.py
  • featbit_openfeature/impl/context_converter.py
  • featbit_openfeature/impl/details_converter.py
  • featbit_openfeature/provider.py
  • featbit_openfeature/py.typed
  • release/description.md
  • release/package.json
  • setup.py
  • tests/openfeature/__init__.py
  • tests/openfeature/fixtures/bootstrap.json
  • tests/openfeature/test_context_converter.py
  • tests/openfeature/test_details_converter.py
  • tests/openfeature/test_offline_integration.py
  • tests/openfeature/test_provider.py
  • tests/test_fbclient.py
💤 Files with no reviewable changes (1)
  • fbclient/init.py

Comment thread featbit_openfeature/provider.py Outdated
Comment thread README.md Outdated
Comment thread release/description.md
@WuJiayi0307

Copy link
Copy Markdown
Author

Addressed all four review findings in 06d29d1:

  • preserve the flag-change listener when removal fails so shutdown can retry without duplicate registration
  • add a regression test for failed listener removal and retry
  • lock down the unchanged EvalDetail.to_json_dict() contract
  • fix the README installation sentence and release-note heading

Validation after the fixes: 105 passed, Flake8 passes, and both wheel and source distribution rebuild successfully. The three inline review threads are now marked addressed/outdated. GitHub Actions is still awaiting first-time fork approval from a repository maintainer.

@WuJiayi0307 WuJiayi0307 changed the title feat: add OpenFeature Python server provider feat: expose variation ID and data update status listeners Jul 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
fbclient/status.py (1)

59-84: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Preserve transition order when publishing callbacks.

Concurrent update_state calls can notify in reverse order: one thread can snapshot OK, release __lock, then another can publish INTERRUPTED before the first invokes its callback. Serialize queued publications in transition order while keeping user callbacks outside __lock, and add a concurrent ordering regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@fbclient/status.py` around lines 59 - 84, The update_state callback flow must
preserve state-transition order under concurrent calls. Modify update_state and
its listener-publication mechanism to queue committed states while holding the
existing lock, then drain that queue serially outside __lock so callbacks
execute in transition order without invoking user listeners under the lock; add
a concurrent regression test verifying ordered OK/INTERRUPTED publications.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@fbclient/status.py`:
- Around line 59-84: The update_state callback flow must preserve
state-transition order under concurrent calls. Modify update_state and its
listener-publication mechanism to queue committed states while holding the
existing lock, then drain that queue serially outside __lock so callbacks
execute in transition order without invoking user listeners under the lock; add
a concurrent regression test verifying ordered OK/INTERRUPTED publications.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 62070b14-1267-4839-993b-9a887e3830d5

📥 Commits

Reviewing files that changed from the base of the PR and between e09df9d and 824aee8.

📒 Files selected for processing (8)
  • MANIFEST.in
  • README.md
  • fbclient/interfaces.py
  • fbclient/status.py
  • release/description.md
  • release/package.json
  • tests/test_data_update_status_provider.py
  • tests/test_fbclient.py
💤 Files with no reviewable changes (1)
  • MANIFEST.in
🚧 Files skipped from review as they are similar to previous changes (2)
  • release/package.json
  • tests/test_fbclient.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant