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,770 @@
1
+ """
2
+ Repository for managing code examples and learning scenarios.
3
+ """
4
+
5
+ from typing import List, Optional, Dict
6
+ from .models import (
7
+ CodeExample, Scenario, ProjectTemplate, LineByLineExplanation,
8
+ ExampleCategory, ProjectType
9
+ )
10
+
11
+
12
+ class ExampleRepository:
13
+ """
14
+ Manages collections of examples and scenarios for Python beginners.
15
+
16
+ Provides categorized examples with step-by-step explanations
17
+ and simple project templates.
18
+ """
19
+
20
+ def __init__(self, examples_dir: Optional[str] = None):
21
+ """
22
+ Initialize the example repository.
23
+
24
+ Args:
25
+ examples_dir: Optional directory containing example files
26
+ """
27
+ self.examples_dir = examples_dir
28
+ self._examples: Dict[str, CodeExample] = {}
29
+ self._scenarios: Dict[str, Scenario] = {}
30
+ self._projects: Dict[str, ProjectTemplate] = {}
31
+ self._initialize_default_examples()
32
+ self._initialize_default_scenarios()
33
+ self._initialize_default_projects()
34
+
35
+ def get_examples_by_topic(self, topic: str) -> List[CodeExample]:
36
+ """
37
+ Get all examples for a specific topic.
38
+
39
+ Args:
40
+ topic: Topic name (e.g., "lists", "dictionaries", "functions")
41
+
42
+ Returns:
43
+ List[CodeExample]: Examples matching the topic
44
+ """
45
+ return [
46
+ example for example in self._examples.values()
47
+ if topic.lower() in [t.lower() for t in example.topics]
48
+ ]
49
+
50
+ def get_examples_by_category(self, category: ExampleCategory) -> List[CodeExample]:
51
+ """
52
+ Get all examples in a specific category.
53
+
54
+ Args:
55
+ category: Example category
56
+
57
+ Returns:
58
+ List[CodeExample]: Examples in the category
59
+ """
60
+ return [
61
+ example for example in self._examples.values()
62
+ if example.category == category
63
+ ]
64
+
65
+ def get_beginner_scenarios(self) -> List[Scenario]:
66
+ """
67
+ Get all scenarios suitable for beginners.
68
+
69
+ Returns:
70
+ List[Scenario]: Beginner-friendly scenarios
71
+ """
72
+ return [
73
+ scenario for scenario in self._scenarios.values()
74
+ if scenario.difficulty == "beginner"
75
+ ]
76
+
77
+ def create_simple_project(self, project_type: ProjectType) -> ProjectTemplate:
78
+ """
79
+ Create a simple project template with step-by-step instructions.
80
+
81
+ Args:
82
+ project_type: Type of project to create
83
+
84
+ Returns:
85
+ ProjectTemplate: Project template with instructions
86
+ """
87
+ project_id = f"{project_type.value}_project"
88
+ if project_id in self._projects:
89
+ return self._projects[project_id]
90
+
91
+ # If project doesn't exist, create a basic template
92
+ from .models import ProjectStep
93
+
94
+ basic_step = ProjectStep(
95
+ step_number=1,
96
+ title=f"Create {project_type.value}",
97
+ description=f"Basic {project_type.value} implementation",
98
+ code_snippet="# Add your code here",
99
+ explanation="This is a placeholder project template"
100
+ )
101
+
102
+ return ProjectTemplate(
103
+ id=project_id,
104
+ title=f"Simple {project_type.value.replace('_', ' ').title()}",
105
+ description=f"A beginner-friendly {project_type.value} project",
106
+ project_type=project_type,
107
+ difficulty="beginner",
108
+ estimated_time=30,
109
+ steps=[basic_step],
110
+ final_code="# Complete implementation"
111
+ )
112
+
113
+ def explain_example_line_by_line(self, example: CodeExample) -> LineByLineExplanation:
114
+ """
115
+ Generate line-by-line explanation for a code example.
116
+
117
+ Args:
118
+ example: Code example to explain
119
+
120
+ Returns:
121
+ LineByLineExplanation: Detailed line-by-line explanation
122
+ """
123
+ from .models import LineExplanation
124
+
125
+ lines = example.code.strip().split('\n')
126
+ line_explanations = []
127
+ key_concepts = set()
128
+
129
+ for i, line in enumerate(lines, 1):
130
+ stripped_line = line.strip()
131
+
132
+ # Skip empty lines and comments (but still include them)
133
+ if not stripped_line or stripped_line.startswith('#'):
134
+ if stripped_line.startswith('#'):
135
+ explanation = "This is a comment that explains the code"
136
+ concepts = ["comments"]
137
+ else:
138
+ explanation = "Empty line for readability"
139
+ concepts = []
140
+ else:
141
+ explanation, concepts = self._analyze_code_line(stripped_line)
142
+
143
+ line_explanations.append(LineExplanation(
144
+ line_number=i,
145
+ code=line,
146
+ explanation=explanation,
147
+ concepts=concepts
148
+ ))
149
+
150
+ key_concepts.update(concepts)
151
+
152
+ # Generate summary based on key concepts
153
+ summary = self._generate_explanation_summary(example, list(key_concepts))
154
+
155
+ return LineByLineExplanation(
156
+ example_id=example.id,
157
+ title=f"Line-by-line: {example.title}",
158
+ lines=line_explanations,
159
+ summary=summary,
160
+ key_concepts=list(key_concepts)
161
+ )
162
+
163
+ def _analyze_code_line(self, line: str) -> tuple[str, List[str]]:
164
+ """
165
+ Analyze a single line of code and generate explanation.
166
+
167
+ Args:
168
+ line: Code line to analyze
169
+
170
+ Returns:
171
+ tuple: (explanation, concepts)
172
+ """
173
+ concepts = []
174
+
175
+ # Variable assignment
176
+ if '=' in line and not any(op in line for op in ['==', '!=', '<=', '>=']):
177
+ if line.count('=') == 1 and '=' not in line.replace('=', ''):
178
+ concepts.append("variable assignment")
179
+ var_name = line.split('=')[0].strip()
180
+ if '[' in line and ']' in line:
181
+ concepts.append("lists")
182
+ if line.count('[') == 1 and line.count(']') == 1 and not line.endswith(']'):
183
+ # This is indexing, not list creation
184
+ concepts.extend(["indexing", "list access"])
185
+ explanation = f"Accesses an element from a list using indexing and assigns it to '{var_name}'"
186
+ else:
187
+ explanation = f"Creates a list and assigns it to variable '{var_name}'"
188
+ elif '{' in line and '}' in line:
189
+ concepts.append("dictionaries")
190
+ explanation = f"Creates a dictionary and assigns it to variable '{var_name}'"
191
+ elif 'input(' in line:
192
+ concepts.append("user input")
193
+ explanation = f"Gets input from user and stores it in variable '{var_name}'"
194
+ elif '(' in line and ')' in line:
195
+ concepts.append("function calls")
196
+ explanation = f"Calls a function and assigns the result to '{var_name}'"
197
+ else:
198
+ explanation = f"Assigns a value to variable '{var_name}'"
199
+
200
+ # Function definitions
201
+ elif line.startswith('def '):
202
+ concepts.extend(["functions", "function definition"])
203
+ func_name = line.split('(')[0].replace('def ', '').strip()
204
+ explanation = f"Defines a function named '{func_name}'"
205
+
206
+ # Function calls
207
+ elif '(' in line and ')' in line and not line.startswith('def'):
208
+ concepts.append("function calls")
209
+ if 'print(' in line:
210
+ concepts.append("output")
211
+ explanation = "Prints output to the console"
212
+ elif 'input(' in line:
213
+ concepts.append("user input")
214
+ explanation = "Gets input from the user"
215
+ elif '.append(' in line:
216
+ concepts.extend(["lists", "list methods"])
217
+ explanation = "Adds an item to the end of a list"
218
+ elif '.extend(' in line:
219
+ concepts.extend(["lists", "list methods"])
220
+ explanation = "Adds multiple items to the end of a list"
221
+ elif '.get(' in line:
222
+ concepts.extend(["dictionaries", "dict methods"])
223
+ explanation = "Safely gets a value from a dictionary"
224
+ elif 'int(' in line or 'float(' in line or 'str(' in line:
225
+ concepts.append("type conversion")
226
+ explanation = "Converts a value to a different data type"
227
+ else:
228
+ explanation = "Calls a function to perform an operation"
229
+
230
+ # Control structures
231
+ elif line.startswith('if '):
232
+ concepts.extend(["conditionals", "if statements"])
233
+ explanation = "Checks a condition and executes code if it's true"
234
+ elif line.startswith('elif '):
235
+ concepts.extend(["conditionals", "elif statements"])
236
+ explanation = "Checks an alternative condition"
237
+ elif line.startswith('else:'):
238
+ concepts.extend(["conditionals", "else statements"])
239
+ explanation = "Executes when no previous conditions were true"
240
+ elif line.startswith('while '):
241
+ concepts.extend(["loops", "while loops"])
242
+ explanation = "Repeats code while a condition is true"
243
+ elif line.startswith('for '):
244
+ concepts.extend(["loops", "for loops"])
245
+ explanation = "Repeats code for each item in a sequence"
246
+
247
+ # Exception handling
248
+ elif line.startswith('try:'):
249
+ concepts.extend(["error handling", "try-except"])
250
+ explanation = "Starts a block that might cause an error"
251
+ elif line.startswith('except'):
252
+ concepts.extend(["error handling", "try-except"])
253
+ explanation = "Handles errors that occur in the try block"
254
+
255
+ # Return statements
256
+ elif line.startswith('return '):
257
+ concepts.extend(["functions", "return statements"])
258
+ explanation = "Returns a value from the function"
259
+
260
+ # Import statements
261
+ elif line.startswith('import ') or line.startswith('from '):
262
+ concepts.append("imports")
263
+ explanation = "Imports code from another module"
264
+
265
+ # Default case
266
+ else:
267
+ explanation = "Executes a Python statement"
268
+
269
+ return explanation, concepts
270
+
271
+ def _generate_explanation_summary(self, example: CodeExample, key_concepts: List[str]) -> str:
272
+ """
273
+ Generate a summary of the code explanation.
274
+
275
+ Args:
276
+ example: The code example
277
+ key_concepts: List of key concepts found in the code
278
+
279
+ Returns:
280
+ str: Summary explanation
281
+ """
282
+ concept_descriptions = {
283
+ "variable assignment": "storing values in variables",
284
+ "lists": "working with ordered collections",
285
+ "dictionaries": "using key-value data structures",
286
+ "functions": "defining and calling reusable code blocks",
287
+ "conditionals": "making decisions with if/else statements",
288
+ "loops": "repeating code execution",
289
+ "user input": "getting data from users",
290
+ "error handling": "managing potential errors gracefully",
291
+ "output": "displaying results to users"
292
+ }
293
+
294
+ if not key_concepts:
295
+ return f"This example demonstrates basic Python syntax: {example.description}"
296
+
297
+ # Get descriptions for found concepts
298
+ found_descriptions = []
299
+ for concept in key_concepts:
300
+ if concept in concept_descriptions:
301
+ found_descriptions.append(concept_descriptions[concept])
302
+
303
+ if found_descriptions:
304
+ concepts_text = ", ".join(found_descriptions[:-1])
305
+ if len(found_descriptions) > 1:
306
+ concepts_text += f", and {found_descriptions[-1]}"
307
+ else:
308
+ concepts_text = found_descriptions[0]
309
+
310
+ return f"This example demonstrates {concepts_text}. {example.description}"
311
+ else:
312
+ return f"This example shows various Python programming concepts. {example.description}"
313
+
314
+ def break_down_complex_concept(self, concept: str, context: str = "") -> List[str]:
315
+ """
316
+ Break down complex programming concepts into simple steps.
317
+
318
+ Args:
319
+ concept: The complex concept to break down
320
+ context: Additional context about how the concept is used
321
+
322
+ Returns:
323
+ List[str]: List of simple explanation steps
324
+ """
325
+ concept_breakdowns = {
326
+ "list comprehension": [
327
+ "List comprehension is a concise way to create lists",
328
+ "It follows the pattern: [expression for item in iterable]",
329
+ "The expression is applied to each item in the iterable",
330
+ "The results are collected into a new list",
331
+ "It's equivalent to using a for loop but more compact"
332
+ ],
333
+
334
+ "dictionary comprehension": [
335
+ "Dictionary comprehension creates dictionaries in one line",
336
+ "It follows the pattern: {key: value for item in iterable}",
337
+ "Each item in the iterable generates a key-value pair",
338
+ "The result is a new dictionary with all the pairs",
339
+ "It's more efficient than using loops to build dictionaries"
340
+ ],
341
+
342
+ "exception handling": [
343
+ "Exception handling prevents programs from crashing",
344
+ "Use 'try:' to mark code that might cause an error",
345
+ "Use 'except:' to specify what to do if an error occurs",
346
+ "The program continues running after handling the error",
347
+ "Always handle specific exceptions when possible"
348
+ ],
349
+
350
+ "function parameters": [
351
+ "Functions can accept input values called parameters",
352
+ "Parameters are defined in parentheses after the function name",
353
+ "When calling the function, you provide arguments for each parameter",
354
+ "The function uses these values to perform its task",
355
+ "Parameters make functions flexible and reusable"
356
+ ],
357
+
358
+ "loops with conditions": [
359
+ "Loops can include conditions to control execution",
360
+ "Use 'if' statements inside loops to check conditions",
361
+ "Use 'continue' to skip the rest of the current iteration",
362
+ "Use 'break' to exit the loop completely",
363
+ "This allows for more complex loop behavior"
364
+ ],
365
+
366
+ "nested data structures": [
367
+ "Data structures can contain other data structures",
368
+ "Lists can contain other lists (nested lists)",
369
+ "Dictionaries can contain lists or other dictionaries",
370
+ "Access nested elements using multiple brackets or keys",
371
+ "This allows for organizing complex data hierarchically"
372
+ ]
373
+ }
374
+
375
+ # Return breakdown if available, otherwise create a generic one
376
+ if concept.lower() in concept_breakdowns:
377
+ return concept_breakdowns[concept.lower()]
378
+
379
+ # Generic breakdown for unknown concepts
380
+ return [
381
+ f"The concept '{concept}' is an important programming idea",
382
+ f"It helps solve specific problems in your code",
383
+ f"Understanding {concept} will make you a better programmer",
384
+ f"Practice using {concept} in different situations",
385
+ f"Look for examples of {concept} in real code"
386
+ ]
387
+
388
+ def get_concept_prerequisites(self, concept: str) -> List[str]:
389
+ """
390
+ Get the prerequisites needed to understand a concept.
391
+
392
+ Args:
393
+ concept: The concept to check prerequisites for
394
+
395
+ Returns:
396
+ List[str]: List of prerequisite concepts
397
+ """
398
+ prerequisites_map = {
399
+ "list comprehension": ["lists", "for loops", "expressions"],
400
+ "dictionary comprehension": ["dictionaries", "for loops", "key-value pairs"],
401
+ "exception handling": ["functions", "conditionals"],
402
+ "nested loops": ["for loops", "while loops", "indentation"],
403
+ "function parameters": ["functions", "variables"],
404
+ "lambda functions": ["functions", "expressions"],
405
+ "file operations": ["strings", "exception handling"],
406
+ "class methods": ["classes", "functions", "self parameter"]
407
+ }
408
+
409
+ return prerequisites_map.get(concept.lower(), [])
410
+
411
+ def add_example(self, example: CodeExample) -> None:
412
+ """
413
+ Add a new example to the repository.
414
+
415
+ Args:
416
+ example: Code example to add
417
+ """
418
+ self._examples[example.id] = example
419
+
420
+ def search_examples(self, query: str, category: Optional[ExampleCategory] = None) -> List[CodeExample]:
421
+ """
422
+ Search for examples matching a query.
423
+
424
+ Args:
425
+ query: Search query
426
+ category: Optional category filter
427
+
428
+ Returns:
429
+ List[CodeExample]: Matching examples
430
+ """
431
+ query_lower = query.lower()
432
+ results = []
433
+
434
+ for example in self._examples.values():
435
+ # Filter by category if specified
436
+ if category and example.category != category:
437
+ continue
438
+
439
+ # Search in title, description, topics, and code
440
+ if (query_lower in example.title.lower() or
441
+ query_lower in example.description.lower() or
442
+ any(query_lower in topic.lower() for topic in example.topics) or
443
+ query_lower in example.code.lower() or
444
+ # Handle plural/singular variations
445
+ (query_lower.endswith('s') and query_lower[:-1] in example.title.lower()) or
446
+ (query_lower.endswith('s') and any(query_lower[:-1] in topic.lower() for topic in example.topics)) or
447
+ (not query_lower.endswith('s') and (query_lower + 's') in example.title.lower()) or
448
+ (not query_lower.endswith('s') and any((query_lower + 's') in topic.lower() for topic in example.topics))):
449
+ results.append(example)
450
+
451
+ return results
452
+
453
+ def _initialize_default_examples(self) -> None:
454
+ """Initialize repository with default examples for beginners."""
455
+ from .models import ProjectStep
456
+
457
+ # List examples
458
+ list_examples = [
459
+ CodeExample(
460
+ id="list_basics",
461
+ title="Working with Lists - Basics",
462
+ description="Learn how to create, access, and modify lists",
463
+ code="""# Creating lists
464
+ fruits = ['apple', 'banana', 'orange']
465
+ numbers = [1, 2, 3, 4, 5]
466
+
467
+ # Accessing elements
468
+ first_fruit = fruits[0] # 'apple'
469
+ last_number = numbers[-1] # 5
470
+
471
+ # Adding elements
472
+ fruits.append('grape')
473
+ numbers.extend([6, 7])
474
+
475
+ # Modifying elements
476
+ fruits[1] = 'blueberry'
477
+
478
+ print(f"Fruits: {fruits}")
479
+ print(f"Numbers: {numbers}")""",
480
+ explanation="Lists are ordered collections that can store multiple items. You can access items by index, add new items, and modify existing ones.",
481
+ difficulty="beginner",
482
+ topics=["lists", "indexing", "append", "extend"],
483
+ prerequisites=[],
484
+ category=ExampleCategory.COLLECTIONS,
485
+ expected_output="Fruits: ['apple', 'blueberry', 'orange', 'grape']\nNumbers: [1, 2, 3, 4, 5, 6, 7]",
486
+ common_mistakes=["Using 1-based indexing instead of 0-based", "Forgetting that negative indices count from the end"]
487
+ ),
488
+
489
+ CodeExample(
490
+ id="list_operations",
491
+ title="List Operations and Methods",
492
+ description="Common list operations like sorting, searching, and removing items",
493
+ code="""# Sample list
494
+ numbers = [3, 1, 4, 1, 5, 9, 2, 6]
495
+
496
+ # Sorting
497
+ sorted_numbers = sorted(numbers) # Creates new list
498
+ numbers.sort() # Modifies original list
499
+
500
+ # Searching
501
+ if 5 in numbers:
502
+ position = numbers.index(5)
503
+ print(f"Found 5 at position {position}")
504
+
505
+ # Removing items
506
+ numbers.remove(1) # Removes first occurrence
507
+ last_item = numbers.pop() # Removes and returns last item
508
+
509
+ # List comprehension
510
+ squares = [x**2 for x in range(1, 6)]
511
+
512
+ print(f"Sorted: {sorted_numbers}")
513
+ print(f"Modified: {numbers}")
514
+ print(f"Squares: {squares}")""",
515
+ explanation="Lists have many built-in methods for common operations. Understanding the difference between methods that modify the list and those that return new lists is important.",
516
+ difficulty="beginner",
517
+ topics=["lists", "sorting", "searching", "list comprehension"],
518
+ prerequisites=["list_basics"],
519
+ category=ExampleCategory.COLLECTIONS,
520
+ expected_output="Found 5 at position 4\nSorted: [1, 1, 2, 3, 4, 5, 6, 9]\nModified: [1, 2, 3, 4, 5, 9]\nSquares: [1, 4, 9, 16, 25]",
521
+ common_mistakes=["Confusing sort() and sorted()", "Using remove() when item might not exist"]
522
+ )
523
+ ]
524
+
525
+ # Dictionary examples
526
+ dict_examples = [
527
+ CodeExample(
528
+ id="dict_basics",
529
+ title="Working with Dictionaries - Basics",
530
+ description="Learn how to create, access, and modify dictionaries",
531
+ code="""# Creating dictionaries
532
+ student = {
533
+ 'name': 'Alice',
534
+ 'age': 20,
535
+ 'grade': 'A',
536
+ 'courses': ['Math', 'Physics']
537
+ }
538
+
539
+ # Accessing values
540
+ name = student['name']
541
+ age = student.get('age', 0) # Safe access with default
542
+
543
+ # Adding/modifying values
544
+ student['email'] = 'alice@example.com'
545
+ student['age'] = 21
546
+
547
+ # Checking if key exists
548
+ if 'grade' in student:
549
+ print(f"{name} has grade: {student['grade']}")
550
+
551
+ # Getting all keys, values, items
552
+ print(f"Keys: {list(student.keys())}")
553
+ print(f"Values: {list(student.values())}")""",
554
+ explanation="Dictionaries store key-value pairs and provide fast lookup by key. Use get() for safe access to avoid KeyError.",
555
+ difficulty="beginner",
556
+ topics=["dictionaries", "dictionary", "key-value pairs", "get method"],
557
+ prerequisites=[],
558
+ category=ExampleCategory.COLLECTIONS,
559
+ expected_output="Alice has grade: A\nKeys: ['name', 'age', 'grade', 'courses', 'email']\nValues: ['Alice', 21, 'A', ['Math', 'Physics'], 'alice@example.com']",
560
+ common_mistakes=["Using [] instead of get() for optional keys", "Trying to access non-existent keys"]
561
+ )
562
+ ]
563
+
564
+ # User input examples
565
+ input_examples = [
566
+ CodeExample(
567
+ id="safe_input_basics",
568
+ title="Safe User Input - Basics",
569
+ description="Learn how to safely get and validate user input",
570
+ code="""# Getting basic input
571
+ name = input("Enter your name: ").strip()
572
+
573
+ # Getting and validating numeric input
574
+ while True:
575
+ try:
576
+ age = int(input("Enter your age: "))
577
+ if age < 0:
578
+ print("Age cannot be negative. Please try again.")
579
+ continue
580
+ break
581
+ except ValueError:
582
+ print("Please enter a valid number.")
583
+
584
+ # Getting yes/no input
585
+ while True:
586
+ choice = input("Do you want to continue? (y/n): ").lower().strip()
587
+ if choice in ['y', 'yes']:
588
+ print("Continuing...")
589
+ break
590
+ elif choice in ['n', 'no']:
591
+ print("Stopping...")
592
+ break
593
+ else:
594
+ print("Please enter 'y' or 'n'.")
595
+
596
+ print(f"Hello {name}, you are {age} years old.")""",
597
+ explanation="Always validate user input to prevent errors. Use try-except for type conversion and loops for validation.",
598
+ difficulty="beginner",
599
+ topics=["input", "validation", "try-except", "loops"],
600
+ prerequisites=[],
601
+ category=ExampleCategory.USER_INPUT,
602
+ expected_output="# Output depends on user input",
603
+ common_mistakes=["Not validating input", "Not handling ValueError", "Not stripping whitespace"]
604
+ )
605
+ ]
606
+
607
+ # Add all examples to repository
608
+ for example in list_examples + dict_examples + input_examples:
609
+ self._examples[example.id] = example
610
+
611
+ def _initialize_default_scenarios(self) -> None:
612
+ """Initialize repository with default learning scenarios."""
613
+ # Collections scenario
614
+ collections_scenario = Scenario(
615
+ id="collections_basics",
616
+ title="Python Collections Fundamentals",
617
+ description="Learn the basics of working with lists and dictionaries",
618
+ examples=[self._examples["list_basics"], self._examples["dict_basics"]],
619
+ learning_objectives=[
620
+ "Understand how to create and use lists",
621
+ "Learn dictionary key-value operations",
622
+ "Practice safe data access patterns"
623
+ ],
624
+ difficulty="beginner",
625
+ estimated_time=45
626
+ )
627
+
628
+ self._scenarios[collections_scenario.id] = collections_scenario
629
+
630
+ def _initialize_default_projects(self) -> None:
631
+ """Initialize repository with default project templates."""
632
+ from .models import ProjectStep
633
+
634
+ # Calculator project
635
+ calculator_steps = [
636
+ ProjectStep(
637
+ step_number=1,
638
+ title="Create basic calculator functions",
639
+ description="Define functions for basic arithmetic operations",
640
+ code_snippet="""def add(a, b):
641
+ return a + b
642
+
643
+ def subtract(a, b):
644
+ return a - b
645
+
646
+ def multiply(a, b):
647
+ return a * b
648
+
649
+ def divide(a, b):
650
+ if b == 0:
651
+ return "Error: Cannot divide by zero"
652
+ return a / b""",
653
+ explanation="Start by creating simple functions for each operation. Notice the error handling for division by zero.",
654
+ hints=["Remember to handle division by zero", "Keep functions simple and focused"]
655
+ ),
656
+
657
+ ProjectStep(
658
+ step_number=2,
659
+ title="Create the main calculator loop",
660
+ description="Build the user interface and input handling",
661
+ code_snippet="""def calculator():
662
+ print("Simple Calculator")
663
+ print("Operations: +, -, *, /")
664
+ print("Type 'quit' to exit")
665
+
666
+ while True:
667
+ try:
668
+ # Get first number
669
+ first = input("Enter first number (or 'quit'): ")
670
+ if first.lower() == 'quit':
671
+ break
672
+ first = float(first)
673
+
674
+ # Get operation
675
+ operation = input("Enter operation (+, -, *, /): ")
676
+ if operation not in ['+', '-', '*', '/']:
677
+ print("Invalid operation!")
678
+ continue
679
+
680
+ # Get second number
681
+ second = float(input("Enter second number: "))
682
+
683
+ # Calculate result
684
+ if operation == '+':
685
+ result = add(first, second)
686
+ elif operation == '-':
687
+ result = subtract(first, second)
688
+ elif operation == '*':
689
+ result = multiply(first, second)
690
+ elif operation == '/':
691
+ result = divide(first, second)
692
+
693
+ print(f"Result: {result}")
694
+
695
+ except ValueError:
696
+ print("Please enter valid numbers!")
697
+
698
+ # Run the calculator
699
+ calculator()""",
700
+ explanation="The main loop handles user input, validates operations, and calls the appropriate function.",
701
+ hints=["Use try-except for input validation", "Provide clear error messages", "Allow users to exit gracefully"]
702
+ )
703
+ ]
704
+
705
+ calculator_project = ProjectTemplate(
706
+ id="calculator_project",
707
+ title="Simple Calculator",
708
+ description="Build a basic calculator that performs arithmetic operations",
709
+ project_type=ProjectType.CALCULATOR,
710
+ difficulty="beginner",
711
+ estimated_time=60,
712
+ steps=calculator_steps,
713
+ final_code="""def add(a, b):
714
+ return a + b
715
+
716
+ def subtract(a, b):
717
+ return a - b
718
+
719
+ def multiply(a, b):
720
+ return a * b
721
+
722
+ def divide(a, b):
723
+ if b == 0:
724
+ return "Error: Cannot divide by zero"
725
+ return a / b
726
+
727
+ def calculator():
728
+ print("Simple Calculator")
729
+ print("Operations: +, -, *, /")
730
+ print("Type 'quit' to exit")
731
+
732
+ while True:
733
+ try:
734
+ first = input("Enter first number (or 'quit'): ")
735
+ if first.lower() == 'quit':
736
+ break
737
+ first = float(first)
738
+
739
+ operation = input("Enter operation (+, -, *, /): ")
740
+ if operation not in ['+', '-', '*', '/']:
741
+ print("Invalid operation!")
742
+ continue
743
+
744
+ second = float(input("Enter second number: "))
745
+
746
+ if operation == '+':
747
+ result = add(first, second)
748
+ elif operation == '-':
749
+ result = subtract(first, second)
750
+ elif operation == '*':
751
+ result = multiply(first, second)
752
+ elif operation == '/':
753
+ result = divide(first, second)
754
+
755
+ print(f"Result: {result}")
756
+
757
+ except ValueError:
758
+ print("Please enter valid numbers!")
759
+
760
+ if __name__ == "__main__":
761
+ calculator()""",
762
+ extensions=[
763
+ "Add more operations (power, square root, etc.)",
764
+ "Add memory functions (store/recall)",
765
+ "Create a GUI version using tkinter",
766
+ "Add calculation history"
767
+ ]
768
+ )
769
+
770
+ self._projects[calculator_project.id] = calculator_project