Skip to content

Commit 1864a3f

Browse files
toddbaertbeeme1mrfedericobond
authored
chore: update readme based on latest template (#227)
Signed-off-by: Todd Baert <[email protected]> Co-authored-by: Michael Beemer <[email protected]> Co-authored-by: Federico Bond <[email protected]>
1 parent 0c314ab commit 1864a3f

File tree

2 files changed

+310
-201
lines changed

2 files changed

+310
-201
lines changed

README.md

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
<!-- markdownlint-disable MD033 -->
2+
<!-- x-hide-in-docs-start -->
3+
<p align="center">
4+
<picture>
5+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/open-feature/community/0e23508c163a6a1ac8c0ced3e4bd78faafe627c7/assets/logo/horizontal/white/openfeature-horizontal-white.svg" />
6+
<img align="center" alt="OpenFeature Logo" src="https://raw.githubusercontent.com/open-feature/community/0e23508c163a6a1ac8c0ced3e4bd78faafe627c7/assets/logo/horizontal/black/openfeature-horizontal-black.svg" />
7+
</picture>
8+
</p>
9+
10+
<h2 align="center">OpenFeature Python SDK</h2>
11+
12+
<!-- x-hide-in-docs-end -->
13+
<!-- The 'github-badges' class is used in the docs -->
14+
<p align="center" class="github-badges">
15+
16+
<a href="https://github.com/open-feature/spec/releases/tag/v0.3.0">
17+
<img alt="Specification" src="https://img.shields.io/static/v1?label=Specification&message=v0.3.0&color=red&style=for-the-badge" />
18+
</a>
19+
20+
<!-- x-release-please-start-version -->
21+
22+
<a href="https://github.com/open-feature/python-sdk/releases/tag/v0.3.1">
23+
<img alt="Latest version" src="https://img.shields.io/static/v1?label=release&message=v0.3.1&color=blue&style=for-the-badge" />
24+
</a>
25+
26+
<!-- x-release-please-end -->
27+
<br/>
28+
<a href="https://github.com/open-feature/python-sdk/actions/workflows/merge.yml">
29+
<img alt="Build status" src="https://github.com/open-feature/python-sdk/actions/workflows/build.yml/badge.svg" />
30+
</a>
31+
32+
<a href="https://codecov.io/gh/open-feature/python-sdk">
33+
<img alt="Codecov" src="https://codecov.io/gh/open-feature/python-sdk/branch/main/graph/badge.svg?token=FQ1I444HB3" />
34+
</a>
35+
36+
<a href="https://www.python.org/downloads/">
37+
<img alt="Min python version" src="https://img.shields.io/badge/python->=3.8-blue.svg" />
38+
</a>
39+
40+
<a href="https://www.repostatus.org/#wip">
41+
<img alt="Repo status" src="https://www.repostatus.org/badges/latest/wip.svg" />
42+
</a>
43+
</p>
44+
<!-- x-hide-in-docs-start -->
45+
46+
[OpenFeature](https://openfeature.dev) is an open specification that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool.
47+
48+
<!-- x-hide-in-docs-end -->
49+
50+
## 🚀 Quick start
51+
52+
### Requirements
53+
54+
- Python 3.8+
55+
56+
### Install
57+
58+
<!---x-release-please-start-version-->
59+
60+
#### Pip install
61+
62+
```bash
63+
pip install openfeature-sdk==0.3.1
64+
```
65+
66+
#### requirements.txt
67+
68+
```bash
69+
openfeature-sdk==0.3.1
70+
```
71+
72+
```python
73+
pip install -r requirements.txt
74+
```
75+
76+
<!---x-release-please-end-->
77+
78+
### Usage
79+
80+
```python
81+
from openfeature import api
82+
from openfeature.provider.in_memory_provider import InMemoryFlag, InMemoryProvider
83+
84+
# flags defined in memory
85+
my_flags = {
86+
"v2_enabled": InMemoryFlag("on", {"on": True, "off": False})
87+
}
88+
89+
# configure a provider
90+
api.set_provider(InMemoryProvider(my_flags))
91+
92+
# create a client
93+
client = api.get_client()
94+
95+
# get a bool flag value
96+
flag_value = client.get_boolean_value("v2_enabled", False)
97+
print("Value: " + str(flag_value))
98+
```
99+
100+
## 🌟 Features
101+
102+
| Status | Features | Description |
103+
| ------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
104+
|| [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
105+
|| [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
106+
|| [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
107+
|| [Logging](#logging) | Integrate with popular logging packages. |
108+
|| [Named clients](#named-clients) | Utilize multiple providers in a single application. |
109+
|| [Eventing](#eventing) | React to state changes in the provider or flag management system. |
110+
|| [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
111+
|| [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
112+
113+
<sub>Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌</sub>
114+
115+
### Providers
116+
117+
[Providers](https://openfeature.dev/docs/reference/concepts/provider) are an abstraction between a flag management system and the OpenFeature SDK.
118+
Look [here](https://openfeature.dev/ecosystem?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Provider&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=python) for a complete list of available providers.
119+
If the provider you're looking for hasn't been created yet, see the [develop a provider](#develop-a-provider) section to learn how to build it yourself.
120+
121+
Once you've added a provider as a dependency, it can be registered with OpenFeature like this:
122+
123+
```python
124+
from openfeature import api
125+
from openfeature.provider.no_op_provider import NoOpProvider
126+
127+
api.set_provider(NoOpProvider())
128+
open_feature_client = api.get_client()
129+
```
130+
131+
<!-- In some situations, it may be beneficial to register multiple providers in the same application.
132+
This is possible using [named clients](#named-clients), which is covered in more detail below. -->
133+
134+
### Targeting
135+
136+
Sometimes, the value of a flag must consider some dynamic criteria about the application or user, such as the user's location, IP, email address, or the server's location.
137+
In OpenFeature, we refer to this as [targeting](https://openfeature.dev/specification/glossary#targeting).
138+
If the flag management system you're using supports targeting, you can provide the input data using the [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context).
139+
140+
```python
141+
from openfeature.api import (
142+
get_client,
143+
get_provider,
144+
set_provider,
145+
get_evaluation_context,
146+
set_evaluation_context,
147+
)
148+
149+
global_context = EvaluationContext(
150+
targeting_key="targeting_key1", attributes={"application": "value1"}
151+
)
152+
request_context = EvaluationContext(
153+
targeting_key="targeting_key2", attributes={"email": request.form['email']}
154+
)
155+
156+
## set global context
157+
set_evaluation_context(global_context)
158+
159+
# merge second context
160+
client = get_client(name="No-op Provider")
161+
client.get_string_value("email", "fallback", request_context)
162+
```
163+
164+
### Hooks
165+
166+
[Hooks](https://openfeature.dev/docs/reference/concepts/hooks) allow for custom logic to be added at well-defined points of the flag evaluation life-cycle.
167+
Look [here](https://openfeature.dev/ecosystem/?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Hook&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=python) for a complete list of available hooks.
168+
If the hook you're looking for hasn't been created yet, see the [develop a hook](#develop-a-hook) section to learn how to build it yourself.
169+
170+
Once you've added a hook as a dependency, it can be registered at the global, client, or flag invocation level.
171+
172+
```python
173+
from openfeature.api import add_hooks
174+
from openfeature.flag_evaluation import FlagEvaluationOptions
175+
176+
# set global hooks at the API-level
177+
add_hooks([MyHook()])
178+
179+
# or configure them in the client
180+
client = OpenFeatureClient()
181+
client.add_hooks([MyHook()])
182+
183+
# or at the invocation-level
184+
options = FlagEvaluationOptions(hooks=[MyHook()])
185+
client.get_boolean_flag("my-flag", False, flag_evaluation_options=options)
186+
```
187+
188+
### Logging
189+
190+
Logging customization is not yet available in the Python SDK.
191+
192+
### Named clients
193+
194+
Named clients are not yet available in the Python SDK. Progress on this feature can be tracked [here](https://github.com/open-feature/python-sdk/issues/125).
195+
196+
### Eventing
197+
198+
Events are not yet available in the Python SDK. Progress on this feature can be tracked [here](https://github.com/open-feature/python-sdk/issues/125).
199+
200+
### Shutdown
201+
202+
A shutdown method is not yet available in the Python SDK. Progress on this feature can be tracked [here](https://github.com/open-feature/python-sdk/issues/125).
203+
204+
## Extending
205+
206+
### Develop a provider
207+
208+
To develop a provider, you need to create a new project and include the OpenFeature SDK as a dependency.
209+
This can be a new repository or included in [the existing contrib repository](https://github.com/open-feature/python-sdk-contrib) available under the OpenFeature organization.
210+
You’ll then need to write the provider by implementing the `AbstractProvider` class exported by the OpenFeature SDK.
211+
212+
```python
213+
from typing import List, Optional
214+
215+
from openfeature.evaluation_context import EvaluationContext
216+
from openfeature.flag_evaluation import FlagResolutionDetails
217+
from openfeature.provider.provider import AbstractProvider
218+
219+
class MyProvider(AbstractProvider):
220+
def get_metadata(self) -> Metadata:
221+
...
222+
223+
def get_provider_hooks(self) -> List[Hook]:
224+
return []
225+
226+
def resolve_boolean_details(
227+
self,
228+
flag_key: str,
229+
default_value: bool,
230+
evaluation_context: Optional[EvaluationContext] = None,
231+
) -> FlagResolutionDetails[bool]:
232+
...
233+
234+
def resolve_string_details(
235+
self,
236+
flag_key: str,
237+
default_value: str,
238+
evaluation_context: Optional[EvaluationContext] = None,
239+
) -> FlagResolutionDetails[str]:
240+
...
241+
242+
def resolve_integer_details(
243+
self,
244+
flag_key: str,
245+
default_value: int,
246+
evaluation_context: Optional[EvaluationContext] = None,
247+
) -> FlagResolutionDetails[int]:
248+
...
249+
250+
def resolve_float_details(
251+
self,
252+
flag_key: str,
253+
default_value: float,
254+
evaluation_context: Optional[EvaluationContext] = None,
255+
) -> FlagResolutionDetails[float]:
256+
...
257+
258+
def resolve_object_details(
259+
self,
260+
flag_key: str,
261+
default_value: Union[dict, list],
262+
evaluation_context: Optional[EvaluationContext] = None,
263+
) -> FlagResolutionDetails[Union[dict, list]]:
264+
...
265+
```
266+
267+
> Built a new provider? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=provider&projects=&template=document-provider.yaml&title=%5BProvider%5D%3A+) so we can add it to the docs!
268+
269+
### Develop a hook
270+
271+
To develop a hook, you need to create a new project and include the OpenFeature SDK as a dependency.
272+
This can be a new repository or included in [the existing contrib repository](https://github.com/open-feature/python-sdk-contrib) available under the OpenFeature organization.
273+
Implement your own hook by creating a hook that inherits from the `Hook` class.
274+
Any of the evaluation life-cycle stages (`before`/`after`/`error`/`finally_after`) can be override to add the desired business logic.
275+
276+
```python
277+
from openfeature.hook import Hook
278+
279+
class MyHook(Hook):
280+
def after(self, hook_context: HookContext, details: FlagEvaluationDetails, hints: dict):
281+
print("This runs after the flag has been evaluated")
282+
283+
```
284+
285+
> Built a new hook? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=hook&projects=&template=document-hook.yaml&title=%5BHook%5D%3A+) so we can add it to the docs!
286+
287+
<!-- x-hide-in-docs-start -->
288+
289+
## ⭐️ Support the project
290+
291+
- Give this repo a ⭐️!
292+
- Follow us on social media:
293+
- Twitter: [@openfeature](https://twitter.com/openfeature)
294+
- LinkedIn: [OpenFeature](https://www.linkedin.com/company/openfeature/)
295+
- Join us on [Slack](https://cloud-native.slack.com/archives/C0344AANLA1)
296+
- For more, check out our [community page](https://openfeature.dev/community/)
297+
298+
## 🤝 Contributing
299+
300+
Interested in contributing? Great, we'd love your help! To get started, take a look at the [CONTRIBUTING](CONTRIBUTING.md) guide.
301+
302+
### Thanks to everyone who has already contributed
303+
304+
<a href="https://github.com/open-feature/python-sdk/graphs/contributors">
305+
<img src="https://contrib.rocks/image?repo=open-feature/python-sdk" alt="Pictures of the folks who have contributed to the project" />
306+
</a>
307+
308+
Made with [contrib.rocks](https://contrib.rocks).
309+
310+
<!-- x-hide-in-docs-end -->

0 commit comments

Comments
 (0)