fishertools 0.2.1__py3-none-any.whl → 0.4.0__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 (69) hide show
  1. fishertools/__init__.py +16 -5
  2. fishertools/errors/__init__.py +11 -3
  3. fishertools/errors/exception_types.py +282 -0
  4. fishertools/errors/explainer.py +87 -1
  5. fishertools/errors/models.py +73 -1
  6. fishertools/errors/patterns.py +40 -0
  7. fishertools/examples/cli_example.py +156 -0
  8. fishertools/examples/learn_example.py +65 -0
  9. fishertools/examples/logger_example.py +176 -0
  10. fishertools/examples/menu_example.py +101 -0
  11. fishertools/examples/storage_example.py +175 -0
  12. fishertools/input_utils.py +185 -0
  13. fishertools/learn/__init__.py +19 -2
  14. fishertools/learn/examples.py +88 -1
  15. fishertools/learn/knowledge_engine.py +321 -0
  16. fishertools/learn/repl/__init__.py +19 -0
  17. fishertools/learn/repl/cli.py +31 -0
  18. fishertools/learn/repl/code_sandbox.py +229 -0
  19. fishertools/learn/repl/command_handler.py +544 -0
  20. fishertools/learn/repl/command_parser.py +165 -0
  21. fishertools/learn/repl/engine.py +479 -0
  22. fishertools/learn/repl/models.py +121 -0
  23. fishertools/learn/repl/session_manager.py +284 -0
  24. fishertools/learn/repl/test_code_sandbox.py +261 -0
  25. fishertools/learn/repl/test_code_sandbox_pbt.py +148 -0
  26. fishertools/learn/repl/test_command_handler.py +224 -0
  27. fishertools/learn/repl/test_command_handler_pbt.py +189 -0
  28. fishertools/learn/repl/test_command_parser.py +160 -0
  29. fishertools/learn/repl/test_command_parser_pbt.py +100 -0
  30. fishertools/learn/repl/test_engine.py +190 -0
  31. fishertools/learn/repl/test_session_manager.py +310 -0
  32. fishertools/learn/repl/test_session_manager_pbt.py +182 -0
  33. fishertools/learn/test_knowledge_engine.py +241 -0
  34. fishertools/learn/test_knowledge_engine_pbt.py +180 -0
  35. fishertools/patterns/__init__.py +46 -0
  36. fishertools/patterns/cli.py +175 -0
  37. fishertools/patterns/logger.py +140 -0
  38. fishertools/patterns/menu.py +99 -0
  39. fishertools/patterns/storage.py +127 -0
  40. fishertools/readme_transformer.py +631 -0
  41. fishertools/safe/__init__.py +6 -1
  42. fishertools/safe/files.py +329 -1
  43. fishertools/transform_readme.py +105 -0
  44. fishertools-0.4.0.dist-info/METADATA +104 -0
  45. fishertools-0.4.0.dist-info/RECORD +131 -0
  46. {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/WHEEL +1 -1
  47. tests/test_documentation_properties.py +329 -0
  48. tests/test_documentation_structure.py +349 -0
  49. tests/test_errors/test_exception_types.py +446 -0
  50. tests/test_errors/test_exception_types_pbt.py +333 -0
  51. tests/test_errors/test_patterns.py +52 -0
  52. tests/test_input_utils/__init__.py +1 -0
  53. tests/test_input_utils/test_input_utils.py +65 -0
  54. tests/test_learn/test_examples.py +179 -1
  55. tests/test_learn/test_explain_properties.py +307 -0
  56. tests/test_patterns_cli.py +611 -0
  57. tests/test_patterns_docstrings.py +473 -0
  58. tests/test_patterns_logger.py +465 -0
  59. tests/test_patterns_menu.py +440 -0
  60. tests/test_patterns_storage.py +447 -0
  61. tests/test_readme_enhancements_v0_3_1.py +2036 -0
  62. tests/test_readme_transformer/__init__.py +1 -0
  63. tests/test_readme_transformer/test_readme_infrastructure.py +1023 -0
  64. tests/test_readme_transformer/test_transform_readme_integration.py +431 -0
  65. tests/test_safe/test_files.py +726 -1
  66. fishertools-0.2.1.dist-info/METADATA +0 -256
  67. fishertools-0.2.1.dist-info/RECORD +0 -81
  68. {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/licenses/LICENSE +0 -0
  69. {fishertools-0.2.1.dist-info → fishertools-0.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,156 @@
1
+ """
2
+ Example demonstrating the SimpleCLI class from fishertools.patterns.
3
+
4
+ This example shows how to create a command-line interface using SimpleCLI.
5
+ Commands are registered via decorators and executed based on command-line
6
+ arguments. Supports --help flag and graceful error handling.
7
+
8
+ Run this file with various commands to see SimpleCLI in action:
9
+ python cli_example.py greet Alice
10
+ python cli_example.py add 5 3
11
+ python cli_example.py --help
12
+ """
13
+
14
+ from fishertools.patterns import SimpleCLI
15
+
16
+
17
+ def main():
18
+ """Create and run a CLI application."""
19
+
20
+ # Create a CLI instance
21
+ cli = SimpleCLI("calculator", "A simple calculator application")
22
+
23
+ # Register commands using decorators
24
+
25
+ @cli.command("greet", "Greet someone with a message")
26
+ def greet(name="World"):
27
+ """Greet a person by name."""
28
+ print(f"Hello, {name}! Welcome to the calculator app.")
29
+
30
+ @cli.command("add", "Add two numbers")
31
+ def add(a, b):
32
+ """Add two numbers and display the result."""
33
+ try:
34
+ result = float(a) + float(b)
35
+ print(f"{a} + {b} = {result}")
36
+ except ValueError:
37
+ print(f"Error: '{a}' and '{b}' must be valid numbers")
38
+
39
+ @cli.command("subtract", "Subtract two numbers")
40
+ def subtract(a, b):
41
+ """Subtract b from a and display the result."""
42
+ try:
43
+ result = float(a) - float(b)
44
+ print(f"{a} - {b} = {result}")
45
+ except ValueError:
46
+ print(f"Error: '{a}' and '{b}' must be valid numbers")
47
+
48
+ @cli.command("multiply", "Multiply two numbers")
49
+ def multiply(a, b):
50
+ """Multiply two numbers and display the result."""
51
+ try:
52
+ result = float(a) * float(b)
53
+ print(f"{a} * {b} = {result}")
54
+ except ValueError:
55
+ print(f"Error: '{a}' and '{b}' must be valid numbers")
56
+
57
+ @cli.command("divide", "Divide two numbers")
58
+ def divide(a, b):
59
+ """Divide a by b and display the result."""
60
+ try:
61
+ a_float = float(a)
62
+ b_float = float(b)
63
+ if b_float == 0:
64
+ print("Error: Cannot divide by zero")
65
+ else:
66
+ result = a_float / b_float
67
+ print(f"{a} / {b} = {result}")
68
+ except ValueError:
69
+ print(f"Error: '{a}' and '{b}' must be valid numbers")
70
+
71
+ @cli.command("power", "Raise a number to a power")
72
+ def power(base, exponent):
73
+ """Raise base to the power of exponent."""
74
+ try:
75
+ result = float(base) ** float(exponent)
76
+ print(f"{base} ^ {exponent} = {result}")
77
+ except ValueError:
78
+ print(f"Error: '{base}' and '{exponent}' must be valid numbers")
79
+
80
+ @cli.command("square", "Calculate the square of a number")
81
+ def square(number):
82
+ """Calculate the square of a number."""
83
+ try:
84
+ result = float(number) ** 2
85
+ print(f"{number}² = {result}")
86
+ except ValueError:
87
+ print(f"Error: '{number}' must be a valid number")
88
+
89
+ @cli.command("sqrt", "Calculate the square root of a number")
90
+ def sqrt(number):
91
+ """Calculate the square root of a number."""
92
+ try:
93
+ num = float(number)
94
+ if num < 0:
95
+ print("Error: Cannot calculate square root of negative number")
96
+ else:
97
+ result = num ** 0.5
98
+ print(f"√{number} = {result}")
99
+ except ValueError:
100
+ print(f"Error: '{number}' must be a valid number")
101
+
102
+ @cli.command("info", "Show information about this application")
103
+ def show_info():
104
+ """Display information about the calculator."""
105
+ print("\n" + "=" * 60)
106
+ print("Calculator Application - SimpleCLI Demo")
107
+ print("=" * 60)
108
+ print("\nThis is a demonstration of the SimpleCLI pattern from")
109
+ print("fishertools.patterns module.")
110
+ print("\nFeatures:")
111
+ print(" • Command registration via decorators")
112
+ print(" • Automatic help generation")
113
+ print(" • Graceful error handling")
114
+ print(" • Support for multiple arguments")
115
+ print("\nUsage examples:")
116
+ print(" python cli_example.py greet Alice")
117
+ print(" python cli_example.py add 10 5")
118
+ print(" python cli_example.py multiply 3.5 2")
119
+ print(" python cli_example.py divide 20 4")
120
+ print(" python cli_example.py power 2 8")
121
+ print(" python cli_example.py square 7")
122
+ print(" python cli_example.py sqrt 16")
123
+ print(" python cli_example.py --help")
124
+ print("=" * 60 + "\n")
125
+
126
+ @cli.command("demo", "Run a demonstration of all commands")
127
+ def run_demo():
128
+ """Run a demonstration of all calculator functions."""
129
+ print("\n" + "=" * 60)
130
+ print("Calculator Demo - Running all operations")
131
+ print("=" * 60 + "\n")
132
+
133
+ print("1. Greeting:")
134
+ greet("Demo User")
135
+
136
+ print("\n2. Basic arithmetic:")
137
+ add("10", "5")
138
+ subtract("10", "5")
139
+ multiply("10", "5")
140
+ divide("10", "5")
141
+
142
+ print("\n3. Power operations:")
143
+ power("2", "8")
144
+ square("7")
145
+ sqrt("16")
146
+
147
+ print("\n" + "=" * 60)
148
+ print("Demo complete!")
149
+ print("=" * 60 + "\n")
150
+
151
+ # Run the CLI
152
+ cli.run()
153
+
154
+
155
+ if __name__ == "__main__":
156
+ main()
@@ -0,0 +1,65 @@
1
+ """
2
+ Example demonstrating the explain() function from fishertools.learn.
3
+
4
+ This example shows how to use the explain() function to get structured
5
+ explanations for Python topics, including descriptions, usage guidance,
6
+ and code examples.
7
+
8
+ Run this file to see explanations for various Python topics.
9
+ """
10
+
11
+ from fishertools.learn import explain
12
+
13
+
14
+ def main():
15
+ """Demonstrate the explain() function with various topics."""
16
+
17
+ print("=" * 70)
18
+ print("fishertools Learning Tools - explain() Function Demo")
19
+ print("=" * 70)
20
+
21
+ # List of topics to demonstrate
22
+ topics = ["list", "for", "lambda", "try", "with"]
23
+
24
+ for topic in topics:
25
+ try:
26
+ print(f"\n{'─' * 70}")
27
+ print(f"Topic: {topic.upper()}")
28
+ print(f"{'─' * 70}")
29
+
30
+ # Get the explanation
31
+ explanation = explain(topic)
32
+
33
+ # Display the explanation
34
+ print(f"\n📖 Description:")
35
+ print(f" {explanation['description']}")
36
+
37
+ print(f"\n💡 When to use:")
38
+ print(f" {explanation['when_to_use']}")
39
+
40
+ print(f"\n💻 Example:")
41
+ print(" " + "\n ".join(explanation['example'].split("\n")))
42
+
43
+ except ValueError as e:
44
+ print(f"❌ Error: {e}")
45
+ except Exception as e:
46
+ print(f"❌ Unexpected error: {e}")
47
+
48
+ # Demonstrate error handling with invalid topic
49
+ print(f"\n{'─' * 70}")
50
+ print("Demonstrating error handling with invalid topic:")
51
+ print(f"{'─' * 70}")
52
+
53
+ try:
54
+ explain("invalid_topic_xyz")
55
+ except ValueError as e:
56
+ print(f"✓ Caught expected error:")
57
+ print(f" {e}")
58
+
59
+ print("\n" + "=" * 70)
60
+ print("Demo complete!")
61
+ print("=" * 70)
62
+
63
+
64
+ if __name__ == "__main__":
65
+ main()
@@ -0,0 +1,176 @@
1
+ """
2
+ Example demonstrating the SimpleLogger class from fishertools.patterns.
3
+
4
+ This example shows how to use SimpleLogger to add logging to applications
5
+ without complex configuration. Demonstrates info, warning, and error logging
6
+ with automatic timestamps and log levels.
7
+
8
+ Run this file to see SimpleLogger in action.
9
+ """
10
+
11
+ import os
12
+ import time
13
+ from fishertools.patterns import SimpleLogger
14
+
15
+
16
+ def main():
17
+ """Demonstrate SimpleLogger functionality."""
18
+
19
+ print("=" * 70)
20
+ print("fishertools Patterns - SimpleLogger Demo")
21
+ print("=" * 70)
22
+
23
+ # Create a logger instance
24
+ log_file = "demo_app.log"
25
+ logger = SimpleLogger(log_file)
26
+
27
+ # Clean up any existing log file from previous runs
28
+ if os.path.exists(log_file):
29
+ os.remove(log_file)
30
+ print(f"\n✓ Cleaned up existing {log_file}")
31
+
32
+ # Example 1: Basic logging
33
+ print("\n" + "─" * 70)
34
+ print("Example 1: Basic logging with different levels")
35
+ print("─" * 70)
36
+
37
+ print("\nLogging messages...")
38
+ logger.info("Application started")
39
+ logger.info("Configuration loaded successfully")
40
+ logger.warning("Deprecated API endpoint used")
41
+ logger.error("Failed to connect to database")
42
+
43
+ print("✓ Messages logged to", log_file)
44
+
45
+ # Example 2: Simulating application workflow
46
+ print("\n" + "─" * 70)
47
+ print("Example 2: Simulating application workflow")
48
+ print("─" * 70)
49
+
50
+ print("\nSimulating user registration workflow...")
51
+
52
+ logger.info("User registration started")
53
+ logger.info("Validating email: user@example.com")
54
+
55
+ time.sleep(0.5) # Simulate processing
56
+
57
+ logger.info("Email validation passed")
58
+ logger.info("Checking username availability")
59
+
60
+ time.sleep(0.5) # Simulate processing
61
+
62
+ logger.info("Username 'john_doe' is available")
63
+ logger.info("Creating user account")
64
+
65
+ time.sleep(0.5) # Simulate processing
66
+
67
+ logger.info("User account created successfully")
68
+ logger.info("Sending welcome email")
69
+ logger.info("User registration completed")
70
+
71
+ print("✓ Workflow logged successfully")
72
+
73
+ # Example 3: Error handling and warnings
74
+ print("\n" + "─" * 70)
75
+ print("Example 3: Error handling and warnings")
76
+ print("─" * 70)
77
+
78
+ print("\nSimulating error scenarios...")
79
+
80
+ logger.warning("Memory usage above 80%")
81
+ logger.warning("Cache hit rate below threshold")
82
+ logger.error("Connection timeout after 30 seconds")
83
+ logger.error("Failed to save user preferences")
84
+ logger.info("Attempting automatic recovery")
85
+ logger.info("Recovery successful")
86
+
87
+ print("✓ Error scenarios logged")
88
+
89
+ # Example 4: Nested directory logging
90
+ print("\n" + "─" * 70)
91
+ print("Example 4: Logging to nested directories")
92
+ print("─" * 70)
93
+
94
+ nested_log_file = "logs/2024/01/application.log"
95
+ nested_logger = SimpleLogger(nested_log_file)
96
+
97
+ print(f"\nCreating logger for nested path: {nested_log_file}")
98
+ nested_logger.info("Nested logging initialized")
99
+ nested_logger.info("This log is in a nested directory structure")
100
+
101
+ print(f"✓ Nested directories created automatically")
102
+ print(f"✓ Logging to {nested_log_file}")
103
+
104
+ # Example 5: Display the log file contents
105
+ print("\n" + "─" * 70)
106
+ print("Example 5: Reading log file contents")
107
+ print("─" * 70)
108
+
109
+ print(f"\nContents of {log_file}:")
110
+ print("─" * 70)
111
+
112
+ try:
113
+ with open(log_file, 'r', encoding='utf-8') as f:
114
+ log_contents = f.read()
115
+ print(log_contents)
116
+ except FileNotFoundError:
117
+ print(f"✗ Log file {log_file} not found")
118
+
119
+ print("─" * 70)
120
+
121
+ # Example 6: Demonstrating log levels
122
+ print("\n" + "─" * 70)
123
+ print("Example 6: Different log levels")
124
+ print("─" * 70)
125
+
126
+ info_logger = SimpleLogger("info_demo.log")
127
+
128
+ print("\nLogging different severity levels...")
129
+ info_logger.info("This is an informational message")
130
+ info_logger.warning("This is a warning message")
131
+ info_logger.error("This is an error message")
132
+
133
+ print("✓ Different log levels demonstrated")
134
+
135
+ # Display the info demo log
136
+ print(f"\nContents of info_demo.log:")
137
+ print("─" * 70)
138
+
139
+ try:
140
+ with open("info_demo.log", 'r', encoding='utf-8') as f:
141
+ print(f.read())
142
+ except FileNotFoundError:
143
+ print("✗ Log file not found")
144
+
145
+ print("─" * 70)
146
+
147
+ # Cleanup
148
+ print("\n" + "─" * 70)
149
+ print("Cleanup")
150
+ print("─" * 70)
151
+
152
+ files_to_remove = [log_file, "info_demo.log", nested_log_file]
153
+
154
+ for file_to_remove in files_to_remove:
155
+ if os.path.exists(file_to_remove):
156
+ os.remove(file_to_remove)
157
+ print(f"✓ Removed {file_to_remove}")
158
+
159
+ # Remove empty directories
160
+ dirs_to_remove = ["logs/2024/01", "logs/2024", "logs"]
161
+
162
+ for dir_to_remove in dirs_to_remove:
163
+ if os.path.exists(dir_to_remove):
164
+ try:
165
+ os.rmdir(dir_to_remove)
166
+ print(f"✓ Removed directory {dir_to_remove}")
167
+ except OSError:
168
+ pass
169
+
170
+ print("\n" + "=" * 70)
171
+ print("SimpleLogger demo complete!")
172
+ print("=" * 70)
173
+
174
+
175
+ if __name__ == "__main__":
176
+ main()
@@ -0,0 +1,101 @@
1
+ """
2
+ Example demonstrating the simple_menu() function from fishertools.patterns.
3
+
4
+ This example shows how to create an interactive console menu using the
5
+ simple_menu() function. The menu allows users to select options and execute
6
+ corresponding functions.
7
+
8
+ Run this file to interact with the menu.
9
+ """
10
+
11
+ from fishertools.patterns import simple_menu
12
+
13
+
14
+ def show_greeting():
15
+ """Display a greeting message."""
16
+ name = input("What's your name? ")
17
+ print(f"Hello, {name}! Welcome to the menu demo.")
18
+
19
+
20
+ def show_calculator():
21
+ """Simple calculator menu."""
22
+ print("\n--- Simple Calculator ---")
23
+ try:
24
+ a = float(input("Enter first number: "))
25
+ b = float(input("Enter second number: "))
26
+
27
+ print(f"\nResults:")
28
+ print(f" {a} + {b} = {a + b}")
29
+ print(f" {a} - {b} = {a - b}")
30
+ print(f" {a} * {b} = {a * b}")
31
+ if b != 0:
32
+ print(f" {a} / {b} = {a / b}")
33
+ else:
34
+ print(f" {a} / {b} = Cannot divide by zero")
35
+ except ValueError:
36
+ print("❌ Invalid input. Please enter numbers.")
37
+
38
+
39
+ def show_about():
40
+ """Display information about the demo."""
41
+ print("\n--- About This Demo ---")
42
+ print("This is a demonstration of the simple_menu() function")
43
+ print("from fishertools.patterns module.")
44
+ print("\nFeatures:")
45
+ print(" • Interactive menu with numbered options")
46
+ print(" • Easy function execution")
47
+ print(" • Graceful error handling")
48
+ print(" • Exit with 'quit' or 'exit' command")
49
+
50
+
51
+ def list_fruits():
52
+ """Display a list of fruits."""
53
+ fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry"]
54
+ print("\n--- Available Fruits ---")
55
+ for i, fruit in enumerate(fruits, 1):
56
+ print(f" {i}. {fruit}")
57
+
58
+
59
+ def show_help():
60
+ """Display help information."""
61
+ print("\n--- Help ---")
62
+ print("This menu demonstrates the simple_menu() function.")
63
+ print("\nHow to use:")
64
+ print(" 1. Select an option by entering its number")
65
+ print(" 2. Follow the prompts for each option")
66
+ print(" 3. Type 'quit' or 'exit' to leave the menu")
67
+ print("\nAvailable options:")
68
+ print(" • Greeting: Get a personalized greeting")
69
+ print(" • Calculator: Perform basic math operations")
70
+ print(" • Fruits: See a list of fruits")
71
+ print(" • About: Learn about this demo")
72
+ print(" • Help: Show this help message")
73
+
74
+
75
+ def main():
76
+ """Run the menu demo."""
77
+ print("=" * 60)
78
+ print("fishertools Patterns - simple_menu() Demo")
79
+ print("=" * 60)
80
+ print("\nWelcome! This demo shows how to use simple_menu().")
81
+ print("Type 'quit' or 'exit' at any time to leave.\n")
82
+
83
+ # Create the menu with options
84
+ menu_options = {
85
+ "Greeting": show_greeting,
86
+ "Calculator": show_calculator,
87
+ "Fruits": list_fruits,
88
+ "About": show_about,
89
+ "Help": show_help,
90
+ }
91
+
92
+ # Run the menu
93
+ simple_menu(menu_options)
94
+
95
+ print("\n" + "=" * 60)
96
+ print("Thank you for using the menu demo!")
97
+ print("=" * 60)
98
+
99
+
100
+ if __name__ == "__main__":
101
+ main()
@@ -0,0 +1,175 @@
1
+ """
2
+ Example demonstrating the JSONStorage class from fishertools.patterns.
3
+
4
+ This example shows how to use JSONStorage to persist and retrieve data
5
+ in JSON format without writing file handling code. Demonstrates saving,
6
+ loading, and checking file existence.
7
+
8
+ Run this file to see JSONStorage in action.
9
+ """
10
+
11
+ import os
12
+ from fishertools.patterns import JSONStorage
13
+
14
+
15
+ def main():
16
+ """Demonstrate JSONStorage functionality."""
17
+
18
+ print("=" * 70)
19
+ print("fishertools Patterns - JSONStorage Demo")
20
+ print("=" * 70)
21
+
22
+ # Create a storage instance
23
+ storage_path = "demo_data.json"
24
+ storage = JSONStorage(storage_path)
25
+
26
+ # Clean up any existing file from previous runs
27
+ if os.path.exists(storage_path):
28
+ os.remove(storage_path)
29
+ print(f"\n✓ Cleaned up existing {storage_path}")
30
+
31
+ # Example 1: Save data
32
+ print("\n" + "─" * 70)
33
+ print("Example 1: Saving data")
34
+ print("─" * 70)
35
+
36
+ user_data = {
37
+ "name": "Alice Johnson",
38
+ "age": 28,
39
+ "email": "alice@example.com",
40
+ "skills": ["Python", "JavaScript", "SQL"],
41
+ "is_active": True,
42
+ "metadata": {
43
+ "created": "2024-01-15",
44
+ "last_login": "2024-01-26"
45
+ }
46
+ }
47
+
48
+ print(f"\nSaving user data to {storage_path}:")
49
+ print(f" {user_data}")
50
+
51
+ storage.save(user_data)
52
+ print("✓ Data saved successfully!")
53
+
54
+ # Example 2: Check if file exists
55
+ print("\n" + "─" * 70)
56
+ print("Example 2: Checking file existence")
57
+ print("─" * 70)
58
+
59
+ if storage.exists():
60
+ print(f"✓ File {storage_path} exists")
61
+ else:
62
+ print(f"✗ File {storage_path} does not exist")
63
+
64
+ # Example 3: Load data
65
+ print("\n" + "─" * 70)
66
+ print("Example 3: Loading data")
67
+ print("─" * 70)
68
+
69
+ loaded_data = storage.load()
70
+ print(f"\nLoaded data from {storage_path}:")
71
+ print(f" Name: {loaded_data['name']}")
72
+ print(f" Age: {loaded_data['age']}")
73
+ print(f" Email: {loaded_data['email']}")
74
+ print(f" Skills: {', '.join(loaded_data['skills'])}")
75
+ print(f" Active: {loaded_data['is_active']}")
76
+ print(f" Created: {loaded_data['metadata']['created']}")
77
+
78
+ # Example 4: Update data
79
+ print("\n" + "─" * 70)
80
+ print("Example 4: Updating data")
81
+ print("─" * 70)
82
+
83
+ loaded_data['age'] = 29
84
+ loaded_data['skills'].append("Docker")
85
+ loaded_data['metadata']['last_login'] = "2024-01-26"
86
+
87
+ print(f"\nUpdating user data:")
88
+ print(f" Age: 28 → {loaded_data['age']}")
89
+ print(f" Skills: Added 'Docker'")
90
+ print(f" Last login: Updated to 2024-01-26")
91
+
92
+ storage.save(loaded_data)
93
+ print("✓ Updated data saved!")
94
+
95
+ # Example 5: Working with nested directories
96
+ print("\n" + "─" * 70)
97
+ print("Example 5: Creating nested directories")
98
+ print("─" * 70)
99
+
100
+ nested_storage_path = "data/users/profiles/alice.json"
101
+ nested_storage = JSONStorage(nested_storage_path)
102
+
103
+ profile_data = {
104
+ "username": "alice_dev",
105
+ "bio": "Python developer and open source enthusiast",
106
+ "followers": 150,
107
+ "following": 75
108
+ }
109
+
110
+ print(f"\nSaving profile to nested path: {nested_storage_path}")
111
+ nested_storage.save(profile_data)
112
+ print("✓ Nested directories created automatically!")
113
+ print(f"✓ Profile saved to {nested_storage_path}")
114
+
115
+ # Verify the nested file was created
116
+ if nested_storage.exists():
117
+ print(f"✓ Verified: {nested_storage_path} exists")
118
+
119
+ # Example 6: Round-trip verification
120
+ print("\n" + "─" * 70)
121
+ print("Example 6: Round-trip verification")
122
+ print("─" * 70)
123
+
124
+ original_data = {
125
+ "items": [1, 2, 3, 4, 5],
126
+ "config": {
127
+ "debug": True,
128
+ "timeout": 30,
129
+ "retries": 3
130
+ },
131
+ "tags": ["important", "urgent", "review"]
132
+ }
133
+
134
+ roundtrip_storage = JSONStorage("roundtrip_test.json")
135
+
136
+ print(f"\nOriginal data:")
137
+ print(f" {original_data}")
138
+
139
+ roundtrip_storage.save(original_data)
140
+ loaded_roundtrip = roundtrip_storage.load()
141
+
142
+ print(f"\nLoaded data:")
143
+ print(f" {loaded_roundtrip}")
144
+
145
+ if original_data == loaded_roundtrip:
146
+ print("✓ Round-trip successful: Data matches perfectly!")
147
+ else:
148
+ print("✗ Round-trip failed: Data mismatch")
149
+
150
+ # Cleanup
151
+ print("\n" + "─" * 70)
152
+ print("Cleanup")
153
+ print("─" * 70)
154
+
155
+ for file_to_remove in [storage_path, nested_storage_path, "roundtrip_test.json"]:
156
+ if os.path.exists(file_to_remove):
157
+ os.remove(file_to_remove)
158
+ print(f"✓ Removed {file_to_remove}")
159
+
160
+ # Remove empty directories
161
+ for dir_to_remove in ["data/users/profiles", "data/users", "data"]:
162
+ if os.path.exists(dir_to_remove):
163
+ try:
164
+ os.rmdir(dir_to_remove)
165
+ print(f"✓ Removed directory {dir_to_remove}")
166
+ except OSError:
167
+ pass
168
+
169
+ print("\n" + "=" * 70)
170
+ print("JSONStorage demo complete!")
171
+ print("=" * 70)
172
+
173
+
174
+ if __name__ == "__main__":
175
+ main()