-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #117 from KozyarValeriy/feat-add-async-python-client
feat: add async python client
- Loading branch information
Showing
26 changed files
with
1,067 additions
and
255 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
format: | ||
poetry run ruff flipt tests --fix | ||
poetry run black flipt tests | ||
|
||
lint: | ||
poetry run ruff flipt tests | ||
poetry run black flipt tests --check | ||
poetry run mypy flipt | ||
poetry run pytest --dead-fixtures | ||
|
||
test: | ||
poetry run pytest --cov | ||
|
||
testcov: | ||
poetry run pytest --cov --cov-report html | ||
|
||
check: format lint test | ||
|
||
.PHONY: format lint test check testcov |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import asyncio | ||
|
||
from flipt import AsyncFliptClient | ||
from flipt.evaluation import BatchEvaluationRequest, EvaluationRequest | ||
|
||
|
||
async def main(): | ||
flipt_client = AsyncFliptClient() | ||
|
||
variant_flag = await flipt_client.evaluation.variant( | ||
EvaluationRequest( | ||
namespace_key="default", | ||
flag_key="flag1", | ||
entity_id="entity", | ||
context={"fizz": "buzz"}, | ||
) | ||
) | ||
boolean_flag = await flipt_client.evaluation.boolean( | ||
EvaluationRequest( | ||
namespace_key="default", | ||
flag_key="flag_boolean", | ||
entity_id="entity", | ||
context={"fizz": "buzz"}, | ||
) | ||
) | ||
batch = await flipt_client.evaluation.batch( | ||
BatchEvaluationRequest( | ||
requests=[ | ||
EvaluationRequest( | ||
namespace_key="default", | ||
flag_key="flag1", | ||
entity_id="entity", | ||
context={"fizz": "buzz"}, | ||
), | ||
EvaluationRequest( | ||
namespace_key="default", | ||
flag_key="flag_boolean", | ||
entity_id="entity", | ||
context={"fizz": "buzz"}, | ||
), | ||
] | ||
) | ||
) | ||
|
||
print(variant_flag) | ||
print(boolean_flag) | ||
print(batch) | ||
|
||
|
||
loop = asyncio.new_event_loop() | ||
loop.run_until_complete(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,7 @@ | ||
import typing | ||
from .evaluation import Evaluation | ||
from .authentication import AuthenticationStrategy | ||
from .async_client import AsyncFliptClient | ||
from .sync_client import FliptClient | ||
|
||
|
||
class FliptClient: | ||
def __init__( | ||
self, | ||
url: str = "http://localhost:8080", | ||
timeout: int = 60, | ||
authentication: typing.Optional[AuthenticationStrategy] = None, | ||
): | ||
self.evaluation = Evaluation(url, timeout, authentication) | ||
__all__ = [ | ||
'FliptClient', | ||
'AsyncFliptClient', | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import httpx | ||
|
||
from .authentication import AuthenticationStrategy | ||
from .evaluation import AsyncEvaluation | ||
|
||
|
||
class AsyncFliptClient: | ||
def __init__( | ||
self, | ||
url: str = "http://localhost:8080", | ||
timeout: int = 60, | ||
authentication: AuthenticationStrategy | None = None, | ||
): | ||
self.httpx_client = httpx.AsyncClient(timeout=timeout) | ||
|
||
self.evaluation = AsyncEvaluation(url, authentication, self.httpx_client) | ||
|
||
async def close(self) -> None: | ||
await self.httpx_client.aclose() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,19 @@ | ||
class AuthenticationStrategy: | ||
def authenticate(self, headers: dict): | ||
def authenticate(self, headers: dict[str, str]) -> None: | ||
raise NotImplementedError() | ||
|
||
|
||
class ClientTokenAuthentication(AuthenticationStrategy): | ||
def __init__(self, token: str): | ||
def __init__(self, token: str) -> None: | ||
self.token = token | ||
|
||
def authenticate(self, headers: dict): | ||
def authenticate(self, headers: dict[str, str]) -> None: | ||
headers["Authorization"] = f"Bearer {self.token}" | ||
|
||
|
||
class JWTAuthentication(AuthenticationStrategy): | ||
def __init__(self, token: str): | ||
def __init__(self, token: str) -> None: | ||
self.token = token | ||
|
||
def authenticate(self, headers: dict): | ||
def authenticate(self, headers: dict[str, str]) -> None: | ||
headers["Authorization"] = f"JWT {self.token}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,85 +1,29 @@ | ||
import httpx | ||
import typing | ||
import json | ||
from .async_evaluation_client import AsyncEvaluation | ||
from .models import ( | ||
BatchEvaluationRequest, | ||
BatchEvaluationResponse, | ||
BooleanEvaluationResponse, | ||
ErrorEvaluationReason, | ||
ErrorEvaluationResponse, | ||
EvaluationReason, | ||
EvaluationRequest, | ||
EvaluationResponse, | ||
EvaluationResponseType, | ||
VariantEvaluationResponse, | ||
) | ||
from ..authentication import AuthenticationStrategy | ||
|
||
|
||
class Evaluation: | ||
def __init__( | ||
self, | ||
url: str, | ||
timeout: int, | ||
authentication: typing.Optional[AuthenticationStrategy] = None, | ||
): | ||
self.url = url | ||
self.headers = {} | ||
self.timeout = timeout | ||
if authentication: | ||
authentication.authenticate(self.headers) | ||
|
||
def variant(self, request: EvaluationRequest) -> VariantEvaluationResponse: | ||
response = httpx.post( | ||
f"{self.url}/evaluate/v1/variant", | ||
headers=self.headers, | ||
json=request.model_dump(), | ||
timeout=self.timeout, | ||
) | ||
|
||
if response.status_code != 200: | ||
body = response.json() | ||
message = "internal error" | ||
|
||
if "message" in body: | ||
message = body["message"] | ||
|
||
raise Exception(message) | ||
|
||
variant_response = json.dumps(response.json()).encode("utf-8") | ||
return VariantEvaluationResponse.model_validate_json(variant_response) | ||
|
||
def boolean(self, request: EvaluationRequest) -> BooleanEvaluationResponse: | ||
response = httpx.post( | ||
f"{self.url}/evaluate/v1/boolean", | ||
headers=self.headers, | ||
json=request.model_dump(), | ||
timeout=self.timeout, | ||
) | ||
|
||
if response.status_code != 200: | ||
body = response.json() | ||
message = "internal error" | ||
|
||
if "message" in body: | ||
message = body["message"] | ||
|
||
raise Exception(message) | ||
|
||
boolean_response = json.dumps(response.json()).encode("utf-8") | ||
return BooleanEvaluationResponse.model_validate_json(boolean_response) | ||
|
||
def batch(self, request: BatchEvaluationRequest) -> BatchEvaluationResponse: | ||
response = httpx.post( | ||
f"{self.url}/evaluate/v1/batch", | ||
headers=self.headers, | ||
json=request.model_dump(), | ||
timeout=self.timeout, | ||
) | ||
|
||
if response.status_code != 200: | ||
body = response.json() | ||
message = "internal error" | ||
|
||
if "message" in body: | ||
message = body["message"] | ||
|
||
raise Exception(message) | ||
|
||
batch_response = json.dumps(response.json()).encode("utf-8") | ||
return BatchEvaluationResponse.model_validate_json(batch_response) | ||
from .sync_evaluation_client import Evaluation | ||
|
||
__all__ = [ | ||
'Evaluation', | ||
'AsyncEvaluation', | ||
'EvaluationResponseType', | ||
'EvaluationReason', | ||
'ErrorEvaluationReason', | ||
'EvaluationRequest', | ||
'BatchEvaluationRequest', | ||
'VariantEvaluationResponse', | ||
'BooleanEvaluationResponse', | ||
'ErrorEvaluationResponse', | ||
'EvaluationResponse', | ||
'BatchEvaluationResponse', | ||
] |
Oops, something went wrong.