gofeatureflag-python-provider 0.4.4__tar.gz → 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. gofeatureflag_python_provider-1.0.0/.gitignore +161 -0
  2. gofeatureflag_python_provider-1.0.0/AGENTS.md +148 -0
  3. gofeatureflag_python_provider-1.0.0/CHANGELOG.md +50 -0
  4. gofeatureflag_python_provider-1.0.0/CLAUDE.md +1 -0
  5. {gofeatureflag_python_provider-0.4.4 → gofeatureflag_python_provider-1.0.0}/PKG-INFO +16 -28
  6. {gofeatureflag_python_provider-0.4.4 → gofeatureflag_python_provider-1.0.0}/README.md +3 -4
  7. gofeatureflag_python_provider-1.0.0/clean.py +0 -0
  8. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/__init__.py +1 -0
  9. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/evaluator/__init__.py +17 -0
  10. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/evaluator/abstract_evaluator.py +136 -0
  11. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/evaluator/inprocess_evaluator.py +330 -0
  12. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/evaluator/remote_evaluator.py +189 -0
  13. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/exceptions.py +25 -0
  14. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/hooks/__init__.py +6 -0
  15. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/hooks/data_collector.py +83 -0
  16. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/hooks/enrich_evaluation_context.py +27 -0
  17. {gofeatureflag_python_provider-0.4.4 → gofeatureflag_python_provider-1.0.0}/gofeatureflag_python_provider/options.py +41 -3
  18. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/provider.py +312 -0
  19. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/services/__init__.py +25 -0
  20. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/services/api.py +210 -0
  21. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/services/event_publisher.py +157 -0
  22. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/services/models.py +23 -0
  23. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/wasm/__init__.py +15 -0
  24. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/wasm/_wasi_version.txt +1 -0
  25. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/wasm/evaluate_wasm.py +203 -0
  26. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/wasm/gofeatureflag-evaluation_0.2.0.wasi +0 -0
  27. gofeatureflag_python_provider-1.0.0/gofeatureflag_python_provider/wasm/models.py +40 -0
  28. gofeatureflag_python_provider-1.0.0/hatch_build.py +0 -0
  29. gofeatureflag_python_provider-1.0.0/pyproject.toml +56 -0
  30. gofeatureflag_python_provider-1.0.0/tests/.gitignore +1 -0
  31. gofeatureflag_python_provider-1.0.0/tests/__init__.py +0 -0
  32. gofeatureflag_python_provider-1.0.0/tests/config.goff.yaml +176 -0
  33. gofeatureflag_python_provider-1.0.0/tests/conftest.py +0 -0
  34. gofeatureflag_python_provider-1.0.0/tests/docker-compose.yml +15 -0
  35. gofeatureflag_python_provider-1.0.0/tests/mock_responses/config/valid-all-types-config-change.json +248 -0
  36. gofeatureflag_python_provider-1.0.0/tests/mock_responses/config/valid-all-types.json +248 -0
  37. gofeatureflag_python_provider-1.0.0/tests/mock_responses/config/valid-flag-config.json +25 -0
  38. gofeatureflag_python_provider-1.0.0/tests/mock_responses/config/valid-scheduled-rollout.json +58 -0
  39. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/bool_targeting_match.json +11 -0
  40. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/bool_targeting_match_no_error_field.json +11 -0
  41. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/disabled_bool.json +6 -0
  42. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/disabled_float.json +6 -0
  43. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/disabled_int.json +6 -0
  44. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/disabled_object.json +8 -0
  45. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/disabled_string.json +6 -0
  46. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/double_key.json +6 -0
  47. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/flag_not_found.json +5 -0
  48. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/integer_key.json +6 -0
  49. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/invalid_json_body.json +7 -0
  50. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/list_key.json +12 -0
  51. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/object_key.json +12 -0
  52. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/string_key.json +6 -0
  53. gofeatureflag_python_provider-1.0.0/tests/mock_responses/ofrep/unknown_reason.json +5 -0
  54. gofeatureflag_python_provider-1.0.0/tests/test_data_collector_hook.py +287 -0
  55. gofeatureflag_python_provider-1.0.0/tests/test_enrich_evaluation_context_hook.py +82 -0
  56. gofeatureflag_python_provider-1.0.0/tests/test_evaluate_wasm.py +348 -0
  57. gofeatureflag_python_provider-1.0.0/tests/test_event_publisher.py +156 -0
  58. gofeatureflag_python_provider-1.0.0/tests/test_gofeatureflag_provider.py +839 -0
  59. gofeatureflag_python_provider-1.0.0/tests/test_gofeatureflag_provider_inprocess.py +333 -0
  60. gofeatureflag_python_provider-1.0.0/tests/test_inprocess_evaluator.py +569 -0
  61. gofeatureflag_python_provider-1.0.0/tests/test_provider_graceful_exit.py +90 -0
  62. gofeatureflag_python_provider-1.0.0/tests/test_remote_evaluator_ofrep.py +86 -0
  63. gofeatureflag_python_provider-1.0.0/tests/test_services_api.py +586 -0
  64. gofeatureflag_python_provider-1.0.0/tests/test_websocket_cache_invalidation.py +121 -0
  65. gofeatureflag_python_provider-1.0.0/uv.lock +860 -0
  66. gofeatureflag_python_provider-0.4.4/gofeatureflag_python_provider/__init__.py +0 -1
  67. gofeatureflag_python_provider-0.4.4/gofeatureflag_python_provider/data_collector_hook.py +0 -142
  68. gofeatureflag_python_provider-0.4.4/gofeatureflag_python_provider/provider.py +0 -326
  69. gofeatureflag_python_provider-0.4.4/pyproject.toml +0 -47
  70. {gofeatureflag_python_provider-0.4.4 → gofeatureflag_python_provider-1.0.0}/gofeatureflag_python_provider/metadata.py +0 -0
  71. {gofeatureflag_python_provider-0.4.4 → gofeatureflag_python_provider-1.0.0}/gofeatureflag_python_provider/request_data_collector.py +0 -0
  72. {gofeatureflag_python_provider-0.4.4 → gofeatureflag_python_provider-1.0.0}/gofeatureflag_python_provider/request_flag_evaluation.py +0 -0
  73. {gofeatureflag_python_provider-0.4.4 → gofeatureflag_python_provider-1.0.0}/gofeatureflag_python_provider/response_flag_evaluation.py +0 -0
@@ -0,0 +1,161 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # uv
98
+ # uv.lock is recommended to be included in version control for reproducibility.
99
+ # https://docs.astral.sh/uv/concepts/projects/layout/#the-lockfile
100
+ #uv.lock
101
+
102
+ # pdm
103
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
104
+ #pdm.lock
105
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
106
+ # in version control.
107
+ # https://pdm.fming.dev/#use-with-ide
108
+ .pdm.toml
109
+
110
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
111
+ __pypackages__/
112
+
113
+ # Celery stuff
114
+ celerybeat-schedule
115
+ celerybeat.pid
116
+
117
+ # SageMath parsed files
118
+ *.sage.py
119
+
120
+ # Environments
121
+ .env
122
+ .venv
123
+ env/
124
+ venv/
125
+ ENV/
126
+ env.bak/
127
+ venv.bak/
128
+
129
+ # Spyder project settings
130
+ .spyderproject
131
+ .spyproject
132
+
133
+ # Rope project settings
134
+ .ropeproject
135
+
136
+ # mkdocs documentation
137
+ /site
138
+
139
+ # mypy
140
+ .mypy_cache/
141
+ .dmypy.json
142
+ dmypy.json
143
+
144
+ # Pyre type checker
145
+ .pyre/
146
+
147
+ # pytype static type analyzer
148
+ .pytype/
149
+
150
+ # Cython debug symbols
151
+ cython_debug/
152
+
153
+ # PyCharm
154
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
155
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
156
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
157
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
158
+ .idea/
159
+
160
+ ./gofeatureflag_python_provider/wasm/_wasi_version.txt
161
+ ./gofeatureflag_python_provider/wasm/gofeatureflag-evaluation_*.wasi
@@ -0,0 +1,148 @@
1
+ # GO Feature Flag Python Provider
2
+
3
+ OpenFeature Python provider for [GO Feature Flag](https://gofeatureflag.org).
4
+
5
+ ## Project Overview
6
+
7
+ This is a Python package that implements the OpenFeature provider interface to connect to a GO Feature Flag relay proxy. It enables Python applications to evaluate feature flags using the OpenFeature SDK.
8
+
9
+ ## Architecture
10
+
11
+ ```
12
+ gofeatureflag_python_provider/
13
+ ├── __init__.py # Package exports
14
+ ├── provider.py # Main GoFeatureFlagProvider class (AbstractProvider implementation)
15
+ ├── options.py # GoFeatureFlagOptions configuration class
16
+ ├── hooks/ # OpenFeature hooks
17
+ │ ├── __init__.py
18
+ │ ├── data_collector.py # Hook for collecting flag evaluation usage data
19
+ │ └── enrich_evaluation_context.py # Hook that adds gofeatureflag metadata to context before evaluation
20
+ ├── metadata.py # Provider metadata
21
+ ├── request_data_collector.py # Data models for usage collection
22
+ ├── request_flag_evaluation.py # Request models for flag evaluation API calls
23
+ └── response_flag_evaluation.py # Response models for flag evaluation API calls
24
+
25
+ tests/
26
+ ├── test_gofeatureflag_python_provider.py # Main provider tests
27
+ ├── test_enrich_evaluation_context_hook.py # EnrichEvaluationContextHook tests
28
+ ├── test_provider_graceful_exit.py # Shutdown/cleanup tests
29
+ ├── test_websocket_cache_invalidation.py # WebSocket cache invalidation tests
30
+ ├── mock_responses/ # JSON mock responses for testing
31
+ ├── config.goff.yaml # Test flag configuration
32
+ └── docker-compose.yml # Test infrastructure
33
+ ```
34
+
35
+ ## Key Components
36
+
37
+ ### GoFeatureFlagProvider (`provider.py`)
38
+ - Extends `AbstractProvider` from OpenFeature SDK
39
+ - Implements all resolve methods: `resolve_boolean_details`, `resolve_string_details`, `resolve_integer_details`, `resolve_float_details`, `resolve_object_details`
40
+ - Uses `generic_go_feature_flag_resolver` for all flag types
41
+ - Features:
42
+ - LRU cache for flag evaluations (`pylru`)
43
+ - WebSocket connection for cache invalidation
44
+ - Data collection for usage analytics
45
+
46
+ ### GoFeatureFlagOptions (`options.py`)
47
+ Configuration options:
48
+ - `endpoint` (required): URL of the GO Feature Flag relay proxy
49
+ - `cache_size`: Max cached flags (default: 10000)
50
+ - `data_flush_interval`: Interval to flush usage data in ms (default: 60000)
51
+ - `disable_data_collection`: Turn off usage tracking (default: false)
52
+ - `reconnect_interval`: WebSocket reconnect interval in seconds (default: 60)
53
+ - `disable_cache_invalidation`: Disable WebSocket cache invalidation (default: false)
54
+ - `api_key`: API key for authenticated requests
55
+ - `exporter_metadata`: Custom metadata for evaluation events
56
+ - `debug`: Enable debug logging (default: false)
57
+ - `urllib3_pool_manager`: Custom HTTP client
58
+
59
+ ### DataCollectorHook (`hooks/data_collector.py`)
60
+ - OpenFeature Hook implementation for collecting usage data
61
+ - Tracks flag evaluations via `after()` and `error()` hooks
62
+ - Flushes data to `/v1/data/collector` endpoint periodically
63
+
64
+ ### EnrichEvaluationContextHook (`hooks/enrich_evaluation_context.py`)
65
+ - Enriches the evaluation context with a `gofeatureflag` attribute (from `exporter_metadata`) before flag resolution
66
+ - Used by the relay proxy for analytics or filtering; registered automatically by the provider
67
+
68
+ ## Development
69
+
70
+ ### Prerequisites
71
+ - Python 3.9+
72
+ - uv (package manager)
73
+
74
+ ### Setup
75
+ ```bash
76
+ # Install dependencies
77
+ uv sync
78
+
79
+ # Run a command in the virtual environment
80
+ uv run <command>
81
+ ```
82
+
83
+ ### Running Tests
84
+ ```bash
85
+ # Run all tests
86
+ uv run pytest
87
+
88
+ # Run specific test file
89
+ uv run pytest tests/test_gofeatureflag_python_provider.py
90
+
91
+ # Run with verbose output
92
+ uv run pytest -v
93
+ ```
94
+
95
+ ### Code Style
96
+ ```bash
97
+ # Format code with black
98
+ uv run black gofeatureflag_python_provider tests
99
+ ```
100
+
101
+ ## Key Patterns
102
+
103
+ ### Pydantic Models
104
+ - All data classes extend Pydantic `BaseModel` for validation
105
+ - Request/response models use `model_dump_json()` for serialization
106
+ - Use `model_validate_json()` for deserialization
107
+
108
+ ### HTTP Communication
109
+ - Uses `urllib3.PoolManager` for HTTP requests
110
+ - POST to `/v1/feature/{flag_key}/eval` for flag evaluation
111
+ - POST to `/v1/data/collector` for usage data
112
+ - WebSocket at `/ws/v1/flag/change` for cache invalidation
113
+
114
+ ### Caching Strategy
115
+ - LRU cache keyed by `{flag_key}:{evaluation_context_hash()}`
116
+ - Cache cleared on WebSocket message (flag config changed)
117
+ - Set `cacheable` field in response determines if result is cached
118
+
119
+ ### Error Handling
120
+ - `FlagNotFoundError`: Flag doesn't exist (404)
121
+ - `InvalidContextError`: Invalid evaluation context (400)
122
+ - `TypeMismatchError`: Response type doesn't match expected type
123
+ - `GeneralError`: Other errors (500+)
124
+
125
+ ## API Reference
126
+
127
+ The provider communicates with the GO Feature Flag relay proxy:
128
+
129
+ | Endpoint | Method | Purpose |
130
+ |----------|--------|---------|
131
+ | `/v1/feature/{flag}/eval` | POST | Evaluate a flag |
132
+ | `/v1/data/collector` | POST | Send usage data |
133
+ | `/ws/v1/flag/change` | WebSocket | Cache invalidation notifications |
134
+
135
+ ## Dependencies
136
+
137
+ Core:
138
+ - `openfeature-sdk`: OpenFeature Python SDK
139
+ - `pydantic`: Data validation
140
+ - `urllib3`: HTTP client
141
+ - `pylru`: LRU cache implementation
142
+ - `websocket-client`: WebSocket support
143
+ - `rel`: WebSocket reconnection handling
144
+
145
+ Dev:
146
+ - `pytest`: Testing framework
147
+ - `black`: Code formatter
148
+ - `pytest-docker`: Docker-based integration tests
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ ## [1.0.0](https://github.com/thomaspoignant/go-feature-flag/compare/openfeature/providers/python-provider/v0.5.0...openfeature/providers/python-provider/v1.0.0) (2026-03-31)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * **python:** New python provider with inprocess support ([#4861](https://github.com/thomaspoignant/go-feature-flag/issues/4861))
9
+
10
+ ### 🚀 New Features
11
+
12
+ * **python:** New python provider with inprocess support ([#4861](https://github.com/thomaspoignant/go-feature-flag/issues/4861)) ([d67c24b](https://github.com/thomaspoignant/go-feature-flag/commit/d67c24b3f5969a7d3ec5a2cd893d6094e3534152))
13
+
14
+
15
+ ### 🔧 Chores
16
+
17
+ * Bump github.com/aws/aws-sdk-go-v2/service/s3 ([#4613](https://github.com/thomaspoignant/go-feature-flag/issues/4613)) ([a8e9b13](https://github.com/thomaspoignant/go-feature-flag/commit/a8e9b136eb972da636726525bffc1c2f86fcb432))
18
+ * Bump go.opentelemetry.io/otel/sdk from 1.41.0 to 1.42.0 ([#4944](https://github.com/thomaspoignant/go-feature-flag/issues/4944)) ([ede0c19](https://github.com/thomaspoignant/go-feature-flag/commit/ede0c19d7452e55e9b8e27d1c929da9c0492a82a))
19
+ * Bump rel in /openfeature/providers/python-provider ([#4816](https://github.com/thomaspoignant/go-feature-flag/issues/4816)) ([abed2fc](https://github.com/thomaspoignant/go-feature-flag/commit/abed2fc066214042bf6002b988de6c32b7288873))
20
+ * Bump urllib3 in /openfeature/providers/python-provider ([#4605](https://github.com/thomaspoignant/go-feature-flag/issues/4605)) ([3d97b25](https://github.com/thomaspoignant/go-feature-flag/commit/3d97b256978c7f74f7e1a3eec229f6db553892ec))
21
+
22
+ ## [0.5.0](https://github.com/thomaspoignant/go-feature-flag/compare/openfeature/providers/python-provider/v0.5.0...openfeature/providers/python-provider/v0.5.0) (2025-10-26)
23
+
24
+
25
+ ### 🚀 New Features
26
+
27
+ * Python Provider Graceful Exit ([#4106](https://github.com/thomaspoignant/go-feature-flag/issues/4106)) ([b48cc0c](https://github.com/thomaspoignant/go-feature-flag/commit/b48cc0c0d3874e002eea174192251e0564540512))
28
+
29
+
30
+ ### 🔧 Chores
31
+
32
+ * Bump pydantic in /openfeature/providers/python-provider ([#4050](https://github.com/thomaspoignant/go-feature-flag/issues/4050)) ([d4ea37f](https://github.com/thomaspoignant/go-feature-flag/commit/d4ea37fa7d3d91742acd75e246563699bb71b287))
33
+ * Bump pydantic in /openfeature/providers/python-provider ([#4120](https://github.com/thomaspoignant/go-feature-flag/issues/4120)) ([beda91c](https://github.com/thomaspoignant/go-feature-flag/commit/beda91cbbc0369c38c71178b92ab13f1103e83a6))
34
+ * Bump websocket-client in /openfeature/providers/python-provider ([#4053](https://github.com/thomaspoignant/go-feature-flag/issues/4053)) ([4147232](https://github.com/thomaspoignant/go-feature-flag/commit/4147232126e8f6af5a03a90001d07177ba1e60a8))
35
+ * **main:** release openfeature/providers/python-provider 0.5.0 ([#4065](https://github.com/thomaspoignant/go-feature-flag/issues/4065)) ([fb0d9ba](https://github.com/thomaspoignant/go-feature-flag/commit/fb0d9babaeae8fc4721c6bcd9a566d8c6e5502a9))
36
+ * Release python as v0.5.0 ([#4142](https://github.com/thomaspoignant/go-feature-flag/issues/4142)) ([0c1508a](https://github.com/thomaspoignant/go-feature-flag/commit/0c1508a7bc466be35d18f3026668f0896f8fa55e))
37
+
38
+ ## [0.5.0](https://github.com/thomaspoignant/go-feature-flag/compare/openfeature/providers/python-provider/v0.4.4...openfeature/providers/python-provider/v0.5.0) (2025-10-26)
39
+
40
+
41
+ ### 🚀 New Features
42
+
43
+ * Python Provider Graceful Exit ([#4106](https://github.com/thomaspoignant/go-feature-flag/issues/4106)) ([b48cc0c](https://github.com/thomaspoignant/go-feature-flag/commit/b48cc0c0d3874e002eea174192251e0564540512))
44
+
45
+
46
+ ### 🔧 Chores
47
+
48
+ * Bump pydantic in /openfeature/providers/python-provider ([#4050](https://github.com/thomaspoignant/go-feature-flag/issues/4050)) ([d4ea37f](https://github.com/thomaspoignant/go-feature-flag/commit/d4ea37fa7d3d91742acd75e246563699bb71b287))
49
+ * Bump pydantic in /openfeature/providers/python-provider ([#4120](https://github.com/thomaspoignant/go-feature-flag/issues/4120)) ([beda91c](https://github.com/thomaspoignant/go-feature-flag/commit/beda91cbbc0369c38c71178b92ab13f1103e83a6))
50
+ * Bump websocket-client in /openfeature/providers/python-provider ([#4053](https://github.com/thomaspoignant/go-feature-flag/issues/4053)) ([4147232](https://github.com/thomaspoignant/go-feature-flag/commit/4147232126e8f6af5a03a90001d07177ba1e60a8))
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -1,36 +1,26 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: gofeatureflag-python-provider
3
- Version: 0.4.4
3
+ Version: 1.0.0
4
4
  Summary: GO Feature Flag provider for OpenFeature
5
- License: Apache-2.0
6
- Keywords: feature flags,feature toggles,go-feature-flag,gofeatureflag,openfeature,open-feature
5
+ Project-URL: Bug Tracker, https://github.com/thomaspoignant/go-feature-flag/issues
6
+ Project-URL: Source Code, https://github.com/thomaspoignant/go-feature-flag/tree/main/openfeature/providers/python-provider
7
+ Project-URL: Documentation, https://github.com/thomaspoignant/go-feature-flag/tree/main/openfeature/providers/python-provider
7
8
  Author: Thomas Poignant
8
- Requires-Python: >=3.9,<4.0
9
- Classifier: License :: OSI Approved :: Apache Software License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.9
12
- Classifier: Programming Language :: Python :: 3.10
13
- Classifier: Programming Language :: Python :: 3.11
14
- Classifier: Programming Language :: Python :: 3.12
15
- Classifier: Programming Language :: Python :: 3.13
9
+ License-Expression: Apache-2.0
10
+ Keywords: feature flags,feature toggles,go-feature-flag,gofeatureflag,open-feature,openfeature
16
11
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
17
12
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
- Requires-Dist: openfeature-sdk (>=0.5.0,<0.9.0)
19
- Requires-Dist: pydantic (>=2.5.2,<3.0.0)
20
- Requires-Dist: pylru (>=1.2.1,<2.0.0)
21
- Requires-Dist: rel (>=0.4.9,<0.5.0)
22
- Requires-Dist: urllib3 (>=2.1.0,<3.0.0)
23
- Requires-Dist: websocket-client (>=1.6.4,<2.0.0)
24
- Project-URL: Bug Tracker, https://github.com/thomaspoignant/go-feature-flag/issues
25
- Project-URL: Documentation, https://github.com/thomaspoignant/go-feature-flag/tree/main/openfeature/providers/python-provider
26
- Project-URL: Homepage, https://gofeatureflag.org
27
- Project-URL: Repository, https://github.com/thomaspoignant/go-feature-flag
28
- Project-URL: Source Code, https://github.com/thomaspoignant/go-feature-flag/tree/main/openfeature/providers/python-provider
13
+ Requires-Python: >=3.9
14
+ Requires-Dist: openfeature-provider-ofrep>=0.2.0
15
+ Requires-Dist: openfeature-sdk<0.9.0,>=0.8.4
16
+ Requires-Dist: pydantic>=2.5.2
17
+ Requires-Dist: urllib3>=2.1.0
18
+ Requires-Dist: wasmtime>=41.0.0
29
19
  Description-Content-Type: text/markdown
30
20
 
31
21
  # GO Feature Flag Python Provider
32
22
 
33
- GO Feature Flag provider allows you to connect to your GO Feature Flag instance.
23
+ GO Feature Flag provider allows you to connect to your GO Feature Flag instance.
34
24
 
35
25
  [GO Feature Flag](https://gofeatureflag.org) believes in simplicity and offers a simple and lightweight solution to use feature flags.
36
26
  Our focus is to avoid any complex infrastructure work to use GO Feature Flag.
@@ -71,9 +61,8 @@ client = api.get_client(domain="test-client")
71
61
 
72
62
  This code block explains how you can create an `EvaluationContext` and use it to evaluate your flag.
73
63
 
74
-
75
64
  > In this example we are evaluating a `boolean` flag, but other types are available.
76
- >
65
+ >
77
66
  > **Refer to the [Open Feature documentation](https://docs.openfeature.dev/docs/reference/concepts/evaluation-api#basic-evaluation) to know more about it.**
78
67
 
79
68
  ```python
@@ -99,10 +88,9 @@ admin_flag = client.get_boolean_value(
99
88
  default_value=default_value,
100
89
  evaluation_context=ctx,
101
90
  )
102
-
91
+
103
92
  if admin_flag:
104
93
  # flag "flag-only-for-admin" is true for the user
105
94
  else:
106
95
  # flag "flag-only-for-admin" is false for the user
107
96
  ```
108
-
@@ -1,6 +1,6 @@
1
1
  # GO Feature Flag Python Provider
2
2
 
3
- GO Feature Flag provider allows you to connect to your GO Feature Flag instance.
3
+ GO Feature Flag provider allows you to connect to your GO Feature Flag instance.
4
4
 
5
5
  [GO Feature Flag](https://gofeatureflag.org) believes in simplicity and offers a simple and lightweight solution to use feature flags.
6
6
  Our focus is to avoid any complex infrastructure work to use GO Feature Flag.
@@ -41,9 +41,8 @@ client = api.get_client(domain="test-client")
41
41
 
42
42
  This code block explains how you can create an `EvaluationContext` and use it to evaluate your flag.
43
43
 
44
-
45
44
  > In this example we are evaluating a `boolean` flag, but other types are available.
46
- >
45
+ >
47
46
  > **Refer to the [Open Feature documentation](https://docs.openfeature.dev/docs/reference/concepts/evaluation-api#basic-evaluation) to know more about it.**
48
47
 
49
48
  ```python
@@ -69,7 +68,7 @@ admin_flag = client.get_boolean_value(
69
68
  default_value=default_value,
70
69
  evaluation_context=ctx,
71
70
  )
72
-
71
+
73
72
  if admin_flag:
74
73
  # flag "flag-only-for-admin" is true for the user
75
74
  else:
File without changes
@@ -0,0 +1,17 @@
1
+ """
2
+ Evaluator implementations for GO Feature Flag provider.
3
+
4
+ Selects remote (relay proxy) or inprocess (local/WASM) evaluation based on options.
5
+ """
6
+
7
+ from gofeatureflag_python_provider.evaluator.abstract_evaluator import AbstractEvaluator
8
+ from gofeatureflag_python_provider.evaluator.inprocess_evaluator import (
9
+ InProcessEvaluator,
10
+ )
11
+ from gofeatureflag_python_provider.evaluator.remote_evaluator import RemoteEvaluator
12
+
13
+ __all__ = [
14
+ "AbstractEvaluator",
15
+ "InProcessEvaluator",
16
+ "RemoteEvaluator",
17
+ ]
@@ -0,0 +1,136 @@
1
+ """
2
+ Abstract interface for flag evaluation.
3
+
4
+ Implementations: RemoteEvaluator (relay proxy), InProcessEvaluator (local/WASM).
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from typing import Optional, Union
9
+
10
+ from openfeature.evaluation_context import EvaluationContext
11
+ from openfeature.flag_evaluation import FlagResolutionDetails
12
+
13
+
14
+ class AbstractEvaluator(ABC):
15
+ """Interface for evaluating feature flags (remote or in-process)."""
16
+
17
+ @abstractmethod
18
+ def initialize(
19
+ self, evaluation_context: Optional[EvaluationContext] = None
20
+ ) -> None:
21
+ """Initialize the evaluator (e.g. cache, WebSocket, WASM)."""
22
+ ...
23
+
24
+ @abstractmethod
25
+ def shutdown(self) -> None:
26
+ """Release resources (connections, threads, etc.)."""
27
+ ...
28
+
29
+ # --- Sync evaluation ---
30
+
31
+ @abstractmethod
32
+ def resolve_boolean_details(
33
+ self,
34
+ flag_key: str,
35
+ default_value: bool,
36
+ evaluation_context: Optional[EvaluationContext] = None,
37
+ ) -> FlagResolutionDetails[bool]:
38
+ """Resolve the flag as a boolean."""
39
+ ...
40
+
41
+ @abstractmethod
42
+ def resolve_string_details(
43
+ self,
44
+ flag_key: str,
45
+ default_value: str,
46
+ evaluation_context: Optional[EvaluationContext] = None,
47
+ ) -> FlagResolutionDetails[str]:
48
+ """Resolve the flag as a string."""
49
+ ...
50
+
51
+ @abstractmethod
52
+ def resolve_integer_details(
53
+ self,
54
+ flag_key: str,
55
+ default_value: int,
56
+ evaluation_context: Optional[EvaluationContext] = None,
57
+ ) -> FlagResolutionDetails[int]:
58
+ """Resolve the flag as an integer."""
59
+ ...
60
+
61
+ @abstractmethod
62
+ def resolve_float_details(
63
+ self,
64
+ flag_key: str,
65
+ default_value: float,
66
+ evaluation_context: Optional[EvaluationContext] = None,
67
+ ) -> FlagResolutionDetails[float]:
68
+ """Resolve the flag as a float."""
69
+ ...
70
+
71
+ @abstractmethod
72
+ def resolve_object_details(
73
+ self,
74
+ flag_key: str,
75
+ default_value: Union[dict, list],
76
+ evaluation_context: Optional[EvaluationContext] = None,
77
+ ) -> FlagResolutionDetails[Union[list, dict]]:
78
+ """Resolve the flag as an object."""
79
+ ...
80
+
81
+ # --- Async evaluation ---
82
+
83
+ @abstractmethod
84
+ async def resolve_boolean_details_async(
85
+ self,
86
+ flag_key: str,
87
+ default_value: bool,
88
+ evaluation_context: Optional[EvaluationContext] = None,
89
+ ) -> FlagResolutionDetails[bool]:
90
+ """Asynchronously resolve the flag as a boolean."""
91
+ ...
92
+
93
+ @abstractmethod
94
+ async def resolve_string_details_async(
95
+ self,
96
+ flag_key: str,
97
+ default_value: str,
98
+ evaluation_context: Optional[EvaluationContext] = None,
99
+ ) -> FlagResolutionDetails[str]:
100
+ """Asynchronously resolve the flag as a string."""
101
+ ...
102
+
103
+ @abstractmethod
104
+ async def resolve_integer_details_async(
105
+ self,
106
+ flag_key: str,
107
+ default_value: int,
108
+ evaluation_context: Optional[EvaluationContext] = None,
109
+ ) -> FlagResolutionDetails[int]:
110
+ """Asynchronously resolve the flag as an integer."""
111
+ ...
112
+
113
+ @abstractmethod
114
+ async def resolve_float_details_async(
115
+ self,
116
+ flag_key: str,
117
+ default_value: float,
118
+ evaluation_context: Optional[EvaluationContext] = None,
119
+ ) -> FlagResolutionDetails[float]:
120
+ """Asynchronously resolve the flag as a float."""
121
+ ...
122
+
123
+ @abstractmethod
124
+ async def resolve_object_details_async(
125
+ self,
126
+ flag_key: str,
127
+ default_value: Union[dict, list],
128
+ evaluation_context: Optional[EvaluationContext] = None,
129
+ ) -> FlagResolutionDetails[Union[dict, list]]:
130
+ """Asynchronously resolve the flag as an object."""
131
+ ...
132
+
133
+ @abstractmethod
134
+ def is_flag_trackable(self, flag_key: str) -> bool:
135
+ """Check if the flag is trackable."""
136
+ ...