cengal.code_flow_control.multiinterface_essence.versions.v_0.essence
Module Docstring Docstrings: http://www.python.org/dev/peps/pep-0257/
1#!/usr/bin/env python 2# coding=utf-8 3 4# Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space> 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17 18 19""" 20Module Docstring 21Docstrings: http://www.python.org/dev/peps/pep-0257/ 22""" 23 24 25__author__ = "ButenkoMS <gtalk@butenkoms.space>" 26__copyright__ = "Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space>" 27__credits__ = ["ButenkoMS <gtalk@butenkoms.space>", ] 28__license__ = "Apache License, Version 2.0" 29__version__ = "4.4.1" 30__maintainer__ = "ButenkoMS <gtalk@butenkoms.space>" 31__email__ = "gtalk@butenkoms.space" 32# __status__ = "Prototype" 33__status__ = "Development" 34# __status__ = "Production" 35 36 37from inspect import isclass 38from cengal.introspection.inspect import get_exception 39from cengal.code_flow_control.args_manager import EntityArgsHolder 40from typing import Any, Callable, NoReturn, Set, Dict, Type, TypeVar, Generic, Optional, Union, Sequence 41# from enum import Enum 42 43 44class EssenceModelException(Exception): 45 pass 46 47 48class IncompatibleEssenceModelError(RuntimeError, EssenceModelException): 49 # Must be raised by constructor of EssenceInterface class if incompatible essence_model was given 50 pass 51 52 53class UnsuitableEssenceInterfaceError(RuntimeError, EssenceModelException): 54 pass 55 56 57class EssenceInterfaceIsNotApplicableError(UnsuitableEssenceInterfaceError, EssenceModelException): 58 # Must be raised by EssenceModel.__call__ when requested EssenceInterface is not active (applicable) 59 pass 60 61 62class EssenceInterfaceIsNotRegisteredError(UnsuitableEssenceInterfaceError, EssenceModelException): 63 # Must be raised by EssenceModel.__call__ when requested EssenceInterface is not registered 64 pass 65 66 67class EssenceModelCanNotInjectSelfError(RuntimeError, EssenceModelException): 68 """Must be raised by EssenceModel.emi_inject_model when an object of a class A(EssenceModel) tries 69 to inject class A - type(self) 70 71 This behavior is restricted since it may lead to: 72 - endless recursion 73 - interface collisions when high order model will include several instances of the same interface class""" 74 pass 75 76 77class EssenceModelCanNotBeInjectedError(RuntimeError, EssenceModelException): 78 # Must be raised by EssenceModel.emi_inject_model if injectable model can not be injected (incompatible) 79 pass 80 81 82class EssenceModelIsNotInjectedError(RuntimeError, EssenceModelException): 83 # Must be raised by EssenceModel.emi_injected_model if not injected model was requested 84 pass 85 86 87class IncompatibleHighOrderEssenceModelError(RuntimeError, EssenceModelException): 88 # Must be raised by EssenceModel.emu_behave_as_unknown_model method if incompatible on attempt to inject it to 89 # incompatible high order model 90 pass 91 92 93class UnknownEssenceModeBehaviorWasNotImplementedProperlyError(NotImplementedError, EssenceModelException): 94 pass 95 96 97class EssenceModelInheritanceAbstract: 98 def __call__(self, interface_class: Type['EssenceInterface'], worker: Optional[Callable] = None, failed_worker: Optional[Callable] = None, *args, **kwargs) -> Any: 99 raise NotImplementedError 100 101 def em_interface(self, interface_class: Type['EssenceInterface']) -> 'EssenceInterface': 102 raise NotImplementedError 103 104 def em_has_interface(self, interface_class: Type['EssenceInterface']) -> bool: 105 raise NotImplementedError 106 107 def em_interface_active(self, interface_class: Type['EssenceInterface']) -> bool: 108 raise NotImplementedError 109 110 def em_active_interfaces(self) -> Set[Type['EssenceInterface']]: 111 raise NotImplementedError 112 113 def em_all_interfaces(self) -> Set[Type['EssenceInterface']]: 114 raise NotImplementedError 115 116 def _em_check_applicability_of_interfaces(self) -> None: 117 raise NotImplementedError 118 119 def em_on_model_updated(self, interface_class: Type['EssenceInterface'], *args, **kwargs): 120 raise NotImplementedError 121 122 def em_add_interface(self, interface_class: Type['EssenceInterface'], *args, **kwargs) -> bool: 123 raise NotImplementedError 124 125 def em_remove_interface(self, interface_class: Type['EssenceInterface']) -> bool: 126 raise NotImplementedError 127 128 129class EssenceModelInjectionAbstract: 130 def emi_on_registered_in_high_order_model(self, high_order_model: 'EssenceModelInjectionAbstract'): 131 raise NotImplementedError 132 133 def emi_on_unregistering_from_high_order_model(self): 134 raise NotImplementedError 135 136 def _emi_notify_high_order_model_about_self_update(self, *args, **kwargs): 137 raise NotImplementedError 138 139 def emi_inject_model(self, essence_model: 'EssenceModelInjectionAbstract') -> bool: 140 raise NotImplementedError 141 142 def emi_injected_models(self): 143 raise NotImplementedError 144 145 def emi_injected_model(self, essence_model_class: Type['EssenceModelInjectionAbstract']): 146 raise NotImplementedError 147 148 def emi_on_injected_model_updated( 149 self, essence_model_class: Type['EssenceModelInjectionAbstract'], *args, **kwargs): 150 raise NotImplementedError 151 152 def emi_remove_injected_model(self, essence_model_class: Type['EssenceModelInjectionAbstract']): 153 raise NotImplementedError 154 155 156class EssenceModelUnknownInjectionAbstract: 157 def emu_is_compatible_high_order_model(self, high_order_model_class: Type['EssenceModelInjectionAbstract']) -> bool: 158 raise NotImplementedError 159 160 def emu_behave_as_unknown_model(self): 161 raise NotImplementedError 162 163 def emu_on_behave_as_unknown_model(self): 164 raise NotImplementedError 165 166 def _emu_register_on_model_changed_callback(self, requester: 'EssenceModelUnknownInjectionAbstract'): 167 raise NotImplementedError 168 169 def _emu_deregister_on_model_changed_callback(self, requester: 'EssenceModelUnknownInjectionAbstract'): 170 raise NotImplementedError 171 172 def _emu_notify_unknown_models_about_self_update(self): 173 raise NotImplementedError 174 175 def emu_on_model_changed_callback(self): 176 raise NotImplementedError 177 178 def emu_is_in_unknown_model_behavior(self): 179 raise NotImplementedError 180 181 182class EssenceModel(EssenceModelInheritanceAbstract, EssenceModelInjectionAbstract, EssenceModelUnknownInjectionAbstract): 183 """Must contain related data in a consistent state. 184 185 In order to do this, you must reload `em_on_model_updated()` and `emi_on_injected_model_updated()` methods. 186 Your interfaces can provide some appropriate information though an additional `parameters of em_on_model_updated()` 187 and `emi_on_injected_model_updated()` methods. 188 189 Do not forget to: 190 - run `self._emi_notify_high_order_model_about_self_update(type(self), interface_class, *args, **kwargs)` at 191 the end of your `em_on_model_updated()` 192 - run `self._emi_notify_high_order_model_about_self_update(type(self), essence_model_class, *args, **kwargs)` at 193 the end of your `emi_on_injected_model_updated()`""" 194 195 emi_compatible_injectable_essence_model_classes: Set[Type['EssenceModel']] = set() 196 # emu_compatible_high_order_essence_model_class: Optional[Type['EssenceModel']] = None 197 emu_compatible_high_order_essence_model_classes: Set[Type['EssenceModel']] = set() 198 199 def __init__(self): 200 self.__em_interfaces: Dict[Type['EssenceInterface'], 'EssenceInterface'] = dict() 201 self.__em_possible_interfaces: Dict[Type['EssenceInterface'], 'EssenceInterface'] = dict() 202 self.__emi_injected_models: Dict[Type['EssenceModel'], 'EssenceModel'] = dict() 203 self.__emi_raise_on_uninjectable_model: bool = True 204 self.__emi_high_order_model: Optional['EssenceModel'] = None 205 self.__emu_in_unknown_model_behavior: bool = False 206 self.__emu_raise_on_incompatible_high_order_model: bool = True 207 self.__emu_unknown_injected_models: Dict[Type['EssenceModel'], 'EssenceModel'] = dict() 208 209 def em_interface(self, interface_class: Type['EssenceInterface']) -> 'EssenceInterface': 210 """Should be called in order to get needed model interface""" 211 if interface_class in self.__em_interfaces: 212 return self.__em_interfaces[interface_class] 213 else: 214 injected_model_interface = None 215 for injected_model_class, injected_model in self.__emi_injected_models.items(): 216 model: 'EssenceModel' = injected_model 217 if model.em_interface_active(interface_class): 218 injected_model_interface = model.em_interface(interface_class) 219 break 220 if injected_model_interface: 221 return injected_model_interface 222 elif interface_class in self.__em_possible_interfaces: 223 raise EssenceInterfaceIsNotApplicableError 224 else: 225 raise EssenceInterfaceIsNotRegisteredError 226 227 def __call__(self, interface_class: Type['EssenceInterface'], worker: Callable, failed_worker: Optional[Callable] = None, *args, **kwargs) -> Any: 228 interface = None 229 exception = None 230 try: 231 interface = self.em_interface(interface_class) 232 except (EssenceInterfaceIsNotApplicableError, EssenceInterfaceIsNotRegisteredError) as exc: 233 exception = get_exception() 234 235 if interface: 236 return worker(interface, *args, **kwargs) 237 else: 238 if failed_worker: 239 return failed_worker(interface, exception, *args, **kwargs) 240 else: 241 return None 242 243 def em_has_interface(self, interface_class: Type['EssenceInterface']) -> bool: 244 has_own_interface = (interface_class in self.__em_interfaces) or \ 245 (interface_class in self.__em_possible_interfaces) 246 one_of_injected_models_has_interface = False 247 for injected_model_class, injected_model in self.__emi_injected_models.items(): 248 model: 'EssenceModel' = injected_model 249 if model.em_has_interface(interface_class) or model.em_interface_active(interface_class): 250 one_of_injected_models_has_interface = True 251 break 252 return has_own_interface or one_of_injected_models_has_interface 253 254 def em_interface_active(self, interface_class: Type['EssenceInterface']) -> bool: 255 own_interface_active = interface_class in self.__em_interfaces 256 one_of_injected_models_has_active_interface = False 257 for injected_model_class, injected_model in self.__emi_injected_models.items(): 258 model: 'EssenceModel' = injected_model 259 if model.em_interface_active(interface_class): 260 one_of_injected_models_has_active_interface = True 261 break 262 return own_interface_active or one_of_injected_models_has_active_interface 263 264 def em_active_interfaces(self) -> Set[Type['EssenceInterface']]: 265 own_active_interfaces = set(self.__em_interfaces) 266 injected_models_active_interfaces: Set[Type['EssenceInterface']] = set() 267 for injected_model_class, injected_model in self.__emi_injected_models.items(): 268 model: 'EssenceModel' = injected_model 269 injected_models_active_interfaces.update(model.em_active_interfaces()) 270 return own_active_interfaces | injected_models_active_interfaces 271 272 def em_all_interfaces(self) -> Set[Type['EssenceInterface']]: 273 own_all_interfaces = set(self.__em_interfaces) | set(self.__em_possible_interfaces) 274 injected_models_all_interfaces: Set[Type['EssenceInterface']] = set() 275 for injected_model_class, injected_model in self.__emi_injected_models.items(): 276 model: 'EssenceModel' = injected_model 277 injected_models_all_interfaces.update(model.em_all_interfaces()) 278 return own_all_interfaces | injected_models_all_interfaces 279 280 def _em_check_applicability_of_interfaces(self) -> None: 281 new_interfaces = dict() 282 new_possible_interfaces = dict() 283 284 for interface_class, interface in self.__em_interfaces.items(): 285 if interface._applicable_impl(): 286 new_interfaces[interface_class] = interface 287 else: 288 new_possible_interfaces[interface_class] = interface 289 290 for interface_class, interface in self.__em_possible_interfaces.items(): 291 if interface._applicable_impl(): 292 new_interfaces[interface_class] = interface 293 else: 294 new_possible_interfaces[interface_class] = interface 295 296 self.__em_interfaces = new_interfaces 297 self.__em_possible_interfaces = new_possible_interfaces 298 299 def em_on_model_updated(self, interface_class: Type['EssenceInterface'], *args, **kwargs): 300 """Must be run by EssenceInterface (by running EssenceInterface.notify_model_about_change method) after changing 301 model's data. It is enough to run in once per a method - at the end of the method work. 302 In 'super' in method of inherit class should be run at the end of the method""" 303 self._em_check_applicability_of_interfaces() 304 self._emu_notify_unknown_models_about_self_update() 305 self._emi_notify_high_order_model_about_self_update(type(self), interface_class, *args, **kwargs) 306 307 def em_add_interface(self, interface_class: Type['EssenceInterface'], *args, **kwargs) -> bool: 308 if (interface_class in self.__em_interfaces) or (interface_class in self.__em_possible_interfaces): 309 return False 310 else: 311 interface = interface_class(self, *args, **kwargs) 312 if interface._applicable_impl(): 313 self.__em_interfaces[interface_class] = interface 314 else: 315 self.__em_possible_interfaces[interface_class] = interface 316 return True 317 318 def em_remove_interface(self, interface_class: Type['EssenceInterface']) -> bool: 319 if interface_class in self.__em_interfaces: 320 del self.__em_interfaces[interface_class] 321 return True 322 elif interface_class in self.__em_possible_interfaces: 323 del self.__em_possible_interfaces[interface_class] 324 return True 325 else: 326 return False 327 328 def emi_on_registered_in_high_order_model(self, high_order_model: 'EssenceModel'): 329 """Will be called after high order model successfully registered this mode""" 330 self.__emi_high_order_model = high_order_model 331 332 def emi_on_unregistering_from_high_order_model(self): 333 # Will be called before high order model actually unregistered this mode 334 self.__emi_high_order_model = None 335 self.__emu_in_unknown_model_behavior = False 336 337 def emi_inject_model(self, essence_model: 'EssenceModel'): 338 # Should use 'EssenceModel' instead of Type['EssenceModel'] since we should use result of fully constructed 339 # essence_model with all needed interfaces - result of an appropriate factory work 340 essence_model_class = type(essence_model) 341 if isinstance(essence_model, type(self)) or isinstance(self, essence_model_class): 342 raise EssenceModelCanNotInjectSelfError 343 344 injectable_model = False 345 if essence_model_class in self.emi_compatible_injectable_essence_model_classes: 346 injectable_model = True 347 else: 348 if essence_model.emu_is_compatible_high_order_model(type(self)): 349 injectable_model = True 350 else: 351 if self.__emu_raise_on_incompatible_high_order_model: 352 raise IncompatibleHighOrderEssenceModelError 353 354 injected = False 355 if injectable_model: 356 self.__emi_injected_models[essence_model_class] = essence_model 357 essence_model.emi_on_registered_in_high_order_model(self) 358 if essence_model_class not in self.emi_compatible_injectable_essence_model_classes: 359 essence_model.emu_behave_as_unknown_model() 360 361 injected = True 362 else: 363 if self.__emi_raise_on_uninjectable_model: 364 raise EssenceModelCanNotBeInjectedError 365 366 return injected 367 368 def emi_injected_models(self): 369 return set(self.__emi_injected_models) 370 371 def emi_injected_model(self, essence_model_class: Type['EssenceModel']): 372 if essence_model_class in self.__emi_injected_models: 373 return self.__emi_injected_models[essence_model_class] 374 else: 375 raise EssenceModelIsNotInjectedError 376 377 def emi_on_injected_model_updated(self, essence_model_class: Type['EssenceModel'], *args, **kwargs): 378 # In 'super' in method of inherit class should be run at the end of the method 379 # With deep injection it will be like (model_3, model_2, model_1, interface_1, arg_1, arg_2, arg_3) 380 # where `interface_1` is an interface of the `model_1` 381 self._em_check_applicability_of_interfaces() 382 self._emu_notify_unknown_models_about_self_update() 383 self._emi_notify_high_order_model_about_self_update(type(self), essence_model_class, *args, **kwargs) 384 385 def _emi_notify_high_order_model_about_self_update(self, *args, **kwargs): 386 if self.__emi_high_order_model and (not self.__emu_in_unknown_model_behavior): 387 high_order_model: 'EssenceModel' = self.__emi_high_order_model 388 high_order_model.emi_on_injected_model_updated(*args, **kwargs) 389 390 def emi_remove_injected_model(self, essence_model_class: Type['EssenceModel']): 391 injected_model: 'EssenceModel' = self.__emi_injected_models[essence_model_class] 392 self._emu_deregister_on_model_changed_callback(injected_model) 393 injected_model.emi_on_unregistering_from_high_order_model() 394 del self.__emi_injected_models[essence_model_class] 395 396 def emu_is_compatible_high_order_model(self, high_order_model_class: Type['EssenceModelInjectionAbstract']) -> bool: 397 """Might be overloaded in order to make this model compatible with more than one high order models 398 399 Args: 400 high_order_model_class (Type[): [description] 401 402 Returns: 403 bool: [description] 404 """ 405 # return high_order_model_class == self.emu_compatible_high_order_essence_model_class 406 return high_order_model_class in self.emu_compatible_high_order_essence_model_classes 407 408 def emu_behave_as_unknown_model(self): 409 # Should be called by a high order model for an unknown injected model 410 # if type(self.__emi_high_order_model) != self.emu_compatible_high_order_essence_model_class: 411 if not self.emu_is_compatible_high_order_model(self.__emi_high_order_model): 412 raise IncompatibleHighOrderEssenceModelError 413 self.__emi_high_order_model._emu_register_on_model_changed_callback(type(self)) 414 self.__emu_in_unknown_model_behavior = True 415 self.emu_on_behave_as_unknown_model() 416 417 def emu_on_behave_as_unknown_model(self): 418 pass 419 420 def _emu_register_on_model_changed_callback(self, requester: 'EssenceModelUnknownInjectionAbstract'): 421 self.__emu_unknown_injected_models[type[requester]] = requester 422 423 def _emu_deregister_on_model_changed_callback(self, requester: 'EssenceModelUnknownInjectionAbstract'): 424 model_type = type(requester) 425 if model_type in self.__emu_unknown_injected_models: 426 del self.__emu_unknown_injected_models[model_type] 427 428 def _emu_notify_unknown_models_about_self_update(self, *args, **kwargs): 429 for umodel in self.__emu_unknown_injected_models.values(): 430 unknown_model: 'EssenceModel' = umodel 431 unknown_model.emu_on_model_changed_callback() 432 433 def emu_on_model_changed_callback(self): 434 raise UnknownEssenceModeBehaviorWasNotImplementedProperlyError 435 436 def emu_is_in_unknown_model_behavior(self): 437 return self.__emu_in_unknown_model_behavior 438 439 440Model = TypeVar('Model', bound=EssenceModel) 441 442 443class EssenceInterface(Generic[Model]): 444 essence_model_class: Type[Model] = EssenceModel 445 446 def __init_subclass__(cls, /, essence_model_class: Optional[Type[Model]] = None, **kwargs): 447 super().__init_subclass__(**kwargs) 448 cls.essence_model_class = EssenceModel if essence_model_class is None else essence_model_class 449 450 def __init__(self, essence_model: Model, *args, **kwargs): 451 self.essence_model: Model = essence_model 452 self.em: Model = essence_model 453 self._on_applicability_changed_handlers: Set[Callable] = set() 454 self._applicability_state: bool = None 455 self.__check_essence_mode_type() 456 457 def __check_essence_mode_type(self): 458 if not isinstance(self.essence_model, self.essence_model_class): 459 raise IncompatibleEssenceModelError 460 461 def applicable(self) -> bool: 462 return True 463 464 def _applicable_impl(self) -> bool: 465 result: bool = self.applicable() 466 if result != self._applicability_state: 467 self._applicability_state = result 468 for handler in self._on_applicability_changed_handlers: 469 handler(self) 470 471 return result 472 473 def add_on_applicability_changed_handler(self, handler: Callable): 474 self._on_applicability_changed_handlers.add(handler) 475 476 def discard_on_applicability_changed_handler(self, handler: Callable): 477 self._on_applicability_changed_handlers.discard(handler) 478 479 def notify_model_about_change(self, *args, **kwargs): 480 # Must be run by EssenceInterface's methods if and after changing model's data. It is enough to run in once per 481 # a method - at the end of the method work. 482 self.essence_model.em_on_model_updated(type(self), *args, **kwargs) 483 484 485def essence_model_changer(func): 486 def wrapper(self: EssenceInterface, *args, **kwargs): 487 try: 488 func(self, *args, **kwargs) 489 finally: 490 self.notify_model_about_change(*args, **kwargs) 491 492 return wrapper 493 494 495em_changer = essence_model_changer 496 497 498class EssenceModelFactoryExample: 499 def __call__(self, *args, **kwargs): 500 model: EssenceModel = EssenceModel() 501 model.em_add_interface(EssenceInterface) 502 return model 503 504 505def simple_essence_model_factory( 506 model: Union[Type[EssenceModel], EntityArgsHolder], 507 interfaces: Union[ 508 Type[EssenceInterface], 509 EntityArgsHolder, 510 Sequence[Union[Type[EssenceInterface], EntityArgsHolder]] 511 ] 512 ) -> EssenceModel: 513 model_instance: EssenceModel = model() 514 if isinstance(interfaces, EntityArgsHolder) or (isinstance(interfaces, type) and issubclass(interfaces, EssenceInterface)): 515 interfaces = (interfaces,) 516 517 for interface in interfaces: 518 if isinstance(interface, type): 519 if issubclass(interface, EssenceInterface): 520 model_instance.em_add_interface(interface) 521 elif isinstance(interface, EntityArgsHolder): 522 model_instance.em_add_interface(*interface.entity_args_kwargs()) 523 else: 524 raise TypeError(f'Wrong interface type: {type(interface)}') 525 526 return model_instance 527 528 529simple_em_factory = simple_essence_model_factory
Common base class for all non-exit exceptions.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
49class IncompatibleEssenceModelError(RuntimeError, EssenceModelException): 50 # Must be raised by constructor of EssenceInterface class if incompatible essence_model was given 51 pass
Unspecified run-time error.
Inherited Members
- builtins.RuntimeError
- RuntimeError
- builtins.BaseException
- with_traceback
- args
Unspecified run-time error.
Inherited Members
- builtins.RuntimeError
- RuntimeError
- builtins.BaseException
- with_traceback
- args
58class EssenceInterfaceIsNotApplicableError(UnsuitableEssenceInterfaceError, EssenceModelException): 59 # Must be raised by EssenceModel.__call__ when requested EssenceInterface is not active (applicable) 60 pass
Unspecified run-time error.
Inherited Members
- builtins.RuntimeError
- RuntimeError
- builtins.BaseException
- with_traceback
- args
63class EssenceInterfaceIsNotRegisteredError(UnsuitableEssenceInterfaceError, EssenceModelException): 64 # Must be raised by EssenceModel.__call__ when requested EssenceInterface is not registered 65 pass
Unspecified run-time error.
Inherited Members
- builtins.RuntimeError
- RuntimeError
- builtins.BaseException
- with_traceback
- args
68class EssenceModelCanNotInjectSelfError(RuntimeError, EssenceModelException): 69 """Must be raised by EssenceModel.emi_inject_model when an object of a class A(EssenceModel) tries 70 to inject class A - type(self) 71 72 This behavior is restricted since it may lead to: 73 - endless recursion 74 - interface collisions when high order model will include several instances of the same interface class""" 75 pass
Must be raised by EssenceModel.emi_inject_model when an object of a class A(EssenceModel) tries to inject class A - type(self)
This behavior is restricted since it may lead to: - endless recursion - interface collisions when high order model will include several instances of the same interface class
Inherited Members
- builtins.RuntimeError
- RuntimeError
- builtins.BaseException
- with_traceback
- args
78class EssenceModelCanNotBeInjectedError(RuntimeError, EssenceModelException): 79 # Must be raised by EssenceModel.emi_inject_model if injectable model can not be injected (incompatible) 80 pass
Unspecified run-time error.
Inherited Members
- builtins.RuntimeError
- RuntimeError
- builtins.BaseException
- with_traceback
- args
83class EssenceModelIsNotInjectedError(RuntimeError, EssenceModelException): 84 # Must be raised by EssenceModel.emi_injected_model if not injected model was requested 85 pass
Unspecified run-time error.
Inherited Members
- builtins.RuntimeError
- RuntimeError
- builtins.BaseException
- with_traceback
- args
88class IncompatibleHighOrderEssenceModelError(RuntimeError, EssenceModelException): 89 # Must be raised by EssenceModel.emu_behave_as_unknown_model method if incompatible on attempt to inject it to 90 # incompatible high order model 91 pass
Unspecified run-time error.
Inherited Members
- builtins.RuntimeError
- RuntimeError
- builtins.BaseException
- with_traceback
- args
94class UnknownEssenceModeBehaviorWasNotImplementedProperlyError(NotImplementedError, EssenceModelException): 95 pass
Method or function hasn't been implemented yet.
Inherited Members
- builtins.NotImplementedError
- NotImplementedError
- builtins.BaseException
- with_traceback
- args
98class EssenceModelInheritanceAbstract: 99 def __call__(self, interface_class: Type['EssenceInterface'], worker: Optional[Callable] = None, failed_worker: Optional[Callable] = None, *args, **kwargs) -> Any: 100 raise NotImplementedError 101 102 def em_interface(self, interface_class: Type['EssenceInterface']) -> 'EssenceInterface': 103 raise NotImplementedError 104 105 def em_has_interface(self, interface_class: Type['EssenceInterface']) -> bool: 106 raise NotImplementedError 107 108 def em_interface_active(self, interface_class: Type['EssenceInterface']) -> bool: 109 raise NotImplementedError 110 111 def em_active_interfaces(self) -> Set[Type['EssenceInterface']]: 112 raise NotImplementedError 113 114 def em_all_interfaces(self) -> Set[Type['EssenceInterface']]: 115 raise NotImplementedError 116 117 def _em_check_applicability_of_interfaces(self) -> None: 118 raise NotImplementedError 119 120 def em_on_model_updated(self, interface_class: Type['EssenceInterface'], *args, **kwargs): 121 raise NotImplementedError 122 123 def em_add_interface(self, interface_class: Type['EssenceInterface'], *args, **kwargs) -> bool: 124 raise NotImplementedError 125 126 def em_remove_interface(self, interface_class: Type['EssenceInterface']) -> bool: 127 raise NotImplementedError
130class EssenceModelInjectionAbstract: 131 def emi_on_registered_in_high_order_model(self, high_order_model: 'EssenceModelInjectionAbstract'): 132 raise NotImplementedError 133 134 def emi_on_unregistering_from_high_order_model(self): 135 raise NotImplementedError 136 137 def _emi_notify_high_order_model_about_self_update(self, *args, **kwargs): 138 raise NotImplementedError 139 140 def emi_inject_model(self, essence_model: 'EssenceModelInjectionAbstract') -> bool: 141 raise NotImplementedError 142 143 def emi_injected_models(self): 144 raise NotImplementedError 145 146 def emi_injected_model(self, essence_model_class: Type['EssenceModelInjectionAbstract']): 147 raise NotImplementedError 148 149 def emi_on_injected_model_updated( 150 self, essence_model_class: Type['EssenceModelInjectionAbstract'], *args, **kwargs): 151 raise NotImplementedError 152 153 def emi_remove_injected_model(self, essence_model_class: Type['EssenceModelInjectionAbstract']): 154 raise NotImplementedError
157class EssenceModelUnknownInjectionAbstract: 158 def emu_is_compatible_high_order_model(self, high_order_model_class: Type['EssenceModelInjectionAbstract']) -> bool: 159 raise NotImplementedError 160 161 def emu_behave_as_unknown_model(self): 162 raise NotImplementedError 163 164 def emu_on_behave_as_unknown_model(self): 165 raise NotImplementedError 166 167 def _emu_register_on_model_changed_callback(self, requester: 'EssenceModelUnknownInjectionAbstract'): 168 raise NotImplementedError 169 170 def _emu_deregister_on_model_changed_callback(self, requester: 'EssenceModelUnknownInjectionAbstract'): 171 raise NotImplementedError 172 173 def _emu_notify_unknown_models_about_self_update(self): 174 raise NotImplementedError 175 176 def emu_on_model_changed_callback(self): 177 raise NotImplementedError 178 179 def emu_is_in_unknown_model_behavior(self): 180 raise NotImplementedError
183class EssenceModel(EssenceModelInheritanceAbstract, EssenceModelInjectionAbstract, EssenceModelUnknownInjectionAbstract): 184 """Must contain related data in a consistent state. 185 186 In order to do this, you must reload `em_on_model_updated()` and `emi_on_injected_model_updated()` methods. 187 Your interfaces can provide some appropriate information though an additional `parameters of em_on_model_updated()` 188 and `emi_on_injected_model_updated()` methods. 189 190 Do not forget to: 191 - run `self._emi_notify_high_order_model_about_self_update(type(self), interface_class, *args, **kwargs)` at 192 the end of your `em_on_model_updated()` 193 - run `self._emi_notify_high_order_model_about_self_update(type(self), essence_model_class, *args, **kwargs)` at 194 the end of your `emi_on_injected_model_updated()`""" 195 196 emi_compatible_injectable_essence_model_classes: Set[Type['EssenceModel']] = set() 197 # emu_compatible_high_order_essence_model_class: Optional[Type['EssenceModel']] = None 198 emu_compatible_high_order_essence_model_classes: Set[Type['EssenceModel']] = set() 199 200 def __init__(self): 201 self.__em_interfaces: Dict[Type['EssenceInterface'], 'EssenceInterface'] = dict() 202 self.__em_possible_interfaces: Dict[Type['EssenceInterface'], 'EssenceInterface'] = dict() 203 self.__emi_injected_models: Dict[Type['EssenceModel'], 'EssenceModel'] = dict() 204 self.__emi_raise_on_uninjectable_model: bool = True 205 self.__emi_high_order_model: Optional['EssenceModel'] = None 206 self.__emu_in_unknown_model_behavior: bool = False 207 self.__emu_raise_on_incompatible_high_order_model: bool = True 208 self.__emu_unknown_injected_models: Dict[Type['EssenceModel'], 'EssenceModel'] = dict() 209 210 def em_interface(self, interface_class: Type['EssenceInterface']) -> 'EssenceInterface': 211 """Should be called in order to get needed model interface""" 212 if interface_class in self.__em_interfaces: 213 return self.__em_interfaces[interface_class] 214 else: 215 injected_model_interface = None 216 for injected_model_class, injected_model in self.__emi_injected_models.items(): 217 model: 'EssenceModel' = injected_model 218 if model.em_interface_active(interface_class): 219 injected_model_interface = model.em_interface(interface_class) 220 break 221 if injected_model_interface: 222 return injected_model_interface 223 elif interface_class in self.__em_possible_interfaces: 224 raise EssenceInterfaceIsNotApplicableError 225 else: 226 raise EssenceInterfaceIsNotRegisteredError 227 228 def __call__(self, interface_class: Type['EssenceInterface'], worker: Callable, failed_worker: Optional[Callable] = None, *args, **kwargs) -> Any: 229 interface = None 230 exception = None 231 try: 232 interface = self.em_interface(interface_class) 233 except (EssenceInterfaceIsNotApplicableError, EssenceInterfaceIsNotRegisteredError) as exc: 234 exception = get_exception() 235 236 if interface: 237 return worker(interface, *args, **kwargs) 238 else: 239 if failed_worker: 240 return failed_worker(interface, exception, *args, **kwargs) 241 else: 242 return None 243 244 def em_has_interface(self, interface_class: Type['EssenceInterface']) -> bool: 245 has_own_interface = (interface_class in self.__em_interfaces) or \ 246 (interface_class in self.__em_possible_interfaces) 247 one_of_injected_models_has_interface = False 248 for injected_model_class, injected_model in self.__emi_injected_models.items(): 249 model: 'EssenceModel' = injected_model 250 if model.em_has_interface(interface_class) or model.em_interface_active(interface_class): 251 one_of_injected_models_has_interface = True 252 break 253 return has_own_interface or one_of_injected_models_has_interface 254 255 def em_interface_active(self, interface_class: Type['EssenceInterface']) -> bool: 256 own_interface_active = interface_class in self.__em_interfaces 257 one_of_injected_models_has_active_interface = False 258 for injected_model_class, injected_model in self.__emi_injected_models.items(): 259 model: 'EssenceModel' = injected_model 260 if model.em_interface_active(interface_class): 261 one_of_injected_models_has_active_interface = True 262 break 263 return own_interface_active or one_of_injected_models_has_active_interface 264 265 def em_active_interfaces(self) -> Set[Type['EssenceInterface']]: 266 own_active_interfaces = set(self.__em_interfaces) 267 injected_models_active_interfaces: Set[Type['EssenceInterface']] = set() 268 for injected_model_class, injected_model in self.__emi_injected_models.items(): 269 model: 'EssenceModel' = injected_model 270 injected_models_active_interfaces.update(model.em_active_interfaces()) 271 return own_active_interfaces | injected_models_active_interfaces 272 273 def em_all_interfaces(self) -> Set[Type['EssenceInterface']]: 274 own_all_interfaces = set(self.__em_interfaces) | set(self.__em_possible_interfaces) 275 injected_models_all_interfaces: Set[Type['EssenceInterface']] = set() 276 for injected_model_class, injected_model in self.__emi_injected_models.items(): 277 model: 'EssenceModel' = injected_model 278 injected_models_all_interfaces.update(model.em_all_interfaces()) 279 return own_all_interfaces | injected_models_all_interfaces 280 281 def _em_check_applicability_of_interfaces(self) -> None: 282 new_interfaces = dict() 283 new_possible_interfaces = dict() 284 285 for interface_class, interface in self.__em_interfaces.items(): 286 if interface._applicable_impl(): 287 new_interfaces[interface_class] = interface 288 else: 289 new_possible_interfaces[interface_class] = interface 290 291 for interface_class, interface in self.__em_possible_interfaces.items(): 292 if interface._applicable_impl(): 293 new_interfaces[interface_class] = interface 294 else: 295 new_possible_interfaces[interface_class] = interface 296 297 self.__em_interfaces = new_interfaces 298 self.__em_possible_interfaces = new_possible_interfaces 299 300 def em_on_model_updated(self, interface_class: Type['EssenceInterface'], *args, **kwargs): 301 """Must be run by EssenceInterface (by running EssenceInterface.notify_model_about_change method) after changing 302 model's data. It is enough to run in once per a method - at the end of the method work. 303 In 'super' in method of inherit class should be run at the end of the method""" 304 self._em_check_applicability_of_interfaces() 305 self._emu_notify_unknown_models_about_self_update() 306 self._emi_notify_high_order_model_about_self_update(type(self), interface_class, *args, **kwargs) 307 308 def em_add_interface(self, interface_class: Type['EssenceInterface'], *args, **kwargs) -> bool: 309 if (interface_class in self.__em_interfaces) or (interface_class in self.__em_possible_interfaces): 310 return False 311 else: 312 interface = interface_class(self, *args, **kwargs) 313 if interface._applicable_impl(): 314 self.__em_interfaces[interface_class] = interface 315 else: 316 self.__em_possible_interfaces[interface_class] = interface 317 return True 318 319 def em_remove_interface(self, interface_class: Type['EssenceInterface']) -> bool: 320 if interface_class in self.__em_interfaces: 321 del self.__em_interfaces[interface_class] 322 return True 323 elif interface_class in self.__em_possible_interfaces: 324 del self.__em_possible_interfaces[interface_class] 325 return True 326 else: 327 return False 328 329 def emi_on_registered_in_high_order_model(self, high_order_model: 'EssenceModel'): 330 """Will be called after high order model successfully registered this mode""" 331 self.__emi_high_order_model = high_order_model 332 333 def emi_on_unregistering_from_high_order_model(self): 334 # Will be called before high order model actually unregistered this mode 335 self.__emi_high_order_model = None 336 self.__emu_in_unknown_model_behavior = False 337 338 def emi_inject_model(self, essence_model: 'EssenceModel'): 339 # Should use 'EssenceModel' instead of Type['EssenceModel'] since we should use result of fully constructed 340 # essence_model with all needed interfaces - result of an appropriate factory work 341 essence_model_class = type(essence_model) 342 if isinstance(essence_model, type(self)) or isinstance(self, essence_model_class): 343 raise EssenceModelCanNotInjectSelfError 344 345 injectable_model = False 346 if essence_model_class in self.emi_compatible_injectable_essence_model_classes: 347 injectable_model = True 348 else: 349 if essence_model.emu_is_compatible_high_order_model(type(self)): 350 injectable_model = True 351 else: 352 if self.__emu_raise_on_incompatible_high_order_model: 353 raise IncompatibleHighOrderEssenceModelError 354 355 injected = False 356 if injectable_model: 357 self.__emi_injected_models[essence_model_class] = essence_model 358 essence_model.emi_on_registered_in_high_order_model(self) 359 if essence_model_class not in self.emi_compatible_injectable_essence_model_classes: 360 essence_model.emu_behave_as_unknown_model() 361 362 injected = True 363 else: 364 if self.__emi_raise_on_uninjectable_model: 365 raise EssenceModelCanNotBeInjectedError 366 367 return injected 368 369 def emi_injected_models(self): 370 return set(self.__emi_injected_models) 371 372 def emi_injected_model(self, essence_model_class: Type['EssenceModel']): 373 if essence_model_class in self.__emi_injected_models: 374 return self.__emi_injected_models[essence_model_class] 375 else: 376 raise EssenceModelIsNotInjectedError 377 378 def emi_on_injected_model_updated(self, essence_model_class: Type['EssenceModel'], *args, **kwargs): 379 # In 'super' in method of inherit class should be run at the end of the method 380 # With deep injection it will be like (model_3, model_2, model_1, interface_1, arg_1, arg_2, arg_3) 381 # where `interface_1` is an interface of the `model_1` 382 self._em_check_applicability_of_interfaces() 383 self._emu_notify_unknown_models_about_self_update() 384 self._emi_notify_high_order_model_about_self_update(type(self), essence_model_class, *args, **kwargs) 385 386 def _emi_notify_high_order_model_about_self_update(self, *args, **kwargs): 387 if self.__emi_high_order_model and (not self.__emu_in_unknown_model_behavior): 388 high_order_model: 'EssenceModel' = self.__emi_high_order_model 389 high_order_model.emi_on_injected_model_updated(*args, **kwargs) 390 391 def emi_remove_injected_model(self, essence_model_class: Type['EssenceModel']): 392 injected_model: 'EssenceModel' = self.__emi_injected_models[essence_model_class] 393 self._emu_deregister_on_model_changed_callback(injected_model) 394 injected_model.emi_on_unregistering_from_high_order_model() 395 del self.__emi_injected_models[essence_model_class] 396 397 def emu_is_compatible_high_order_model(self, high_order_model_class: Type['EssenceModelInjectionAbstract']) -> bool: 398 """Might be overloaded in order to make this model compatible with more than one high order models 399 400 Args: 401 high_order_model_class (Type[): [description] 402 403 Returns: 404 bool: [description] 405 """ 406 # return high_order_model_class == self.emu_compatible_high_order_essence_model_class 407 return high_order_model_class in self.emu_compatible_high_order_essence_model_classes 408 409 def emu_behave_as_unknown_model(self): 410 # Should be called by a high order model for an unknown injected model 411 # if type(self.__emi_high_order_model) != self.emu_compatible_high_order_essence_model_class: 412 if not self.emu_is_compatible_high_order_model(self.__emi_high_order_model): 413 raise IncompatibleHighOrderEssenceModelError 414 self.__emi_high_order_model._emu_register_on_model_changed_callback(type(self)) 415 self.__emu_in_unknown_model_behavior = True 416 self.emu_on_behave_as_unknown_model() 417 418 def emu_on_behave_as_unknown_model(self): 419 pass 420 421 def _emu_register_on_model_changed_callback(self, requester: 'EssenceModelUnknownInjectionAbstract'): 422 self.__emu_unknown_injected_models[type[requester]] = requester 423 424 def _emu_deregister_on_model_changed_callback(self, requester: 'EssenceModelUnknownInjectionAbstract'): 425 model_type = type(requester) 426 if model_type in self.__emu_unknown_injected_models: 427 del self.__emu_unknown_injected_models[model_type] 428 429 def _emu_notify_unknown_models_about_self_update(self, *args, **kwargs): 430 for umodel in self.__emu_unknown_injected_models.values(): 431 unknown_model: 'EssenceModel' = umodel 432 unknown_model.emu_on_model_changed_callback() 433 434 def emu_on_model_changed_callback(self): 435 raise UnknownEssenceModeBehaviorWasNotImplementedProperlyError 436 437 def emu_is_in_unknown_model_behavior(self): 438 return self.__emu_in_unknown_model_behavior
Must contain related data in a consistent state.
In order to do this, you must reload em_on_model_updated()
and emi_on_injected_model_updated()
methods.
Your interfaces can provide some appropriate information though an additional parameters of em_on_model_updated()
and emi_on_injected_model_updated()
methods.
Do not forget to:
- run
self._emi_notify_high_order_model_about_self_update(type(self), interface_class, *args, **kwargs)
at the end of yourem_on_model_updated()
- run
self._emi_notify_high_order_model_about_self_update(type(self), essence_model_class, *args, **kwargs)
at the end of youremi_on_injected_model_updated()
210 def em_interface(self, interface_class: Type['EssenceInterface']) -> 'EssenceInterface': 211 """Should be called in order to get needed model interface""" 212 if interface_class in self.__em_interfaces: 213 return self.__em_interfaces[interface_class] 214 else: 215 injected_model_interface = None 216 for injected_model_class, injected_model in self.__emi_injected_models.items(): 217 model: 'EssenceModel' = injected_model 218 if model.em_interface_active(interface_class): 219 injected_model_interface = model.em_interface(interface_class) 220 break 221 if injected_model_interface: 222 return injected_model_interface 223 elif interface_class in self.__em_possible_interfaces: 224 raise EssenceInterfaceIsNotApplicableError 225 else: 226 raise EssenceInterfaceIsNotRegisteredError
Should be called in order to get needed model interface
244 def em_has_interface(self, interface_class: Type['EssenceInterface']) -> bool: 245 has_own_interface = (interface_class in self.__em_interfaces) or \ 246 (interface_class in self.__em_possible_interfaces) 247 one_of_injected_models_has_interface = False 248 for injected_model_class, injected_model in self.__emi_injected_models.items(): 249 model: 'EssenceModel' = injected_model 250 if model.em_has_interface(interface_class) or model.em_interface_active(interface_class): 251 one_of_injected_models_has_interface = True 252 break 253 return has_own_interface or one_of_injected_models_has_interface
255 def em_interface_active(self, interface_class: Type['EssenceInterface']) -> bool: 256 own_interface_active = interface_class in self.__em_interfaces 257 one_of_injected_models_has_active_interface = False 258 for injected_model_class, injected_model in self.__emi_injected_models.items(): 259 model: 'EssenceModel' = injected_model 260 if model.em_interface_active(interface_class): 261 one_of_injected_models_has_active_interface = True 262 break 263 return own_interface_active or one_of_injected_models_has_active_interface
265 def em_active_interfaces(self) -> Set[Type['EssenceInterface']]: 266 own_active_interfaces = set(self.__em_interfaces) 267 injected_models_active_interfaces: Set[Type['EssenceInterface']] = set() 268 for injected_model_class, injected_model in self.__emi_injected_models.items(): 269 model: 'EssenceModel' = injected_model 270 injected_models_active_interfaces.update(model.em_active_interfaces()) 271 return own_active_interfaces | injected_models_active_interfaces
273 def em_all_interfaces(self) -> Set[Type['EssenceInterface']]: 274 own_all_interfaces = set(self.__em_interfaces) | set(self.__em_possible_interfaces) 275 injected_models_all_interfaces: Set[Type['EssenceInterface']] = set() 276 for injected_model_class, injected_model in self.__emi_injected_models.items(): 277 model: 'EssenceModel' = injected_model 278 injected_models_all_interfaces.update(model.em_all_interfaces()) 279 return own_all_interfaces | injected_models_all_interfaces
300 def em_on_model_updated(self, interface_class: Type['EssenceInterface'], *args, **kwargs): 301 """Must be run by EssenceInterface (by running EssenceInterface.notify_model_about_change method) after changing 302 model's data. It is enough to run in once per a method - at the end of the method work. 303 In 'super' in method of inherit class should be run at the end of the method""" 304 self._em_check_applicability_of_interfaces() 305 self._emu_notify_unknown_models_about_self_update() 306 self._emi_notify_high_order_model_about_self_update(type(self), interface_class, *args, **kwargs)
Must be run by EssenceInterface (by running EssenceInterface.notify_model_about_change method) after changing model's data. It is enough to run in once per a method - at the end of the method work. In 'super' in method of inherit class should be run at the end of the method
308 def em_add_interface(self, interface_class: Type['EssenceInterface'], *args, **kwargs) -> bool: 309 if (interface_class in self.__em_interfaces) or (interface_class in self.__em_possible_interfaces): 310 return False 311 else: 312 interface = interface_class(self, *args, **kwargs) 313 if interface._applicable_impl(): 314 self.__em_interfaces[interface_class] = interface 315 else: 316 self.__em_possible_interfaces[interface_class] = interface 317 return True
319 def em_remove_interface(self, interface_class: Type['EssenceInterface']) -> bool: 320 if interface_class in self.__em_interfaces: 321 del self.__em_interfaces[interface_class] 322 return True 323 elif interface_class in self.__em_possible_interfaces: 324 del self.__em_possible_interfaces[interface_class] 325 return True 326 else: 327 return False
329 def emi_on_registered_in_high_order_model(self, high_order_model: 'EssenceModel'): 330 """Will be called after high order model successfully registered this mode""" 331 self.__emi_high_order_model = high_order_model
Will be called after high order model successfully registered this mode
338 def emi_inject_model(self, essence_model: 'EssenceModel'): 339 # Should use 'EssenceModel' instead of Type['EssenceModel'] since we should use result of fully constructed 340 # essence_model with all needed interfaces - result of an appropriate factory work 341 essence_model_class = type(essence_model) 342 if isinstance(essence_model, type(self)) or isinstance(self, essence_model_class): 343 raise EssenceModelCanNotInjectSelfError 344 345 injectable_model = False 346 if essence_model_class in self.emi_compatible_injectable_essence_model_classes: 347 injectable_model = True 348 else: 349 if essence_model.emu_is_compatible_high_order_model(type(self)): 350 injectable_model = True 351 else: 352 if self.__emu_raise_on_incompatible_high_order_model: 353 raise IncompatibleHighOrderEssenceModelError 354 355 injected = False 356 if injectable_model: 357 self.__emi_injected_models[essence_model_class] = essence_model 358 essence_model.emi_on_registered_in_high_order_model(self) 359 if essence_model_class not in self.emi_compatible_injectable_essence_model_classes: 360 essence_model.emu_behave_as_unknown_model() 361 362 injected = True 363 else: 364 if self.__emi_raise_on_uninjectable_model: 365 raise EssenceModelCanNotBeInjectedError 366 367 return injected
378 def emi_on_injected_model_updated(self, essence_model_class: Type['EssenceModel'], *args, **kwargs): 379 # In 'super' in method of inherit class should be run at the end of the method 380 # With deep injection it will be like (model_3, model_2, model_1, interface_1, arg_1, arg_2, arg_3) 381 # where `interface_1` is an interface of the `model_1` 382 self._em_check_applicability_of_interfaces() 383 self._emu_notify_unknown_models_about_self_update() 384 self._emi_notify_high_order_model_about_self_update(type(self), essence_model_class, *args, **kwargs)
391 def emi_remove_injected_model(self, essence_model_class: Type['EssenceModel']): 392 injected_model: 'EssenceModel' = self.__emi_injected_models[essence_model_class] 393 self._emu_deregister_on_model_changed_callback(injected_model) 394 injected_model.emi_on_unregistering_from_high_order_model() 395 del self.__emi_injected_models[essence_model_class]
397 def emu_is_compatible_high_order_model(self, high_order_model_class: Type['EssenceModelInjectionAbstract']) -> bool: 398 """Might be overloaded in order to make this model compatible with more than one high order models 399 400 Args: 401 high_order_model_class (Type[): [description] 402 403 Returns: 404 bool: [description] 405 """ 406 # return high_order_model_class == self.emu_compatible_high_order_essence_model_class 407 return high_order_model_class in self.emu_compatible_high_order_essence_model_classes
Might be overloaded in order to make this model compatible with more than one high order models
Args: high_order_model_class (Type[): [description]
Returns: bool: [description]
409 def emu_behave_as_unknown_model(self): 410 # Should be called by a high order model for an unknown injected model 411 # if type(self.__emi_high_order_model) != self.emu_compatible_high_order_essence_model_class: 412 if not self.emu_is_compatible_high_order_model(self.__emi_high_order_model): 413 raise IncompatibleHighOrderEssenceModelError 414 self.__emi_high_order_model._emu_register_on_model_changed_callback(type(self)) 415 self.__emu_in_unknown_model_behavior = True 416 self.emu_on_behave_as_unknown_model()
444class EssenceInterface(Generic[Model]): 445 essence_model_class: Type[Model] = EssenceModel 446 447 def __init_subclass__(cls, /, essence_model_class: Optional[Type[Model]] = None, **kwargs): 448 super().__init_subclass__(**kwargs) 449 cls.essence_model_class = EssenceModel if essence_model_class is None else essence_model_class 450 451 def __init__(self, essence_model: Model, *args, **kwargs): 452 self.essence_model: Model = essence_model 453 self.em: Model = essence_model 454 self._on_applicability_changed_handlers: Set[Callable] = set() 455 self._applicability_state: bool = None 456 self.__check_essence_mode_type() 457 458 def __check_essence_mode_type(self): 459 if not isinstance(self.essence_model, self.essence_model_class): 460 raise IncompatibleEssenceModelError 461 462 def applicable(self) -> bool: 463 return True 464 465 def _applicable_impl(self) -> bool: 466 result: bool = self.applicable() 467 if result != self._applicability_state: 468 self._applicability_state = result 469 for handler in self._on_applicability_changed_handlers: 470 handler(self) 471 472 return result 473 474 def add_on_applicability_changed_handler(self, handler: Callable): 475 self._on_applicability_changed_handlers.add(handler) 476 477 def discard_on_applicability_changed_handler(self, handler: Callable): 478 self._on_applicability_changed_handlers.discard(handler) 479 480 def notify_model_about_change(self, *args, **kwargs): 481 # Must be run by EssenceInterface's methods if and after changing model's data. It is enough to run in once per 482 # a method - at the end of the method work. 483 self.essence_model.em_on_model_updated(type(self), *args, **kwargs)
Abstract base class for generic types.
A generic type is typically declared by inheriting from this class parameterized with one or more type variables. For example, a generic mapping type might be defined as::
class Mapping(Generic[KT, VT]): def __getitem__(self, key: KT) -> VT: ... # Etc.
This class can then be used as follows::
def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: try: return mapping[key] except KeyError: return default
506def simple_essence_model_factory( 507 model: Union[Type[EssenceModel], EntityArgsHolder], 508 interfaces: Union[ 509 Type[EssenceInterface], 510 EntityArgsHolder, 511 Sequence[Union[Type[EssenceInterface], EntityArgsHolder]] 512 ] 513 ) -> EssenceModel: 514 model_instance: EssenceModel = model() 515 if isinstance(interfaces, EntityArgsHolder) or (isinstance(interfaces, type) and issubclass(interfaces, EssenceInterface)): 516 interfaces = (interfaces,) 517 518 for interface in interfaces: 519 if isinstance(interface, type): 520 if issubclass(interface, EssenceInterface): 521 model_instance.em_add_interface(interface) 522 elif isinstance(interface, EntityArgsHolder): 523 model_instance.em_add_interface(*interface.entity_args_kwargs()) 524 else: 525 raise TypeError(f'Wrong interface type: {type(interface)}') 526 527 return model_instance
506def simple_essence_model_factory( 507 model: Union[Type[EssenceModel], EntityArgsHolder], 508 interfaces: Union[ 509 Type[EssenceInterface], 510 EntityArgsHolder, 511 Sequence[Union[Type[EssenceInterface], EntityArgsHolder]] 512 ] 513 ) -> EssenceModel: 514 model_instance: EssenceModel = model() 515 if isinstance(interfaces, EntityArgsHolder) or (isinstance(interfaces, type) and issubclass(interfaces, EssenceInterface)): 516 interfaces = (interfaces,) 517 518 for interface in interfaces: 519 if isinstance(interface, type): 520 if issubclass(interface, EssenceInterface): 521 model_instance.em_add_interface(interface) 522 elif isinstance(interface, EntityArgsHolder): 523 model_instance.em_add_interface(*interface.entity_args_kwargs()) 524 else: 525 raise TypeError(f'Wrong interface type: {type(interface)}') 526 527 return model_instance