diff --git a/statvar_imports/brazil_sidra_ibge/README.md b/statvar_imports/brazil_sidra_ibge/README.md index 513633fba7..3ed227e00f 100644 --- a/statvar_imports/brazil_sidra_ibge/README.md +++ b/statvar_imports/brazil_sidra_ibge/README.md @@ -6,7 +6,7 @@ - Import Type: Fully Autorefresh -- Data Availability: 2022 to 2025 +- Data Availability: Data is available from 2022-03 for every quarter and data is added every 3 months. - Release Frequency: P3M, which means every 3 months (quarterly). diff --git a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py index ce35215dcf..864d22b306 100644 --- a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py +++ b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py @@ -1,4 +1,4 @@ -# Copyright 2025 Google LLC +# Copyright 2026 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,28 +12,55 @@ # See the License for the specific language governing permissions and # limitations under the License. +""" +Downloads PNAD Continuous (PNADc) quarterly data directly via IBGE REST API. +Fetches data starting from Q1 2022 to the latest available period and reshapes +the output into Excel spreadsheets. +""" + import os -import re import time -import glob -from absl import app, logging, flags from pathlib import Path +from typing import Any, Dict, List, Optional + +from absl import app, flags, logging +import pandas as pd +import requests +from requests.adapters import HTTPAdapter +from urllib3.util import Retry + +from vars import ( + LOCATIONS, + get_panel_1_specs, + get_panel_2_specs, + get_panel_3_specs, + get_panel_4_specs, +) -# Import specific Selenium exceptions -from selenium.common.exceptions import TimeoutException, NoSuchElementException -from selenium import webdriver -from selenium.webdriver.common.by import By -from selenium.webdriver.chrome.options import Options as ChromeOptions -from selenium.webdriver.support.ui import WebDriverWait, Select -from selenium.webdriver.support import expected_conditions as EC +# --- Robust Session Setup --- +def get_robust_session() -> requests.Session: + """Configures a global requests Session with automated retries and connection pooling. + + Retries up to 10 times with exponential backoff on common server error codes (500, 502, 503, 504). + """ + session = requests.Session() + retries = Retry( + total=10, + backoff_factor=1, + status_forcelist=[500, 502, 503, 504], + raise_on_status=False + ) + session.mount("https://", HTTPAdapter(max_retries=retries)) + return session +# Global session instance +SESSION = get_robust_session() -# --- Configuration --- -BASE_URL = "https://sidra.ibge.gov.br/home/pnadct/" +# --- Configuration Constants --- SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) DOWNLOAD_DIR = os.path.join(SCRIPT_DIR, "input_files") -# Mapping of panel index to subfolder name +# Maps panel indices (1 to 4) to their target folder names PANEL_FOLDER_MAP = { 1: "Employment_And_Unemployment_Labor_Force", 2: "Population_Economic_sector", @@ -41,196 +68,289 @@ 4: "Mass_Income" } +# The starting quarter code (YYYYQQ) for filtering period metadata +PERIOD_START = "202201" -def setup_driver(): - """Configures and returns a Selenium WebDriver.""" - chrome_options = ChromeOptions() - prefs = { - "download.default_directory": DOWNLOAD_DIR, - "download.prompt_for_download": False, - "download.directory_upgrade": True, - "safeBrowse.enabled": True - } - chrome_options.add_experimental_option("prefs", prefs) - chrome_options.add_argument("--headless") - chrome_options.add_argument("--no-sandbox") - chrome_options.add_argument("--disable-dev-shm-usage") - chrome_options.add_argument("--window-size=1920,1080") - chrome_options.add_argument("--disable-gpu") + +def get_available_periods() -> List[Dict[str, Any]]: + """Fetches available period metadata starting from Q1 2022 to the latest available period. + + Returns: + List[Dict[str, Any]]: List of dictionary objects containing period metadata. + """ + url = "https://servicodados.ibge.gov.br/api/v3/agregados/6461/periodos" + headers = {"User-Agent": "Mozilla/5.0"} - logging.info("WebDriver options configured.") - return webdriver.Chrome(options=chrome_options) - - -def wait_for_downloads(timeout=30): - """Waits for all downloads to finish.""" - start_time = time.time() - while True: - if not any(f.endswith(".crdownload") for f in os.listdir(DOWNLOAD_DIR)): - return True - if time.time() - start_time > timeout: - logging.fatal("Timeout waiting for downloads to complete. Exiting script.") - raise RuntimeError("Timeout waiting for downloads.") - time.sleep(1) - -def rename_and_move_downloaded_file(place_name, panel_index): - """Renames the most recently downloaded file and moves it to the correct subfolder.""" try: - time.sleep(1) # Give a moment for the file system to update + res = SESSION.get(url, headers=headers, timeout=30) + res.raise_for_status() + periods_data = res.json() + + # Verify JSON structure before filtering + if not isinstance(periods_data, list): + logging.error("API response for periods was not a valid list.") + return [] + + return [p for p in periods_data if isinstance(p, dict) and p.get("id", "") >= PERIOD_START] - # Get the destination folder name from the map - folder_name = PANEL_FOLDER_MAP.get(panel_index) - if not folder_name: - logging.warning(f"No folder mapping found for panel index {panel_index}. Skipping file move for {place_name}.") - return + except requests.exceptions.RequestException as req_err: + logging.error(f"Network error fetching period metadata from IBGE API: {req_err}") + except ValueError as json_err: + logging.error(f"Failed to parse JSON period metadata response: {json_err}") + except Exception as e: + logging.error(f"Unexpected error when retrieving available periods: {e}") - # Find the latest downloaded file in the main DOWNLOAD_DIR - list_of_files = glob.glob(os.path.join(DOWNLOAD_DIR, '*.xlsx')) - if not list_of_files: - logging.warning(f"No XLSX file found to rename for {place_name} (Panel {panel_index}).") - return - - latest_file = max(list_of_files, key=os.path.getctime) - - # Construct the new filename - new_filename = f"{place_name.replace(' ', '_')}_Panel_{panel_index}_{os.path.basename(latest_file)}" + return [] + + +def format_quarter_label(period_item: Dict[str, Any]) -> str: + """Formats period literals to match UI quarter headers (e.g., '1º trimestre 2022'). + + Args: + period_item: A dictionary containing period properties ('id', 'literals'). + + Returns: + str: Formatted string header for the quarter. + """ + try: + # Check literals list for an explicit quarter description string + for lit in period_item.get("literals", []): + if "trimestre" in lit.lower(): + return lit.lower().replace(" ", " ").strip() - # Construct the destination path including the subfolder - destination_dir = os.path.join(DOWNLOAD_DIR, folder_name) - Path(destination_dir).mkdir(parents=True, exist_ok=True) # Ensure subfolder exists - new_filepath = os.path.join(destination_dir, new_filename) - - # Move and rename the file - os.rename(latest_file, new_filepath) - logging.info(f"Moved and renamed file from '{os.path.basename(latest_file)}' to '{new_filepath}'") + # Fallback parsing based on period ID structure (YYYYQQ) + p_id = period_item["id"] + year = p_id[:4] + q = int(p_id[4:]) + return f"{q}º trimestre {year}" except Exception as e: - logging.fatal(f"Failed to rename and move file for {place_name} (Panel {panel_index}): {e}. Exiting script.") - raise RuntimeError(f"File operation failed: {e}") + logging.warning(f"Failed to format quarter label for {period_item}: {e}") + return str(period_item.get("id", "Unknown Period")) -def download_panel(driver, panel_index, place_name): - """ - Locates a panel, opens the dropdown, clicks the download button, - and then calls the rename and move function. +def fetch_aggregate_series(agg_id: int, var_id: int, geo_code: str, period_query: str, classif: Optional[str] = None) -> Dict[str, Dict[str, str]]: + """Helper function to query IBGE aggregate API endpoint using robust SESSION with error handling. + + Args: + agg_id: The aggregate code. + var_id: The variable code. + geo_code: IBGE geographical region string (e.g., 'N1[1]'). + period_query: Pipeline-separated period string (e.g., '202201|202202'). + classif: Optional classification parameters string. + + Returns: + Dict[str, Dict[str, str]]: Dictionary mapping category keys to time series data. """ + url = f"https://servicodados.ibge.gov.br/api/v3/agregados/{agg_id}/periodos/{period_query}/variaveis/{var_id}?localidades={geo_code}" + if classif: + url += f"&classificacao={classif}" + + headers = {"User-Agent": "Mozilla/5.0"} try: - panel_id = f"pnadct-q{panel_index}" - panel_div = WebDriverWait(driver, 15).until( - EC.presence_of_element_located((By.ID, panel_id)) - ) - - dropdown_button = WebDriverWait(panel_div, 10).until( - EC.element_to_be_clickable((By.CSS_SELECTOR, "div.janela-btn.dropdown span.dropdown-toggle")) - ) - dropdown_button.click() - - export_option = WebDriverWait(panel_div, 10).until( - EC.element_to_be_clickable((By.CSS_SELECTOR, "ul.dropdown-menu li[data-item='0'] a")) - ) - export_option.click() + r = SESSION.get(url, headers=headers, timeout=30) - logging.info(f" Downloading XLSX from panel {panel_id} for {place_name}") - time.sleep(2) # Give a moment for the download to initiate - rename_and_move_downloaded_file(place_name, panel_index) + # Non-200 responses should yield gracefully without crashing the whole run + if r.status_code != 200: + logging.warning(f"HTTP {r.status_code} received for Agg {agg_id}, Var {var_id}") + return {} + + data = r.json() - except (TimeoutException, NoSuchElementException) as e: - logging.fatal(f" Selenium element error during download from {panel_id} for {place_name}: {e}. Exiting script.") - raise RuntimeError(f"Selenium element error: {e}") # Added raise + # Guard check to ensure valid list structure returned from API + if not isinstance(data, list) or not data or "resultados" not in data[0]: + logging.warning(f"Invalid or empty response structure for Agg {agg_id}, Var {var_id}") + return {} + + result_map = {} + for res in data[0]["resultados"]: + cat_key = "Total" + # Extract category classification keys if present + if res.get("classificacoes"): + cats = res["classificacoes"][0].get("categoria", {}) + if cats: + cat_key = list(cats.keys())[0] + + # Map time-series dictionary to category key + for s in res.get("series", []): + serie = s.get("serie", {}) + result_map[cat_key] = serie + + return result_map + + except requests.exceptions.RequestException as req_err: + logging.warning(f"Network exception downloading Agg {agg_id}, Var {var_id}: {req_err}") + except ValueError as json_err: + logging.warning(f"JSON decoding error for Agg {agg_id}, Var {var_id}: {json_err}") except Exception as e: - logging.fatal(f" Critical download failure from {panel_id} for {place_name}: {e}. Exiting script.") - raise RuntimeError(f"Critical download failure: {e}") # Added raise + logging.warning(f"Unexpected error fetching Agg {agg_id}, Var {var_id}: {e}") + return {} -def get_url_slug(place_name): - """ - Generates a URL slug from the place name, matching the website's pattern. - """ - import unicodedata - slug = place_name.lower().replace(' ', '-') - # Normalize unicode characters to their base form - nfkd_form = unicodedata.normalize('NFKD', slug) - return "".join([c for c in nfkd_form if not unicodedata.combining(c)]) -def get_place_select_element(driver): - """ - Waits for and returns the Select object for the place dropdown. +def fetch_panel_data(place_name: str, geo_code: str, panel_index: int, periods: List[Dict[str, Any]]) -> None: + """Fetches SIDRA data for 2022Q1 to latest period, reshapes output, and writes to Excel. + + Args: + place_name: Display name of state/region. + geo_code: IBGE spatial lookup code. + panel_index: Index number (1 to 4) representing the panel configuration. + periods: List of available periods metadata dictionaries. """ try: - select_element = WebDriverWait(driver, 20).until( - EC.presence_of_element_located((By.ID, "codigolist-pnadct")) - ) - return Select(select_element) - except TimeoutException: - logging.fatal("Timeout while waiting for the place selection dropdown. Exiting script.") - raise RuntimeError("Could not find the 'codigolist-pnadct' element.") + period_ids = [p["id"] for p in periods] + period_labels = [format_quarter_label(p) for p in periods] + period_query = "|".join(period_ids) + + folder_name = PANEL_FOLDER_MAP[panel_index] + dest_dir = os.path.join(DOWNLOAD_DIR, folder_name) + + # Safely create target output directory + try: + Path(dest_dir).mkdir(parents=True, exist_ok=True) + except Exception as e: + logging.error(f"Could not create destination directory '{dest_dir}': {e}") + return + + filename = f"{place_name.replace(' ', '_')}_Panel_{panel_index}_Pesquisa Nacional por Amostra de Domicílios Contínua - Divulgação Trimestral.xlsx" + filepath = os.path.join(dest_dir, filename) + + title_row = "Pesquisa Nacional por Amostra de Domicílios Contínua - Divulgação Trimestral" + num_cols = len(period_labels) + 1 + rows = [] + + # Define subheaders by panel type + if panel_index == 1: + subtitle_row = f"Taxas e Níveis - Indicadores selecionados - Últimos {len(periods)} trimestres" + elif panel_index == 2: + subtitle_row = f"População - Indicadores selecionados - Últimos {len(periods)} trimestres" + elif panel_index == 3: + subtitle_row = f"Rendimento - Indicadores selecionados - Últimos {len(periods)} trimestres" + elif panel_index == 4: + subtitle_row = f"Massa de rendimento - Indicadores selecionados - Últimos {len(periods)} trimestres" + + # Build table metadata header block + rows.append([title_row] + [''] * (num_cols - 1)) + rows.append([subtitle_row] + [''] * (num_cols - 1)) + rows.append([place_name] + [''] * (num_cols - 1)) + rows.append(['Indicador', 'Trimestre de coleta'] + [''] * (num_cols - 2)) + rows.append([''] + period_labels) + + # --------------------------------------------------------- + # Panel 1: Employment and Unemployment / Labor Force + # --------------------------------------------------------- + if panel_index == 1: + s1 = fetch_aggregate_series(6461, 4096, geo_code, period_query).get("Total", {}) + s2 = fetch_aggregate_series(6466, 4097, geo_code, period_query).get("Total", {}) + s3 = fetch_aggregate_series(6467, 4098, geo_code, period_query).get("Total", {}) + s4 = fetch_aggregate_series(6468, 4099, geo_code, period_query).get("Total", {}) + + ind_specs = get_panel_1_specs(s1, s2, s3, s4) + for name, serie in ind_specs: + vals = [serie.get(pid, '') for pid in period_ids] + rows.append([name] + vals) + + rows.append(["Fonte: IBGE, Diretoria de Pesquisas, Coordenação de Trabalho e Rendimento, Pesquisa Nacional por Amostra de Domicílios Contínua"] + [''] * (num_cols - 1)) + + # --------------------------------------------------------- + # Panel 2: Population & Economic Sectors + # --------------------------------------------------------- + elif panel_index == 2: + s_pop = fetch_aggregate_series(6462, 606, geo_code, period_query).get("Total", {}) + m_6463 = fetch_aggregate_series(6463, 1641, geo_code, period_query, classif="629[all]") + m_6464 = fetch_aggregate_series(6464, 4090, geo_code, period_query, classif="11913[all]") + m_6465 = fetch_aggregate_series(6465, 4090, geo_code, period_query, classif="888[all]") + + ind_specs = get_panel_2_specs(s_pop, m_6463, m_6464, m_6465) + for name, serie in ind_specs: + vals = [serie.get(pid, '') for pid in period_ids] + rows.append([name] + vals) + + # --------------------------------------------------------- + # Panel 3: Average Real Income + # --------------------------------------------------------- + elif panel_index == 3: + s_all_usual = fetch_aggregate_series(6472, 5933, geo_code, period_query).get("Total", {}) + s_all_eff = fetch_aggregate_series(6469, 5935, geo_code, period_query).get("Total", {}) + m_6471 = fetch_aggregate_series(6471, 5932, geo_code, period_query, classif="11913[all]") + s_main_eff = fetch_aggregate_series(6470, 5934, geo_code, period_query).get("Total", {}) + m_6473 = fetch_aggregate_series(6473, 5932, geo_code, period_query, classif="888[all]") + + ind_specs = get_panel_3_specs(s_all_usual, s_all_eff, m_6471, s_main_eff, m_6473) + for name, serie in ind_specs: + vals = [serie.get(pid, '') for pid in period_ids] + rows.append([name] + vals) + + # --------------------------------------------------------- + # Panel 4: Mass Income + # --------------------------------------------------------- + elif panel_index == 4: + s_mass_usual = fetch_aggregate_series(6474, 6293, geo_code, period_query).get("Total", {}) + s_mass_eff = fetch_aggregate_series(6475, 6295, geo_code, period_query).get("Total", {}) + + ind_specs = get_panel_4_specs(s_mass_usual, s_mass_eff) + for name, serie in ind_specs: + vals = [serie.get(pid, '') for pid in period_ids] + rows.append([name] + vals) + + rows.append(["Fonte: IBGE, Diretoria de Pesquisas, Coordenação de Trabalho e Rendimento, Pesquisa Nacional por Amostra de Domicílios Contínua"] + [''] * (num_cols - 1)) + rows.append(["Nota: 1 - O rendimento está deflacionado para o mês do meio do último trimestre de coleta divulgado."] + [''] * (num_cols - 1)) + rows.append(["2 - O rendimento efetivo se refere ao valor recebido no mês anterior ao da coleta."] + [''] * (num_cols - 1)) + + # Convert constructed matrix to DataFrame + df_out = pd.DataFrame(rows) + + # Safely write spreadsheet out to file + try: + with pd.ExcelWriter(filepath, engine='openpyxl') as writer: + df_out.to_excel(writer, sheet_name='Sheet 1', index=False, header=False) + logging.info(f"Saved: '{filepath}'") + except Exception as write_err: + logging.error(f"Failed writing Excel file to '{filepath}': {write_err}") + + except Exception as general_err: + logging.error(f"Failed processing Panel {panel_index} for '{place_name}': {general_err}") + def main(argv): - """Main function to orchestrate the scraping and downloading.""" - del argv # Unused. + """Main execution function to orchestrate downloading and processing data.""" + del argv logging.info("Script started.") - - # Create the main download directory and the four subfolders - os.makedirs(DOWNLOAD_DIR, exist_ok=True) - for folder_name in PANEL_FOLDER_MAP.values(): - os.makedirs(os.path.join(DOWNLOAD_DIR, folder_name), exist_ok=True) - - driver = setup_driver() + + # Safely create input base directory structure try: - driver.get(BASE_URL) - logging.info(f"Navigated to base URL: {BASE_URL}") + os.makedirs(DOWNLOAD_DIR, exist_ok=True) + for folder_name in PANEL_FOLDER_MAP.values(): + os.makedirs(os.path.join(DOWNLOAD_DIR, folder_name), exist_ok=True) + except Exception as dir_err: + logging.fatal(f"Could not setup target download folders: {dir_err}") + return - # Use the new helper function - select = get_place_select_element(driver) - options_text = [option.text.strip() for option in select.options] + # Retrieve period metadata + periods = get_available_periods() + if not periods: + logging.error("No valid periods found or failed to retrieve periods. Exiting script.") + return - logging.info("\n Processing: Brasil") - try: - for panel_index in range(1, 5): - download_panel(driver, panel_index, 'Brasil') - wait_for_downloads() - except (TimeoutException, NoSuchElementException) as e: - logging.fatal(f" Selenium element error processing 'Brasil' page. Exiting. Error: {e}") - raise RuntimeError(f"Selenium error for 'Brasil' page: {e}") - except Exception as e: - logging.fatal(f" Critical failure processing 'Brasil' page. Exiting. Error: {e}") - raise RuntimeError(f"Critical processing failure for 'Brasil' page: {e}") + logging.info(f"Fetched {len(periods)} available periods starting from {PERIOD_START}: {[p['id'] for p in periods]}") - for place_name in options_text: - if not place_name: - continue + # Process each location and panel step-by-step + for place_name, geo_code in LOCATIONS.items(): + logging.info(f"Processing: {place_name}") + for panel_index in range(1, 5): + try: + fetch_panel_data(place_name, geo_code, panel_index, periods) + except Exception as p_err: + logging.error(f"Unhandled error for {place_name} (Panel {panel_index}): {p_err}") - logging.info(f"\n Processing: {place_name}") + # Short pause to reduce load on the IBGE REST API + time.sleep(0.1) + + logging.info("Script finished successfully.") - try: - # Use the new helper function again - select = get_place_select_element(driver) - - select.select_by_visible_text(place_name) - - place_slug = get_url_slug(place_name) - WebDriverWait(driver, 20).until(EC.url_contains(place_slug)) - WebDriverWait(driver, 20).until( - EC.url_contains(place_slug) and - EC.presence_of_element_located((By.ID, "pnadct-q1")) - ) - - for panel_index in range(1, 5): - download_panel(driver, panel_index, place_name) - - wait_for_downloads() - - except (TimeoutException, NoSuchElementException) as e: - logging.fatal(f" Selenium element error selecting or downloading for {place_name}. Exiting. Error: {e}") - raise RuntimeError(f"Selenium error for {place_name}: {e}") - except Exception as e: - logging.fatal(f" Critical failure selecting or downloading for {place_name}. Exiting. Error: {e}") - raise RuntimeError(f"Critical processing failure for {place_name}: {e}") - - finally: - driver.quit() - logging.info("WebDriver closed.") - logging.info("Script finished.") if __name__ == "__main__": - flags.FLAGS.log_dir = SCRIPT_DIR - app.run(main) + try: + flags.FLAGS.log_dir = SCRIPT_DIR + app.run(main) + except Exception as main_err: + logging.fatal(f"Application terminated due to an unhandled exception: {main_err}") \ No newline at end of file diff --git a/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_average_real_income.csv b/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_average_real_income.csv new file mode 100644 index 0000000000..f626a35df1 --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_average_real_income.csv @@ -0,0 +1,34 @@ +"observationAbout" +"wikidataId/Q40780" +"wikidataId/Q40885" +"wikidataId/Q40130" +"wikidataId/Q40040" +"wikidataId/Q40430" +"country/BRA" +"wikidataId/Q40123" +"wikidataId/Q980175" +"wikidataId/Q119158" +"wikidataId/Q43233" +"wikidataId/Q41587" +"wikidataId/Q42362" +"wikidataId/Q42824" +"wikidataId/Q43319" +"wikidataId/Q39109" +"wikidataId/Q1136194" +"wikidataId/Q478465" +"wikidataId/Q39517" +"wikidataId/Q38088" +"wikidataId/Q15499" +"wikidataId/Q40942" +"wikidataId/Q42722" +"wikidataId/Q43255" +"wikidataId/Q40030" +"wikidataId/Q41428" +"wikidataId/Q43235" +"wikidataId/Q42508" +"wikidataId/Q175" +"wikidataId/Q41115" +"wikidataId/Q43783" +"wikidataId/Q1088815" +"wikidataId/Q1060042" +"wikidataId/Q43695" diff --git a/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_employment_unemployment.csv b/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_employment_unemployment.csv new file mode 100644 index 0000000000..f626a35df1 --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_employment_unemployment.csv @@ -0,0 +1,34 @@ +"observationAbout" +"wikidataId/Q40780" +"wikidataId/Q40885" +"wikidataId/Q40130" +"wikidataId/Q40040" +"wikidataId/Q40430" +"country/BRA" +"wikidataId/Q40123" +"wikidataId/Q980175" +"wikidataId/Q119158" +"wikidataId/Q43233" +"wikidataId/Q41587" +"wikidataId/Q42362" +"wikidataId/Q42824" +"wikidataId/Q43319" +"wikidataId/Q39109" +"wikidataId/Q1136194" +"wikidataId/Q478465" +"wikidataId/Q39517" +"wikidataId/Q38088" +"wikidataId/Q15499" +"wikidataId/Q40942" +"wikidataId/Q42722" +"wikidataId/Q43255" +"wikidataId/Q40030" +"wikidataId/Q41428" +"wikidataId/Q43235" +"wikidataId/Q42508" +"wikidataId/Q175" +"wikidataId/Q41115" +"wikidataId/Q43783" +"wikidataId/Q1088815" +"wikidataId/Q1060042" +"wikidataId/Q43695" diff --git a/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_mass_income.csv b/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_mass_income.csv new file mode 100644 index 0000000000..f626a35df1 --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_mass_income.csv @@ -0,0 +1,34 @@ +"observationAbout" +"wikidataId/Q40780" +"wikidataId/Q40885" +"wikidataId/Q40130" +"wikidataId/Q40040" +"wikidataId/Q40430" +"country/BRA" +"wikidataId/Q40123" +"wikidataId/Q980175" +"wikidataId/Q119158" +"wikidataId/Q43233" +"wikidataId/Q41587" +"wikidataId/Q42362" +"wikidataId/Q42824" +"wikidataId/Q43319" +"wikidataId/Q39109" +"wikidataId/Q1136194" +"wikidataId/Q478465" +"wikidataId/Q39517" +"wikidataId/Q38088" +"wikidataId/Q15499" +"wikidataId/Q40942" +"wikidataId/Q42722" +"wikidataId/Q43255" +"wikidataId/Q40030" +"wikidataId/Q41428" +"wikidataId/Q43235" +"wikidataId/Q42508" +"wikidataId/Q175" +"wikidataId/Q41115" +"wikidataId/Q43783" +"wikidataId/Q1088815" +"wikidataId/Q1060042" +"wikidataId/Q43695" diff --git a/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_population_economic.csv b/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_population_economic.csv new file mode 100644 index 0000000000..f626a35df1 --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_population_economic.csv @@ -0,0 +1,34 @@ +"observationAbout" +"wikidataId/Q40780" +"wikidataId/Q40885" +"wikidataId/Q40130" +"wikidataId/Q40040" +"wikidataId/Q40430" +"country/BRA" +"wikidataId/Q40123" +"wikidataId/Q980175" +"wikidataId/Q119158" +"wikidataId/Q43233" +"wikidataId/Q41587" +"wikidataId/Q42362" +"wikidataId/Q42824" +"wikidataId/Q43319" +"wikidataId/Q39109" +"wikidataId/Q1136194" +"wikidataId/Q478465" +"wikidataId/Q39517" +"wikidataId/Q38088" +"wikidataId/Q15499" +"wikidataId/Q40942" +"wikidataId/Q42722" +"wikidataId/Q43255" +"wikidataId/Q40030" +"wikidataId/Q41428" +"wikidataId/Q43235" +"wikidataId/Q42508" +"wikidataId/Q175" +"wikidataId/Q41115" +"wikidataId/Q43783" +"wikidataId/Q1088815" +"wikidataId/Q1060042" +"wikidataId/Q43695" diff --git a/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_employment_unemployment.csv b/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_employment_unemployment.csv new file mode 100644 index 0000000000..25f7aadb83 --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_employment_unemployment.csv @@ -0,0 +1,3 @@ +"NumObservationsDates","MeasurementMethods","observationPeriods","MinDate","MinValue","MaxValue","NumObservations","Units","StatVar","NumPlaces","MaxDate","ScalingFactors" +"17","[]","[P3M]","2022-03","2.1","17.5","561","[Percent]","Count_Person_Years14Onwards_Unemployed_AsAFractionOf_Count_Person_Years14Onwards","33","2026-03","[100]" +"17","[]","[P3M]","2022-03","47.1","71.4","561","[Percent]","Count_Person_Years14Onwards_InLaborForce_AsAFractionOf_Count_Person_Years14Onwards","33","2026-03","[100]" diff --git a/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_mass_income.csv b/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_mass_income.csv new file mode 100644 index 0000000000..42522005d8 --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_mass_income.csv @@ -0,0 +1,3 @@ +"Units","MinValue","MaxDate","NumObservationsDates","MeasurementMethods","observationPeriods","MinDate","MaxValue","NumObservations","ScalingFactors","StatVar","NumPlaces" +"[BRL]","6.48E8","2026-03","17","[]","[P3M]","2022-03","4.06112E11","561","[]","Monthly_Income_Person_Years14Onwards_Employed_IncomeActuallyReceived","33" +"[BRL]","6.33E8","2026-03","17","[]","[P3M]","2022-03","3.74819E11","561","[]","Monthly_Income_Person_Years14Onwards_Employed","33" diff --git a/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_population_economic.csv b/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_population_economic.csv new file mode 100644 index 0000000000..fb0c685ec3 --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_population_economic.csv @@ -0,0 +1,24 @@ +"NumPlaces","NumObservations","Units","StatVar","observationPeriods","MaxValue","MinValue","ScalingFactors","MeasurementMethods","NumObservationsDates","MinDate","MaxDate" +"33","561","[]","Count_Person_Years14Onwards_PublicSector_Employed","[P3M]","1.3004E7","53000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_Employer_Employed","[P3M]","4270000.0","6000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person","[P3M]","2.13328E8","583000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_AdminSocialServiceEducation_Employed","[P3M]","1.9362E7","59000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_AgricultureForestFishingSector_Employed","[P3M]","8700000.0","12000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_AuxiliaryFamilyWorker_Employed","[P3M]","1923000.0","1000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards","[P3M]","1.7508E8","435000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_SelfEmployed_Employed","[P3M]","2.6109E7","61000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_PrivateSectorNoFormalContract_Employed","[P3M]","1.4067E7","26000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_DomesticServicesSector_Employed","[P3M]","6020000.0","10000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_TransportStorageSector_Employed","[P3M]","5992000.0","9000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_IBGEOtherServicesSector_Employed","[P3M]","5540000.0","10000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_VehicleTradeRepair_Employed","[P3M]","1.9505E7","43000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_GeneralIndustry_Employed","[P3M]","1.3287E7","10000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_Employed","[P3M]","1.02998E8","232000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_CommunicationFinanceSector_Employed","[P3M]","1.3229E7","20000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_AccommodationFoodSector_Employed","[P3M]","5636000.0","12000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_ConstructionSector_Employed","[P3M]","7688000.0","15000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_InLaborForce","[P3M]","1.08569E8","255000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_Unemployed","[P3M]","1.1725E7","12000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_DomesticWorker_Employed","[P3M]","5978000.0","10000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_PrivateSectorFormalContract_Employed","[P3M]","3.9409E7","55000.0","[]","[]","17","2022-03","2026-03" +"33","561","[]","Count_Person_Years14Onwards_NotInLaborForce","[P3M]","6.6525E7","165000.0","[]","[]","17","2022-03","2026-03" diff --git a/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_report_average_real_income.csv b/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_report_average_real_income.csv new file mode 100644 index 0000000000..07c3aff76e --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_report_average_real_income.csv @@ -0,0 +1,21 @@ +"MaxValue","NumObservationsDates","MinValue","MinDate","NumObservations","observationPeriods","MeasurementMethods","ScalingFactors","NumPlaces","Units","MaxDate","StatVar" +"5474.0","17","1257.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_IBGEOtherServicesSector_Employed_MainJob" +"5875.0","17","1497.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_GeneralIndustry_Employed_MainJob" +"7585.0","17","1827.0","2022-03","561","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_Employed_AllJobs_IncomeActuallyReceived" +"10441.0","17","2962.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_AdminSocialServiceEducation_Employed_MainJob" +"5440.0","17","1571.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_TransportStorageSector_Employed_MainJob" +"5631.0","17","611.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_AgricultureForestFishingSector_Employed_MainJob" +"3956.0","17","1926.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_PrivateSectorFormalContract_Employed_MainJob" +"3939.0","17","1650.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_VehicleCommerceRepair_Employed_MainJob" +"6464.0","17","1769.0","2022-03","561","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_Employed_MainJob" +"12900.0","17","2946.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_PublicSector_Employed_MainJob" +"14912.0","17","3527.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_Employer_Employed_MainJob" +"4364.0","17","1093.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_PrivateSectorNoFormalContract_Employed_MainJob" +"7351.0","17","1779.0","2022-03","561","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_Employed_MainJob_IncomeActuallyReceived" +"2020.0","17","722.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_DomesticWorker_Employed_MainJob" +"4883.0","17","1242.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_SelfEmployed_Employed_MainJob" +"3369.0","17","1227.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_AccommodationFoodSector_Employed_MainJob" +"6720.0","17","1813.0","2022-03","561","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_Employed_AllJobs" +"7364.0","17","2224.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_CommunicationFinanceSector_Employed_MainJob" +"2020.0","17","722.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_DomesticServicesSector_Employed_MainJob" +"5150.0","17","1339.0","2022-03","529","[]","[]","[]","33","[BRL]","2026-03","Monthly_Mean_Income_Person_Years14Onwards_ConstructionSector_Employed_MainJob" diff --git a/statvar_imports/brazil_sidra_ibge/manifest.json b/statvar_imports/brazil_sidra_ibge/manifest.json index a18fddf2ed..fc196ff96a 100644 --- a/statvar_imports/brazil_sidra_ibge/manifest.json +++ b/statvar_imports/brazil_sidra_ibge/manifest.json @@ -9,10 +9,10 @@ "provenance_description": "Population Census on Economy Statistics for Brazil at country and state level.", "scripts": [ "brazil_download_script.py", - "../../tools/statvar_importer/stat_var_processor.py --existing_statvar_mcf=gs://unresolved_mcf/scripts/statvar/stat_vars.mcf --input_data=input_files/Average_Real_Income/*.xlsx --pv_map=config_files/average_real_income_pvmap.csv,config_files/place_pvmap.csv --config_file=config_files/brazil_sidra_metadata.csv --output_path=output/average_real_income_output", - "../../tools/statvar_importer/stat_var_processor.py --existing_statvar_mcf=gs://unresolved_mcf/scripts/statvar/stat_vars.mcf --input_data=input_files/Mass_Income/*.xlsx --pv_map=config_files/mass_income_pvmap.csv,config_files/place_pvmap.csv --config_file=config_files/brazil_sidra_metadata.csv --output_path=output/mass_income_output", - "../../tools/statvar_importer/stat_var_processor.py --existing_statvar_mcf=gs://unresolved_mcf/scripts/statvar/stat_vars.mcf --input_data=input_files/Population_Economic_sector/*.xlsx --pv_map=config_files/population_pvmap.csv,config_files/place_pvmap.csv --config_file=config_files/brazil_sidra_metadata.csv --output_path=output/population_economic_sector_output", - "../../tools/statvar_importer/stat_var_processor.py --existing_statvar_mcf=gs://unresolved_mcf/scripts/statvar/stat_vars.mcf --input_data=input_files/Employment_And_Unemployment_Labor_Force/*.xlsx --pv_map=config_files/employment_and_unemployment_labor_force_pvmap.csv,config_files/place_pvmap.csv --config_file=config_files/brazil_sidra_metadata.csv --output_path=output/employment_and_unemployment_labor_force_output" + "../../tools/statvar_importer/stat_var_processor.py --existing_statvar_mcf=gs://unresolved_mcf/scripts/statvar/stat_vars.mcf --input_data=input_files/Average_Real_Income/*.xlsx --pv_map=config_files/average_real_income_pvmap.csv,config_files/place_pvmap.csv --config_file=config_files/brazil_sidra_metadata.csv --output_path=output/average_real_income_output --output_counters=counters/average_real_income_counters.csv", + "../../tools/statvar_importer/stat_var_processor.py --existing_statvar_mcf=gs://unresolved_mcf/scripts/statvar/stat_vars.mcf --input_data=input_files/Mass_Income/*.xlsx --pv_map=config_files/mass_income_pvmap.csv,config_files/place_pvmap.csv --config_file=config_files/brazil_sidra_metadata.csv --output_path=output/mass_income_output --output_counters=counters/mass_income_counters.csv", + "../../tools/statvar_importer/stat_var_processor.py --existing_statvar_mcf=gs://unresolved_mcf/scripts/statvar/stat_vars.mcf --input_data=input_files/Population_Economic_sector/*.xlsx --pv_map=config_files/population_pvmap.csv,config_files/place_pvmap.csv --config_file=config_files/brazil_sidra_metadata.csv --output_path=output/population_economic_sector_output --output_counters=counters/population_economic_sector_counters.csv", + "../../tools/statvar_importer/stat_var_processor.py --existing_statvar_mcf=gs://unresolved_mcf/scripts/statvar/stat_vars.mcf --input_data=input_files/Employment_And_Unemployment_Labor_Force/*.xlsx --pv_map=config_files/employment_and_unemployment_labor_force_pvmap.csv,config_files/place_pvmap.csv --config_file=config_files/brazil_sidra_metadata.csv --output_path=output/employment_and_unemployment_labor_force_output --output_counters=counters/employment_and_unemployment_labor_force_counters.csv" ], "import_inputs": [ { @@ -36,9 +36,12 @@ "input_files/Average_Real_Income/*.xlsx", "input_files/Mass_Income/*.xlsx", "input_files/Population_Economic_sector/*.xlsx", - "input_files/Employment_And_Unemployment_Labor_Force/*.xlsx" + "input_files/Employment_And_Unemployment_Labor_Force/*.xlsx", + "golden_data/*.csv", + "counters/*.csv" ], - "cron_schedule": "30 09 25 * *" + "cron_schedule": "30 09 25 * *", + "validation_config_file": "validation_config.json" } ] } \ No newline at end of file diff --git a/statvar_imports/brazil_sidra_ibge/validation_config.json b/statvar_imports/brazil_sidra_ibge/validation_config.json new file mode 100644 index 0000000000..77371c96f3 --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/validation_config.json @@ -0,0 +1,85 @@ +{ + "schema_version": "1.0", + "rules": [ + { + "rule_id": "check_deleted_records_percent", + "description": "Checks that the percentage of deleted records for the entire import is within threshold.", + "validator": "DELETED_RECORDS_PERCENT", + "params": { + "threshold": 0.1 + } + }, + { + "rule_id": "check_goldens_average_real_income", + "description": "Validates average real income data against its golden summary report.", + "validator": "GOLDENS_CHECK", + "params": { + "golden_files": "../../../../golden_data/golden_summary_report_average_real_income.csv", + "input_files": "../../input0/genmcf/summary_report.csv" + } + }, + { + "rule_id": "check_goldens_mass_income", + "description": "Validates mass income data against its golden summary report.", + "validator": "GOLDENS_CHECK", + "params": { + "golden_files": "../../../../golden_data/golden_summary_mass_income.csv", + "input_files": "../../input1/genmcf/summary_report.csv" + } + }, + { + "rule_id": "check_goldens_population_economic", + "description": "Validates population economic sector data against its golden summary report.", + "validator": "GOLDENS_CHECK", + "params": { + "golden_files": "../../../../golden_data/golden_summary_population_economic.csv", + "input_files": "../../input2/genmcf/summary_report.csv" + } + }, + { + "rule_id": "check_goldens_employment_unemployment", + "description": "Validates employment and unemployment data against its golden summary report.", + "validator": "GOLDENS_CHECK", + "params": { + "golden_files": "../../../../golden_data/golden_summary_employment_unemployment.csv", + "input_files": "../../input3/genmcf/summary_report.csv" + } + }, + { + "rule_id": "Check_goldens_output_csv_average_real_income", + "description": "Verifies the generated output CSV data matches established critical golden records", + "validator": "GOLDENS_CHECK", + "params": { + "golden_files": "../../../../golden_data/golden_observations_average_real_income.csv", + "input_files": "../../../../output/average_real_income_output.csv" + } + }, + { + "rule_id": "Check_goldens_output_csv_mass_income", + "description": "Verifies the generated output CSV data matches established critical golden records", + "validator": "GOLDENS_CHECK", + "params": { + "golden_files": "../../../../golden_data/golden_observations_mass_income.csv", + "input_files": "../../../../output/mass_income_output.csv" + } + }, + { + "rule_id": "Check_goldens_output_csv_population_economic", + "description": "Verifies the generated output CSV data matches established critical golden records", + "validator": "GOLDENS_CHECK", + "params": { + "golden_files": "../../../../golden_data/golden_observations_population_economic.csv", + "input_files": "../../../../output/population_economic_sector_output.csv" + } + }, + { + "rule_id": "Check_goldens_output_csv_employment_unemployment", + "description": "Verifies the generated output CSV data matches established critical golden records", + "validator": "GOLDENS_CHECK", + "params": { + "golden_files": "../../../../golden_data/golden_observations_employment_unemployment.csv", + "input_files": "../../../../output/employment_and_unemployment_labor_force_output.csv" + } + } + ] +} \ No newline at end of file diff --git a/statvar_imports/brazil_sidra_ibge/vars.py b/statvar_imports/brazil_sidra_ibge/vars.py new file mode 100644 index 0000000000..ff8c3870ef --- /dev/null +++ b/statvar_imports/brazil_sidra_ibge/vars.py @@ -0,0 +1,311 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Configuration variables and location mappings for IBGE SIDRA data extraction.""" + +from typing import Any, Dict, List, Tuple + +# Mapping of Brazilian location display names to IBGE geo-location codes +LOCATIONS = { + "Brasil": "N1[1]", + "Norte": "N2[1]", + "Nordeste": "N2[2]", + "Sudeste": "N2[3]", + "Sul": "N2[4]", + "Centro-Oeste": "N2[5]", + "Rondônia": "N3[11]", + "Acre": "N3[12]", + "Amazonas": "N3[13]", + "Roraima": "N3[14]", + "Pará": "N3[15]", + "Amapá": "N3[16]", + "Tocantins": "N3[17]", + "Maranhão": "N3[21]", + "Piauí": "N3[22]", + "Ceará": "N3[23]", + "Rio Grande do Norte": "N3[24]", + "Paraíba": "N3[25]", + "Pernambuco": "N3[26]", + "Alagoas": "N3[27]", + "Sergipe": "N3[28]", + "Bahia": "N3[29]", + "Minas Gerais": "N3[31]", + "Espírito Santo": "N3[32]", + "Rio de Janeiro": "N3[33]", + "São Paulo": "N3[35]", + "Paraná": "N3[41]", + "Santa Catarina": "N3[42]", + "Rio Grande do Sul": "N3[43]", + "Mato Grosso do Sul": "N3[50]", + "Mato Grosso": "N3[51]", + "Goiás": "N3[52]", + "Distrito Federal": "N3[53]", +} + +# --------------------------------------------------------- +# Panel 1: Employment and Unemployment / Labor Force +# --------------------------------------------------------- + +def get_panel_1_specs( + s1: Dict[str, Any], s2: Dict[str, Any], s3: Dict[str, Any], s4: Dict[str, Any] +) -> List[Tuple[str, Dict[str, Any]]]: + """Returns indicator specification mappings for Panel 1.""" + return [ + ( + "Taxa de participação na força de trabalho das pessoas de 14 anos ou mais de idade, na semana de referência (%)", + s1, + ), + ( + "Nível da ocupação das pessoas de 14 anos ou mais de idade, na semana de referência (%)", + s2, + ), + ( + "Nível da desocupação das pessoas de 14 anos ou mais de idade, na semana de referência (%)", + s3, + ), + ( + "Taxa de desocupação das pessoas de 14 anos ou mais de idade, na semana de referência (%)", + s4, + ), + ] + +# --------------------------------------------------------- +# Panel 2: Population & Economic Sectors +# --------------------------------------------------------- + +def get_panel_2_specs( + s_pop: Dict[str, Any], + m_6463: Dict[str, Dict[str, Any]], + m_6464: Dict[str, Dict[str, Any]], + m_6465: Dict[str, Dict[str, Any]], +) -> List[Tuple[str, Dict[str, Any]]]: + """Returns indicator specification mappings for Panel 2.""" + return [ + ("População total (milhares)", s_pop), + ("Pessoas de 14 anos ou mais de idade (milhares)", m_6463.get("32385", {})), + ( + "Pessoas de 14 anos ou mais de idade, na força de trabalho, na semana de referência (milhares)", + m_6463.get("32386", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência (milhares)", + m_6463.get("32387", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, desocupadas na semana de referência (milhares)", + m_6463.get("32446", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, fora da força de trabalho, na semana de referência (milhares)", + m_6463.get("32447", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência como Empregado no setor privado com carteira de trabalho assinada (milhares)", + m_6464.get("31722", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência como Empregado no setor privado sem carteira de trabalho assinada (milhares)", + m_6464.get("31723", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência como Trabalhador doméstico (milhares)", + m_6464.get("31724", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência como Empregado no setor público (inclusive servidor estatutário e militar) (milhares)", + m_6464.get("31727", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência como Empregador (milhares)", + m_6464.get("96170", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência como Conta-própria (milhares)", + m_6464.get("96171", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência como Trabalhador familiar auxiliar (milhares)", + m_6464.get("31731", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Agricultura, pecuária, produção florestal, pesca e aquicultura (milhares)", + m_6465.get("47947", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Indústria geral (milhares)", + m_6465.get("47948", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Indústria de transformação (milhares)", + {}, + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Construção (milhares)", + m_6465.get("47949", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Comércio, reparação de veículos automotores e motocicletas (milhares)", + m_6465.get("47950", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Transporte, armazenagem e correio (milhares)", + m_6465.get("56622", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Alojamento e alimentação (milhares)", + m_6465.get("56623", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Informação, comunicação e atividades financeiras, imobiliárias, profissionais e administrativas (milhares)", + m_6465.get("56624", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Administração pública, defesa, seguridade social, educação, saúde humana e serviços sociais (milhares)", + m_6465.get("60032", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Outros serviços (milhares)", + m_6465.get("56627", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Serviços Domésticos (milhares)", + m_6465.get("56628", {}), + ), + ( + "Pessoas de 14 anos ou mais de idade, ocupadas na semana de referência no grupamento de atividade Atividades mal definidas (milhares)", + {}, + ), + ] + +# --------------------------------------------------------- +# Panel 3: Average Real Income +# --------------------------------------------------------- + +def get_panel_3_specs( + s_all_usual: Dict[str, Any], + s_all_eff: Dict[str, Any], + m_6471: Dict[str, Dict[str, Any]], + s_main_eff: Dict[str, Any], + m_6473: Dict[str, Dict[str, Any]], +) -> List[Tuple[str, Dict[str, Any]]]: + """Returns indicator specification mappings for Panel 3.""" + return [ + ( + "Rendimento médio real de todos os trabalhos, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho (R$)", + s_all_usual, + ), + ( + "Rendimento médio real de todos os trabalhos, efetivamente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho (R$)", + s_all_eff, + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho (R$)", + m_6471.get("96165", {}), + ), + ( + "Rendimento médio real do trabalho principal, efetivamente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho (R$)", + s_main_eff, + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, como Empregado no setor privado com carteira de trabalho assinada (R$)", + m_6471.get("31722", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, como Empregado no setor privado sem carteira de trabalho assinada (R$)", + m_6471.get("31723", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, como Trabalhador doméstico (R$)", + m_6471.get("31724", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, como Empregado no setor público (inclusive servidor estatutário e militar) (R$)", + m_6471.get("31727", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, como Empregador (R$)", + m_6471.get("96170", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, como Conta-própria (R$)", + m_6471.get("96171", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Agricultura, pecuária, produção florestal, pesca e aquicultura (R$)", + m_6473.get("47947", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Indústria geral (R$)", + m_6473.get("47948", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Indústria de transformação (R$)", + {}, + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Construção (R$)", + m_6473.get("47949", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Comércio, reparação de veículos automotores e motocicletas (R$)", + m_6473.get("47950", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Transporte, armazenagem e correio (R$)", + m_6473.get("56622", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho,no grupamento de atividade Alojamento e alimentação (R$)", + m_6473.get("56623", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Informação, comunicação e atividades financeiras, imobiliárias, profissionais e administrativas (R$)", + m_6473.get("56624", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Administração pública, defesa, seguridade social, educação, saúde humana e serviços sociais (R$)", + m_6473.get("60032", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Outros serviços (R$)", + m_6473.get("56627", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Serviços Domésticos (R$)", + m_6473.get("56628", {}), + ), + ( + "Rendimento médio real do trabalho principal, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho, no grupamento de atividade Atividades mal definidas (R$)", + {}, + ), + ] + +# --------------------------------------------------------- +# Panel 4: Mass Income +# --------------------------------------------------------- + +def get_panel_4_specs( + s_mass_usual: Dict[str, Any], s_mass_eff: Dict[str, Any] +) -> List[Tuple[str, Dict[str, Any]]]: + """Returns indicator specification mappings for Panel 4.""" + return [ + ( + "Massa de rendimento real de todos os trabalhos, habitualmente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho (milhões de R$)", + s_mass_usual, + ), + ( + "Massa de rendimento real de todos os trabalhos, efetivamente recebido por mês, pelas pessoas de 14 anos ou mais de idade, ocupadas na semana de referência, com rendimento de trabalho (milhões de R$)", + s_mass_eff, + ), + ]