1 Commits

Author SHA1 Message Date
27c576db21 Merge pull request 'dev' (#1) from dev into master
Reviewed-on: https://chacha.ddns.net/gitea/chacha/pyrestresource/pulls/1
new-tag:0.1.0
2023-11-06 16:07:12 +01:00
21 changed files with 201 additions and 295 deletions

View File

@@ -3,4 +3,5 @@ encoding//src/pyrestresource/__init__.py=utf-8
encoding//src/pyrestresource/__metadata__.py=utf-8
encoding//src/pyrestresource/rest_login.py=utf-8
encoding//src/pyrestresource/rest_resource.py=utf-8
encoding//src/pyrestresource/rest_resource_handler_walker.py=utf-8
encoding/<project>=UTF-8

View File

@@ -64,11 +64,6 @@ concurrency = [
'thread'
]
[tool.coverage.report]
exclude_also = [
"if TYPE_CHECKING:",
]
[project.urls]
Homepage = "https://chacha.ddns.net/gitea/chacha/pyrestresource"
Documentation = "https://chacha.ddns.net/mkdocs-web/chacha/pyrestresource/master/latest/"

View File

@@ -31,7 +31,6 @@ from .rest_request_opt import (
RestRequestParams_Dict_POST,
RestRequestParams_Dict_DELETE,
RestRequestParams_Dict_GET,
RestRequestParams_Dict_elem_GET,
)
from .rest_resource_plugin import (
ResourcePlugin_field_default,

View File

@@ -6,7 +6,7 @@ from enum import Enum, auto
from .rest_types import rsrc_verb
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from .rest_login import UserLogin

View File

@@ -30,7 +30,7 @@ from .rest_exceptions import (
RestResourceLoginException_InvalidSession,
)
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from .rest_request import RestRequest
from .rest_request_opt import RestRequestParams_RestResourceBase_PUT, RestRequestParams_RestResourceBase_GET

View File

@@ -1,11 +1,17 @@
from __future__ import annotations
from typing import Literal, Type, Any, Callable, TYPE_CHECKING
from typing import (
Any,
Literal,
Callable,
Optional,
TYPE_CHECKING,
)
from pydantic.fields import Field, _Unset, PydanticUndefined
from .rest_exceptions import RestResourceModelException
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from .rest_ACL import ACL_record
from .rest_resource_plugin import ResourcePlugin
from typing import Unpack
@@ -18,11 +24,11 @@ def RestField(
default_factory: Callable[[], Any] | None = _Unset,
alias: str | None = _Unset,
alias_priority: int | None = _Unset,
validation_alias: str | "AliasPath" | "AliasChoices" | None = _Unset,
validation_alias: str | AliasPath | AliasChoices | None = _Unset,
serialization_alias: str | None = _Unset,
title: str | None = _Unset,
description: str | None = _Unset,
examples: "list[Any] | None" = _Unset,
examples: list[Any] | None = _Unset,
exclude: bool | None = _Unset,
discriminator: str | None = _Unset,
json_schema_extra: dict[str, Any] | Callable[[dict[str, Any]], None] | None = _Unset,
@@ -44,8 +50,8 @@ def RestField(
min_length: int | None = _Unset,
max_length: int | None = _Unset,
union_mode: Literal["smart", "left_to_right"] = _Unset,
ACL: list["ACL_record"] | None = _Unset,
plugin: Type["ResourcePlugin"] | None = _Unset,
ACL: Optional[list[ACL_record]] = _Unset,
plugin: Optional[type[ResourcePlugin]] = _Unset,
**extra: Unpack[_EmptyKwargs],
) -> Any:
if not json_schema_extra or json_schema_extra is _Unset:

View File

@@ -35,7 +35,7 @@ from .rest_exceptions import (
RestResourceConfigException,
)
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from typing import Optional
from .rest_types import T_SupportedRESTFields
from .rest_resource import RestResourceBase

View File

@@ -9,7 +9,7 @@ from .rest_types import (
_T_DictKey,
)
if TYPE_CHECKING:
if TYPE_CHECKING is True:
pass

View File

@@ -35,7 +35,7 @@ from .rest_exceptions import (
RestResourceException,
)
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from .rest_request import RestRequest
from .rest_types import T_SupportedRESTFields
from .rest_resource_plugin import ResourcePlugin

View File

@@ -43,7 +43,7 @@ from .rest_exceptions import (
RestResourceHandlerException_Forbiden,
)
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from .rest_types import T_T_DictKey, T_T_DictValues
from .rest_request import RestRequest
@@ -292,14 +292,6 @@ class ResourceHandler_dict(
_dict: dict[T_DictKey, T_DictValues] = cast(dict[T_DictKey, T_DictValues], self.resource)
if self.req.get_resource_origin(1) in self.prev_handler.resource._plugins_:
plugin_dict: ResourcePlugin_dict = cast(
ResourcePlugin_dict,
self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)],
)
plugin_dict.set_context(self.req, self.req.get_root_resource())
return plugin_dict.handle_dict_get_keys(self.resource, params)
return list(_dict.keys())
def _handle_process_delete(self, params) -> None:
@@ -404,38 +396,15 @@ class ResourceHandler_dict_elem(
# print(f"{type(self).__name__}->resource = {type(self.resource).__name__}")
assert self.prev_handler is not None
assert isinstance(self.prev_handler.resource, RestResourceBase)
dict_key_type: T_T_DictKey = self.prev_handler.resource._dict_key_type_[self.req.get_resource_origin(1)]
dict_key_type: T_T_DictKey = cast(RestResourceBase, self.prev_handler.resource)._dict_key_type_[self.req.get_resource_origin(1)]
if issubclass(dict_key_type, bytes):
key_byte = dict_key_type(self.req.get_resource_origin(0), "utf-8")
dict_byte: dict[T_DictKey, T_DictValues] = cast(dict[T_DictKey, T_DictValues], self.resource)
if self.req.get_resource_origin(1) in self.prev_handler.resource._plugins_:
plugin_dict: ResourcePlugin_dict = cast(
ResourcePlugin_dict,
self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)],
)
plugin_dict.set_context(self.req, self.req.get_root_resource())
return plugin_dict.handle_dict_elem_get(dict_byte, key_byte, params)
return dict_byte[key_byte]
return cast(dict[T_DictKey, T_DictValues], self.resource)[key_byte]
else:
key_std = dict_key_type(self.req.get_resource_origin(0))
dict_std: dict[T_DictKey, T_DictValues] = cast(dict[T_DictKey, T_DictValues], self.resource)
if self.req.get_resource_origin(1) in self.prev_handler.resource._plugins_:
plugin_dict: ResourcePlugin_dict = cast(
ResourcePlugin_dict,
self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)],
)
plugin_dict.set_context(self.req, self.req.get_root_resource())
return plugin_dict.handle_dict_elem_get(dict_std, key_std, params)
return dict_std[key_std]
key = dict_key_type(self.req.get_resource_origin(0))
return cast(dict[T_DictKey, T_DictValues], self.resource)[key]
def _handle_process_delete(self, params) -> None:
# print(f"{type(self).__name__}->_handle_process_delete()")
@@ -446,36 +415,15 @@ class ResourceHandler_dict_elem(
# because self.req is another context that is not saved to improve performances
assert self.prev_handler is not None
assert isinstance(self.prev_handler.resource, RestResourceBase)
dict_key_type: T_T_DictKey = self.prev_handler.resource._dict_key_type_[self.req.get_resource_origin(2)]
dict_key_type: T_T_DictKey = cast(RestResourceBase, self.prev_handler.resource)._dict_key_type_[self.req.get_resource_origin(2)]
if issubclass(dict_key_type, bytes):
key_byte = dict_key_type(self.req.get_resource_origin(1), "utf-8")
dict_byte: dict[T_DictKey, T_DictValues] = cast(dict[T_DictKey, T_DictValues], self.resource)
if self.req.get_resource_origin(2) in self.prev_handler.resource._plugins_:
plugin_dict: ResourcePlugin_dict = cast(
ResourcePlugin_dict, self.prev_handler.resource._plugins_[self.req.get_resource_origin(2)]
)
plugin_dict.set_context(self.req, self.req.get_root_resource())
plugin_dict.handle_dict_delete(dict_byte, key_byte, params)
return None
del dict_byte[key_byte]
del cast(dict[T_DictKey, T_DictValues], self.resource)[key_byte]
else:
key_std = dict_key_type(self.req.get_resource_origin(1))
dict_std: dict[T_DictKey, T_DictValues] = cast(dict[T_DictKey, T_DictValues], self.resource)
if self.req.get_resource_origin(2) in self.prev_handler.resource._plugins_:
plugin_dict: ResourcePlugin_dict = cast(
ResourcePlugin_dict, self.prev_handler.resource._plugins_[self.req.get_resource_origin(2)]
)
plugin_dict.set_context(self.req, self.req.get_root_resource())
plugin_dict.handle_dict_delete(dict_std, key_std, params)
return None
del dict_std[key_std]
key = dict_key_type(self.req.get_resource_origin(1))
del cast(dict[T_DictKey, T_DictValues], self.resource)[key]
@ResourceHandler.register_resource_handler
@@ -545,14 +493,14 @@ class ResourceHandler_RestResourceBase(
self.resource.check_acl_self(self.req, None)
for key, attr in self.resource.model_fields.items():
if key in self.resource._plugins_:
if isinstance(self.resource._plugins_[key], ResourcePlugin_field):
plugin_field = cast(ResourcePlugin_field, self.resource._plugins_[key])
plugin_field.set_context(self.req, self.req.get_root_resource())
if issubclass(self.resource._plugins_[key], ResourcePlugin_field):
plugin_field = cast(ResourcePlugin_field, self.resource._plugins_[key](self.req, self.req.get_root_resource()))
value = getattr(self.resource, key)
setattr(self.resource, key, plugin_field.handle_field_get(value, params))
elif isinstance(self.resource._plugins_[key], ResourcePlugin_RestResourceBase):
plugin_resource = cast(ResourcePlugin_RestResourceBase, self.resource._plugins_[key])
plugin_resource.set_context(self.req, self.req.get_root_resource())
elif issubclass(self.resource._plugins_[key], ResourcePlugin_RestResourceBase):
plugin_resource = cast(
ResourcePlugin_RestResourceBase, self.resource._plugins_[key](self.req, self.req.get_root_resource())
)
value = getattr(self.resource, key)
setattr(self.resource, key, plugin_resource.handle_resource_get(value, params))
@@ -571,14 +519,18 @@ class ResourceHandler_RestResourceBase(
key = self.req.get_resource_origin(0)
if key in self.resource._plugins_:
if isinstance(self.resource._plugins_[key], ResourcePlugin_field):
plugin_field = cast(ResourcePlugin_field, self.resource._plugins_[key])
plugin_field.set_context(self.req, self.req.get_root_resource())
if issubclass(self.resource._plugins_[key], ResourcePlugin_field):
plugin_field = cast(
ResourcePlugin_field,
self.resource._plugins_[key](self.req, self.req.get_root_resource()),
)
value = plugin_field.handle_field_get(value, params)
elif isinstance(self.resource._plugins_[key], ResourcePlugin_RestResourceBase):
plugin_resource = cast(ResourcePlugin_RestResourceBase, self.resource._plugins_[key])
plugin_resource.set_context(self.req, self.req.get_root_resource())
elif issubclass(self.resource._plugins_[key], ResourcePlugin_RestResourceBase):
plugin_resource = cast(
ResourcePlugin_RestResourceBase,
self.resource._plugins_[key](self.req, self.req.get_root_resource()),
)
value = plugin_resource.handle_resource_get(value, params)
return value
@@ -598,9 +550,10 @@ class ResourceHandler_RestResourceBase(
if isinstance(_new_resrc, RestResourceBase):
for key, attr in _new_resrc.model_fields.items():
if key in _new_resrc._plugins_:
if isinstance(_new_resrc._plugins_[key], ResourcePlugin_field):
plugin_field: ResourcePlugin_field = cast(ResourcePlugin_field, _new_resrc._plugins_[key])
plugin_field.set_context(self.req, self.req.get_root_resource())
if issubclass(_new_resrc._plugins_[key], ResourcePlugin_field):
plugin_field: ResourcePlugin_field = cast(
ResourcePlugin_field, _new_resrc._plugins_[key](self.req, self.req.get_root_resource())
)
value = getattr(_new_resrc, key)
setattr(_new_resrc, key, plugin_field.handle_field_put(value, params))
@@ -614,17 +567,19 @@ class ResourceHandler_RestResourceBase(
):
key = self.req.get_resource_origin(2)
if key in self.prev_handler.prev_handler.resource._plugins_:
plugin_dict: ResourcePlugin_dict = cast(ResourcePlugin_dict, self.prev_handler.prev_handler.resource._plugins_[key])
plugin_dict.set_context(self.req, self.req.get_root_resource())
plugin_dict: ResourcePlugin_dict = cast(
ResourcePlugin_dict,
self.prev_handler.prev_handler.resource._plugins_[key](self.req, self.req.get_root_resource()),
)
_new_resrc = plugin_dict.handle_dict_elem_put(_new_resrc, params)
# element is within a RestResourceBase
elif isinstance(self.prev_handler.resource, RestResourceBase):
key = self.req.get_resource_origin(1)
if key in self.prev_handler.resource._plugins_:
plugin_rsrc: ResourcePlugin_RestResourceBase = cast(
ResourcePlugin_RestResourceBase, self.prev_handler.resource._plugins_[key]
ResourcePlugin_RestResourceBase,
self.prev_handler.resource._plugins_[key](self.req, self.req.get_root_resource()),
)
plugin_rsrc.set_context(self.req, self.req.get_root_resource())
_new_resrc = plugin_rsrc.handle_resource_put(_new_resrc, params)
self.resource.update(**_new_resrc.__dict__)
@@ -673,9 +628,9 @@ class ResourceHandler_simple(
if self.req.get_resource_origin(1) in self.prev_handler.resource._plugins_:
plugin_simple: ResourcePlugin_field = cast(
ResourcePlugin_field, self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)]
ResourcePlugin_field,
self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)](self.req, self.req.get_root_resource()),
)
plugin_simple.set_context(self.req, self.req.get_root_resource())
return plugin_simple.handle_field_get(self.resource, params)
return self.resource
@@ -694,9 +649,9 @@ class ResourceHandler_simple(
if self.req.get_resource_origin(1) in self.prev_handler.resource._plugins_:
# print("PLUGIN FOUND")
plugin_simple: ResourcePlugin_field = cast(
ResourcePlugin_field, self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)]
ResourcePlugin_field,
self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)](self.req, self.req.get_root_resource()),
)
plugin_simple.set_context(self.req, self.req.get_root_resource())
# print(value)
value = plugin_simple.handle_field_put(value, params)
# print(value)

View File

@@ -0,0 +1,83 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pyrestresource(c) by chacha
#
# pyrestresource is licensed under a
# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Unported License.
#
# You should have received a copy of the license along with this
# work. If not, see <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
"""CLI interface module"""
from __future__ import annotations
from typing import TYPE_CHECKING
from .rest_resource_walker import (
RestResourceWalkerFutureResult,
RestResourceWalker_Root,
RestResourceWalker_Sub_T_Dict,
RestResourceWalker_Sub_RestFields,
RestResourceWalker_Sub_RestResourceBase,
)
if TYPE_CHECKING is True:
from typing import Optional, Any
class RestResourceWalkerFutureResult_RestResourceBase_handler(RestResourceWalkerFutureResult[dict]):
def process_future(self, result: Optional[list[dict]]) -> Optional[dict]:
# print(f"RestResourceWalkerFutureResult_RestResourceBase_handler {result}")
res: dict[str, Any] = {}
res[self.source.resource_name] = {}
if result:
for subres in result:
key = next(iter(subres))
print(key)
res[self.source.resource_name] = res[self.source.resource_name] | subres
return res
class RestResourceWalkerFutureResult_Dict_handler(RestResourceWalkerFutureResult[dict]):
def process_future(self, result: Optional[list[dict]]) -> Optional[dict]:
# print(f"RestResourceWalkerFutureResult_Dict_handler {result}")
res: dict[str, Any] = {}
if result:
for subres in result:
res = res | subres
return res
class RestResourceWalkerFutureResult_RestFields_handler(RestResourceWalkerFutureResult[dict]):
def process_future(self, result: Optional[list[dict]]) -> Optional[dict]:
# print(f"RestResourceWalkerFutureResult_RestFields_handler {result}")
# print(self.source.resource)
res: dict[str, Any] = {}
res[self.source.resource_name] = {}
if result:
for subres in result:
key = next(iter(subres))
print(key)
res[self.source.resource_name] = res[self.source.resource_name] | subres
return res
class RestResourceWalker_Sub_T_Dict__handler(RestResourceWalker_Sub_T_Dict):
cls_RestResourceWalkerFutureResult = RestResourceWalkerFutureResult_Dict_handler
class RestResourceWalker_Sub_RestResourceBase__handler(RestResourceWalker_Sub_RestResourceBase):
cls_RestResourceWalkerFutureResult = RestResourceWalkerFutureResult_RestResourceBase_handler
class RestResourceWalker_Sub_RestResourceFields__handler(RestResourceWalker_Sub_RestFields):
cls_RestResourceWalkerFutureResult = RestResourceWalkerFutureResult_RestFields_handler
class RestResourceWalker_Root__handler(RestResourceWalker_Root):
cls_RestResourceWalker_Sub = [
RestResourceWalker_Sub_T_Dict__handler,
RestResourceWalker_Sub_RestResourceFields__handler,
RestResourceWalker_Sub_RestResourceBase__handler,
]

View File

@@ -13,7 +13,7 @@ from .rest_types import (
from .rest_exceptions import RestResourceConfigException
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from .rest_request import RestRequest
from .rest_resource import RestResourceBase
from .rest_request_opt import (
@@ -30,10 +30,7 @@ if TYPE_CHECKING:
class ResourcePlugin(ABC):
def __init__(self) -> None:
...
def set_context(self, request: RestRequest, root_resource: RestResourceBase) -> None:
def __init__(self, request: RestRequest, root_resource: RestResourceBase) -> None:
self.__request: RestRequest = request
self.__root_resource: RestResourceBase = root_resource
@@ -133,7 +130,6 @@ class ResourcePlugin_dict(ResourcePlugin, Generic[_T_DictKey, _T_DictValues]):
def handle_dict_post(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
key: _T_DictKey,
resource: _T_DictValues,
params: RestRequestParams_Dict_POST[_T_DictKey],
) -> Optional[_T_DictKey]:
@@ -141,15 +137,6 @@ class ResourcePlugin_dict(ResourcePlugin, Generic[_T_DictKey, _T_DictValues]):
@abstractmethod
def handle_dict_delete(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
key: _T_DictKey,
params: RestRequestParams_Dict_DELETE[_T_DictKey],
) -> None:
...
@abstractmethod
def handle_dict_delete_all(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
params: RestRequestParams_Dict_DELETE[_T_DictKey],
@@ -159,20 +146,17 @@ class ResourcePlugin_dict(ResourcePlugin, Generic[_T_DictKey, _T_DictValues]):
@abstractmethod
def handle_dict_elem_get(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
key: _T_DictKey,
resource: TV_RestResourceBase,
params: RestRequestParams_Dict_elem_GET,
) -> _T_DictValues:
) -> TV_RestResourceBase:
...
@abstractmethod
def handle_dict_elem_put(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
key: _T_DictKey,
resource: _T_DictValues,
resource: TV_RestResourceBase,
params: RestRequestParams_Dict_elem_PUT,
) -> None:
) -> TV_RestResourceBase:
...
@@ -189,41 +173,31 @@ class ResourcePlugin_dict_default(ResourcePlugin_dict[_T_DictKey, _T_DictValues]
def handle_dict_post(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
key: _T_DictKey,
resource: _T_DictValues,
params: RestRequestParams_Dict_POST[_T_DictKey],
) -> Optional[_T_DictKey]:
resource_dict[key] = resource
return key
if params.API_key is not None:
resource_dict[params.API_key] = resource
return params.API_key
def handle_dict_delete(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
key: _T_DictKey,
params: RestRequestParams_Dict_DELETE[_T_DictKey],
) -> None:
del resource_dict[key]
def handle_dict_delete_all(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
params: RestRequestParams_Dict_DELETE[_T_DictKey],
) -> None:
resource_dict.clear()
if params.API_key is not None:
del resource_dict[params.API_key]
def handle_dict_elem_get(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
key: _T_DictKey,
resource: TV_RestResourceBase,
params: RestRequestParams_Dict_elem_GET,
) -> _T_DictValues:
return resource_dict[key]
) -> TV_RestResourceBase:
return resource
def handle_dict_elem_put(
self,
resource_dict: dict[_T_DictKey, _T_DictValues],
key: _T_DictKey,
resource: _T_DictValues,
resource: TV_RestResourceBase,
params: RestRequestParams_Dict_elem_PUT,
) -> None:
resource_dict[key] = resource
) -> TV_RestResourceBase:
return resource

View File

@@ -29,8 +29,8 @@ from .rest_ACL import (
)
from .rest_exceptions import RestResourcePluginException_InvalidPluginSignature, RestResourceModelException, RestResourceModelException_ACL
if TYPE_CHECKING:
...
if TYPE_CHECKING is True:
pass
class RestResourceWalker_Sub_T_Dict__tree_init(RestResourceWalker_Sub_T_Dict):
@@ -68,7 +68,7 @@ class RestResourceWalker_Sub_T_Dict__tree_init(RestResourceWalker_Sub_T_Dict):
plugin_dict: type[ResourcePlugin_dict] = self.resource.json_schema_extra["plugin"]
if not issubclass(plugin_dict, ResourcePlugin_dict):
raise RestResourcePluginException_InvalidPluginSignature()
self.parent.annotation._plugins_[self.resource_name] = plugin_dict()
self.parent.annotation._plugins_[self.resource_name] = plugin_dict
# print("ADD DICT PLUGIN")
if "ACL" in self.resource.json_schema_extra:
@@ -115,7 +115,7 @@ class RestResourceWalker_Sub_RestFields__tree_init(RestResourceWalker_Sub_RestFi
plugin_field: type[ResourcePlugin_field] = self.resource.json_schema_extra["plugin"]
if not issubclass(plugin_field, ResourcePlugin_field):
raise RestResourcePluginException_InvalidPluginSignature()
self.parent.annotation._plugins_[self.resource_name] = plugin_field()
self.parent.annotation._plugins_[self.resource_name] = plugin_field
# print("ADD FIELD PLUGIN")
if "ACL" in self.resource.json_schema_extra:
@@ -158,7 +158,7 @@ class RestResourceWalker_Sub_RestResourceBase__tree_init(RestResourceWalker_Sub_
plugin_resource: type[ResourcePlugin_RestResourceBase] = self.resource.json_schema_extra["plugin"]
if not issubclass(plugin_resource, ResourcePlugin_RestResourceBase):
raise RestResourcePluginException_InvalidPluginSignature()
self.parent.annotation._plugins_[self.resource_name] = plugin_resource()
self.parent.annotation._plugins_[self.resource_name] = plugin_resource
# print("ADD RESOURCE PLUGIN")
if "ACL" in self.resource.json_schema_extra:

View File

@@ -17,7 +17,7 @@ from .rest_types import _T_SupportedRESTFields
from .rest_resource import RestResourceBase
from .rest_exceptions import RestResourceModelException
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from typing import Any, Optional
TV_RestResourceWalkerFutureResult = TypeVar("TV_RestResourceWalkerFutureResult")

View File

@@ -1,6 +1,6 @@
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring
from __future__ import annotations
from typing import Union, get_origin, NewType, TypeVar, Type, TYPE_CHECKING
from typing import Union, get_origin, NewType, TypeVar, TYPE_CHECKING
from enum import Enum, auto
from datetime import datetime
@@ -8,7 +8,7 @@ from pathlib import Path
from uuid import UUID
from ipaddress import IPv4Address, IPv4Network
if TYPE_CHECKING:
if TYPE_CHECKING is True:
from .rest_resource import RestResourceBase
T_Gen_DictKeys: type = type({}.keys())
@@ -91,8 +91,8 @@ _T_DictValues = TypeVar(
NoneType,
)
T_T_FieldValue = Type[T_FieldValue]
T_T_DictValues = Type[T_DictValues]
T_T_FieldValue = type(T_FieldValue)
T_T_DictValues = type[T_DictValues]
T_Dict = dict[T_DictKey, T_DictValues]
_T_Dict = dict[_T_DictKey, _T_DictValues]

View File

@@ -4,12 +4,12 @@ from os import chdir
from pathlib import Path
from typing import Optional, ClassVar
from time import sleep
import socket
from contextlib import closing
import requests
from requests.adapters import HTTPAdapter
import uvicorn
import socket
import requests
from contextlib import closing
from multiprocessing import Process
from requests.adapters import HTTPAdapter
from src.pyrestresource import (
RestField,

View File

@@ -8,6 +8,10 @@ from uuid import UUID, uuid4
from time import time
import json
print(__name__)
print(__package__)
from src.pyrestresource import (
RestField,
RestResourceHandlerException_Forbiden,
@@ -480,7 +484,7 @@ class Test_RestAPI_PERFO(unittest.TestCase):
init_classes()
self.testapp = RootApp()
# @unittest.skip
@unittest.skip
def test_perf_dict(self):
print(f"LIB INTERNAL PERF TEST")
n_loop = 10000

View File

@@ -1,129 +0,0 @@
from __future__ import annotations
import unittest
from os import chdir
from pathlib import Path
from typing import Annotated
from src.pyrestresource import (
RestField,
register_rest_rootpoint,
RestResourceBase,
rsrc_verb,
RestRequestParams_GET,
RestRequestParams_POST,
RestRequestParams_Dict_GET,
RestRequestParams_PUT,
RestRequestParams_Dict_elem_GET,
RestRequestParams_Dict_DELETE,
T_SupportedRESTFields,
ResourcePlugin_dict_default,
)
testdir_path = Path(__file__).parent.resolve()
chdir(testdir_path.parent.resolve())
# to allow mock-ing, all the tested classes are in a function
def init_classes():
class Test_Record(RestResourceBase):
test_str: str
test_int: int
class ResourcePlugin_dict_Test_Record(ResourcePlugin_dict_default[str, Test_Record]):
static_Test_Record_active: bool = True
static_Test_Record = Test_Record(test_str="mytest", test_int=84)
def handle_dict_get_keys(
self,
resource_dict: dict[str, Test_Record],
params: RestRequestParams_Dict_GET,
) -> list[str]:
# print("HOOK handle_dict_get_keys")
# print(resource_dict)
# print(params)
result = super().handle_dict_get_keys(resource_dict, params)
if self.static_Test_Record_active is True:
result.append("static_elem")
return result
def handle_dict_elem_get(
self,
resource_dict: dict[str, Test_Record],
key: str,
params: RestRequestParams_Dict_elem_GET,
) -> Test_Record:
# print("HOOK handle_dict_elem_get")
# print(resource_dict)
# print(key)
# print(params)
if key == "static_elem":
if self.static_Test_Record_active is True:
return self.static_Test_Record
else:
raise RuntimeError("Key Not Found")
return super().handle_dict_elem_get(resource_dict, key, params)
def handle_dict_delete(
self,
resource_dict: dict[str, Test_Record],
key: str,
params: RestRequestParams_Dict_DELETE[str],
) -> None:
print("HOOK handle_dict_delete")
print(resource_dict)
print(key)
print(params)
print(self.static_Test_Record_active)
if key == "static_elem":
self.static_Test_Record_active = False
else:
del resource_dict[key]
@register_rest_rootpoint
class RootApp(RestResourceBase):
str_dict_Test_Record: dict[str, Test_Record] = RestField(
default={"test": Test_Record(test_str="Hi", test_int=42)},
plugin=ResourcePlugin_dict_Test_Record,
)
# this add the classes to globals to allow using them later on
# => this is only for uinit-testing purpose and is not needed in real use
globals()[Test_Record.__name__] = Test_Record
globals()[RootApp.__name__] = RootApp
class Test_RestAPI_Plugin_Dict(unittest.TestCase):
def setUp(self) -> None:
chdir(testdir_path.parent.resolve())
init_classes()
self.testapp = RootApp()
def test_get_root(self):
result = self.testapp.process_request("/", rsrc_verb.GET)
self.assertEqual(result.get_result(), "{}")
# print(result.get_result())
def test_get_dict_keys(self):
result = self.testapp.process_request("/str_dict_Test_Record", rsrc_verb.GET)
self.assertEqual(result.get_result(), '["test", "static_elem"]')
def test_get_dict_elems(self):
result = self.testapp.process_request("/str_dict_Test_Record/test", rsrc_verb.GET)
self.assertEqual(result.get_result(), '{"test_str": "Hi", "test_int": 42}')
result = self.testapp.process_request("/str_dict_Test_Record/static_elem", rsrc_verb.GET)
self.assertEqual(result.get_result(), '{"test_str": "mytest", "test_int": 84}')
def test_delete_dict_elems(self):
result = self.testapp.process_request("/str_dict_Test_Record/test", rsrc_verb.DELETE)
print(result.get_result())
result = self.testapp.process_request("/str_dict_Test_Record", rsrc_verb.GET)
self.assertEqual(result.get_result(), '["static_elem"]')
result = self.testapp.process_request("/str_dict_Test_Record/static_elem", rsrc_verb.DELETE)
print(result.get_result())
result = self.testapp.process_request("/str_dict_Test_Record", rsrc_verb.GET)
self.assertEqual(result.get_result(), "[]")

View File

@@ -1,11 +1,16 @@
from __future__ import annotations
import unittest
from typing import Optional
from os import chdir
from pathlib import Path
from io import StringIO
from contextlib import redirect_stdout
print(__name__)
print(__package__)
from src.pyrestresource import (
RestField,
RestResourceBase,

View File

@@ -1,9 +1,15 @@
from __future__ import annotations
import unittest
from typing import Optional
from os import chdir
from pathlib import Path
print(__name__)
print(__package__)
from src.pyrestresource import (
RestField,
RestResourceBase,

View File

@@ -1,16 +1,22 @@
from __future__ import annotations
import unittest
from unittest.mock import patch
from os import chdir
from pathlib import Path
from typing import Optional
from uuid import UUID, uuid4
from time import time, sleep
import socket
from contextlib import closing
import requests
from requests.adapters import HTTPAdapter
import json
import uvicorn
import socket
import requests
from contextlib import closing
from multiprocessing import Process
from requests.adapters import HTTPAdapter
import coverage
print(__name__)
print(__package__)
from src.pyrestresource import (
RestField,
@@ -22,6 +28,7 @@ from src.pyrestresource import (
RestRequestParams_Dict_GET,
T_SupportedRESTFields,
)
from pprint import pprint
from test import ThreadedUvicorn
@@ -262,7 +269,7 @@ class Test_RestAPI_WebServer(unittest.TestCase):
s.close()
server.stop()
# @unittest.skip
@unittest.skip
def test_perf_dict(self):
print(f"SOCKET PERF TEST")
n_loop = 10000