• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SwissDataScienceCenter / renku-data-services / 12116288219

02 Dec 2024 09:22AM UTC coverage: 85.851%. Remained the same
12116288219

Pull #541

github

web-flow
Merge 8665a1434 into c671649df
Pull Request #541: feat: add kpack k8s resources

232 of 243 new or added lines in 11 files covered. (95.47%)

3 existing lines in 3 files now uncovered.

14502 of 16892 relevant lines covered (85.85%)

1.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.36
/components/renku_data_services/base_api/misc.py
1
"""Common blueprints."""
2

3
from collections.abc import Awaitable, Callable, Coroutine
2✔
4
from dataclasses import dataclass
2✔
5
from functools import wraps
2✔
6
from typing import Any, Concatenate, NoReturn, ParamSpec, TypeVar, cast
2✔
7

8
from pydantic import BaseModel, RootModel
2✔
9
from sanic import Request, json
2✔
10
from sanic.response import JSONResponse
2✔
11
from sanic_ext import validate
2✔
12

13
from renku_data_services import errors
2✔
14
from renku_data_services.base_api.blueprint import BlueprintFactoryResponse, CustomBlueprint
2✔
15

16

17
@dataclass(kw_only=True)
2✔
18
class MiscBP(CustomBlueprint):
2✔
19
    """Server contains all handlers for CRC and the configuration."""
20

21
    apispec: dict[str, Any]
2✔
22
    version: str
2✔
23

24
    def get_apispec(self) -> BlueprintFactoryResponse:
2✔
25
        """Servers the OpenAPI specification."""
26

27
        async def _get_apispec(_: Request) -> JSONResponse:
2✔
28
            return json(self.apispec)
1✔
29

30
        return "/spec.json", ["GET"], _get_apispec
2✔
31

32
    def get_error(self) -> BlueprintFactoryResponse:
2✔
33
        """Returns a sample error response."""
34

35
        async def _get_error(_: Request) -> NoReturn:
2✔
36
            raise errors.ValidationError(message="Sample validation error")
1✔
37

38
        return "/error", ["GET"], _get_error
2✔
39

40
    def get_version(self) -> BlueprintFactoryResponse:
2✔
41
        """Returns the version."""
42

43
        async def _get_version(_: Request) -> JSONResponse:
2✔
44
            return json({"version": self.version})
2✔
45

46
        return "/version", ["GET"], _get_version
2✔
47

48

49
_T = TypeVar("_T")
2✔
50
_P = ParamSpec("_P")
2✔
51

52

53
def validate_db_ids(f: Callable[_P, Awaitable[_T]]) -> Callable[_P, Coroutine[Any, Any, _T]]:
2✔
54
    """Decorator for a Sanic handler that errors out if passed in IDs are outside of the valid range for postgres."""
55

56
    @wraps(f)
2✔
57
    async def decorated_function(*args: _P.args, **kwargs: _P.kwargs) -> _T:
2✔
58
        resource_pool_id = cast(int | None, kwargs.get("resource_pool_id"))
2✔
59
        class_id = cast(int | None, kwargs.get("class_id"))
2✔
60
        min_val = 1  # postgres primary keys start at 1
2✔
61
        max_val = 2_147_483_647  # the max value for a default postgres primary key sequence
2✔
62
        if resource_pool_id and not min_val <= resource_pool_id <= max_val:
2✔
63
            raise errors.ValidationError(
1✔
64
                message=f"The provided resource pool ID is outside of the allowed range [{min_val}, {max_val}]"
65
            )
66
        if class_id and not min_val <= class_id <= max_val:
2✔
UNCOV
67
            raise errors.ValidationError(
×
68
                message=f"The provided resource class ID is outside of the allowed range [{min_val}, {max_val}]"
69
            )
70
        response = await f(*args, **kwargs)
2✔
71
        return response
2✔
72

73
    return decorated_function
2✔
74

75

76
def validate_query(
2✔
77
    query: type[BaseModel],
78
) -> Callable[
79
    [Callable[Concatenate[Request, _P], Awaitable[_T]]],
80
    Callable[Concatenate[Request, _P], Coroutine[Any, Any, _T]],
81
]:
82
    """Decorator for sanic query parameter validation.
83

84
    Should be removed once sanic fixes this error in their validation code.
85
    """
86

87
    def decorator(
2✔
88
        f: Callable[Concatenate[Request, _P], Awaitable[_T]],
89
    ) -> Callable[Concatenate[Request, _P], Coroutine[Any, Any, _T]]:
90
        @wraps(f)
2✔
91
        async def decorated_function(request: Request, *args: _P.args, **kwargs: _P.kwargs) -> _T:
2✔
92
            try:
2✔
93
                return await validate(query=query)(f)(request, *args, **kwargs)
2✔
94
            except KeyError:
2✔
95
                raise errors.ValidationError(message="Failed to validate the query parameters")
1✔
96

97
        return decorated_function
2✔
98

99
    return decorator
2✔
100

101

102
def validate_body_root_model(
2✔
103
    json: type[RootModel],
104
) -> Callable[
105
    [Callable[Concatenate[Request, _P], Awaitable[_T]]],
106
    Callable[Concatenate[Request, _P], Coroutine[Any, Any, _T]],
107
]:
108
    """Decorator for sanic json payload validation when the model is derived from RootModel.
109

110
    Should be removed once sanic fixes this error in their validation code.
111
    Issue link: https://github.com/sanic-org/sanic-ext/issues/198
112
    """
113

114
    def decorator(
2✔
115
        f: Callable[Concatenate[Request, _P], Awaitable[_T]],
116
    ) -> Callable[Concatenate[Request, _P], Coroutine[Any, Any, _T]]:
117
        @wraps(f)
2✔
118
        async def decorated_function(request: Request, *args: _P.args, **kwargs: _P.kwargs) -> _T:
2✔
119
            if request.json is not None:
2✔
120
                request.parsed_json = {"root": request.parsed_json}  # type: ignore[assignment]
2✔
121
            return await validate(json=json)(f)(request, *args, **kwargs)
2✔
122

123
        return decorated_function
2✔
124

125
    return decorator
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc