yaml.constructor.ConstructorError: при построении объекта Python не удается найти «module_name» в модуле ‘__main__’

#python #configuration #yaml #config #pyyaml

#python #конфигурация #yaml #config #pyyaml

Вопрос:

Я попытался создать некоторые классы из file.yml

Структура притеров.yml вы можете увидеть ниже:

 --- !Station
recipients:
        - amp;first_phone ['Max']
        - amp;second_phone ['Anna', 'Alisa']
obj:
        - amp;first !!python/object:__main__.Nokia
                model: Nokia_8800
                recipients: *first_phone
        - amp;second !!python/object:__main__.Apple
                model: iPhone4
                recipients: *second_phone
spam_station: !station
    Nokia: *first
    Apple: *second
  

Конструктор класса представлен в spam_station.py

 from abc import ABC, abstractmethod
from typing import Union
from yaml import YAMLObject, load

class AbstrackPhone(ABC):
    @abstractmethod
    def send_message(self, message):
        pass

class Nokia(AbstrackPhone):
    def __init__(self):
        self.model = None
        self.recipients = []

    def send_message(self, message):
        for recipient in self.recipients:
            print(f"Hi {recipient} i'm {self.model}. {message}")


class Apple(AbstrackPhone):
    def __init__(self):
        self.model = None
        self.recipients = []

    def send_message(self, message):
        for recipient in self.recipients:
            print(f"Hi {recipient} i'm {self.model}. {message}")


class ConstructStation(YAMLObject):
    yaml_tag = u'!Station'

    @classmethod
    def from_yaml(Class, loader, node):
        def get_satation(loader, node):
            data = loader.construct_mapping(node)
            station = Class.Station()
            station.add_phones(data.values())
            return station

        loader.add_constructor(u"!station", get_satation)
        return loader.construct_mapping(node)['spam_station']

    class Station():

        def __init__(self):
            self.senders = []

        def add_phones(self, phones: Union[list, str]):
            self.senders.extend(phones)

        def send_message(self, message, **kwargs):
            for sender in self.senders:
                sender.send_message(message, **kwargs)

def station():
    with open('../yaml_config/printers') as file:
        spam_station = load(file)
    return spam_station

if __name__ == "__main__":
    station().send_message('Good luck!!!')
  

Я пробовал импортировать и использовать ‘station’ в sender.py:

 from station.spam_station import station

if __name__ == "__main__":
    station().send_message('Good luck!!!')
  

когда я запускаю spam_station.py , все в порядке:

 Hi Max i'm Nokia_8800. Good luck!!!
Hi Anna i'm iPhone4. Good luck!!!
Hi Alisa i'm iPhone4. Good luck!!!
  

когда я запускаю sender.py , у меня ошибка:

 yaml.constructor.ConstructorError: while constructing a Python object
cannot find 'Nokia' in the module '__main__'
  in "../yaml_config/printers", line 7, column 11
  

Как решить эту проблему? Пожалуйста, скажите мне, какова хорошая практика для настройки объектов python на yaml. Спасибо!

Ответ №1:

Проблема в том, что при выполнении sender.py этот файл (а не spam_station.py ) есть __main__ .

Вероятно, лучшее решение — избегать зависимости от путей импорта в файле YAML. Вы уже делаете это с Station помощью, поэтому вы можете просто сделать это и для других классов:

 class Nokia(AbstrackPhone, YAMLObject):
    yaml_tag = u"!Nokia"
    def __init__(self, model = None, recipients = []):
        self.model = model
        self.recipients = recipients

    def send_message(self, message):
        for recipient in self.recipients:
            print(f"Hi {recipient} i'm {self.model}. {message}")
  

Теперь вы можете использовать !Nokia вместо !!python/object:__main__.Nokia в файле YAML. То же самое относится и к Apple классу.