anb-python-components 1.2.1__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. anb_python_components-1.4.0/PKG-INFO +148 -0
  2. anb_python_components-1.4.0/anb_python_components/__init__.py +46 -0
  3. anb_python_components-1.4.0/anb_python_components/classes/__init__.py +8 -0
  4. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/classes/action_state.py +2 -1
  5. anb_python_components-1.4.0/anb_python_components/classes/dataclass_analyzer.py +97 -0
  6. anb_python_components-1.4.0/anb_python_components/classes/interface.py +192 -0
  7. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/classes/shortcode_parser.py +1 -1
  8. anb_python_components-1.4.0/anb_python_components/custom_types/__init__.py +7 -0
  9. anb_python_components-1.4.0/anb_python_components/decorators/__init__.py +2 -0
  10. anb_python_components-1.4.0/anb_python_components/decorators/interface_decorators.py +74 -0
  11. anb_python_components-1.4.0/anb_python_components/enums/__init__.py +5 -0
  12. anb_python_components-1.4.0/anb_python_components/exceptions/__init__.py +3 -0
  13. anb_python_components-1.4.0/anb_python_components/extensions/__init__.py +7 -0
  14. anb_python_components-1.4.0/anb_python_components/extensions/dataclass_extension.py +59 -0
  15. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/extensions/string_extension_constant.py +0 -1
  16. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/extensions/type_extension.py +26 -1
  17. anb_python_components-1.4.0/anb_python_components/models/__init__.py +4 -0
  18. anb_python_components-1.4.0/anb_python_components.egg-info/PKG-INFO +148 -0
  19. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components.egg-info/SOURCES.txt +9 -0
  20. anb_python_components-1.4.0/anb_python_components.egg-info/not-zip-safe +1 -0
  21. anb_python_components-1.4.0/anb_python_components.egg-info/requires.txt +1 -0
  22. anb_python_components-1.4.0/setup.py +74 -0
  23. anb_python_components-1.4.0/tests/classes/dataclass_analyzer_test.py +62 -0
  24. anb_python_components-1.4.0/tests/classes/interface_test.py +47 -0
  25. anb_python_components-1.2.1/PKG-INFO +0 -12
  26. anb_python_components-1.2.1/anb_python_components/__init__.py +0 -1
  27. anb_python_components-1.2.1/anb_python_components/classes/__init__.py +0 -1
  28. anb_python_components-1.2.1/anb_python_components/custom_types/__init__.py +0 -3
  29. anb_python_components-1.2.1/anb_python_components/enums/__init__.py +0 -1
  30. anb_python_components-1.2.1/anb_python_components/exceptions/__init__.py +0 -1
  31. anb_python_components-1.2.1/anb_python_components/extensions/__init__.py +0 -1
  32. anb_python_components-1.2.1/anb_python_components/models/__init__.py +0 -1
  33. anb_python_components-1.2.1/anb_python_components.egg-info/PKG-INFO +0 -12
  34. anb_python_components-1.2.1/setup.py +0 -26
  35. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/LICENSE +0 -0
  36. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/README.md +0 -0
  37. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/classes/directory.py +0 -0
  38. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/classes/file.py +0 -0
  39. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/custom_types/guid.py +0 -0
  40. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/custom_types/object_array.py +0 -0
  41. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/custom_types/shortcode_attributes.py +0 -0
  42. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/custom_types/two_dim_size.py +0 -0
  43. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/custom_types/version_info.py +0 -0
  44. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/enums/message_type.py +0 -0
  45. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/enums/not_bool_action.py +0 -0
  46. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/enums/type_copy_strategy.py +0 -0
  47. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/exceptions/wrong_type_exception.py +0 -0
  48. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/extensions/array_extension.py +0 -0
  49. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/extensions/bool_extension.py +0 -0
  50. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/extensions/string_extension.py +0 -0
  51. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/models/action_state_message.py +0 -0
  52. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components/models/shortcode_model.py +0 -0
  53. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components.egg-info/dependency_links.txt +0 -0
  54. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/anb_python_components.egg-info/top_level.txt +0 -0
  55. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/setup.cfg +0 -0
  56. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/__init__.py +0 -0
  57. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/classes/__init__.py +0 -0
  58. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/classes/action_state_test.py +0 -0
  59. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/classes/directory_test.py +0 -0
  60. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/classes/file_test.py +0 -0
  61. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/classes/shortcode_parser_test.py +0 -0
  62. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/custom_types/__init__.py +0 -0
  63. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/custom_types/guid_test.py +0 -0
  64. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/custom_types/object_array_test.py +0 -0
  65. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/custom_types/two_dim_size_test.py +0 -0
  66. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/custom_types/version_info_test.py +0 -0
  67. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/extensions/__init__.py +0 -0
  68. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/extensions/array_extension_test.py +0 -0
  69. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/extensions/bool_extension_test.py +0 -0
  70. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/extensions/string_extension_test.py +0 -0
  71. {anb_python_components-1.2.1 → anb_python_components-1.4.0}/tests/extensions/type_extension_test.py +0 -0
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.4
2
+ Name: anb_python_components
3
+ Version: 1.4.0
4
+ Summary: Набор компонентов Python, которые упрощают разработку / A set of Python components that simplify development
5
+ Home-page: https://gitflic.ru/project/babaev-an/anb-python-components
6
+ Author: Александр Бабаев
7
+ Author-email: contact_with_us@babaev-an.ru
8
+ Project-URL: Documentation, https://gitflic.ru/project/babaev-an/anb-python-components/wiki
9
+ Project-URL: Source, https://gitflic.ru/project/babaev-an/anb-python-components
10
+ Project-URL: Tracker, https://gitflic.ru/project/babaev-an/anb-python-components/issue?page=0
11
+ Keywords: python components development utils
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.14.0
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: setuptools>=80.9.0
23
+ Dynamic: author
24
+ Dynamic: author-email
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: keywords
30
+ Dynamic: license-file
31
+ Dynamic: project-url
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ # 📌🇷🇺 Русская версия
37
+
38
+ ---
39
+
40
+ ## Набор компонентов Python для упрощения разработки приложений
41
+
42
+ **ANB Python Components** — это библиотека полезных классов и модулей, предназначенная для ускорения процесса разработки
43
+ программного обеспечения на языке программирования Python. Библиотека включает широкий спектр инструментов, облегчающих
44
+ выполнение повседневных задач разработчика, от обработки файлов и сетевых запросов до автоматизации тестирования и
45
+ интеграции с популярными фреймворками.
46
+
47
+ ### ✅ Основные возможности:
48
+
49
+ - Удобные инструменты для работы с файлами и каталогами.
50
+ - Классы для работы с файлами и директориями.
51
+ - Классы для удобной передачи состояния.
52
+ - Новые
53
+ типы [GUID](https://gitflic.ru/project/babaev-an/anb-python-components/wiki/page?file=class_desc%2Ftypes%2Fguid.md),
54
+ [TwoDimSize](https://gitflic.ru/project/babaev-an/anb-python-components/wiki/page?file=class_desc%2Ftypes%2Ftwo_dim_size.md)
55
+ и [VersionInfo](https://gitflic.ru/project/babaev-an/anb-python-components/wiki/page?file=class_desc%2Ftypes%2Fversion_info.md).
56
+ - Расширение массивов, типа `bool`, типа `GUID`, типа `str`.
57
+ - Класс для перевода любого типа в строку и наоборот.
58
+
59
+ ### ⚙️ Установка и использование:
60
+
61
+ Установить пакет можно через pip:
62
+
63
+ ```bash
64
+ pip install anb-python-components --index-url https://registry.gitflic.ru/project/babaev-an/anb-python-components/package/-/pypi/simple
65
+ ```
66
+
67
+ Подключайте необходимые модули и начните пользоваться ими прямо сейчас:
68
+
69
+ ```python
70
+ from anb_python_components.custom_types.two_dim_size import TwoDimSize
71
+
72
+ # Пример использования
73
+ two_dim = TwoDimSize.parse('100x150', 'x')
74
+
75
+ # Теперь присваиваем какому-либо объекту
76
+ some_object_width = two_dim.width
77
+ some_object_height = two_dim.height
78
+ ```
79
+
80
+ ### 🛠️ Поддерживаемые технологии:
81
+
82
+ - `Python` версии 3.13.7 и выше
83
+ - Совместима с большинством популярных веб-фреймворков и библиотек Python
84
+ - Оптимизирован для работы с большими объемами данных и высоконагруженными приложениями
85
+
86
+ ### 💬 Вопросы и поддержка:
87
+
88
+ Для подробной справки обратитесь к руководству по библиотеке в разделе документации:
89
+
90
+ 🔗 Справочное руководство → [Документация библиотеки](https://gitflic.ru/project/babaev-an/anb-python-components/wiki)
91
+
92
+ ---
93
+
94
+ # 📌🇬🇧 English Version
95
+
96
+ ---
97
+
98
+ ## Python Component Collection for Streamlining Application Development
99
+
100
+ **ANB Python Components** is a collection of useful classes and modules specifically tailored to accelerate the process
101
+ of developing software using the Python programming language. It offers a broad spectrum of tools that simplify everyday
102
+ developer tasks, from file manipulation and network requests to test automation and seamless integration with widely
103
+ used frameworks.
104
+
105
+ ### ✅ Main Features:
106
+
107
+ - Handy tools for working with files and directories.
108
+ - Classes for handling files and folders.
109
+ - Classes for convenient state transfer.
110
+ - New custom_types such
111
+ as [GUID](https://gitflic.ru/project/babaev-an/anb-python-components/wiki/page?file=class_desc%2Ftypes%2Fguid.md), [TwoDimSize](https://gitflic.ru/project/babaev-an/anb-python-components/wiki/page?file=class_desc%2Ftypes%2Ftwo_dim_size.md),
112
+ and [VersionInfo](https://gitflic.ru/project/babaev-an/anb-python-components/wiki/page?file=class_desc%2Ftypes%2Fversion_info.md).
113
+ - Extensions for arrays, `bool`, `GUID`, and `str` custom_types.
114
+ - Class for converting any type into string representation and vice versa.
115
+
116
+ ### ⚙️ Installation and Usage:
117
+
118
+ You can install this package via pip:
119
+
120
+ ```bash
121
+ pip install anb-python-components --index-url https://registry.gitflic.ru/project/babaev-an/anb-python-components/package/-/pypi/simple
122
+ ```
123
+
124
+ Import required modules and start using them immediately:
125
+
126
+ ```python
127
+ from anb_python_components.custom_types.two_dim_size import TwoDimSize
128
+
129
+ # Example usage
130
+ two_dim = TwoDimSize.parse('100x150', 'x')
131
+
132
+ # Now assign it to some object
133
+ some_object_width = two_dim.width
134
+ some_object_height = two_dim.height
135
+ ```
136
+
137
+ ### 🛠️ Supported Technologies:
138
+
139
+ - **Python**: version 3.13.7 or higher
140
+ - Compatibility with most popular Python web frameworks and libraries
141
+ - Optimized for performance with large-scale datasets and highly loaded applications
142
+
143
+ ### 💬 Questions and Support:
144
+
145
+ For comprehensive guidance and support, consult the library's documentation section:
146
+
147
+ 🔗 Reference Guide → [Library Documentation](https://gitflic.ru/project/babaev-an/anb-python-components/wiki) (in Russian
148
+ Only)
@@ -0,0 +1,46 @@
1
+ # anb_python_components/__init__.py
2
+
3
+ # classes
4
+ from anb_python_components.classes import ActionState, DataclassAnalyzer, Directory, File, Interface, ShortCodeParser
5
+ # custom_types
6
+ from anb_python_components.custom_types import GUID, ObjectArray, ShortCodeAttributes, TwoDimSize, VersionInfo
7
+ # decorators
8
+ from anb_python_components.decorators import implement, interface_required
9
+ # enums
10
+ from anb_python_components.enums import MessageType, NotBoolAction, TypeCopyStrategy
11
+ # exceptions
12
+ from anb_python_components.exceptions import WrongTypeException
13
+ # extensions
14
+ from anb_python_components.extensions import (
15
+ ArrayExtension, BoolExtension, DataClassExtension, StringExtension,
16
+ TypeExtension
17
+ )
18
+ # models
19
+ from anb_python_components.models import ActionStateMessage, ShortCodeModel
20
+
21
+ __all__ = [
22
+ 'ActionState',
23
+ 'Directory',
24
+ 'File',
25
+ 'DataclassAnalyzer',
26
+ 'Interface',
27
+ 'ShortCodeParser',
28
+ 'GUID',
29
+ 'ObjectArray',
30
+ 'ShortCodeAttributes',
31
+ 'TwoDimSize',
32
+ 'VersionInfo',
33
+ 'interface_required',
34
+ 'implement',
35
+ 'MessageType',
36
+ 'NotBoolAction',
37
+ 'TypeCopyStrategy',
38
+ 'WrongTypeException',
39
+ 'ArrayExtension',
40
+ 'BoolExtension',
41
+ 'StringExtension',
42
+ "TypeExtension",
43
+ "DataClassExtension",
44
+ 'ActionStateMessage',
45
+ 'ShortCodeModel'
46
+ ]
@@ -0,0 +1,8 @@
1
+ # anb_python_components/classes/__init__.py
2
+
3
+ from anb_python_components.classes.action_state import ActionState
4
+ from anb_python_components.classes.dataclass_analyzer import DataclassAnalyzer
5
+ from anb_python_components.classes.directory import Directory
6
+ from anb_python_components.classes.file import File
7
+ from anb_python_components.classes.interface import Interface
8
+ from anb_python_components.classes.shortcode_parser import ShortCodeParser
@@ -2,8 +2,9 @@
2
2
  import copy
3
3
  from typing import Callable
4
4
 
5
+ from anb_python_components.enums.message_type import MessageType
5
6
  from anb_python_components.exceptions.wrong_type_exception import WrongTypeException
6
- from anb_python_components.models.action_state_message import ActionStateMessage, MessageType
7
+ from anb_python_components.models.action_state_message import ActionStateMessage
7
8
 
8
9
  class ActionState[T]:
9
10
  """
@@ -0,0 +1,97 @@
1
+ # anb_python_components/classes/dataclass_analyzer.py
2
+ from dataclasses import fields, is_dataclass
3
+ from typing import Any
4
+
5
+ class DataclassAnalyzer:
6
+ """
7
+ Класс анализа классов отмеченных как dataclass.
8
+ """
9
+
10
+ @staticmethod
11
+ def analyze_properties (cls, prop_name: str) -> dict[str, Any]:
12
+ """
13
+ Анализирует декораторы (метаданные) указанного свойства класса.
14
+ :param cls: Класс (должен реализовывать dataclass).
15
+ :param prop_name: Имя свойства.
16
+ :return: Словарь с информацией о применённых декораторах.
17
+ """
18
+ # Проверяем, что класс является dataclass
19
+ if not is_dataclass(cls):
20
+ # - иначе бросаем исключение
21
+ raise TypeError(f"Класс {cls.__name__} не является dataclass / Class {cls.__name__} is not a dataclass")
22
+
23
+ # Находим поле по имени
24
+ # - задаём начальное значение None
25
+ field_obj = None
26
+
27
+ # Перебираем поля класса
28
+ for field in fields(cls):
29
+ # - ищем поле с указанным именем
30
+ if field.name == prop_name:
31
+ # - если нашли, сохраняем объект поля
32
+ field_obj = field
33
+ # - и выходим из цикла
34
+ break
35
+
36
+ # Если поле не найдено
37
+ if field_obj is None:
38
+ # - бросаем исключение
39
+ raise AttributeError(
40
+ f"Свойство '{prop_name}' не найдено в классе {cls.__name__} / Property '{prop_name}' not found in class {cls.__name__}"
41
+ )
42
+
43
+ # Создаем словарь для результатов
44
+ results = {}
45
+
46
+ # Собираем метаданные
47
+ metadata = field_obj.metadata or {}
48
+
49
+ # Перебираем метаданные
50
+ for key, value in metadata.items():
51
+ # - добавляем в словарь
52
+ results[key] = value
53
+
54
+ # Возвращаем результаты
55
+ return results
56
+
57
+ @staticmethod
58
+ def analyze_class (cls) -> dict[str, dict[str, Any]]:
59
+ """
60
+ Анализирует все свойства dataclass-класса и класс‑уровневые метаданные.
61
+ :param cls: Dataclass-класс.
62
+ :return: Словарь с метаданными полей и класса.
63
+ """
64
+ # Проверяем, что класс является dataclass
65
+ if not is_dataclass(cls):
66
+ # - иначе бросаем исключение
67
+ raise TypeError(f"Класс {cls.__name__} не является dataclass / Class {cls.__name__} is not a dataclass")
68
+
69
+ results = {}
70
+
71
+ # Собираем класс‑уровневые метаданные (всё, что начинается с __meta_)
72
+ # - создаём пустой словарь
73
+ class_metadata = {}
74
+
75
+ # Перебираем атрибуты класса
76
+ for attr_name in dir(cls):
77
+ # - ищем атрибуты, начинающиеся с __meta_
78
+ if attr_name.startswith("__meta_"):
79
+ # -- удаляем префикс __meta_ и берём значение
80
+ key = attr_name[len("__meta_"):]
81
+ # -- добавляем в словарь
82
+ class_metadata[key] = getattr(cls, attr_name)
83
+
84
+ # Если есть метаданные
85
+ if class_metadata:
86
+ # - добавляем в результаты
87
+ results["__CLASS__"] = class_metadata
88
+
89
+ # Анализируем каждое поле
90
+ for field in fields(cls):
91
+ # - получаем имя поля
92
+ field_name = field.name
93
+ # - анализируем поле и сохраняем результаты в словарь
94
+ results[field_name] = DataclassAnalyzer.analyze_properties(cls, field_name)
95
+
96
+ # Возвращаем результаты
97
+ return results
@@ -0,0 +1,192 @@
1
+ # anb_python_components/classes/interface.py
2
+
3
+ import inspect
4
+ from functools import lru_cache
5
+ from typing import Any, Protocol, get_origin, runtime_checkable
6
+
7
+ @runtime_checkable
8
+ class Interface(Protocol):
9
+ """
10
+ Базовый класс для объявления интерфейсов с расширенной проверкой.
11
+ """
12
+
13
+ @classmethod
14
+ @lru_cache(maxsize = 128)
15
+ def verify (cls, obj_or_class) -> tuple[bool, list[str]]:
16
+ """
17
+ Проверяет, что объект или класс реализует интерфейс.
18
+ :param obj_or_class: Объект (созданный класс) или класс (или, точнее, его имя), который должен реализовывать интерфейс.
19
+ :return: Кортеж (is_ok, problems), где is_ok — True, если объект или класс реализует интерфейс, иначе False,
20
+ а problems — список сообщений об ошибках, если is_ok == False.
21
+ """
22
+ # Разбираем аргумент на объект или имя класса. Если аргумент — имя класса, то получаем его класс. В противном случае,
23
+ # возвращаем аргумент как объект.
24
+ target = obj_or_class if isinstance(obj_or_class, type) else obj_or_class.__class__
25
+
26
+ # Инициализируем список проблем
27
+ problems = []
28
+
29
+ # Собираем все методы интерфейса (включая унаследованные)
30
+ interface_methods = cls._get_all_interface_methods()
31
+
32
+ # Проходим по методам интерфейса
33
+ for method_name, signature in interface_methods.items():
34
+ # - если метод отсутствует в объекте
35
+ if not hasattr(target, method_name):
36
+ # -- добавляем в список проблем
37
+ problems.append(f"отсутствует метод '{method_name}' / missing method '{method_name}'")
38
+ # -- идём к следующему методу
39
+ continue
40
+
41
+ # - получаем именованный атрибут метода
42
+ target_method = getattr(target, method_name)
43
+
44
+ # - проверяем, что метод — вызываемый
45
+ if not callable(target_method):
46
+ # -- если нет, добавляем в список проблем
47
+ problems.append(f"'{method_name}' it is not callable")
48
+ # -- идём к следующему методу
49
+ continue
50
+
51
+ try:
52
+ # - получаем сигнатуру метода
53
+ target_signature = inspect.signature(target_method)
54
+
55
+ # - сравниваем сигнатуры метода и интерфейса
56
+ cls._compare_signatures(signature, target_signature, method_name, problems)
57
+ except (ValueError, TypeError) as e:
58
+ # Если сигнатуру нельзя получить, добавляем в список проблем
59
+ problems.append(f"ошибка проверки сигнатуры / signature verification error '{method_name}': {e}")
60
+
61
+ # В результат вернём кортеж (is_ok, problems), где is_ok — True, если проблем нет, иначе False, а problems — список проблем.
62
+ return len(problems) == 0, problems
63
+
64
+ @classmethod
65
+ def check (cls, obj_or_class) -> bool:
66
+ """
67
+ Строгая проверка — поднимает исключение при несоответствии.
68
+ :param obj_or_class: Объект (созданный класс) или класс (или, точнее, его имя), который должен реализовывать интерфейс.
69
+ :return: True, если объект или класс реализует интерфейс.
70
+ """
71
+ # Проверяем, что объект или класс реализует интерфейс методом verify и получаем результат проверки
72
+ is_ok, problems = cls.verify(obj_or_class)
73
+
74
+ # Если объект или класс не реализует интерфейс
75
+ if not is_ok:
76
+ # - получаем имя объекта или класса
77
+ target_name = obj_or_class.__name__ if isinstance(obj_or_class, type) else obj_or_class.__class__.__name__
78
+
79
+ # - генерируем исключение с проблемами
80
+ raise TypeError(
81
+ f"{target_name} не реализует интерфейс {cls.__name__}.\n" +
82
+ f"{target_name} not implements interface {cls.__name__}.\n" +
83
+ f"Проблемы / Problems:\n" +
84
+ "\n ".join(problems)
85
+ )
86
+
87
+ # Возвращаем True, если объект или класс реализует интерфейс
88
+ return True
89
+
90
+ @classmethod
91
+ def get_methods (cls) -> dict[str, inspect.Signature]:
92
+ """
93
+ Возвращает словарь методов интерфейса с их сигнатурами.
94
+ :return: Словарь методов интерфейса с их сигнатурами.
95
+ """
96
+ return cls._get_interface_methods(cls)
97
+
98
+ @classmethod
99
+ def _get_all_interface_methods (cls) -> dict[str, inspect.Signature]:
100
+ """
101
+ Собирает все методы из иерархии наследования интерфейсов.
102
+ :return: Словарь методов с их сигнатурами.
103
+ """
104
+ # Создаем словарь методов
105
+ methods = {}
106
+
107
+ # Проходим по иерархии наследования интерфейсов рекурсивно
108
+ for base in reversed(cls.__mro__):
109
+ # - пропускаем базовый класс и сам интерфейс
110
+ if base is Interface or not issubclass(base, Interface):
111
+ continue
112
+
113
+ # - добавляем методы базового интерфейса
114
+ methods.update(cls._get_interface_methods(base))
115
+
116
+ # Возвращаем собранные методы
117
+ return methods
118
+
119
+ @staticmethod
120
+ def _get_interface_methods (interface_cls) -> dict[str, inspect.Signature]:
121
+ """Извлекает методы интерфейса и их сигнатуры."""
122
+ methods = {}
123
+ for attr_name in dir(interface_cls):
124
+ if attr_name.startswith('_') or attr_name == 'verify':
125
+ continue
126
+ attr = getattr(interface_cls, attr_name)
127
+ if callable(attr):
128
+ try:
129
+ signature = inspect.signature(attr)
130
+ methods[attr_name] = signature
131
+ except (ValueError, TypeError):
132
+ # Если сигнатуру нельзя получить, оставляем пустую
133
+ methods[attr_name] = inspect.Signature()
134
+ return methods
135
+
136
+ @staticmethod
137
+ def _compare_signatures (
138
+ expected: inspect.Signature,
139
+ actual: inspect.Signature,
140
+ method_name: str,
141
+ problems: list[str]
142
+ ) -> None:
143
+ """
144
+ Сравнивает сигнатуры методов.
145
+ :param expected: Ожидаемая сигнатура.
146
+ :param actual: Текущая сигнатура.
147
+ :param method_name: Имя метода.
148
+ :param problems: Список проблем.
149
+ :return: None
150
+ """
151
+ # Проверяем количество параметров
152
+ expected_params = list(expected.parameters.values())
153
+ actual_params = list(actual.parameters.values())
154
+
155
+ # Проверяем количество параметров
156
+ if len(expected_params) != len(actual_params):
157
+ # - если количество параметров не совпадает, добавляем в список проблем
158
+ problems.append(
159
+ f"'{method_name}': ожидается {len(expected_params)} параметров, получено {len(actual_params)} / {method_name}': expected {len(expected_params)} parameters, got {len(actual_params)}"
160
+ )
161
+
162
+ # - прерываем выполнение
163
+ return
164
+
165
+ # Проверяем типы параметров (если указаны)
166
+ for i, (exp_param, act_param) in enumerate(zip(expected_params, actual_params)):
167
+ # - проверяем, что у ожидаемого параметра (exp_param) есть аннотация
168
+ if exp_param.annotation is not exp_param.empty:
169
+ # -- получаем тип ожидаемого параметра
170
+ expected_type = exp_param.annotation
171
+ # -- получаем тип текущего параметра
172
+ actual_type = act_param.annotation if act_param.annotation is not act_param.empty else Any
173
+
174
+ # -- сравниваем типы
175
+ if get_origin(expected_type) != get_origin(actual_type):
176
+ # --- если типы не совпадают, добавляем в список проблем
177
+ problems.append(
178
+ f"Тип аннотации не совпадает для / annotation type mismatch for parameter '{exp_param.name}'"
179
+ )
180
+
181
+ @classmethod
182
+ def register (cls, target_class):
183
+ """
184
+ Регистрирует класс как реализующий интерфейс (для документации).
185
+ :param target_class: Класс, который должен реализовывать интерфейс.
186
+ :return: Регистрированный класс.
187
+ """
188
+ # Проверяем, что класс реализует интерфейс
189
+ cls.check(target_class)
190
+
191
+ # Возвращаем класс
192
+ return target_class
@@ -4,8 +4,8 @@ import re
4
4
  from typing import Callable, Dict
5
5
 
6
6
  from anb_python_components.classes.action_state import ActionState
7
- from anb_python_components.models.shortcode_model import ShortCodeModel
8
7
  from anb_python_components.custom_types.shortcode_attributes import ShortCodeAttributes
8
+ from anb_python_components.models.shortcode_model import ShortCodeModel
9
9
 
10
10
  class ShortCodeParser:
11
11
  """
@@ -0,0 +1,7 @@
1
+ # anb_python_components/custom_types/__init__.py
2
+
3
+ from anb_python_components.custom_types.guid import GUID
4
+ from anb_python_components.custom_types.object_array import ObjectArray
5
+ from anb_python_components.custom_types.shortcode_attributes import ShortCodeAttributes
6
+ from anb_python_components.custom_types.two_dim_size import TwoDimSize
7
+ from anb_python_components.custom_types.version_info import VersionInfo
@@ -0,0 +1,2 @@
1
+ # anb_python_components/decorators/__init__.py
2
+ from anb_python_components.decorators.interface_decorators import implement, interface_required
@@ -0,0 +1,74 @@
1
+ # anb_python_components/decorators/interface_decorators.py
2
+ import inspect
3
+ from typing import Callable
4
+
5
+ from anb_python_components import Interface
6
+
7
+ def interface_required (signature: Callable | None = None, **kwargs) -> Callable:
8
+ """
9
+ Декоратор для явного указания обязательных методов интерфейса.
10
+ Позволяет задать сигнатуру через аннотации.
11
+ """
12
+
13
+ def decorator (func) -> Callable:
14
+ """
15
+ Декоратор для проверки сигнатуры.
16
+ :param func: Функция для проверки.
17
+ :return: Проверенная функция.
18
+ """
19
+ # Если сигнатура указана
20
+ if signature is not None:
21
+ # - сохраняем сигнатуру в атрибуте сигнатуры
22
+ func.__signature__ = inspect.signature(signature)
23
+ else:
24
+ # - иначе сохраняем сигнатуру в атрибуте аннотаций
25
+ func.__annotations__ = kwargs
26
+
27
+ # Возвращаем функцию
28
+ return func
29
+
30
+ # Возвращаем функцию-декоратор
31
+ return decorator
32
+
33
+ def implement (interface):
34
+ """
35
+ Декоратор для явного указания реализации интерфейса.
36
+ :param interface: Класс-интерфейс (наследник Interface)
37
+ :raise: TypeError: если класс не реализует интерфейс
38
+ :return: Оригинальный класс (с добавленным атрибутом __implements__)
39
+ """
40
+
41
+ def decorator (cls):
42
+ """
43
+ Декоратор для реализации интерфейса.
44
+ :param cls: Класс для реализации интерфейса.
45
+ :return: Оригинальный класс с реализацией интерфейса.
46
+ """
47
+ # 1. Проверяем, что interface действительно является интерфейсом
48
+ if not isinstance(interface, type) or not issubclass(interface, Interface):
49
+ raise TypeError(
50
+ f"{interface} не является интерфейсом (не наследуется от Interface) / is not an interface (does not inherit from Interface)"
51
+ )
52
+
53
+ # 2. Выполняем строгую проверку реализации
54
+ try:
55
+ interface.check(cls)
56
+ except TypeError as e:
57
+ raise TypeError(
58
+ f"Класс {cls.__name__} не реализует интерфейс {interface.__name__} / class {cls.__name__} does not implement interface {interface.__name__}\n {e}"
59
+ ) from e
60
+
61
+ # 3. Добавляем метаданные о реализации
62
+ if not hasattr(cls, '__implements__'):
63
+ cls.__implements__ = []
64
+ cls.__implements__.append(interface)
65
+
66
+ # 4. Сохраняем ссылку на интерфейс для интроспекции
67
+ impl_attr = f'__implements_{interface.__name__}'
68
+ setattr(cls, impl_attr, True)
69
+
70
+ # 5. Декоратор должен вернуть оригинальный класс
71
+ return cls
72
+
73
+ # Возвращаем функцию-декоратор
74
+ return decorator
@@ -0,0 +1,5 @@
1
+ # anb_python_components/enums/__init__.py
2
+
3
+ from anb_python_components.enums.message_type import MessageType
4
+ from anb_python_components.enums.not_bool_action import NotBoolAction
5
+ from anb_python_components.enums.type_copy_strategy import TypeCopyStrategy
@@ -0,0 +1,3 @@
1
+ # anb_python_components/exceptions/__init__.py
2
+
3
+ from anb_python_components.exceptions.wrong_type_exception import WrongTypeException
@@ -0,0 +1,7 @@
1
+ # anb_python_components/extensions/__init__.py
2
+
3
+ from anb_python_components.extensions.array_extension import ArrayExtension
4
+ from anb_python_components.extensions.bool_extension import BoolExtension
5
+ from anb_python_components.extensions.dataclass_extension import DataClassExtension
6
+ from anb_python_components.extensions.string_extension import StringExtension
7
+ from anb_python_components.extensions.type_extension import TypeExtension