optimization (WIP)

This commit is contained in:
cclecle
2023-11-02 01:00:30 +00:00
parent f9b016d845
commit 2251b1d5e9
9 changed files with 136 additions and 149 deletions

View File

@@ -2,4 +2,5 @@ eclipse.preferences.version=1
encoding//src/pyrestresource/__init__.py=utf-8
encoding//src/pyrestresource/__metadata__.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

@@ -62,22 +62,24 @@ class RequestFactory(
return RestRequest[RestRequestParams_DELETE](self.cls_RestRequestParams_DELETE, url, verb, data, query_string)
raise RuntimeError("Invalid Verb")
def update_RestRequest(self, origin_request: RestRequest) -> RestRequest:
def update_RestRequest(self, request: RestRequest) -> None:
"""create an updated copy of a RestRequest object based on a different LUT_verb configuration
Args:
origin_request: the original request
"""
# /!\ mypy seems not being able to propagate typevar to composed classes
if origin_request.verb is rsrc_verb.GET:
return RestRequest[RestRequestParams_GET](self.cls_RestRequestParams_GET, None, None, None, None, origin_request)
if origin_request.verb is rsrc_verb.PUT:
return RestRequest[RestRequestParams_PUT](self.cls_RestRequestParams_PUT, None, None, None, None, origin_request)
if origin_request.verb is rsrc_verb.POST:
return RestRequest[RestRequestParams_POST](self.cls_RestRequestParams_POST, None, None, None, None, origin_request)
if origin_request.verb is rsrc_verb.DELETE:
return RestRequest[RestRequestParams_DELETE](self.cls_RestRequestParams_DELETE, None, None, None, None, origin_request)
raise RuntimeError("Invalid Verb")
if request.verb is rsrc_verb.GET:
request.update_ReqParams(self.cls_RestRequestParams_GET)
elif request.verb is rsrc_verb.PUT:
request.update_ReqParams(self.cls_RestRequestParams_PUT)
elif request.verb is rsrc_verb.POST:
request.update_ReqParams(self.cls_RestRequestParams_POST)
elif request.verb is rsrc_verb.DELETE:
request.update_ReqParams(self.cls_RestRequestParams_DELETE)
else:
raise RuntimeError("Invalid Verb")
return
class RestRequest(Generic[_T_RestRequestParams]):
@@ -87,21 +89,22 @@ class RestRequest(Generic[_T_RestRequestParams]):
def __init__(
self,
type_request_params: type[_T_RestRequestParams],
url: Optional[str] = None,
verb: Optional[rsrc_verb] = None,
url: str,
verb: rsrc_verb,
data: Optional[dict[str, T_SupportedRESTFields]] = None,
query_string: Optional[str] = None,
origin_request: Optional[RestRequest] = None,
incoming_cookie: dict[str, str] = {},
outgoing_cookie: dict[str, str] = {},
) -> None:
"""class to handle a request context, that will be kept and updated while walking url parts
Args:
type_request_params: type of the request param
url: http url of the request
verb: http verb received
data: data associated with the request
type_request_params: type of the request param
origin_request: orginial request in case of updates.
In this case, all other argument - but type_request_params - are ignored and inherited from the origin_request
query_string: query arguments after url (eg: ?arg1=value1&arg2=value2 ...)
"""
# defining all types
@@ -113,14 +116,8 @@ class RestRequest(Generic[_T_RestRequestParams]):
self.url_stack: list[str]
self._saved_url_stack: list[str]
self.url_stack_index: int
# = updating request from a previous one =
if origin_request:
self.__dict__ = origin_request.__dict__.copy()
if type_request_params:
self.ReqParams = type_request_params(**self._saved_url_params)
# print("request updated")
return
self.incoming_cookie: dict[str, str] = incoming_cookie
self.outgoing_cookie: dict[str, str] = outgoing_cookie
# = or create a fresh one =
if url is None or verb is None or data is None:
@@ -144,6 +141,9 @@ class RestRequest(Generic[_T_RestRequestParams]):
self._saved_url_stack = self.url_stack.copy()
self.url_stack_index = 0
def update_ReqParams(self, type_request_params: type[_T_RestRequestParams]):
self.ReqParams = type_request_params(**self._saved_url_params)
def _parse_url(self, url: str) -> None:
# remove repeated slash ('/')
url = sub(r"\/{2,}", "/", url)

View File

@@ -23,7 +23,7 @@ from typing import (
TYPE_CHECKING,
)
import json
from pydantic.fields import FieldInfo
from pydantic.fields import FieldInfo, Field
from pydantic import BaseModel
from .helpers import _JSONEncoder
@@ -43,6 +43,8 @@ from .rest_resource_walker import (
RestResourceWalker_Sub_RestResourceBase,
)
from .rest_request import RestRequest
if TYPE_CHECKING:
from .rest_types import (
T_ListIndex,
@@ -95,34 +97,6 @@ class RestResourceWalker_Root__tree_exclude(RestResourceWalker_Root):
]
class pluginCTX:
cookies: dict[str, str] = dict()
class RestResourceWalker_Sub_RestResourceBase__init_pluginCTX(RestResourceWalker_Sub_RestResourceBase):
_pluginCTX: pluginCTX = pluginCTX()
def process(self):
# import pprint
# print(f"hey: {self.resource}")
# pprint.pprint(self.resource)
# print(type(self.resource))
# print(self.annotation._plugins_)
for plugin in self.annotation._plugins_.values():
# print("SET COOKIE")
plugin.cookies = self._pluginCTX.cookies
class RestResourceWalker_Root__init_pluginCTX(RestResourceWalker_Root):
cls_RestResourceWalker_Sub = [
RestResourceWalker_Sub_T_Dict,
RestResourceWalker_Sub_RestFields,
RestResourceWalker_Sub_RestResourceBase__init_pluginCTX,
]
class RestResourceWalker_Sub_T_Dict__tree_init(RestResourceWalker_Sub_T_Dict):
def process(self) -> None:
datatype = get_args(self.annotation)
@@ -139,6 +113,9 @@ class RestResourceWalker_Sub_T_Dict__tree_init(RestResourceWalker_Sub_T_Dict):
self.parent.annotation._dict_value_type_[self.resource_name] = datatype[1] # pylint: disable=protected-access
self.parent.annotation._model_dump_excluded_[self.resource_name] = True # pylint: disable=protected-access
self.resource.exclude = True
self.parent.resource.model_rebuild(force=True)
if (
isinstance(self.resource, FieldInfo)
and self.resource.json_schema_extra is not None
@@ -158,11 +135,19 @@ class RestResourceWalker_Sub_T_Dict__tree_init(RestResourceWalker_Sub_T_Dict):
class RestResourceWalker_Sub_RestFields__tree_init(RestResourceWalker_Sub_RestFields):
def process(self) -> None:
if self.parent is not None and isinstance(self.parent, RestResourceWalker_Sub_RestResourceBase):
import pprint
# print("1aaaaaaaaaa")
# pprint.pprint(self.resource.json_schema_extra)
# pprint.pprint(self.annotation)
# pprint.pprint(self.resource.exclude)
if (
isinstance(self.resource, FieldInfo)
and self.resource.json_schema_extra is not None
and type(self.resource.json_schema_extra) is dict
):
# print("aaaaaaaaaa")
if "primary_key" in self.resource.json_schema_extra and self.resource.json_schema_extra["primary_key"] is True:
if self.parent.annotation._primary_key_ is not None:
raise RuntimeError(f"Only one primary key is allowed {self.parent.resource_name}.{self.resource_name}")
@@ -190,6 +175,8 @@ class RestResourceWalker_Sub_RestResourceBase__tree_init(RestResourceWalker_Sub_
# preprocessing types / structure
if self.parent is not None and isinstance(self.parent, RestResourceWalker_Sub_RestResourceBase):
self.parent.annotation._model_dump_excluded_[self.resource_name] = True
self.resource.exclude = True
self.parent.resource.model_rebuild(force=True)
if (
isinstance(self.resource, FieldInfo)
@@ -229,6 +216,7 @@ class RestResourceBase(ABC, BaseModel, validate_assignment=True):
ResourcePlugin_field | ResourcePlugin_RestResourceBase | ResourcePlugin_dict,
]
] = {}
_request: Optional[RestRequest] = None
def update(self, **new_data):
for field, value in new_data.items():
@@ -263,12 +251,13 @@ class RestResourceBase(ABC, BaseModel, validate_assignment=True):
body = await self.read_body(receive)
verb = rsrc_verb[scope["method"]]
type(self)._resp_cookies = dict()
self._request = None
result = self.process_request(
scope["path"], rsrc_verb[scope["method"]], body.decode("utf-8"), scope["query_string"].decode("utf-8")
)
assert self._request != None
status = 200
if verb in (rsrc_verb.POST, rsrc_verb.PUT):
status = 201
@@ -281,7 +270,7 @@ class RestResourceBase(ABC, BaseModel, validate_assignment=True):
],
}
for name, value in type(self)._resp_cookies.items():
for name, value in self._request.outgoing_cookie.items():
header_resp["headers"].append(["Set-Cookie", f"{name}={value}"])
# print("----SENT HEADER ---")
@@ -315,10 +304,9 @@ class RestResourceBase(ABC, BaseModel, validate_assignment=True):
if data_json:
data = json.loads(data_json)
RestResourceWalker_Sub_RestResourceBase__init_pluginCTX._pluginCTX.cookies = type(self)._resp_cookies
RestResourceWalker_Root__init_pluginCTX(self).process()
ressource: ResourceHandler = ResourceHandler_RestResourceBase(self, url, verb, data, query_string)
self._request = ressource.get_request()
result = ressource.process_verb()
# print("OOO")
@@ -326,10 +314,11 @@ class RestResourceBase(ABC, BaseModel, validate_assignment=True):
# print("OOO2")
if isinstance(result, RestResourceBase):
exclude: Optional[dict[str, bool]] = None
raw_exclude = RestResourceWalker_Root__tree_exclude(result).process()
exclude = next(iter(raw_exclude.values()))
return json.dumps(result.model_dump(mode="json", exclude=exclude))
# exclude: Optional[dict[str, bool]] = None
# raw_exclude = RestResourceWalker_Root__tree_exclude(result).process()
# exclude = next(iter(raw_exclude.values()))
# return json.dumps(result.model_dump(mode="json", exclude=exclude))
return json.dumps(result.model_dump(mode="json"))
if result is not None:
return json.dumps(result, cls=_JSONEncoder)

View File

@@ -95,7 +95,9 @@ class ResourceHandler(
self.req: RestRequest
if prev_handler is not None:
self.prev_handler = prev_handler
self.req = self._request_factory.update_RestRequest(self.prev_handler.req)
self.req = prev_handler.get_request()
self._request_factory.update_RestRequest(self.req)
elif None in [url, verb]:
raise RuntimeError("if req not set, url,verb must be setted")
else:
@@ -129,6 +131,9 @@ class ResourceHandler(
cls._ar_resource_handler_cls_.append(other_cls)
return other_cls
def get_request(self) -> RestRequest:
return self.req
def process_verb(
self,
) -> Optional[_T_Resource | T_DictKey | list[T_DictKey]]:
@@ -455,10 +460,14 @@ class ResourceHandler_RestResourceBase(
if self.req.get_resource_origin(0) == "/":
return
if (
self.req.get_resource_origin(0) not in self.resource.model_fields
or self.resource.model_fields[self.req.get_resource_origin(0)].exclude is True
):
# print("======")
# print(self.req.get_resource_origin(0))
# print(len(self.req.get_url_stack()))
# print(self.resource._model_dump_excluded_)
# print(type(self.resource))
# print(self.resource.exclude)
if self.req.get_resource_origin(0) not in self.resource.model_fields:
raise RuntimeError(f"Unknown or not allowed field access detected: {self.req.get_url_stack()}")
def _handle_process_get(self, params) -> RestResourceBase:
@@ -471,11 +480,11 @@ class ResourceHandler_RestResourceBase(
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: ResourcePlugin_field = cast(ResourcePlugin_field, self.resource._plugins_[key])
plugin_field: ResourcePlugin_field = cast(ResourcePlugin_field, self.resource._plugins_[key](self.req))
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_field: ResourcePlugin_field = cast(ResourcePlugin_RestResourceBase, self.resource._plugins_[key])
plugin_field: ResourcePlugin_field = cast(ResourcePlugin_RestResourceBase, self.resource._plugins_[key](self.req))
value = getattr(self.resource, key)
setattr(self.resource, key, plugin_field.handle_resource_get(value, params))
@@ -496,14 +505,14 @@ class ResourceHandler_RestResourceBase(
if isinstance(self.resource._plugins_[key], ResourcePlugin_field):
plugin_rsrc: ResourcePlugin_RestResourceBase = cast(
ResourcePlugin_RestResourceBase,
self.resource._plugins_[key],
self.resource._plugins_[key](self.req),
)
value = plugin_rsrc.handle_field_get(value, params)
elif isinstance(self.resource._plugins_[key], ResourcePlugin_RestResourceBase):
plugin_rsrc: ResourcePlugin_RestResourceBase = cast(
ResourcePlugin_RestResourceBase,
self.resource._plugins_[key],
self.resource._plugins_[key](self.req),
)
value = plugin_rsrc.handle_resource_get(value, params)
@@ -523,7 +532,7 @@ class ResourceHandler_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: ResourcePlugin_field = cast(ResourcePlugin_field, _new_resrc._plugins_[key](self.req))
value = getattr(_new_resrc, key)
setattr(_new_resrc, key, plugin_field.handle_field_put(value, params))
@@ -539,7 +548,7 @@ class ResourceHandler_RestResourceBase(
if key in self.prev_handler.prev_handler.resource._plugins_:
plugin_rsrc: ResourcePlugin_RestResourceBase = cast(
ResourcePlugin_RestResourceBase,
self.prev_handler.prev_handler.resource._plugins_[key],
self.prev_handler.prev_handler.resource._plugins_[key](self.req),
)
_new_resrc = plugin_rsrc.handle_dict_elem_put(_new_resrc, params)
# element is within a RestResourceBase
@@ -548,7 +557,7 @@ class ResourceHandler_RestResourceBase(
if key in self.prev_handler.resource._plugins_:
plugin_rsrc: ResourcePlugin_RestResourceBase = cast(
ResourcePlugin_RestResourceBase,
self.prev_handler.resource._plugins_[key],
self.prev_handler.resource._plugins_[key](self.req),
)
_new_resrc = plugin_rsrc.handle_resource_put(_new_resrc, params)
@@ -597,7 +606,7 @@ 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)],
self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)](self.req),
)
return plugin_simple.handle_field_get(self.resource, params)
@@ -616,7 +625,7 @@ class ResourceHandler_simple(
# print("PLUGIN FOUND")
plugin_simple: ResourcePlugin_field = cast(
ResourcePlugin_field,
self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)],
self.prev_handler.resource._plugins_[self.req.get_resource_origin(1)](self.req),
)
# print(value)
value = plugin_simple.handle_field_put(value, params)

View File

@@ -10,6 +10,7 @@ from .rest_types import (
TV_RestResourceBase,
)
from .rest_request import RestRequest
if TYPE_CHECKING or True:
from .rest_request_opt import (
@@ -26,15 +27,16 @@ if TYPE_CHECKING or True:
class ResourcePlugin(Protocol):
cookies: dict[str, str] = dict()
def __init__(self, request: RestRequest) -> None:
self.request: RestRequest = request
def set_cookie(self, name: str, value: str):
def set_resp_cookie(self, name: str, value: str):
# print("AAA")
# print(name)
# print(value)
# print(self.cookies)
# print(type(self.cookies))
self.cookies[name] = value
self.request.outgoing_cookie[name] = value
@runtime_checkable

View File

@@ -55,12 +55,13 @@ class RestResourceWalker_Sub(ABC, Generic[TV_RestResourceWalkerFutureResult]):
resource_name: str,
resource: FieldInfo | Type["RestResourceBase"],
parent: Optional[RestResourceWalker_Sub] = None,
argument: Optional[any] = None,
) -> Optional[RestResourceWalker_Sub]:
for sub in subs:
_is_valid, _anno, _optional = sub.check_type(resource)
if _is_valid is True:
return sub(resource_name, resource, parent, _anno, _optional)
return sub(resource_name, resource, parent, _anno, _optional, argument)
raise RuntimeError(f"Incompatible Field Found: {type(resource).__name__}")
return None
@@ -70,8 +71,10 @@ class RestResourceWalker_Sub(ABC, Generic[TV_RestResourceWalkerFutureResult]):
resource: FieldInfo | Type["RestResourceBase"],
parent: Optional[RestResourceWalker_Sub] = None,
annotation: Optional[type["RestResourceBase"]] = None,
optional: Optional[bool] = None,
_optional: Optional[bool] = None,
argument: Optional[any] = None,
):
self.argument: any = argument
self.resource_name: str = resource_name
self.resource: FieldInfo | Type["RestResourceBase"] = resource
self.parent: Optional[RestResourceWalker_Sub] = parent
@@ -84,11 +87,11 @@ class RestResourceWalker_Sub(ABC, Generic[TV_RestResourceWalkerFutureResult]):
self.annotation: type["RestResourceBase"]
self.optional: bool
if annotation is None or optional is None:
if annotation is None or _optional is None:
self.annotation, self.optional = self.ProcessAnnotation(resource)
else:
self.annotation = annotation
self.optional = optional
self.optional = _optional
if self.annotation is None:
raise RuntimeError("Only annotated types are allowed in RestResourceBase derived classes")
@@ -120,10 +123,6 @@ class RestResourceWalker_Sub(ABC, Generic[TV_RestResourceWalkerFutureResult]):
print("-------------------")
"""
@classmethod
def init_sub(cls, walker: RestResourceWalker_Root) -> None:
pass
@abstractmethod
def get_future(self) -> Optional[RestResourceWalkerFutureResult]:
return self.future_result
@@ -238,6 +237,7 @@ class RestResourceWalker_Root:
]
def __init__(self, resource: "RestResourceBase" | Type["RestResourceBase"]) -> None:
self.subwalker_argument: any = None
from .rest_resource import RestResourceBase
self.resource: Type["RestResourceBase"]
@@ -246,14 +246,11 @@ class RestResourceWalker_Root:
else:
self.resource = resource
def process(self, deep_limit: Optional[int] = None) -> Optional[TV_RestResourceWalkerFutureResult]:
def process(self, argument: Optional[any] = None, deep_limit: Optional[int] = None) -> Optional[TV_RestResourceWalkerFutureResult]:
current_deep: int = 0
for cls_Sub in self.cls_RestResourceWalker_Sub:
_self = self
cls_Sub.init_sub(_self)
sub_walker_initial: Optional[RestResourceWalker_Sub] = RestResourceWalker_Sub.get(
self.cls_RestResourceWalker_Sub, "/", self.resource, None
self.cls_RestResourceWalker_Sub, "/", self.resource, None, argument
)
if sub_walker_initial is not None:
@@ -270,10 +267,7 @@ class RestResourceWalker_Root:
new_resource_list = []
for resource_name, resource, parent_sub_walker in resource_list:
sub_walker = RestResourceWalker_Sub.get(
self.cls_RestResourceWalker_Sub,
resource_name,
resource,
parent_sub_walker,
self.cls_RestResourceWalker_Sub, resource_name, resource, parent_sub_walker, argument
)
if sub_walker is not None:
sub_walker.process()

View File

@@ -65,7 +65,7 @@ def init_classes():
if _UserLogin.username == resource.username and _UserLogin.secret == resource.secret:
print("user connected")
_UserLogin.token = token_hex(16)
self.set_cookie("test", _UserLogin.token)
self.set_resp_cookie("test", _UserLogin.token)
print(f"generated token: {_UserLogin.token}")
return resource
print("login NOT found")
@@ -84,7 +84,7 @@ def init_classes():
class RootApp(RestResourceBase):
login: Login = Field(
default=Login(),
plugin=ResourcePlugin_Login(),
plugin=ResourcePlugin_Login,
)
# this add the classes to globals to allow using them later on
@@ -155,8 +155,8 @@ class Test_RestAPI_LOGIN_Web(unittest.TestCase):
self.assertEqual(response.status_code, 201)
response = s.get(f"http://{ip}:{port}/login")
response = s.get(f"http://{ip}:{port}/login")
response = s.get(f"http://{ip}:{port}/login")
response = s.get(f"http://{ip}:{port}/")
finally:
proc.terminate()

View File

@@ -47,13 +47,13 @@ def init_classes():
class Info_get(RestResourceBase):
# test plugin injection within annotation
# + test plugin on a simple field
version: Annotated[str, Field(plugin=ResourcePlugin_version_get())]
version: Annotated[str, Field(plugin=ResourcePlugin_version_get)]
api_version: str
class Info_put(RestResourceBase):
# test plugin injection within annotation
# + test plugin on a simple field
version: Annotated[str, Field(plugin=ResourcePlugin_version_put())]
version: Annotated[str, Field(plugin=ResourcePlugin_version_put)]
api_version: str
@register_rest_rootpoint
@@ -62,7 +62,7 @@ def init_classes():
# + test plugin on a RestResourceBase field
info: Info_get = Field(
default=Info_get(version="0.0.1", api_version="0.0.2"),
plugin=ResourcePlugin_Info(),
plugin=ResourcePlugin_Info,
)
info_put: Info_put = Field(
default=Info_put(version="0.0.1", api_version="0.0.2"),
@@ -83,7 +83,7 @@ def init_bad_plugin1():
return resource
class TestResource(RestResourceBase):
tetvaluestr: Annotated[str, Field(plugin=ResourcePlugin_TestResource())]
tetvaluestr: Annotated[str, Field(plugin=ResourcePlugin_TestResource)]
@register_rest_rootpoint
class RootApp2(RestResourceBase):
@@ -99,7 +99,7 @@ def init_bad_plugin2():
return resource
class TestResource(RestResourceBase):
tetvaluestr: Annotated[str, Field(plugin=ResourcePlugin_TestResource())]
tetvaluestr: Annotated[str, Field(plugin=ResourcePlugin_TestResource)]
@register_rest_rootpoint
class RootApp2(RestResourceBase):
@@ -114,7 +114,7 @@ def init_bad_plugin3():
pass
class TestResource(RestResourceBase):
tetvaluestr: Annotated[str, Field(plugin=ResourcePlugin_TestResource())]
tetvaluestr: Annotated[str, Field(plugin=ResourcePlugin_TestResource)]
@register_rest_rootpoint
class RootApp2(RestResourceBase):

View File

@@ -1,7 +1,7 @@
from __future__ import annotations
import unittest
from typing import Annotated, Optional
from typing import Optional, cast
from os import chdir
from pathlib import Path
@@ -28,50 +28,39 @@ chdir(testdir_path.parent.resolve())
class RestResourceWalker_Sub_T_Dict_TEST_Print(RestResourceWalker_Sub_T_Dict):
counter: dict[str, int] = {}
@classmethod
def init_sub(cls, walker: RestResourceWalker_Root) -> None:
cls.counter = {}
cls_counter: dict[str, int] = {}
def process(self) -> None:
if self.resource_name not in self.counter:
self.counter[self.resource_name] = 0
self.counter[self.resource_name] = self.counter[self.resource_name] + 1
counter = self.cls_counter
if self.resource_name not in counter:
counter[self.resource_name] = 0
counter[self.resource_name] = counter[self.resource_name] + 1
print(f"DICT {self.resource_name} {self.counter[self.resource_name]}")
print(f"DICT {self.resource_name} {counter[self.resource_name]}")
class RestResourceWalker_Sub_RestFields_TEST_Print(RestResourceWalker_Sub_RestFields):
counter: dict[str, int] = {}
@classmethod
def init_sub(cls, walker: RestResourceWalker_Root) -> None:
cls.counter = {}
cls_counter: dict[str, int] = {}
def process(self) -> None:
if self.resource_name not in self.counter:
self.counter[self.resource_name] = 0
self.counter[self.resource_name] = self.counter[self.resource_name] + 1
counter = self.cls_counter
if self.resource_name not in counter:
counter[self.resource_name] = 0
counter[self.resource_name] = counter[self.resource_name] + 1
print(f"FIELD {self.resource_name} {self.counter[self.resource_name]}")
print(f"FIELD {self.resource_name} {counter[self.resource_name]}")
class RestResourceWalker_Sub_RestResourceBase_TEST_Print(
RestResourceWalker_Sub_RestResourceBase
):
counter: dict[str, int] = {}
@classmethod
def init_sub(cls, walker: RestResourceWalker_Root) -> None:
cls.counter = {}
class RestResourceWalker_Sub_RestResourceBase_TEST_Print(RestResourceWalker_Sub_RestResourceBase):
cls_counter: dict[str, int] = {}
def process(self) -> None:
if self.resource_name not in self.counter:
self.counter[self.resource_name] = 0
self.counter[self.resource_name] = self.counter[self.resource_name] + 1
counter = self.cls_counter
if self.resource_name not in counter:
counter[self.resource_name] = 0
counter[self.resource_name] = counter[self.resource_name] + 1
print(f"RestResource {self.resource_name} {self.counter[self.resource_name]}")
print(f"RestResource {self.resource_name} {counter[self.resource_name]}")
class RestResourceWalker_Root_TEST_Print(RestResourceWalker_Root):
@@ -114,11 +103,12 @@ class Test_Walker(unittest.TestCase):
init_classes()
def test_walk_class(self):
RestResourceWalker_Sub_T_Dict_TEST_Print.cls_counter = {}
RestResourceWalker_Sub_RestFields_TEST_Print.cls_counter = {}
RestResourceWalker_Sub_RestResourceBase_TEST_Print.cls_counter = {}
test = RestResourceWalker_Root_TEST_Print(RootApp)
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(
StringIO()
) as capted_stderr:
test.process()
with redirect_stdout(StringIO()) as capted_stdout:
test.process({})
self.assertIn("RestResource info 1", capted_stdout.getvalue())
self.assertIn("RestResource info2 1", capted_stdout.getvalue())
self.assertIn("DICT peoples 1", capted_stdout.getvalue())
@@ -133,12 +123,13 @@ class Test_Walker(unittest.TestCase):
self.assertIn("FIELD last_name 1", capted_stdout.getvalue())
def test_walk_obj(self):
RestResourceWalker_Sub_T_Dict_TEST_Print.cls_counter = {}
RestResourceWalker_Sub_RestFields_TEST_Print.cls_counter = {}
RestResourceWalker_Sub_RestResourceBase_TEST_Print.cls_counter = {}
instRootApp = RootApp()
test = RestResourceWalker_Root_TEST_Print(instRootApp)
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(
StringIO()
) as capted_stderr:
test.process()
with redirect_stdout(StringIO()) as capted_stdout:
test.process({})
self.assertIn("RestResource info 1", capted_stdout.getvalue())
self.assertIn("RestResource info2 1", capted_stdout.getvalue())
self.assertIn("DICT peoples 1", capted_stdout.getvalue())
@@ -153,11 +144,12 @@ class Test_Walker(unittest.TestCase):
self.assertIn("FIELD last_name 1", capted_stdout.getvalue())
def test_walk_obj_nested_RestResource(self):
RestResourceWalker_Sub_T_Dict_TEST_Print.cls_counter = {}
RestResourceWalker_Sub_RestFields_TEST_Print.cls_counter = {}
RestResourceWalker_Sub_RestResourceBase_TEST_Print.cls_counter = {}
instRootApp = RootApp()
test = RestResourceWalker_Root_TEST_Print(instRootApp.info)
with redirect_stdout(StringIO()) as capted_stdout, redirect_stderr(
StringIO()
) as capted_stderr:
test.process()
with redirect_stdout(StringIO()) as capted_stdout:
test.process({})
self.assertIn("FIELD version 1", capted_stdout.getvalue())
self.assertIn("FIELD api_version 1", capted_stdout.getvalue())