fishertools 0.2.1__py3-none-any.whl
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.
- fishertools/__init__.py +82 -0
- fishertools/config/__init__.py +24 -0
- fishertools/config/manager.py +247 -0
- fishertools/config/models.py +96 -0
- fishertools/config/parser.py +265 -0
- fishertools/decorators.py +93 -0
- fishertools/documentation/__init__.py +38 -0
- fishertools/documentation/api.py +242 -0
- fishertools/documentation/generator.py +502 -0
- fishertools/documentation/models.py +126 -0
- fishertools/documentation/visual.py +583 -0
- fishertools/errors/__init__.py +29 -0
- fishertools/errors/exceptions.py +191 -0
- fishertools/errors/explainer.py +303 -0
- fishertools/errors/formatters.py +386 -0
- fishertools/errors/models.py +228 -0
- fishertools/errors/patterns.py +119 -0
- fishertools/errors/recovery.py +467 -0
- fishertools/examples/__init__.py +22 -0
- fishertools/examples/models.py +118 -0
- fishertools/examples/repository.py +770 -0
- fishertools/helpers.py +116 -0
- fishertools/integration.py +451 -0
- fishertools/learn/__init__.py +18 -0
- fishertools/learn/examples.py +550 -0
- fishertools/learn/tips.py +281 -0
- fishertools/learning/__init__.py +32 -0
- fishertools/learning/core.py +349 -0
- fishertools/learning/models.py +112 -0
- fishertools/learning/progress.py +314 -0
- fishertools/learning/session.py +500 -0
- fishertools/learning/tutorial.py +626 -0
- fishertools/legacy/__init__.py +76 -0
- fishertools/legacy/deprecated.py +261 -0
- fishertools/legacy/deprecation.py +149 -0
- fishertools/safe/__init__.py +16 -0
- fishertools/safe/collections.py +242 -0
- fishertools/safe/files.py +240 -0
- fishertools/safe/strings.py +15 -0
- fishertools/utils.py +57 -0
- fishertools-0.2.1.dist-info/METADATA +256 -0
- fishertools-0.2.1.dist-info/RECORD +81 -0
- fishertools-0.2.1.dist-info/WHEEL +5 -0
- fishertools-0.2.1.dist-info/licenses/LICENSE +21 -0
- fishertools-0.2.1.dist-info/top_level.txt +2 -0
- tests/__init__.py +6 -0
- tests/conftest.py +25 -0
- tests/test_config/__init__.py +3 -0
- tests/test_config/test_basic_config.py +57 -0
- tests/test_config/test_config_error_handling.py +287 -0
- tests/test_config/test_config_properties.py +435 -0
- tests/test_documentation/__init__.py +3 -0
- tests/test_documentation/test_documentation_properties.py +253 -0
- tests/test_documentation/test_visual_documentation_properties.py +444 -0
- tests/test_errors/__init__.py +3 -0
- tests/test_errors/test_api.py +301 -0
- tests/test_errors/test_error_handling.py +354 -0
- tests/test_errors/test_explainer.py +173 -0
- tests/test_errors/test_formatters.py +338 -0
- tests/test_errors/test_models.py +248 -0
- tests/test_errors/test_patterns.py +270 -0
- tests/test_examples/__init__.py +3 -0
- tests/test_examples/test_example_repository_properties.py +204 -0
- tests/test_examples/test_specific_examples.py +303 -0
- tests/test_integration.py +298 -0
- tests/test_integration_enhancements.py +462 -0
- tests/test_learn/__init__.py +3 -0
- tests/test_learn/test_examples.py +221 -0
- tests/test_learn/test_tips.py +285 -0
- tests/test_learning/__init__.py +3 -0
- tests/test_learning/test_interactive_learning_properties.py +337 -0
- tests/test_learning/test_learning_system_properties.py +194 -0
- tests/test_learning/test_progress_tracking_properties.py +279 -0
- tests/test_legacy/__init__.py +3 -0
- tests/test_legacy/test_backward_compatibility.py +236 -0
- tests/test_legacy/test_deprecation_warnings.py +208 -0
- tests/test_safe/__init__.py +3 -0
- tests/test_safe/test_collections_properties.py +189 -0
- tests/test_safe/test_files.py +104 -0
- tests/test_structure.py +58 -0
- tests/test_structure_enhancements.py +115 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Legacy module for backward compatibility
|
|
3
|
+
|
|
4
|
+
This module contains functions from the original fishertools library that align
|
|
5
|
+
with the new mission of making Python more convenient and safer for beginners.
|
|
6
|
+
All functions maintain identical behavior for backward compatibility.
|
|
7
|
+
|
|
8
|
+
It also includes deprecated functions with clear migration guidance.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
# Import deprecation system
|
|
12
|
+
from .deprecation import (
|
|
13
|
+
deprecated,
|
|
14
|
+
show_deprecation_info,
|
|
15
|
+
list_deprecated_functions,
|
|
16
|
+
# Example deprecated functions for demonstration
|
|
17
|
+
unsafe_file_reader,
|
|
18
|
+
risky_divide,
|
|
19
|
+
complex_list_operation,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
# Import retained functions that align with beginner-friendly mission
|
|
23
|
+
from .deprecated import (
|
|
24
|
+
# File and directory utilities - helpful for beginners
|
|
25
|
+
read_json,
|
|
26
|
+
write_json,
|
|
27
|
+
ensure_dir,
|
|
28
|
+
get_file_size,
|
|
29
|
+
list_files,
|
|
30
|
+
|
|
31
|
+
# String utilities - common beginner needs
|
|
32
|
+
clean_string,
|
|
33
|
+
validate_email,
|
|
34
|
+
|
|
35
|
+
# Data utilities - safe operations for beginners
|
|
36
|
+
chunk_list,
|
|
37
|
+
merge_dicts,
|
|
38
|
+
flatten_dict,
|
|
39
|
+
|
|
40
|
+
# Configuration helper - simplified config management
|
|
41
|
+
QuickConfig,
|
|
42
|
+
|
|
43
|
+
# Simple logging - educational and beginner-friendly
|
|
44
|
+
SimpleLogger,
|
|
45
|
+
|
|
46
|
+
# Decorators that help beginners understand code behavior
|
|
47
|
+
timer,
|
|
48
|
+
debug,
|
|
49
|
+
retry,
|
|
50
|
+
cache_result,
|
|
51
|
+
validate_types,
|
|
52
|
+
|
|
53
|
+
# Utility functions
|
|
54
|
+
timestamp,
|
|
55
|
+
generate_password,
|
|
56
|
+
hash_string,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
__all__ = [
|
|
60
|
+
# Deprecation system
|
|
61
|
+
'deprecated', 'show_deprecation_info', 'list_deprecated_functions',
|
|
62
|
+
# Example deprecated functions
|
|
63
|
+
'unsafe_file_reader', 'risky_divide', 'complex_list_operation',
|
|
64
|
+
# File operations
|
|
65
|
+
'read_json', 'write_json', 'ensure_dir', 'get_file_size', 'list_files',
|
|
66
|
+
# String operations
|
|
67
|
+
'clean_string', 'validate_email',
|
|
68
|
+
# Data operations
|
|
69
|
+
'chunk_list', 'merge_dicts', 'flatten_dict',
|
|
70
|
+
# Helper classes
|
|
71
|
+
'QuickConfig', 'SimpleLogger',
|
|
72
|
+
# Decorators
|
|
73
|
+
'timer', 'debug', 'retry', 'cache_result', 'validate_types',
|
|
74
|
+
# Utilities
|
|
75
|
+
'timestamp', 'generate_password', 'hash_string',
|
|
76
|
+
]
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deprecated functions from original fishertools library
|
|
3
|
+
|
|
4
|
+
These functions are retained for backward compatibility and align with the new
|
|
5
|
+
mission of making Python more convenient and safer for beginners. All functions
|
|
6
|
+
maintain identical behavior to the original implementation.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import time
|
|
12
|
+
import re
|
|
13
|
+
import hashlib
|
|
14
|
+
import random
|
|
15
|
+
import string
|
|
16
|
+
import functools
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any, Dict, List, Optional, Callable
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# File and directory utilities - helpful for beginners
|
|
22
|
+
def read_json(filepath: str) -> Dict[str, Any]:
|
|
23
|
+
"""Читает JSON файл и возвращает словарь"""
|
|
24
|
+
with open(filepath, 'r', encoding='utf-8') as f:
|
|
25
|
+
return json.load(f)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def write_json(data: Dict[str, Any], filepath: str, indent: int = 2) -> None:
|
|
29
|
+
"""Записывает данные в JSON файл"""
|
|
30
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
31
|
+
json.dump(data, f, ensure_ascii=False, indent=indent)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def ensure_dir(path: str) -> None:
|
|
35
|
+
"""Создает директорию если она не существует"""
|
|
36
|
+
Path(path).mkdir(parents=True, exist_ok=True)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_file_size(filepath: str) -> int:
|
|
40
|
+
"""Возвращает размер файла в байтах"""
|
|
41
|
+
return os.path.getsize(filepath)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def list_files(directory: str, extension: Optional[str] = None) -> List[str]:
|
|
45
|
+
"""Возвращает список файлов в директории с опциональной фильтрацией по расширению"""
|
|
46
|
+
path = Path(directory)
|
|
47
|
+
if extension:
|
|
48
|
+
pattern = f"*.{extension.lstrip('.')}"
|
|
49
|
+
return [str(f) for f in path.glob(pattern)]
|
|
50
|
+
return [str(f) for f in path.iterdir() if f.is_file()]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def timestamp() -> str:
|
|
54
|
+
"""Возвращает текущую временную метку в читаемом формате"""
|
|
55
|
+
return time.strftime("%Y-%m-%d %H:%M:%S")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def flatten_dict(d: Dict[str, Any], parent_key: str = '', sep: str = '.') -> Dict[str, Any]:
|
|
59
|
+
"""Превращает вложенный словарь в плоский"""
|
|
60
|
+
items = []
|
|
61
|
+
for k, v in d.items():
|
|
62
|
+
new_key = f"{parent_key}{sep}{k}" if parent_key else k
|
|
63
|
+
if isinstance(v, dict):
|
|
64
|
+
items.extend(flatten_dict(v, new_key, sep=sep).items())
|
|
65
|
+
else:
|
|
66
|
+
items.append((new_key, v))
|
|
67
|
+
return dict(items)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# String utilities - common beginner needs
|
|
71
|
+
def validate_email(email: str) -> bool:
|
|
72
|
+
"""Проверяет корректность email адреса"""
|
|
73
|
+
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
|
74
|
+
return bool(re.match(pattern, email))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def clean_string(text: str) -> str:
|
|
78
|
+
"""Очищает строку от лишних пробелов и символов"""
|
|
79
|
+
# Убираем лишние пробелы
|
|
80
|
+
text = re.sub(r'\s+', ' ', text.strip())
|
|
81
|
+
# Убираем специальные символы (оставляем только буквы, цифры, пробелы и основную пунктуацию)
|
|
82
|
+
text = re.sub(r'[^\w\s.,!?-]', '', text)
|
|
83
|
+
return text
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# Data utilities - safe operations for beginners
|
|
87
|
+
def chunk_list(lst: List[Any], chunk_size: int) -> List[List[Any]]:
|
|
88
|
+
"""Разбивает список на части заданного размера"""
|
|
89
|
+
return [lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size)]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def merge_dicts(*dicts: Dict[str, Any]) -> Dict[str, Any]:
|
|
93
|
+
"""Объединяет несколько словарей в один"""
|
|
94
|
+
result = {}
|
|
95
|
+
for d in dicts:
|
|
96
|
+
result.update(d)
|
|
97
|
+
return result
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# Security utilities - helpful for beginners
|
|
101
|
+
def generate_password(length: int = 12, include_symbols: bool = True) -> str:
|
|
102
|
+
"""Генерирует случайный пароль"""
|
|
103
|
+
chars = string.ascii_letters + string.digits
|
|
104
|
+
if include_symbols:
|
|
105
|
+
chars += "!@#$%^&*"
|
|
106
|
+
|
|
107
|
+
return ''.join(random.choice(chars) for _ in range(length))
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def hash_string(text: str, algorithm: str = 'sha256') -> str:
|
|
111
|
+
"""Хеширует строку указанным алгоритмом"""
|
|
112
|
+
hash_obj = hashlib.new(algorithm)
|
|
113
|
+
hash_obj.update(text.encode('utf-8'))
|
|
114
|
+
return hash_obj.hexdigest()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# Helper classes - simplified for beginners
|
|
118
|
+
class QuickConfig:
|
|
119
|
+
"""Простой класс для работы с конфигурацией"""
|
|
120
|
+
|
|
121
|
+
def __init__(self, config_dict: Optional[Dict[str, Any]] = None):
|
|
122
|
+
self._config = config_dict or {}
|
|
123
|
+
|
|
124
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
125
|
+
"""Получить значение по ключу с поддержкой точечной нотации"""
|
|
126
|
+
keys = key.split('.')
|
|
127
|
+
value = self._config
|
|
128
|
+
|
|
129
|
+
for k in keys:
|
|
130
|
+
if isinstance(value, dict) and k in value:
|
|
131
|
+
value = value[k]
|
|
132
|
+
else:
|
|
133
|
+
return default
|
|
134
|
+
|
|
135
|
+
return value
|
|
136
|
+
|
|
137
|
+
def set(self, key: str, value: Any) -> None:
|
|
138
|
+
"""Установить значение по ключу с поддержкой точечной нотации"""
|
|
139
|
+
keys = key.split('.')
|
|
140
|
+
config = self._config
|
|
141
|
+
|
|
142
|
+
for k in keys[:-1]:
|
|
143
|
+
if k not in config:
|
|
144
|
+
config[k] = {}
|
|
145
|
+
config = config[k]
|
|
146
|
+
|
|
147
|
+
config[keys[-1]] = value
|
|
148
|
+
|
|
149
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
150
|
+
"""Вернуть конфигурацию как словарь"""
|
|
151
|
+
return self._config.copy()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class SimpleLogger:
|
|
155
|
+
"""Простой логгер для быстрой отладки"""
|
|
156
|
+
|
|
157
|
+
def __init__(self, name: str = "MyDevTools"):
|
|
158
|
+
self.name = name
|
|
159
|
+
|
|
160
|
+
def info(self, message: str) -> None:
|
|
161
|
+
"""Информационное сообщение"""
|
|
162
|
+
print(f"[{self.name}] INFO: {message}")
|
|
163
|
+
|
|
164
|
+
def warning(self, message: str) -> None:
|
|
165
|
+
"""Предупреждение"""
|
|
166
|
+
print(f"[{self.name}] WARNING: {message}")
|
|
167
|
+
|
|
168
|
+
def error(self, message: str) -> None:
|
|
169
|
+
"""Ошибка"""
|
|
170
|
+
print(f"[{self.name}] ERROR: {message}")
|
|
171
|
+
|
|
172
|
+
def debug(self, message: str) -> None:
|
|
173
|
+
"""Отладочное сообщение"""
|
|
174
|
+
print(f"[{self.name}] DEBUG: {message}")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# Educational decorators - help beginners understand code behavior
|
|
178
|
+
def timer(func: Callable) -> Callable:
|
|
179
|
+
"""Декоратор для измерения времени выполнения функции"""
|
|
180
|
+
@functools.wraps(func)
|
|
181
|
+
def wrapper(*args, **kwargs):
|
|
182
|
+
start_time = time.time()
|
|
183
|
+
result = func(*args, **kwargs)
|
|
184
|
+
end_time = time.time()
|
|
185
|
+
print(f"{func.__name__} выполнилась за {end_time - start_time:.4f} секунд")
|
|
186
|
+
return result
|
|
187
|
+
return wrapper
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def debug(func: Callable) -> Callable:
|
|
191
|
+
"""Декоратор для отладки - выводит аргументы и результат функции"""
|
|
192
|
+
@functools.wraps(func)
|
|
193
|
+
def wrapper(*args, **kwargs):
|
|
194
|
+
print(f"Вызов {func.__name__} с аргументами: args={args}, kwargs={kwargs}")
|
|
195
|
+
result = func(*args, **kwargs)
|
|
196
|
+
print(f"{func.__name__} вернула: {result}")
|
|
197
|
+
return result
|
|
198
|
+
return wrapper
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def retry(max_attempts: int = 3, delay: float = 1.0):
|
|
202
|
+
"""Декоратор для повторных попыток выполнения функции при ошибке"""
|
|
203
|
+
def decorator(func: Callable) -> Callable:
|
|
204
|
+
@functools.wraps(func)
|
|
205
|
+
def wrapper(*args, **kwargs):
|
|
206
|
+
for attempt in range(max_attempts):
|
|
207
|
+
try:
|
|
208
|
+
return func(*args, **kwargs)
|
|
209
|
+
except Exception as e:
|
|
210
|
+
if attempt == max_attempts - 1:
|
|
211
|
+
raise e
|
|
212
|
+
print(f"Попытка {attempt + 1} не удалась: {e}. Повтор через {delay} сек...")
|
|
213
|
+
time.sleep(delay)
|
|
214
|
+
return wrapper
|
|
215
|
+
return decorator
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def cache_result(func: Callable) -> Callable:
|
|
219
|
+
"""Простой декоратор для кеширования результатов функции"""
|
|
220
|
+
cache = {}
|
|
221
|
+
|
|
222
|
+
@functools.wraps(func)
|
|
223
|
+
def wrapper(*args, **kwargs):
|
|
224
|
+
# Создаем ключ из аргументов
|
|
225
|
+
key = str(args) + str(sorted(kwargs.items()))
|
|
226
|
+
|
|
227
|
+
if key in cache:
|
|
228
|
+
print(f"Результат {func.__name__} взят из кеша")
|
|
229
|
+
return cache[key]
|
|
230
|
+
|
|
231
|
+
result = func(*args, **kwargs)
|
|
232
|
+
cache[key] = result
|
|
233
|
+
return result
|
|
234
|
+
|
|
235
|
+
return wrapper
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def validate_types(**expected_types):
|
|
239
|
+
"""Декоратор для проверки типов аргументов функции"""
|
|
240
|
+
def decorator(func: Callable) -> Callable:
|
|
241
|
+
@functools.wraps(func)
|
|
242
|
+
def wrapper(*args, **kwargs):
|
|
243
|
+
# Получаем имена параметров функции
|
|
244
|
+
import inspect
|
|
245
|
+
sig = inspect.signature(func)
|
|
246
|
+
bound_args = sig.bind(*args, **kwargs)
|
|
247
|
+
bound_args.apply_defaults()
|
|
248
|
+
|
|
249
|
+
# Проверяем типы
|
|
250
|
+
for param_name, expected_type in expected_types.items():
|
|
251
|
+
if param_name in bound_args.arguments:
|
|
252
|
+
value = bound_args.arguments[param_name]
|
|
253
|
+
if not isinstance(value, expected_type):
|
|
254
|
+
raise TypeError(
|
|
255
|
+
f"Параметр '{param_name}' должен быть типа {expected_type.__name__}, "
|
|
256
|
+
f"получен {type(value).__name__}"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
return func(*args, **kwargs)
|
|
260
|
+
return wrapper
|
|
261
|
+
return decorator
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Deprecation warning system for fishertools
|
|
3
|
+
|
|
4
|
+
This module provides utilities for managing deprecation warnings and
|
|
5
|
+
migration guidance for functions being removed from the library.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import warnings
|
|
9
|
+
import functools
|
|
10
|
+
from typing import Callable, Optional
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def deprecated(
|
|
14
|
+
reason: str = "This function is deprecated",
|
|
15
|
+
alternative: Optional[str] = None,
|
|
16
|
+
removal_version: Optional[str] = None
|
|
17
|
+
) -> Callable:
|
|
18
|
+
"""
|
|
19
|
+
Decorator to mark functions as deprecated with clear migration guidance.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
reason: Explanation of why the function is deprecated
|
|
23
|
+
alternative: Suggested replacement function or approach
|
|
24
|
+
removal_version: Version when the function will be removed
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Decorated function that issues deprecation warning when called
|
|
28
|
+
"""
|
|
29
|
+
def decorator(func: Callable) -> Callable:
|
|
30
|
+
@functools.wraps(func)
|
|
31
|
+
def wrapper(*args, **kwargs):
|
|
32
|
+
# Build comprehensive warning message
|
|
33
|
+
message_parts = [
|
|
34
|
+
f"Функция '{func.__name__}' устарела.",
|
|
35
|
+
reason
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
if alternative:
|
|
39
|
+
message_parts.append(f"Используйте вместо неё: {alternative}")
|
|
40
|
+
|
|
41
|
+
if removal_version:
|
|
42
|
+
message_parts.append(f"Будет удалена в версии {removal_version}")
|
|
43
|
+
|
|
44
|
+
message_parts.append("Подробности миграции: https://github.com/f1sherFM/fishertools/wiki/migration")
|
|
45
|
+
|
|
46
|
+
warning_message = " ".join(message_parts)
|
|
47
|
+
|
|
48
|
+
# Issue deprecation warning
|
|
49
|
+
warnings.warn(
|
|
50
|
+
warning_message,
|
|
51
|
+
DeprecationWarning,
|
|
52
|
+
stacklevel=2
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Execute original function
|
|
56
|
+
return func(*args, **kwargs)
|
|
57
|
+
|
|
58
|
+
# Mark function as deprecated for introspection
|
|
59
|
+
wrapper._is_deprecated = True
|
|
60
|
+
wrapper._deprecation_info = {
|
|
61
|
+
'reason': reason,
|
|
62
|
+
'alternative': alternative,
|
|
63
|
+
'removal_version': removal_version
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return wrapper
|
|
67
|
+
return decorator
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def show_deprecation_info(func: Callable) -> dict:
|
|
71
|
+
"""
|
|
72
|
+
Get deprecation information for a function.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
func: Function to check for deprecation info
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Dictionary with deprecation details or empty dict if not deprecated
|
|
79
|
+
"""
|
|
80
|
+
if hasattr(func, '_is_deprecated') and func._is_deprecated:
|
|
81
|
+
return func._deprecation_info.copy()
|
|
82
|
+
return {}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def list_deprecated_functions(module) -> list:
|
|
86
|
+
"""
|
|
87
|
+
List all deprecated functions in a module.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
module: Module to scan for deprecated functions
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
List of deprecated function names
|
|
94
|
+
"""
|
|
95
|
+
deprecated_funcs = []
|
|
96
|
+
|
|
97
|
+
for name in dir(module):
|
|
98
|
+
obj = getattr(module, name)
|
|
99
|
+
if callable(obj) and hasattr(obj, '_is_deprecated') and obj._is_deprecated:
|
|
100
|
+
deprecated_funcs.append(name)
|
|
101
|
+
|
|
102
|
+
return deprecated_funcs
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# Example deprecated functions for demonstration
|
|
106
|
+
@deprecated(
|
|
107
|
+
reason="Эта функция не соответствует новой миссии библиотеки",
|
|
108
|
+
alternative="fishertools.safe.safe_read_file()",
|
|
109
|
+
removal_version="1.0.0"
|
|
110
|
+
)
|
|
111
|
+
def unsafe_file_reader(filepath: str) -> str:
|
|
112
|
+
"""
|
|
113
|
+
DEPRECATED: Небезопасное чтение файла без обработки ошибок
|
|
114
|
+
|
|
115
|
+
Эта функция устарела и будет удалена в версии 1.0.0.
|
|
116
|
+
Используйте вместо неё fishertools.safe.safe_read_file()
|
|
117
|
+
"""
|
|
118
|
+
with open(filepath, 'r') as f:
|
|
119
|
+
return f.read()
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@deprecated(
|
|
123
|
+
reason="Функция может вызывать ошибки у новичков",
|
|
124
|
+
alternative="fishertools.safe.safe_divide()",
|
|
125
|
+
removal_version="1.0.0"
|
|
126
|
+
)
|
|
127
|
+
def risky_divide(a: float, b: float) -> float:
|
|
128
|
+
"""
|
|
129
|
+
DEPRECATED: Деление без проверки на ноль
|
|
130
|
+
|
|
131
|
+
Эта функция устарела и будет удалена в версии 1.0.0.
|
|
132
|
+
Используйте вместо неё fishertools.safe.safe_divide()
|
|
133
|
+
"""
|
|
134
|
+
return a / b
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@deprecated(
|
|
138
|
+
reason="Слишком сложная для новичков",
|
|
139
|
+
alternative="Используйте стандартные методы списков",
|
|
140
|
+
removal_version="1.0.0"
|
|
141
|
+
)
|
|
142
|
+
def complex_list_operation(lst: list) -> list:
|
|
143
|
+
"""
|
|
144
|
+
DEPRECATED: Сложная операция со списком
|
|
145
|
+
|
|
146
|
+
Эта функция устарела и будет удалена в версии 1.0.0.
|
|
147
|
+
Используйте стандартные методы списков для простоты.
|
|
148
|
+
"""
|
|
149
|
+
return [x for i, x in enumerate(lst) if i % 2 == 0 and x is not None]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Safe utilities module for fishertools.
|
|
3
|
+
|
|
4
|
+
This module provides beginner-friendly versions of common operations
|
|
5
|
+
that prevent typical mistakes and provide helpful error messages.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .collections import safe_get, safe_divide, safe_max, safe_min, safe_sum
|
|
9
|
+
from .files import safe_read_file, safe_write_file, safe_file_exists, safe_get_file_size, safe_list_files
|
|
10
|
+
from .strings import safe_string_operations
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"safe_get", "safe_divide", "safe_max", "safe_min", "safe_sum",
|
|
14
|
+
"safe_read_file", "safe_write_file", "safe_file_exists", "safe_get_file_size", "safe_list_files",
|
|
15
|
+
"safe_string_operations"
|
|
16
|
+
]
|