python-lab-toolkit 1.0.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 (86) hide show
  1. pylab/__init__.py +43 -0
  2. pylab/cli.py +282 -0
  3. pylab/data/Data.csv +11 -0
  4. pylab/data/alphabet_stock_data.csv +143 -0
  5. pylab/data/breast-cancer.csv +351 -0
  6. pylab/data/dirtydata.csv +33 -0
  7. pylab/data/groceries.csv +359 -0
  8. pylab/data/iris.csv +151 -0
  9. pylab/data/rainfall.csv +151 -0
  10. pylab/data/students.csv +7 -0
  11. pylab/data/winequality-red.csv +1601 -0
  12. pylab/data/winequality-white.csv +2401 -0
  13. pylab/datasets.py +277 -0
  14. pylab/environment.py +136 -0
  15. pylab/errors.py +53 -0
  16. pylab/generator.py +216 -0
  17. pylab/registry.py +562 -0
  18. pylab/templates/q1/variable_validator.py +43 -0
  19. pylab/templates/q10/password_strength.py +42 -0
  20. pylab/templates/q11/recursion_math.py +28 -0
  21. pylab/templates/q12/main_analyzer.py +46 -0
  22. pylab/templates/q12/text_analyzer.py +16 -0
  23. pylab/templates/q12/text_preprocessor.py +15 -0
  24. pylab/templates/q13/student.py +26 -0
  25. pylab/templates/q14/circle.py +26 -0
  26. pylab/templates/q15/employee_salary.py +46 -0
  27. pylab/templates/q16/smart_calculator.py +51 -0
  28. pylab/templates/q17/complex_number.py +43 -0
  29. pylab/templates/q18/vehicle_inheritance.py +43 -0
  30. pylab/templates/q19/file_word_counter.py +48 -0
  31. pylab/templates/q19/sample.txt +6 -0
  32. pylab/templates/q2/single_number.py +26 -0
  33. pylab/templates/q20/age_validator.py +27 -0
  34. pylab/templates/q21/transaction_manager.py +45 -0
  35. pylab/templates/q22/date_formatter.py +30 -0
  36. pylab/templates/q23/rainfall_analyzer.py +73 -0
  37. pylab/templates/q24/student_marks.py +58 -0
  38. pylab/templates/q25/library_manager.py +182 -0
  39. pylab/templates/q26/mysql_employee_manager.py +239 -0
  40. pylab/templates/q27/crud_client.py +98 -0
  41. pylab/templates/q27/mock_server.py +85 -0
  42. pylab/templates/q28/index.html +33 -0
  43. pylab/templates/q28/login_handler.py +31 -0
  44. pylab/templates/q28/server.py +44 -0
  45. pylab/templates/q29/index.html +50 -0
  46. pylab/templates/q29/register_handler.py +42 -0
  47. pylab/templates/q29/server.py +42 -0
  48. pylab/templates/q3/string_operations.py +32 -0
  49. pylab/templates/q30/crud_handler.py +60 -0
  50. pylab/templates/q30/database.py +66 -0
  51. pylab/templates/q30/index.html +59 -0
  52. pylab/templates/q30/server.py +51 -0
  53. pylab/templates/q31/numpy_matrix.py +40 -0
  54. pylab/templates/q32/numpy_slicing.py +43 -0
  55. pylab/templates/q33/pandas_students.py +41 -0
  56. pylab/templates/q34/pandas_salary.py +37 -0
  57. pylab/templates/q35/sales_barchart.py +58 -0
  58. pylab/templates/q36/weather_plot.py +50 -0
  59. pylab/templates/q37/age_categorization.py +38 -0
  60. pylab/templates/q38/concat_rows.py +38 -0
  61. pylab/templates/q39/concat_cols.py +38 -0
  62. pylab/templates/q4/menu_string_processor.py +68 -0
  63. pylab/templates/q40/concat_merge.py +44 -0
  64. pylab/templates/q41/pandas_joins.py +46 -0
  65. pylab/templates/q42/groupby_school.py +32 -0
  66. pylab/templates/q43/groupby_multi.py +29 -0
  67. pylab/templates/q44/alphabet_stock_viz.py +95 -0
  68. pylab/templates/q45/multi_plot.py +65 -0
  69. pylab/templates/q46/dataframe_barchart.py +60 -0
  70. pylab/templates/q47/preprocess_data.py +54 -0
  71. pylab/templates/q48/clean_dirtydata.py +62 -0
  72. pylab/templates/q49/wine_regression.py +169 -0
  73. pylab/templates/q5/phonebook.py +105 -0
  74. pylab/templates/q50/breast_cancer_classifier.py +147 -0
  75. pylab/templates/q51/iris_clustering.py +95 -0
  76. pylab/templates/q52/apriori_groceries.py +88 -0
  77. pylab/templates/q6/calculator.py +67 -0
  78. pylab/templates/q7/session_attendees.py +37 -0
  79. pylab/templates/q8/number_properties.py +68 -0
  80. pylab/templates/q9/greet_people.py +26 -0
  81. python_lab_toolkit-1.0.0.dist-info/LICENSE +21 -0
  82. python_lab_toolkit-1.0.0.dist-info/METADATA +427 -0
  83. python_lab_toolkit-1.0.0.dist-info/RECORD +86 -0
  84. python_lab_toolkit-1.0.0.dist-info/WHEEL +5 -0
  85. python_lab_toolkit-1.0.0.dist-info/entry_points.txt +2 -0
  86. python_lab_toolkit-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,182 @@
1
+ import os
2
+ import sqlite3
3
+ import sys
4
+
5
+ DEFAULT_DB = "library.db"
6
+
7
+ INITIAL_BOOKS = [
8
+ ("Clean Code", "Robert C. Martin", "Programming", 5),
9
+ ("Introduction to Algorithms", "Thomas H. Cormen", "Computer Science", 3),
10
+ ("Fluent Python", "Luciano Ramalho", "Programming", 4),
11
+ ("Designing Data-Intensive Applications", "Martin Kleppmann", "Architecture", 6),
12
+ ("Artificial Intelligence: A Modern Approach", "Stuart Russell", "AI", 2),
13
+ ]
14
+
15
+ class LibraryDatabase:
16
+ def __init__(self, db_path=DEFAULT_DB):
17
+ self.db_path = db_path
18
+ self.conn = sqlite3.connect(self.db_path)
19
+ self.create_table()
20
+ self.auto_seed()
21
+
22
+ def create_table(self):
23
+ query = """
24
+ CREATE TABLE IF NOT EXISTS books (
25
+ book_id INTEGER PRIMARY KEY AUTOINCREMENT,
26
+ title TEXT NOT NULL,
27
+ author TEXT NOT NULL,
28
+ category TEXT NOT NULL,
29
+ copies INTEGER NOT NULL CHECK (copies >= 0)
30
+ );
31
+ """
32
+ with self.conn:
33
+ self.conn.execute(query)
34
+
35
+ def auto_seed(self):
36
+ cursor = self.conn.execute("SELECT COUNT(*) FROM books;")
37
+ count = cursor.fetchone()[0]
38
+ if count == 0:
39
+ self.insert_batch(INITIAL_BOOKS)
40
+
41
+ def insert_book(self, title, author, category, copies):
42
+ query = "INSERT INTO books (title, author, category, copies) VALUES (?, ?, ?, ?);"
43
+ with self.conn:
44
+ cursor = self.conn.execute(query, (title.strip(), author.strip(), category.strip(), int(copies)))
45
+ return cursor.lastrowid
46
+
47
+ def insert_batch(self, book_list):
48
+ query = "INSERT INTO books (title, author, category, copies) VALUES (?, ?, ?, ?);"
49
+ with self.conn:
50
+ cursor = self.conn.executemany(query, book_list)
51
+ return cursor.rowcount
52
+
53
+ def get_all_books(self):
54
+ query = "SELECT book_id, title, author, category, copies FROM books ORDER BY book_id ASC;"
55
+ cursor = self.conn.execute(query)
56
+ return cursor.fetchall()
57
+
58
+ def search_by_id(self, book_id):
59
+ query = "SELECT book_id, title, author, category, copies FROM books WHERE book_id = ?;"
60
+ cursor = self.conn.execute(query, (int(book_id),))
61
+ return cursor.fetchone()
62
+
63
+ def search_by_category(self, category):
64
+ query = "SELECT book_id, title, author, category, copies FROM books WHERE LOWER(category) = LOWER(?);"
65
+ cursor = self.conn.execute(query, (category.strip(),))
66
+ return cursor.fetchall()
67
+
68
+ def update_copies(self, book_id, new_copies):
69
+ query = "UPDATE books SET copies = ? WHERE book_id = ?;"
70
+ with self.conn:
71
+ cursor = self.conn.execute(query, (int(new_copies), int(book_id)))
72
+ return cursor.rowcount > 0
73
+
74
+ def delete_book(self, book_id):
75
+ query = "DELETE FROM books WHERE book_id = ?;"
76
+ with self.conn:
77
+ cursor = self.conn.execute(query, (int(book_id),))
78
+ return cursor.rowcount > 0
79
+
80
+ def close(self):
81
+ self.conn.close()
82
+
83
+ def display_books(records):
84
+ if not records:
85
+ print("No matching book records found.")
86
+ return
87
+ print(f"{'ID':<6} | {'Title':<30} | {'Author':<20} | {'Category':<16} | {'Copies':<6}")
88
+ print("-" * 88)
89
+ for r in records:
90
+ print(f"{r[0]:<6} | {r[1]:<30} | {r[2]:<20} | {r[3]:<16} | {r[4]:<6}")
91
+
92
+ def run_automated_suite(db):
93
+ print("================================================================================")
94
+ print(" SQLITE LIBRARY MANAGEMENT SYSTEM (Automated Execution)")
95
+ print(" All SQL tables, parameterized inserts, queries, updates, and deletes are")
96
+ print(" executed automatically with zero coding or database setup required.")
97
+ print("================================================================================")
98
+
99
+ print("\n1. Current Books Catalog (Auto-Initialized):")
100
+ display_books(db.get_all_books())
101
+
102
+ print("\n2. Executing Parameterized Single Insert (Title: 'Python Distilled', Copies: 7)...")
103
+ new_id = db.insert_book("Python Distilled", "David Beazley", "Programming", 7)
104
+ print(f" Success: Book inserted with generated ID: {new_id}")
105
+
106
+ print("\n3. Searching for Book ID 2 (Introduction to Algorithms):")
107
+ display_books([db.search_by_id(2)])
108
+
109
+ print("\n4. Updating Copies for Book ID 2 to 15 copies...")
110
+ db.update_copies(2, 15)
111
+ display_books([db.search_by_id(2)])
112
+
113
+ print("\n5. Searching Books by Category 'Programming':")
114
+ display_books(db.search_by_category("Programming"))
115
+
116
+ print("\n6. Deleting Book ID 1 (Clean Code)...")
117
+ db.delete_book(1)
118
+ print(" Success: Book deleted from database.")
119
+
120
+ print("\n7. Final Updated Catalog:")
121
+ display_books(db.get_all_books())
122
+ print("\n================================================================================")
123
+ print(" All SQL operations completed successfully!")
124
+ print("================================================================================")
125
+
126
+ def main():
127
+ db = LibraryDatabase()
128
+
129
+ if len(sys.argv) > 1 and sys.argv[1] == "--menu":
130
+ while True:
131
+ print("\n=== SQLite Library Interactive Menu ===")
132
+ print("1. View All Books")
133
+ print("2. Add Single Book")
134
+ print("3. Search Book by ID")
135
+ print("4. Search Books by Category")
136
+ print("5. Update Copies")
137
+ print("6. Delete Book")
138
+ print("7. Run Automated Demo")
139
+ print("8. Exit")
140
+
141
+ choice = input("\nEnter choice (1-8): ").strip()
142
+ if choice == "1":
143
+ display_books(db.get_all_books())
144
+ elif choice == "2":
145
+ title = input("Enter title: ")
146
+ author = input("Enter author: ")
147
+ cat = input("Enter category: ")
148
+ copies = int(input("Enter copies: "))
149
+ nid = db.insert_book(title, author, cat, copies)
150
+ print(f"Book added with ID {nid}.")
151
+ elif choice == "3":
152
+ bid = input("Enter Book ID: ")
153
+ b = db.search_by_id(bid)
154
+ display_books([b] if b else [])
155
+ elif choice == "4":
156
+ cat = input("Enter category: ")
157
+ display_books(db.search_by_category(cat))
158
+ elif choice == "5":
159
+ bid = input("Enter Book ID: ")
160
+ c = int(input("Enter new copies count: "))
161
+ ok = db.update_copies(bid, c)
162
+ print("Updated successfully." if ok else "Book ID not found.")
163
+ elif choice == "6":
164
+ bid = input("Enter Book ID: ")
165
+ ok = db.delete_book(bid)
166
+ print("Deleted successfully." if ok else "Book ID not found.")
167
+ elif choice == "7":
168
+ run_automated_suite(db)
169
+ elif choice == "8":
170
+ print("Closing database.")
171
+ db.close()
172
+ break
173
+ else:
174
+ print("Invalid selection.")
175
+ else:
176
+ run_automated_suite(db)
177
+ print("\nTip: To use the interactive menu, run:")
178
+ print(" python library_manager.py --menu")
179
+ db.close()
180
+
181
+ if __name__ == "__main__":
182
+ main()
@@ -0,0 +1,239 @@
1
+ import os
2
+ import sqlite3
3
+ import sys
4
+
5
+ SAMPLE_EMPLOYEES = [
6
+ (101, "Aarav Sharma", "Engineering", "Senior Software Engineer", 75000.0),
7
+ (102, "Diya Patel", "Data Science", "ML Specialist", 82000.0),
8
+ (103, "Kabir Mehta", "Marketing", "Marketing Associate", 42000.0),
9
+ (104, "Ananya Sen", "Engineering", "Tech Lead", 95000.0),
10
+ (105, "Rohan Verma", "Operations", "Coordinator", 38000.0),
11
+ ]
12
+
13
+ class EmployeeDatabaseBackend:
14
+ def __init__(self):
15
+ self.is_mysql = False
16
+ self.conn = None
17
+ self.cursor = None
18
+ self._init_connection()
19
+
20
+ def _init_connection(self):
21
+ host = os.environ.get("MYSQL_HOST", "localhost")
22
+ user = os.environ.get("MYSQL_USER", "root")
23
+ password = os.environ.get("MYSQL_PASSWORD", "")
24
+ database = os.environ.get("MYSQL_DATABASE", "company_db")
25
+
26
+ try:
27
+ import mysql.connector
28
+ raw_conn = mysql.connector.connect(host=host, user=user, password=password, connection_timeout=2)
29
+ cur = raw_conn.cursor()
30
+ cur.execute(f"CREATE DATABASE IF NOT EXISTS `{database}`;")
31
+ cur.execute(f"USE `{database}`;")
32
+ self.conn = raw_conn
33
+ self.cursor = cur
34
+ self.is_mysql = True
35
+ print(f"Connected to live MySQL Server ({host} -> database '{database}')")
36
+ except Exception:
37
+ db_path = "mysql_simulation_company.db"
38
+ self.conn = sqlite3.connect(db_path)
39
+ self.cursor = self.conn.cursor()
40
+ self.is_mysql = False
41
+ print("Note: MySQL server not active. Automatically using built-in zero-setup database engine.")
42
+ print("All SQL table operations, parameterized batch inserts, and queries run automatically!\n")
43
+
44
+ def get_placeholder(self):
45
+ return "%s" if self.is_mysql else "?"
46
+
47
+ def execute(self, sql, params=None):
48
+ if not self.is_mysql and "%s" in sql:
49
+ sql = sql.replace("%s", "?")
50
+ if params is not None:
51
+ return self.cursor.execute(sql, params)
52
+ return self.cursor.execute(sql)
53
+
54
+ def executemany(self, sql, param_list):
55
+ if not self.is_mysql and "%s" in sql:
56
+ sql = sql.replace("%s", "?")
57
+ return self.cursor.executemany(sql, param_list)
58
+
59
+ def commit(self):
60
+ self.conn.commit()
61
+
62
+ def fetchall(self):
63
+ return self.cursor.fetchall()
64
+
65
+ def fetchone(self):
66
+ return self.cursor.fetchone()
67
+
68
+ def close(self):
69
+ self.conn.close()
70
+
71
+ def create_table(db):
72
+ query = """
73
+ CREATE TABLE IF NOT EXISTS employees (
74
+ emp_id INT PRIMARY KEY,
75
+ name VARCHAR(100) NOT NULL,
76
+ department VARCHAR(50) NOT NULL,
77
+ designation VARCHAR(50) NOT NULL,
78
+ salary DECIMAL(10, 2) NOT NULL
79
+ );
80
+ """
81
+ db.execute(query)
82
+ db.commit()
83
+
84
+ def insert_employee(db, emp_id, name, department, designation, salary):
85
+ ph = db.get_placeholder()
86
+ query = f"INSERT INTO employees (emp_id, name, department, designation, salary) VALUES ({ph}, {ph}, {ph}, {ph}, {ph});"
87
+ db.execute(query, (emp_id, name, department, designation, salary))
88
+ db.commit()
89
+
90
+ def insert_batch(db, emp_tuples):
91
+ ph = db.get_placeholder()
92
+ query = f"INSERT INTO employees (emp_id, name, department, designation, salary) VALUES ({ph}, {ph}, {ph}, {ph}, {ph});"
93
+ db.executemany(query, emp_tuples)
94
+ db.commit()
95
+
96
+ def get_all_employees(db):
97
+ db.execute("SELECT emp_id, name, department, designation, salary FROM employees ORDER BY emp_id ASC;")
98
+ return db.fetchall()
99
+
100
+ def search_employee(db, emp_id):
101
+ ph = db.get_placeholder()
102
+ db.execute(f"SELECT emp_id, name, department, designation, salary FROM employees WHERE emp_id = {ph};", (emp_id,))
103
+ return db.fetchone()
104
+
105
+ def update_salary(db, emp_id, new_salary):
106
+ ph = db.get_placeholder()
107
+ db.execute(f"UPDATE employees SET salary = {ph} WHERE emp_id = {ph};", (new_salary, emp_id))
108
+ db.commit()
109
+
110
+ def update_designation(db, emp_id, new_desig):
111
+ ph = db.get_placeholder()
112
+ db.execute(f"UPDATE employees SET designation = {ph} WHERE emp_id = {ph};", (new_desig, emp_id))
113
+ db.commit()
114
+
115
+ def delete_employee(db, emp_id):
116
+ ph = db.get_placeholder()
117
+ db.execute(f"DELETE FROM employees WHERE emp_id = {ph};", (emp_id,))
118
+ db.commit()
119
+
120
+ def get_high_earners(db, threshold=50000.0):
121
+ ph = db.get_placeholder()
122
+ db.execute(f"SELECT emp_id, name, department, designation, salary FROM employees WHERE salary > {ph} ORDER BY salary DESC;", (threshold,))
123
+ return db.fetchall()
124
+
125
+ def display_table(records):
126
+ if not records:
127
+ print("No matching employee records.")
128
+ return
129
+ print(f"{'ID':<6} | {'Name':<20} | {'Department':<16} | {'Designation':<26} | {'Salary':<12}")
130
+ print("-" * 90)
131
+ for r in records:
132
+ print(f"{r[0]:<6} | {r[1]:<20} | {r[2]:<16} | {r[3]:<26} | ₹{float(r[4]):<11,.2f}")
133
+
134
+ def run_automated_suite(db):
135
+ print("================================================================================")
136
+ print(" MYSQL EMPLOYEE MANAGEMENT SYSTEM (Automated Execution)")
137
+ print(" All SQL operations (schema creation, batch loading, updates, threshold")
138
+ print(" queries) execute automatically without requiring manual SQL coding.")
139
+ print("================================================================================")
140
+
141
+ create_table(db)
142
+ db.execute("DELETE FROM employees;")
143
+ db.commit()
144
+
145
+ print("\n1. Executing executemany() Batch Insert (5 Employees)...")
146
+ insert_batch(db, SAMPLE_EMPLOYEES)
147
+ print(" Success: 5 employee records inserted into database.")
148
+
149
+ print("\n2. Executing Parameterized Single Insert (EmpID 106, Ishaan Gupta)...")
150
+ insert_employee(db, 106, "Ishaan Gupta", "Data Science", "Research Scientist", 88000.0)
151
+ print(" Success: Single employee record inserted.")
152
+
153
+ print("\n3. All Employees in Database:")
154
+ display_table(get_all_employees(db))
155
+
156
+ print("\n4. Searching for Employee ID 102:")
157
+ display_table([search_employee(db, 102)])
158
+
159
+ print("\n5. Updating Employee 103 Salary to ₹58,000.00 and Designation to 'Marketing Lead'...")
160
+ update_salary(db, 103, 58000.0)
161
+ update_designation(db, 103, "Marketing Lead")
162
+ display_table([search_employee(db, 103)])
163
+
164
+ print("\n6. Filtering Employees Earning More than ₹50,000.00:")
165
+ display_table(get_high_earners(db, 50000.0))
166
+
167
+ print("\n7. Deleting Employee ID 105 (Rohan Verma)...")
168
+ delete_employee(db, 105)
169
+ print(" Success: Employee 105 deleted.")
170
+
171
+ print("\n8. Final Staff Roster:")
172
+ display_table(get_all_employees(db))
173
+
174
+ print("\n================================================================================")
175
+ print(" All MySQL employee operations completed successfully!")
176
+ print("================================================================================")
177
+
178
+ def main():
179
+ db = EmployeeDatabaseBackend()
180
+
181
+ if len(sys.argv) > 1 and sys.argv[1] == "--menu":
182
+ create_table(db)
183
+ while True:
184
+ print("\n=== MySQL Employee Management Menu ===")
185
+ print("1. Display All Employees")
186
+ print("2. Search Employee by ID")
187
+ print("3. Add Single Employee")
188
+ print("4. Update Salary")
189
+ print("5. Update Designation")
190
+ print("6. Delete Employee")
191
+ print("7. Display Employees Earning > ₹50,000")
192
+ print("8. Run Automated Demonstration")
193
+ print("9. Exit")
194
+
195
+ choice = input("\nEnter choice (1-9): ").strip()
196
+ if choice == "1":
197
+ display_table(get_all_employees(db))
198
+ elif choice == "2":
199
+ eid = int(input("Enter Employee ID: "))
200
+ display_table([search_employee(db, eid)])
201
+ elif choice == "3":
202
+ eid = int(input("Enter Employee ID: "))
203
+ name = input("Enter Name: ")
204
+ dept = input("Enter Department: ")
205
+ desig = input("Enter Designation: ")
206
+ sal = float(input("Enter Salary: "))
207
+ insert_employee(db, eid, name, dept, desig, sal)
208
+ print("Employee inserted.")
209
+ elif choice == "4":
210
+ eid = int(input("Enter Employee ID: "))
211
+ sal = float(input("Enter New Salary: "))
212
+ update_salary(db, eid, sal)
213
+ print("Salary updated.")
214
+ elif choice == "5":
215
+ eid = int(input("Enter Employee ID: "))
216
+ desig = input("Enter New Designation: ")
217
+ update_designation(db, eid, desig)
218
+ print("Designation updated.")
219
+ elif choice == "6":
220
+ eid = int(input("Enter Employee ID: "))
221
+ delete_employee(db, eid)
222
+ print("Employee deleted.")
223
+ elif choice == "7":
224
+ display_table(get_high_earners(db, 50000.0))
225
+ elif choice == "8":
226
+ run_automated_suite(db)
227
+ elif choice == "9":
228
+ db.close()
229
+ break
230
+ else:
231
+ print("Invalid selection.")
232
+ else:
233
+ run_automated_suite(db)
234
+ print("\nTip: To use the interactive menu, run:")
235
+ print(" python mysql_employee_manager.py --menu")
236
+ db.close()
237
+
238
+ if __name__ == "__main__":
239
+ main()
@@ -0,0 +1,98 @@
1
+ import os
2
+ import sys
3
+
4
+ try:
5
+ import requests
6
+ except ImportError:
7
+ print("Error: The 'requests' library is required.")
8
+ print("Install it with: pip install requests")
9
+ sys.exit(1)
10
+
11
+ def create_student(base_url, name, roll_number, course):
12
+ payload = {
13
+ "name": name.strip(),
14
+ "roll_number": str(roll_number).strip(),
15
+ "course": course.strip()
16
+ }
17
+ resp = requests.post(base_url, json=payload, timeout=8)
18
+ if resp.status_code not in (200, 201):
19
+ raise RuntimeError(f"POST failed with status {resp.status_code}: {resp.text}")
20
+ return resp.json()
21
+
22
+ def list_students(base_url):
23
+ resp = requests.get(base_url, timeout=8)
24
+ if resp.status_code != 200:
25
+ raise RuntimeError(f"GET failed with status {resp.status_code}: {resp.text}")
26
+ return resp.json()
27
+
28
+ def update_student(base_url, student_id, updated_data):
29
+ url = f"{base_url.rstrip('/')}/{student_id}"
30
+ resp = requests.put(url, json=updated_data, timeout=8)
31
+ if resp.status_code not in (200, 204):
32
+ raise RuntimeError(f"PUT failed with status {resp.status_code}: {resp.text}")
33
+ return True
34
+
35
+ def delete_student(base_url, student_id):
36
+ url = f"{base_url.rstrip('/')}/{student_id}"
37
+ resp = requests.delete(url, timeout=8)
38
+ if resp.status_code not in (200, 204):
39
+ raise RuntimeError(f"DELETE failed with status {resp.status_code}: {resp.text}")
40
+ return True
41
+
42
+ def display_student_list(students):
43
+ print(f"{'ID':<26} | {'Name':<18} | {'Roll No':<10} | {'Course':<20}")
44
+ print("-" * 80)
45
+ for s in students:
46
+ s_id = s.get("_id") or s.get("id", "N/A")
47
+ print(f"{str(s_id):<26} | {s.get('name', ''):<18} | {s.get('roll_number', ''):<10} | {s.get('course', ''):<20}")
48
+
49
+ def main():
50
+ print("=== CRUDCrud REST API Student Client ===")
51
+ api_endpoint = os.environ.get("CRUDCRUD_URL")
52
+ if not api_endpoint and len(sys.argv) > 1:
53
+ api_endpoint = sys.argv[1]
54
+
55
+ if not api_endpoint:
56
+ api_endpoint = "http://127.0.0.1:8000/api/students"
57
+ print(f"No custom CRUDCRUD_URL configured. Defaulting to local offline mock: {api_endpoint}")
58
+ print("To run against the local mock, start 'python mock_server.py' in a separate terminal.")
59
+ print("To run against live CRUDCrud, pass your active endpoint: python crud_client.py https://crudcrud.com/api/<id>/students\n")
60
+
61
+ try:
62
+ print("1. Creating 3 Students via POST...")
63
+ s1 = create_student(api_endpoint, "Aarav Sharma", "CS101", "Computer Science")
64
+ s2 = create_student(api_endpoint, "Diya Patel", "DS102", "Data Analytics")
65
+ s3 = create_student(api_endpoint, "Kabir Mehta", "CY103", "Cybersecurity")
66
+ print(" Students created successfully.")
67
+
68
+ print("\n2. Retrieving and displaying all students via GET:")
69
+ roster = list_students(api_endpoint)
70
+ display_student_list(roster)
71
+
72
+ id_to_update = s2.get("_id") or s2.get("id")
73
+ id_to_delete = s1.get("_id") or s1.get("id")
74
+
75
+ print(f"\n3. Updating 2nd Student ({id_to_update}) course to 'Artificial Intelligence' via PUT...")
76
+ update_student(api_endpoint, id_to_update, {
77
+ "name": "Diya Patel",
78
+ "roll_number": "DS102",
79
+ "course": "Artificial Intelligence"
80
+ })
81
+ print(" Update succeeded.")
82
+
83
+ print(f"\n4. Deleting 1st Student ({id_to_delete}) via DELETE...")
84
+ delete_student(api_endpoint, id_to_delete)
85
+ print(" Deletion succeeded.")
86
+
87
+ print("\n5. Final Student Roster:")
88
+ final_roster = list_students(api_endpoint)
89
+ display_student_list(final_roster)
90
+
91
+ except requests.exceptions.RequestException as net_err:
92
+ print(f"\nNetwork Communication Error: {net_err}")
93
+ print("Tip: If practicing offline, run 'python mock_server.py' to launch the built-in local REST server.")
94
+ except Exception as ex:
95
+ print(f"\nOperation Failed: {ex}")
96
+
97
+ if __name__ == "__main__":
98
+ main()
@@ -0,0 +1,85 @@
1
+ import json
2
+ from http.server import HTTPServer, BaseHTTPRequestHandler
3
+ import sys
4
+ import uuid
5
+
6
+ STUDENT_STORE = {}
7
+
8
+ class MockCRUDHandler(BaseHTTPRequestHandler):
9
+ def _send_json(self, data, status=200):
10
+ body = json.dumps(data).encode("utf-8")
11
+ self.send_response(status)
12
+ self.send_header("Content-Type", "application/json")
13
+ self.send_header("Content-Length", str(len(body)))
14
+ self.end_headers()
15
+ self.wfile.write(body)
16
+
17
+ def do_GET(self):
18
+ parts = self.path.strip("/").split("/")
19
+ if parts == ["api", "students"]:
20
+ self._send_json(list(STUDENT_STORE.values()))
21
+ elif len(parts) == 3 and parts[:2] == ["api", "students"]:
22
+ s_id = parts[2]
23
+ if s_id in STUDENT_STORE:
24
+ self._send_json(STUDENT_STORE[s_id])
25
+ else:
26
+ self._send_json({"error": "Not Found"}, status=404)
27
+ else:
28
+ self._send_json({"error": "Unknown endpoint"}, status=404)
29
+
30
+ def do_POST(self):
31
+ parts = self.path.strip("/").split("/")
32
+ if parts == ["api", "students"]:
33
+ length = int(self.headers.get("Content-Length", 0))
34
+ payload = json.loads(self.rfile.read(length).decode("utf-8"))
35
+ s_id = str(uuid.uuid4())[:8]
36
+ payload["_id"] = s_id
37
+ STUDENT_STORE[s_id] = payload
38
+ self._send_json(payload, status=201)
39
+ else:
40
+ self._send_json({"error": "Unknown endpoint"}, status=404)
41
+
42
+ def do_PUT(self):
43
+ parts = self.path.strip("/").split("/")
44
+ if len(parts) == 3 and parts[:2] == ["api", "students"]:
45
+ s_id = parts[2]
46
+ if s_id in STUDENT_STORE:
47
+ length = int(self.headers.get("Content-Length", 0))
48
+ payload = json.loads(self.rfile.read(length).decode("utf-8"))
49
+ payload["_id"] = s_id
50
+ STUDENT_STORE[s_id] = payload
51
+ self._send_json(payload, status=200)
52
+ else:
53
+ self._send_json({"error": "Not Found"}, status=404)
54
+ else:
55
+ self._send_json({"error": "Unknown endpoint"}, status=404)
56
+
57
+ def do_DELETE(self):
58
+ parts = self.path.strip("/").split("/")
59
+ if len(parts) == 3 and parts[:2] == ["api", "students"]:
60
+ s_id = parts[2]
61
+ if s_id in STUDENT_STORE:
62
+ del STUDENT_STORE[s_id]
63
+ self._send_json({"message": "Deleted"}, status=200)
64
+ else:
65
+ self._send_json({"error": "Not Found"}, status=404)
66
+ else:
67
+ self._send_json({"error": "Unknown endpoint"}, status=404)
68
+
69
+ def log_message(self, format, *args):
70
+ pass
71
+
72
+ def run(port=8000):
73
+ server_address = ("127.0.0.1", port)
74
+ httpd = HTTPServer(server_address, MockCRUDHandler)
75
+ print(f"Mock CRUDCrud server running at http://127.0.0.1:{port}/api/students")
76
+ print("Press Ctrl+C to terminate server.")
77
+ try:
78
+ httpd.serve_forever()
79
+ except KeyboardInterrupt:
80
+ print("\nShutting down server.")
81
+ httpd.server_close()
82
+
83
+ if __name__ == "__main__":
84
+ p = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
85
+ run(p)
@@ -0,0 +1,33 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>CGI Portal Login</title>
6
+ <style>
7
+ body { font-family: sans-serif; background: #f0f2f5; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
8
+ .card { background: white; padding: 32px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); width: 320px; }
9
+ h2 { margin-top: 0; color: #1a73e8; }
10
+ .field { margin-bottom: 16px; }
11
+ label { display: block; margin-bottom: 6px; font-weight: bold; font-size: 14px; }
12
+ input[type="text"], input[type="password"] { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }
13
+ button { width: 100%; padding: 10px; background: #1a73e8; color: white; border: none; border-radius: 4px; font-weight: bold; cursor: pointer; }
14
+ button:hover { background: #1557b0; }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <div class="card">
19
+ <h2>System Login</h2>
20
+ <form action="/login" method="POST">
21
+ <div class="field">
22
+ <label for="username">Username</label>
23
+ <input type="text" id="username" name="username" required>
24
+ </div>
25
+ <div class="field">
26
+ <label for="password">Password</label>
27
+ <input type="password" id="password" name="password" required>
28
+ </div>
29
+ <button type="submit">Log In</button>
30
+ </form>
31
+ </div>
32
+ </body>
33
+ </html>
@@ -0,0 +1,31 @@
1
+ import html
2
+ import urllib.parse
3
+
4
+ def handle_login(post_body):
5
+ params = urllib.parse.parse_qs(post_body)
6
+ username = params.get("username", ["Guest"])[0]
7
+ safe_user = html.escape(username)
8
+ masked_indicator = "[Protected & Encrypted]"
9
+
10
+ response = f"""<!DOCTYPE html>
11
+ <html lang="en">
12
+ <head>
13
+ <meta charset="UTF-8">
14
+ <title>Authentication Result</title>
15
+ <style>
16
+ body {{ font-family: sans-serif; background: #eef2f7; display: flex; justify-content: center; align-items: center; height: 100vh; }}
17
+ .box {{ background: white; padding: 32px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); max-width: 400px; }}
18
+ h2 {{ color: #2e7d32; }}
19
+ </style>
20
+ </head>
21
+ <body>
22
+ <div class="box">
23
+ <h2>Welcome, {safe_user}!</h2>
24
+ <p>Your authentication request was processed successfully via Python CGI.</p>
25
+ <p><strong>Username:</strong> {safe_user}</p>
26
+ <p><strong>Credential Status:</strong> {masked_indicator}</p>
27
+ <p><a href="/">Back to Login</a></p>
28
+ </div>
29
+ </body>
30
+ </html>"""
31
+ return response