Browse Source

Merge branch 'feature/export' of 1ffy/sp-1 into master

Всеволод Левитан 1 year ago
parent
commit
8b69f71117

+ 1 - 1
src/errors/argument_exception.py

@@ -3,4 +3,4 @@ from src.errors.base_exception import base_exception
 
 class argument_exception(base_exception):
     def __init__(self, *args):
-        super().__init__(args)
+        super().__init__(args)

+ 4 - 5
src/errors/base_exception.py

@@ -3,12 +3,11 @@ from src.errors.error_proxy import error_proxy
 
 class base_exception(Exception):
     __inner_error: error_proxy = error_proxy()
-    
+
     def __init__(self, *args: object) -> None:
         super().__init__(*args)
         self.__inner_error.set_error(self)
-        
-    @property    
+
+    @property
     def error(self):
-        return self.__inner_error      
-    
+        return self.__inner_error

+ 22 - 31
src/errors/error_proxy.py

@@ -1,17 +1,13 @@
-
-
 class error_proxy:
     __error_text = ""
     __error_source = ""
     __is_error = False
-    
-    
+
     def __init__(self, error_text: str = "", error_source: str = "") -> None:
         self.error_source = error_source
         self.error_text = error_text
-        
-    
-    @property    
+
+    @property
     def error_text(self):
         """
             Текст сообщения
@@ -19,22 +15,20 @@ class error_proxy:
             _type_: _description_
         """
         return self.__error_text
-    
-    
+
     @error_text.setter
     def error_text(self, value: str):
         if not isinstance(value, str):
             raise Exception("Некорректно передан аргумент!")
-        
-        if(value.strip() ==""):
+
+        if value.strip() == "":
             self.__is_error = False
             return
-            
+
         self.__error_text = value.strip()
         self.__is_error = True
-        
-        
-    @property    
+
+    @property
     def error_source(self):
         """
             Источник ошибки
@@ -42,27 +36,24 @@ class error_proxy:
             _type_: _description_
         """
         return self.__error_source
-    
-    
+
     @error_source.setter
     def error_source(self, value: str):
         if not isinstance(value, str):
             raise Exception("Некорректно передан аргумент!")
-        
-        if(value.strip() ==""):
+
+        if value.strip() == "":
             return
-            
+
         self.__error_source = value.strip()
-    
-        
+
     @property
     def is_error(self):
         """
-            Флаг. Есть ошибка
+        Флаг. Есть ошибка
         """
-        return self.__is_error  
-        
-        
+        return self.__is_error
+
     def set_error(self, exception: Exception):
         """
             Сохранить ошибку
@@ -71,16 +62,16 @@ class error_proxy:
         """
         if not isinstance(exception, Exception):
             self.error_text = "Некорректно переданы параметры!"
-            self.error_source = "set_error" 
+            self.error_source = "set_error"
             return
 
-        if exception is not None:        
+        if exception is not None:
             self.error_text = f"ОШИБКА! {str(exception)}"
             self.error_source = f"ИСКЛЮЧЕНИЕ! {type(exception)}"
         else:
             self.error_text = ""
-            
-    @property        
+
+    @property
     def is_empty(self) -> bool:
         """
             Флаг. Есть ошибка
@@ -90,4 +81,4 @@ class error_proxy:
         if len(self._error_text) != 0:
             return False
         else:
-            return True         
+            return True

+ 1 - 1
src/errors/file_exception.py

@@ -3,4 +3,4 @@ from src.errors.base_exception import base_exception
 
 class file_exception(base_exception):
     def __init__(self, *args):
-        super().__init__(args)
+        super().__init__(args)

+ 1 - 1
src/errors/instance_exception.py

@@ -3,4 +3,4 @@ from src.errors.base_exception import base_exception
 
 class instance_exception(base_exception):
     def __init__(self, *args):
-        super().__init__(args)
+        super().__init__(args)

+ 35 - 0
src/export/exporter.py

@@ -0,0 +1,35 @@
+from src.models.abstract_reference import abstract_reference
+from src.export.strategies.export import export
+from src.validation.validator import validator
+from src.storage.storage import storage
+
+
+class exporter:
+    """Класс для экспорта данных моделей"""
+
+    # Валидатор
+    __vtor = validator()
+
+    def __init__(self, strategy: export):
+        self.__vtor.check_type(strategy, export)
+        self.__strat = strategy
+
+    def export_models(self, models: list[abstract_reference]) -> str:
+        """Экспортировать модели"""
+        self.__vtor.check_collection_types_all(models, abstract_reference)
+        res = self.__strat.export_header(models[0])
+        for model in models:
+            res += f"\n{self.__strat.export_model(model)}"
+
+        return res
+
+    def export_by_key(self, key):
+        """Экспортировать модели из storage по ключу"""
+
+        # Проверяем чтобы ключ был строкой с длиной >0
+        self.__vtor.check_type(key, str)
+        self.__vtor.check_length_greater(key, 0)
+
+        models = storage().data[key]
+
+        return self.export_models(models)

+ 30 - 0
src/export/strategies/csv_export.py

@@ -0,0 +1,30 @@
+from src.export.strategies.export import export
+from src.models.abstract_reference import abstract_reference
+
+
+class csv_export(export):
+    """Класс стратегии для экспорта в CSV"""
+
+    def export_header(self, model: abstract_reference):
+        """
+            Создать заголовок экспорта
+        Args:
+            model (abstract_reference): модель, по которой нужно построить заголовок
+        """
+
+        return ";".join(super().get_properties(model).keys())
+
+    def export_model(self, model: abstract_reference):
+        """
+            Экспортировать модель
+        Args:
+            model (abstract_reference): модель, строку с которой нужно создать
+        """
+
+        properties = super().get_properties(model)
+        res = ""
+        for property in properties.keys():
+            val = properties[property]
+            res += str(val).replace(";", ",") + ";"
+
+        return res[:-1]

+ 33 - 0
src/export/strategies/export.py

@@ -0,0 +1,33 @@
+from src.models.abstract_reference import abstract_reference
+
+
+class export:
+    """Базовый класс стратегии экспорта"""
+
+    def get_properties(self, model: abstract_reference):
+        properties = {}
+        for name in dir(model.__class__):
+            if name == "error":
+                continue
+            attr = getattr(model.__class__, name)
+            if isinstance(attr, property):
+                properties[name] = attr.fget(model)
+        return properties
+
+    def export_header(model: abstract_reference):
+        """
+            Создать заголовок экспорта
+        Args:
+            model (abstract_reference): модель, по которой нужно построить заголовок
+        """
+
+        pass
+
+    def export_model(model: abstract_reference):
+        """
+            Экспортировать модель
+        Args:
+            model (abstract_reference): модель, строку с которой нужно создать
+        """
+
+        pass

+ 22 - 0
src/export/strategies/json_export.py

@@ -0,0 +1,22 @@
+from src.export.strategies.export import export
+from src.models.abstract_reference import abstract_reference
+
+
+class json_export(export):
+    """Класс стратегии для экспорта в JSON"""
+
+    def export_header(model: abstract_reference):
+        """
+            Создать заголовок экспорта
+        Args:
+            model (abstract_reference): модель, по которой нужно построить заголовок
+        """
+        pass
+
+    def export_model(model: abstract_reference):
+        """
+            Экспортировать модель
+        Args:
+            model (abstract_reference): модель, строку с которой нужно создать
+        """
+        pass

+ 22 - 0
src/export/strategies/markdown_export.py

@@ -0,0 +1,22 @@
+from src.export.strategies.export import export
+from src.models.abstract_reference import abstract_reference
+
+
+class markdown_export(export):
+    """Класс стратегии для экспорта в Markdown"""
+
+    def export_header(model: abstract_reference):
+        """
+            Создать заголовок экспорта
+        Args:
+            model (abstract_reference): модель, по которой нужно построить заголовок
+        """
+        pass
+
+    def export_model(model: abstract_reference):
+        """
+            Экспортировать модель
+        Args:
+            model (abstract_reference): модель, строку с которой нужно создать
+        """
+        pass

+ 22 - 0
src/export/strategies/xml_export.py

@@ -0,0 +1,22 @@
+from src.export.strategies.export import export
+from src.models.abstract_reference import abstract_reference
+
+
+class xml_export(export):
+    """Класс стратегии для экспорта в XML"""
+
+    def export_header(model: abstract_reference):
+        """
+            Создать заголовок экспорта
+        Args:
+            model (abstract_reference): модель, по которой нужно построить заголовок
+        """
+        pass
+
+    def export_model(model: abstract_reference):
+        """
+            Экспортировать модель
+        Args:
+            model (abstract_reference): модель, строку с которой нужно создать
+        """
+        pass

+ 40 - 30
src/logic/start_factory.py

@@ -7,6 +7,7 @@ from src.settings.settings import settings
 from src.storage.storage import storage
 from src.validation.validator import validator
 
+
 #
 # Класс для обработки начало работы приложения
 #
@@ -14,33 +15,29 @@ class start_factory:
     __options: settings = None
     __storage: storage = None
     __vtor = validator()
-    
-    def __init__(self, _options: settings,
-                 _storage: storage = None) -> None:
-        
+
+    def __init__(self, _options: settings, _storage: storage = None) -> None:
         self.__vtor.check_type(_options, settings)
         self.__vtor.check_type(_storage, storage)
         self.__options = _options
         self.__storage = _storage
 
-    def __save(self, key:str, items: list):
+    def __save(self, key: str, items: list):
         """
             Сохранить данные
         Args:
             key (str): ключ доступ
             items (list): список
         """
-       
+
         self.__vtor.check_type(key, str)
-        
-        if self.__storage == None:
+
+        if self.__storage is None:
             self.__storage = storage()
-            
-        self.__storage.data[ key ] = items
-        
-        
-                
-    @property            
+
+        self.__storage.data[key] = items
+
+    @property
     def storage(self):
         """
              Ссылка на объект хранилище данных
@@ -48,12 +45,11 @@ class start_factory:
             _type_: _description_
         """
         return self.__storage
-    
-    
+
     @staticmethod
     def create_recipes():
         """
-            Фабричный метод Создать список рецептов
+        Фабричный метод Создать список рецептов
         """
 
         result = []
@@ -62,11 +58,24 @@ class start_factory:
         group = nomenclature_group_model("group")
 
         ingredients = [
-            ingredient_model("Мука", nomenclature_model("Мука", "Мука пшеничная", g, group), 100, g),
-            ingredient_model("Сахар", nomenclature_model("Сахар", "Сахарный песок", g, group), 80, g),
-            ingredient_model("Масло", nomenclature_model("Масло", "Масло сливочное", g, group), 70, g),
-            ingredient_model("Яйцо", nomenclature_model("Яйцо", "Яйцо куриное", pcs, group), 1, pcs),
-            ingredient_model("Ванилин", nomenclature_model("Ванилин", "Ванилин продуктовый", g, group), 5, g)
+            ingredient_model(
+                "Мука", nomenclature_model("Мука", "Мука пшеничная", g, group), 100, g
+            ),
+            ingredient_model(
+                "Сахар", nomenclature_model("Сахар", "Сахарный песок", g, group), 80, g
+            ),
+            ingredient_model(
+                "Масло", nomenclature_model("Масло", "Масло сливочное", g, group), 70, g
+            ),
+            ingredient_model(
+                "Яйцо", nomenclature_model("Яйцо", "Яйцо куриное", pcs, group), 1, pcs
+            ),
+            ingredient_model(
+                "Ванилин",
+                nomenclature_model("Ванилин", "Ванилин продуктовый", g, group),
+                5,
+                g,
+            ),
         ]
         steps = [
             "Как испечь вафли хрустящие в вафельнице? Подготовьте необходимые продукты. Из данного количества у меня получилось 8 штук диаметром около 10 см.",
@@ -76,14 +85,15 @@ class start_factory:
             "Всыпьте муку, добавьте ванилин.",
             "Перемешайте массу венчиком до состояния гладкого однородного теста.",
             "Разогрейте вафельницу по инструкции к ней. У меня очень старая, еще советских времен электровафельница. Она может и не очень красивая, но печет замечательно! Я не смазываю вафельницу маслом, в тесте достаточно жира, да и к ней уже давно ничего не прилипает. Но вы смотрите по своей модели. Выкладывайте тесто по столовой ложке. Можно класть немного меньше теста, тогда вафли будут меньше и их получится больше.",
-            "Пеките вафли несколько минут до золотистого цвета. Осторожно откройте вафельницу, она очень горячая! Снимите вафлю лопаткой. Горячая она очень мягкая, как блинчик. Но по мере остывания становится твердой и хрустящей. Такие вафли можно свернуть трубочкой. Но делать это надо сразу же после выпекания, пока она мягкая и горячая, потом у вас ничего не получится, вафля поломается. Приятного аппетита!"
+            "Пеките вафли несколько минут до золотистого цвета. Осторожно откройте вафельницу, она очень горячая! Снимите вафлю лопаткой. Горячая она очень мягкая, как блинчик. Но по мере остывания становится твердой и хрустящей. Такие вафли можно свернуть трубочкой. Но делать это надо сразу же после выпекания, пока она мягкая и горячая, потом у вас ничего не получится, вафля поломается. Приятного аппетита!",
         ]
 
-        result.append(recipe_model.create("Вафли хрустящие в вафельнице", ingredients, steps))
+        result.append(
+            recipe_model.create("Вафли хрустящие в вафельнице", ingredients, steps)
+        )
 
         return result
-    
-    
+
     def create(self):
         """
            В зависимости от настроек, сформировать начальную номенклатуру
@@ -91,11 +101,11 @@ class start_factory:
         Returns:
             _type_: _description_
         """
-        
+
         result = []
-        if self.__options.is_first_run == True:
+        if self.__options.is_first_run:
             self.__options.is_first_run = False
-            
+
             # Формируем и зпоминаем номеклатуру
             res = self.create_recipes()
             ingredients = set()
@@ -109,7 +119,7 @@ class start_factory:
             result = nomenclatures
             munits = set([x.measurement_unit for x in nomenclatures])
             nomgroups = set([x.nomenclature_group for x in nomenclatures])
-            self.__save(storage.nomenclature_key(), nomenclatures )
+            self.__save(storage.nomenclature_key(), nomenclatures)
             self.__save(storage.measurement_unit_key(), munits)
             self.__save(storage.nomenclature_group_key(), nomgroups)
             self.__save(storage.ingredient_key(), ingredients)

+ 17 - 15
src/models/abstract_reference.py

@@ -6,17 +6,20 @@ from src.validation.validator import validator
 
 class abstract_reference(ABC):
     __id: uuid.UUID
-    __name:str = ""
+    __name: str = ""
     __error: error_proxy = error_proxy()
 
     # Валидатор
     __vtor = validator()
-    
+
     def __init__(self, name: str = None) -> None:
         self.name = name
         self.__id = uuid.uuid4()
-        
-    @property    
+
+    def __str__(self):
+        return self.name
+
+    @property
     def error(self):
         """
            Работа с ошибками
@@ -24,31 +27,30 @@ class abstract_reference(ABC):
         Returns:
             _type_: _description_
         """
-        return self.__error    
-        
-    @property    
+        return self.__error
+
+    @property
     def id(self):
         """
             Уникальный код
         Returns:
             _type_: _description_
         """
-        return self.__id    
-        
-    @property    
+        return self.__id
+
+    @property
     def name(self):
         """
            Наименование
         Returns:
             _type_: _description_
         """
-        return self.__name.strip()    
-   
-    @name.setter 
+        return self.__name.strip()
+
+    @name.setter
     def name(self, value: str):
         self.__vtor.check_type(value, str)
         value = value.strip()
         self.__vtor.check_length_bound(value, 1, 50)
-        
+
         self.__name = value
-        

+ 6 - 7
src/models/company_model.py

@@ -3,7 +3,7 @@ from src.settings.settings import settings
 from src.validation.validator import validator
 
 
-class company_model (abstract_reference):
+class company_model(abstract_reference):
     # ИНН
     __tax_id = 0
     # БИК
@@ -16,14 +16,13 @@ class company_model (abstract_reference):
     # Валидатор
     __vtor = validator()
 
-
     def __init__(self, name, data: settings):
         """
         Args:
             data (settings): Объект настроек с данными организации
         """
         self.__vtor.check_type(data, settings)
-        
+
         self.__tax_id = data.tax_id
         self.__bank_id = data.bank_id
         self.__bank_account_id = data.bank_account_id
@@ -36,21 +35,21 @@ class company_model (abstract_reference):
         """ИНН"""
 
         return self.__tax_id
-    
+
     @property
     def bank_id(self):
         """БИК"""
 
         return self.__bank_id
-    
+
     @property
     def bank_account_id(self):
         """Банковский счет"""
 
         return self.__bank_account_id
-    
+
     @property
     def property_type(self):
         """Вид собственности"""
 
-        return self.__property_type
+        return self.__property_type

+ 12 - 11
src/models/ingredient_model.py

@@ -4,7 +4,7 @@ from src.models.abstract_reference import abstract_reference
 from src.validation.validator import validator
 
 
-class ingredient_model (abstract_reference):
+class ingredient_model(abstract_reference):
     # Номенклатура ингредиента
     __nomenclature = None
 
@@ -14,12 +14,16 @@ class ingredient_model (abstract_reference):
     # Единица измерения количества ингредиента
     __measurement_unit = None
 
-
     # Валидатор
     __vtor = validator()
 
-
-    def __init__(self, name, nomenclature:nomenclature_model, amount:int, unit:measurement_unit_model):
+    def __init__(
+        self,
+        name,
+        nomenclature: nomenclature_model,
+        amount: int,
+        unit: measurement_unit_model,
+    ):
         self.__vtor.check_type(nomenclature, nomenclature_model)
         self.__vtor.check_number(amount)
         self.__vtor.check_type(unit, measurement_unit_model)
@@ -28,13 +32,12 @@ class ingredient_model (abstract_reference):
         self.__measurement_unit = unit
         super().__init__(name)
 
-    
     @property
     def nomenclature(self):
         """Номенклатура ингредиента"""
 
         return self.__nomenclature
-    
+
     @nomenclature.setter
     def nomenclature(self, value: nomenclature_model):
         """
@@ -49,13 +52,12 @@ class ingredient_model (abstract_reference):
 
         self.__nomenclature = value
 
-    
     @property
     def amount(self):
         """Количество ингредиента"""
 
         return self.__amount
-    
+
     @amount.setter
     def amount(self, value):
         """
@@ -70,13 +72,12 @@ class ingredient_model (abstract_reference):
 
         self.__amount = value
 
-
     @property
     def measurement_unit(self):
         """Единица измерения количества ингредиента"""
 
         return self.__measurement_unit
-    
+
     @measurement_unit.setter
     def measurement_unit(self, value: measurement_unit_model):
         """
@@ -89,4 +90,4 @@ class ingredient_model (abstract_reference):
 
         self.__vtor.check_type(value, measurement_unit_model)
 
-        self.__measurement_unit = value
+        self.__measurement_unit = value

+ 15 - 20
src/models/measurement_unit_model.py

@@ -2,7 +2,7 @@ from src.models.abstract_reference import abstract_reference
 from src.validation.validator import validator
 
 
-class measurement_unit_model (abstract_reference):
+class measurement_unit_model(abstract_reference):
     # Базовая единица измерения
     __base_measurement_unit = None
     # Базовый коэффициент
@@ -11,7 +11,7 @@ class measurement_unit_model (abstract_reference):
     # Валидатор
     __vtor = validator()
 
-    def __init__(self, name, base_coefficient = 1, base_measurement=None):
+    def __init__(self, name, base_coefficient=1, base_measurement=None):
         """
         Args:
             base_measurement (measurement_unit_model): Базовая единица измерения
@@ -25,19 +25,18 @@ class measurement_unit_model (abstract_reference):
         self.__base_coefficient = base_coefficient
 
         super().__init__(name)
-        
 
     @property
     def base_measurement_unit(self):
         """
-            Базовая единица измерения
+        Базовая единица измерения
         """
 
         if self.__base_measurement_unit is None:
             return self
 
         return self.__base_measurement_unit
-    
+
     @base_measurement_unit.setter
     def base_measurement_unit(self, value):
         """
@@ -52,15 +51,14 @@ class measurement_unit_model (abstract_reference):
 
         self.__base_measurement_unit = value
 
-    
     @property
     def base_coefficient(self):
         """
-            Коэффициент относительно базовой единицы измерения
+        Коэффициент относительно базовой единицы измерения
         """
 
         return self.__base_coefficient
-    
+
     @base_coefficient.setter
     def base_coefficient(self, value):
         """
@@ -74,16 +72,15 @@ class measurement_unit_model (abstract_reference):
         self.__vtor.check_number(value)
 
         self.__base_coefficient = value
-    
 
     def to_base_unit(self, value):
         """
-            Значение в базовой единице измерения
+        Значение в базовой единице измерения
         """
 
         return value * self.base_coefficient
-    
-    @staticmethod    
+
+    @staticmethod
     def create_g():
         """
             Создать единицу измерения грамм
@@ -92,8 +89,8 @@ class measurement_unit_model (abstract_reference):
             Модель грамма
         """
         item = measurement_unit_model("грамм")
-        return item    
-    
+        return item
+
     @staticmethod
     def create_kg():
         """
@@ -104,7 +101,7 @@ class measurement_unit_model (abstract_reference):
         g = measurement_unit_model.create_g()
         item = measurement_unit_model("киллограмм", 1000, g)
         return item
-    
+
     @staticmethod
     def create_pcs():
         """
@@ -113,7 +110,7 @@ class measurement_unit_model (abstract_reference):
             Модель штуки
         """
         return measurement_unit_model("штук")
-    
+
     @staticmethod
     def create_ml():
         """
@@ -122,7 +119,7 @@ class measurement_unit_model (abstract_reference):
             Модель миллилитра
         """
         return measurement_unit_model("мл")
-    
+
     @staticmethod
     def create_l():
         """
@@ -130,6 +127,4 @@ class measurement_unit_model (abstract_reference):
         Returns:
             Модель литра
         """
-        return measurement_unit_model("литр",
-                                      measurement_unit_model.create_ml(),
-                                      1000)
+        return measurement_unit_model("литр", measurement_unit_model.create_ml(), 1000)

+ 2 - 2
src/models/nomenclature_group_model.py

@@ -1,7 +1,7 @@
 from src.models.abstract_reference import abstract_reference
 
 
-class nomenclature_group_model (abstract_reference):
+class nomenclature_group_model(abstract_reference):
     def __init__(self, name):
         super().__init__(name)
 
@@ -14,4 +14,4 @@ class nomenclature_group_model (abstract_reference):
             _type_: _description_
         """
         item = nomenclature_group_model("Ингредиенты")
-        return item
+        return item

+ 7 - 8
src/models/nomenclature_model.py

@@ -15,7 +15,6 @@ class nomenclature_model(abstract_reference):
     # Валидатор
     __vtor = validator()
 
-
     def __init__(self, name, full_name, measurement_unit, nomenclature_group):
         """
         Args:
@@ -38,9 +37,9 @@ class nomenclature_model(abstract_reference):
     @property
     def full_name(self):
         """Полное наименование (до 256 символов)"""
-        
+
         return self.__full_name
-    
+
     @full_name.setter
     def full_name(self, value: str):
         """
@@ -56,13 +55,13 @@ class nomenclature_model(abstract_reference):
         self.__vtor.check_length_less(256)
 
         self.__full_name = value
-    
+
     @property
     def measurement_unit(self):
         """Единица измерения"""
 
         return self.__measurement_unit
-    
+
     @measurement_unit.setter
     def measurement_unit(self, value: measurement_unit_model):
         """
@@ -76,13 +75,13 @@ class nomenclature_model(abstract_reference):
         self.__vtor.check_type(value, measurement_unit_model)
 
         self.__measurement_unit = value
-    
+
     @property
     def nomenclature_group(self):
         """Группа номенклатуры"""
 
         return self.__nomenclature_group
-    
+
     @nomenclature_group.setter
     def nomenclature_group(self, value: nomenclature_group_model):
         """
@@ -95,4 +94,4 @@ class nomenclature_model(abstract_reference):
 
         self.__vtor.check_type(value, nomenclature_group_model)
 
-        self.__nomenclature_group = value
+        self.__nomenclature_group = value

+ 11 - 15
src/models/recipe_model.py

@@ -3,24 +3,21 @@ from src.models.abstract_reference import abstract_reference
 from src.validation.validator import validator
 
 
-class recipe_model (abstract_reference):
+class recipe_model(abstract_reference):
     # Ингредиенты рецепта
     __ingredients = list()
 
     # Шаги приготовления рецепта
     __steps = list()
 
-
     # Валидатор
     __vtor = validator()
 
-
     def __init__(self, name):
         super().__init__(name)
 
-    
     @staticmethod
-    def create(name, ingredients:list=None, steps:list=None):
+    def create(name, ingredients: list = None, steps: list = None):
         """
             Фабричный метод для создания рецепта
         Args:
@@ -31,19 +28,18 @@ class recipe_model (abstract_reference):
         """
 
         recipe = recipe_model(name)
-        
+
         recipe.ingredients = ingredients if ingredients is not None else list()
         recipe.steps = steps if steps is not None else list()
 
         return recipe
 
-
     @property
     def ingredients(self):
         """Ингредиенты рецепта"""
 
         return self.__ingredients
-    
+
     @ingredients.setter
     def ingredients(self, ingredients: list):
         """
@@ -57,16 +53,15 @@ class recipe_model (abstract_reference):
 
         self.__vtor.check_type(ingredients, list)
         self.__vtor.check_collection_types_all(ingredients, ingredient_model)
-        
-        self.__ingredients = ingredients
 
+        self.__ingredients = ingredients
 
     @property
     def steps(self):
         """Шаги рецепта"""
 
         return self.__steps
-    
+
     @steps.setter
     def steps(self, steps: list):
         """
@@ -79,8 +74,9 @@ class recipe_model (abstract_reference):
         """
 
         self.__vtor.check_type(steps, list)
-        self.__vtor.check_collection_all(steps,
-                                               lambda item: self.__vtor.check_type(item, str))
+        self.__vtor.check_collection_all(
+            steps, lambda item: self.__vtor.check_type(item, str)
+        )
         self.__vtor.check_collection_types_all(steps, str)
-        
-        self.__steps = steps
+
+        self.__steps = steps

+ 2 - 2
src/models/warehouse_model.py

@@ -1,6 +1,6 @@
 from src.models.abstract_reference import abstract_reference
 
 
-class warehouse_model (abstract_reference):
+class warehouse_model(abstract_reference):
     def __init__(self, name):
-        super().__init__(name)
+        super().__init__(name)

+ 32 - 17
src/settings/settings.py

@@ -20,17 +20,19 @@ class settings:
     # Первый ли запуск
     __is_first_run = True
 
+    # Стратегия экспорта
+    __export_format = "csv"
 
     # Валидатор
     __vtor = None
 
     def __init__(self):
         self.__vtor = validator()
-    
+
     @property
     def first_name(self):
         return self.__first_name
-    
+
     @first_name.setter
     def first_name(self, value: str):
         """
@@ -43,13 +45,13 @@ class settings:
         """
 
         self.__vtor.check_type(value, str)
-        
+
         self.__first_name = value.strip()
 
     @property
     def tax_id(self):
         return self.__tax_id
-    
+
     @tax_id.setter
     def tax_id(self, value: int):
         """
@@ -66,11 +68,11 @@ class settings:
         self.__vtor.check_length(value, 12)
 
         self.__tax_id = value
-    
+
     @property
     def bank_id(self):
         return self.__bank_id
-    
+
     @bank_id.setter
     def bank_id(self, value: int):
         """
@@ -88,11 +90,10 @@ class settings:
 
         self.__bank_id = value
 
-    
     @property
     def bank_account_id(self):
         return self.__bank_account_id
-    
+
     @bank_account_id.setter
     def bank_account_id(self, value: int):
         """
@@ -109,12 +110,11 @@ class settings:
         self.__vtor.check_length(value, 11)
 
         self.__bank_account_id = value
-        
 
     @property
     def corresp_account_id(self):
         return self.__corresp_account_id
-    
+
     @corresp_account_id.setter
     def corresp_account_id(self, value: int):
         """
@@ -132,11 +132,10 @@ class settings:
 
         self.__corresp_account_id = value
 
-
     @property
     def property_name(self):
         return self.__property_name
-    
+
     @property_name.setter
     def property_name(self, value: str):
         """
@@ -152,11 +151,10 @@ class settings:
 
         self.__property_name = value
 
-    
     @property
     def property_type(self):
         return self.__property_type
-    
+
     @property_type.setter
     def property_type(self, value: str):
         """
@@ -174,13 +172,12 @@ class settings:
 
         self.__property_type = value
 
-
     @property
     def is_first_run(self):
         """Первый ли запуск?"""
 
         return self.__is_first_run
-    
+
     @is_first_run.setter
     def is_first_run(self, value: bool):
         """
@@ -193,4 +190,22 @@ class settings:
 
         self.__vtor.check_type(value, bool)
 
-        self.__is_first_run = value
+        self.__is_first_run = value
+
+    @property
+    def export_format(self):
+        """Предпочитаемый формат экспорта"""
+
+        return self.__export_format
+
+    @export_format.setter
+    def export_format(self, value: str):
+        """
+            Предпочитаемый формат экспорта
+        Args:
+            value (str): Значение (допустимо: ["csv", "json", "markdown", "xml"])
+        """
+
+        value = value.lower()
+
+        self.__vtor.check_value_in(value, ["csv", "json", "markdown", "xml"])

+ 12 - 11
src/settings/settings_manager.py

@@ -1,11 +1,12 @@
-import os, json
+import os
+import json
 from src.settings.settings import settings
 from src.errors.instance_exception import instance_exception
 from src.validation.validator import validator
 from src.errors.file_exception import file_exception
 
 
-class settings_manager (object):
+class settings_manager(object):
     # Объект настроек
     __settings = settings()
     # Путь до файла настроек
@@ -16,7 +17,6 @@ class settings_manager (object):
     # Валидатор
     __vtor = validator()
 
-
     # Возвращаем существующий инстанс при вызове new() (singleton)
     def __new__(cls):
         if not hasattr(cls, "instance"):
@@ -26,11 +26,11 @@ class settings_manager (object):
     @property
     def data(self):
         return self.__data
-    
+
     @property
     def settings(self):
         return self.__settings
-    
+
     def __convert(self):
         """
             Заполнить объект настроек
@@ -46,7 +46,8 @@ class settings_manager (object):
         # Переносим считанные значения в инстанс настроек
         for key in self.__data.keys():
             # Пропускаем, если у settings нет соответствующего свойства
-            if not hasattr(self.__settings, key): continue
+            if not hasattr(self.__settings, key):
+                continue
             setattr(self.__settings, key, self.__data[key])
 
     def open(self, filename):
@@ -60,10 +61,10 @@ class settings_manager (object):
         """
         # Проверяем, чтобы путь был строкой
         self.__vtor.check_type(filename, str)
-        
+
         # Проверяем, чтобы путь не был пуст
         self.__vtor.check_length_greater(filename, 0)
-        
+
         # Убираем leading/trailing пробелы
         self.__filename = filename.strip()
         return self.__open()
@@ -80,12 +81,12 @@ class settings_manager (object):
         # Проверяем, существует ли файл по данному пути
         if not os.path.exists(settings_file):
             raise file_exception("Файл не найден")
-        
+
         # Открываем файл и парсим JSON
         with open(settings_file, "r", encoding="UTF-8") as read_file:
             self.__data = json.load(read_file)
-        
+
         # Заполняем объект settings прочитанными значениями
         self.__convert()
 
-        return True
+        return True

+ 6 - 13
src/storage/storage.py

@@ -3,13 +3,12 @@
 #
 class storage:
     __data = {}
-    
-    
+
     def __new__(cls):
-        if not hasattr(cls, 'instance'):
+        if not hasattr(cls, "instance"):
             cls.instance = super(storage, cls).__new__(cls)
-        return cls.instance  
-    
+        return cls.instance
+
     @property
     def data(self) -> dict:
         """
@@ -20,7 +19,6 @@ class storage:
         """
         return self.__data
 
- 
     @staticmethod
     def nomenclature_key():
         """
@@ -30,7 +28,6 @@ class storage:
         """
         return "nomenclature"
 
-  
     @staticmethod
     def nomenclature_group_key():
         """
@@ -39,9 +36,8 @@ class storage:
             _type_: _description_
         """
         return "group"
-      
-      
-    @staticmethod  
+
+    @staticmethod
     def measurement_unit_key():
         """
               Список единиц измерения
@@ -49,7 +45,6 @@ class storage:
             _type_: _description_
         """
         return "unit"
-    
 
     @staticmethod
     def ingredient_key():
@@ -59,7 +54,6 @@ class storage:
             _type_: _description_
         """
         return "ingredient"
-    
 
     @staticmethod
     def recipe_key():
@@ -69,4 +63,3 @@ class storage:
             _type_: _description_
         """
         return "recipe"
-    

+ 60 - 23
src/validation/validator.py

@@ -1,3 +1,4 @@
+from ast import arg
 import re
 from numbers import Number
 from src.errors.argument_exception import argument_exception
@@ -9,7 +10,7 @@ class validator:
         if not hasattr(cls, "instance"):
             cls.instance = super(validator, cls).__new__(cls)
         return cls.instance
-    
+
     def check(self, value, method):
         """
             Валидация аргумента по лямбде
@@ -22,7 +23,7 @@ class validator:
 
         if not method(value):
             raise argument_exception("Аргумент не прошел валидацию по лямбде")
-        
+
         return True
 
     def check_type(self, value, exp_type):
@@ -36,10 +37,12 @@ class validator:
         """
 
         if not isinstance(value, exp_type):
-            raise argument_exception(f"Некорректный тип аргумента ({type(value)}, expected {exp_type})")
+            raise argument_exception(
+                f"Некорректный тип аргумента ({type(value)}, expected {exp_type})"
+            )
 
         return True
-    
+
     def check_type_any(self, value, *types):
         """
             Валидация аргумента по соответствию одному из типов
@@ -59,8 +62,10 @@ class validator:
                 break
 
         if not flag:
-            raise argument_exception("Аргумент не соответствует ни одному из ожидаемых типов "\
-                                     + f"({type(value)}, expected={', '.join(types)})")
+            raise argument_exception(
+                "Аргумент не соответствует ни одному из ожидаемых типов "
+                + f"({type(value)}, expected={', '.join(types)})"
+            )
 
         return True
 
@@ -78,7 +83,9 @@ class validator:
             value = str(value)
 
         if len(value) != length:
-            raise argument_exception(f"Несоответствующая длина аргумента ({len(value)}, expected {length})")
+            raise argument_exception(
+                f"Несоответствующая длина аргумента ({len(value)}, expected {length})"
+            )
 
         return True
 
@@ -95,10 +102,11 @@ class validator:
 
         if value is int:
             value = str(value)
-        
-        if (len(value) > length if inclusive \
-                else len(value) >= length):
-                    raise argument_exception(f"Превышена длина аргумента ({len(value)}, max={length})")
+
+        if len(value) > length if inclusive else len(value) >= length:
+            raise argument_exception(
+                f"Превышена длина аргумента ({len(value)}, max={length})"
+            )
 
         return True
 
@@ -116,13 +124,21 @@ class validator:
         if value is int:
             value = str(value)
 
-        if (len(value) < length if inclusive \
-                else len(value) <= length):
-            raise argument_exception("Недостаточная длина аргумента ({len(value)}, min={length})")
+        if len(value) < length if inclusive else len(value) <= length:
+            raise argument_exception(
+                "Недостаточная длина аргумента ({len(value)}, min={length})"
+            )
 
         return True
 
-    def check_length_bound(self, value, min_length: int, max_length: int, inclusive_min=True, inclusive_max=True):
+    def check_length_bound(
+        self,
+        value,
+        min_length: int,
+        max_length: int,
+        inclusive_min=True,
+        inclusive_max=True,
+    ):
         """
             Валидация аргумента по минимальной и максимальной длинам
         Args:
@@ -158,6 +174,23 @@ class validator:
 
         return True
 
+    def check_value_in(self, value, expected: list):
+        """
+            Валидация аргумента по принадлежности списку
+        Args:
+            value (any): Передаваемый аргумент
+            expected (list): Список допустимых значений
+        Raises:
+            argument_exception: Значение аргумента не принадлежит списку допустимых
+        """
+
+        if value not in expected:
+            raise argument_exception(
+                f"Значение аргумента не принадлежит списку допустимых ({value} not in {"".join(expected)})"
+            )
+
+        return True
+
     def check_regex(self, value, expression: str):
         """
             Валидация аргумента по регулярному выражению
@@ -169,7 +202,9 @@ class validator:
         """
 
         if re.match(expression, value) is None:
-            raise argument_exception(f"Аргумент не соответствует регулярному выражению ({str(value)}, regex: {expression})")
+            raise argument_exception(
+                f"Аргумент не соответствует регулярному выражению ({str(value)}, regex: {expression})"
+            )
 
         return True
 
@@ -183,10 +218,12 @@ class validator:
         """
 
         if not isinstance(value, Number):
-            raise argument_exception(f"Аргумент не является числом (type={type(value)})")
-        
+            raise argument_exception(
+                f"Аргумент не является числом (type={type(value)})"
+            )
+
         return True
-    
+
     def check_collection_all(self, value, method):
         """
             Валидация коллекции по соответствию лямбде
@@ -204,9 +241,9 @@ class validator:
             except argument_exception as exc:
                 raise argument_exception(f"Один из членов коллекции не прошел валидацию \
                                          ({exc.error.error_text} on item #{num})")
-            
+
         return True
-    
+
     def check_collection_types_all(self, value, exp_type):
         """
             Валидация коллекции по соответствию типа
@@ -220,8 +257,8 @@ class validator:
         for num, val in enumerate(value):
             try:
                 self.check_type(val, exp_type)
-            except argument_exception as exc:
+            except argument_exception:
                 raise argument_exception(f"Один из членов коллекции не соответствует типу {exp_type} \
                                          (excepted {exp_type}, got {type(val)} on element #{num})")
-            
+
         return True

+ 13 - 19
tests/test_errors.py

@@ -3,12 +3,10 @@ import unittest
 from src.errors.argument_exception import argument_exception
 
 
-
 class test_errors(unittest.TestCase):
-    
     def test_check_argument_exception(self):
         # Подготовка
-        
+
         # Действие
         try:
             raise argument_exception("Test")
@@ -16,34 +14,30 @@ class test_errors(unittest.TestCase):
             # Проверка
             print(ex.error.error_text)
             print(ex.error.error_source)
-            
-            
+
             assert ex.error.is_error
             return
-            
-        assert False  
-        
-    
+
+        assert False
+
     def test_check_set_exception(self):
         # Подготовка
         error = error_proxy()
-              
-        
+
         # Действие
         try:
-            result = 1 / 0
-        except Exception as ex  :
+            raise Exception()
+        except Exception as ex:
             error.set_error(ex)
-            
+
         # Проверки
         assert error.is_error
-        
-    
+
     def test_check_set_error_text(self):
         # Подготовка
         error = error_proxy("Test", "Test")
-        
+
         # Действие
-        
+
         # Проверки
-        assert error.is_error
+        assert error.is_error

+ 32 - 0
tests/test_export.py

@@ -0,0 +1,32 @@
+import unittest
+from src.export.strategies.csv_export import csv_export
+from src.export.exporter import exporter
+from src.models.measurement_unit_model import measurement_unit_model
+
+from src.storage.storage import storage
+
+
+#
+# Набор автотестов для проверки работы экспорта
+# #
+class test_export(unittest.TestCase):
+    def test_csv_munits(self):
+        # Подготовка
+        strg = storage()
+
+        munit1 = measurement_unit_model("g")
+        munit2 = measurement_unit_model("kg")
+        munit3 = measurement_unit_model("t")
+
+        strg.data[strg.measurement_unit_key()] = [munit1, munit2, munit3]
+
+        exp = exporter(csv_export())
+
+        expected = f"base_coefficient;base_measurement_unit;id;name\n{munit1.base_coefficient};{str(munit1.base_measurement_unit)};{munit1.id};{munit1.name}\n{munit2.base_coefficient};{str(munit2.base_measurement_unit)};{munit2.id};{munit2.name}\n{munit3.base_coefficient};{str(munit3.base_measurement_unit)};{munit3.id};{munit3.name}"
+
+        # Действие
+        csv = exp.export_by_key(strg.measurement_unit_key())
+
+        # Проверки
+        assert isinstance(csv, str)
+        assert csv == expected

+ 19 - 23
tests/test_factory.py

@@ -7,36 +7,36 @@ import unittest
 
 from src.storage.storage import storage
 
+
 #
 # Набор автотестов для проверки работы фабричного метода
 # #
-class factory_test(unittest.TestCase):
-
+class test_factory(unittest.TestCase):
     #
     # Проверка создания ед. измерения
     #
     def test_factory(self):
         # Подготовка
         unit = measurement_unit_model.create_kg()
-        
+
         # Действие
-        
+
         # Проверки
         assert isinstance(unit, measurement_unit_model)
         assert unit.base_coefficient == 1000
-        
-    # 
+
+    #
     # Проверка создание начальной номенклатуры
-    #    
+    #
     def test_create_recipes(self):
         # Подготовка
         items = start_factory.create_recipes()
-        
+
         # действие
-        
+
         # Прверки
-        assert len(items) > 0 
-        
+        assert len(items) > 0
+
     #
     # Проверка создания и записи списка номенклатур
     #
@@ -49,7 +49,7 @@ class factory_test(unittest.TestCase):
         st = setman.settings
 
         start_factory(st, stor).create()
-        
+
         # Действие
 
         # Проверка
@@ -59,25 +59,21 @@ class factory_test(unittest.TestCase):
         assert len(stor.data[stor.ingredient_key()]) > 0
         assert len(stor.data[stor.recipe_key()]) > 0
 
-    #      
+    #
     # Проверка работы класса start_factory
     #
     def test_start_factory(self):
         # Подготовка
         manager = settings_manager()
         strg = storage()
-        factory = start_factory( manager.settings,  strg)
-        
-        
+        factory = start_factory(manager.settings, strg)
+
         # Действие
         result = factory.create()
-        
-        
+
         # Проверка
-        if manager.settings.is_first_run == True:
+        if manager.settings.is_first_run:
             assert len(result) > 0
             return
-        
-        
-        assert len(result) == 0    
-        
+
+        assert len(result) == 0

+ 13 - 16
tests/test_models.py

@@ -6,9 +6,7 @@ from src.settings.settings_manager import settings_manager
 from src.models.measurement_unit_model import measurement_unit_model
 from src.models.nomenclature_group_model import nomenclature_group_model
 from src.models.nomenclature_model import nomenclature_model
-from src.models.warehouse_model import warehouse_model
 from src.models.abstract_reference import abstract_reference
-from src.errors.argument_exception import argument_exception
 from os import path
 
 
@@ -18,10 +16,10 @@ class test_models(unittest.TestCase):
         setman = settings_manager()
         setman.open(path.dirname(__file__) + "/../config/settings.json")
         sts = setman.settings
-    
+
         # Действие
         company = company_model("Test company", sts)
-    
+
         # Проверка
         assert isinstance(company, company_model)
         print("c", company.tax_id)
@@ -30,15 +28,14 @@ class test_models(unittest.TestCase):
         assert company.bank_id == sts.bank_id
         assert company.bank_account_id == sts.bank_account_id
         assert company.property_type == sts.property_type
-        
+
     def test_measurement_unit(self):
         # Подготовка
         g = measurement_unit_model("Граммы")
         kg = measurement_unit_model("Килограммы", 1000, g)
-    
+
         # Действие
-        
-    
+
         # Проверка
         assert isinstance(g, measurement_unit_model)
         assert isinstance(kg, measurement_unit_model)
@@ -49,11 +46,12 @@ class test_models(unittest.TestCase):
         # Подготовка
         munit = measurement_unit_model("Test munit")
         fn = "abc"
-        nom = nomenclature_model("Test nomenclature", fn, munit, nomenclature_group_model("Test ng"))
-    
+        nom = nomenclature_model(
+            "Test nomenclature", fn, munit, nomenclature_group_model("Test ng")
+        )
+
         # Действие
-        
-    
+
         # Проверка
         assert isinstance(nom, nomenclature_model)
         assert nom.full_name == fn
@@ -96,16 +94,15 @@ class test_models(unittest.TestCase):
         assert len(recipe.steps) == 2
         assert recipe.steps[0] == steps[0]
         assert recipe.steps[1] == steps[1]
-        
+
     def test_base_name_validation(self):
         # Подготовка
         fn = "abc"
         some = abstract_reference(fn)
         fn *= 2
-    
+
         # Действие
         some.name = fn
-    
+
         # Проверка
         assert some.name == fn
-    

+ 12 - 11
tests/test_settings.py

@@ -1,20 +1,21 @@
 from src.settings.settings import settings
 from src.settings.settings_manager import settings_manager
-import unittest, os, random
-    
+import unittest
+import os
+import random
+
 
 class test_settings(unittest.TestCase):
     projdir = os.path.dirname(__file__) + "/.."
-    
-    
+
     def test_first_name_setter(self):
         """Проверить корректность заполнения поля first_name"""
         # Подготовка
         item = settings()
-        
+
         # Действие
         item.first_name = "a  "
-        
+
         # Проверка
         assert item.first_name == "a"
 
@@ -33,12 +34,12 @@ class test_settings(unittest.TestCase):
         """Проверить корректность загрузки настроек"""
         # Подготовка
         man = settings_manager()
-        
+
         # Действие
         result = man.open(f"{self.projdir}/config/settings.json")
 
         # Проверка
-        assert result == True
+        assert result
 
     def test_settings_fields_nonempty(self):
         """Проверить, что все поля настроек не пусты после считывания настроек"""
@@ -54,7 +55,7 @@ class test_settings(unittest.TestCase):
         # Проверка
         for key in dict.keys():
             assert len(str(dict[key])) != 0
-            
+
     def test_settings_any_filename(self):
         """Проверить, что менеджер настроек может открыть файл с любым названием и в любой папке"""
         # Подготовка
@@ -62,9 +63,9 @@ class test_settings(unittest.TestCase):
             os.mkdir(f"{self.projdir}/.test_data")
         alp = "abcdefghijklmnopqrstuvwxyz"
         dirname = f"{self.projdir}/.test_data/"
-        dirname += ''.join(random.choice(alp) for _ in range(6))
+        dirname += "".join(random.choice(alp) for _ in range(6))
         filename = f"{dirname}/"
-        filename += ''.join(random.choice(alp) for _ in range(6)) + ".json"
+        filename += "".join(random.choice(alp) for _ in range(6)) + ".json"
         os.mkdir(dirname)
         print(filename)
         f = open(filename, "w", encoding="UTF-8")

+ 38 - 8
tests/test_validator.py

@@ -4,7 +4,6 @@ import unittest
 
 
 class test_validator(unittest.TestCase):
-
     def test_validator_lambda(self):
         """Проверить работоспособность validator.check()"""
         # Подготовка
@@ -65,13 +64,38 @@ class test_validator(unittest.TestCase):
         # Вхождение в максимум
         assert vtor.check_length_bound("abc", 1, 3)
         # Невхождение в максимум
-        self.assertRaises(argument_exception, lambda: vtor.check_length_bound("abc", 1, 2))
+        self.assertRaises(
+            argument_exception, lambda: vtor.check_length_bound("abc", 1, 2)
+        )
         # Невхождение в минимум
-        self.assertRaises(argument_exception, lambda: vtor.check_length_bound("abc", 4, 5))
+        self.assertRaises(
+            argument_exception, lambda: vtor.check_length_bound("abc", 4, 5)
+        )
         # Невхождение в исключительный минимум
-        self.assertRaises(argument_exception, lambda: vtor.check_length_bound("abc", 3, 5, inclusive_min=False))
+        self.assertRaises(
+            argument_exception,
+            lambda: vtor.check_length_bound("abc", 3, 5, inclusive_min=False),
+        )
         # Невхождение в исключительный максимум
-        self.assertRaises(argument_exception, lambda: vtor.check_length_bound("abc", 1, 3, inclusive_max=False))
+        self.assertRaises(
+            argument_exception,
+            lambda: vtor.check_length_bound("abc", 1, 3, inclusive_max=False),
+        )
+
+    def test_validator_value_in(self):
+        """Проверить работоспособность validator.check_value_in()"""
+        # Подготовка
+        vtor = validator()
+        exp = ["alpha", "test", "beta"]
+
+        # Действие
+
+        # Проверка
+
+        # Вхождение в список допустимых
+        assert vtor.check_value_in("test", exp)
+        # Невхождение в список допустимых
+        self.assertRaises(argument_exception, lambda: vtor.check_value_in("gamma", exp))
 
     def test_validator_regex(self):
         """Проверить работоспособность validator.check_regex()"""
@@ -82,7 +106,9 @@ class test_validator(unittest.TestCase):
 
         # Проверка
         assert vtor.check_regex("abc", ".*b[c]+")
-        self.assertRaises(argument_exception, lambda: vtor.check_regex("abc", ".*b[c]+[a]+"))
+        self.assertRaises(
+            argument_exception, lambda: vtor.check_regex("abc", ".*b[c]+[a]+")
+        )
 
     def test_validator_collection_all(self):
         """Проверить работоспособность validator.check_collection_all()"""
@@ -95,7 +121,9 @@ class test_validator(unittest.TestCase):
 
         # Проверка
         assert vtor.check_collection_all(col1, lambda x: x > 4)
-        self.assertRaises(argument_exception, lambda: vtor.check_collection_all(col2, lambda x: x > 4))
+        self.assertRaises(
+            argument_exception, lambda: vtor.check_collection_all(col2, lambda x: x > 4)
+        )
 
     def test_validator_collection_types_all(self):
         """Проверить работоспособность validator.check_collection_types_all()"""
@@ -108,4 +136,6 @@ class test_validator(unittest.TestCase):
 
         # Проверка
         assert vtor.check_collection_types_all(col1, str)
-        self.assertRaises(argument_exception, lambda: vtor.check_collection_types_all(col2, str))
+        self.assertRaises(
+            argument_exception, lambda: vtor.check_collection_types_all(col2, str)
+        )