From a4d914c7f2c1cbcde85b41d1d81e0b509de7a593 Mon Sep 17 00:00:00 2001 From: bashmak Date: Sat, 30 Jun 2018 17:09:14 +0300 Subject: [PATCH] Make metaclass for lazy init objects --- agent/core.py | 10 ++-------- agent/mod_mikrotik.py | 6 +++--- djing/lib/decorators.py | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/agent/core.py b/agent/core.py index def183f..2ed3110 100644 --- a/agent/core.py +++ b/agent/core.py @@ -1,4 +1,4 @@ -from abc import ABCMeta, abstractmethod +from abc import ABC, abstractmethod from typing import Iterator, Any, Tuple, Optional from .structs import AbonStruct, TariffStruct, VectorAbon, VectorTariff, IpStruct @@ -15,7 +15,7 @@ class NasNetworkError(Exception): # Communicate with NAS -class BaseTransmitter(metaclass=ABCMeta): +class BaseTransmitter(ABC): @abstractmethod def add_user_range(self, user_list: VectorAbon): """add subscribers list to NAS""" @@ -106,12 +106,6 @@ class BaseTransmitter(metaclass=ABCMeta): def sync_nas(self, users_from_db: Iterator): list_for_add, list_for_del = self._diff_users(users_from_db) if len(list_for_del) > 0: - print('FOR DELETE') - for ld in list_for_del: - print(ld) self.remove_user_range(list_for_del) if len(list_for_add) > 0: - print('FOR ADD') - for la in list_for_add: - print(la) self.add_user_range(list_for_add) diff --git a/agent/mod_mikrotik.py b/agent/mod_mikrotik.py index d430632..ca5b9f4 100644 --- a/agent/mod_mikrotik.py +++ b/agent/mod_mikrotik.py @@ -1,10 +1,12 @@ import re import socket import binascii +from abc import ABCMeta from hashlib import md5 from ipaddress import ip_network from typing import Iterable, Optional, Tuple, Generator, Dict +from djing.lib.decorators import LazyInitMetaclass from .structs import TariffStruct, AbonStruct, IpStruct, VectorAbon, VectorTariff from . import settings as local_settings from django.conf import settings @@ -30,8 +32,6 @@ class ApiRos(object): sk.connect((ip, port or 8728)) self.sk = sk - self.currenttag = 0 - def login(self, username, pwd): if self.is_login: return @@ -172,7 +172,7 @@ class IpAddressListObj(IpStruct): self.mk_id = str(mk_id).replace('*', '') -class MikrotikTransmitter(BaseTransmitter, ApiRos): +class MikrotikTransmitter(BaseTransmitter, ApiRos, metaclass=type('_ABC_Lazy_mcs', (ABCMeta, LazyInitMetaclass), {})): def __init__(self, login=None, password=None, ip=None, port=None): ip = ip or getattr(local_settings, 'NAS_IP') diff --git a/djing/lib/decorators.py b/djing/lib/decorators.py index 2a69fed..f7c2aad 100644 --- a/djing/lib/decorators.py +++ b/djing/lib/decorators.py @@ -55,3 +55,40 @@ def hash_auth_view(fn): else: return HttpResponseForbidden('Access Denied') return wrapped + + +# Lazy initialize metaclass +class LazyInitMetaclass(type): + """ + Type this metaclass if you want to make your object with lazy initialize. + Method __init__ called only when you try to call something method + from object of your class. + """ + def __new__(mcs, name: str, bases: tuple, attrs: dict): + new_class_new = super(LazyInitMetaclass, mcs).__new__ + + def _lazy_call_decorator(fn): + def wrapped(self, *args, **kwargs): + if not self._is_initialized: + self._lazy_init(*self._args, **self._kwargs) + return fn(self, *args, **kwargs) + + return wrapped + + # Apply decorator to all public class methods + new_attrs = {k: _lazy_call_decorator(v) for k, v in attrs.items() if not k.startswith('__') and not k.endswith('__') and callable(v)} + if new_attrs: + attrs.update(new_attrs) + attrs['_is_initialized'] = False + + new_class = new_class_new(mcs, name, bases, attrs) + + real_init = getattr(new_class, '__init__') + + def _lazy_init(self, *args, **kwargs): + self._args = args + self._kwargs = kwargs + setattr(new_class, '__init__', _lazy_init) + setattr(new_class, '_lazy_init', real_init) + + return new_class