cwadayi commited on
Commit
8e064e1
·
verified ·
1 Parent(s): 8198489

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +160 -36
app.py CHANGED
@@ -2,64 +2,134 @@
2
 
3
  from fastapi import FastAPI, HTTPException
4
  from pydantic import BaseModel
5
- from typing import Union # Correct import for Union type hints in Python < 3.10
6
  import sqlite3
7
  import os
 
8
 
9
  # Define the Pydantic model for Item creation/update
10
  class Item(BaseModel):
11
- name: str
12
- description: Union[str, None] = None # Corrected syntax for Python 3.9
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  # Define the Pydantic model for Item update specifically (allowing partial updates)
15
- # This model allows all fields to be optional, so you can update just 'name' or just 'description'
16
  class ItemUpdate(BaseModel):
17
- name: Union[str, None] = None
18
- description: Union[str, None] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  app = FastAPI()
21
 
22
  # Define the path for your SQLite database file
23
- # This will be created in the /app directory of your Hugging Face Space.
24
- # Files in /app are generally persisted across restarts within a Space.
25
  DATABASE_FILE = os.path.join(os.getcwd(), "data.db")
 
26
 
27
  def get_db_connection():
28
  """Establishes and returns a SQLite database connection."""
29
  try:
30
  conn = sqlite3.connect(DATABASE_FILE)
31
- # Configure connection to return rows as dictionaries for easier access
32
  conn.row_factory = sqlite3.Row
33
  return conn
34
  except sqlite3.Error as err:
35
  print(f"Error connecting to database: {err}")
36
- # In a real-world scenario, you might want to log this error and potentially
37
- # use a more sophisticated error handling strategy.
38
  raise HTTPException(status_code=500, detail="Database connection error")
39
 
40
  @app.on_event("startup")
41
  async def startup_event():
42
  """
43
  Initializes the database: creates the 'items' table if it doesn't exist.
 
44
  This runs once when the FastAPI application starts.
45
  """
46
- conn = None # Initialize conn to None to ensure it's closed in finally block even if connection fails
47
  try:
48
  conn = get_db_connection()
49
  cursor = conn.cursor()
 
 
50
  cursor.execute("""
51
  CREATE TABLE IF NOT EXISTS items (
52
  id INTEGER PRIMARY KEY AUTOINCREMENT,
53
- name TEXT NOT NULL,
54
- description TEXT
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  )
56
  """)
57
  conn.commit()
58
  print(f"Database table 'items' checked/created successfully at {DATABASE_FILE}.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  except Exception as e:
60
  print(f"Error during database startup: {e}")
61
- # If critical tables cannot be created, the app might not function.
62
- # Consider raising the exception to prevent the app from starting in a broken state.
63
  finally:
64
  if conn:
65
  conn.close()
@@ -67,20 +137,39 @@ async def startup_event():
67
  @app.get("/")
68
  async def root():
69
  """Root endpoint for the API."""
70
- return {"message": "Welcome to the API!"}
71
 
72
  @app.post("/items/")
73
- async def create_item(item: Item): # FastAPI automatically expects JSON body based on Pydantic model
74
  """Creates a new item in the database."""
75
  conn = get_db_connection()
76
  cursor = conn.cursor()
77
  try:
78
- query = "INSERT INTO items (name, description) VALUES (?, ?)"
79
- cursor.execute(query, (item.name, item.description)) # Access data via item.name, item.description
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  conn.commit()
81
  return {"message": "Item created successfully", "id": cursor.lastrowid}
82
  except Exception as e:
83
- conn.rollback() # Rollback changes if an error occurs
84
  raise HTTPException(status_code=500, detail=f"Error creating item: {e}")
85
  finally:
86
  cursor.close()
@@ -94,7 +183,6 @@ async def read_items():
94
  try:
95
  cursor.execute("SELECT * FROM items")
96
  items = cursor.fetchall()
97
- # Convert sqlite3.Row objects to dictionaries for JSON serialization
98
  return {"items": [dict(item) for item in items]}
99
  except Exception as e:
100
  raise HTTPException(status_code=500, detail=f"Error reading items: {e}")
@@ -120,7 +208,7 @@ async def read_item(item_id: int):
120
  conn.close()
121
 
122
  @app.put("/items/{item_id}")
123
- async def update_item(item_id: int, item: ItemUpdate): # Use ItemUpdate for partial updates
124
  """Updates an existing item by its ID."""
125
  conn = get_db_connection()
126
  cursor = conn.cursor()
@@ -128,31 +216,68 @@ async def update_item(item_id: int, item: ItemUpdate): # Use ItemUpdate for part
128
  updates = []
129
  params = []
130
 
131
- if item.name is not None:
132
- updates.append("name = ?")
133
- params.append(item.name)
134
- if item.description is not None:
135
- updates.append("description = ?")
136
- params.append(item.description)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  if not updates:
139
- # If no fields were provided for update, return a 400 Bad Request
140
  raise HTTPException(status_code=400, detail="No fields to update provided")
141
 
142
  query = f"UPDATE items SET {', '.join(updates)} WHERE id = ?"
143
- params.append(item_id) # Add item_id to the end of parameters for the WHERE clause
144
 
145
  cursor.execute(query, tuple(params))
146
  conn.commit()
147
 
148
  if cursor.rowcount == 0:
149
- # If no rows were affected, the item with the given ID was not found
150
  raise HTTPException(status_code=404, detail="Item not found")
151
  return {"message": "Item updated successfully"}
152
- except HTTPException: # Re-raise FastAPI's own HTTPExceptions
153
  raise
154
  except Exception as e:
155
- conn.rollback() # Rollback changes if an error occurs
156
  raise HTTPException(status_code=500, detail=f"Error updating item: {e}")
157
  finally:
158
  cursor.close()
@@ -167,11 +292,10 @@ async def delete_item(item_id: int):
167
  cursor.execute("DELETE FROM items WHERE id = ?", (item_id,))
168
  conn.commit()
169
  if cursor.rowcount == 0:
170
- # If no rows were affected, the item with the given ID was not found
171
  raise HTTPException(status_code=404, detail="Item not found")
172
  return {"message": "Item deleted successfully"}
173
  except Exception as e:
174
- conn.rollback() # Rollback changes if an error occurs
175
  raise HTTPException(status_code=500, detail=f"Error deleting item: {e}")
176
  finally:
177
  cursor.close()
 
2
 
3
  from fastapi import FastAPI, HTTPException
4
  from pydantic import BaseModel
5
+ from typing import Union
6
  import sqlite3
7
  import os
8
+ import pandas as pd # Import pandas for CSV reading
9
 
10
  # Define the Pydantic model for Item creation/update
11
  class Item(BaseModel):
12
+ date: str
13
+ time: str
14
+ lat: float
15
+ lon: float
16
+ depth: float
17
+ ML: float
18
+ nstn: int
19
+ dmin: float
20
+ gap: int
21
+ trms: float
22
+ ERH: float
23
+ ERZ: float
24
+ fixed: str
25
+ nph: int
26
+ quality: str
27
 
28
  # Define the Pydantic model for Item update specifically (allowing partial updates)
 
29
  class ItemUpdate(BaseModel):
30
+ date: Union[str, None] = None
31
+ time: Union[str, None] = None
32
+ lat: Union[float, None] = None
33
+ lon: Union[float, None] = None
34
+ depth: Union[float, None] = None
35
+ ML: Union[float, None] = None
36
+ nstn: Union[int, None] = None
37
+ dmin: Union[float, None] = None
38
+ gap: Union[int, None] = None
39
+ trms: Union[float, None] = None
40
+ ERH: Union[float, None] = None
41
+ ERZ: Union[float, None] = None
42
+ fixed: Union[str, None] = None
43
+ nph: Union[int, None] = None
44
+ quality: Union[str, None] = None
45
 
46
  app = FastAPI()
47
 
48
  # Define the path for your SQLite database file
 
 
49
  DATABASE_FILE = os.path.join(os.getcwd(), "data.db")
50
+ CSV_FILE_PATH = "GDMScatalog.csv" # Path to your CSV file
51
 
52
  def get_db_connection():
53
  """Establishes and returns a SQLite database connection."""
54
  try:
55
  conn = sqlite3.connect(DATABASE_FILE)
 
56
  conn.row_factory = sqlite3.Row
57
  return conn
58
  except sqlite3.Error as err:
59
  print(f"Error connecting to database: {err}")
 
 
60
  raise HTTPException(status_code=500, detail="Database connection error")
61
 
62
  @app.on_event("startup")
63
  async def startup_event():
64
  """
65
  Initializes the database: creates the 'items' table if it doesn't exist.
66
+ Also, populates the database with data from the CSV file if the table is empty.
67
  This runs once when the FastAPI application starts.
68
  """
69
+ conn = None
70
  try:
71
  conn = get_db_connection()
72
  cursor = conn.cursor()
73
+
74
+ # Create table if it doesn't exist
75
  cursor.execute("""
76
  CREATE TABLE IF NOT EXISTS items (
77
  id INTEGER PRIMARY KEY AUTOINCREMENT,
78
+ date TEXT NOT NULL,
79
+ time TEXT NOT NULL,
80
+ lat REAL NOT NULL,
81
+ lon REAL NOT NULL,
82
+ depth REAL NOT NULL,
83
+ ML REAL NOT NULL,
84
+ nstn INTEGER NOT NULL,
85
+ dmin REAL NOT NULL,
86
+ gap INTEGER NOT NULL,
87
+ trms REAL NOT NULL,
88
+ ERH REAL NOT NULL,
89
+ ERZ REAL NOT NULL,
90
+ fixed TEXT NOT NULL,
91
+ nph INTEGER NOT NULL,
92
+ quality TEXT NOT NULL
93
  )
94
  """)
95
  conn.commit()
96
  print(f"Database table 'items' checked/created successfully at {DATABASE_FILE}.")
97
+
98
+ # Check if the table is empty and populate from CSV
99
+ cursor.execute("SELECT COUNT(*) FROM items")
100
+ count = cursor.fetchone()[0]
101
+
102
+ if count == 0:
103
+ print("Table 'items' is empty. Populating from CSV file...")
104
+ if os.path.exists(CSV_FILE_PATH):
105
+ try:
106
+ df = pd.read_csv(CSV_FILE_PATH)
107
+ # Convert DataFrame to a list of tuples for insertion
108
+ # Ensure the order of columns matches the INSERT query
109
+ data_to_insert = [
110
+ (row['date'], row['time'], row['lat'], row['lon'], row['depth'],
111
+ row['ML'], row['nstn'], row['dmin'], row['gap'], row['trms'],
112
+ row['ERH'], row['ERZ'], row['fixed'], row['nph'], row['quality'])
113
+ for index, row in df.iterrows()
114
+ ]
115
+
116
+ insert_query = """
117
+ INSERT INTO items (date, time, lat, lon, depth, ML, nstn, dmin, gap, trms, ERH, ERZ, fixed, nph, quality)
118
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
119
+ """
120
+ cursor.executemany(insert_query, data_to_insert)
121
+ conn.commit()
122
+ print(f"Successfully inserted {len(data_to_insert)} records from {CSV_FILE_PATH}.")
123
+ except Exception as e:
124
+ print(f"Error populating database from CSV: {e}")
125
+ conn.rollback() # Rollback if CSV insertion fails
126
+ else:
127
+ print(f"CSV file not found at {CSV_FILE_PATH}. Database not populated.")
128
+ else:
129
+ print(f"Table 'items' already contains {count} records. Skipping CSV import.")
130
+
131
  except Exception as e:
132
  print(f"Error during database startup: {e}")
 
 
133
  finally:
134
  if conn:
135
  conn.close()
 
137
  @app.get("/")
138
  async def root():
139
  """Root endpoint for the API."""
140
+ return {"message": "Welcome to the API! https://cwadayi-sqlite-api.hf.space/items/"}
141
 
142
  @app.post("/items/")
143
+ async def create_item(item: Item):
144
  """Creates a new item in the database."""
145
  conn = get_db_connection()
146
  cursor = conn.cursor()
147
  try:
148
+ query = """
149
+ INSERT INTO items (date, time, lat, lon, depth, ML, nstn, dmin, gap, trms, ERH, ERZ, fixed, nph, quality)
150
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
151
+ """
152
+ cursor.execute(query, (
153
+ item.date,
154
+ item.time,
155
+ item.lat,
156
+ item.lon,
157
+ item.depth,
158
+ item.ML,
159
+ item.nstn,
160
+ item.dmin,
161
+ item.gap,
162
+ item.trms,
163
+ item.ERH,
164
+ item.ERZ,
165
+ item.fixed,
166
+ item.nph,
167
+ item.quality
168
+ ))
169
  conn.commit()
170
  return {"message": "Item created successfully", "id": cursor.lastrowid}
171
  except Exception as e:
172
+ conn.rollback()
173
  raise HTTPException(status_code=500, detail=f"Error creating item: {e}")
174
  finally:
175
  cursor.close()
 
183
  try:
184
  cursor.execute("SELECT * FROM items")
185
  items = cursor.fetchall()
 
186
  return {"items": [dict(item) for item in items]}
187
  except Exception as e:
188
  raise HTTPException(status_code=500, detail=f"Error reading items: {e}")
 
208
  conn.close()
209
 
210
  @app.put("/items/{item_id}")
211
+ async def update_item(item_id: int, item: ItemUpdate):
212
  """Updates an existing item by its ID."""
213
  conn = get_db_connection()
214
  cursor = conn.cursor()
 
216
  updates = []
217
  params = []
218
 
219
+ if item.date is not None:
220
+ updates.append("date = ?")
221
+ params.append(item.date)
222
+ if item.time is not None:
223
+ updates.append("time = ?")
224
+ params.append(item.time)
225
+ if item.lat is not None:
226
+ updates.append("lat = ?")
227
+ params.append(item.lat)
228
+ if item.lon is not None:
229
+ updates.append("lon = ?")
230
+ params.append(item.lon)
231
+ if item.depth is not None:
232
+ updates.append("depth = ?")
233
+ params.append(item.depth)
234
+ if item.ML is not None:
235
+ updates.append("ML = ?")
236
+ params.append(item.ML)
237
+ if item.nstn is not None:
238
+ updates.append("nstn = ?")
239
+ params.append(item.nstn)
240
+ if item.dmin is not None:
241
+ updates.append("dmin = ?")
242
+ params.append(item.dmin)
243
+ if item.gap is not None:
244
+ updates.append("gap = ?")
245
+ params.append(item.gap)
246
+ if item.trms is not None:
247
+ updates.append("trms = ?")
248
+ params.append(item.trms)
249
+ if item.ERH is not None:
250
+ updates.append("ERH = ?")
251
+ params.append(item.ERH)
252
+ if item.ERZ is not None:
253
+ updates.append("ERZ = ?")
254
+ params.append(item.ERZ)
255
+ if item.fixed is not None:
256
+ updates.append("fixed = ?")
257
+ params.append(item.fixed)
258
+ if item.nph is not None:
259
+ updates.append("nph = ?")
260
+ params.append(item.nph)
261
+ if item.quality is not None:
262
+ updates.append("quality = ?")
263
+ params.append(item.quality)
264
 
265
  if not updates:
 
266
  raise HTTPException(status_code=400, detail="No fields to update provided")
267
 
268
  query = f"UPDATE items SET {', '.join(updates)} WHERE id = ?"
269
+ params.append(item_id)
270
 
271
  cursor.execute(query, tuple(params))
272
  conn.commit()
273
 
274
  if cursor.rowcount == 0:
 
275
  raise HTTPException(status_code=404, detail="Item not found")
276
  return {"message": "Item updated successfully"}
277
+ except HTTPException:
278
  raise
279
  except Exception as e:
280
+ conn.rollback()
281
  raise HTTPException(status_code=500, detail=f"Error updating item: {e}")
282
  finally:
283
  cursor.close()
 
292
  cursor.execute("DELETE FROM items WHERE id = ?", (item_id,))
293
  conn.commit()
294
  if cursor.rowcount == 0:
 
295
  raise HTTPException(status_code=404, detail="Item not found")
296
  return {"message": "Item deleted successfully"}
297
  except Exception as e:
298
+ conn.rollback()
299
  raise HTTPException(status_code=500, detail=f"Error deleting item: {e}")
300
  finally:
301
  cursor.close()