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,204 @@
1
+ """
2
+ Property-based tests for Example Repository quality.
3
+
4
+ Feature: fishertools-enhancements, Property 3: Example Repository Quality
5
+ Validates: Requirements 3.1, 3.2, 3.3, 3.4, 3.5
6
+ """
7
+
8
+ import pytest
9
+ from hypothesis import given, strategies as st, assume
10
+ from fishertools.examples import ExampleRepository
11
+ from fishertools.examples.models import (
12
+ CodeExample, ExampleCategory, ProjectType, Scenario
13
+ )
14
+
15
+
16
+ class TestExampleRepositoryQuality:
17
+ """Property tests for Example Repository quality and completeness."""
18
+
19
+ def test_repository_initialization(self):
20
+ """Test that repository initializes with default examples."""
21
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
22
+ repo = ExampleRepository()
23
+
24
+ # Should have examples for beginners
25
+ list_examples = repo.get_examples_by_topic("lists")
26
+ dict_examples = repo.get_examples_by_topic("dictionaries")
27
+ input_examples = repo.get_examples_by_category(ExampleCategory.USER_INPUT)
28
+
29
+ assert len(list_examples) > 0, "Should have list examples for beginners"
30
+ assert len(dict_examples) > 0, "Should have dictionary examples for beginners"
31
+ assert len(input_examples) > 0, "Should have user input examples for beginners"
32
+
33
+ @given(st.sampled_from(list(ExampleCategory)))
34
+ def test_category_examples_have_required_properties(self, category):
35
+ """Test that all examples in a category have required properties."""
36
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
37
+ repo = ExampleRepository()
38
+ examples = repo.get_examples_by_category(category)
39
+
40
+ for example in examples:
41
+ # All examples should have basic required properties
42
+ assert example.id, "Example should have an ID"
43
+ assert example.title, "Example should have a title"
44
+ assert example.description, "Example should have a description"
45
+ assert example.code, "Example should have code"
46
+ assert example.explanation, "Example should have an explanation"
47
+ assert example.difficulty in ["beginner", "intermediate", "advanced"], \
48
+ "Example should have valid difficulty level"
49
+ assert example.topics, "Example should have topics"
50
+ assert example.category == category, "Example should match requested category"
51
+
52
+ @given(st.text(min_size=1, max_size=20).filter(lambda x: x.strip()))
53
+ def test_search_functionality_completeness(self, query):
54
+ """Test that search finds relevant examples."""
55
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
56
+ repo = ExampleRepository()
57
+
58
+ # Add a test example that should match the query
59
+ test_example = CodeExample(
60
+ id=f"test_{query.lower().replace(' ', '_')}",
61
+ title=f"Example about {query}",
62
+ description=f"This example demonstrates {query}",
63
+ code=f"# Code for {query}\nprint('{query}')",
64
+ explanation=f"This explains {query}",
65
+ difficulty="beginner",
66
+ topics=[query.lower()],
67
+ prerequisites=[],
68
+ category=ExampleCategory.BASIC_SYNTAX
69
+ )
70
+ repo.add_example(test_example)
71
+
72
+ # Search should find the example
73
+ results = repo.search_examples(query)
74
+ found_ids = [ex.id for ex in results]
75
+
76
+ assert test_example.id in found_ids, \
77
+ f"Search for '{query}' should find the matching example"
78
+
79
+ def test_beginner_scenarios_completeness(self):
80
+ """Test that beginner scenarios provide comprehensive learning paths."""
81
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
82
+ repo = ExampleRepository()
83
+ scenarios = repo.get_beginner_scenarios()
84
+
85
+ assert len(scenarios) > 0, "Should have beginner scenarios"
86
+
87
+ for scenario in scenarios:
88
+ assert scenario.difficulty == "beginner", "All scenarios should be beginner level"
89
+ assert scenario.examples, "Scenario should contain examples"
90
+ assert scenario.learning_objectives, "Scenario should have learning objectives"
91
+ assert scenario.estimated_time > 0, "Scenario should have estimated time"
92
+
93
+ # All examples in scenario should be beginner-friendly
94
+ for example in scenario.examples:
95
+ assert example.difficulty == "beginner", \
96
+ "All examples in beginner scenario should be beginner level"
97
+
98
+ @given(st.sampled_from(list(ProjectType)))
99
+ def test_project_templates_have_step_by_step_instructions(self, project_type):
100
+ """Test that project templates provide step-by-step instructions."""
101
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
102
+ repo = ExampleRepository()
103
+ project = repo.create_simple_project(project_type)
104
+
105
+ assert project.project_type == project_type, "Project should match requested type"
106
+ assert project.difficulty == "beginner", "Simple projects should be beginner level"
107
+ assert project.steps, "Project should have steps"
108
+ assert project.final_code, "Project should have final code"
109
+ assert project.estimated_time > 0, "Project should have estimated time"
110
+
111
+ # Each step should have proper structure
112
+ for i, step in enumerate(project.steps):
113
+ assert step.step_number == i + 1, "Steps should be numbered sequentially"
114
+ assert step.title, "Step should have a title"
115
+ assert step.description, "Step should have a description"
116
+
117
+ def test_line_by_line_explanations_completeness(self):
118
+ """Test that line-by-line explanations cover all code lines."""
119
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
120
+ repo = ExampleRepository()
121
+
122
+ # Get a sample example
123
+ examples = repo.get_examples_by_category(ExampleCategory.COLLECTIONS)
124
+ assume(len(examples) > 0)
125
+
126
+ example = examples[0]
127
+ explanation = repo.explain_example_line_by_line(example)
128
+
129
+ # Count non-empty lines in original code
130
+ code_lines = [line for line in example.code.strip().split('\n')]
131
+ explanation_lines = explanation.lines
132
+
133
+ assert len(explanation_lines) == len(code_lines), \
134
+ "Should have explanation for every line of code"
135
+
136
+ assert explanation.example_id == example.id, \
137
+ "Explanation should reference correct example"
138
+ assert explanation.summary, "Explanation should have a summary"
139
+ assert explanation.key_concepts, "Explanation should identify key concepts"
140
+
141
+ # Each line explanation should have required properties
142
+ for line_exp in explanation_lines:
143
+ assert line_exp.line_number > 0, "Line number should be positive"
144
+ assert line_exp.explanation, "Each line should have an explanation"
145
+
146
+ def test_safe_user_input_examples_security(self):
147
+ """Test that user input examples demonstrate safe practices."""
148
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
149
+ repo = ExampleRepository()
150
+ input_examples = repo.get_examples_by_category(ExampleCategory.USER_INPUT)
151
+
152
+ assert len(input_examples) > 0, "Should have user input examples"
153
+
154
+ for example in input_examples:
155
+ code = example.code.lower()
156
+
157
+ # Should demonstrate input validation
158
+ assert 'try:' in code or 'except' in code or 'if' in code, \
159
+ "User input examples should show validation or error handling"
160
+
161
+ # Should use safe input practices
162
+ if 'input(' in code:
163
+ assert '.strip()' in code or 'strip(' in code, \
164
+ "Should demonstrate input cleaning with strip()"
165
+
166
+ def test_collection_examples_cover_basic_operations(self):
167
+ """Test that collection examples cover fundamental operations."""
168
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
169
+ repo = ExampleRepository()
170
+
171
+ # Test list examples
172
+ list_examples = repo.get_examples_by_topic("lists")
173
+ assert len(list_examples) > 0, "Should have list examples"
174
+
175
+ list_code = " ".join([ex.code.lower() for ex in list_examples])
176
+ assert 'append(' in list_code, "List examples should show append operation"
177
+ assert '[' in list_code and ']' in list_code, "List examples should show list creation"
178
+
179
+ # Test dictionary examples
180
+ dict_examples = repo.get_examples_by_topic("dictionaries")
181
+ assert len(dict_examples) > 0, "Should have dictionary examples"
182
+
183
+ dict_code = " ".join([ex.code.lower() for ex in dict_examples])
184
+ assert '{' in dict_code and '}' in dict_code, "Dict examples should show dict creation"
185
+ assert '.get(' in dict_code or 'get(' in dict_code, \
186
+ "Dict examples should show safe access with get()"
187
+
188
+ @given(st.text(min_size=1, max_size=50).filter(lambda x: x.strip()))
189
+ def test_concept_breakdown_provides_simple_steps(self, concept):
190
+ """Test that complex concepts are broken down into simple steps."""
191
+ # Feature: fishertools-enhancements, Property 3: Example Repository Quality
192
+ repo = ExampleRepository()
193
+
194
+ steps = repo.break_down_complex_concept(concept)
195
+
196
+ assert len(steps) > 0, "Should provide breakdown steps for any concept"
197
+ assert all(isinstance(step, str) for step in steps), \
198
+ "All breakdown steps should be strings"
199
+ assert all(len(step.strip()) > 0 for step in steps), \
200
+ "All breakdown steps should have content"
201
+
202
+ # Steps should mention the concept
203
+ concept_mentioned = any(concept.lower() in step.lower() for step in steps)
204
+ assert concept_mentioned, f"Breakdown should mention the concept '{concept}'"
@@ -0,0 +1,303 @@
1
+ """
2
+ Unit tests for specific examples in the Example Repository.
3
+
4
+ Tests security of user input examples, correctness of collection examples,
5
+ and completeness of step-by-step instructions.
6
+ Requirements: 3.2, 3.3
7
+ """
8
+
9
+ import pytest
10
+ from fishertools.examples import ExampleRepository
11
+ from fishertools.examples.models import ExampleCategory, ProjectType
12
+
13
+
14
+ class TestSpecificExamples:
15
+ """Unit tests for specific example scenarios."""
16
+
17
+ def setup_method(self):
18
+ """Set up test fixtures."""
19
+ self.repo = ExampleRepository()
20
+
21
+ def test_user_input_examples_security(self):
22
+ """Test that user input examples demonstrate secure practices."""
23
+ input_examples = self.repo.get_examples_by_category(ExampleCategory.USER_INPUT)
24
+
25
+ # Should have at least one user input example
26
+ assert len(input_examples) > 0
27
+
28
+ # Check the safe input basics example specifically
29
+ safe_input_example = None
30
+ for example in input_examples:
31
+ if "safe_input_basics" in example.id:
32
+ safe_input_example = example
33
+ break
34
+
35
+ assert safe_input_example is not None, "Should have safe input basics example"
36
+
37
+ # Verify security practices in the code
38
+ code = safe_input_example.code
39
+
40
+ # Should use strip() to clean input
41
+ assert ".strip()" in code, "Should demonstrate input cleaning with strip()"
42
+
43
+ # Should use try-except for type conversion
44
+ assert "try:" in code and "except ValueError:" in code, \
45
+ "Should demonstrate error handling for type conversion"
46
+
47
+ # Should validate input ranges
48
+ assert "< 0" in code or "> 0" in code, \
49
+ "Should demonstrate input validation"
50
+
51
+ # Should use loops for input validation
52
+ assert "while True:" in code, \
53
+ "Should demonstrate input validation loops"
54
+
55
+ # Should provide user feedback for invalid input
56
+ assert "Please" in code and ("try again" in code or "enter" in code), \
57
+ "Should provide helpful error messages"
58
+
59
+ def test_list_examples_correctness(self):
60
+ """Test that list examples demonstrate correct operations."""
61
+ list_examples = self.repo.get_examples_by_topic("lists")
62
+
63
+ assert len(list_examples) >= 2, "Should have multiple list examples"
64
+
65
+ # Check basic list example
66
+ basic_example = None
67
+ operations_example = None
68
+
69
+ for example in list_examples:
70
+ if "list_basics" in example.id:
71
+ basic_example = example
72
+ elif "list_operations" in example.id:
73
+ operations_example = example
74
+
75
+ assert basic_example is not None, "Should have basic list example"
76
+ assert operations_example is not None, "Should have list operations example"
77
+
78
+ # Test basic list operations
79
+ basic_code = basic_example.code
80
+ assert "fruits = [" in basic_code, "Should show list creation"
81
+ assert ".append(" in basic_code, "Should show append operation"
82
+ assert ".extend(" in basic_code, "Should show extend operation"
83
+ assert "[0]" in basic_code, "Should show indexing"
84
+ assert "[-1]" in basic_code, "Should show negative indexing"
85
+
86
+ # Test advanced list operations
87
+ ops_code = operations_example.code
88
+ assert ".sort()" in ops_code, "Should show in-place sorting"
89
+ assert "sorted(" in ops_code, "Should show non-destructive sorting"
90
+ assert ".index(" in ops_code, "Should show searching"
91
+ assert ".remove(" in ops_code, "Should show item removal"
92
+ assert ".pop()" in ops_code, "Should show pop operation"
93
+ assert "[x**2 for x in" in ops_code, "Should show list comprehension"
94
+
95
+ def test_dictionary_examples_correctness(self):
96
+ """Test that dictionary examples demonstrate correct operations."""
97
+ dict_examples = self.repo.get_examples_by_topic("dictionaries")
98
+
99
+ assert len(dict_examples) >= 1, "Should have dictionary examples"
100
+
101
+ # Check basic dictionary example
102
+ basic_example = None
103
+ for example in dict_examples:
104
+ if "dict_basics" in example.id:
105
+ basic_example = example
106
+ break
107
+
108
+ assert basic_example is not None, "Should have basic dictionary example"
109
+
110
+ code = basic_example.code
111
+
112
+ # Should demonstrate dictionary creation
113
+ assert "student = {" in code, "Should show dictionary creation"
114
+
115
+ # Should show both direct access and safe access
116
+ assert "student['" in code, "Should show direct key access"
117
+ assert ".get(" in code, "Should show safe access with get()"
118
+
119
+ # Should demonstrate key existence checking
120
+ assert "in student" in code, "Should show key existence checking"
121
+
122
+ # Should show dictionary methods
123
+ assert ".keys()" in code, "Should show keys() method"
124
+ assert ".values()" in code, "Should show values() method"
125
+
126
+ # Should demonstrate adding new key-value pairs
127
+ assert "student['" in code and "=" in code, "Should show adding new keys"
128
+
129
+ def test_project_step_by_step_completeness(self):
130
+ """Test that project templates have complete step-by-step instructions."""
131
+ calculator_project = self.repo.create_simple_project(ProjectType.CALCULATOR)
132
+
133
+ # Should have proper project structure
134
+ assert calculator_project.title, "Project should have a title"
135
+ assert calculator_project.description, "Project should have a description"
136
+ assert calculator_project.difficulty == "beginner", "Should be beginner level"
137
+ assert calculator_project.estimated_time > 0, "Should have estimated time"
138
+
139
+ # Should have multiple steps
140
+ assert len(calculator_project.steps) >= 2, "Should have multiple steps"
141
+
142
+ # Check first step (function definitions)
143
+ first_step = calculator_project.steps[0]
144
+ assert first_step.step_number == 1, "First step should be numbered 1"
145
+ assert "function" in first_step.title.lower(), "First step should be about functions"
146
+ assert first_step.code_snippet, "Step should have code snippet"
147
+ assert first_step.explanation, "Step should have explanation"
148
+ assert first_step.hints, "Step should have hints"
149
+
150
+ # Code should include basic arithmetic functions
151
+ code = first_step.code_snippet
152
+ assert "def add(" in code, "Should define add function"
153
+ assert "def subtract(" in code, "Should define subtract function"
154
+ assert "def multiply(" in code, "Should define multiply function"
155
+ assert "def divide(" in code, "Should define divide function"
156
+ assert "if b == 0:" in code, "Should handle division by zero"
157
+
158
+ # Check second step (main loop)
159
+ second_step = calculator_project.steps[1]
160
+ assert second_step.step_number == 2, "Second step should be numbered 2"
161
+ assert "loop" in second_step.title.lower() or "main" in second_step.title.lower(), \
162
+ "Second step should be about main loop"
163
+
164
+ main_code = second_step.code_snippet
165
+ assert "while True:" in main_code, "Should have main loop"
166
+ assert "input(" in main_code, "Should get user input"
167
+ assert "try:" in main_code and "except" in main_code, \
168
+ "Should handle input errors"
169
+ assert "quit" in main_code.lower(), "Should allow user to quit"
170
+
171
+ # Final code should be complete and runnable
172
+ final_code = calculator_project.final_code
173
+ assert "def add(" in final_code, "Final code should include all functions"
174
+ assert "def calculator(" in final_code, "Final code should include main function"
175
+ assert "if __name__" in final_code, "Final code should have main guard"
176
+
177
+ # Should have extension suggestions
178
+ assert calculator_project.extensions, "Should suggest extensions"
179
+ assert len(calculator_project.extensions) > 0, "Should have extension ideas"
180
+
181
+ def test_line_by_line_explanation_accuracy(self):
182
+ """Test that line-by-line explanations are accurate and helpful."""
183
+ # Get a specific example to test
184
+ list_examples = self.repo.get_examples_by_topic("lists")
185
+ basic_example = None
186
+
187
+ for example in list_examples:
188
+ if "list_basics" in example.id:
189
+ basic_example = example
190
+ break
191
+
192
+ assert basic_example is not None, "Should have basic list example"
193
+
194
+ # Generate line-by-line explanation
195
+ explanation = self.repo.explain_example_line_by_line(basic_example)
196
+
197
+ # Should have explanation for each line
198
+ code_lines = basic_example.code.strip().split('\n')
199
+ assert len(explanation.lines) == len(code_lines), \
200
+ "Should have explanation for each line"
201
+
202
+ # Check specific line explanations
203
+ explanations_text = [line.explanation.lower() for line in explanation.lines]
204
+
205
+ # Should identify list creation
206
+ list_creation_found = any("list" in exp and ("create" in exp or "assign" in exp)
207
+ for exp in explanations_text)
208
+ assert list_creation_found, "Should identify list creation"
209
+
210
+ # Should identify indexing
211
+ indexing_found = any("index" in exp or "access" in exp
212
+ for exp in explanations_text)
213
+ assert indexing_found, "Should identify indexing operations"
214
+
215
+ # Should identify method calls
216
+ method_found = any(("append" in exp or "extend" in exp or
217
+ ("adds" in exp and ("item" in exp or "multiple" in exp)))
218
+ for exp in explanations_text)
219
+ assert method_found, "Should identify method calls"
220
+
221
+ # Summary should be comprehensive
222
+ summary = explanation.summary.lower()
223
+ assert "list" in summary, "Summary should mention lists"
224
+ assert len(explanation.key_concepts) > 0, "Should identify key concepts"
225
+ assert "lists" in explanation.key_concepts, "Should identify lists as key concept"
226
+
227
+ def test_concept_breakdown_accuracy(self):
228
+ """Test that concept breakdowns are accurate and educational."""
229
+ # Test specific concept breakdowns
230
+ list_comp_breakdown = self.repo.break_down_complex_concept("list comprehension")
231
+
232
+ assert len(list_comp_breakdown) >= 3, "Should have multiple breakdown steps"
233
+
234
+ breakdown_text = " ".join(list_comp_breakdown).lower()
235
+ assert "list comprehension" in breakdown_text, "Should mention the concept"
236
+ assert "expression" in breakdown_text, "Should explain expression part"
237
+ assert "iterable" in breakdown_text, "Should explain iterable part"
238
+ assert "for" in breakdown_text, "Should mention for loop connection"
239
+
240
+ # Test exception handling breakdown
241
+ exception_breakdown = self.repo.break_down_complex_concept("exception handling")
242
+
243
+ exception_text = " ".join(exception_breakdown).lower()
244
+ assert "exception" in exception_text or "error" in exception_text, \
245
+ "Should mention exceptions or errors"
246
+ assert "try" in exception_text, "Should mention try blocks"
247
+ assert "except" in exception_text, "Should mention except blocks"
248
+
249
+ # Test prerequisites
250
+ list_comp_prereqs = self.repo.get_concept_prerequisites("list comprehension")
251
+ assert "lists" in list_comp_prereqs, "List comprehension should require lists knowledge"
252
+ assert "for loops" in list_comp_prereqs, "List comprehension should require loop knowledge"
253
+
254
+ def test_search_functionality_specific_cases(self):
255
+ """Test search functionality with specific queries."""
256
+ # Search for lists
257
+ list_results = self.repo.search_examples("list")
258
+ assert len(list_results) > 0, "Should find list examples"
259
+
260
+ # All results should be relevant to lists
261
+ for result in list_results:
262
+ result_text = (result.title + " " + result.description + " " +
263
+ " ".join(result.topics) + " " + result.code).lower()
264
+ assert "list" in result_text, "Search results should be relevant"
265
+
266
+ # Search for dictionaries
267
+ dict_results = self.repo.search_examples("dictionary")
268
+ assert len(dict_results) > 0, "Should find dictionary examples"
269
+
270
+ # Search with category filter
271
+ input_results = self.repo.search_examples("input", ExampleCategory.USER_INPUT)
272
+ assert len(input_results) > 0, "Should find input examples in USER_INPUT category"
273
+
274
+ for result in input_results:
275
+ assert result.category == ExampleCategory.USER_INPUT, \
276
+ "Filtered results should match category"
277
+
278
+ def test_example_safety_and_best_practices(self):
279
+ """Test that examples follow safety and best practices."""
280
+ all_examples = []
281
+ for category in ExampleCategory:
282
+ all_examples.extend(self.repo.get_examples_by_category(category))
283
+
284
+ assert len(all_examples) > 0, "Should have examples to test"
285
+
286
+ for example in all_examples:
287
+ code = example.code
288
+
289
+ # Should not use dangerous practices
290
+ assert "eval(" not in code, "Examples should not use eval()"
291
+ assert "exec(" not in code, "Examples should not use exec()"
292
+
293
+ # Input examples should be safe
294
+ if example.category == ExampleCategory.USER_INPUT:
295
+ if "input(" in code:
296
+ # Should validate or clean input
297
+ assert (".strip()" in code or "try:" in code or
298
+ "if " in code), "Input examples should validate input"
299
+
300
+ # Should have proper error handling where needed for user input
301
+ if ("int(" in code or "float(" in code) and "input(" in code:
302
+ assert ("try:" in code and "except" in code), \
303
+ "Type conversion of user input should have error handling"