anb-python-components 1.3.0__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.
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/PKG-INFO +3 -1
- anb_python_components-1.4.0/anb_python_components/__init__.py +46 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/classes/__init__.py +1 -0
- anb_python_components-1.4.0/anb_python_components/classes/dataclass_analyzer.py +97 -0
- anb_python_components-1.4.0/anb_python_components/exceptions/__init__.py +3 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/extensions/__init__.py +1 -0
- anb_python_components-1.4.0/anb_python_components/extensions/dataclass_extension.py +59 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/extensions/type_extension.py +26 -1
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components.egg-info/PKG-INFO +3 -1
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components.egg-info/SOURCES.txt +4 -0
- anb_python_components-1.4.0/anb_python_components.egg-info/requires.txt +1 -0
- anb_python_components-1.4.0/setup.py +74 -0
- anb_python_components-1.4.0/tests/classes/dataclass_analyzer_test.py +62 -0
- anb_python_components-1.3.0/anb_python_components/__init__.py +0 -55
- anb_python_components-1.3.0/anb_python_components/exceptions/__init__.py +0 -3
- anb_python_components-1.3.0/setup.py +0 -38
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/LICENSE +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/README.md +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/classes/action_state.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/classes/directory.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/classes/file.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/classes/interface.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/classes/shortcode_parser.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/custom_types/__init__.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/custom_types/guid.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/custom_types/object_array.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/custom_types/shortcode_attributes.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/custom_types/two_dim_size.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/custom_types/version_info.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/decorators/__init__.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/decorators/interface_decorators.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/enums/__init__.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/enums/message_type.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/enums/not_bool_action.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/enums/type_copy_strategy.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/exceptions/wrong_type_exception.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/extensions/array_extension.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/extensions/bool_extension.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/extensions/string_extension.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/extensions/string_extension_constant.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/models/__init__.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/models/action_state_message.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/models/shortcode_model.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components.egg-info/dependency_links.txt +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components.egg-info/not-zip-safe +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components.egg-info/top_level.txt +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/setup.cfg +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/__init__.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/classes/__init__.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/classes/action_state_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/classes/directory_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/classes/file_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/classes/interface_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/classes/shortcode_parser_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/custom_types/__init__.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/custom_types/guid_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/custom_types/object_array_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/custom_types/two_dim_size_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/custom_types/version_info_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/extensions/__init__.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/extensions/array_extension_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/extensions/bool_extension_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/extensions/string_extension_test.py +0 -0
- {anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/extensions/type_extension_test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anb_python_components
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Набор компонентов Python, которые упрощают разработку / A set of Python components that simplify development
|
|
5
5
|
Home-page: https://gitflic.ru/project/babaev-an/anb-python-components
|
|
6
6
|
Author: Александр Бабаев
|
|
@@ -19,6 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
19
19
|
Requires-Python: >=3.14.0
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
+
Requires-Dist: setuptools>=80.9.0
|
|
22
23
|
Dynamic: author
|
|
23
24
|
Dynamic: author-email
|
|
24
25
|
Dynamic: classifier
|
|
@@ -28,6 +29,7 @@ Dynamic: home-page
|
|
|
28
29
|
Dynamic: keywords
|
|
29
30
|
Dynamic: license-file
|
|
30
31
|
Dynamic: project-url
|
|
32
|
+
Dynamic: requires-dist
|
|
31
33
|
Dynamic: requires-python
|
|
32
34
|
Dynamic: summary
|
|
33
35
|
|
|
@@ -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
|
+
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# anb_python_components/classes/__init__.py
|
|
2
2
|
|
|
3
3
|
from anb_python_components.classes.action_state import ActionState
|
|
4
|
+
from anb_python_components.classes.dataclass_analyzer import DataclassAnalyzer
|
|
4
5
|
from anb_python_components.classes.directory import Directory
|
|
5
6
|
from anb_python_components.classes.file import File
|
|
6
7
|
from anb_python_components.classes.interface import Interface
|
|
@@ -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
|
|
@@ -2,5 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from anb_python_components.extensions.array_extension import ArrayExtension
|
|
4
4
|
from anb_python_components.extensions.bool_extension import BoolExtension
|
|
5
|
+
from anb_python_components.extensions.dataclass_extension import DataClassExtension
|
|
5
6
|
from anb_python_components.extensions.string_extension import StringExtension
|
|
6
7
|
from anb_python_components.extensions.type_extension import TypeExtension
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# anb_python_components/extensions/dataclass_extension.py
|
|
2
|
+
import copy
|
|
3
|
+
from dataclasses import Field, field
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from anb_python_components.extensions.type_extension import TypeExtension
|
|
7
|
+
|
|
8
|
+
# Базовая структура для представления расширенного типа
|
|
9
|
+
class DataClassExtension:
|
|
10
|
+
@staticmethod
|
|
11
|
+
def define (default: Any = None, metadata: dict[str, Any] = None) -> Field:
|
|
12
|
+
"""
|
|
13
|
+
Определяет поле с расширенными метаданными.
|
|
14
|
+
:param default: Значение по умолчанию для поля.
|
|
15
|
+
:param metadata: Метаданные для поля.
|
|
16
|
+
:return: Объект поля.
|
|
17
|
+
"""
|
|
18
|
+
# Создаём словарь метаданных
|
|
19
|
+
meta = {} if metadata is None else metadata
|
|
20
|
+
|
|
21
|
+
# Если значение по умолчанию не передано
|
|
22
|
+
if default is None:
|
|
23
|
+
# - то создаём поле без значения по умолчанию
|
|
24
|
+
return field(metadata = meta)
|
|
25
|
+
|
|
26
|
+
# Если значение по умолчанию передано неизменяемым типом, то создаём поле с этим значением по умолчанию, иначе с функцией-фабрикой
|
|
27
|
+
return field(default = default, metadata = meta) if TypeExtension.check_immutability(default) else field(
|
|
28
|
+
default_factory = lambda: copy.copy(default), metadata = meta
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def defines (default: Any, *fields: Field) -> Field:
|
|
33
|
+
"""
|
|
34
|
+
Определяет поле с расширенными метаданными и переданными полями.
|
|
35
|
+
:param default: Значение по умолчанию для поля.
|
|
36
|
+
:param fields: Поля для расширения.
|
|
37
|
+
:return: Объект поля.
|
|
38
|
+
"""
|
|
39
|
+
# Создаём словарь метаданных
|
|
40
|
+
metas = {}
|
|
41
|
+
|
|
42
|
+
# Проверяем, что все аргументы — экземпляры Field
|
|
43
|
+
for i, f in enumerate(fields):
|
|
44
|
+
# - если хоть один аргумент не является полем
|
|
45
|
+
if not isinstance(f, Field):
|
|
46
|
+
# -- то создаём текстовое описание ошибки
|
|
47
|
+
error = [
|
|
48
|
+
f"Аргумент fields[{i}] должен быть экземпляром dataclasses.Field, получено {type(f).__name__}",
|
|
49
|
+
f"Argument fields[{i}] must be an instance of dataclasses.Field, got {type(f).__name__}"
|
|
50
|
+
]
|
|
51
|
+
# -- и выбрасываем исключение
|
|
52
|
+
raise TypeError("\n".join(error))
|
|
53
|
+
|
|
54
|
+
# Собираем все метаданные из переданных полей
|
|
55
|
+
for f in fields:
|
|
56
|
+
if f.metadata:
|
|
57
|
+
metas.update(f.metadata)
|
|
58
|
+
|
|
59
|
+
return DataClassExtension.define(default, metas)
|
|
@@ -109,4 +109,29 @@ class TypeExtension:
|
|
|
109
109
|
inner_type = args[0] # Получаем T из list[T]
|
|
110
110
|
return TypeExtension.is_immutable_type(inner_type) # Проверяем T
|
|
111
111
|
|
|
112
|
-
return False
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def check_immutability (value: Any) -> bool:
|
|
116
|
+
"""
|
|
117
|
+
Проверяет, является ли значение `value` неизменяемым по типу.
|
|
118
|
+
:param value: Проверяемое значение.
|
|
119
|
+
:return: True, если тип значения неизменяемый, иначе False.
|
|
120
|
+
"""
|
|
121
|
+
# None — неизменяемый
|
|
122
|
+
if value is None:
|
|
123
|
+
return True
|
|
124
|
+
|
|
125
|
+
# Получаем фактический тип значения
|
|
126
|
+
value_type = type(value)
|
|
127
|
+
|
|
128
|
+
# Используем get_origin/get_args для анализа
|
|
129
|
+
origin = get_origin(value_type)
|
|
130
|
+
|
|
131
|
+
# Если это параметризованный тип (list[int], Union[str, int] и т.п.),
|
|
132
|
+
if origin is not None:
|
|
133
|
+
# - передаём сам параметризованный тип в is_immutable_type
|
|
134
|
+
return TypeExtension.is_immutable_type(origin)
|
|
135
|
+
else:
|
|
136
|
+
# - иначе проверяем тип напрямую (для простых типов, таких как int, str и т.п.)
|
|
137
|
+
return TypeExtension.is_immutable_type(value_type)
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anb_python_components
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Набор компонентов Python, которые упрощают разработку / A set of Python components that simplify development
|
|
5
5
|
Home-page: https://gitflic.ru/project/babaev-an/anb-python-components
|
|
6
6
|
Author: Александр Бабаев
|
|
@@ -19,6 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
19
19
|
Requires-Python: >=3.14.0
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
+
Requires-Dist: setuptools>=80.9.0
|
|
22
23
|
Dynamic: author
|
|
23
24
|
Dynamic: author-email
|
|
24
25
|
Dynamic: classifier
|
|
@@ -28,6 +29,7 @@ Dynamic: home-page
|
|
|
28
29
|
Dynamic: keywords
|
|
29
30
|
Dynamic: license-file
|
|
30
31
|
Dynamic: project-url
|
|
32
|
+
Dynamic: requires-dist
|
|
31
33
|
Dynamic: requires-python
|
|
32
34
|
Dynamic: summary
|
|
33
35
|
|
|
@@ -6,9 +6,11 @@ anb_python_components.egg-info/PKG-INFO
|
|
|
6
6
|
anb_python_components.egg-info/SOURCES.txt
|
|
7
7
|
anb_python_components.egg-info/dependency_links.txt
|
|
8
8
|
anb_python_components.egg-info/not-zip-safe
|
|
9
|
+
anb_python_components.egg-info/requires.txt
|
|
9
10
|
anb_python_components.egg-info/top_level.txt
|
|
10
11
|
anb_python_components/classes/__init__.py
|
|
11
12
|
anb_python_components/classes/action_state.py
|
|
13
|
+
anb_python_components/classes/dataclass_analyzer.py
|
|
12
14
|
anb_python_components/classes/directory.py
|
|
13
15
|
anb_python_components/classes/file.py
|
|
14
16
|
anb_python_components/classes/interface.py
|
|
@@ -30,6 +32,7 @@ anb_python_components/exceptions/wrong_type_exception.py
|
|
|
30
32
|
anb_python_components/extensions/__init__.py
|
|
31
33
|
anb_python_components/extensions/array_extension.py
|
|
32
34
|
anb_python_components/extensions/bool_extension.py
|
|
35
|
+
anb_python_components/extensions/dataclass_extension.py
|
|
33
36
|
anb_python_components/extensions/string_extension.py
|
|
34
37
|
anb_python_components/extensions/string_extension_constant.py
|
|
35
38
|
anb_python_components/extensions/type_extension.py
|
|
@@ -39,6 +42,7 @@ anb_python_components/models/shortcode_model.py
|
|
|
39
42
|
tests/__init__.py
|
|
40
43
|
tests/classes/__init__.py
|
|
41
44
|
tests/classes/action_state_test.py
|
|
45
|
+
tests/classes/dataclass_analyzer_test.py
|
|
42
46
|
tests/classes/directory_test.py
|
|
43
47
|
tests/classes/file_test.py
|
|
44
48
|
tests/classes/interface_test.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
setuptools>=80.9.0
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from os import path
|
|
2
|
+
|
|
3
|
+
from setuptools import find_packages, setup
|
|
4
|
+
|
|
5
|
+
# Получаем текущую директорию
|
|
6
|
+
this_directory = path.abspath(path.dirname(__file__))
|
|
7
|
+
|
|
8
|
+
# Функция для чтения requirements.txt
|
|
9
|
+
def read_requirements () -> list[str]:
|
|
10
|
+
"""
|
|
11
|
+
Читает файл requirements.txt и возвращает список зависимостей.
|
|
12
|
+
:return: Список зависимостей.
|
|
13
|
+
"""
|
|
14
|
+
# Путь к файлу requirements.txt в текущей директории
|
|
15
|
+
requirements_path = path.join(this_directory, 'requirements.txt')
|
|
16
|
+
|
|
17
|
+
# Проверяем, существует ли файл requirements.txt
|
|
18
|
+
if not path.exists(requirements_path):
|
|
19
|
+
# - если нет, возвращаем пустой список
|
|
20
|
+
return []
|
|
21
|
+
|
|
22
|
+
# Читаем файл requirements.txt
|
|
23
|
+
with open(requirements_path, encoding = 'utf-8') as f:
|
|
24
|
+
# - возвращаем список зависимостей, предварительно убрав пустые строки и комментарии
|
|
25
|
+
lines = [line.strip() for line in f if line.strip() and not line.startswith('#')]
|
|
26
|
+
|
|
27
|
+
# Возвращаем список зависимостей
|
|
28
|
+
return lines
|
|
29
|
+
|
|
30
|
+
def read_readme () -> str:
|
|
31
|
+
"""
|
|
32
|
+
Получает содержимое файла README.md и возвращает его в виде строки.
|
|
33
|
+
:return: Содержимое файла README.md.
|
|
34
|
+
"""
|
|
35
|
+
# Задаём переменную для хранения содержимого файла README.md
|
|
36
|
+
readme_content = ''
|
|
37
|
+
|
|
38
|
+
# Открываем файл README.md
|
|
39
|
+
with open(path.join(this_directory, 'README.md'), encoding = 'utf-8') as f:
|
|
40
|
+
# - и читаем его содержимое
|
|
41
|
+
readme_content = f.read()
|
|
42
|
+
|
|
43
|
+
# Возвращаем содержимое файла README.md
|
|
44
|
+
return readme_content
|
|
45
|
+
|
|
46
|
+
setup(
|
|
47
|
+
name = 'anb_python_components',
|
|
48
|
+
version = '1.4.0',
|
|
49
|
+
description = 'Набор компонентов Python, которые упрощают разработку / A set of Python components that simplify development',
|
|
50
|
+
long_description = read_readme(),
|
|
51
|
+
long_description_content_type = 'text/markdown',
|
|
52
|
+
author = 'Александр Бабаев',
|
|
53
|
+
author_email = 'contact_with_us@babaev-an.ru',
|
|
54
|
+
url = 'https://gitflic.ru/project/babaev-an/anb-python-components',
|
|
55
|
+
packages = find_packages(),
|
|
56
|
+
install_requires = read_requirements(),
|
|
57
|
+
python_requires = '>=3.14.0',
|
|
58
|
+
classifiers = [
|
|
59
|
+
'Development Status :: 5 - Production/Stable',
|
|
60
|
+
'Intended Audience :: Developers',
|
|
61
|
+
'License :: OSI Approved :: MIT License',
|
|
62
|
+
'Programming Language :: Python :: 3',
|
|
63
|
+
'Programming Language :: Python :: 3.14',
|
|
64
|
+
'Operating System :: OS Independent',
|
|
65
|
+
'Topic :: Software Development :: Libraries :: Python Modules',
|
|
66
|
+
],
|
|
67
|
+
keywords = 'python components development utils',
|
|
68
|
+
project_urls = {
|
|
69
|
+
'Documentation': 'https://gitflic.ru/project/babaev-an/anb-python-components/wiki',
|
|
70
|
+
'Source': 'https://gitflic.ru/project/babaev-an/anb-python-components',
|
|
71
|
+
'Tracker': 'https://gitflic.ru/project/babaev-an/anb-python-components/issue?page=0',
|
|
72
|
+
},
|
|
73
|
+
zip_safe = False,
|
|
74
|
+
)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# tests/dataclass_analyzer_test.py
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
from dataclasses import dataclass, is_dataclass
|
|
5
|
+
|
|
6
|
+
from anb_python_components import DataClassExtension, DataclassAnalyzer
|
|
7
|
+
|
|
8
|
+
class Fields:
|
|
9
|
+
@staticmethod
|
|
10
|
+
def primary_key (default = None):
|
|
11
|
+
return DataClassExtension.define(default, metadata = {'db_primary_key': True})
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def unique (default = None):
|
|
15
|
+
return DataClassExtension.define(default, metadata = {'db_unique': True})
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def indexed (default = None):
|
|
19
|
+
return DataClassExtension.define(default, metadata = {'db_indexed': True})
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def compose (default, *fields):
|
|
23
|
+
return DataClassExtension.defines(default, *fields)
|
|
24
|
+
|
|
25
|
+
def table_name (name: str):
|
|
26
|
+
"""
|
|
27
|
+
Декоратор для dataclass-класса, задающий имя таблицы в СУБД.
|
|
28
|
+
:param name: Имя таблицы.
|
|
29
|
+
:return: Обогащённый класс.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def decorator (cls):
|
|
33
|
+
if not is_dataclass(cls):
|
|
34
|
+
raise TypeError(f"Класс {cls.__name__} должен быть dataclass")
|
|
35
|
+
|
|
36
|
+
# Сохраняем имя таблицы как атрибут класса (начинается с __meta_)
|
|
37
|
+
cls.__meta_table_name = name
|
|
38
|
+
return cls
|
|
39
|
+
|
|
40
|
+
return decorator
|
|
41
|
+
|
|
42
|
+
@table_name("ANB")
|
|
43
|
+
@dataclass
|
|
44
|
+
class A:
|
|
45
|
+
a: int = Fields.primary_key(0)
|
|
46
|
+
b: str = Fields.compose("", Fields.unique(), Fields.indexed())
|
|
47
|
+
|
|
48
|
+
class DataclassAnalyzerTest(unittest.TestCase):
|
|
49
|
+
def test_analyze (self):
|
|
50
|
+
analyze_result = DataclassAnalyzer.analyze_class(A)
|
|
51
|
+
self.assertEqual("ANB", analyze_result["__CLASS__"]["table_name"])
|
|
52
|
+
self.assertTrue(analyze_result["a"]["db_primary_key"])
|
|
53
|
+
|
|
54
|
+
analyze_result = DataclassAnalyzer.analyze_properties(A, "a")
|
|
55
|
+
self.assertTrue(analyze_result["db_primary_key"])
|
|
56
|
+
|
|
57
|
+
analyze_result = DataclassAnalyzer.analyze_properties(A, "b")
|
|
58
|
+
self.assertTrue(analyze_result["db_unique"])
|
|
59
|
+
self.assertTrue(analyze_result["db_indexed"])
|
|
60
|
+
|
|
61
|
+
if __name__ == '__main__':
|
|
62
|
+
unittest.main()
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# anb_python_components/__init__.py
|
|
2
|
-
|
|
3
|
-
# classes
|
|
4
|
-
from anb_python_components.classes.action_state import ActionState
|
|
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
|
|
9
|
-
# custom_types
|
|
10
|
-
from anb_python_components.custom_types.guid import GUID
|
|
11
|
-
from anb_python_components.custom_types.object_array import ObjectArray
|
|
12
|
-
from anb_python_components.custom_types.shortcode_attributes import ShortCodeAttributes
|
|
13
|
-
from anb_python_components.custom_types.two_dim_size import TwoDimSize
|
|
14
|
-
from anb_python_components.custom_types.version_info import VersionInfo
|
|
15
|
-
# decorators
|
|
16
|
-
from anb_python_components.decorators.interface_decorators import implement, interface_required
|
|
17
|
-
# enums
|
|
18
|
-
from anb_python_components.enums.message_type import MessageType
|
|
19
|
-
from anb_python_components.enums.not_bool_action import NotBoolAction
|
|
20
|
-
from anb_python_components.enums.type_copy_strategy import TypeCopyStrategy
|
|
21
|
-
# exceptions
|
|
22
|
-
from anb_python_components.exceptions.wrong_type_exception import WrongTypeException
|
|
23
|
-
# extensions
|
|
24
|
-
from anb_python_components.extensions.array_extension import ArrayExtension
|
|
25
|
-
from anb_python_components.extensions.bool_extension import BoolExtension
|
|
26
|
-
from anb_python_components.extensions.string_extension import StringExtension
|
|
27
|
-
from anb_python_components.extensions.type_extension import TypeExtension
|
|
28
|
-
# models
|
|
29
|
-
from anb_python_components.models.action_state_message import ActionStateMessage
|
|
30
|
-
from anb_python_components.models.shortcode_model import ShortCodeModel
|
|
31
|
-
|
|
32
|
-
__all__ = [
|
|
33
|
-
'ActionState',
|
|
34
|
-
'Directory',
|
|
35
|
-
'File',
|
|
36
|
-
'Interface',
|
|
37
|
-
'ShortCodeParser',
|
|
38
|
-
'GUID',
|
|
39
|
-
'ObjectArray',
|
|
40
|
-
'ShortCodeAttributes',
|
|
41
|
-
'TwoDimSize',
|
|
42
|
-
'VersionInfo',
|
|
43
|
-
'interface_required',
|
|
44
|
-
'implement',
|
|
45
|
-
'MessageType',
|
|
46
|
-
'NotBoolAction',
|
|
47
|
-
'TypeCopyStrategy',
|
|
48
|
-
'WrongTypeException',
|
|
49
|
-
'ArrayExtension',
|
|
50
|
-
'BoolExtension',
|
|
51
|
-
'StringExtension',
|
|
52
|
-
"TypeExtension",
|
|
53
|
-
'ActionStateMessage',
|
|
54
|
-
'ShortCodeModel'
|
|
55
|
-
]
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
from os import path
|
|
2
|
-
|
|
3
|
-
from setuptools import find_packages, setup
|
|
4
|
-
|
|
5
|
-
# Получаем длинное описание из README.md
|
|
6
|
-
this_directory = path.abspath(path.dirname(__file__))
|
|
7
|
-
with open(path.join(this_directory, 'README.md'), encoding = 'utf-8') as f:
|
|
8
|
-
long_description = f.read()
|
|
9
|
-
|
|
10
|
-
setup(
|
|
11
|
-
name = 'anb_python_components',
|
|
12
|
-
version = '1.3.0',
|
|
13
|
-
description = 'Набор компонентов Python, которые упрощают разработку / A set of Python components that simplify development',
|
|
14
|
-
long_description = long_description,
|
|
15
|
-
long_description_content_type = 'text/markdown',
|
|
16
|
-
author = 'Александр Бабаев',
|
|
17
|
-
author_email = 'contact_with_us@babaev-an.ru',
|
|
18
|
-
url = 'https://gitflic.ru/project/babaev-an/anb-python-components',
|
|
19
|
-
packages = find_packages(),
|
|
20
|
-
install_requires = [],
|
|
21
|
-
python_requires = '>=3.14.0',
|
|
22
|
-
classifiers = [
|
|
23
|
-
'Development Status :: 5 - Production/Stable',
|
|
24
|
-
'Intended Audience :: Developers',
|
|
25
|
-
'License :: OSI Approved :: MIT License',
|
|
26
|
-
'Programming Language :: Python :: 3',
|
|
27
|
-
'Programming Language :: Python :: 3.14',
|
|
28
|
-
'Operating System :: OS Independent',
|
|
29
|
-
'Topic :: Software Development :: Libraries :: Python Modules',
|
|
30
|
-
],
|
|
31
|
-
keywords = 'python components development utils',
|
|
32
|
-
project_urls = {
|
|
33
|
-
'Documentation': 'https://gitflic.ru/project/babaev-an/anb-python-components/wiki',
|
|
34
|
-
'Source': 'https://gitflic.ru/project/babaev-an/anb-python-components',
|
|
35
|
-
'Tracker': 'https://gitflic.ru/project/babaev-an/anb-python-components/issue?page=0',
|
|
36
|
-
},
|
|
37
|
-
zip_safe = False,
|
|
38
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/classes/file.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/enums/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/anb_python_components/models/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/classes/action_state_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/classes/shortcode_parser_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/custom_types/object_array_test.py
RENAMED
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/custom_types/two_dim_size_test.py
RENAMED
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/custom_types/version_info_test.py
RENAMED
|
File without changes
|
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/extensions/array_extension_test.py
RENAMED
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/extensions/bool_extension_test.py
RENAMED
|
File without changes
|
|
File without changes
|
{anb_python_components-1.3.0 → anb_python_components-1.4.0}/tests/extensions/type_extension_test.py
RENAMED
|
File without changes
|