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
class EssenceModelException(builtins.Exception):
45class EssenceModelException(Exception):
46    pass

Common base class for all non-exit exceptions.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
args
class IncompatibleEssenceModelError(builtins.RuntimeError, EssenceModelException):
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
class UnsuitableEssenceInterfaceError(builtins.RuntimeError, EssenceModelException):
54class UnsuitableEssenceInterfaceError(RuntimeError, EssenceModelException):
55    pass

Unspecified run-time error.

Inherited Members
builtins.RuntimeError
RuntimeError
builtins.BaseException
with_traceback
args
class EssenceInterfaceIsNotApplicableError(UnsuitableEssenceInterfaceError, EssenceModelException):
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
class EssenceInterfaceIsNotRegisteredError(UnsuitableEssenceInterfaceError, EssenceModelException):
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
class EssenceModelCanNotInjectSelfError(builtins.RuntimeError, EssenceModelException):
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
class EssenceModelCanNotBeInjectedError(builtins.RuntimeError, EssenceModelException):
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
class EssenceModelIsNotInjectedError(builtins.RuntimeError, EssenceModelException):
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
class IncompatibleHighOrderEssenceModelError(builtins.RuntimeError, EssenceModelException):
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
class UnknownEssenceModeBehaviorWasNotImplementedProperlyError(builtins.NotImplementedError, EssenceModelException):
94class UnknownEssenceModeBehaviorWasNotImplementedProperlyError(NotImplementedError, EssenceModelException):
95    pass

Method or function hasn't been implemented yet.

Inherited Members
builtins.NotImplementedError
NotImplementedError
builtins.BaseException
with_traceback
args
class EssenceModelInheritanceAbstract:
 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
def em_interface( self, interface_class: type[EssenceInterface]) -> EssenceInterface:
102    def em_interface(self, interface_class: Type['EssenceInterface']) -> 'EssenceInterface':
103        raise NotImplementedError
def em_has_interface( self, interface_class: type[EssenceInterface]) -> bool:
105    def em_has_interface(self, interface_class: Type['EssenceInterface']) -> bool:
106        raise NotImplementedError
def em_interface_active( self, interface_class: type[EssenceInterface]) -> bool:
108    def em_interface_active(self, interface_class: Type['EssenceInterface']) -> bool:
109        raise NotImplementedError
def em_active_interfaces( self) -> set[type[EssenceInterface]]:
111    def em_active_interfaces(self) -> Set[Type['EssenceInterface']]:
112        raise NotImplementedError
def em_all_interfaces( self) -> set[type[EssenceInterface]]:
114    def em_all_interfaces(self) -> Set[Type['EssenceInterface']]:
115        raise NotImplementedError
def em_on_model_updated( self, interface_class: type[EssenceInterface], *args, **kwargs):
120    def em_on_model_updated(self, interface_class: Type['EssenceInterface'], *args, **kwargs):
121        raise NotImplementedError
def em_add_interface( self, interface_class: type[EssenceInterface], *args, **kwargs) -> bool:
123    def em_add_interface(self, interface_class: Type['EssenceInterface'], *args, **kwargs) -> bool:
124        raise NotImplementedError
def em_remove_interface( self, interface_class: type[EssenceInterface]) -> bool:
126    def em_remove_interface(self, interface_class: Type['EssenceInterface']) -> bool:
127        raise NotImplementedError
class EssenceModelInjectionAbstract:
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
def emi_on_registered_in_high_order_model( self, high_order_model: EssenceModelInjectionAbstract):
131    def emi_on_registered_in_high_order_model(self, high_order_model: 'EssenceModelInjectionAbstract'):
132        raise NotImplementedError
def emi_on_unregistering_from_high_order_model(self):
134    def emi_on_unregistering_from_high_order_model(self):
135        raise NotImplementedError
def emi_inject_model( self, essence_model: EssenceModelInjectionAbstract) -> bool:
140    def emi_inject_model(self, essence_model: 'EssenceModelInjectionAbstract') -> bool:
141        raise NotImplementedError
def emi_injected_models(self):
143    def emi_injected_models(self):
144        raise NotImplementedError
def emi_injected_model( self, essence_model_class: type[EssenceModelInjectionAbstract]):
146    def emi_injected_model(self, essence_model_class: Type['EssenceModelInjectionAbstract']):
147        raise NotImplementedError
def emi_on_injected_model_updated( self, essence_model_class: type[EssenceModelInjectionAbstract], *args, **kwargs):
149    def emi_on_injected_model_updated(
150            self, essence_model_class: Type['EssenceModelInjectionAbstract'], *args, **kwargs):
151        raise NotImplementedError
def emi_remove_injected_model( self, essence_model_class: type[EssenceModelInjectionAbstract]):
153    def emi_remove_injected_model(self, essence_model_class: Type['EssenceModelInjectionAbstract']):
154        raise NotImplementedError
class EssenceModelUnknownInjectionAbstract:
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
def emu_is_compatible_high_order_model( self, high_order_model_class: type[EssenceModelInjectionAbstract]) -> bool:
158    def emu_is_compatible_high_order_model(self, high_order_model_class: Type['EssenceModelInjectionAbstract']) -> bool:
159        raise NotImplementedError
def emu_behave_as_unknown_model(self):
161    def emu_behave_as_unknown_model(self):
162        raise NotImplementedError
def emu_on_behave_as_unknown_model(self):
164    def emu_on_behave_as_unknown_model(self):
165        raise NotImplementedError
def emu_on_model_changed_callback(self):
176    def emu_on_model_changed_callback(self):
177        raise NotImplementedError
def emu_is_in_unknown_model_behavior(self):
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 your em_on_model_updated()
  • run self._emi_notify_high_order_model_about_self_update(type(self), essence_model_class, *args, **kwargs) at the end of your emi_on_injected_model_updated()
emi_compatible_injectable_essence_model_classes: set[type[EssenceModel]] = set()
emu_compatible_high_order_essence_model_classes: set[type[EssenceModel]] = set()
def em_interface( self, interface_class: type[EssenceInterface]) -> EssenceInterface:
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

def em_has_interface( self, interface_class: type[EssenceInterface]) -> bool:
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
def em_interface_active( self, interface_class: type[EssenceInterface]) -> bool:
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
def em_active_interfaces( self) -> set[type[EssenceInterface]]:
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
def em_all_interfaces( self) -> set[type[EssenceInterface]]:
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
def em_on_model_updated( self, interface_class: type[EssenceInterface], *args, **kwargs):
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

def em_add_interface( self, interface_class: type[EssenceInterface], *args, **kwargs) -> bool:
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
def em_remove_interface( self, interface_class: type[EssenceInterface]) -> bool:
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
def emi_on_registered_in_high_order_model( self, high_order_model: EssenceModel):
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

def emi_on_unregistering_from_high_order_model(self):
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
def emi_inject_model( self, essence_model: EssenceModel):
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
def emi_injected_models(self):
369    def emi_injected_models(self):
370        return set(self.__emi_injected_models)
def emi_injected_model( self, essence_model_class: type[EssenceModel]):
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
def emi_on_injected_model_updated( self, essence_model_class: type[EssenceModel], *args, **kwargs):
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)
def emi_remove_injected_model( self, essence_model_class: type[EssenceModel]):
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]
def emu_is_compatible_high_order_model( self, high_order_model_class: type[EssenceModelInjectionAbstract]) -> bool:
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]

def emu_behave_as_unknown_model(self):
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()
def emu_on_behave_as_unknown_model(self):
418    def emu_on_behave_as_unknown_model(self):
419        pass
def emu_on_model_changed_callback(self):
434    def emu_on_model_changed_callback(self):
435        raise UnknownEssenceModeBehaviorWasNotImplementedProperlyError
def emu_is_in_unknown_model_behavior(self):
437    def emu_is_in_unknown_model_behavior(self):
438        return self.__emu_in_unknown_model_behavior
class EssenceInterface(typing.Generic[~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

EssenceInterface(essence_model: ~Model, *args, **kwargs)
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()
essence_model_class: Type[~Model] = <class 'EssenceModel'>
essence_model: ~Model
em: ~Model
def applicable(self) -> bool:
462    def applicable(self) -> bool:
463        return True
def add_on_applicability_changed_handler(self, handler: Callable):
474    def add_on_applicability_changed_handler(self, handler: Callable):
475        self._on_applicability_changed_handlers.add(handler)
def discard_on_applicability_changed_handler(self, handler: Callable):
477    def discard_on_applicability_changed_handler(self, handler: Callable):
478        self._on_applicability_changed_handlers.discard(handler)
def notify_model_about_change(self, *args, **kwargs):
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)
def essence_model_changer(func):
486def essence_model_changer(func):
487    def wrapper(self: EssenceInterface, *args, **kwargs):
488        try:
489            func(self, *args, **kwargs)
490        finally:
491            self.notify_model_about_change(*args, **kwargs)
492
493    return wrapper
def em_changer(func):
486def essence_model_changer(func):
487    def wrapper(self: EssenceInterface, *args, **kwargs):
488        try:
489            func(self, *args, **kwargs)
490        finally:
491            self.notify_model_about_change(*args, **kwargs)
492
493    return wrapper
class EssenceModelFactoryExample:
499class EssenceModelFactoryExample:
500    def __call__(self, *args, **kwargs):
501        model: EssenceModel = EssenceModel()
502        model.em_add_interface(EssenceInterface)
503        return model
def simple_essence_model_factory( model: Union[Type[EssenceModel], cengal.code_flow_control.args_manager.versions.v_0.args_manager.EntityArgsHolder], interfaces: Union[Type[EssenceInterface], cengal.code_flow_control.args_manager.versions.v_0.args_manager.EntityArgsHolder, Sequence[Union[Type[EssenceInterface], cengal.code_flow_control.args_manager.versions.v_0.args_manager.EntityArgsHolder]]]) -> EssenceModel:
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
def simple_em_factory( model: Union[Type[EssenceModel], cengal.code_flow_control.args_manager.versions.v_0.args_manager.EntityArgsHolder], interfaces: Union[Type[EssenceInterface], cengal.code_flow_control.args_manager.versions.v_0.args_manager.EntityArgsHolder, Sequence[Union[Type[EssenceInterface], cengal.code_flow_control.args_manager.versions.v_0.args_manager.EntityArgsHolder]]]) -> EssenceModel:
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