Skip to content

feat(python)!: New python provider with inprocess support#4861

Open
thomaspoignant wants to merge 21 commits intomainfrom
python-wasm-provider
Open

feat(python)!: New python provider with inprocess support#4861
thomaspoignant wants to merge 21 commits intomainfrom
python-wasm-provider

Conversation

@thomaspoignant
Copy link
Owner

Summary

Adds in-process evaluation support to the GO Feature Flag Python provider, allowing flag evaluation without requiring a relay proxy when using WASM.

Changes

  • Evaluator abstraction: Introduced AbstractEvaluator with two implementations:
    • InprocessEvaluator: Evaluates flags locally via WASM (no relay proxy required)
    • RemoteEvaluator: Existing HTTP-based evaluation against the relay proxy (OFREP-style API)
  • WASM integration: New wasm/ module with evaluate_wasm.py and bundled WASI binary for in-process evaluation
  • Provider refactor: GoFeatureFlagProvider now delegates to the chosen evaluator; logic split into evaluators and services
  • Services: New services/ package (API client, event publisher, models) used by the remote evaluator
  • Hooks: Data collector and enrich-evaluation-context hooks moved/refactored under hooks/
  • Build: Python provider build switched from Poetry to uv (pyproject.toml + uv.lock); poetry.lock removed
  • Tests: Added tests for inprocess evaluator, WASM evaluation, services API, data collector hook, and enrich context hook; updated existing provider and integration tests
  • CI: .github/workflows/release-python-provider.yml updated for the new layout
  • Docs: Added AGENTS.md and CLAUDE.md for the Python provider

Checklist

  • Tests added/updated
  • Code follows project patterns (evaluators, hooks, Pydantic models)
  • No new secrets or credentials
  • Build and tooling (uv) aligned with project

Signed-off-by: Thomas Poignant thomas.poignant@gofeatureflag.org

@netlify
Copy link

netlify bot commented Feb 20, 2026

Deploy Preview for go-feature-flag-doc-preview ready!

Name Link
🔨 Latest commit 82fe44e
🔍 Latest deploy log https://app.netlify.com/projects/go-feature-flag-doc-preview/deploys/69affd2de1ebda0008a59129
😎 Deploy Preview https://deploy-preview-4861--go-feature-flag-doc-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
@thomaspoignant thomaspoignant marked this pull request as draft February 20, 2026 18:09
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant refactoring of the Python provider, adding support for in-process evaluation via WASM, and includes architectural improvements like the AbstractEvaluator interface and a switch to uv for dependency management. A high-severity security issue was identified in the WASM memory management logic: the current implementation uses raw pointers to WASM linear memory without proper bounds checking, which could allow a compromised or malicious WASM module to escape its sandbox and read or write host process memory. It is recommended to use the built-in safe memory access methods from the wasmtime SDK to ensure the integrity of the sandbox. Additionally, several critical issues need attention: the WASM binary required for in-process evaluation is not included in the final package distribution due to the exclude configuration in pyproject.toml; the async methods in InProcessEvaluator are not truly asynchronous and should use asyncio.to_thread; the AGENTS.md file is outdated; and the removal of the provider-level LRU cache is a breaking change that requires explicit documentation. Addressing these points will ensure a more secure and smoother experience for users and contributors.

@thomaspoignant thomaspoignant force-pushed the python-wasm-provider branch 2 times, most recently from 076aa6f to b8dc83a Compare February 20, 2026 18:20
Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
@codecov
Copy link

codecov bot commented Feb 20, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.81%. Comparing base (6ef96c1) to head (82fe44e).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4861   +/-   ##
=======================================
  Coverage   85.81%   85.81%           
=======================================
  Files         153      153           
  Lines        6541     6541           
=======================================
  Hits         5613     5613           
  Misses        698      698           
  Partials      230      230           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
@thomaspoignant
Copy link
Owner Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a significant and valuable feature: in-process flag evaluation using WASM for the GO Feature Flag Python provider. While the refactoring is well-executed with clear abstractions like AbstractEvaluator and the move to uv and hatchling is a positive modernization step, two critical security vulnerabilities have been identified. The use of a non-thread-safe wasmtime.Store across multiple threads in the in-process evaluator can lead to application crashes, and the EventPublisher is vulnerable to thread exhaustion and unbounded memory growth if the data collector becomes unreachable. Addressing these issues is critical for stability and security. Additionally, improvements are needed for outdated documentation, a potential regression in data collection for the remote evaluator, and async handling in the new in-process evaluator.

thomaspoignant and others added 8 commits February 23, 2026 08:51
….to_thread

Async resolve_*_details_async methods now use asyncio.to_thread() to run
sync evaluation in a thread, avoiding event loop blocking. Update test
docstring to match.
… evaluator

When a flag is not found in _is_trackable, log warning and return True so
unknown flags remain visible in exporters. Update uv.lock.
…evaluation

- Add wasm_pool_size option (default 10) to control number of wasmtime Store
  instances; Store is not thread-safe, so a pool allows parallel evaluations.
- Refactor EvaluateWasm to use a Queue of Store slots and _create_slot helper.
- InProcessEvaluator passes pool_size into EvaluateWasm (default 4 when unset).
- Add test_evaluate_concurrent_threads to assert concurrent evaluation works.
Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
Co-authored-by: Cursor <cursoragent@cursor.com>
@thomaspoignant
Copy link
Owner Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a major refactoring to the Python provider, adding support for in-process evaluation using WASM. The architecture is now split into InProcessEvaluator and RemoteEvaluator (wrapping OFREP), which is a significant improvement in modularity. The introduction of an EventPublisher service also cleans up the data collection logic. However, there are a few critical points to address. The WASM binary required for in-process evaluation is not included in the package distribution, which will cause failures for users. Additionally, data collection appears to be disabled for remote evaluations, which is a significant change in functionality. The documentation in AGENTS.md is also outdated and needs to be updated to reflect the new architecture.

thomaspoignant and others added 3 commits February 25, 2026 17:43
The file had several outdated references: phantom ffclient/ directory,
non-existent modules/evaluation, missing providers (PHP, Ruby, Swift),
missing exporters (Logs, OpenTelemetry), incorrect Exporter interface
signature, and missing Makefile targets.

Co-authored-by: Cursor <cursoragent@cursor.com>
Port the Java InProcessEvaluation test class to Python, exercising
the full provider stack (provider -> InProcessEvaluator -> WASM) with
mock flag configurations for all flag types, disabled flags, error
paths, and scheduled rollouts.

Co-authored-by: Cursor <cursoragent@cursor.com>
@thomaspoignant
Copy link
Owner Author

/gemini review

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces in-process evaluation using WASM and migrates the remote evaluation to the OFREP standard, featuring a clean and modular Evaluator abstraction. No security vulnerabilities were found. However, there are several critical points to address: the packaging for the in-process mode appears broken as the WASM binary is not included, the default evaluation mode has been switched to INPROCESS which is a breaking change, data collection for the remote evaluator seems disabled, and there's a minor issue with error handling in the in-process evaluator. Additionally, the move to OFREPProvider for remote evaluation results in the loss of the custom caching mechanism, a performance characteristic change that should be communicated to users.

@thomaspoignant thomaspoignant marked this pull request as ready for review February 25, 2026 17:26
@thomaspoignant thomaspoignant changed the title feat(python): New python provider with inprocess support feat(python)!: New python provider with inprocess support Feb 26, 2026
@thomaspoignant
Copy link
Owner Author

@kouk @michaelmyc
Based on your previous PR and Issues, I know that you are using the python provider.
This PR is a new implementation and I would like to get your point of view on this new implementation.

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
@kouk
Copy link
Contributor

kouk commented Mar 10, 2026

So, @thomaspoignant my understanding is that with this update as a user I get to use bypass the middleman (aka relay-proxy) by using the in process provider, and all the storage mechanism details get put inside the WASM module right? And then the main disadvantage is the lack of a local cache.

Right now if I was a user and wanted to update to this new provider I would go with remote evaluation because it would be unclear if and how I would retain all the integrations I have with my relay-proxy. But I would lose caching, so my relay proxy would be on the critical path of each application transaction (Resulting in different behavior of my app based on the availability of the proxy). Am I missing something?

@sonarqubecloud
Copy link

@thomaspoignant
Copy link
Owner Author

@kouk sorry for the delay.
In this update you keep the relay proxy but instead of deporting the evaluation to the relay proxy, the relay proxy is here to serve the configuration to the provider.

It means that the evaluation happens inside the provider (removing network ops and assuring a faster and more reliable evaluation).
It also means that all your current integration with the relay-proxy will work as you know it (retrievers, exporters etc ...).

The remote evaluation still has no caching because if you want a more accurate way you can always use the inprocess implementation.

Does it answer all your doubts?

@michaelmyc
Copy link
Contributor

michaelmyc commented Mar 13, 2026

Didn't have time to check everything. Looks like this is adding a wasm resolver locally that syncs with the remote flag system. Not sure why we need wasm?

I like the idea that when the remote relay-proxy is down the system could use the local resolver with a recent result (compared to cache which is the last query result that could be ages ago). But I'm not sure how much extra resources it's going to use. It could become a resource hog for relay proxies with a ton of flags, and in a micro-services architecture where each service is designed to be lightweight, it might not be a good default option.

@kouk
Copy link
Contributor

kouk commented Mar 14, 2026 via email

@michaelmyc
Copy link
Contributor

My intuition is that wasm is serving the purpose of a common code base that would work across different providers (python, JS, etc.) so that the project doesn't have to maintain fully separate implementations. Perhaps the wasm module is implemented in Golang or something in another repo? In any case, what I wanted to ask is, if the relay proxy is still just serving the configuration does the WASM module keep the last config in memory in case it cannot reach the proxy?

--- |/ |/ Konstantinos @.> |\ |\ Koukopoulos https://keybase.io/kouk
On Fri, Mar 13, 2026, 09:14 Michael Mao @.
> wrote: michaelmyc left a comment (thomaspoignant/go-feature-flag#4861) <#4861 (comment)> Didn't have time to check everything. Looks like this is adding a wasm resolver locally that syncs with the remote flag system. Not sure why we need wasm? — Reply to this email directly, view it on GitHub <#4861 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADPKRYTVGFSP5P32V7L6HT4QOYM3AVCNFSM6AAAAACV2YSHEWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DANJTGI2TANJXGM . You are receiving this because you were mentioned.Message ID: @.***>

Ah, if that's the case, I think WASM would be a great addition. More code reuse is welcome.

I concur that the caching mechanism should be the key focus of our discussions. My main concerns about pre-emptive caching for local evaluation:

  1. size of flags being synced too large can cause:
    • startup time being too long
    • memory hog
    • syncing time getting too long
    • client-side syncing issues (if the same module being reused in Android/iOS/web)
  2. much more frequent sync calls to proxy-server could more resource intensive at the proxy-server level

Again, this PR is quite large and I'm not sure if my understanding of the caching mechanism is correct, so not sure if my concerns are valid.

@thomaspoignant
Copy link
Owner Author

Hey sorry for the late reply @kouk you are totally right, the WASM module is used accross languages, the goal is to be certain that all the evaluation is exactly the same cross languages.

FYI, this is already the default implementation in Java, .NET and node.

@michaelmyc

1.size of flags being synced too large can cause:
This is actually a really good point and it can slow down the initialization of the provider.

2.much more frequent sync calls to proxy-server could more resource intensive at the proxy-server level
And yes this is the opposite trade off when being in full remote evaluation.

What would be an ideal compromise for you to work well with this provider?

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.

3 participants