flagswitch-sdk 0.1.0__py3-none-any.whl
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.
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from flagswitch_sdk.client import FlagSwitch
|
|
2
|
+
from flagswitch_sdk.exceptions import (
|
|
3
|
+
FlagSwitchConnectionError,
|
|
4
|
+
FlagSwitchError,
|
|
5
|
+
InvalidApiKeyError,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"FlagSwitch",
|
|
10
|
+
"FlagSwitchError",
|
|
11
|
+
"InvalidApiKeyError",
|
|
12
|
+
"FlagSwitchConnectionError",
|
|
13
|
+
]
|
flagswitch_sdk/client.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import httpx
|
|
5
|
+
|
|
6
|
+
from flagswitch_sdk.exceptions import FlagSwitchConnectionError, InvalidApiKeyError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
_BASE_URL = "http://localhost:8010/api/fs"
|
|
10
|
+
_CACHE_TTL = 30
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FlagSwitch:
|
|
14
|
+
def __init__(self, api_key: str):
|
|
15
|
+
self._api_key = api_key
|
|
16
|
+
self._cache_ttl = _CACHE_TTL
|
|
17
|
+
self._cache: dict[str, Any] = {}
|
|
18
|
+
self._cache_ts: float = 0
|
|
19
|
+
|
|
20
|
+
def _is_cache_valid(self) -> bool:
|
|
21
|
+
return bool(self._cache) and (time.time() - self._cache_ts) < self._cache_ttl
|
|
22
|
+
|
|
23
|
+
async def _fetch_flags(self) -> dict[str, Any]:
|
|
24
|
+
try:
|
|
25
|
+
async with httpx.AsyncClient() as http:
|
|
26
|
+
response = await http.get(
|
|
27
|
+
f"{_BASE_URL}/evaluate",
|
|
28
|
+
headers={"X-Api-Key": self._api_key},
|
|
29
|
+
timeout=5.0,
|
|
30
|
+
)
|
|
31
|
+
except httpx.RequestError as e:
|
|
32
|
+
raise FlagSwitchConnectionError(f"Failed to reach FlagSwitch server: {e}")
|
|
33
|
+
|
|
34
|
+
if response.status_code == 401:
|
|
35
|
+
raise InvalidApiKeyError("Invalid or inactive API key.")
|
|
36
|
+
|
|
37
|
+
if response.status_code != 200:
|
|
38
|
+
raise FlagSwitchConnectionError(
|
|
39
|
+
f"Unexpected response from FlagSwitch: {response.status_code}"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
payload = response.json()
|
|
43
|
+
return payload.get("data") or {}
|
|
44
|
+
|
|
45
|
+
async def _get_flags(self) -> dict[str, Any]:
|
|
46
|
+
if self._is_cache_valid():
|
|
47
|
+
return self._cache
|
|
48
|
+
|
|
49
|
+
flags = await self._fetch_flags()
|
|
50
|
+
self._cache = flags
|
|
51
|
+
self._cache_ts = time.time()
|
|
52
|
+
return flags
|
|
53
|
+
|
|
54
|
+
async def is_enabled(self, key: str, default: bool = False) -> bool:
|
|
55
|
+
flags = await self._get_flags()
|
|
56
|
+
return bool(flags.get(key, default))
|
|
57
|
+
|
|
58
|
+
async def get_all_flags(self) -> dict[str, Any]:
|
|
59
|
+
return await self._get_flags()
|
|
60
|
+
|
|
61
|
+
def invalidate_cache(self) -> None:
|
|
62
|
+
self._cache = {}
|
|
63
|
+
self._cache_ts = 0
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
flagswitch_sdk/__init__.py,sha256=M2Tzsh6QBcMT0CYH42pFk9lh1EN5W178WdNLXARmuY0,278
|
|
2
|
+
flagswitch_sdk/client.py,sha256=2E6I6zU-k4degIn8euqT7E-alLVhrqR0zk4fiecd-Tw,1921
|
|
3
|
+
flagswitch_sdk/exceptions.py,sha256=1U7kIpG7gpDWlNUTY0DMSu7jvyQNthd6uKAvUWznlTI,158
|
|
4
|
+
flagswitch_sdk-0.1.0.dist-info/METADATA,sha256=1i9JSx55Gb-TKFZzDtHgzwY9V1lA5f_0MLEymtjW3HA,168
|
|
5
|
+
flagswitch_sdk-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
6
|
+
flagswitch_sdk-0.1.0.dist-info/top_level.txt,sha256=HBU_4eNfY6K1zhUZ0MivKVIjO1hKA0t9OnXe2ga0-mA,15
|
|
7
|
+
flagswitch_sdk-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flagswitch_sdk
|