5
0
Fork 0
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

154 linhas
5.1 KiB

Esse arquivo contém caracteres Unicode ambíguos!

Este arquivo contém caracteres ambíguos Unicode que podem ser confundidos com outros no seu idioma atual. Se o seu caso de uso for intencional e legítimo, você pode ignorar com segurança este aviso. Use o botão Escapar para destacar esses caracteres.

import os
from functools import wraps
from abc import ABCMeta, abstractmethod
from inspect import getcallargs
class Cachable:
'''Базовый класс для создания классов, кэширующих вывод своих методов.
Декоратор @Cachable.method_cached() предназначен для указания методов
с кэшируемым выводом.'''
def __init__(self):
self.clear_method_cache()
def clear_method_cache(self):
self._method_cache = {}
@staticmethod
def method_cached(key=lambda *args, **kwargs: hash(args)):
def decorator(function):
function_name = function.__name__
@wraps(function)
def wrapper(self, *args, **kwargs):
keyval = key(*args, **kwargs)
assert isinstance(self, Cachable)
if function_name not in self._method_cache:
self._method_cache[function_name] = {}
cache = self._method_cache[function_name]
if keyval not in cache:
cache[keyval] = function(self, *args, **kwargs)
return cache[keyval]
@wraps(function)
def null_wrapper(self):
assert isinstance(self, Cachable)
if function_name not in self._method_cache:
self._method_cache[function_name] = function(self)
return self._method_cache[function_name]
if len(function.__code__.co_varnames) > 1:
return wrapper
else:
return null_wrapper
return decorator
class Singleton(type):
'''Метакласс для создания синглтонов.'''
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonParam(type):
'''Метакласс для создания синглтонов по параметрам.'''
_instances = {}
_init = {}
def __init__(cls, class_name, base_classes, class_dict):
cls._init[cls] = class_dict.get('__init__', None)
def __call__(cls, *args, **kwargs):
init = cls._init[cls]
if init is not None:
key_value = (cls, frozenset(getcallargs(init, None, *args,
**kwargs).items()))
else:
key_value = cls
if key_value not in cls._instances:
cls._instances[key_value] = super().__call__(*args, **kwargs)
return cls._instances[key_value]
class GenericFS(metaclass=ABCMeta):
'''Абстрактный класс для работы с файловыми системами.'''
@abstractmethod
def exists(self, path):
pass
@abstractmethod
def read(self, path):
pass
@abstractmethod
def glob(self, path):
pass
@abstractmethod
def realpath(self, path):
pass
@abstractmethod
def write(self, path, data):
pass
@abstractmethod
def listdir(self, path, fullpath=False):
pass
def get_traceback_caller(exception_type, exception_object,
exception_traceback):
'''Возвращает имя модуля, в котором было сгенерировано исключение,
и соответствующий номер строки.'''
while exception_traceback.tb_next:
exception_traceback = exception_traceback.tb_next
line_number = exception_traceback.tb_lineno
module_path, module_name = os.path.split(exception_traceback.tb_frame.
f_code.co_filename)
if module_name.endswith('.py'):
module_name = module_name[:-3]
full_module_name = [module_name]
while (module_path and module_path != '/' and not
module_path.endswith('site-packages')):
module_path, package_name = os.path.split(module_path)
full_module_name.insert(0, package_name)
if module_path.endswith('site-packages'):
module_name = '.'.join(full_module_name)
return module_name, line_number
def unique(iterable):
'''Возвращает итерируемый объект, содержащий только уникальные элементы
входного объекта, сохраняя их порядок.
'''
output = []
for element in iterable:
if element not in output:
output.append(element)
return output
def flat_iterable(iterable, types=(list, tuple, map, zip, filter)):
'''Распаковывает все вложенные итерируемые объекты во входном объекте.
Например:
[1, 2, [3, 4, [5, 6], 7], [8, 9], 10] -> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
'''
if isinstance(iterable, types):
for it in iterable:
for sub_iterable in flat_iterable(it, types=types):
yield sub_iterable
else:
yield iterable