Skip to content

Commit

Permalink
Merge pull request #12 from KuzmenkoAlexey/add-python-313
Browse files Browse the repository at this point in the history
Add tests for Python3.13, update libs
  • Loading branch information
kindermax authored Feb 4, 2025
2 parents 0f6b1a3 + 4353d25 commit 98c49ee
Show file tree
Hide file tree
Showing 19 changed files with 667 additions and 452 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
strategy:
matrix:
python-version: [3.7]
python-version: [3.9]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.9, "3.10", 3.11, 3.12]
python-version: [3.9, "3.10", 3.11, 3.12, 3.13]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion featureflags_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.6.1"
__version__ = "0.6.2"
11 changes: 6 additions & 5 deletions featureflags_client/http/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections.abc import Generator
from contextlib import contextmanager
from typing import Any, Dict, Generator, Optional, Union, cast
from typing import Any, Optional, Union, cast

from featureflags_client.http.flags import Flags
from featureflags_client.http.managers.base import (
Expand All @@ -20,9 +21,9 @@ def __init__(self, manager: BaseManager) -> None:
@contextmanager
def flags(
self,
ctx: Optional[Dict[str, Any]] = None,
ctx: Optional[dict[str, Any]] = None,
*,
overrides: Optional[Dict[str, bool]] = None,
overrides: Optional[dict[str, bool]] = None,
) -> Generator[Flags, None, None]:
"""
Context manager to wrap your request handling code and get actual
Expand All @@ -33,9 +34,9 @@ def flags(
@contextmanager
def values(
self,
ctx: Optional[Dict[str, Any]] = None,
ctx: Optional[dict[str, Any]] = None,
*,
overrides: Optional[Dict[str, Union[int, str]]] = None,
overrides: Optional[dict[str, Union[int, str]]] = None,
) -> Generator[Values, None, None]:
"""
Context manager to wrap your request handling code and get actual
Expand Down
50 changes: 27 additions & 23 deletions featureflags_client/http/conditions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
import re
from typing import Any, Callable, Dict, List, Optional, Set, Union
from typing import Any, Callable, Optional, Union

from featureflags_client.http.types import Check, Flag, Operator, Value
from featureflags_client.http.utils import hash_flag_value
Expand All @@ -10,12 +10,12 @@
_UNDEFINED = object()


def false(_ctx: Dict[str, Any]) -> bool:
def false(_ctx: dict[str, Any]) -> bool:
return False


def except_false(func: Callable) -> Callable:
def wrapper(ctx: Dict[str, Any]) -> Any:
def wrapper(ctx: dict[str, Any]) -> Any:
try:
return func(ctx)
except (TypeError, ValueError):
Expand All @@ -26,15 +26,15 @@ def wrapper(ctx: Dict[str, Any]) -> Any:

def equal(name: str, value: Any) -> Callable:
@except_false
def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
return ctx.get(name, _UNDEFINED) == value

return proc


def less_than(name: str, value: Any) -> Callable:
@except_false
def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
ctx_val = ctx.get(name, _UNDEFINED)
return ctx_val is not _UNDEFINED and ctx_val < value

Expand All @@ -43,7 +43,7 @@ def proc(ctx: Dict[str, Any]) -> bool:

def less_or_equal(name: str, value: Any) -> Callable:
@except_false
def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
ctx_val = ctx.get(name, _UNDEFINED)
return ctx_val is not _UNDEFINED and ctx_val <= value

Expand All @@ -52,7 +52,7 @@ def proc(ctx: Dict[str, Any]) -> bool:

def greater_than(name: str, value: Any) -> Callable:
@except_false
def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
ctx_val = ctx.get(name, _UNDEFINED)
return ctx_val is not _UNDEFINED and ctx_val > value

Expand All @@ -61,7 +61,7 @@ def proc(ctx: Dict[str, Any]) -> bool:

def greater_or_equal(name: str, value: Any) -> Callable:
@except_false
def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
ctx_val = ctx.get(name, _UNDEFINED)
return ctx_val is not _UNDEFINED and ctx_val >= value

Expand All @@ -70,15 +70,15 @@ def proc(ctx: Dict[str, Any]) -> bool:

def contains(name: str, value: Any) -> Callable:
@except_false
def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
return value in ctx.get(name, "")

return proc


def percent(name: str, value: Any) -> Callable:
@except_false
def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
ctx_val = ctx.get(name, _UNDEFINED)
if ctx_val is _UNDEFINED:
return False
Expand All @@ -91,7 +91,7 @@ def proc(ctx: Dict[str, Any]) -> bool:

def regexp(name: str, value: Any) -> Callable:
@except_false
def proc(ctx: Dict[str, Any], _re: re.Pattern = re.compile(value)) -> bool:
def proc(ctx: dict[str, Any], _re: re.Pattern = re.compile(value)) -> bool:
return _re.match(ctx.get(name, "")) is not None

return proc
Expand All @@ -106,7 +106,7 @@ def subset(name: str, value: Any) -> Callable:
if value:

@except_false
def proc(ctx: Dict[str, Any], _value: Optional[Set] = None) -> bool:
def proc(ctx: dict[str, Any], _value: Optional[set] = None) -> bool:
_value = _value or set(value)
ctx_val = ctx.get(name)
return bool(ctx_val) and _value.issuperset(ctx_val)
Expand All @@ -121,7 +121,7 @@ def superset(name: str, value: Any) -> Callable:
if value:

@except_false
def proc(ctx: Dict[str, Any], _value: Optional[Set] = None) -> bool:
def proc(ctx: dict[str, Any], _value: Optional[set] = None) -> bool:
_value = _value or set(value)
ctx_val = ctx.get(name)
return bool(ctx_val) and _value.issubset(ctx_val)
Expand All @@ -132,7 +132,7 @@ def proc(ctx: Dict[str, Any], _value: Optional[Set] = None) -> bool:
return proc


OPERATIONS_MAP: Dict[Operator, Callable[..., Callable[..., bool]]] = {
OPERATIONS_MAP: dict[Operator, Callable[..., Callable[..., bool]]] = {
Operator.EQUAL: equal,
Operator.LESS_THAN: less_than,
Operator.LESS_OR_EQUAL: less_or_equal,
Expand Down Expand Up @@ -177,7 +177,7 @@ def flag_proc(flag: Flag) -> Optional[Callable]:

if flag.enabled and conditions:

def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
return any(
all(check(ctx) for check in checks) for checks in conditions
)
Expand All @@ -187,13 +187,13 @@ def proc(ctx: Dict[str, Any]) -> bool:
f"Flag[{flag.name}] is disabled or do not have any conditions"
)

def proc(ctx: Dict[str, Any]) -> bool:
def proc(ctx: dict[str, Any]) -> bool:
return flag.enabled

return proc


def update_flags_state(flags: List[Flag]) -> Dict[str, Callable[..., bool]]:
def update_flags_state(flags: list[Flag]) -> dict[str, Callable[..., bool]]:
"""
Assign a proc to each flag which has to be computed.
"""
Expand All @@ -215,13 +215,17 @@ def str_to_int(value: Union[int, str]) -> Union[int, str]:
return value


def value_proc(value: Value) -> Union[Callable, int, str]:
def value_proc(value: Value) -> Union[Callable[..., Union[int, str]]]:
if not value.overridden:
# Value was not overridden on server, use value from defaults.
log.debug(
f"Value[{value.name}] is not override yet, using default value"
)
return str_to_int(value.value_default)

def proc(ctx: dict[str, Any]) -> Union[int, str]:
return str_to_int(value.value_default)

return proc

conditions = []
for condition in value.conditions:
Expand All @@ -239,7 +243,7 @@ def value_proc(value: Value) -> Union[Callable, int, str]:

if value.enabled and conditions:

def proc(ctx: Dict[str, Any]) -> Union[int, str]:
def proc(ctx: dict[str, Any]) -> Union[int, str]:
for condition_value_override, checks in conditions:
if all(check(ctx) for check in checks):
return str_to_int(condition_value_override)
Expand All @@ -250,15 +254,15 @@ def proc(ctx: Dict[str, Any]) -> Union[int, str]:
f"Value[{value.name}] is disabled or do not have any conditions"
)

def proc(ctx: Dict[str, Any]) -> Union[int, str]:
def proc(ctx: dict[str, Any]) -> Union[int, str]:
return str_to_int(value.value_override)

return proc


def update_values_state(
values: List[Value],
) -> Dict[str, Callable[..., Union[int, str]]]:
values: list[Value],
) -> dict[str, Callable[..., Union[int, str]]]:
"""
Assign a proc to each values which has to be computed.
"""
Expand Down
6 changes: 3 additions & 3 deletions featureflags_client/http/flags.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Dict, Optional
from typing import Any, Optional

from featureflags_client.http.managers.base import BaseManager

Expand All @@ -11,8 +11,8 @@ class Flags:
def __init__(
self,
manager: BaseManager,
ctx: Optional[Dict[str, Any]] = None,
overrides: Optional[Dict[str, bool]] = None,
ctx: Optional[dict[str, Any]] = None,
overrides: Optional[dict[str, bool]] = None,
) -> None:
self._manager = manager
self._defaults = manager.defaults
Expand Down
12 changes: 6 additions & 6 deletions featureflags_client/http/managers/aiohttp.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from enum import EnumMeta
from typing import Any, Dict, List, Optional, Type, Union
from typing import Any, Optional, Union

from featureflags_client.http.constants import Endpoints
from featureflags_client.http.managers.base import (
Expand Down Expand Up @@ -28,10 +28,10 @@ def __init__( # noqa: PLR0913
self,
url: str,
project: str,
variables: List[Variable],
defaults: Union[EnumMeta, Type, Dict[str, bool]],
variables: list[Variable],
defaults: Union[EnumMeta, type, dict[str, bool]],
values_defaults: Optional[
Union[EnumMeta, Type, Dict[str, Union[int, str]]]
Union[EnumMeta, type, dict[str, Union[int, str]]]
] = None,
request_timeout: int = 5,
refresh_interval: int = 10,
Expand All @@ -53,9 +53,9 @@ async def close(self) -> None:
async def _post( # type: ignore
self,
url: Endpoints,
payload: Dict[str, Any],
payload: dict[str, Any],
timeout: int,
) -> Dict[str, Any]:
) -> dict[str, Any]:
async with self._session.post(
url=url.value,
json=payload,
Expand Down
Loading

0 comments on commit 98c49ee

Please sign in to comment.