Package: openfeature-sdk
OpenFeature Python SDKOpenFeatureis an open specification that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool.🚀 Quick startRequirementsPython 3.8+InstallPip installpipinstallopenfeature-sdk==0.5.0requirements.txtopenfeature-sdk==0.5.0pipinstall-rrequirements.txtUsagefromopenfeatureimportapifromopenfeature.provider.in_memory_providerimportInMemoryFlag,InMemoryProvider# flags defined in memorymy_flags={"v2_enabled":InMemoryFlag("on",{"on":True,"off":False})}# configure a providerapi.set_provider(InMemoryProvider(my_flags))# create a clientclient=api.get_client()# get a bool flag valueflag_value=client.get_boolean_value("v2_enabled",False)print("Value: "+str(flag_value))🌟 FeaturesStatusFeaturesDescription✅ProvidersIntegrate with a commercial, open source, or in-house feature management tool.✅TargetingContextually-aware flag evaluation usingevaluation context.✅HooksAdd functionality to various stages of the flag evaluation life-cycle.✅LoggingIntegrate with popular logging packages.✅DomainsLogically bind clients with providers.❌EventingReact to state changes in the provider or flag management system.✅ShutdownGracefully clean up a provider during application shutdown.✅ExtendingExtend OpenFeature with custom providers and hooks.Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌ProvidersProvidersare an abstraction between a flag management system and the OpenFeature SDK.
Lookherefor a complete list of available providers.
If the provider you're looking for hasn't been created yet, see thedevelop a providersection to learn how to build it yourself.Once you've added a provider as a dependency, it can be registered with OpenFeature like this:fromopenfeatureimportapifromopenfeature.provider.no_op_providerimportNoOpProviderapi.set_provider(NoOpProvider())open_feature_client=api.get_client()In some situations, it may be beneficial to register multiple providers in the same application.
This is possible usingdomains, which is covered in more detail below.TargetingSometimes, 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.
In OpenFeature, we refer to this astargeting.
If the flag management system you're using supports targeting, you can provide the input data using theevaluation context.fromopenfeature.apiimport(get_client,get_provider,set_provider,get_evaluation_context,set_evaluation_context,)global_context=EvaluationContext(targeting_key="targeting_key1",attributes={"application":"value1"})request_context=EvaluationContext(targeting_key="targeting_key2",attributes={"email":request.form['email']})## set global contextset_evaluation_context(global_context)# merge second contextclient=get_client(name="No-op Provider")client.get_string_value("email","fallback",request_context)HooksHooksallow for custom logic to be added at well-defined points of the flag evaluation life-cycle.
Lookherefor a complete list of available hooks.
If the hook you're looking for hasn't been created yet, see thedevelop a hooksection to learn how to build it yourself.Once you've added a hook as a dependency, it can be registered at the global, client, or flag invocation level.fromopenfeature.apiimportadd_hooksfromopenfeature.flag_evaluationimportFlagEvaluationOptions# set global hooks at the API-leveladd_hooks([MyHook()])# or configure them in the clientclient=OpenFeatureClient()client.add_hooks([MyHook()])# or at the invocation-leveloptions=FlagEvaluationOptions(hooks=[MyHook()])client.get_boolean_flag("my-flag",False,flag_evaluation_options=options)LoggingThe OpenFeature SDK logs to theopenfeaturelogger using theloggingpackage from the Python Standard Library.DomainsClients can be assigned to a domain.
A domain is a logical identifier which can be used to associate clients with a particular provider.
If a domain has no associated provider, the global provider is used.fromopenfeatureimportapi# Registering the default providerapi.set_provider(MyProvider());# Registering a provider to a domainapi.set_provider(MyProvider(),"my-domain");# A client bound to the default providerdefault_client=api.get_client();# A client bound to the MyProvider providerdomain_scoped_client=api.get_client("my-domain");Domains can be defined on a provider during registration.
For more details, please refer to theproviderssection.EventingEvents are not yet available in the Python SDK. Progress on this feature can be trackedhere.ShutdownThe OpenFeature API provides a shutdown function to perform a cleanup of all registered providers. This should only be called when your application is in the process of shutting down.fromopenfeatureimportapiapi.shutdown()ExtendingDevelop a providerTo develop a provider, you need to create a new project and include the OpenFeature SDK as a dependency.
This can be a new repository or included inthe existing contrib repositoryavailable under the OpenFeature organization.
You’ll then need to write the provider by implementing theAbstractProviderclass exported by the OpenFeature SDK.fromtypingimportList,Optionalfromopenfeature.evaluation_contextimportEvaluationContextfromopenfeature.flag_evaluationimportFlagResolutionDetailsfromopenfeature.provider.providerimportAbstractProviderclassMyProvider(AbstractProvider):defget_metadata(self)->Metadata:...defget_provider_hooks(self)->List[Hook]:return[]defresolve_boolean_details(self,flag_key:str,default_value:bool,evaluation_context:Optional[EvaluationContext]=None,)->FlagResolutionDetails[bool]:...defresolve_string_details(self,flag_key:str,default_value:str,evaluation_context:Optional[EvaluationContext]=None,)->FlagResolutionDetails[str]:...defresolve_integer_details(self,flag_key:str,default_value:int,evaluation_context:Optional[EvaluationContext]=None,)->FlagResolutionDetails[int]:...defresolve_float_details(self,flag_key:str,default_value:float,evaluation_context:Optional[EvaluationContext]=None,)->FlagResolutionDetails[float]:...defresolve_object_details(self,flag_key:str,default_value:Union[dict,list],evaluation_context:Optional[EvaluationContext]=None,)->FlagResolutionDetails[Union[dict,list]]:...Built a new provider?Let us knowso we can add it to the docs!Develop a hookTo develop a hook, you need to create a new project and include the OpenFeature SDK as a dependency.
This can be a new repository or included inthe existing contrib repositoryavailable under the OpenFeature organization.
Implement your own hook by creating a hook that inherits from theHookclass.
Any of the evaluation life-cycle stages (before/after/error/finally_after) can be override to add the desired business logic.fromopenfeature.hookimportHookclassMyHook(Hook):defafter(self,hook_context:HookContext,details:FlagEvaluationDetails,hints:dict):print("This runs after the flag has been evaluated")Built a new hook?Let us knowso we can add it to the docs!⭐️ Support the projectGive this repo a ⭐️!Follow us on social media:Twitter:@openfeatureLinkedIn:OpenFeatureJoin us onSlackFor more, check out ourcommunity page🤝 ContributingInterested in contributing? Great, we'd love your help! To get started, take a look at theCONTRIBUTINGguide.Thanks to everyone who has already contributedMade withcontrib.rocks.