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.
Files changed (81) hide show
  1. fishertools/__init__.py +82 -0
  2. fishertools/config/__init__.py +24 -0
  3. fishertools/config/manager.py +247 -0
  4. fishertools/config/models.py +96 -0
  5. fishertools/config/parser.py +265 -0
  6. fishertools/decorators.py +93 -0
  7. fishertools/documentation/__init__.py +38 -0
  8. fishertools/documentation/api.py +242 -0
  9. fishertools/documentation/generator.py +502 -0
  10. fishertools/documentation/models.py +126 -0
  11. fishertools/documentation/visual.py +583 -0
  12. fishertools/errors/__init__.py +29 -0
  13. fishertools/errors/exceptions.py +191 -0
  14. fishertools/errors/explainer.py +303 -0
  15. fishertools/errors/formatters.py +386 -0
  16. fishertools/errors/models.py +228 -0
  17. fishertools/errors/patterns.py +119 -0
  18. fishertools/errors/recovery.py +467 -0
  19. fishertools/examples/__init__.py +22 -0
  20. fishertools/examples/models.py +118 -0
  21. fishertools/examples/repository.py +770 -0
  22. fishertools/helpers.py +116 -0
  23. fishertools/integration.py +451 -0
  24. fishertools/learn/__init__.py +18 -0
  25. fishertools/learn/examples.py +550 -0
  26. fishertools/learn/tips.py +281 -0
  27. fishertools/learning/__init__.py +32 -0
  28. fishertools/learning/core.py +349 -0
  29. fishertools/learning/models.py +112 -0
  30. fishertools/learning/progress.py +314 -0
  31. fishertools/learning/session.py +500 -0
  32. fishertools/learning/tutorial.py +626 -0
  33. fishertools/legacy/__init__.py +76 -0
  34. fishertools/legacy/deprecated.py +261 -0
  35. fishertools/legacy/deprecation.py +149 -0
  36. fishertools/safe/__init__.py +16 -0
  37. fishertools/safe/collections.py +242 -0
  38. fishertools/safe/files.py +240 -0
  39. fishertools/safe/strings.py +15 -0
  40. fishertools/utils.py +57 -0
  41. fishertools-0.2.1.dist-info/METADATA +256 -0
  42. fishertools-0.2.1.dist-info/RECORD +81 -0
  43. fishertools-0.2.1.dist-info/WHEEL +5 -0
  44. fishertools-0.2.1.dist-info/licenses/LICENSE +21 -0
  45. fishertools-0.2.1.dist-info/top_level.txt +2 -0
  46. tests/__init__.py +6 -0
  47. tests/conftest.py +25 -0
  48. tests/test_config/__init__.py +3 -0
  49. tests/test_config/test_basic_config.py +57 -0
  50. tests/test_config/test_config_error_handling.py +287 -0
  51. tests/test_config/test_config_properties.py +435 -0
  52. tests/test_documentation/__init__.py +3 -0
  53. tests/test_documentation/test_documentation_properties.py +253 -0
  54. tests/test_documentation/test_visual_documentation_properties.py +444 -0
  55. tests/test_errors/__init__.py +3 -0
  56. tests/test_errors/test_api.py +301 -0
  57. tests/test_errors/test_error_handling.py +354 -0
  58. tests/test_errors/test_explainer.py +173 -0
  59. tests/test_errors/test_formatters.py +338 -0
  60. tests/test_errors/test_models.py +248 -0
  61. tests/test_errors/test_patterns.py +270 -0
  62. tests/test_examples/__init__.py +3 -0
  63. tests/test_examples/test_example_repository_properties.py +204 -0
  64. tests/test_examples/test_specific_examples.py +303 -0
  65. tests/test_integration.py +298 -0
  66. tests/test_integration_enhancements.py +462 -0
  67. tests/test_learn/__init__.py +3 -0
  68. tests/test_learn/test_examples.py +221 -0
  69. tests/test_learn/test_tips.py +285 -0
  70. tests/test_learning/__init__.py +3 -0
  71. tests/test_learning/test_interactive_learning_properties.py +337 -0
  72. tests/test_learning/test_learning_system_properties.py +194 -0
  73. tests/test_learning/test_progress_tracking_properties.py +279 -0
  74. tests/test_legacy/__init__.py +3 -0
  75. tests/test_legacy/test_backward_compatibility.py +236 -0
  76. tests/test_legacy/test_deprecation_warnings.py +208 -0
  77. tests/test_safe/__init__.py +3 -0
  78. tests/test_safe/test_collections_properties.py +189 -0
  79. tests/test_safe/test_files.py +104 -0
  80. tests/test_structure.py +58 -0
  81. tests/test_structure_enhancements.py +115 -0
@@ -0,0 +1,191 @@
1
+ """
2
+ Custom exception classes for fishertools error handling.
3
+
4
+ This module defines the exception hierarchy for fishertools, providing
5
+ specific error types for different failure scenarios.
6
+ """
7
+
8
+
9
+ class FishertoolsError(Exception):
10
+ """
11
+ Base exception class for all fishertools-specific errors.
12
+
13
+ This is the parent class for all custom exceptions in fishertools.
14
+ It provides a consistent interface and allows catching all fishertools
15
+ errors with a single except clause.
16
+ """
17
+
18
+ def __init__(self, message: str, original_error: Exception = None):
19
+ """
20
+ Initialize the fishertools error.
21
+
22
+ Args:
23
+ message: Human-readable error message in Russian
24
+ original_error: The original exception that caused this error (optional)
25
+ """
26
+ super().__init__(message)
27
+ self.message = message
28
+ self.original_error = original_error
29
+
30
+ def __str__(self) -> str:
31
+ """Return the error message."""
32
+ return self.message
33
+
34
+ def get_full_message(self) -> str:
35
+ """
36
+ Get the full error message including original error if available.
37
+
38
+ Returns:
39
+ Complete error message with context
40
+ """
41
+ if self.original_error:
42
+ return f"{self.message} (Причина: {self.original_error})"
43
+ return self.message
44
+
45
+
46
+ class ExplanationError(FishertoolsError):
47
+ """
48
+ Exception raised when error explanation fails.
49
+
50
+ This exception is raised when the ErrorExplainer cannot create
51
+ a proper explanation for a given exception, typically due to
52
+ pattern matching failures or internal processing errors.
53
+ """
54
+
55
+ def __init__(self, message: str, exception_type: str = None, original_error: Exception = None):
56
+ """
57
+ Initialize the explanation error.
58
+
59
+ Args:
60
+ message: Description of what went wrong during explanation
61
+ exception_type: The type of exception that couldn't be explained
62
+ original_error: The original exception that caused this error
63
+ """
64
+ super().__init__(message, original_error)
65
+ self.exception_type = exception_type
66
+
67
+ def get_full_message(self) -> str:
68
+ """Get the full error message with exception type context."""
69
+ base_message = super().get_full_message()
70
+ if self.exception_type:
71
+ return f"{base_message} (Тип исключения: {self.exception_type})"
72
+ return base_message
73
+
74
+
75
+ class FormattingError(FishertoolsError):
76
+ """
77
+ Exception raised when output formatting fails.
78
+
79
+ This exception is raised when formatters cannot properly format
80
+ an ErrorExplanation, typically due to invalid formatter configuration
81
+ or output generation issues.
82
+ """
83
+
84
+ def __init__(self, message: str, formatter_type: str = None, original_error: Exception = None):
85
+ """
86
+ Initialize the formatting error.
87
+
88
+ Args:
89
+ message: Description of what went wrong during formatting
90
+ formatter_type: The type of formatter that failed
91
+ original_error: The original exception that caused this error
92
+ """
93
+ super().__init__(message, original_error)
94
+ self.formatter_type = formatter_type
95
+
96
+ def get_full_message(self) -> str:
97
+ """Get the full error message with formatter type context."""
98
+ base_message = super().get_full_message()
99
+ if self.formatter_type:
100
+ return f"{base_message} (Тип форматтера: {self.formatter_type})"
101
+ return base_message
102
+
103
+
104
+ class ConfigurationError(FishertoolsError):
105
+ """
106
+ Exception raised when configuration is invalid.
107
+
108
+ This exception is raised when ExplainerConfig or other configuration
109
+ objects contain invalid values that prevent proper system operation.
110
+ """
111
+
112
+ def __init__(self, message: str, config_field: str = None, config_value: str = None, original_error: Exception = None):
113
+ """
114
+ Initialize the configuration error.
115
+
116
+ Args:
117
+ message: Description of the configuration problem
118
+ config_field: The configuration field that has an invalid value
119
+ config_value: The invalid value that caused the error
120
+ original_error: The original exception that caused this error
121
+ """
122
+ super().__init__(message, original_error)
123
+ self.config_field = config_field
124
+ self.config_value = config_value
125
+
126
+ def get_full_message(self) -> str:
127
+ """Get the full error message with configuration context."""
128
+ base_message = super().get_full_message()
129
+ if self.config_field and self.config_value:
130
+ return f"{base_message} (Поле: {self.config_field}, Значение: {self.config_value})"
131
+ elif self.config_field:
132
+ return f"{base_message} (Поле: {self.config_field})"
133
+ return base_message
134
+
135
+
136
+ class PatternError(FishertoolsError):
137
+ """
138
+ Exception raised when error pattern operations fail.
139
+
140
+ This exception is raised when ErrorPattern objects cannot be created,
141
+ loaded, or used properly, typically due to invalid pattern definitions
142
+ or pattern matching failures.
143
+ """
144
+
145
+ def __init__(self, message: str, pattern_type: str = None, original_error: Exception = None):
146
+ """
147
+ Initialize the pattern error.
148
+
149
+ Args:
150
+ message: Description of the pattern problem
151
+ pattern_type: The type of pattern that caused the error
152
+ original_error: The original exception that caused this error
153
+ """
154
+ super().__init__(message, original_error)
155
+ self.pattern_type = pattern_type
156
+
157
+ def get_full_message(self) -> str:
158
+ """Get the full error message with pattern type context."""
159
+ base_message = super().get_full_message()
160
+ if self.pattern_type:
161
+ return f"{base_message} (Тип паттерна: {self.pattern_type})"
162
+ return base_message
163
+
164
+
165
+ class SafeUtilityError(FishertoolsError):
166
+ """
167
+ Exception raised when safe utility operations fail.
168
+
169
+ This exception is raised when safe utility functions encounter
170
+ errors that cannot be handled gracefully, typically due to
171
+ invalid inputs or system-level failures.
172
+ """
173
+
174
+ def __init__(self, message: str, utility_name: str = None, original_error: Exception = None):
175
+ """
176
+ Initialize the safe utility error.
177
+
178
+ Args:
179
+ message: Description of the utility problem
180
+ utility_name: The name of the utility function that failed
181
+ original_error: The original exception that caused this error
182
+ """
183
+ super().__init__(message, original_error)
184
+ self.utility_name = utility_name
185
+
186
+ def get_full_message(self) -> str:
187
+ """Get the full error message with utility name context."""
188
+ base_message = super().get_full_message()
189
+ if self.utility_name:
190
+ return f"{base_message} (Утилита: {self.utility_name})"
191
+ return base_message
@@ -0,0 +1,303 @@
1
+ """
2
+ Main error explainer implementation.
3
+
4
+ This module contains the ErrorExplainer class and explain_error function.
5
+ """
6
+
7
+ from typing import Optional, List
8
+ from .models import ErrorExplanation, ExplainerConfig, ErrorPattern
9
+ from .patterns import load_default_patterns
10
+ from .exceptions import ExplanationError, FormattingError, ConfigurationError, FishertoolsError
11
+
12
+
13
+ class ErrorExplainer:
14
+ """
15
+ Main class for explaining Python errors in simple terms.
16
+
17
+ Uses pattern matching to provide contextual explanations for different
18
+ types of Python exceptions.
19
+ """
20
+
21
+ def __init__(self, config: Optional[ExplainerConfig] = None):
22
+ """
23
+ Initialize the error explainer with optional configuration.
24
+
25
+ Args:
26
+ config: Configuration for the explainer behavior
27
+
28
+ Raises:
29
+ ConfigurationError: If the provided configuration is invalid
30
+ ExplanationError: If pattern loading fails
31
+ """
32
+ try:
33
+ self.config = config or ExplainerConfig()
34
+ self.patterns = self._load_patterns()
35
+ except Exception as e:
36
+ if isinstance(e, (ConfigurationError, ExplanationError)):
37
+ raise
38
+ raise ExplanationError(f"Не удалось инициализировать ErrorExplainer: {e}", original_error=e)
39
+
40
+ def _load_patterns(self) -> List[ErrorPattern]:
41
+ """
42
+ Load error patterns for matching exceptions.
43
+
44
+ Returns:
45
+ List of ErrorPattern objects
46
+
47
+ Raises:
48
+ ExplanationError: If patterns cannot be loaded
49
+ """
50
+ try:
51
+ return load_default_patterns()
52
+ except Exception as e:
53
+ raise ExplanationError(f"Не удалось загрузить паттерны ошибок: {e}", original_error=e)
54
+
55
+ def explain(self, exception: Exception) -> ErrorExplanation:
56
+ """
57
+ Create an explanation for the given exception.
58
+
59
+ Args:
60
+ exception: The exception to explain
61
+
62
+ Returns:
63
+ Structured explanation of the error
64
+
65
+ Raises:
66
+ ExplanationError: If explanation creation fails
67
+ """
68
+ if not isinstance(exception, Exception):
69
+ raise ExplanationError(f"Параметр должен быть экземпляром Exception, получен {type(exception).__name__}")
70
+
71
+ try:
72
+ # Try to find a matching pattern
73
+ pattern = self._match_pattern(exception)
74
+
75
+ if pattern:
76
+ return self._create_explanation_from_pattern(exception, pattern)
77
+ else:
78
+ return self._create_fallback_explanation(exception)
79
+
80
+ except Exception as e:
81
+ if isinstance(e, ExplanationError):
82
+ raise
83
+ # Graceful degradation - create a minimal explanation if all else fails
84
+ return self._create_emergency_explanation(exception, e)
85
+
86
+ def _match_pattern(self, exception: Exception) -> Optional[ErrorPattern]:
87
+ """
88
+ Find the best matching pattern for the given exception.
89
+
90
+ Args:
91
+ exception: The exception to match
92
+
93
+ Returns:
94
+ Matching ErrorPattern or None if no match found
95
+ """
96
+ try:
97
+ for pattern in self.patterns:
98
+ if pattern.matches(exception):
99
+ return pattern
100
+ return None
101
+ except Exception as e:
102
+ # If pattern matching fails, log the error but don't raise
103
+ # This allows fallback explanation to work
104
+ return None
105
+
106
+ def _create_explanation_from_pattern(self, exception: Exception,
107
+ pattern: ErrorPattern) -> ErrorExplanation:
108
+ """
109
+ Create explanation using a matched pattern.
110
+
111
+ Args:
112
+ exception: The original exception
113
+ pattern: The matched pattern
114
+
115
+ Returns:
116
+ ErrorExplanation based on the pattern
117
+
118
+ Raises:
119
+ ExplanationError: If explanation creation fails
120
+ """
121
+ try:
122
+ return ErrorExplanation(
123
+ original_error=str(exception),
124
+ error_type=type(exception).__name__,
125
+ simple_explanation=pattern.explanation,
126
+ fix_tip=pattern.tip,
127
+ code_example=pattern.example,
128
+ additional_info=f"Частые причины: {', '.join(pattern.common_causes)}"
129
+ )
130
+ except Exception as e:
131
+ raise ExplanationError(f"Не удалось создать объяснение из паттерна: {e}",
132
+ exception_type=type(exception).__name__, original_error=e)
133
+
134
+ def _create_fallback_explanation(self, exception: Exception) -> ErrorExplanation:
135
+ """
136
+ Create a generic explanation for unsupported exceptions.
137
+
138
+ Args:
139
+ exception: The exception to explain
140
+
141
+ Returns:
142
+ Generic ErrorExplanation
143
+ """
144
+ try:
145
+ error_type = type(exception).__name__
146
+
147
+ return ErrorExplanation(
148
+ original_error=str(exception),
149
+ error_type=error_type,
150
+ simple_explanation=f"Произошла ошибка типа {error_type}. Это означает, что в вашем коде что-то пошло не так.",
151
+ fix_tip="Внимательно прочитайте сообщение об ошибке и проверьте строку кода, где произошла ошибка. Убедитесь, что все переменные определены и имеют правильные типы.",
152
+ code_example=f"# Пример обработки ошибки {error_type}:\ntry:\n # ваш код здесь\n pass\nexcept {error_type} as e:\n print(f'Ошибка: {{e}}')",
153
+ additional_info="Если вы не можете решить проблему самостоятельно, попробуйте поискать информацию об этом типе ошибки в документации Python или задать вопрос на форуме."
154
+ )
155
+ except Exception as e:
156
+ # If even fallback fails, create emergency explanation
157
+ return self._create_emergency_explanation(exception, e)
158
+
159
+ def _create_emergency_explanation(self, exception: Exception, original_error: Exception) -> ErrorExplanation:
160
+ """
161
+ Create a minimal explanation when all other methods fail.
162
+
163
+ This is the last resort for graceful degradation.
164
+
165
+ Args:
166
+ exception: The original exception to explain
167
+ original_error: The error that prevented normal explanation
168
+
169
+ Returns:
170
+ Minimal ErrorExplanation that should always work
171
+ """
172
+ try:
173
+ error_type = getattr(type(exception), '__name__', 'Unknown')
174
+ error_message = str(exception) if exception else 'Неизвестная ошибка'
175
+
176
+ return ErrorExplanation(
177
+ original_error=error_message,
178
+ error_type=error_type,
179
+ simple_explanation="Произошла ошибка в вашем коде. К сожалению, не удалось создать подробное объяснение.",
180
+ fix_tip="Проверьте сообщение об ошибке выше и попробуйте найти проблему в коде. Обратитесь за помощью, если не можете решить проблему самостоятельно.",
181
+ code_example="# Общий способ обработки ошибок:\ntry:\n # ваш код\n pass\nexcept Exception as e:\n print(f'Ошибка: {e}')",
182
+ additional_info=f"Внутренняя ошибка fishertools: {original_error}"
183
+ )
184
+ except Exception:
185
+ # Absolute last resort - create explanation with minimal dependencies
186
+ return ErrorExplanation(
187
+ original_error="Критическая ошибка",
188
+ error_type="Critical",
189
+ simple_explanation="Произошла критическая ошибка в системе объяснения ошибок.",
190
+ fix_tip="Обратитесь к разработчикам fishertools с описанием проблемы.",
191
+ code_example="# Обратитесь за помощью",
192
+ additional_info="Критическая ошибка системы"
193
+ )
194
+
195
+
196
+ def explain_error(exception: Exception,
197
+ language: str = 'ru',
198
+ format_type: str = 'console',
199
+ **kwargs) -> None:
200
+ """
201
+ Main public API function for explaining Python errors in simple terms.
202
+
203
+ This function takes any Python exception and provides a beginner-friendly
204
+ explanation in Russian, including what the error means, how to fix it,
205
+ and a relevant code example.
206
+
207
+ Args:
208
+ exception: The Python exception to explain (required)
209
+ language: Language for explanations ('ru' or 'en', default: 'ru')
210
+ format_type: Output format ('console', 'plain', 'json', default: 'console')
211
+ **kwargs: Additional formatting parameters:
212
+ - use_colors: Whether to use colors in console output (default: True)
213
+ - show_original_error: Whether to show original error message (default: True)
214
+ - show_traceback: Whether to show traceback (default: False)
215
+
216
+ Raises:
217
+ TypeError: If exception parameter is not an Exception instance
218
+ ValueError: If language or format_type parameters are invalid
219
+
220
+ Examples:
221
+ >>> try:
222
+ ... result = 10 / 0
223
+ ... except Exception as e:
224
+ ... explain_error(e)
225
+
226
+ >>> explain_error(TypeError("'str' object cannot be interpreted as an integer"))
227
+
228
+ >>> explain_error(ValueError("invalid literal"), format_type='json')
229
+ """
230
+ # Parameter validation with custom exceptions
231
+ if not isinstance(exception, Exception):
232
+ raise TypeError(f"Параметр 'exception' должен быть экземпляром Exception, "
233
+ f"получен {type(exception).__name__}")
234
+
235
+ # Validate language parameter
236
+ valid_languages = ['ru', 'en']
237
+ if language not in valid_languages:
238
+ raise ValueError(f"Параметр 'language' должен быть одним из {valid_languages}, "
239
+ f"получен '{language}'")
240
+
241
+ # Validate format_type parameter
242
+ valid_formats = ['console', 'plain', 'json']
243
+ if format_type not in valid_formats:
244
+ raise ValueError(f"Параметр 'format_type' должен быть одним из {valid_formats}, "
245
+ f"получен '{format_type}'")
246
+
247
+ try:
248
+ from .formatters import get_formatter
249
+
250
+ # Create configuration based on parameters
251
+ config = ExplainerConfig(
252
+ language=language,
253
+ format_type=format_type,
254
+ use_colors=kwargs.get('use_colors', True),
255
+ show_original_error=kwargs.get('show_original_error', True),
256
+ show_traceback=kwargs.get('show_traceback', False)
257
+ )
258
+
259
+ # Create explainer and get explanation
260
+ explainer = ErrorExplainer(config)
261
+ explanation = explainer.explain(exception)
262
+
263
+ # Get appropriate formatter and format output
264
+ formatter = get_formatter(format_type, use_colors=config.use_colors)
265
+ formatted_output = formatter.format(explanation)
266
+
267
+ # Output to console by default
268
+ print(formatted_output)
269
+
270
+ except ExplanationError as e:
271
+ # Handle explanation-specific errors gracefully
272
+ print(f"Ошибка при объяснении исключения: {e.get_full_message()}")
273
+ print(f"Оригинальная ошибка: {type(exception).__name__}: {exception}")
274
+ if e.original_error:
275
+ print(f"Техническая информация: {e.original_error}")
276
+
277
+ except FormattingError as e:
278
+ # Handle formatting errors - try to show basic explanation
279
+ print(f"Ошибка форматирования: {e.get_full_message()}")
280
+ try:
281
+ # Try to create a basic explanation without formatting
282
+ explainer = ErrorExplainer()
283
+ explanation = explainer.explain(exception)
284
+ print(f"Простое объяснение: {explanation.simple_explanation}")
285
+ print(f"Совет: {explanation.fix_tip}")
286
+ except Exception:
287
+ print(f"Оригинальная ошибка: {type(exception).__name__}: {exception}")
288
+
289
+ except ConfigurationError as e:
290
+ # Handle configuration errors
291
+ print(f"Ошибка конфигурации: {e.get_full_message()}")
292
+ print(f"Оригинальная ошибка: {type(exception).__name__}: {exception}")
293
+
294
+ except FishertoolsError as e:
295
+ # Handle any other fishertools-specific errors
296
+ print(f"Ошибка fishertools: {e.get_full_message()}")
297
+ print(f"Оригинальная ошибка: {type(exception).__name__}: {exception}")
298
+
299
+ except Exception as e:
300
+ # Ultimate fallback for any unexpected errors
301
+ print(f"Неожиданная ошибка в fishertools: {e}")
302
+ print(f"Оригинальная ошибка: {type(exception).__name__}: {exception}")
303
+ print("Пожалуйста, сообщите об этой проблеме разработчикам fishertools.")