From ad4cc3ebadc74c98ffd19dd48987d334cb6f312c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lu=C3=A3=20Bida=20Vacaro?= <82233055+luabida@users.noreply.github.com> Date: Fri, 28 Oct 2022 10:44:12 -0300 Subject: [PATCH] BREAKING CHANGE(refactor): Refactor of Data Collection modules to match ETL worflow (#193) * chore(refactor): Refactor of Data Collection modules to match ETL workflow * Refactor OWID data collection * Move config to a private module * Colombia collection * Refactor foph import module --- docs/tutorials/data/foph.ipynb | 11 +- .../article/download_data.ipynb | 11 +- .../forecast_switzerland/forecast_swiss.py | 2 +- .../forecast_switzerland/verify_train.ipynb | 4 +- .../analysis/forecast_models/lstm_models.py | 2 +- .../{data_collection/config.py => _config.py} | 0 .../{data_collection => colombia}/__init__.py | 0 .../compare_data.py => colombia/extract.py} | 12 +- .../data_chunk.py => colombia/loading.py} | 69 ++++++++-- .../colombia/load_chunks_into_db.py | 76 ----------- .../data/data_collection/foph/compare_data.py | 79 ----------- .../data/data_collection/foph/load_into_db.py | 62 --------- .../data/data_collection/owid/__init__.py | 0 .../data_collection/owid/download_data.py | 56 -------- .../colombia => foph}/__init__.py | 0 .../foph/download_data.py => foph/extract.py} | 34 +++-- epigraphhub/data/foph/loading.py | 123 ++++++++++++++++++ .../update_index.py => foph/transform.py} | 0 epigraphhub/data/{foph.py => foph/viz.py} | 0 .../foph => owid}/__init__.py | 0 .../owid/compare_data.py => owid/extract.py} | 69 +++++++--- .../owid/load_into_db.py => owid/loading.py} | 39 +++--- .../update_index.py => owid/transform.py} | 4 +- 23 files changed, 304 insertions(+), 349 deletions(-) rename epigraphhub/data/{data_collection/config.py => _config.py} (100%) rename epigraphhub/data/{data_collection => colombia}/__init__.py (100%) rename epigraphhub/data/{data_collection/colombia/compare_data.py => colombia/extract.py} (88%) rename epigraphhub/data/{data_collection/colombia/data_chunk.py => colombia/loading.py} (53%) delete mode 100644 epigraphhub/data/data_collection/colombia/load_chunks_into_db.py delete mode 100644 epigraphhub/data/data_collection/foph/compare_data.py delete mode 100644 epigraphhub/data/data_collection/foph/load_into_db.py delete mode 100644 epigraphhub/data/data_collection/owid/__init__.py delete mode 100644 epigraphhub/data/data_collection/owid/download_data.py rename epigraphhub/data/{data_collection/colombia => foph}/__init__.py (100%) rename epigraphhub/data/{data_collection/foph/download_data.py => foph/extract.py} (75%) create mode 100644 epigraphhub/data/foph/loading.py rename epigraphhub/data/{data_collection/foph/update_index.py => foph/transform.py} (100%) rename epigraphhub/data/{foph.py => foph/viz.py} (100%) rename epigraphhub/data/{data_collection/foph => owid}/__init__.py (100%) rename epigraphhub/data/{data_collection/owid/compare_data.py => owid/extract.py} (55%) rename epigraphhub/data/{data_collection/owid/load_into_db.py => owid/loading.py} (92%) rename epigraphhub/data/{data_collection/owid/update_index.py => owid/transform.py} (95%) diff --git a/docs/tutorials/data/foph.ipynb b/docs/tutorials/data/foph.ipynb index 2dfade12..54b8c3e1 100644 --- a/docs/tutorials/data/foph.ipynb +++ b/docs/tutorials/data/foph.ipynb @@ -250,7 +250,7 @@ } ], "source": [ - "from epigraphhub.data.foph import get_cluster_data\n", + "from epigraphhub.data.foph.viz import get_cluster_data\n", "\n", "dict_cols = {\n", " \"foph_cases_d\": [\"datum\", \"georegion\", \"entries\"],\n", @@ -315,7 +315,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.10.6 64-bit", "language": "python", "name": "python3" }, @@ -329,7 +329,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.10.6" + }, + "vscode": { + "interpreter": { + "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1" + } } }, "nbformat": 4, diff --git a/docs/tutorials/forecast_switzerland/article/download_data.ipynb b/docs/tutorials/forecast_switzerland/article/download_data.ipynb index 6bc4409d..d580a490 100644 --- a/docs/tutorials/forecast_switzerland/article/download_data.ipynb +++ b/docs/tutorials/forecast_switzerland/article/download_data.ipynb @@ -17,7 +17,7 @@ "source": [ "import os \n", "os.chdir('../../')\n", - "from epigraphhub.data.foph import get_cluster_data, get_georegion_data" + "from epigraphhub.data.foph.viz import get_cluster_data, get_georegion_data" ] }, { @@ -86,7 +86,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.10.6 64-bit", "language": "python", "name": "python3" }, @@ -100,7 +100,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.10.6" + }, + "vscode": { + "interpreter": { + "hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1" + } } }, "nbformat": 4, diff --git a/docs/tutorials/forecast_switzerland/forecast_swiss.py b/docs/tutorials/forecast_switzerland/forecast_swiss.py index 4ce6ccf2..9a25b916 100644 --- a/docs/tutorials/forecast_switzerland/forecast_swiss.py +++ b/docs/tutorials/forecast_switzerland/forecast_swiss.py @@ -13,7 +13,7 @@ from epigraphhub.analysis.clustering import compute_clusters from epigraphhub.analysis.forecast_models.ngboost_models import NGBModel -from epigraphhub.data.foph import get_cluster_data, get_data_by_location +from epigraphhub.data.foph.viz import get_cluster_data, get_data_by_location params_model = { "Base": default_tree_learner, diff --git a/docs/tutorials/forecast_switzerland/verify_train.ipynb b/docs/tutorials/forecast_switzerland/verify_train.ipynb index 3787b6b7..e9b3e548 100644 --- a/docs/tutorials/forecast_switzerland/verify_train.ipynb +++ b/docs/tutorials/forecast_switzerland/verify_train.ipynb @@ -21,7 +21,7 @@ "from joblib import dump, load\n", "import matplotlib.pyplot as plt\n", "from epigraphhub.analysis.preprocessing import build_lagged_features\n", - "from epigraphhub.data.foph import get_cluster_data\n", + "from epigraphhub.data.foph.viz import get_cluster_data\n", "from epigraphhub.analysis.forecast_models.ngboost_models import get_targets \n", "from forecast_swiss import get_cluster_by_canton" ] @@ -155,7 +155,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] diff --git a/epigraphhub/analysis/forecast_models/lstm_models.py b/epigraphhub/analysis/forecast_models/lstm_models.py index 3d976264..67918bd4 100644 --- a/epigraphhub/analysis/forecast_models/lstm_models.py +++ b/epigraphhub/analysis/forecast_models/lstm_models.py @@ -32,7 +32,7 @@ from epigraphhub.analysis.clustering import compute_clusters from epigraphhub.analysis.preprocessing import lstm_split_data as split_data from epigraphhub.analysis.preprocessing import normalize_data -from epigraphhub.data.foph import get_cluster_data +from epigraphhub.data.foph.viz import get_cluster_data def build_model(hidden, features, predict_n, look_back=10, batch_size=1): diff --git a/epigraphhub/data/data_collection/config.py b/epigraphhub/data/_config.py similarity index 100% rename from epigraphhub/data/data_collection/config.py rename to epigraphhub/data/_config.py diff --git a/epigraphhub/data/data_collection/__init__.py b/epigraphhub/data/colombia/__init__.py similarity index 100% rename from epigraphhub/data/data_collection/__init__.py rename to epigraphhub/data/colombia/__init__.py diff --git a/epigraphhub/data/data_collection/colombia/compare_data.py b/epigraphhub/data/colombia/extract.py similarity index 88% rename from epigraphhub/data/data_collection/colombia/compare_data.py rename to epigraphhub/data/colombia/extract.py index 23b814f0..fcacaac1 100644 --- a/epigraphhub/data/data_collection/colombia/compare_data.py +++ b/epigraphhub/data/colombia/extract.py @@ -18,14 +18,20 @@ from loguru import logger from epigraphhub.connection import get_engine -from epigraphhub.data.data_collection.config import COLOMBIA_CLIENT, COLOMBIA_LOG_PATH +from epigraphhub.data._config import COLOMBIA_CLIENT, COLOMBIA_LOG_PATH from epigraphhub.settings import env logger.add(COLOMBIA_LOG_PATH, retention="7 days") client = COLOMBIA_CLIENT -def table_last_update() -> datetime: +def compare() -> bool: + db_last_update = _table_last_update() + data_last_update = _web_last_update() + return db_last_update == data_last_update + + +def _table_last_update() -> datetime: """ This method will connect to the SQL Database and query the maximum date found in Colombia table. @@ -51,7 +57,7 @@ def table_last_update() -> datetime: raise (e) -def web_last_update() -> datetime: +def _web_last_update() -> datetime: """ This method will request the maximum date found in Colombia data through Socrata API and returns it as a datetime object for further evaluation. diff --git a/epigraphhub/data/data_collection/colombia/data_chunk.py b/epigraphhub/data/colombia/loading.py similarity index 53% rename from epigraphhub/data/data_collection/colombia/data_chunk.py rename to epigraphhub/data/colombia/loading.py index fb4ec344..0e378e76 100644 --- a/epigraphhub/data/data_collection/colombia/data_chunk.py +++ b/epigraphhub/data/colombia/loading.py @@ -3,28 +3,79 @@ @author: eduardoaraujo Last change on 2022/09/22 -This module is responsible for slicing data found in Colombia Governmental -COVID database through Socrata API and parse rows to the same pattern before -inserting into the SQL Database. Receives the data and uses a date range to -create chunk slices and yield them with the updated values. +This module is responsible retrieve generated chunks of data containing COVID +information collect via Socrata API from Colombia Governmental's data +collection. Connect to SQL Database and load chunks in order to update +positive_cases_covid_d table. Methods ------- -chunked_fetch(): - Returns a DataFrame with the chunk of Colombia data with parsed values - in order to load them into SQL DB. +gen_chunks_into_db(): + Generate chunks of data to insert into SQL Database using pangres. """ from datetime import datetime, timedelta import pandas as pd +from loguru import logger +from pangres import upsert -from epigraphhub.data.data_collection.config import COLOMBIA_CLIENT +from epigraphhub.connection import get_engine +from epigraphhub.data._config import COLOMBIA_CLIENT, COLOMBIA_LOG_PATH +from epigraphhub.settings import env +logger.add(COLOMBIA_LOG_PATH, retention="7 days") client = COLOMBIA_CLIENT -def chunked_fetch(maxrecords, start=0, chunk_size=10000): +def upload(): + """ + This method will receive chunks generated by chunked_fetch and load them + into the SQL Database. Pangres receives the records found in the Colombia data + through Socrata API, uses the generator to load chunks with size of 10000 into + SQL DB using upsert method. + @note Colombia sometimes has a post update in the data, so rows update + in this case is required to retrieve the rows updated. + """ + slice_date = datetime.date(datetime.today()) - timedelta(200) + slice_date = slice_date.strftime("%Y-%m-%d") + + # count the number of records that will be fetched + records = client.get_all( + "gt2j-8ykr", + select="COUNT(*)", + where=f'fecha_reporte_web > "{slice_date}"', + ) + + for i in records: + record_count = i + break + + del records + + maxrecords = int(record_count["COUNT"]) + + engine = get_engine(env.db.default_credential) + + for df_new in _chunked_fetch(maxrecords): + + # save the data + with engine.connect() as conn: + upsert( + con=conn, + df=df_new, + table_name="positive_cases_covid_d", + schema="colombia", + if_row_exists="update", + chunksize=1000, + add_new_columns=True, + create_table=False, + ) + + logger.info("Table positive_cases_covid_d updated.") + + +def _chunked_fetch(maxrecords, start=0, chunk_size=10000): """ Connects to Colombia database through Socrata API and generates slices of data in chunks in order to insert them into diff --git a/epigraphhub/data/data_collection/colombia/load_chunks_into_db.py b/epigraphhub/data/data_collection/colombia/load_chunks_into_db.py deleted file mode 100644 index 11e023f9..00000000 --- a/epigraphhub/data/data_collection/colombia/load_chunks_into_db.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -Created on Mon Jan 31 08:53:59 2022 -@author: eduardoaraujo - -Last change on 2022/09/22 -This module is responsible retrieve generated chunks of data containing COVID -information collect via Socrata API from Colombia Governmental's data -collection. Connect to SQL Database and load chunks in order to update -positive_cases_covid_d table. - -Methods -------- - -gen_chunks_into_db(): - Generate chunks of data to insert into SQL Database using pangres. -""" -from datetime import datetime, timedelta - -from loguru import logger -from pangres import upsert - -from epigraphhub.connection import get_engine -from epigraphhub.data.data_collection.colombia.data_chunk import chunked_fetch -from epigraphhub.data.data_collection.config import COLOMBIA_CLIENT, COLOMBIA_LOG_PATH -from epigraphhub.settings import env - -logger.add(COLOMBIA_LOG_PATH, retention="7 days") -client = COLOMBIA_CLIENT - - -def gen_chunks_into_db(): - """ - This method will receive chunks generated by chunked_fetch and load them - into the SQL Database. Pangres receives the records found in the Colombia data - through Socrata API, uses the generator to load chunks with size of 10000 into - SQL DB using upsert method. - @note Colombia sometimes has a post update in the data, so rows update - in this case is required to retrieve the rows updated. - @see epigraphhub.data.data_collection.colombia.data_chunk - """ - slice_date = datetime.date(datetime.today()) - timedelta(200) - slice_date = slice_date.strftime("%Y-%m-%d") - - # count the number of records that will be fetched - records = client.get_all( - "gt2j-8ykr", - select="COUNT(*)", - where=f'fecha_reporte_web > "{slice_date}"', - ) - - for i in records: - record_count = i - break - - del records - - maxrecords = int(record_count["COUNT"]) - - engine = get_engine(env.db.default_credential) - - for df_new in chunked_fetch(maxrecords): - - # save the data - with engine.connect() as conn: - upsert( - con=conn, - df=df_new, - table_name="positive_cases_covid_d", - schema="colombia", - if_row_exists="update", - chunksize=1000, - add_new_columns=True, - create_table=False, - ) - - logger.info("Table positive_cases_covid_d updated.") diff --git a/epigraphhub/data/data_collection/foph/compare_data.py b/epigraphhub/data/data_collection/foph/compare_data.py deleted file mode 100644 index a3e16ff1..00000000 --- a/epigraphhub/data/data_collection/foph/compare_data.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -Last change on 2022/09/22 -Comparing Federal Office of Public Health (FOPH) COVID data consists in -a step before pushing it to the database. Is responsible for retrieving -the last date in both CSV and SQL table. - -Methods -------- - -csv_last_update(filename): - Returns the max date in a CSV file. - -table_last_update(table): - Connects to the SQL database and returns its max date. -""" -from datetime import datetime - -import pandas as pd -from loguru import logger - -from epigraphhub.connection import get_engine -from epigraphhub.data.data_collection.config import FOPH_CSV_PATH, FOPH_LOG_PATH -from epigraphhub.settings import env - -logger.add(FOPH_LOG_PATH, retention="7 days") - - -def csv_last_update(filename) -> datetime: - """ - Method responsible for retrieving the maximum date in a CSV file. - - Args: - filename (str) : The CSV filename. - - Returns: - last_update (datetime) : Datetime with the max date in the CSV. - - Raises: - Exception (Exception) : Empty dataframe from CSV. - """ - df = pd.read_csv(f"{FOPH_CSV_PATH}/{filename}") - if "date" not in df: - last_update = df.datum.max() - else: - last_update = df.date.max() - if df.empty: - raise Exception("Empty file.") - return datetime.strptime(str(last_update), "%Y-%m-%d") - - -def table_last_update(table) -> datetime: - """ - Method responsible for connecting and retrieving the maximum date - of a table in the SQL Database. - @see epigraphhub.connection : Where the connection is configured. - - Args: - table (str) : Table name as in the CSV file. Later - tansformed into SQL DB table format. - - Returns: - last_update (datetime) : Datetime with the max date in the table. - - Raises: - Exception (Exception) : Connection with the database could not be - stablished. - """ - engine = get_engine(env.db.default_credential) - try: - df = pd.read_sql(f"select * from switzerland.foph_{table.lower()}_d;", engine) - if "date" not in df: - df = df.datum.dropna() - last_update = df.max() - df = df.date.dropna() - last_update = df.max() - return datetime.strptime(str(last_update), "%Y-%m-%d %H:%M:%S") - except Exception as e: - logger.error(f"Could not access {table} table\n{e}") - raise (e) diff --git a/epigraphhub/data/data_collection/foph/load_into_db.py b/epigraphhub/data/data_collection/foph/load_into_db.py deleted file mode 100644 index 1777b08d..00000000 --- a/epigraphhub/data/data_collection/foph/load_into_db.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Last change on 2022/09/22 -This module will retrieve the data from a CSV file, create a connection -with the SQL Database and update it with the new information. Pangres -will generate chunks with total length of 1000 and insert them into the -corresponding table as specified by the downloaded CSV file. -@see epigraphhub.data.data_collection.foph.download -@see epigraphhub.connection - -Methods -------- - -load(table, filename): - Connects to SQL DB and update a table with CSV information. -""" -import pandas as pd -from loguru import logger -from pangres import upsert - -from epigraphhub.connection import get_engine -from epigraphhub.data.data_collection.config import FOPH_CSV_PATH, FOPH_LOG_PATH -from epigraphhub.settings import env - -logger.add(FOPH_LOG_PATH, retention="7 days") - - -def load(table, filename): - """ - A generator responsible connecting and loading data - retrieved from a CSV file into its respective table in - the SQL Database, as defined in the connection configuration. - @see epigraphhub.connection - - Args: - table (str) : Raw table name. Later parsed to SQL format. - filename (str) : File name as defined in the CSV URL. - @see .download as above. - """ - new_df = pd.read_csv(f"{FOPH_CSV_PATH}/{filename}") - logger.info(f"Reading {filename}") - - new_df = new_df.rename(columns=str.lower) - new_df.index.name = "id_" - if "date" not in new_df.columns: - new_df["date"] = pd.to_datetime(new_df.datum) - else: - new_df["date"] = pd.to_datetime(new_df.date) - logger.info(f"Table {table} passed to DataFrame") - - engine = get_engine(env.db.default_credential) - with engine.connect() as conn: - upsert( - con=conn, - df=new_df, - table_name=f"foph_{table.lower()}_d", - schema="switzerland", - if_row_exists="update", - chunksize=1000, - add_new_columns=True, - create_table=True, - ) - logger.info(f"Table foph_{table.lower()}_d updated") diff --git a/epigraphhub/data/data_collection/owid/__init__.py b/epigraphhub/data/data_collection/owid/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/epigraphhub/data/data_collection/owid/download_data.py b/epigraphhub/data/data_collection/owid/download_data.py deleted file mode 100644 index 493c06e3..00000000 --- a/epigraphhub/data/data_collection/owid/download_data.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -Last change on 2022/09/22 -This module is used for fetching and downloading COVID -data from Our World in Data. The data of interest consists in a -CSV table containing COVID information around the globe. - - -Methods -------- - -download_csv(): - Runs curl from the OWID database and stores the CSV file in the tmp dir. - -remove_csv(): - Removes the CSV file recursively. -""" -import os -import subprocess - -from loguru import logger - -from epigraphhub.data.data_collection.config import ( - OWID_CSV_PATH, - OWID_CSV_URL, - OWID_FILENAME, - OWID_LOG_PATH, -) - -logger.add(OWID_LOG_PATH, retention="7 days") - - -def download_csv(): - """ - This method is responsible for download the CSV file from the - OWID database. The file contains world information about COVID. - """ - os.makedirs(OWID_CSV_PATH, exist_ok=True) - subprocess.run( - [ - "curl", - "--silent", - "-f", - "-o", - f"{OWID_CSV_PATH}/{OWID_FILENAME}", - f"{OWID_CSV_URL}", - ] - ) - logger.info("OWID csv downloaded.") - - -def remove_csv(): - """ - This method deletes the OWID CSV file recursively. - """ - os.remove(f"{OWID_CSV_PATH}/{OWID_FILENAME}") - logger.info("OWID csv removed.") diff --git a/epigraphhub/data/data_collection/colombia/__init__.py b/epigraphhub/data/foph/__init__.py similarity index 100% rename from epigraphhub/data/data_collection/colombia/__init__.py rename to epigraphhub/data/foph/__init__.py diff --git a/epigraphhub/data/data_collection/foph/download_data.py b/epigraphhub/data/foph/extract.py similarity index 75% rename from epigraphhub/data/data_collection/foph/download_data.py rename to epigraphhub/data/foph/extract.py index 97eee0b8..fa1ef893 100644 --- a/epigraphhub/data/data_collection/foph/download_data.py +++ b/epigraphhub/data/foph/extract.py @@ -1,5 +1,5 @@ """ -Last change on 2022/09/22 +Last change on 2022/10/24 This module is used for fetching and downloading COVID data from Federal Office of Public Health. The data of interest consists in the following CSV tables: @@ -35,20 +35,17 @@ """ import os import subprocess +from pathlib import Path import requests from loguru import logger -from epigraphhub.data.data_collection.config import ( - FOPH_CSV_PATH, - FOPH_LOG_PATH, - FOPH_URL, -) +from epigraphhub.data._config import FOPH_CSV_PATH, FOPH_LOG_PATH, FOPH_URL logger.add(FOPH_LOG_PATH, retention="7 days") -def get_csv_relation(source=FOPH_URL): +def fetch(source=FOPH_URL): """ A generator responsible for accessing FOPH and retrieve the CSV relation, such as its Table name and URL as a tuple. @@ -66,7 +63,7 @@ def get_csv_relation(source=FOPH_URL): yield table, url -def download_csv(url): +def download(url): """ This methods runs curl in a URL that corresponds to a CSV file and stores it as specified in the URL. @@ -89,9 +86,22 @@ def download_csv(url): logger.info(f"{filename} downloaded at {FOPH_CSV_PATH}.") -def remove_csvs(): +def remove(filename: str = None, entire_dir: bool = False): """ - Removes recursively the FOPH CSV's folder. + Removes recursively the FOPH CSV's folder or filename. """ - subprocess.run(["rm", "-rf", FOPH_CSV_PATH]) - logger.info(f"{FOPH_CSV_PATH} removed.") + if entire_dir: + subprocess.run(["rm", "-rf", FOPH_CSV_PATH]) + logger.info(f"{FOPH_CSV_PATH} removed.") + + elif filename: + file_path = Path(FOPH_CSV_PATH) / filename + if file_path.exists(): + file_path.unlink() + logger.info(f"{file_path} removed.") + else: + raise Exception(f"{file_path} not found.") + + else: + logger.error(f"Set `entire_dir=True` to remove CSV dir") + raise Exception("Nothing was selected to remove") diff --git a/epigraphhub/data/foph/loading.py b/epigraphhub/data/foph/loading.py new file mode 100644 index 00000000..8194c270 --- /dev/null +++ b/epigraphhub/data/foph/loading.py @@ -0,0 +1,123 @@ +""" +Last change on 2022/10/24 +This module will retrieve the data from a CSV file, create a connection +with the SQL Database and update it with the new information. Pangres +will generate chunks with total length of 1000 and insert them into the +corresponding table as specified by the downloaded CSV file. +@see epigraphhub.connection + +Methods +------- + +load(table, filename): + Connects to SQL DB and update a table with CSV information. +""" +from datetime import datetime + +import pandas as pd +from loguru import logger +from pangres import upsert + +from epigraphhub.connection import get_engine +from epigraphhub.data._config import FOPH_CSV_PATH, FOPH_LOG_PATH +from epigraphhub.settings import env + +logger.add(FOPH_LOG_PATH, retention="7 days") + + +def upload(table, filename): + """ + A generator responsible connecting and loading data + retrieved from a CSV file into its respective table in + the SQL Database, as defined in the connection configuration. + @see epigraphhub.connection + + Args: + table (str) : Raw table name. Later parsed to SQL format. + filename (str) : File name as defined in the CSV URL. + @see .download as above. + """ + new_df = pd.read_csv(f"{FOPH_CSV_PATH}/{filename}") + logger.info(f"Reading {filename}") + + new_df = new_df.rename(columns=str.lower) + new_df.index.name = "id_" + if "date" not in new_df.columns: + new_df["date"] = pd.to_datetime(new_df.datum) + else: + new_df["date"] = pd.to_datetime(new_df.date) + logger.info(f"Table {table} passed to DataFrame") + + engine = get_engine(env.db.default_credential) + with engine.connect() as conn: + upsert( + con=conn, + df=new_df, + table_name=f"foph_{table.lower()}_d", + schema="switzerland", + if_row_exists="update", + chunksize=1000, + add_new_columns=True, + create_table=True, + ) + logger.info(f"Table foph_{table.lower()}_d updated") + + +def compare(filename, table) -> bool: + csv_date = _csv_last_update(filename) + table_date = _table_last_update(table) + return csv_date == table_date + + +def _csv_last_update(filename) -> datetime: + """ + Method responsible for retrieving the maximum date in a CSV file. + + Args: + filename (str) : The CSV filename. + + Returns: + last_update (datetime) : Datetime with the max date in the CSV. + + Raises: + Exception (Exception) : Empty dataframe from CSV. + """ + df = pd.read_csv(f"{FOPH_CSV_PATH}/{filename}") + if "date" not in df: + last_update = df.datum.max() + else: + last_update = df.date.max() + if df.empty: + raise Exception("Empty file.") + return datetime.strptime(str(last_update), "%Y-%m-%d") + + +def _table_last_update(table) -> datetime: + """ + Method responsible for connecting and retrieving the maximum date + of a table in the SQL Database. + @see epigraphhub.connection : Where the connection is configured. + + Args: + table (str) : Table name as in the CSV file. Later + tansformed into SQL DB table format. + + Returns: + last_update (datetime) : Datetime with the max date in the table. + + Raises: + Exception (Exception) : Connection with the database could not be + stablished. + """ + engine = get_engine(env.db.default_credential) + try: + df = pd.read_sql(f"select * from switzerland.foph_{table.lower()}_d;", engine) + if "date" not in df: + df = df.datum.dropna() + last_update = df.max() + df = df.date.dropna() + last_update = df.max() + return datetime.strptime(str(last_update), "%Y-%m-%d %H:%M:%S") + except Exception as e: + logger.error(f"Could not access {table} table\n{e}") + raise (e) diff --git a/epigraphhub/data/data_collection/foph/update_index.py b/epigraphhub/data/foph/transform.py similarity index 100% rename from epigraphhub/data/data_collection/foph/update_index.py rename to epigraphhub/data/foph/transform.py diff --git a/epigraphhub/data/foph.py b/epigraphhub/data/foph/viz.py similarity index 100% rename from epigraphhub/data/foph.py rename to epigraphhub/data/foph/viz.py diff --git a/epigraphhub/data/data_collection/foph/__init__.py b/epigraphhub/data/owid/__init__.py similarity index 100% rename from epigraphhub/data/data_collection/foph/__init__.py rename to epigraphhub/data/owid/__init__.py diff --git a/epigraphhub/data/data_collection/owid/compare_data.py b/epigraphhub/data/owid/extract.py similarity index 55% rename from epigraphhub/data/data_collection/owid/compare_data.py rename to epigraphhub/data/owid/extract.py index 128aabed..6297ef3a 100644 --- a/epigraphhub/data/data_collection/owid/compare_data.py +++ b/epigraphhub/data/owid/extract.py @@ -1,19 +1,18 @@ """ -Last change on 2022/09/22 -Comparing Our World in Data (OWID) COVID data consists in -a step before pushing it to the database. Is responsible for retrieving -the table size in both CSV and in the SQL Database. -@see epigraphhub.connection +Last change on 2022/10/24 +This module is used for fetching and downloading COVID +data from Our World in Data. The data of interest consists in a +CSV table containing COVID information around the globe. + Methods ------- -database_size(remote): - If remote, creates the ssh connection with the SQL server. Then returns - the total count of the OWID table. +download_csv(): + Runs curl from the OWID database and stores the CSV file in the tmp dir. -csv_size(): - Looks for the OWID CSV file and returns its total rows count. +remove_csv(): + Removes the CSV file recursively. """ import os import shlex as sx @@ -22,8 +21,9 @@ from loguru import logger from epigraphhub.connection import get_engine -from epigraphhub.data.data_collection.config import ( +from epigraphhub.data._config import ( OWID_CSV_PATH, + OWID_CSV_URL, OWID_FILENAME, OWID_HOST, OWID_LOG_PATH, @@ -31,9 +31,43 @@ from epigraphhub.settings import env logger.add(OWID_LOG_PATH, retention="7 days") +engine = get_engine(env.db.default_credential) + + +def download() -> None: + """ + This method is responsible for download the CSV file from the + OWID database. The file contains world information about COVID. + """ + os.makedirs(OWID_CSV_PATH, exist_ok=True) + subprocess.run( + [ + "curl", + "--silent", + "-f", + "-o", + f"{OWID_CSV_PATH}/{OWID_FILENAME}", + f"{OWID_CSV_URL}", + ] + ) + logger.info("OWID csv downloaded.") + + +def compare() -> bool: + table_size = _get_database_size(remote=False) + csv_size = _get_csv_size() + return table_size == csv_size -def database_size(remote=True): +def remove() -> None: + """ + This method deletes the OWID CSV file recursively. + """ + os.remove(f"{OWID_CSV_PATH}/{OWID_FILENAME}") + logger.info("OWID csv removed.") + + +def _get_database_size(remote=True) -> int: """ Method responsible for connecting in the SQL database and return the total count of the OWID table. @@ -64,18 +98,13 @@ def database_size(remote=True): proc.kill() -def csv_size(): +def _get_csv_size() -> int: """ Method responsible for connecting in the SQL database and return - the total count of the OWID table. - - Args: - remote (bool) : If the SQL container is not locally configured, - creates a ssh tunnel with the Database. + the total count of the OWID CSV file. Raises: - Exception (Exception) : Connection with the Database could not be - stablished. + Exception (Exception) : CSV file not found. """ try: raw_shape = subprocess.Popen( diff --git a/epigraphhub/data/data_collection/owid/load_into_db.py b/epigraphhub/data/owid/loading.py similarity index 92% rename from epigraphhub/data/data_collection/owid/load_into_db.py rename to epigraphhub/data/owid/loading.py index e75a1656..1193943a 100644 --- a/epigraphhub/data/data_collection/owid/load_into_db.py +++ b/epigraphhub/data/owid/loading.py @@ -24,7 +24,7 @@ from loguru import logger from epigraphhub.connection import get_engine -from epigraphhub.data.data_collection.config import ( +from epigraphhub.data._config import ( OWID_CSV_PATH, OWID_FILENAME, OWID_HOST, @@ -37,24 +37,7 @@ engine_public = get_engine(env.db.default_credential) -def parse_types(df): - """ - Method responsible for receive the OWID DataFrame and return - a DataFrame with the date parsed to datetime objects. - - Args: - df (DataFrame) : OWID DataFrame. - - Returns: - df (DataFrame) : OWID DataFrame with date column parsed to datetime. - """ - df = df.convert_dtypes() - df["date"] = pd.to_datetime(df.date) - logger.info("OWID data types parsed.") - return df - - -def load(remote=True): +def upload(remote=True): """ A generator responsible connecting and loading data retrieved from the OWID CSV file into owid_covid table in @@ -70,7 +53,7 @@ def load(remote=True): ) try: data = pd.read_csv(os.path.join(OWID_CSV_PATH, OWID_FILENAME)) - data = parse_types(data) + data = _parse_date(data) engine = engine_public data.to_sql( "owid_covid", @@ -87,3 +70,19 @@ def load(remote=True): finally: if remote: proc.kill() + + +def _parse_date(df): + """ + Method responsible for receive the OWID DataFrame and return + a DataFrame with the date parsed to datetime objects. + + Args: + df (DataFrame) : OWID DataFrame. + + Returns: + df (DataFrame) : OWID DataFrame with date column parsed to datetime. + """ + df = df.convert_dtypes() + df["date"] = pd.to_datetime(df.date) + return df diff --git a/epigraphhub/data/data_collection/owid/update_index.py b/epigraphhub/data/owid/transform.py similarity index 95% rename from epigraphhub/data/data_collection/owid/update_index.py rename to epigraphhub/data/owid/transform.py index 2bff3c70..32763d75 100644 --- a/epigraphhub/data/data_collection/owid/update_index.py +++ b/epigraphhub/data/owid/transform.py @@ -1,5 +1,5 @@ """ -Last change on 2022/09/22 +Last change on 2022/10/24 This module is responsible for including missing index in the OWID SQL table. Connects to the SQL server as defined in the connection. @see epigraphhub.connection @@ -16,7 +16,7 @@ from loguru import logger from epigraphhub.connection import get_engine -from epigraphhub.data.data_collection.config import OWID_HOST, OWID_LOG_PATH +from epigraphhub.data._config import OWID_HOST, OWID_LOG_PATH from epigraphhub.settings import env logger.add(OWID_LOG_PATH, retention="7 days")