From 514e2db6d25f5d6e8d78a87ac8020b38ce7cdf61 Mon Sep 17 00:00:00 2001 From: Samartha Bhat Date: Wed, 25 Mar 2026 22:28:11 +0530 Subject: [PATCH] Fix API errors, add env support, and handle future race data gracefully --- app/__pycache__/__init__.cpython-313.pyc | Bin 0 -> 166 bytes app/__pycache__/__init__.cpython-314.pyc | Bin 0 -> 168 bytes app/__pycache__/data_loader.cpython-313.pyc | Bin 0 -> 4260 bytes app/__pycache__/data_loader.cpython-314.pyc | Bin 0 -> 3961 bytes .../data_processor.cpython-313.pyc | Bin 0 -> 3577 bytes .../data_processor.cpython-314.pyc | Bin 0 -> 4273 bytes app/__pycache__/visualizer.cpython-313.pyc | Bin 0 -> 7852 bytes app/__pycache__/visualizer.cpython-314.pyc | Bin 0 -> 8638 bytes app/data_loader.py | 20 +++++++++---- main.py | 28 ++++++++++++++++-- 10 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 app/__pycache__/__init__.cpython-313.pyc create mode 100644 app/__pycache__/__init__.cpython-314.pyc create mode 100644 app/__pycache__/data_loader.cpython-313.pyc create mode 100644 app/__pycache__/data_loader.cpython-314.pyc create mode 100644 app/__pycache__/data_processor.cpython-313.pyc create mode 100644 app/__pycache__/data_processor.cpython-314.pyc create mode 100644 app/__pycache__/visualizer.cpython-313.pyc create mode 100644 app/__pycache__/visualizer.cpython-314.pyc diff --git a/app/__pycache__/__init__.cpython-313.pyc b/app/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..496745f967dfad784c344cf0d067b856514eff8f GIT binary patch literal 166 zcmey&%ge<81kYa`&IHkqK?DpiLK&Y~fQ+dO=?t2Tek&P@n1H;`AgNof&Q>v@#i>Qb zF~y0wiA6C1mB|^2MY#b*`B|ySCB-rR1*v&%hEOWLq_iZzC^Io9Cb6I(CO$qhFS8^* kUaz3?7Kcr4eoARhs$CH)&{UAE#UREk literal 0 HcmV?d00001 diff --git a/app/__pycache__/__init__.cpython-314.pyc b/app/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b482af89e361f7dcf59070bdb67fab7704add39 GIT binary patch literal 168 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 literal 0 HcmV?d00001 diff --git a/app/__pycache__/data_processor.cpython-313.pyc b/app/__pycache__/data_processor.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd8c337e55714bdde5537cc7ccce1bc0520f783e GIT binary patch literal 3577 zcmb`K&u<&Y6~||nKg3^BV#{I@Taku}VvDNGxV8n^imX<0s@4c%J7N_Suo_~;UD=!N zFU%}$(={69WThw&`CwGJGzwav6i~o9=Gq^BfHn#sXVXK_9*P7#u%LVBt?$k5%9OyM zO3(o~JHOt{o7vBP=dsn@ogt9^@ztO8)hr=@$4ZpqVWIT}6dsT=DNC;sCY9wyX+G+U z#=^54>)d`eUXC9nZ^c>cTUaK9W&B%MCWU39+|}7D@HPparNpSN>ryfOCGO?2FRROb zl4)*@SyicRd${8m{91P*dq5V*d|PK!90?1GOkl(?`3am^0@~)$a$gz`>)3DMd|23* z%5pjOk~|*zfun{=F@EQtnTv*|SX8l8>M+ewm_`l7p{n94blGO~rp{}Mq2Ezl-L^`Z z%t<<@8?MGUwQDX8<@A>B-oT1lW8tWiv}`k%)1^99nSN7a)T)_F@W5qo`k)Ha&9Liy zGD9J$%XGw1ORvDfb4)R{;v}6{ZnZhXY?IDhy#z+{;!H!kcAH5mcB83cAr3x3G1^Wk zP`+VIo2hN1cFm;hDsN@a)3pNsy6p>SWN84n_c~8KnRRp1B$_%3a+8;v!1j8yat~jI%Ni=d zH!!2BoGOS`r3xcmFfnQ-ejoo6=qH{ZjN~Wd13z}1)2(HD_k$8%@KT0#!NK`CVHCkE z`SMcTPeq1)SGW_u3;owD)lXxA18(k@NOe#bQx;s08@49&GQ4 zuocU4)(?%(;h3L72GI8JgI3^qrSaz0v8mO8t@H%|wC|bq%>6fa`bNFJ(Z>1hzVVgW zl{@cTew2T9{ki+*#!}8G(P4nXTyt+`LrP zs~9XOtWMn^b5QUth&L*sYr-?|354CSYv7ch#d*W(9*__sWW045 zvIpcEYNtpGyEt^dE2HDxeGx!PSy~`H%d@pN2v(^2gvLKMvUn`CaeE>%YzK6i$1E z(;uDLDNJ~UiM5$EWv#q+V(akq$FD;sKBn+uX+NoAm$)1J1e~H#_mc{D>yE|%DB`Dd zh!L56i~F*pGWb6L!6u{FBUStubol9A2YDRYF$4^5lYHlGu+uQ=2k_&6fD8oU2uU5f z_x8QFMJUuv5?X9L?+s4u3|{aCFMO7oZpCDpT)DJrdhz~diVS_H@jb8b@=jsaE6o1o z%y!|2&}Vz`fo6t0LwE8cUVh}${OIFE{7~|5`O$ahR%ia2?SAjvFVC%AT<`Xd9N)>F zXeCH`{8zEni)%ezZg4wAH(uB)VPS`A@4GY8*ex zKOP;PeLndoIS+X;I}NpCZGSn63n{6YWw{Y?VJ#?ZsD&9TQ=Y>pn0de+#l@7}-LBv5R~ v4|AKj$5?EZ&}!&|vG>OUtJ4psHm5?XV^ZJ7((jEAjV6KONAADzAw2po<7Zjf literal 0 HcmV?d00001 diff --git a/app/__pycache__/data_processor.cpython-314.pyc b/app/__pycache__/data_processor.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d717e4ddd9835b9b2d07291e9df3ae847e1065c0 GIT binary patch literal 4273 zcmd57&-6`tKCDUzZTOO_}nR;49nNTQ<9jbcNNA}f{bsxS=1^d?qwAVjRlm9_2u zVRmVmPEa#I0V_q(s6c}{K!7-Cib_CG_s~PG{W%v>R6@?ShXy?q33_0l7(s7+Z+4fW z7{PXWXfnXgzWI4GZ{Ex|-}K&X;MB5@ap!%2J} zk%T^?9dURm1ag?kf)oL{jmaS?3UZ9eVTl_enfNC-*b7Ata{Mrb;1l56dl|ASSs;u2 znI98Ug1UZknOor`E)OkU$_3U074Vn%2e+T(hsdVz32M50Y1xfX#VJ!`lXrQm)bI6__@YT2TU@G$C8}Oi zsA!b+CHUbqIJ{Sc;b!SodnztMDlLnnRw=u`$y1^vuQnM&OvGC9SdKtS!YUQ zt5Hg9BG^v{#9%quxSIgE5SZz9c(xThW8644dh({=h85j%DsC7Kf+4%@I9B1Btd$je zlcN!EC_8$?Gy$S}#6LgDC{kPijY5{; zC|ow)lGAL-3>PeW92){~^dLAO`vv{wt3Q9Wj^g|L-Na^s)$XqYbXdX}7&!g{!lQ!& zj`$&Pkl?Dz!ZDw0I^fYumk>)W-TbUHJ8WP70m1>i`=*;upD|u zy%7LhF*yZ>#B)BXY)3T!BLS|Q6-9JZK%4CVYLu%L5w9$VA*>ZVh#F5lzzsv8W{bLN z+p2L@ESkDymZ6(>L>VN-^cCZWhPi5_vw+&!Qppx&1Vf<+JsnWd$~q$Yp%C1+{L!$t z-`}&NVVr6#n~f`gSz%}6v9C?Z@BL?<{Q`|Fv05p8kNVC7*?+S6;jH z%?I+g(NO`A8!VT8XZ)>kkL4!rPH#>#mU{q@*O?c;UY3(W%~t?GF?{3G1`aLN0Wg_O z6vu!EC}P-aW;exfsH*G}oGenMXwnjpN&4P@+2@CdF&+f6`4 zgXI{!XgBN%?Z@mWX04d$3NV41=p37lLO*sQ=0NzW1a@g7zjb^H!SdY0DeOF(;D3rH zL!inMMvj1fjCTky1V z=#!Qdgp)_e748aO7EY2fKM%XJ%7gp5^9|O^Va(H#Qe=TYxRPMbAhf*--svY7#|X*e zwy*>`2lzSAX&q~czc^1wj0_MV*dkF$imjbAwg*)K=sHi7#O&h4TT(s zFB30XJ`ky*VN>Gyee=LF3)$O%H%-AejaddZ0ZVIU8H{qAPjvHp59pGK!O zSzjv2Gw$dT?m)qZAMGaz_9Ujln=Jcm{C-qAakf0f)#O>Czoe)r67 zYVyO>;m}7~Q*JaHCdnBeLyOEQR8&g*&KJ{Vr)JMs&dYFVE0tfwif+TvkLOuW4>wuDtkp08Z z$lOHakB<#No{6{-3phmf9fa={77DS8pDlHhc#dZ;oanS}mdctkL!XD9c+za7le)lh b+~3I2`w<8j?vFvZe?JS-7h`Z$GVT8YWwoDD literal 0 HcmV?d00001 diff --git a/app/__pycache__/visualizer.cpython-313.pyc b/app/__pycache__/visualizer.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10a380ebd4381c30b67c3c4f31ff850c34e47d0a GIT binary patch literal 7852 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 literal 0 HcmV?d00001 diff --git a/app/data_loader.py b/app/data_loader.py index 1052e9d1..d92f11dc 100644 --- a/app/data_loader.py +++ b/app/data_loader.py @@ -4,9 +4,10 @@ from dotenv import load_dotenv import os -load_dotenv() +load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), "..", ".env")) -BASE_URL = os.getenv("BASE_API_URL") +BASE_API_URL = os.getenv("BASE_API_URL") +print(BASE_API_URL) def fetch_data(endpoint, params=None): @@ -29,11 +30,18 @@ def fetch_data(endpoint, params=None): if params is None: params = {} - url = f"{BASE_URL}{endpoint}" + url = f"{BASE_API_URL}{endpoint}" full_url = requests.Request('GET', url, params=params).prepare().url - response = requests.get(full_url) - response.raise_for_status() - return pd.DataFrame(response.json()) + try: + response = requests.get(full_url) + + if response.status_code == 404: + return pd.DataFrame() + response.raise_for_status() + return pd.DataFrame(response.json()) + except requests.exceptions.RequestException as e: + print("API Error:", e) + return pd.DataFrame() # Cached API calls using Streamlit's cache_data decorator diff --git a/main.py b/main.py index adaccab4..f886c74d 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,5 @@ import streamlit as st +import datetime from app.data_loader import ( fetch_data, fetch_sessions, @@ -28,15 +29,19 @@ with col1: # Step 1: Select Year and Country dynamically - available_years = [2023, 2024, 2025] + available_years = [2023, 2024, 2025, 2026] selected_year = st.selectbox("Select Year", available_years, index=len(available_years) - 1) # Fetch all meetings for selected year all_meetings = fetch_data("meetings", {"year": selected_year}) + current_year = datetime.datetime.now().year if all_meetings.empty: - st.error("No meetings found for this year.") - st.stop() + if selected_year >= current_year: + st.warning("No race data yet. Showing upcoming schedule if available.") + else: + st.error("No meetings found for this year.") + st.stop() available_countries = sorted(all_meetings["country_name"].dropna().unique()) selected_country = st.selectbox("Select Country", available_countries) @@ -46,12 +51,21 @@ filtered_meetings["label"] = filtered_meetings["meeting_name"] + " - " + filtered_meetings["location"] filtered_meetings = filtered_meetings.sort_values(by="meeting_key", ascending=False) + if filtered_meetings.empty: + st.warning("🚧 No Grand Prix available yet for this selection.") + st.stop() + with col2: selected_meeting = st.selectbox("Select Grand Prix", filtered_meetings["label"], disabled=True) selected_meeting_key = filtered_meetings.loc[ filtered_meetings["label"] == selected_meeting, "meeting_key" ].values[0] sessions = fetch_sessions(selected_meeting_key) + + if sessions.empty: + st.info("📅 Session schedule not available yet.") + st.stop() + selected_session = st.selectbox("Select Session", sessions["label"]) sessions["session_type"] = sessions["label"].str.extract(r"^(.*?)\s\(") selected_session_type = sessions.loc[sessions["label"] == selected_session, "session_type"].values[0] @@ -72,8 +86,16 @@ with st.expander(f"📈 Lap Time Chart for {selected_session_type} at {selected_country} {selected_year}", expanded=True): lap_df = fetch_laps(selected_session_key) + + if lap_df.empty: + st.info("🚧 This session hasn't happened yet. Showing schedule only.") + st.stop() + processed_df = process_lap_data(lap_df) + if processed_df.empty: + st.info("🚧 This session hasn’t happened yet. Data will appear after completion.") + # Merge name_acronym into the lap data processed_df["driver_number"] = processed_df["driver_number"].astype(str) processed_df = processed_df.merge(driver_info, on="driver_number", how="left")