Уведомления

Группа в Telegram: @pythonsu

#1 Май 6, 2019 21:44:59

Dezex
Зарегистрирован: 2015-12-08
Сообщения: 16
Репутация: +  0  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

Всем привет.

Написал огромный модуль (переписал с php - не мое на py).

Задано оч много Exception, сообщения которых всегда начинаются с некоторого шаблона.
Для примера:

 class Server(object):
    """docstring for Server"""
    def __init__(self, id_):
        self.__id = id_  
        self.__ip = None
        
    @property
    def log_head(self):
        return "Server ID: {} IP: {}. ".format(self.id, self.ip)
    @property
    def ip(self):
        return self.__ip
    @property
    def id(self):
        return self.__id
    def test(self):
        raise SrvException("{}We have some problem.".format(self.log_head))

Хочу убрать (спрятать) self.log_head, чтобы не указывать каждый раз.
Додумался ток до этого:

 class SrvException(Exception):
    _target_srv = None
    class __metaclass__(type):
        @property
        def target_srv(cls):
            return cls._target_srv
        @target_srv.setter
        def target_srv(cls, srv_inst):
            cls._target_srv = srv_inst
    def __init__(self, message):
        ip = SrvException.target_srv.ip
        id_ = SrvException.target_srv.id
        message = "Server ID: {} IP: {}. {}".format(id_, ip, message)
        super(SrvException, self).__init__(message)
class Server(object):
    """docstring for Server"""
    def __init__(self, id_):
        SrvException.target_srv = self
        self.__id = id_
        self.__ip = None
    @property
    def ip(self):
        return self.__ip
    @property
    def id(self):
        return self.__id
    def test(self):
        raise SrvException("We have some problem.")
inst = Server(0)
inst.test()


Проблемы:
1) Говорят это не комильфо:
         SrvException.target_srv = self

2) Нельзя использовать несколько экземпляров Server из модуля: все завязаны на один класс SrvException.

Подскажите пожалуйста по п.1,2 проблем.

Отредактировано Dezex (Май 6, 2019 21:45:55)

Офлайн

#2 Май 7, 2019 06:06:06

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

Dezex

Мне кажется, в ваших размышлениях есть концептуальная ошибка. Исключения и логгирование исключений, это совершенно разные и непересекающиеся аспекты программы. Исключения возникают потому, что в программе произошли непредвиденные события, программа сообщает о неполадках. Логгирование ошибок - один из инструментов администрирования, его наличие или отсутствие никак не влияет на то, что в программе возникают исключительные ситуации, не надо искусственно связывать эти задачи.

    
import logging
logging.basicConfig(filename="sample.log", level=logging.INFO)
  
class Logger:
      
     def __init__(self, server):
           self.server = server
     def text(text):
           return f"[{self.server.ip}-{self.server.id}] {text}"
          
     def debug(text):
             logging.debug(selt.text(text))
     def error(text):
            logging.error(self.text(text))
class Server:
    
     def __init__(self):
           self.logger = Logger(self)
  
     def test(self):
          try:
              connect()
          except ConnectionError as e:
              self.logger.error(e)



Офлайн

#3 Май 7, 2019 11:04:01

Dezex
Зарегистрирован: 2015-12-08
Сообщения: 16
Репутация: +  0  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

FishHook

Спасибо за ответ. И за наводку на библиотеку logging - не пользовался (самопал), удобно.

Да, я представляю разницу в исключениях и логировании.
И изначально я переделывал Excpetion (которые пред. автор использовал в PHP) на логирование (для начала самопальная функция в том же классе), но понял вот что:

набор пакетов, модулей немалый (проект), некоторые вещи я могу упустить (ошибки в коде, которые вызовут эти самые предполагаемые Exception). И мне удобнее получить место в модуле, коде, что и дает raise Exception в одну строчку. Поэтому логи типа error, debug должны поднимать эту информацию.

Посмотрел на logging, было бы мощно, если она могла делать так:
при необходимости (через аргументы basicConfig) можно включать трассировку на местах .error, .debbug сообщений дополнительно к стд. тексту.

Офлайн

#4 Май 7, 2019 12:32:56

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

Dezex
можно включать трассировку на местах

Все есть из коробки, запустите

 import logging
logging.basicConfig(level=logging.DEBUG)
  
try:
    1 / 0
except Exception:
    logging.exception("AHTUNG!!!!!")
  
logging.debug("The program successfully completed")



Офлайн

#5 Май 7, 2019 12:52:03

Dezex
Зарегистрирован: 2015-12-08
Сообщения: 16
Репутация: +  0  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

FishHook

Так фишка в том, что не та логика: я не использую try/except.
Проверка идет по условию, например переменная установлена или нет.

И опять спасибо за logging. В принципе получилось то, что я хотел: сообщение + вкл/выкл трассировка по коду по уровню DEBUG. Но немного криво - поднимаю Exception рядом с логером.

Пример:

 import sys
import logging
logging.basicConfig(level=logging.DEBUG, format="%(levelname)-0s:%(name)-0s: %(message)s")
class Logger:
    def __init__(self, server):
        self.server = server
        self.logger = logging.getLogger()
    def text(self, text):
        return "Server ID: {}, IP: {}. {}".format(self.server.id, self.server.id, text)
    def debug(self, text):
        self.logger.debug(self.text(text))
    def error(self, text):
        self.logger.error(self.text(text))
    def critical(self, text):
        self.logger.critical(self.text(text))
        if self.logger.isEnabledFor(logging.DEBUG):
            print ""
            raise Exception
        
        sys.exit()
class Server:
    def __init__(self, id_):
        self.logger = Logger(self)
        self.__id = id_
        self.__ip = None
    @property
    def ip(self):
        return self.__ip
    @property
    def id(self):
        return self.__id
    def test(self):
        var = None
        if var is None:
            self.logger.critical("Variable value was not setted.")
inst = Server(0)
inst.test()
sys.exit()

Вывод:
 CRITICAL:root: Server ID: 0, IP: 0. Variable value was not setted.
Traceback (most recent call last):
  File "./__debug.py", line 105, in <module>
    inst.test()
  File "./__debug.py", line 101, in test
    self.logger.critical("Variable value was not setted.")
  File "./__debug.py", line 78, in critical
    raise Exception
Exception

Так приемлемо?
Думаю у меня на месте забанят.

Отредактировано Dezex (Май 7, 2019 13:17:51)

Офлайн

#6 Май 7, 2019 13:07:48

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

Dezex

Я думаю так: если программа не может дальше работать с имеющимися данными, например, не до конца проиницировали переменную билдером, то это исключительная ситуация, и эксепшен должен быть зарайзен. Если какой-то внешний по отношению к сущности, в которой возникла ошибка, перехватит этот эксепшен - ну отлично, видимо, он знает, что делает.

 class Server:
    def test(self):
        var = None
        if var is None:
            raise ServerError("var is undefined")
inst = Server(0)
try:
    inst.test()
except ServerError as e:
    logger.error(e)



Офлайн

#7 Май 7, 2019 13:36:47

Dezex
Зарегистрирован: 2015-12-08
Сообщения: 16
Репутация: +  0  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

FishHook

Да, у меня в итоге так и получается, но неявно через self.logger.critical. Я затеял это из-за доп. информации, которая повторяется:
CRITICAL:root: Server ID: 0, IP: 0. Variable value was not setted.

+ единый интерфейс - Logger

Отредактировано Dezex (Май 7, 2019 13:38:09)

Офлайн

#8 Май 8, 2019 11:39:06

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2849
Репутация: +  186  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

> Задано оч много Exception, сообщения которых всегда начинаются с некоторого шаблона….
> Хочу убрать (спрятать) self.log_head, чтобы не указывать каждый раз.
> Додумался ток до этого:

Ты до какой-то ерунды додумался. Используй наследование и всё будет хорошо.



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#9 Май 8, 2019 13:39:49

Dezex
Зарегистрирован: 2015-12-08
Сообщения: 16
Репутация: +  0  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

Rodegast

А пример?

Офлайн

#10 Май 8, 2019 20:32:41

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2849
Репутация: +  186  -
Профиль   Отправить e-mail  

Завязать custom Exception на class instance

> А пример?

Какой пример? Про наследование?

 class SrvException(Exception):
    @property
    def log_head(self):
        return "Server ID: {} IP: {}. ".format(self.id, self.ip)
 
class ServerException(SrvException):
    def __init__(self, _id, ip=None):
        self.__id = _id
        self.__ip = ip
    @property
    def ip(self):
        return self.__ip
    @property
    def id(self):
        return self.__id



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version