Compare commits
1 Commits
0.1.0.post
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 27c576db21 |
@@ -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
|
||||
|
||||
@@ -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/"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,7 +9,7 @@ from .rest_types import (
|
||||
_T_DictKey,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
if TYPE_CHECKING is True:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
83
src/pyrestresource/rest_resource_handler_walker.py
Normal file
83
src/pyrestresource/rest_resource_handler_walker.py
Normal 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,
|
||||
]
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(), "[]")
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user