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,298 @@
1
+ """
2
+ Integration tests for fishertools.
3
+
4
+ These tests verify that all components work together correctly,
5
+ from exception handling to formatted output.
6
+ """
7
+
8
+ import pytest
9
+ import io
10
+ import sys
11
+ from contextlib import redirect_stdout
12
+ from unittest.mock import patch
13
+
14
+ import fishertools
15
+ from fishertools import explain_error
16
+ from fishertools.errors import ErrorExplainer, ErrorExplanation
17
+ from fishertools.errors.formatters import get_formatter
18
+
19
+
20
+ class TestMainAPIIntegration:
21
+ """Test the main API integration and complete workflow."""
22
+
23
+ def test_explain_error_complete_workflow(self):
24
+ """Test complete workflow from exception to formatted output."""
25
+ # Create a test exception
26
+ test_exception = ValueError("invalid literal for int() with base 10: 'abc'")
27
+
28
+ # Capture output
29
+ output_buffer = io.StringIO()
30
+
31
+ with redirect_stdout(output_buffer):
32
+ explain_error(test_exception)
33
+
34
+ output = output_buffer.getvalue()
35
+
36
+ # Verify output contains expected sections
37
+ assert "Ошибка Python: ValueError" in output
38
+ assert "Что это означает" in output
39
+ assert "Как исправить" in output
40
+ assert "Пример" in output
41
+ assert "invalid literal for int()" in output
42
+
43
+ def test_explain_error_with_different_formats(self):
44
+ """Test explain_error with different output formats."""
45
+ test_exception = TypeError("'str' object cannot be interpreted as an integer")
46
+
47
+ # Test console format (default)
48
+ output_buffer = io.StringIO()
49
+ with redirect_stdout(output_buffer):
50
+ explain_error(test_exception, format_type='console')
51
+ console_output = output_buffer.getvalue()
52
+ assert "🚨 Ошибка Python:" in console_output
53
+
54
+ # Test plain format
55
+ output_buffer = io.StringIO()
56
+ with redirect_stdout(output_buffer):
57
+ explain_error(test_exception, format_type='plain')
58
+ plain_output = output_buffer.getvalue()
59
+ assert "Ошибка Python:" in plain_output
60
+ assert "🚨" not in plain_output # No emojis in plain format
61
+
62
+ # Test JSON format
63
+ output_buffer = io.StringIO()
64
+ with redirect_stdout(output_buffer):
65
+ explain_error(test_exception, format_type='json')
66
+ json_output = output_buffer.getvalue()
67
+ assert '"error_type": "TypeError"' in json_output
68
+ assert '"simple_explanation"' in json_output
69
+
70
+ def test_explain_error_parameter_validation(self):
71
+ """Test that explain_error validates parameters correctly."""
72
+ # Test invalid exception parameter
73
+ with pytest.raises(TypeError, match="должен быть экземпляром Exception"):
74
+ explain_error("not an exception")
75
+
76
+ # Test invalid language parameter
77
+ with pytest.raises(ValueError, match="должен быть одним из"):
78
+ explain_error(ValueError("test"), language='invalid')
79
+
80
+ # Test invalid format_type parameter
81
+ with pytest.raises(ValueError, match="должен быть одним из"):
82
+ explain_error(ValueError("test"), format_type='invalid')
83
+
84
+ def test_explain_error_with_optional_parameters(self):
85
+ """Test explain_error with various optional parameters."""
86
+ test_exception = IndexError("list index out of range")
87
+
88
+ # Test with colors disabled
89
+ output_buffer = io.StringIO()
90
+ with redirect_stdout(output_buffer):
91
+ explain_error(test_exception, use_colors=False)
92
+ output = output_buffer.getvalue()
93
+ assert "IndexError" in output
94
+
95
+ # Test with original error hidden
96
+ output_buffer = io.StringIO()
97
+ with redirect_stdout(output_buffer):
98
+ explain_error(test_exception, show_original_error=False)
99
+ output = output_buffer.getvalue()
100
+ # Should still contain explanation but format might differ
101
+ assert "Что это означает" in output
102
+
103
+
104
+ class TestComponentIntegration:
105
+ """Test integration between different components."""
106
+
107
+ def test_explainer_formatter_integration(self):
108
+ """Test that ErrorExplainer works correctly with formatters."""
109
+ explainer = ErrorExplainer()
110
+ test_exception = KeyError("'missing_key'")
111
+
112
+ # Get explanation
113
+ explanation = explainer.explain(test_exception)
114
+
115
+ # Test with different formatters
116
+ console_formatter = get_formatter('console')
117
+ plain_formatter = get_formatter('plain')
118
+ json_formatter = get_formatter('json')
119
+
120
+ console_output = console_formatter.format(explanation)
121
+ plain_output = plain_formatter.format(explanation)
122
+ json_output = json_formatter.format(explanation)
123
+
124
+ # All should contain the error information
125
+ assert "KeyError" in console_output
126
+ assert "KeyError" in plain_output
127
+ assert '"error_type": "KeyError"' in json_output
128
+
129
+ # Console should have formatting
130
+ assert "🚨" in console_output or "═══" in console_output
131
+
132
+ # Plain should be simpler
133
+ assert "🚨" not in plain_output
134
+
135
+ # JSON should be valid JSON structure
136
+ import json
137
+ json_data = json.loads(json_output)
138
+ assert json_data['error_type'] == 'KeyError'
139
+
140
+ def test_pattern_matching_integration(self):
141
+ """Test that pattern matching works with real exceptions."""
142
+ explainer = ErrorExplainer()
143
+
144
+ # Test common exceptions that should have specific patterns
145
+ test_cases = [
146
+ (TypeError("'str' object cannot be interpreted as an integer"), "TypeError"),
147
+ (ValueError("invalid literal for int()"), "ValueError"),
148
+ (AttributeError("'str' object has no attribute 'append'"), "AttributeError"),
149
+ (IndexError("list index out of range"), "IndexError"),
150
+ (KeyError("'missing_key'"), "KeyError"),
151
+ ]
152
+
153
+ for exception, expected_type in test_cases:
154
+ explanation = explainer.explain(exception)
155
+ assert explanation.error_type == expected_type
156
+ assert explanation.simple_explanation is not None
157
+ assert explanation.fix_tip is not None
158
+ assert explanation.code_example is not None
159
+
160
+ def test_fallback_explanation_integration(self):
161
+ """Test that fallback explanations work for unknown exceptions."""
162
+ explainer = ErrorExplainer()
163
+
164
+ # Create a custom exception that shouldn't have a specific pattern
165
+ class CustomException(Exception):
166
+ pass
167
+
168
+ custom_exception = CustomException("This is a custom error")
169
+ explanation = explainer.explain(custom_exception)
170
+
171
+ # Should get fallback explanation
172
+ assert explanation.error_type == "CustomException"
173
+ assert "Произошла ошибка типа CustomException" in explanation.simple_explanation
174
+ assert explanation.fix_tip is not None
175
+ assert explanation.code_example is not None
176
+
177
+
178
+ class TestModuleAccessibility:
179
+ """Test that all modules and functions are accessible through the main API."""
180
+
181
+ def test_main_api_accessibility(self):
182
+ """Test that main API functions are accessible."""
183
+ # Primary API
184
+ assert hasattr(fishertools, 'explain_error')
185
+ assert callable(fishertools.explain_error)
186
+
187
+ # Safe utilities
188
+ assert hasattr(fishertools, 'safe_get')
189
+ assert hasattr(fishertools, 'safe_divide')
190
+ assert hasattr(fishertools, 'safe_read_file')
191
+
192
+ # Learning tools
193
+ assert hasattr(fishertools, 'generate_example')
194
+ assert hasattr(fishertools, 'show_best_practice')
195
+
196
+ # All should be callable
197
+ assert callable(fishertools.safe_get)
198
+ assert callable(fishertools.safe_divide)
199
+ assert callable(fishertools.generate_example)
200
+ assert callable(fishertools.show_best_practice)
201
+
202
+ def test_module_imports_accessibility(self):
203
+ """Test that modules can be imported and used."""
204
+ # Test errors module
205
+ from fishertools import errors
206
+ assert hasattr(errors, 'explain_error')
207
+ assert hasattr(errors, 'ErrorExplainer')
208
+
209
+ # Test safe module
210
+ from fishertools import safe
211
+ assert hasattr(safe, 'safe_get')
212
+ assert hasattr(safe, 'safe_divide')
213
+
214
+ # Test learn module
215
+ from fishertools import learn
216
+ assert hasattr(learn, 'generate_example')
217
+ assert hasattr(learn, 'show_best_practice')
218
+
219
+ # Test legacy module
220
+ from fishertools import legacy
221
+ assert legacy is not None
222
+
223
+ def test_direct_imports_work(self):
224
+ """Test that direct imports from fishertools work."""
225
+ # These should all work without errors
226
+ from fishertools import explain_error
227
+ from fishertools import safe_get, safe_divide
228
+ from fishertools import generate_example, show_best_practice
229
+
230
+ # Test that they're the same objects as module attributes
231
+ assert explain_error is fishertools.explain_error
232
+ assert safe_get is fishertools.safe_get
233
+ assert generate_example is fishertools.generate_example
234
+
235
+
236
+ class TestErrorHandlingIntegration:
237
+ """Test error handling across the integrated system."""
238
+
239
+ def test_graceful_error_handling(self):
240
+ """Test that the system handles errors gracefully."""
241
+ # Test with a problematic exception that might cause issues
242
+ test_exception = Exception("Test exception with unicode: тест")
243
+
244
+ # Should not raise an exception
245
+ output_buffer = io.StringIO()
246
+ with redirect_stdout(output_buffer):
247
+ explain_error(test_exception)
248
+
249
+ output = output_buffer.getvalue()
250
+ assert len(output) > 0 # Should produce some output
251
+ assert "Exception" in output
252
+
253
+ def test_system_robustness(self):
254
+ """Test system robustness with edge cases."""
255
+ # Test with exception with empty message
256
+ empty_exception = ValueError("")
257
+ output_buffer = io.StringIO()
258
+ with redirect_stdout(output_buffer):
259
+ explain_error(empty_exception)
260
+ output = output_buffer.getvalue()
261
+ assert "ValueError" in output
262
+
263
+ # Test with exception with very long message
264
+ long_message = "x" * 1000
265
+ long_exception = RuntimeError(long_message)
266
+ output_buffer = io.StringIO()
267
+ with redirect_stdout(output_buffer):
268
+ explain_error(long_exception)
269
+ output = output_buffer.getvalue()
270
+ assert "RuntimeError" in output
271
+
272
+
273
+ class TestBackwardCompatibility:
274
+ """Test that backward compatibility is maintained."""
275
+
276
+ def test_legacy_module_access(self):
277
+ """Test that legacy modules are still accessible."""
278
+ # These should work for backward compatibility
279
+ import fishertools.utils
280
+ import fishertools.decorators
281
+ import fishertools.helpers
282
+
283
+ # Modules should be importable
284
+ assert fishertools.utils is not None
285
+ assert fishertools.decorators is not None
286
+ assert fishertools.helpers is not None
287
+
288
+ def test_legacy_functions_accessible(self):
289
+ """Test that legacy functions are accessible through fishertools."""
290
+ # Legacy modules should be in __all__
291
+ assert 'utils' in fishertools.__all__
292
+ assert 'decorators' in fishertools.__all__
293
+ assert 'helpers' in fishertools.__all__
294
+
295
+ # Should be accessible as attributes
296
+ assert hasattr(fishertools, 'utils')
297
+ assert hasattr(fishertools, 'decorators')
298
+ assert hasattr(fishertools, 'helpers')