-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmini_project.py
More file actions
92 lines (77 loc) · 3.98 KB
/
Copy pathmini_project.py
File metadata and controls
92 lines (77 loc) · 3.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
"""
Chapter 18: Mini Project — Database Transaction Manager
=======================================================
A professional-grade implementation of a context manager that handles
database transactions. It automatically commits if the block succeeds,
and automatically rolls back if an exception is raised.
"""
import sys
from contextlib import contextmanager
sys.stdout.reconfigure(encoding="utf-8")
# ─────────────────────────────────────────────────────────────────────────────
# Mock Database Connection
# ─────────────────────────────────────────────────────────────────────────────
class MockDatabaseConnection:
def __init__(self):
self.state = "connected"
self.transactions_committed = 0
self.transactions_rolled_back = 0
def execute(self, query):
if "DROP" in query.upper():
raise ValueError(f"Dangerous query detected: {query}")
print(f" [DB] Executing: {query}")
def commit(self):
self.transactions_committed += 1
print(" [DB] COMMIT successful.")
def rollback(self):
self.transactions_rolled_back += 1
print(" [DB] ROLLBACK successful. Data preserved.")
def close(self):
self.state = "closed"
print(" [DB] Connection securely closed.")
# ─────────────────────────────────────────────────────────────────────────────
# The Context Manager
# ─────────────────────────────────────────────────────────────────────────────
@contextmanager
def transaction():
"""
A transactional context manager.
Yields a live database connection.
Commits on success, rolls back on exception, and closes safely.
"""
conn = MockDatabaseConnection()
try:
# Pass the connection to the user's `with` block
yield conn
# If the block finishes without errors, we arrive here
conn.commit()
except Exception as e:
# If ANY error happens in the `with` block, we catch it here
print(f" [CM] Caught exception: {e}")
conn.rollback()
# We must re-raise the exception so the caller knows it failed
raise
finally:
# This will ALWAYS run, whether we hit the commit or the rollback
conn.close()
# ─────────────────────────────────────────────────────────────────────────────
# Pipeline Execution
# ─────────────────────────────────────────────────────────────────────────────
def main():
print("=" * 60)
print(" Transaction Manager Pipeline")
print("=" * 60)
print("\n--- Scenario 1: The Happy Path ---")
with transaction() as db:
db.execute("INSERT INTO users (name) VALUES ('Alice')")
db.execute("UPDATE stats SET count = count + 1")
print("\n--- Scenario 2: The Exception Path ---")
try:
with transaction() as db:
db.execute("INSERT INTO users (name) VALUES ('Bob')")
# This will trigger our ValueError inside the DB mock
db.execute("DROP TABLE users")
except ValueError:
print(" [Main] Application handled the dropped exception.")
if __name__ == "__main__":
main()