Skip to content

Commit

Permalink
Merge pull request #2 from Jonxslays/issue/1
Browse files Browse the repository at this point in the history
Add support for update key
  • Loading branch information
Jonxslays committed Jul 23, 2023
2 parents 3c333fd + 7a8180c commit c6002d9
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 16 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## v0.4.0 (Jul 2023)

### Additions

- Add `UNDEFINED`, `UndefinedOr`, and `UndefinedNoneOr` types.
- Add `update_key` method to key service.
- Add `name` parameter to the `create_key` method.

### Changes

- Refactor existing methods to use the new `UNDEFINED` type.

---

## v0.3.0 (Jul 2023)

### Bugfixes
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "unkey.py"
version = "0.3.0"
version = "0.4.0"
description = "An asynchronous Python SDK for unkey.dev."
authors = ["Jonxslays"]
license = "GPL-3.0-only"
Expand Down
Empty file added tests/services/__init__.py
Empty file.
31 changes: 31 additions & 0 deletions tests/services/test_base_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from __future__ import annotations

from unittest import mock

import pytest

from unkey import UNDEFINED
from unkey import BaseService


@pytest.fixture()
def service() -> BaseService:
return BaseService(mock.Mock(), mock.Mock())


def test_generate_map(service: BaseService) -> None:
result = service._generate_map(one=1, two=2) # type: ignore

assert result == {"one": 1, "two": 2}


def test_generate_map_with_undefined(service: BaseService) -> None:
result = service._generate_map(one=1, two=UNDEFINED) # type: ignore

assert result == {"one": 1}


def test_generate_map_with_none(service: BaseService) -> None:
result = service._generate_map(one=1, two=None) # type: ignore

assert result == {"one": 1, "two": None}
100 changes: 100 additions & 0 deletions tests/test_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,103 @@ def test_to_ratelimit(
result = serializer.to_ratelimit(raw_ratelimit)

assert result == full_ratelimit


#################
# to_api_key_meta
#################


def _raw_api_key_meta() -> DictT:
return {
"id": "fxc_DDD",
"meta": {"test": 1},
"start": "fxc",
"apiId": "api_FFF",
"expires": 123,
"remaining": 12,
"ownerId": "jonxslays",
"createdAt": 456,
"workspaceId": "ws_GGG",
"ratelimit": {
"type": "fast",
"limit": 1,
"refillRate": 2,
"refillInterval": 3,
},
}


@pytest.fixture()
def raw_api_key_meta() -> DictT:
return _raw_api_key_meta()


def _full_api_key_meta() -> models.ApiKeyMeta:
model = models.ApiKeyMeta()
model.id = "fxc_DDD"
model.meta = {"test": 1}
model.start = "fxc"
model.api_id = "api_FFF"
model.expires = 123
model.remaining = 12
model.owner_id = "jonxslays"
model.created_at = 456
model.workspace_id = "ws_GGG"
model.ratelimit = models.Ratelimit(
models.RatelimitType.Fast,
limit=1,
refill_rate=2,
refill_interval=3,
)

return model


@pytest.fixture()
def full_api_key_meta() -> models.ApiKeyMeta:
return _full_api_key_meta()


def test_to_api_key_meta(
raw_api_key_meta: DictT,
full_api_key_meta: models.ApiKeyMeta,
) -> None:
result = serializer.to_api_key_meta(raw_api_key_meta)

assert result == full_api_key_meta


#################
# to_api_key_list
#################


def _raw_api_key_list() -> DictT:
return {"total": 1, "keys": [_raw_api_key_meta()]}


@pytest.fixture()
def raw_api_key_list() -> DictT:
return _raw_api_key_list()


def _full_api_key_list() -> models.ApiKeyList:
model = models.ApiKeyList()
model.total = 1
model.keys = [_full_api_key_meta()]
return model


@pytest.fixture()
def full_api_key_list() -> models.ApiKeyList:
return _full_api_key_list()


def test_to_api_key_list(
raw_api_key_list: DictT,
full_api_key_list: models.ApiKeyList,
) -> None:
result = serializer.to_api_key_list(raw_api_key_list)

assert result == full_api_key_list
9 changes: 8 additions & 1 deletion unkey/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Final

__packagename__: Final[str] = "unkey.py"
__version__: Final[str] = "0.3.0"
__version__: Final[str] = "0.4.0"
__author__: Final[str] = "Jonxslays"
__copyright__: Final[str] = "2023-present Jonxslays"
__description__: Final[str] = "An asynchronous Python SDK for unkey.dev."
Expand All @@ -21,13 +21,15 @@
from . import routes
from . import serializer
from . import services
from . import undefined
from .client import *
from .errors import *
from .models import *
from .result import *
from .routes import *
from .serializer import *
from .services import *
from .undefined import *

__all__ = (
"client",
Expand All @@ -38,6 +40,7 @@
"routes",
"serializer",
"services",
"undefined",
"Api",
"ApiKey",
"ApiKeyList",
Expand All @@ -55,11 +58,15 @@
"HttpResponse",
"HttpService",
"KeyService",
"MissingRequiredArgument",
"Ok",
"Ratelimit",
"RatelimitType",
"Result",
"Route",
"Serializer",
"UndefinedNoneOr",
"UndefinedOr",
"UnwrapError",
"UNDEFINED",
)
16 changes: 11 additions & 5 deletions unkey/errors.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

__all__ = ("UnwrapError", "BaseError")
__all__ = ("BaseError", "MissingRequiredArgument", "UnwrapError")


class BaseError(Exception):
Expand All @@ -10,12 +10,18 @@ class BaseError(Exception):


class UnwrapError(BaseError):
"""Raised when calling unwrap or unwrap_err incorrectly.
message: The error message.
"""
"""Raised when calling unwrap or unwrap_err incorrectly."""

__slots__ = ()

def __init__(self, message: str) -> None:
super().__init__(f"Unwrap failed: {message}")


class MissingRequiredArgument(BaseError):
"""Raised when a required argument is missing."""

__slots__ = ()

def __init__(self, message: str) -> None:
super().__init__(f"Missing required argument: {message}")
1 change: 1 addition & 0 deletions unkey/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def compile(self, *args: t.Union[str, int]) -> CompiledRoute:
CREATE_KEY: t.Final[Route] = Route(c.POST, "/keys")
VERIFY_KEY: t.Final[Route] = Route(c.POST, "/keys/verify")
REVOKE_KEY: t.Final[Route] = Route(c.DELETE, "/keys/{}")
UPDATE_KEY: t.Final[Route] = Route(c.PUT, "/keys/{}")

# Apis
GET_API: t.Final[Route] = Route(c.GET, "/apis/{}")
Expand Down
8 changes: 7 additions & 1 deletion unkey/services/apis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from unkey import models
from unkey import result
from unkey import routes
from unkey import undefined

from . import BaseService

Expand Down Expand Up @@ -46,7 +47,12 @@ async def get_api(self, api_id: str) -> ResultT[models.Api]:
return result.Ok(self._serializer.to_api(data))

async def list_keys(
self, api_id: str, *, owner_id: t.Optional[str] = None, limit: int = 100, offset: int = 0
self,
api_id: str,
*,
owner_id: undefined.UndefinedOr[str] = undefined.UNDEFINED,
limit: int = 100,
offset: int = 0,
) -> ResultT[models.ApiKeyList]:
"""Gets a paginated list of keys for the given api.
Expand Down
8 changes: 5 additions & 3 deletions unkey/services/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from datetime import datetime
from datetime import timedelta

from unkey import undefined

if t.TYPE_CHECKING:
from unkey import serializer

Expand All @@ -30,13 +32,13 @@ def __init__(self, http_service: HttpService, serializer: serializer.Serializer)
self._serializer = serializer

def _generate_map(self, **kwargs: t.Any) -> t.Dict[str, t.Any]:
return {k: v for k, v in kwargs.items() if v is not None}
return {k: v for k, v in kwargs.items() if v is not undefined.UNDEFINED}

def _expires_in(
self, *, milliseconds: int = 0, seconds: int = 0, minutes: int = 0, days: int = 0
) -> int | None:
) -> undefined.UndefinedOr[int]:
if not any({milliseconds, seconds, minutes, days}):
return None
return undefined.UNDEFINED

delta = timedelta(days=days, minutes=minutes, seconds=seconds, milliseconds=milliseconds)
return int((datetime.now() + delta).timestamp()) * 1000
Loading

0 comments on commit c6002d9

Please sign in to comment.