From eb57fce1c1741294d7c6ef56ef9fad5562fc51ea Mon Sep 17 00:00:00 2001 From: Minotriz02 Date: Tue, 28 May 2024 13:22:20 -0500 Subject: [PATCH 1/7] agronomy error and document --- src/aclimate_api/agronomy.py | 72 ++++++++++++++++++++++++------------ src/aclimate_api/main.py | 2 +- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/aclimate_api/agronomy.py b/src/aclimate_api/agronomy.py index d481e82..8f78a75 100644 --- a/src/aclimate_api/agronomy.py +++ b/src/aclimate_api/agronomy.py @@ -2,38 +2,64 @@ import json import pandas as pd - class Agronomy: def __init__(self, url_root): self.url_root = url_root + """ + Retrieves agronomy data from the API. + + Returns: + dict: A dictionary containing two DataFrames: 'cultivars' and 'soils'. + The 'cultivars' DataFrame contains information about different cultivars, + including crop ID, crop name, cultivar ID, cultivar name, rainfed status, + and national status. + The 'soils' DataFrame contains information about different soils, + including crop ID, crop name, soil ID, and soil name. + """ def get_agronomy(self): - url = f"{self.url_root}Agronomic/true/json" - response = requests.get(url) - data = json.loads(response.text) + try: + url = f"{self.url_root}Agronomic/true/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None - cultivars_data = [] - for crop in data: - for cultivar in crop['cultivars']: - cultivars_data.append({ - 'crop_id': crop['cp_id'], - 'crop_name': crop['cp_name'], - 'cultivar_id': cultivar['id'], - 'cultivar_name': cultivar['name'], - 'cultivar_rainfed': cultivar['rainfed'], - 'cultivar_national': cultivar['national'] - }) + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + cultivars_data = [] soils_data = [] - for crop in data: - for soil in crop['soils']: - soils_data.append({ - 'crop_id': crop['cp_id'], - 'crop_name': crop['cp_name'], - 'soil_id': soil['id'], - 'soil_name': soil['name'] - }) + try: + for crop in data: + for cultivar in crop['cultivars']: + cultivars_data.append({ + 'crop_id': crop['cp_id'], + 'crop_name': crop['cp_name'], + 'cultivar_id': cultivar['id'], + 'cultivar_name': cultivar['name'], + 'cultivar_rainfed': cultivar['rainfed'], + 'cultivar_national': cultivar['national'] + }) + + for soil in crop['soils']: + soils_data.append({ + 'crop_id': crop['cp_id'], + 'crop_name': crop['cp_name'], + 'soil_id': soil['id'], + 'soil_name': soil['name'] + }) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None agronomy = {'cultivars': pd.DataFrame(cultivars_data), 'soils': pd.DataFrame(soils_data)} return agronomy diff --git a/src/aclimate_api/main.py b/src/aclimate_api/main.py index add1b05..66ef7eb 100644 --- a/src/aclimate_api/main.py +++ b/src/aclimate_api/main.py @@ -11,7 +11,7 @@ def main(): f = Forecast("https://webapi.aclimate.org/api/") # print(f.get_forecast_climate(["5a7e422057d7f316c8bc574e"])) a = Agronomy("https://webapi.aclimate.org/api/") - # print(a.get_agronomy()) + print(a.get_agronomy()) h = Historical("https://webapi.aclimate.org/api/") # print(h.get_historical_climatology(["5a7e422057d7f316c8bc574e"])) gs = Geoserver("https://geo.aclimate.org/geoserver/") From 80aceffe240268d7d545d31604d1aecd55aa7874 Mon Sep 17 00:00:00 2001 From: Minotriz02 Date: Tue, 28 May 2024 13:47:24 -0500 Subject: [PATCH 2/7] forecast error and document --- src/aclimate_api/forecast.py | 490 +++++++++++++++++++++++++---------- src/aclimate_api/main.py | 4 +- 2 files changed, 350 insertions(+), 144 deletions(-) diff --git a/src/aclimate_api/forecast.py b/src/aclimate_api/forecast.py index 817a432..3ea2ce7 100644 --- a/src/aclimate_api/forecast.py +++ b/src/aclimate_api/forecast.py @@ -7,168 +7,319 @@ class Forecast: def __init__(self, url_root): self.url_root = url_root + + """ + Retrieves the forecast climate data for the given weather stations. + + Args: + stations (list): A list of weather station IDs. + + Returns: + dict: A dictionary containing the forecast climate data, including probabilities, + performance, and scenarios. The keys of the dictionary are 'probabilities', + 'performance', and 'scenarios', and the values are pandas DataFrames. + + """ def get_forecast_climate(self, stations): - ws = ",".join(stations) - url = f"{self.url_root}Forecast/Climate/{ws}/true/json" - response = requests.get(url) - data = json.loads(response.text) + try: + ws = ",".join(stations) + url = f"{self.url_root}Forecast/Climate/{ws}/true/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None df_prob_list = [] - for w in data['climate']: - for wd in w['data']: - for p in wd['probabilities']: + df_perf_list = [] + df_scen_list = [] + try: + for w in data['climate']: + for wd in w['data']: + for p in wd['probabilities']: + if isinstance(p, dict) and all(isinstance(v, (int, float, str)) for v in p.values()): + df = pd.DataFrame(p, index=[0]) + else: + df = pd.DataFrame(p) + df = df.assign(ws_id=w['weather_station'], year=wd['year'], month=wd['month']) + df_prob_list.append(df) + + for p in w['performance']: if isinstance(p, dict) and all(isinstance(v, (int, float, str)) for v in p.values()): df = pd.DataFrame(p, index=[0]) else: df = pd.DataFrame(p) - df = df.assign(ws_id=w['weather_station'], year=wd['year'], month=wd['month']) - df_prob_list.append(df) - df_prob = pd.concat(df_prob_list, ignore_index=True) + df_perf_list.append(df) - df_perf_list = [] - for w in data['climate']: - for p in w['performance']: - if isinstance(p, dict) and all(isinstance(v, (int, float, str)) for v in p.values()): - df = pd.DataFrame(p, index=[0]) - else: - df = pd.DataFrame(p) - df_perf_list.append(df) - df_perf = pd.concat(df_perf_list, ignore_index=True) + for w in data['scenario']: + for wm in w['monthly_data']: + for d in wm['data']: + if isinstance(d, dict) and all(isinstance(v, (int, float, str)) for v in d.values()): + df = pd.DataFrame(d, index=[0]) + else: + df = pd.DataFrame(d) + df = df.assign(ws_id=w['weather_station'], scenario=w['name'], year=w['year'], month=wm['month']) + df_scen_list.append(df) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None - df_scen_list = [] - for w in data['scenario']: - for wm in w['monthly_data']: - for d in wm['data']: - if isinstance(d, dict) and all(isinstance(v, (int, float, str)) for v in d.values()): - df = pd.DataFrame(d, index=[0]) - else: - df = pd.DataFrame(d) - df = df.assign(ws_id=w['weather_station'], scenario=w['name'], year=w['year'], month=wm['month']) - df_scen_list.append(df) + df_prob = pd.concat(df_prob_list, ignore_index=True) + df_perf = pd.concat(df_perf_list, ignore_index=True) df_scen = pd.concat(df_scen_list, ignore_index=True) forecast_climate = {'probabilities': df_prob, 'performance': df_perf, 'scenarios': df_scen} return forecast_climate # print(get_forecast_climate("https://webapi.aclimate.org/api/", ["5a7e422057d7f316c8bc574e"])) + """ + Retrieves the forecast yield data for the specified weather stations. + + Args: + stations (list): A list of weather station IDs. + Returns: + pandas.DataFrame: A DataFrame containing the forecast yield data for the specified weather stations. + """ def get_forecast_crop(self, stations): - ws = ",".join(stations) - url = f"{self.url_root}Forecast/Yield/{ws}/json" - response = requests.get(url) - data = json.loads(response.text) - + try: + ws = ",".join(stations) + url = f"{self.url_root}Forecast/Yield/{ws}/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + df_yield_list = [] - for w in data.get('yield', []): - for wy in w.get('yield', []): - for y in wy.get('data', []): - if isinstance(y, dict) and all(isinstance(v, (int, float, str)) for v in y.values()): - df = pd.DataFrame(y, index=[0]) - else: - df = pd.DataFrame(y) - df = df.assign(ws_id=w['weather_station'], cultivar=wy['cultivar'], soil=wy['soil'], start=wy['start'], end=wy['end']) - df_yield_list.append(df) + try: + for w in data.get('yield', []): + for wy in w.get('yield', []): + for y in wy.get('data', []): + if isinstance(y, dict) and all(isinstance(v, (int, float, str)) for v in y.values()): + df = pd.DataFrame(y, index=[0]) + else: + df = pd.DataFrame(y) + df = df.assign(ws_id=w['weather_station'], cultivar=wy['cultivar'], soil=wy['soil'], start=wy['start'], end=wy['end']) + df_yield_list.append(df) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None + df = pd.concat(df_yield_list, ignore_index=True) if df_yield_list else pd.DataFrame() return df # print(get_forecast_crop("https://webapi.aclimate.org/api/", ["5a7e422057d7f316c8bc574e"])) + """ + Retrieves forecast information for a given year. + + Args: + year (int): The year for which to retrieve the forecast information. + + Returns: + pandas.DataFrame: A DataFrame containing the forecast information, including columns for 'id', 'start', 'end', and 'confidence'. + """ def get_forecast_information(self, year): - url = f"{self.url_root}Forecast/Log/{year}/json" - response = requests.get(url) - data = json.loads(response.text) - + try: + url = f"{self.url_root}Forecast/Log/{year}/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + df_list = [] - for c in data: - df = pd.DataFrame({ - 'id': c['id'], - 'start': c['start'], - 'end': c['end'], - 'confindece': c['confindece'] - }, index=[0]) - df_list.append(df) + try: + for c in data: + df = pd.DataFrame({ + 'id': c['id'], + 'start': c['start'], + 'end': c['end'], + 'confidence': c['confindece'] + }, index=[0]) + df_list.append(df) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None + df = pd.concat(df_list, ignore_index=True) - return df # print(get_forecast_information("https://webapi.aclimate.org/api/", 2021)) - def get_forecast_subseasonal(url_root, stations): - ws = ",".join(stations) - url = f"{url_root}Forecast/SubseasonalWS/{ws}/json" - response = requests.get(url) - data = json.loads(response.text) + """ + Retrieves the subseasonal forecast data for the given weather stations. + + Args: + stations (list): A list of weather station IDs. + + Returns: + pandas.DataFrame: A DataFrame containing the subseasonal forecast data. + The DataFrame has the following columns: + - weather_station: The ID of the weather station. + - year: The year of the forecast. + - month: The month of the forecast. + - week: The week of the forecast. + - measure: The measure of the forecast. + - lower: The lower bound of the forecast. + - normal: The normal value of the forecast. + - upper: The upper bound of the forecast. + + If no subseasonal forecast data is available, an empty DataFrame is returned. + """ + def get_forecast_subseasonal(self, stations): + try: + ws = ",".join(stations) + url = f"{self.url_root}Forecast/SubseasonalWS/{ws}/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None if not data.get('subseasonal'): - return pd.DataFrame() + return pd.DataFrame() data_list = [] - for x in data['subseasonal']: - if not x.get('data'): - continue - for y in x['data']: - if not y.get('probabilities'): - continue - for z in y['probabilities']: - data_dict = { - 'weather_station': x['weather_station'], - 'year': y['year'], - 'month': y['month'], - 'week': y['week'], - 'measure': z['measure'], - 'lower': z['lower'], - 'normal': z['normal'], - 'upper': z['upper'] - } - data_list.append(data_dict) + try: + for x in data['subseasonal']: + if not x.get('data'): + continue + for y in x['data']: + if not y.get('probabilities'): + continue + for z in y['probabilities']: + data_dict = { + 'weather_station': x['weather_station'], + 'year': y['year'], + 'month': y['month'], + 'week': y['week'], + 'measure': z['measure'], + 'lower': z['lower'], + 'normal': z['normal'], + 'upper': z['upper'] + } + data_list.append(data_dict) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None if not data_list: - return pd.DataFrame() + return pd.DataFrame() df = pd.DataFrame(data_list) return df # print(get_forecast_subseasonal("https://webapi.aclimate.org/api/", ["5a7e422057d7f316c8bc574e"])) + """ + Retrieves the forecast climate data for previous periods. + + Args: + forecast (str): The forecast identifier. + stations (list): A list of weather station IDs. + + Returns: + dict: A dictionary containing the forecast climate data for previous periods. + The dictionary has the following keys: + - 'probabilities': A pandas DataFrame containing the probability data. + - 'performance': A pandas DataFrame containing the performance data. + - 'scenarios': A pandas DataFrame containing the scenario data. + """ def get_forecast_climate_previous(self, forecast, stations): - ws = ",".join(stations) - url = f"{self.url_root}Forecast/ClimatePrevious/{forecast}/{ws}/true/json" - response = requests.get(url) - data = json.loads(response.text) - + try: + ws = ",".join(stations) + url = f"{self.url_root}Forecast/ClimatePrevious/{forecast}/{ws}/true/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + df_prob_list = [] - for w in data['climate']: - for wd in w['data']: - for p in wd['probabilities']: + df_perf_list = [] + df_scen_list = [] + + try: + for w in data['climate']: + for wd in w['data']: + for p in wd['probabilities']: + if isinstance(p, dict) and all(isinstance(value, (int, float, str)) for value in p.values()): + df = pd.DataFrame(p, index=[0]) + else: + df = pd.DataFrame(p) + df = df.assign(ws_id=w['weather_station'], year=wd['year'], month=wd['month']) + df_prob_list.append(df) + + for p in w['performance']: if isinstance(p, dict) and all(isinstance(value, (int, float, str)) for value in p.values()): df = pd.DataFrame(p, index=[0]) else: df = pd.DataFrame(p) - df = df.assign(ws_id=w['weather_station'], year=wd['year'], month=wd['month']) - df_prob_list.append(df) - df_prob = pd.concat(df_prob_list, ignore_index=True) + df = df.assign(ws_id=w['weather_station'], year=p['year'], month=p['month']) + df_perf_list.append(df) - df_perf_list = [] - for w in data['climate']: - for p in w['performance']: - if isinstance(p, dict) and all(isinstance(value, (int, float, str)) for value in p.values()): - df = pd.DataFrame(p, index=[0]) - else: - df = pd.DataFrame(p) - df = df.assign(ws_id=w['weather_station'], year=p['year'], month=p['month']) - df_perf_list.append(df) - df_perf = pd.concat(df_perf_list, ignore_index=True) + for w in data['scenario']: + for wm in w['monthly_data']: + for d in wm['data']: + if isinstance(d, dict) and all(isinstance(value, (int, float, str)) for value in d.values()): + df = pd.DataFrame(d, index=[0]) + else: + df = pd.DataFrame(d) + df = df.assign(ws_id=w['weather_station'], scenario=w['name'], year=w['year'], month=wm['month']) + df_scen_list.append(df) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None - df_scen_list = [] - for w in data['scenario']: - for wm in w['monthly_data']: - for d in wm['data']: - if isinstance(d, dict) and all(isinstance(value, (int, float, str)) for value in d.values()): - df = pd.DataFrame(d, index=[0]) - else: - df = pd.DataFrame(d) - df = df.assign(ws_id=w['weather_station'], scenario=w['name'], year=w['year'], month=wm['month']) - df_scen_list.append(df) + df_prob = pd.concat(df_prob_list, ignore_index=True) + df_perf = pd.concat(df_perf_list, ignore_index=True) df_scen = pd.concat(df_scen_list, ignore_index=True) forecast_climate_previous = {'probabilities': df_prob, 'performance': df_perf, 'scenarios': df_scen} @@ -177,22 +328,50 @@ def get_forecast_climate_previous(self, forecast, stations): # print(get_forecast_climate_previous("https://webapi.aclimate.org/api/", "602d1da7a1c81c22b08683b5", ["5a7e422057d7f316c8bc574e"])) + """ + Retrieves the previous yield forecast for a given forecast and list of weather stations. + + Args: + forecast (str): The forecast identifier. + stations (list): A list of weather station identifiers. + + Returns: + pandas.DataFrame: A DataFrame containing the forecasted yield data for the specified forecast and weather stations. + """ def get_forecast_crop_previous(self, forecast, stations): - ws = ",".join(stations) - url = f"{self.url_root}Forecast/YieldPrevious/{forecast}/{ws}/json" - response = requests.get(url) - data = json.loads(response.text) - + try: + ws = ",".join(stations) + url = f"{self.url_root}Forecast/YieldPrevious/{forecast}/{ws}/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + df_list = [] - for w in data.get('yield', []): - for wy in w.get('yield', []): - for y in wy.get('data', []): - if isinstance(y, dict) and all(isinstance(value, (int, float, str)) for value in y.values()): - df = pd.DataFrame(y, index=[0]) - else: - df = pd.DataFrame(y) - df = df.assign(ws_id=w['weather_station'], cultivar=wy['cultivar'], soil=wy['soil'], start=wy['start'], end=wy['end']) - df_list.append(df) + try: + for w in data.get('yield', []): + for wy in w.get('yield', []): + for y in wy.get('data', []): + if isinstance(y, dict) and all(isinstance(value, (int, float, str)) for value in y.values()): + df = pd.DataFrame(y, index=[0]) + else: + df = pd.DataFrame(y) + df = df.assign(ws_id=w['weather_station'], cultivar=wy['cultivar'], soil=wy['soil'], start=wy['start'], end=wy['end']) + df_list.append(df) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None + if df_list: df = pd.concat(df_list, ignore_index=True) else: @@ -202,24 +381,51 @@ def get_forecast_crop_previous(self, forecast, stations): # print(get_forecast_crop_previous("https://webapi.aclimate.org/api/", "602d1da7a1c81c22b08683b5", ["5a7e422057d7f316c8bc574e"])) - def get_forecast_crop_exc(self, stations): - ws = ",".join(stations) - url = f"{self.url_root}Forecast/YieldExceedance/{ws}/json" - response = requests.get(url) - data = json.loads(response.text) - + """ + Retrieves the forecast crop exceedance data for the given weather stations. + + Args: + stations (list): A list of weather station IDs. + + Returns: + pandas.DataFrame: A DataFrame containing the forecast crop exceedance data. + """ + def get_forecast_crop_exc(self, stations): + try: + ws = ",".join(stations) + url = f"{self.url_root}Forecast/YieldExceedance/{ws}/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + df_yield_list = [] - for w in data.get('yield', []): - for wy in w.get('yield', []): - for y in wy.get('data', []): - if isinstance(y, dict) and all(isinstance(v, (int, float, str)) for v in y.values()): - df = pd.DataFrame(y, index=[0]) - else: - df = pd.DataFrame(y) - df = df.assign(ws_id=w['weather_station'], cultivar=wy['cultivar'], soil=wy['soil'], start=wy['start'], end=wy['end']) - df_yield_list.append(df) + try: + for w in data.get('yield', []): + for wy in w.get('yield', []): + for y in wy.get('data', []): + if isinstance(y, dict) and all(isinstance(v, (int, float, str)) for v in y.values()): + df = pd.DataFrame(y, index=[0]) + else: + df = pd.DataFrame(y) + df = df.assign(ws_id=w['weather_station'], cultivar=wy['cultivar'], soil=wy['soil'], start=wy['start'], end=wy['end']) + df_yield_list.append(df) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None + df = pd.concat(df_yield_list, ignore_index=True) if df_yield_list else pd.DataFrame() - + return df # print(get_forecast_crop_exc("https://webapi.aclimate.org/api/", ["5a7e422057d7f316c8bc574e"])) diff --git a/src/aclimate_api/main.py b/src/aclimate_api/main.py index 66ef7eb..a0e1d10 100644 --- a/src/aclimate_api/main.py +++ b/src/aclimate_api/main.py @@ -9,9 +9,9 @@ def main(): g = Geographic("https://webapi.aclimate.org/api/") # print(g.get_geographic("636c0813e57f2e6ac61394e6")) f = Forecast("https://webapi.aclimate.org/api/") - # print(f.get_forecast_climate(["5a7e422057d7f316c8bc574e"])) + print(f.get_forecast_crop_exc(["5a7e422057d7f316c8bc574e"])) a = Agronomy("https://webapi.aclimate.org/api/") - print(a.get_agronomy()) + # print(a.get_agronomy()) h = Historical("https://webapi.aclimate.org/api/") # print(h.get_historical_climatology(["5a7e422057d7f316c8bc574e"])) gs = Geoserver("https://geo.aclimate.org/geoserver/") From 4ec43eb470f6664259ecc01e3b7f260c2c7d1ba5 Mon Sep 17 00:00:00 2001 From: Minotriz02 Date: Tue, 28 May 2024 13:58:02 -0500 Subject: [PATCH 3/7] geographic error and document --- src/aclimate_api/geographic.py | 200 ++++++++++++++++++++++++--------- src/aclimate_api/main.py | 4 +- 2 files changed, 151 insertions(+), 53 deletions(-) diff --git a/src/aclimate_api/geographic.py b/src/aclimate_api/geographic.py index 60009d2..3650337 100644 --- a/src/aclimate_api/geographic.py +++ b/src/aclimate_api/geographic.py @@ -7,64 +7,72 @@ def __init__(self, url_root): self.url_root = url_root def get_geographic_country(self): - # Download data - url = f"{self.url_root}Geographic/Country/json" - response = requests.get(url) - data = json.loads(response.text) - - df = pd.DataFrame(data) + """ + Retrieves geographic country data from the API. + + Returns: + pandas.DataFrame: A DataFrame containing the geographic country data. + """ + try: + url = f"{self.url_root}Geographic/Country/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + + try: + df = pd.DataFrame(data) + except ValueError as e: + print("Error: Failed to convert data to DataFrame") + print(e) + return None + return df #print(get_geographic("https://webapi.aclimate.org/api/")) def get_geographic(self, country_id): - # Download data - url = f"{self.url_root}Geographic/{country_id}/json" - response = requests.get(url) - data = json.loads(response.text) - - df_list = [] - - for s in data: - for m in s['municipalities']: - for w in m['weather_stations']: - df_list.append({ - 'country_id': s['country']['id'], - 'country_iso2': s['country']['iso2'], - 'country_name': s['country']['name'], - 'state_id': s['id'], - 'state_name': s['name'], - 'municipality_id': m['id'], - 'municipality_name': m['name'], - 'ws_id': w['id'], - 'ws_ext_id': w['ext_id'], - 'ws_name': w['name'], - 'ws_origin': w['origin'], - 'ws_lat': w['latitude'], - 'ws_lon': w['longitude'] - }) + """ + Retrieves geographic data for a given country ID. - df = pd.DataFrame(df_list) + Parameters: + - country_id (str): The ID of the country for which to retrieve geographic data. - return df + Returns: + - df (pandas.DataFrame): A DataFrame containing the retrieved geographic data. + """ + try: + url = f"{self.url_root}Geographic/{country_id}/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None - #print(get_geographic("https://webapi.aclimate.org/api/", "636c0813e57f2e6ac61394e6")) + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None - def get_geographic_crop(self, country_id): - # Download data - url = f"{self.url_root}Geographic/Crop/{country_id}/json" - response = requests.get(url) - data = json.loads(response.text) - df_list = [] - - for cr in data: - for s in cr['states']: + try: + for s in data: for m in s['municipalities']: for w in m['weather_stations']: df_list.append({ - 'crop_id': cr['id'], - 'crop_name': cr['name'], + 'country_id': s['country']['id'], 'country_iso2': s['country']['iso2'], 'country_name': s['country']['name'], 'state_id': s['id'], @@ -78,19 +86,109 @@ def get_geographic_crop(self, country_id): 'ws_lat': w['latitude'], 'ws_lon': w['longitude'] }) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None + + df = pd.DataFrame(df_list) + + return df + + #print(get_geographic("https://webapi.aclimate.org/api/", "636c0813e57f2e6ac61394e6")) + + def get_geographic_crop(self, country_id): + """ + Retrieves geographic crop data for a given country. + + Args: + country_id (str): The ID of the country for which to retrieve crop data. + + Returns: + pandas.DataFrame: A DataFrame containing the geographic crop data. + """ + try: + url = f"{self.url_root}Geographic/Crop/{country_id}/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + + df_list = [] + try: + for cr in data: + for s in cr['states']: + for m in s['municipalities']: + for w in m['weather_stations']: + df_list.append({ + 'crop_id': cr['id'], + 'crop_name': cr['name'], + 'country_iso2': s['country']['iso2'], + 'country_name': s['country']['name'], + 'state_id': s['id'], + 'state_name': s['name'], + 'municipality_id': m['id'], + 'municipality_name': m['name'], + 'ws_id': w['id'], + 'ws_ext_id': w['ext_id'], + 'ws_name': w['name'], + 'ws_origin': w['origin'], + 'ws_lat': w['latitude'], + 'ws_lon': w['longitude'] + }) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None df = pd.DataFrame(df_list) + return df #print(get_geographic_crop("https://webapi.aclimate.org/api/", "61e59d829d5d2486e18d2ea8")) def get_geographic_ws(self, country_id): - # Download data - url = f"{self.url_root}Geographic/{country_id}/WeatherStations/json" - response = requests.get(url) - data = json.loads(response.text) - - df = pd.DataFrame(data) + """ + Retrieves weather stations data for a specific country. + + Parameters: + country_id (str): The ID of the country for which to retrieve weather stations data. + + Returns: + pandas.DataFrame: A DataFrame containing the weather stations data. + """ + try: + url = f"{self.url_root}Geographic/{country_id}/WeatherStations/json" + response = requests.get(url) + response.raise_for_status() # Raise an exception if the GET request failed + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + + try: + df = pd.DataFrame(data) + except ValueError as e: + print("Error: Failed to convert data to DataFrame") + print(e) + return None + return df # print(get_geographic_crop("https://webapi.aclimate.org/api/", "61e59d829d5d2486e18d2ea8")) \ No newline at end of file diff --git a/src/aclimate_api/main.py b/src/aclimate_api/main.py index a0e1d10..f6ccc5d 100644 --- a/src/aclimate_api/main.py +++ b/src/aclimate_api/main.py @@ -7,9 +7,9 @@ def main(): g = Geographic("https://webapi.aclimate.org/api/") - # print(g.get_geographic("636c0813e57f2e6ac61394e6")) + print(g.get_geographic_ws("61e59d829d5d2486e18d2ea8")) f = Forecast("https://webapi.aclimate.org/api/") - print(f.get_forecast_crop_exc(["5a7e422057d7f316c8bc574e"])) + # print(f.get_forecast_crop_exc(["5a7e422057d7f316c8bc574e"])) a = Agronomy("https://webapi.aclimate.org/api/") # print(a.get_agronomy()) h = Historical("https://webapi.aclimate.org/api/") From f9f91a60b6a69d5d8604b7df0c841c5467441625 Mon Sep 17 00:00:00 2001 From: Minotriz02 Date: Tue, 28 May 2024 14:00:32 -0500 Subject: [PATCH 4/7] forecast document adjusted --- src/aclimate_api/forecast.py | 142 +++++++++++++++++------------------ 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/aclimate_api/forecast.py b/src/aclimate_api/forecast.py index 3ea2ce7..83d75a5 100644 --- a/src/aclimate_api/forecast.py +++ b/src/aclimate_api/forecast.py @@ -7,20 +7,19 @@ class Forecast: def __init__(self, url_root): self.url_root = url_root + def get_forecast_climate(self, stations): + """ + Retrieves the forecast climate data for the given weather stations. - """ - Retrieves the forecast climate data for the given weather stations. - - Args: - stations (list): A list of weather station IDs. + Args: + stations (list): A list of weather station IDs. - Returns: - dict: A dictionary containing the forecast climate data, including probabilities, - performance, and scenarios. The keys of the dictionary are 'probabilities', - 'performance', and 'scenarios', and the values are pandas DataFrames. + Returns: + dict: A dictionary containing the forecast climate data, including probabilities, + performance, and scenarios. The keys of the dictionary are 'probabilities', + 'performance', and 'scenarios', and the values are pandas DataFrames. - """ - def get_forecast_climate(self, stations): + """ try: ws = ",".join(stations) url = f"{self.url_root}Forecast/Climate/{ws}/true/json" @@ -81,16 +80,17 @@ def get_forecast_climate(self, stations): return forecast_climate # print(get_forecast_climate("https://webapi.aclimate.org/api/", ["5a7e422057d7f316c8bc574e"])) - """ - Retrieves the forecast yield data for the specified weather stations. + + def get_forecast_crop(self, stations): + """ + Retrieves the forecast yield data for the specified weather stations. - Args: - stations (list): A list of weather station IDs. + Args: + stations (list): A list of weather station IDs. - Returns: - pandas.DataFrame: A DataFrame containing the forecast yield data for the specified weather stations. - """ - def get_forecast_crop(self, stations): + Returns: + pandas.DataFrame: A DataFrame containing the forecast yield data for the specified weather stations. + """ try: ws = ",".join(stations) url = f"{self.url_root}Forecast/Yield/{ws}/json" @@ -129,7 +129,8 @@ def get_forecast_crop(self, stations): # print(get_forecast_crop("https://webapi.aclimate.org/api/", ["5a7e422057d7f316c8bc574e"])) - """ + def get_forecast_information(self, year): + """ Retrieves forecast information for a given year. Args: @@ -138,7 +139,6 @@ def get_forecast_crop(self, stations): Returns: pandas.DataFrame: A DataFrame containing the forecast information, including columns for 'id', 'start', 'end', and 'confidence'. """ - def get_forecast_information(self, year): try: url = f"{self.url_root}Forecast/Log/{year}/json" response = requests.get(url) @@ -175,27 +175,27 @@ def get_forecast_information(self, year): # print(get_forecast_information("https://webapi.aclimate.org/api/", 2021)) - """ - Retrieves the subseasonal forecast data for the given weather stations. - - Args: - stations (list): A list of weather station IDs. - - Returns: - pandas.DataFrame: A DataFrame containing the subseasonal forecast data. - The DataFrame has the following columns: - - weather_station: The ID of the weather station. - - year: The year of the forecast. - - month: The month of the forecast. - - week: The week of the forecast. - - measure: The measure of the forecast. - - lower: The lower bound of the forecast. - - normal: The normal value of the forecast. - - upper: The upper bound of the forecast. - - If no subseasonal forecast data is available, an empty DataFrame is returned. - """ def get_forecast_subseasonal(self, stations): + """ + Retrieves the subseasonal forecast data for the given weather stations. + + Args: + stations (list): A list of weather station IDs. + + Returns: + pandas.DataFrame: A DataFrame containing the subseasonal forecast data. + The DataFrame has the following columns: + - weather_station: The ID of the weather station. + - year: The year of the forecast. + - month: The month of the forecast. + - week: The week of the forecast. + - measure: The measure of the forecast. + - lower: The lower bound of the forecast. + - normal: The normal value of the forecast. + - upper: The upper bound of the forecast. + + If no subseasonal forecast data is available, an empty DataFrame is returned. + """ try: ws = ",".join(stations) url = f"{self.url_root}Forecast/SubseasonalWS/{ws}/json" @@ -249,21 +249,21 @@ def get_forecast_subseasonal(self, stations): # print(get_forecast_subseasonal("https://webapi.aclimate.org/api/", ["5a7e422057d7f316c8bc574e"])) - """ - Retrieves the forecast climate data for previous periods. + def get_forecast_climate_previous(self, forecast, stations): + """ + Retrieves the forecast climate data for previous periods. - Args: - forecast (str): The forecast identifier. - stations (list): A list of weather station IDs. + Args: + forecast (str): The forecast identifier. + stations (list): A list of weather station IDs. - Returns: - dict: A dictionary containing the forecast climate data for previous periods. - The dictionary has the following keys: - - 'probabilities': A pandas DataFrame containing the probability data. - - 'performance': A pandas DataFrame containing the performance data. - - 'scenarios': A pandas DataFrame containing the scenario data. - """ - def get_forecast_climate_previous(self, forecast, stations): + Returns: + dict: A dictionary containing the forecast climate data for previous periods. + The dictionary has the following keys: + - 'probabilities': A pandas DataFrame containing the probability data. + - 'performance': A pandas DataFrame containing the performance data. + - 'scenarios': A pandas DataFrame containing the scenario data. + """ try: ws = ",".join(stations) url = f"{self.url_root}Forecast/ClimatePrevious/{forecast}/{ws}/true/json" @@ -328,17 +328,17 @@ def get_forecast_climate_previous(self, forecast, stations): # print(get_forecast_climate_previous("https://webapi.aclimate.org/api/", "602d1da7a1c81c22b08683b5", ["5a7e422057d7f316c8bc574e"])) - """ - Retrieves the previous yield forecast for a given forecast and list of weather stations. + def get_forecast_crop_previous(self, forecast, stations): + """ + Retrieves the previous yield forecast for a given forecast and list of weather stations. - Args: - forecast (str): The forecast identifier. - stations (list): A list of weather station identifiers. + Args: + forecast (str): The forecast identifier. + stations (list): A list of weather station identifiers. - Returns: - pandas.DataFrame: A DataFrame containing the forecasted yield data for the specified forecast and weather stations. - """ - def get_forecast_crop_previous(self, forecast, stations): + Returns: + pandas.DataFrame: A DataFrame containing the forecasted yield data for the specified forecast and weather stations. + """ try: ws = ",".join(stations) url = f"{self.url_root}Forecast/YieldPrevious/{forecast}/{ws}/json" @@ -381,16 +381,16 @@ def get_forecast_crop_previous(self, forecast, stations): # print(get_forecast_crop_previous("https://webapi.aclimate.org/api/", "602d1da7a1c81c22b08683b5", ["5a7e422057d7f316c8bc574e"])) - """ - Retrieves the forecast crop exceedance data for the given weather stations. + def get_forecast_crop_exc(self, stations): + """ + Retrieves the forecast crop exceedance data for the given weather stations. - Args: - stations (list): A list of weather station IDs. + Args: + stations (list): A list of weather station IDs. - Returns: - pandas.DataFrame: A DataFrame containing the forecast crop exceedance data. - """ - def get_forecast_crop_exc(self, stations): + Returns: + pandas.DataFrame: A DataFrame containing the forecast crop exceedance data. + """ try: ws = ",".join(stations) url = f"{self.url_root}Forecast/YieldExceedance/{ws}/json" From 5b1a212a9d2be059b86c53de8e70da74c2d95cc0 Mon Sep 17 00:00:00 2001 From: Minotriz02 Date: Tue, 28 May 2024 14:01:11 -0500 Subject: [PATCH 5/7] agronomy document adjusted --- src/aclimate_api/agronomy.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/aclimate_api/agronomy.py b/src/aclimate_api/agronomy.py index 8f78a75..3c81fd3 100644 --- a/src/aclimate_api/agronomy.py +++ b/src/aclimate_api/agronomy.py @@ -7,18 +7,18 @@ class Agronomy: def __init__(self, url_root): self.url_root = url_root - """ - Retrieves agronomy data from the API. - - Returns: - dict: A dictionary containing two DataFrames: 'cultivars' and 'soils'. - The 'cultivars' DataFrame contains information about different cultivars, - including crop ID, crop name, cultivar ID, cultivar name, rainfed status, - and national status. - The 'soils' DataFrame contains information about different soils, - including crop ID, crop name, soil ID, and soil name. - """ def get_agronomy(self): + """ + Retrieves agronomy data from the API. + + Returns: + dict: A dictionary containing two DataFrames: 'cultivars' and 'soils'. + The 'cultivars' DataFrame contains information about different cultivars, + including crop ID, crop name, cultivar ID, cultivar name, rainfed status, + and national status. + The 'soils' DataFrame contains information about different soils, + including crop ID, crop name, soil ID, and soil name. + """ try: url = f"{self.url_root}Agronomic/true/json" response = requests.get(url) From a2763fab5196056413cc480a2714499a1dacff36 Mon Sep 17 00:00:00 2001 From: Minotriz02 Date: Tue, 28 May 2024 14:12:13 -0500 Subject: [PATCH 6/7] geoserver error and document --- src/aclimate_api/geoserver.py | 207 ++++++++++++++++++++++++++++------ src/aclimate_api/main.py | 4 +- 2 files changed, 176 insertions(+), 35 deletions(-) diff --git a/src/aclimate_api/geoserver.py b/src/aclimate_api/geoserver.py index 5c0c429..8acd792 100644 --- a/src/aclimate_api/geoserver.py +++ b/src/aclimate_api/geoserver.py @@ -13,51 +13,136 @@ def __init__(self, url_root): self.url_root = url_root def get_geo_workspaces(self): + """ + Retrieves the list of GeoServer workspaces. + + Returns: + pandas.DataFrame: A DataFrame containing the workspace names and their corresponding hrefs. + """ user = os.getenv("GEOSERVER_USER") password = os.getenv("GEOSERVER_PASSWORD") - - url = f"{self.url_root}/rest/workspaces.json" - response = requests.get(url, auth=(user, password)) + if not user or not password: + print("Error: Missing GeoServer credentials") + return None + + try: + url = f"{self.url_root}/rest/workspaces.json" + response = requests.get(url, auth=(user, password)) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return pd.DataFrame() - data = json.loads(response.text) - workspaces_list = data['workspaces']['workspace'] - workspace_df = pd.DataFrame([{'workspace_name': ws['name'], 'workspace_href': ws['href']} for ws in workspaces_list]) + if response.status_code == 401: + print("Error: Unauthorized. Check your GeoServer credentials.") + return None + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return None + + try: + workspaces_list = data['workspaces']['workspace'] + workspace_df = pd.DataFrame([{'workspace_name': ws['name'], 'workspace_href': ws['href']} for ws in workspaces_list]) + except KeyError as e: + print("Error: Missing key in data") + print(e) + return None + return workspace_df # print(get_geo_workspaces("https://geo.aclimate.org/geoserver/")) - def get_geo_mosaic_name(self, workspace): + def get_geo_mosaic_name(self, workspace): + """ + Retrieves the names and hrefs of the mosaics in the specified GeoServer workspace. + + Args: + workspace (str): The name of the GeoServer workspace. + + Returns: + pandas.DataFrame: A DataFrame containing the mosaic names and hrefs, or an empty DataFrame if there was an error. + """ user = os.getenv("GEOSERVER_USER") password = os.getenv("GEOSERVER_PASSWORD") - - url = f"{self.url_root}/rest/workspaces/{workspace}/coveragestores.json" - response = requests.get(url, auth=(user, password)) - - if response.status_code == 200: + if not user or not password: + print("Error: Missing GeoServer credentials") + return pd.DataFrame() + + try: + url = f"{self.url_root}/rest/workspaces/{workspace}/coveragestores.json" + response = requests.get(url, auth=(user, password)) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return pd.DataFrame() + + if response.status_code == 401: + print("Error: Unauthorized. Check your GeoServer credentials.") + return pd.DataFrame() + + try: data = json.loads(response.text) - if 'coverageStores' in data and 'coverageStore' in data['coverageStores']: + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return pd.DataFrame() + + if 'coverageStores' in data and 'coverageStore' in data['coverageStores']: + try: mosaics_list = data['coverageStores']['coverageStore'] mosaics_df = pd.DataFrame([{'mosaic_name': ms['name'], 'mosaic_href': ms['href']} for ms in mosaics_list]) - return mosaics_df + except KeyError as e: + print("Error: Missing key in data") + print(e) + return pd.DataFrame() + return mosaics_df + return pd.DataFrame() # print(get_geo_mosaic_name("https://geo.aclimate.org/geoserver/", "waterpoints_et")) def get_geo_mosaics(self, workspace, mosaic_name, year, month=1, day=1): - url = f"{self.url_root}{workspace}/ows?service=WCS&request=GetCoverage&version=2.0.1&coverageId={mosaic_name}&format=image/geotiff&subset=Time(\"{year}-{month:02d}-{day:02d}T00:00:00.000Z\")" - response = requests.get(url) + """ + Retrieves a geospatial mosaic from a GeoServer instance. + + Args: + workspace (str): The name of the workspace where the mosaic is located. + mosaic_name (str): The name of the mosaic to retrieve. + year (int): The year of the mosaic to retrieve. + month (int, optional): The month of the mosaic to retrieve. Defaults to 1. + day (int, optional): The day of the mosaic to retrieve. Defaults to 1. + + Returns: + numpy.ndarray or None: The raster data of the retrieved mosaic as a NumPy array, or None if an error occurred. + """ + try: + url = f"{self.url_root}{workspace}/ows?service=WCS&request=GetCoverage&version=2.0.1&coverageId={mosaic_name}&format=image/geotiff&subset=Time(\"{year}-{month:02d}-{day:02d}T00:00:00.000Z\")" + response = requests.get(url) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None if response.status_code == 200: - # Create a temporary file - temp_tiff = tempfile.mktemp(suffix=".tif") - with open(temp_tiff, 'wb') as f: - f.write(response.content) - - # Load the raster data - raster_data = rasterio.open(temp_tiff) - return raster_data.read() + try: + # Create a temporary file + temp_tiff = tempfile.mktemp(suffix=".tif") + with open(temp_tiff, 'wb') as f: + f.write(response.content) + + # Load the raster data + raster_data = rasterio.open(temp_tiff) + return raster_data.read() + except Exception as e: + print("Error: Failed to write the response content to a temporary file or load the raster data") + print(e) + return None else: match_result = re.findall("(.*?)", response.text) @@ -71,29 +156,85 @@ def get_geo_mosaics(self, workspace, mosaic_name, year, month=1, day=1): # print(get_geo_mosaics("https://geo.aclimate.org/geoserver/", "waterpoints_et", "biomass", 2024, 4, 22)) def get_geo_polygon_name(self, workspace): + """ + Retrieves the names and hrefs of polygons from the specified workspace in GeoServer. + + Args: + workspace (str): The name of the workspace in GeoServer. + + Returns: + pandas.DataFrame: A DataFrame containing the names and hrefs of the polygons, with columns 'polygon_name' and 'polygon_href'. + If no polygons are found or an error occurs, an empty DataFrame is returned. + """ user = os.getenv("GEOSERVER_USER") password = os.getenv("GEOSERVER_PASSWORD") - url = f"{self.url_root}rest/workspaces/{workspace}/datastores.json" - response = requests.get(url, auth=(user, password)) + if not user or not password: + print("Error: Missing GeoServer credentials") + return pd.DataFrame() - if response.status_code == 200: + try: + url = f"{self.url_root}rest/workspaces/{workspace}/datastores.json" + response = requests.get(url, auth=(user, password)) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return pd.DataFrame() + + if response.status_code == 401: + print("Error: Unauthorized. Check your GeoServer credentials.") + return pd.DataFrame() + + try: data = json.loads(response.text) - if 'dataStores' in data and 'dataStore' in data['dataStores']: + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return pd.DataFrame() + + if 'dataStores' in data and 'dataStore' in data['dataStores']: + try: polygons_list = data['dataStores']['dataStore'] polygons_df = pd.DataFrame([{'polygon_name': pg['name'], 'polygon_href': pg['href']} for pg in polygons_list]) - return polygons_df + except KeyError as e: + print("Error: Missing key in data") + print(e) + return pd.DataFrame() + return polygons_df + return pd.DataFrame() # print(get_geo_polygon_name("https://geo.aclimate.org/geoserver/", "fc_cenaos_hn")) def get_geo_polygons(self, workspace, polygon_name): - url = f"{self.url_root}/{workspace}/ows?service=WFS&request=GetFeature&version=2.0.1&typeNames={workspace}:{polygon_name}&outputFormat=application/json" - response = requests.get(url) + """ + Retrieves geo polygons from a GeoServer. + + Args: + workspace (str): The name of the workspace in GeoServer. + polygon_name (str): The name of the polygon to retrieve. + + Returns: + GeoDataFrame or None: The retrieved geo polygons as a GeoDataFrame if successful, + None otherwise. + """ + try: + url = f"{self.url_root}/{workspace}/ows?service=WFS&request=GetFeature&version=2.0.1&typeNames={workspace}:{polygon_name}&outputFormat=application/json" + response = requests.get(url) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return None if response.status_code == 200: - sf_obj_geoserver = gpd.read_file(response.text) - return sf_obj_geoserver + try: + sf_obj_geoserver = gpd.read_file(response.text) + return sf_obj_geoserver + except Exception as e: + print("Error: Failed to read the response text as a file") + print(e) + return None + else: exception_text = re.search(r'(.*?)', response.text) if exception_text: diff --git a/src/aclimate_api/main.py b/src/aclimate_api/main.py index f6ccc5d..9520d4d 100644 --- a/src/aclimate_api/main.py +++ b/src/aclimate_api/main.py @@ -7,7 +7,7 @@ def main(): g = Geographic("https://webapi.aclimate.org/api/") - print(g.get_geographic_ws("61e59d829d5d2486e18d2ea8")) + # print(g.get_geographic_ws("61e59d829d5d2486e18d2ea8")) f = Forecast("https://webapi.aclimate.org/api/") # print(f.get_forecast_crop_exc(["5a7e422057d7f316c8bc574e"])) a = Agronomy("https://webapi.aclimate.org/api/") @@ -15,7 +15,7 @@ def main(): h = Historical("https://webapi.aclimate.org/api/") # print(h.get_historical_climatology(["5a7e422057d7f316c8bc574e"])) gs = Geoserver("https://geo.aclimate.org/geoserver/") - # print(gs.get_geo_workspaces()) + # print(gs.get_geo_polygon_name("fc_cenaos_hn")) if __name__ == "__main__": main() \ No newline at end of file From c2c8738dd904c0cc001d762686223ba15a431c6c Mon Sep 17 00:00:00 2001 From: Minotriz02 Date: Tue, 28 May 2024 14:19:38 -0500 Subject: [PATCH 7/7] historical error and document --- src/aclimate_api/historical.py | 207 ++++++++++++++++++++++++--------- src/aclimate_api/main.py | 1 - 2 files changed, 155 insertions(+), 53 deletions(-) diff --git a/src/aclimate_api/historical.py b/src/aclimate_api/historical.py index 2e7bc32..3d47fd6 100644 --- a/src/aclimate_api/historical.py +++ b/src/aclimate_api/historical.py @@ -8,22 +8,47 @@ def __init__(self, url_root): self.url_root = url_root def get_historical_climatology(self, stations): + """ + Retrieves historical climatology data for the specified weather stations. + + Args: + stations (list): A list of weather station IDs. + + Returns: + pandas.DataFrame: A DataFrame containing the historical climatology data. + """ ws = ",".join(stations) url = f"{self.url_root}/Historical/Climatology/{ws}/json" - response = requests.get(url) - data = json.loads(response.text) + try: + response = requests.get(url) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return pd.DataFrame() + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return pd.DataFrame() data_list = [] for w in data: - for md in w['monthly_data']: - for wd in md['data']: - row_dict = { - 'ws_id': w['weather_station'], - 'month': md['month'], - 'measure': wd['measure'], - 'value': wd['value'] - } - data_list.append(row_dict) + try: + for md in w['monthly_data']: + for wd in md['data']: + row_dict = { + 'ws_id': w['weather_station'], + 'month': md['month'], + 'measure': wd['measure'], + 'value': wd['value'] + } + data_list.append(row_dict) + except KeyError as e: + print("Error: Missing key in data") + print(e) + continue df = pd.DataFrame(data_list) @@ -32,23 +57,48 @@ def get_historical_climatology(self, stations): # print(get_historical_climatology("https://webapi.aclimate.org/api/", ['5a7e422057d7f316c8bc574e'])) def get_historical_historicalclimatic(self, stations): + """ + Retrieves historical climatic data for the given weather stations. + + Args: + stations (list): A list of weather station IDs. + + Returns: + pandas.DataFrame: A DataFrame containing the historical climatic data. + """ ws = ",".join(stations) url = f"{self.url_root}/Historical/HistoricalClimatic/{ws}/json" - response = requests.get(url) - data = json.loads(response.text) + try: + response = requests.get(url) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return pd.DataFrame() + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return pd.DataFrame() data_list = [] for w in data: - for md in w['monthly_data']: - for wd in md['data']: - row_dict = { - 'ws_id': w['weather_station'], - 'year': w['year'], - 'month': md['month'], - 'measure': wd['measure'], - 'value': wd['value'] - } - data_list.append(row_dict) + try: + for md in w['monthly_data']: + for wd in md['data']: + row_dict = { + 'ws_id': w['weather_station'], + 'year': w['year'], + 'month': md['month'], + 'measure': wd['measure'], + 'value': wd['value'] + } + data_list.append(row_dict) + except KeyError as e: + print("Error: Missing key in data") + print(e) + continue df = pd.DataFrame(data_list) @@ -57,48 +107,101 @@ def get_historical_historicalclimatic(self, stations): # print(get_historical_historicalclimatic("https://webapi.aclimate.org/api/", ['5a7e422057d7f316c8bc574e'])) def get_historical_historicalyieldyears(self, stations): + """ + Retrieves the historical yield years for the given stations. + + Args: + stations (list): A list of station names. + + Returns: + pandas.DataFrame: A DataFrame containing the historical yield years. + """ ws = ",".join(stations) url = f"{self.url_root}/Historical/HistoricalYieldYears/{ws}/json" - response = requests.get(url) - data = json.loads(response.text) - df = pd.DataFrame({'year': data}) + try: + response = requests.get(url) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return pd.DataFrame() + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return pd.DataFrame() + + try: + df = pd.DataFrame({'year': data}) + except pd.errors.EmptyDataError as e: + print("Error: No data to create DataFrame") + print(e) + return pd.DataFrame() + return df # print(get_historical_historicalyieldyears("https://webapi.aclimate.org/api/", ['5a7e422057d7f316c8bc574e'])) def get_historical_historicalyield(self, stations, years): + """ + Retrieves historical yield data for the specified weather stations and years. + + Args: + stations (list): A list of weather station IDs. + years (list): A list of years for which to retrieve data. + + Returns: + pandas.DataFrame: A DataFrame containing the retrieved historical yield data. + """ ws = ",".join(stations) yearsSplit = ','.join(years) url = f"{self.url_root}/Historical/HistoricalYield/{ws}/{yearsSplit}/json" - response = requests.get(url) - data = json.loads(response.text) + try: + response = requests.get(url) + except requests.exceptions.RequestException as e: + print(f"Error: Failed to retrieve data from {url}") + print(e) + return pd.DataFrame() + + try: + data = json.loads(response.text) + except json.JSONDecodeError as e: + print("Error: Failed to decode the response as JSON") + print(e) + return pd.DataFrame() data_list = [] for w in data: - for wy in w['yield']: - for y in wy['data']: - row_dict = { - 'ws_id': w['weather_station'], - 'cultivar': wy['cultivar'], - 'soil': wy['soil'], - 'start': wy['start'], - 'end': wy['end'], - 'measure': y['measure'], - 'median': y['median'], - 'avg': y['avg'], - 'min': y['min'], - 'max': y['max'], - 'quar_1': y['quar_1'], - 'quar_2': y['quar_2'], - 'quar_3': y['quar_3'], - 'conf_lower': y['conf_lower'], - 'conf_upper': y['conf_upper'], - 'sd': y['sd'], - 'perc_5': y['perc_5'], - 'perc_95': y['perc_95'], - 'coef_var': y['coef_var'] - } - data_list.append(row_dict) + try: + for wy in w['yield']: + for y in wy['data']: + row_dict = { + 'ws_id': w['weather_station'], + 'cultivar': wy['cultivar'], + 'soil': wy['soil'], + 'start': wy['start'], + 'end': wy['end'], + 'measure': y['measure'], + 'median': y['median'], + 'avg': y['avg'], + 'min': y['min'], + 'max': y['max'], + 'quar_1': y['quar_1'], + 'quar_2': y['quar_2'], + 'quar_3': y['quar_3'], + 'conf_lower': y['conf_lower'], + 'conf_upper': y['conf_upper'], + 'sd': y['sd'], + 'perc_5': y['perc_5'], + 'perc_95': y['perc_95'], + 'coef_var': y['coef_var'] + } + data_list.append(row_dict) + except KeyError as e: + print("Error: Missing key in data") + print(e) + continue df = pd.DataFrame(data_list) diff --git a/src/aclimate_api/main.py b/src/aclimate_api/main.py index 9520d4d..f5049fd 100644 --- a/src/aclimate_api/main.py +++ b/src/aclimate_api/main.py @@ -1,4 +1,3 @@ -import os from geographic import Geographic from forecast import Forecast from agronomy import Agronomy