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,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for safe file operations.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
import tempfile
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from fishertools.safe.files import (
|
|
10
|
+
safe_read_file, safe_write_file, safe_file_exists,
|
|
11
|
+
safe_get_file_size, safe_list_files
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestSafeFileOperations:
|
|
16
|
+
"""Unit tests for safe file operations."""
|
|
17
|
+
|
|
18
|
+
def test_safe_read_file_existing_file(self):
|
|
19
|
+
"""Test reading an existing file."""
|
|
20
|
+
with tempfile.NamedTemporaryFile(mode='w', delete=False, encoding='utf-8') as f:
|
|
21
|
+
f.write("Test content")
|
|
22
|
+
temp_path = f.name
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
result = safe_read_file(temp_path)
|
|
26
|
+
assert result == "Test content"
|
|
27
|
+
finally:
|
|
28
|
+
os.unlink(temp_path)
|
|
29
|
+
|
|
30
|
+
def test_safe_read_file_nonexistent_file(self):
|
|
31
|
+
"""Test reading a non-existent file returns default."""
|
|
32
|
+
result = safe_read_file("nonexistent_file.txt", default="default content")
|
|
33
|
+
assert result == "default content"
|
|
34
|
+
|
|
35
|
+
def test_safe_write_file_success(self):
|
|
36
|
+
"""Test writing to a file successfully."""
|
|
37
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
38
|
+
file_path = Path(temp_dir) / "test_file.txt"
|
|
39
|
+
result = safe_write_file(file_path, "Hello World")
|
|
40
|
+
assert result is True
|
|
41
|
+
assert file_path.exists()
|
|
42
|
+
assert file_path.read_text(encoding='utf-8') == "Hello World"
|
|
43
|
+
|
|
44
|
+
def test_safe_file_exists_existing_file(self):
|
|
45
|
+
"""Test checking existence of an existing file."""
|
|
46
|
+
with tempfile.NamedTemporaryFile(delete=False) as f:
|
|
47
|
+
temp_path = f.name
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
assert safe_file_exists(temp_path) is True
|
|
51
|
+
finally:
|
|
52
|
+
os.unlink(temp_path)
|
|
53
|
+
|
|
54
|
+
def test_safe_file_exists_nonexistent_file(self):
|
|
55
|
+
"""Test checking existence of a non-existent file."""
|
|
56
|
+
assert safe_file_exists("nonexistent_file.txt") is False
|
|
57
|
+
|
|
58
|
+
def test_safe_get_file_size_existing_file(self):
|
|
59
|
+
"""Test getting size of an existing file."""
|
|
60
|
+
with tempfile.NamedTemporaryFile(mode='w', delete=False, encoding='utf-8') as f:
|
|
61
|
+
f.write("12345") # 5 bytes
|
|
62
|
+
temp_path = f.name
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
size = safe_get_file_size(temp_path)
|
|
66
|
+
assert size == 5
|
|
67
|
+
finally:
|
|
68
|
+
os.unlink(temp_path)
|
|
69
|
+
|
|
70
|
+
def test_safe_get_file_size_nonexistent_file(self):
|
|
71
|
+
"""Test getting size of a non-existent file returns default."""
|
|
72
|
+
size = safe_get_file_size("nonexistent_file.txt", default=100)
|
|
73
|
+
assert size == 100
|
|
74
|
+
|
|
75
|
+
def test_safe_list_files_existing_directory(self):
|
|
76
|
+
"""Test listing files in an existing directory."""
|
|
77
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
78
|
+
# Create some test files
|
|
79
|
+
(Path(temp_dir) / "file1.txt").write_text("content1")
|
|
80
|
+
(Path(temp_dir) / "file2.py").write_text("content2")
|
|
81
|
+
(Path(temp_dir) / "subdir").mkdir()
|
|
82
|
+
|
|
83
|
+
files = safe_list_files(temp_dir)
|
|
84
|
+
assert "file1.txt" in files
|
|
85
|
+
assert "file2.py" in files
|
|
86
|
+
assert len(files) == 2 # Should not include subdirectory
|
|
87
|
+
|
|
88
|
+
def test_safe_list_files_nonexistent_directory(self):
|
|
89
|
+
"""Test listing files in a non-existent directory returns default."""
|
|
90
|
+
files = safe_list_files("nonexistent_directory", default=["default"])
|
|
91
|
+
assert files == ["default"]
|
|
92
|
+
|
|
93
|
+
def test_input_validation_errors(self):
|
|
94
|
+
"""Test that functions raise appropriate errors for invalid inputs."""
|
|
95
|
+
from fishertools.errors.exceptions import SafeUtilityError
|
|
96
|
+
|
|
97
|
+
with pytest.raises(SafeUtilityError, match="не может быть None"):
|
|
98
|
+
safe_read_file(None)
|
|
99
|
+
|
|
100
|
+
with pytest.raises(SafeUtilityError, match="должна быть строкой"):
|
|
101
|
+
safe_read_file("test.txt", encoding=123)
|
|
102
|
+
|
|
103
|
+
with pytest.raises(SafeUtilityError, match="должно быть строкой"):
|
|
104
|
+
safe_write_file("test.txt", 123)
|
tests/test_structure.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for project structure and imports.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TestProjectStructure:
|
|
9
|
+
"""Tests to verify the new project structure works correctly."""
|
|
10
|
+
|
|
11
|
+
def test_main_imports(self):
|
|
12
|
+
"""Test that main fishertools imports work."""
|
|
13
|
+
import fishertools
|
|
14
|
+
|
|
15
|
+
# Test that main API is available
|
|
16
|
+
assert hasattr(fishertools, 'explain_error')
|
|
17
|
+
|
|
18
|
+
# Test that modules are available
|
|
19
|
+
assert hasattr(fishertools, 'errors')
|
|
20
|
+
assert hasattr(fishertools, 'safe')
|
|
21
|
+
assert hasattr(fishertools, 'learn')
|
|
22
|
+
assert hasattr(fishertools, 'legacy')
|
|
23
|
+
|
|
24
|
+
def test_errors_module_imports(self):
|
|
25
|
+
"""Test that errors module imports work."""
|
|
26
|
+
from fishertools.errors import ErrorExplainer, explain_error, ErrorPattern
|
|
27
|
+
from fishertools.errors.models import ErrorExplanation, ExplainerConfig
|
|
28
|
+
|
|
29
|
+
# Test that classes can be instantiated
|
|
30
|
+
explainer = ErrorExplainer()
|
|
31
|
+
assert explainer is not None
|
|
32
|
+
|
|
33
|
+
config = ExplainerConfig()
|
|
34
|
+
assert config is not None
|
|
35
|
+
|
|
36
|
+
def test_safe_module_imports(self):
|
|
37
|
+
"""Test that safe module imports work."""
|
|
38
|
+
from fishertools.safe import safe_get, safe_divide, safe_read_file
|
|
39
|
+
|
|
40
|
+
# Test that functions are callable
|
|
41
|
+
assert callable(safe_get)
|
|
42
|
+
assert callable(safe_divide)
|
|
43
|
+
assert callable(safe_read_file)
|
|
44
|
+
|
|
45
|
+
def test_learn_module_imports(self):
|
|
46
|
+
"""Test that learn module imports work."""
|
|
47
|
+
from fishertools.learn import generate_example, show_best_practice
|
|
48
|
+
|
|
49
|
+
# Test that functions are callable
|
|
50
|
+
assert callable(generate_example)
|
|
51
|
+
assert callable(show_best_practice)
|
|
52
|
+
|
|
53
|
+
def test_legacy_module_imports(self):
|
|
54
|
+
"""Test that legacy module imports work."""
|
|
55
|
+
import fishertools.legacy
|
|
56
|
+
|
|
57
|
+
# Module should be importable
|
|
58
|
+
assert fishertools.legacy is not None
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test the basic structure of fishertools enhancements.
|
|
3
|
+
|
|
4
|
+
This test verifies that all new modules can be imported correctly
|
|
5
|
+
and that the basic interfaces are properly defined.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from hypothesis import given, strategies as st
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestEnhancementStructure:
|
|
13
|
+
"""Test the basic structure of enhancement modules."""
|
|
14
|
+
|
|
15
|
+
def test_learning_module_imports(self):
|
|
16
|
+
"""Test that learning module components can be imported."""
|
|
17
|
+
from fishertools.learning import (
|
|
18
|
+
LearningSystem, TutorialEngine, ProgressSystem,
|
|
19
|
+
InteractiveSessionManager
|
|
20
|
+
)
|
|
21
|
+
from fishertools.learning.models import (
|
|
22
|
+
StepExplanation, InteractiveExercise, LearningProgress,
|
|
23
|
+
TutorialSession, ValidationResult, CodeContext
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Verify classes can be instantiated (basic structure test)
|
|
27
|
+
assert LearningSystem is not None
|
|
28
|
+
assert TutorialEngine is not None
|
|
29
|
+
assert ProgressSystem is not None
|
|
30
|
+
assert InteractiveSessionManager is not None
|
|
31
|
+
|
|
32
|
+
def test_documentation_module_imports(self):
|
|
33
|
+
"""Test that documentation module components can be imported."""
|
|
34
|
+
from fishertools.documentation import (
|
|
35
|
+
DocumentationGenerator, VisualDocumentation, APIGenerator
|
|
36
|
+
)
|
|
37
|
+
from fishertools.documentation.models import (
|
|
38
|
+
APIInfo, FunctionInfo, SphinxDocuments, NavigationTree
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Verify classes can be instantiated (basic structure test)
|
|
42
|
+
assert DocumentationGenerator is not None
|
|
43
|
+
assert VisualDocumentation is not None
|
|
44
|
+
assert APIGenerator is not None
|
|
45
|
+
|
|
46
|
+
def test_examples_module_imports(self):
|
|
47
|
+
"""Test that examples module components can be imported."""
|
|
48
|
+
from fishertools.examples import ExampleRepository
|
|
49
|
+
from fishertools.examples.models import (
|
|
50
|
+
CodeExample, Scenario, ProjectTemplate, LineByLineExplanation
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Verify classes can be instantiated (basic structure test)
|
|
54
|
+
assert ExampleRepository is not None
|
|
55
|
+
|
|
56
|
+
def test_config_module_imports(self):
|
|
57
|
+
"""Test that config module components can be imported."""
|
|
58
|
+
from fishertools.config import ConfigurationManager, ConfigurationParser
|
|
59
|
+
from fishertools.config.models import (
|
|
60
|
+
LearningConfig, ValidationResult, RecoveryAction, ConfigError
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Verify classes can be instantiated (basic structure test)
|
|
64
|
+
assert ConfigurationManager is not None
|
|
65
|
+
assert ConfigurationParser is not None
|
|
66
|
+
|
|
67
|
+
def test_main_package_imports(self):
|
|
68
|
+
"""Test that new modules are accessible from main package."""
|
|
69
|
+
import fishertools
|
|
70
|
+
|
|
71
|
+
# Verify new modules are available
|
|
72
|
+
assert hasattr(fishertools, 'learning')
|
|
73
|
+
assert hasattr(fishertools, 'documentation')
|
|
74
|
+
assert hasattr(fishertools, 'examples')
|
|
75
|
+
assert hasattr(fishertools, 'config')
|
|
76
|
+
|
|
77
|
+
def test_data_models_structure(self):
|
|
78
|
+
"""Test that data models have expected attributes."""
|
|
79
|
+
from fishertools.learning.models import StepExplanation, DifficultyLevel
|
|
80
|
+
from fishertools.config.models import LearningConfig
|
|
81
|
+
|
|
82
|
+
# Test enum values
|
|
83
|
+
assert DifficultyLevel.BEGINNER.value == "beginner"
|
|
84
|
+
assert DifficultyLevel.INTERMEDIATE.value == "intermediate"
|
|
85
|
+
assert DifficultyLevel.ADVANCED.value == "advanced"
|
|
86
|
+
|
|
87
|
+
# Test default config creation
|
|
88
|
+
config = LearningConfig()
|
|
89
|
+
assert config.default_level == "beginner"
|
|
90
|
+
assert config.visual_aids_enabled is True
|
|
91
|
+
assert config.progress_tracking_enabled is True
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class TestHypothesisConfiguration:
|
|
95
|
+
"""Test that Hypothesis is properly configured for property-based testing."""
|
|
96
|
+
|
|
97
|
+
@given(st.text())
|
|
98
|
+
def test_hypothesis_basic_functionality(self, text_input):
|
|
99
|
+
"""Basic test to verify Hypothesis is working."""
|
|
100
|
+
# This is a trivial property test to verify Hypothesis setup
|
|
101
|
+
assert isinstance(text_input, str)
|
|
102
|
+
|
|
103
|
+
@given(st.integers(min_value=1, max_value=100))
|
|
104
|
+
def test_hypothesis_integer_generation(self, number):
|
|
105
|
+
"""Test integer generation for future property tests."""
|
|
106
|
+
assert 1 <= number <= 100
|
|
107
|
+
assert isinstance(number, int)
|
|
108
|
+
|
|
109
|
+
@given(st.lists(st.text(), min_size=0, max_size=10))
|
|
110
|
+
def test_hypothesis_list_generation(self, text_list):
|
|
111
|
+
"""Test list generation for future property tests."""
|
|
112
|
+
assert isinstance(text_list, list)
|
|
113
|
+
assert len(text_list) <= 10
|
|
114
|
+
for item in text_list:
|
|
115
|
+
assert isinstance(item, str)
|