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,82 @@
1
+ """
2
+ Fishertools - инструменты, которые делают Python удобнее и безопаснее для новичков
3
+
4
+ Основная функция:
5
+ explain_error() - объясняет ошибки Python в понятных словах
6
+
7
+ Модули:
8
+ errors - система объяснения ошибок
9
+ safe - безопасные утилиты для новичков
10
+ learn - обучающие инструменты
11
+ legacy - функции для обратной совместимости
12
+ """
13
+
14
+ __version__ = "0.2.1"
15
+ __author__ = "f1sherFM"
16
+
17
+ # Primary API - main interface for users
18
+ from .errors import explain_error
19
+
20
+ # Exception classes for error handling
21
+ from .errors import (
22
+ FishertoolsError, ExplanationError, FormattingError,
23
+ ConfigurationError, PatternError, SafeUtilityError
24
+ )
25
+
26
+ # Safe utilities - commonly used beginner-friendly functions
27
+ from .safe import (
28
+ safe_get, safe_divide, safe_max, safe_min, safe_sum,
29
+ safe_read_file, safe_write_file, safe_file_exists,
30
+ safe_get_file_size, safe_list_files
31
+ )
32
+
33
+ # Learning tools - educational functions
34
+ from .learn import (
35
+ generate_example, show_best_practice,
36
+ list_available_concepts, list_available_topics
37
+ )
38
+
39
+ # Legacy imports for backward compatibility
40
+ from . import utils
41
+ from . import decorators
42
+ from . import helpers
43
+
44
+ # Module imports for advanced users who want to access specific modules
45
+ from . import errors
46
+ from . import safe
47
+ from . import learn
48
+ from . import legacy
49
+
50
+ # New enhancement modules (fishertools-enhancements)
51
+ from . import learning
52
+ from . import documentation
53
+ from . import examples
54
+ from . import config
55
+ from . import integration
56
+
57
+ __all__ = [
58
+ # Primary API - the main function users should import
59
+ "explain_error",
60
+
61
+ # Exception classes for error handling
62
+ "FishertoolsError", "ExplanationError", "FormattingError",
63
+ "ConfigurationError", "PatternError", "SafeUtilityError",
64
+
65
+ # Safe utilities - direct access to commonly used functions
66
+ "safe_get", "safe_divide", "safe_max", "safe_min", "safe_sum",
67
+ "safe_read_file", "safe_write_file", "safe_file_exists",
68
+ "safe_get_file_size", "safe_list_files",
69
+
70
+ # Learning tools - direct access to educational functions
71
+ "generate_example", "show_best_practice",
72
+ "list_available_concepts", "list_available_topics",
73
+
74
+ # Legacy modules for backward compatibility
75
+ "utils", "decorators", "helpers",
76
+
77
+ # New modules for advanced usage
78
+ "errors", "safe", "learn", "legacy",
79
+
80
+ # Enhancement modules (fishertools-enhancements)
81
+ "learning", "documentation", "examples", "config", "integration"
82
+ ]
@@ -0,0 +1,24 @@
1
+ """
2
+ Configuration Management Module
3
+
4
+ Handles learning system configuration through various file formats
5
+ with validation and error recovery.
6
+ """
7
+
8
+ from .manager import ConfigurationManager
9
+ from .parser import ConfigurationParser
10
+ from .models import (
11
+ LearningConfig,
12
+ ValidationResult,
13
+ RecoveryAction,
14
+ ConfigError
15
+ )
16
+
17
+ __all__ = [
18
+ "ConfigurationManager",
19
+ "ConfigurationParser",
20
+ "LearningConfig",
21
+ "ValidationResult",
22
+ "RecoveryAction",
23
+ "ConfigError"
24
+ ]
@@ -0,0 +1,247 @@
1
+ """
2
+ Configuration manager for the learning system.
3
+ """
4
+
5
+ from typing import Optional, Dict, Any
6
+ import json
7
+ import os
8
+ from dataclasses import asdict
9
+ from .models import LearningConfig, ValidationResult, RecoveryAction, ConfigError
10
+ from .parser import ConfigurationParser
11
+
12
+
13
+ class ConfigurationManager:
14
+ """
15
+ Manages learning system configuration through various file formats.
16
+
17
+ Handles loading, saving, validation, and error recovery for
18
+ configuration files in JSON, YAML, and TOML formats.
19
+ """
20
+
21
+ def __init__(self, default_config_path: Optional[str] = None):
22
+ """
23
+ Initialize the configuration manager.
24
+
25
+ Args:
26
+ default_config_path: Optional path to default configuration file
27
+ """
28
+ self.default_config_path = default_config_path or self._get_default_config_path()
29
+ self.parser = ConfigurationParser()
30
+ self._current_config: Optional[LearningConfig] = None
31
+
32
+ def _get_default_config_path(self) -> str:
33
+ """Get the path to the default configuration file."""
34
+ current_dir = os.path.dirname(__file__)
35
+ return os.path.join(current_dir, 'default_config.json')
36
+
37
+ def load_config(self, config_path: str) -> LearningConfig:
38
+ """
39
+ Load configuration from a file.
40
+
41
+ Args:
42
+ config_path: Path to the configuration file
43
+
44
+ Returns:
45
+ LearningConfig: Loaded configuration
46
+
47
+ Raises:
48
+ FileNotFoundError: If config file doesn't exist
49
+ ValueError: If config format is invalid
50
+ """
51
+ try:
52
+ # Parse the configuration file
53
+ config_data = self.parser.parse_file(config_path)
54
+
55
+ # Validate the configuration
56
+ validation_result = self.parser.validate_structure(config_data)
57
+
58
+ if not validation_result.is_valid:
59
+ error_messages = [error.message for error in validation_result.errors]
60
+ raise ValueError(f"Configuration validation failed: {'; '.join(error_messages)}")
61
+
62
+ # Create LearningConfig object with defaults for missing fields
63
+ default_config = self.get_default_config()
64
+ merged_config = self.merge_configs(default_config, config_data)
65
+
66
+ self._current_config = merged_config
67
+ return merged_config
68
+
69
+ except FileNotFoundError:
70
+ raise FileNotFoundError(f"Configuration file not found: {config_path}")
71
+ except Exception as e:
72
+ raise ValueError(f"Failed to load configuration: {e}")
73
+
74
+ def save_config(self, config: LearningConfig, config_path: str) -> None:
75
+ """
76
+ Save configuration to a file.
77
+
78
+ Args:
79
+ config: Configuration to save
80
+ config_path: Path where to save the configuration
81
+
82
+ Raises:
83
+ IOError: If file cannot be written
84
+ """
85
+ try:
86
+ # Determine format based on file extension
87
+ format_type = self.parser.detect_format(config_path)
88
+
89
+ # Format the configuration
90
+ if format_type.value == 'json':
91
+ content = self.parser.format_to_json(config)
92
+ elif format_type.value == 'yaml':
93
+ content = self.parser.format_to_yaml(config)
94
+ else:
95
+ raise ValueError(f"Unsupported format for saving: {format_type}")
96
+
97
+ # Ensure directory exists
98
+ os.makedirs(os.path.dirname(config_path), exist_ok=True)
99
+
100
+ # Write the file
101
+ with open(config_path, 'w', encoding='utf-8') as f:
102
+ f.write(content)
103
+
104
+ except Exception as e:
105
+ raise IOError(f"Failed to save configuration to {config_path}: {e}")
106
+
107
+ def validate_config(self, config: LearningConfig) -> ValidationResult:
108
+ """
109
+ Validate a configuration object.
110
+
111
+ Args:
112
+ config: Configuration to validate
113
+
114
+ Returns:
115
+ ValidationResult: Validation result with errors/warnings
116
+ """
117
+ # Convert config to dict for validation
118
+ config_dict = asdict(config)
119
+ return self.parser.validate_structure(config_dict)
120
+
121
+ def apply_config(self, config: LearningConfig) -> None:
122
+ """
123
+ Apply configuration to the learning system.
124
+
125
+ Args:
126
+ config: Configuration to apply
127
+ """
128
+ # Validate the configuration first
129
+ validation_result = self.validate_config(config)
130
+
131
+ if not validation_result.is_valid:
132
+ error_messages = [error.message for error in validation_result.errors]
133
+ raise ValueError(f"Cannot apply invalid configuration: {'; '.join(error_messages)}")
134
+
135
+ # Store as current configuration
136
+ self._current_config = config
137
+
138
+ # Here we would apply the configuration to various system components
139
+ # For now, we just store it as the current configuration
140
+
141
+ def get_default_config(self) -> LearningConfig:
142
+ """
143
+ Get the default configuration.
144
+
145
+ Returns:
146
+ LearningConfig: Default configuration
147
+ """
148
+ try:
149
+ if os.path.exists(self.default_config_path):
150
+ config_data = self.parser.parse_file(self.default_config_path)
151
+ return self._dict_to_config(config_data)
152
+ else:
153
+ # Return hardcoded defaults if file doesn't exist
154
+ return LearningConfig()
155
+ except Exception:
156
+ # Return hardcoded defaults if parsing fails
157
+ return LearningConfig()
158
+
159
+ def merge_configs(self, base_config: LearningConfig, override_config: Dict[str, Any]) -> LearningConfig:
160
+ """
161
+ Merge configuration with overrides.
162
+
163
+ Args:
164
+ base_config: Base configuration
165
+ override_config: Configuration overrides
166
+
167
+ Returns:
168
+ LearningConfig: Merged configuration
169
+ """
170
+ # Convert base config to dict
171
+ base_dict = asdict(base_config)
172
+
173
+ # Update with overrides
174
+ base_dict.update(override_config)
175
+
176
+ # Convert back to LearningConfig
177
+ return self._dict_to_config(base_dict)
178
+
179
+ def _dict_to_config(self, config_dict: Dict[str, Any]) -> LearningConfig:
180
+ """
181
+ Convert dictionary to LearningConfig object.
182
+
183
+ Args:
184
+ config_dict: Configuration dictionary
185
+
186
+ Returns:
187
+ LearningConfig: Configuration object
188
+ """
189
+ # Filter out unknown fields and create LearningConfig
190
+ valid_fields = {
191
+ field.name for field in LearningConfig.__dataclass_fields__.values()
192
+ }
193
+
194
+ filtered_dict = {
195
+ key: value for key, value in config_dict.items()
196
+ if key in valid_fields
197
+ }
198
+
199
+ return LearningConfig(**filtered_dict)
200
+
201
+ def get_current_config(self) -> Optional[LearningConfig]:
202
+ """
203
+ Get the currently loaded configuration.
204
+
205
+ Returns:
206
+ Optional[LearningConfig]: Current configuration or None if not loaded
207
+ """
208
+ return self._current_config
209
+
210
+ def handle_config_error(self, error: ConfigError) -> RecoveryAction:
211
+ """
212
+ Handle configuration errors with appropriate recovery actions.
213
+
214
+ Args:
215
+ error: Configuration error to handle
216
+
217
+ Returns:
218
+ RecoveryAction: Recommended recovery action
219
+ """
220
+ from ..errors.recovery import get_recovery_manager, ErrorContext, ErrorSeverity
221
+
222
+ recovery_manager = get_recovery_manager()
223
+
224
+ # Determine error severity based on error type
225
+ if isinstance(error, FileNotFoundError):
226
+ severity = ErrorSeverity.MEDIUM
227
+ error_type = "config_file_missing"
228
+ elif "validation" in str(error).lower():
229
+ severity = ErrorSeverity.MEDIUM
230
+ error_type = "config_validation_error"
231
+ elif "parse" in str(error).lower() or "syntax" in str(error).lower():
232
+ severity = ErrorSeverity.HIGH
233
+ error_type = "config_parse_error"
234
+ else:
235
+ severity = ErrorSeverity.MEDIUM
236
+ error_type = "config_general_error"
237
+
238
+ error_context = ErrorContext(
239
+ component="configuration",
240
+ operation="load_config",
241
+ error_type=error_type,
242
+ error_message=str(error),
243
+ severity=severity,
244
+ metadata={"config_path": getattr(error, 'config_path', 'unknown')}
245
+ )
246
+
247
+ return recovery_manager.handle_error(error_context)
@@ -0,0 +1,96 @@
1
+ """
2
+ Data models for the Configuration Management module.
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from typing import List, Optional, Dict, Any, Literal
7
+ from enum import Enum
8
+
9
+
10
+ class ConfigFormat(Enum):
11
+ """Supported configuration file formats."""
12
+ JSON = "json"
13
+ YAML = "yaml"
14
+ TOML = "toml"
15
+
16
+
17
+ class ErrorSeverity(Enum):
18
+ """Severity levels for configuration errors."""
19
+ WARNING = "warning"
20
+ ERROR = "error"
21
+ CRITICAL = "critical"
22
+
23
+
24
+ class RecoveryStrategy(Enum):
25
+ """Strategies for error recovery."""
26
+ USE_DEFAULTS = "use_defaults"
27
+ PROMPT_USER = "prompt_user"
28
+ FAIL_GRACEFULLY = "fail_gracefully"
29
+ RETRY = "retry"
30
+
31
+
32
+ @dataclass
33
+ class ConfigError:
34
+ """Configuration error information."""
35
+ message: str
36
+ field_path: str
37
+ severity: ErrorSeverity
38
+ suggested_fix: Optional[str] = None
39
+ line_number: Optional[int] = None
40
+
41
+
42
+ @dataclass
43
+ class ValidationResult:
44
+ """Result of configuration validation."""
45
+ is_valid: bool
46
+ errors: List[ConfigError] = None
47
+ warnings: List[ConfigError] = None
48
+
49
+ def __post_init__(self):
50
+ if self.errors is None:
51
+ self.errors = []
52
+ if self.warnings is None:
53
+ self.warnings = []
54
+
55
+
56
+ @dataclass
57
+ class RecoveryAction:
58
+ """Action to take for error recovery."""
59
+ strategy: RecoveryStrategy
60
+ message: str
61
+ fallback_config: Optional[Dict[str, Any]] = None
62
+
63
+
64
+ @dataclass
65
+ class LearningConfig:
66
+ """Configuration for the learning system."""
67
+ # Basic settings
68
+ default_level: Literal["beginner", "intermediate", "advanced"] = "beginner"
69
+ explanation_verbosity: Literal["brief", "detailed", "comprehensive"] = "detailed"
70
+
71
+ # Visual settings
72
+ visual_aids_enabled: bool = True
73
+ diagram_style: str = "modern"
74
+ color_scheme: str = "default"
75
+
76
+ # Progress and tracking
77
+ progress_tracking_enabled: bool = True
78
+ save_progress_locally: bool = True
79
+
80
+ # Content and examples
81
+ suggested_topics_count: int = 3
82
+ max_examples_per_topic: int = 5
83
+ exercise_difficulty_progression: List[str] = None
84
+
85
+ # Integration
86
+ readthedocs_project: Optional[str] = None
87
+ sphinx_theme: str = "sphinx_rtd_theme"
88
+
89
+ # Advanced settings
90
+ enable_interactive_sessions: bool = True
91
+ session_timeout_minutes: int = 30
92
+ max_hint_count: int = 3
93
+
94
+ def __post_init__(self):
95
+ if self.exercise_difficulty_progression is None:
96
+ self.exercise_difficulty_progression = ["beginner", "intermediate", "advanced"]