-
Notifications
You must be signed in to change notification settings - Fork 24
Restructure modules #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
11fb716
dceeac7
b37c291
9f835db
a571579
2217e5f
05c7687
321626c
450289d
fd53f16
b3ecead
2abeae4
5388c08
c08878f
5acd63d
f725c85
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
[flake8] | ||
max-line-length = 88 | ||
max-line-length = 88 | ||
exclude = .venv/*,venv/*,.git,__pycache__ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# This workflow uses actions that are not certified by GitHub. | ||
# They are provided by a third-party and are governed by | ||
# separate terms of service, privacy policy, and support | ||
# documentation. | ||
|
||
name: Test | ||
|
||
on: | ||
push: | ||
branches: | ||
- '*' | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
container: [ "python:3.8", "python:3.9", "python:3.10" ] | ||
container: | ||
image: ${{ matrix.container }} | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Cache virtualenvironment | ||
uses: actions/cache@v2 | ||
with: | ||
path: ~/.venv | ||
key: ${{ hashFiles('requirements.txt', 'requirements-dev.txt') }} | ||
|
||
- name: Upgrade pip | ||
run: pip install --upgrade pip | ||
|
||
- name: Create and activate Virtualenv | ||
run: | | ||
pip install virtualenv | ||
[ ! -d ".venv" ] && virtualenv .venv | ||
. .venv/bin/activate | ||
|
||
- name: Install dependencies | ||
run: pip install -r requirements-dev.txt | ||
|
||
- name: Run black formatter check | ||
run: black --check . | ||
|
||
- name: Run flake8 formatter check | ||
run: flake8 . | ||
|
||
- name: Run isort formatter check | ||
run: isort . | ||
|
||
- name: Test with pytest | ||
run: pytest |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
from open_feature.flag_evaluation.error_code import ErrorCode | ||
|
||
|
||
class OpenFeatureError(Exception): | ||
""" | ||
A generic open feature exception, this exception should not be raised. Instead | ||
the more specific exceptions extending this one should be used. | ||
""" | ||
|
||
def __init__(self, error_message: str = None, error_code: ErrorCode = None): | ||
""" | ||
Constructor for the generic OpenFeatureError. | ||
@param error_message: a string message representing why the error has been | ||
raised | ||
@param error_code: the ErrorCode string enum value for the type of error | ||
@return: the generic OpenFeatureError exception | ||
""" | ||
self.error_message = error_message | ||
self.error_code = error_code | ||
|
||
|
||
class FlagNotFoundError(OpenFeatureError): | ||
""" | ||
This exception should be raised when the provider cannot find a flag with the | ||
key provided by the user. | ||
""" | ||
|
||
def __init__(self, error_message: str = None): | ||
""" | ||
Constructor for the FlagNotFoundError. The error code for | ||
this type of exception is ErrorCode.FLAG_NOT_FOUND. | ||
@param error_message: a string message representing why the error has been | ||
raised | ||
@return: the generic FlagNotFoundError exception | ||
""" | ||
super().__init__(error_message, ErrorCode.FLAG_NOT_FOUND) | ||
|
||
|
||
class GeneralError(OpenFeatureError): | ||
""" | ||
This exception should be raised when the for an exception within the open | ||
feature python sdk. | ||
""" | ||
|
||
def __init__(self, error_message: str = None): | ||
""" | ||
Constructor for the GeneralError. The error code for this type of exception | ||
is ErrorCode.GENERAL. | ||
@param error_message: a string message representing why the error has been | ||
raised | ||
@return: the generic GeneralError exception | ||
""" | ||
super().__init__(error_message, ErrorCode.GENERAL) | ||
|
||
|
||
class ParseError(OpenFeatureError): | ||
""" | ||
This exception should be raised when the flag returned by the provider cannot | ||
be parsed into a FlagEvaluationDetails object. | ||
""" | ||
|
||
def __init__(self, error_message: str = None): | ||
""" | ||
Constructor for the ParseError. The error code for this type of exception | ||
is ErrorCode.PARSE_ERROR. | ||
@param error_message: a string message representing why the error has been | ||
raised | ||
@return: the generic ParseError exception | ||
""" | ||
super().__init__(error_message, ErrorCode.PARSE_ERROR) | ||
|
||
|
||
class TypeMismatchError(OpenFeatureError): | ||
""" | ||
This exception should be raised when the flag returned by the provider does | ||
not match the type requested by the user. | ||
""" | ||
|
||
def __init__(self, error_message: str = None): | ||
""" | ||
Constructor for the TypeMismatchError. The error code for this type of | ||
exception is ErrorCode.TYPE_MISMATCH. | ||
@param error_message: a string message representing why the error has been | ||
raised | ||
@return: the generic TypeMismatchError exception | ||
""" | ||
super().__init__(error_message, ErrorCode.TYPE_MISMATCH) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,30 @@ | ||
# pyproject.toml | ||
[build-system] | ||
requires = ["setuptools>=61.0.0", "wheel"] | ||
build-backend = "setuptools.build_meta" | ||
|
||
[project] | ||
name = "python_open_feature_sdk" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We may want to change this - I'm not sure if there are any conventions we need to follow. But it's not important for this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Easy enough to change at another point There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. |
||
version = "0.0.1" | ||
description = "Standardizing Feature Flagging for Everyone" | ||
readme = "README.md" | ||
authors = [{ name = "Open Feature", email = "[email protected]" }] | ||
license = { file = "LICENSE" } | ||
classifiers = [ | ||
"License :: OSI Approved :: Apache", | ||
"Programming Language :: Python", | ||
"Programming Language :: Python :: 3", | ||
] | ||
keywords = [] | ||
dependencies = [] | ||
requires-python = ">=3.8" | ||
|
||
[project.optional-dependencies] | ||
dev = ["black", "flake8", "isort", "pip-tools", "pytest", "pre-commit"] | ||
|
||
[project.urls] | ||
Homepage = "https://github.com/open-feature/python-sdk" | ||
|
||
[tool.isort] | ||
profile = "black" | ||
multi_line_output = 3 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,65 @@ | ||
# Open Feature Python SDK | ||
This SDK is still in an experimental phase. | ||
# Open Feature SDK for Python | ||
[](https://www.repostatus.org/#wip) | ||
|
||
This is the Python implementation of [OpenFeature](https://openfeature.dev), a vendor-agnostic abstraction library for evaluating feature flags. | ||
|
||
We support multiple data types for flags (numbers, strings, booleans, objects) as well as hooks, which can alter the lifecycle of a flag evaluation. | ||
|
||
This library is intended to be used in server-side contexts and has not been evaluated for use in mobile devices. | ||
|
||
|
||
## Usage | ||
While Boolean provides the simplest introduction, we offer a variety of flag types. | ||
```python | ||
# Depending on the flag type, use one of the methods below | ||
flag_key = "PROVIDER_FLAG" | ||
boolean_result = open_feature_client.get_boolean_value(key=flag_key) | ||
number_result = open_feature_client.get_number_value(key=flag_key) | ||
string_result = open_feature_client.get_string_value(key=flag_key) | ||
object_result = open_feature_client.get_object_value(key=flag_key) | ||
``` | ||
Each provider class may have further setup required i.e. secret keys, environment variables etc | ||
|
||
## Requirements | ||
- Python 3.8+ | ||
|
||
## Installation | ||
### Add it to your build | ||
Pip install | ||
```bash | ||
pip install python-open-feature-sdk==0.0.1 | ||
``` | ||
|
||
requirements.txt | ||
```bash | ||
python-open-feature-sdk==0.0.1 | ||
``` | ||
```python | ||
pip install requirements.txt | ||
``` | ||
|
||
### Configure it | ||
In order to use the sdk there is some minor configuration. Follow the script below: | ||
|
||
```python | ||
from open_feature import open_feature_api | ||
|
||
open_feature_api.set_provider(NoOpProvider()) | ||
open_feature_client = open_feature_api.get_client() | ||
``` | ||
|
||
## Contacting us | ||
We hold regular meetings which you can see [here](https://github.com/open-feature/community/#meetings-and-events). | ||
|
||
We are also present on the `#openfeature` channel in the [CNCF slack](https://slack.cncf.io/). | ||
|
||
## Contributors | ||
|
||
Thanks so much to our contributors. | ||
|
||
<a href="https://github.com/open-feature/python-sdk/graphs/contributors"> | ||
<img src="https://contrib.rocks/image?repo=open-feature/python-sdk" /> | ||
</a> | ||
|
||
|
||
## How to use | ||
Made with [contrib.rocks](https://contrib.rocks). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,8 @@ | ||
pylint | ||
pep8 | ||
autopep8 | ||
pytest | ||
pytest-mock | ||
black | ||
pip-tools | ||
responses | ||
pre-commit | ||
flake8 | ||
pytest-mock |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import pytest | ||
|
||
from open_feature import open_feature_api as api | ||
from open_feature.provider.no_op_provider import NoOpProvider | ||
|
||
|
||
@pytest.fixture() | ||
def no_op_provider_client(): | ||
api.set_provider(NoOpProvider()) | ||
return api.get_client() |
Uh oh!
There was an error while loading. Please reload this page.