From e226d6ac6f05fc46e56e0c71b4491abf8e3f57be Mon Sep 17 00:00:00 2001 From: Krishnam Maheshwari Date: Tue, 28 Jul 2026 08:36:24 +0000 Subject: [PATCH 1/8] Download script is changed to add all quarters of data --- .../brazil_download_script.py | 433 ++++++++++-------- 1 file changed, 248 insertions(+), 185 deletions(-) diff --git a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py index ce35215dcf..1b55fd4ad2 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. @@ -13,27 +13,20 @@ # limitations under the License. import os -import re import time -import glob +import requests +import urllib3 +import pandas as pd from absl import app, logging, flags from pathlib import Path -# 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 - +# Suppress SSL InsecureRequestWarning +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # --- Configuration --- -BASE_URL = "https://sidra.ibge.gov.br/home/pnadct/" 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 PANEL_FOLDER_MAP = { 1: "Employment_And_Unemployment_Labor_Force", 2: "Population_Economic_sector", @@ -41,196 +34,266 @@ 4: "Mass_Income" } +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]" +} -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") - - 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 - - # 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 - - # 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)}" - - # 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}'") - 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}") +PERIOD_START = "202201" + +def get_available_periods(): + """ + Fetches available period metadata starting from Q1 2022 to the latest available period. + """ + url = "https://servicodados.ibge.gov.br/api/v3/agregados/6461/periodos" + headers = {"User-Agent": "Mozilla/5.0"} + res = requests.get(url, headers=headers, verify=False, timeout=30) + res.raise_for_status() + periods_data = res.json() + return [p for p in periods_data if p["id"] >= PERIOD_START] +def format_quarter_label(period_item): + """ + Formats period literals to match UI quarter headers (e.g. '1º trimestre 2022'). + """ + for lit in period_item.get("literals", []): + if "trimestre" in lit.lower(): + return lit.lower().replace(" ", " ").strip() + p_id = period_item["id"] + year = p_id[:4] + q = int(p_id[4:]) + return f"{q}º trimestre {year}" -def download_panel(driver, panel_index, place_name): +def fetch_aggregate_series(agg_id, var_id, geo_code, period_query, classif=None): """ - Locates a panel, opens the dropdown, clicks the download button, - and then calls the rename and move function. + Helper function to query IBGE aggregate API endpoint. """ + 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 = requests.get(url, headers=headers, verify=False, timeout=30) + if r.status_code != 200: + return {} + data = r.json() + if not data or "resultados" not in data[0]: + return {} - 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) - - 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 + result_map = {} + for res in data[0]["resultados"]: + cat_key = "Total" + if res.get("classificacoes"): + cats = res["classificacoes"][0].get("categoria", {}) + if cats: + cat_key = list(cats.keys())[0] + for s in res.get("series", []): + serie = s.get("serie", {}) + result_map[cat_key] = serie + return result_map 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"Error fetching agg {agg_id} var {var_id}: {e}") + return {} -def get_url_slug(place_name): +def fetch_panel_data(place_name, geo_code, panel_index, periods): """ - Generates a URL slug from the place name, matching the website's pattern. + Fetches SIDRA data for 2022Q1 to the latest available period and reshapes the output + to match the original homepage UI export configuration. """ - 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)]) + period_ids = [p["id"] for p in periods] + period_labels = [format_quarter_label(p) for p in periods] + period_query = "|".join(period_ids) -def get_place_select_element(driver): - """ - Waits for and returns the Select object for the place dropdown. - """ - 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.") + folder_name = PANEL_FOLDER_MAP[panel_index] + dest_dir = os.path.join(DOWNLOAD_DIR, folder_name) + Path(dest_dir).mkdir(parents=True, exist_ok=True) + + 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 = [] + + 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" + else: + subtitle_row = f"Massa de rendimento - Indicadores selecionados - Últimos {len(periods)} trimestres" + + 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) + + 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 = [ + ("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), + ] + 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)) + + 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 = [ + ("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)", {}), + ] + for name, serie in ind_specs: + vals = [serie.get(pid, '') for pid in period_ids] + rows.append([name] + vals) + + 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 = [ + ("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$)", {}), + ] + for name, serie in ind_specs: + vals = [serie.get(pid, '') for pid in period_ids] + rows.append([name] + vals) + + 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 = [ + ("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), + ] + 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)) + + df_out = pd.DataFrame(rows) + os.makedirs(dest_dir, exist_ok=True) + 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}'") def main(argv): - """Main function to orchestrate the scraping and downloading.""" - del argv # Unused. + 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() - try: - driver.get(BASE_URL) - logging.info(f"Navigated to base URL: {BASE_URL}") - - # Use the new helper function - select = get_place_select_element(driver) - options_text = [option.text.strip() for option in select.options] - - 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}") - - for place_name in options_text: - if not place_name: - continue - - logging.info(f"\n Processing: {place_name}") - - 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.") + + periods = get_available_periods() + logging.info(f"Fetched {len(periods)} available periods starting from {PERIOD_START}: {[p['id'] for p in periods]}") + + for place_name, geo_code in LOCATIONS.items(): + logging.info(f"Processing: {place_name}") + for panel_index in range(1, 5): + fetch_panel_data(place_name, geo_code, panel_index, periods) + time.sleep(0.1) + + logging.info("Script finished successfully.") if __name__ == "__main__": flags.FLAGS.log_dir = SCRIPT_DIR - app.run(main) + app.run(main) \ No newline at end of file From a2c9c282e1f546f2fbf6eb2e47463bf395e562cd Mon Sep 17 00:00:00 2001 From: Krishnam Maheshwari Date: Tue, 28 Jul 2026 12:23:31 +0000 Subject: [PATCH 2/8] Download script is changed to add all quarters of data --- statvar_imports/brazil_sidra_ibge/brazil_download_script.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py index 1b55fd4ad2..9702857781 100644 --- a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py +++ b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py @@ -12,6 +12,12 @@ # 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 time import requests From d1c2e12babef0ccbb8d9a37e3f3137d9ff514571 Mon Sep 17 00:00:00 2001 From: Krishnam24maheshwari Date: Wed, 29 Jul 2026 08:04:37 +0000 Subject: [PATCH 3/8] Fix missing newline at end of brazil_download_script.py Added a newline at the end of the file for proper formatting. --- statvar_imports/brazil_sidra_ibge/brazil_download_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py index 9702857781..f23aa161b3 100644 --- a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py +++ b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py @@ -302,4 +302,4 @@ def main(argv): if __name__ == "__main__": flags.FLAGS.log_dir = SCRIPT_DIR - app.run(main) \ No newline at end of file + app.run(main) From 438f1edcc8bdc0bf11fefe1eb11cbaedc8f2a2a8 Mon Sep 17 00:00:00 2001 From: Krishnam24maheshwari Date: Wed, 29 Jul 2026 14:13:58 +0530 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- statvar_imports/brazil_sidra_ibge/brazil_download_script.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py index f23aa161b3..cc14bfd509 100644 --- a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py +++ b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py @@ -84,7 +84,7 @@ def get_available_periods(): """ url = "https://servicodados.ibge.gov.br/api/v3/agregados/6461/periodos" headers = {"User-Agent": "Mozilla/5.0"} - res = requests.get(url, headers=headers, verify=False, timeout=30) + res = SESSION.get(url, headers=headers, timeout=30) res.raise_for_status() periods_data = res.json() return [p for p in periods_data if p["id"] >= PERIOD_START] @@ -111,11 +111,11 @@ def fetch_aggregate_series(agg_id, var_id, geo_code, period_query, classif=None) headers = {"User-Agent": "Mozilla/5.0"} try: - r = requests.get(url, headers=headers, verify=False, timeout=30) + r = SESSION.get(url, headers=headers, timeout=30) if r.status_code != 200: return {} data = r.json() - if not data or "resultados" not in data[0]: + if not isinstance(data, list) or not data or "resultados" not in data[0]: return {} result_map = {} From 4d7186f2cffab772564f1282b3a6bf3cc283e49a Mon Sep 17 00:00:00 2001 From: Krishnam24maheshwari Date: Wed, 29 Jul 2026 14:26:26 +0530 Subject: [PATCH 5/8] Implement robust session for API requests Added a robust session setup for HTTP requests with retries and connection pooling. Updated functions to utilize the new session for API calls. --- .../brazil_download_script.py | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py index cc14bfd509..b108b2b3cb 100644 --- a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py +++ b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py @@ -21,13 +21,26 @@ import os import time import requests -import urllib3 import pandas as pd from absl import app, logging, flags from pathlib import Path +from requests.adapters import HTTPAdapter +from urllib3.util import Retry -# Suppress SSL InsecureRequestWarning -urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) +# --- Robust Session Setup --- +def get_robust_session() -> requests.Session: + """Configures a global requests Session with retries and connection pooling.""" + 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 + +SESSION = get_robust_session() # --- Configuration --- SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -78,6 +91,7 @@ PERIOD_START = "202201" + def get_available_periods(): """ Fetches available period metadata starting from Q1 2022 to the latest available period. @@ -89,6 +103,7 @@ def get_available_periods(): periods_data = res.json() return [p for p in periods_data if p["id"] >= PERIOD_START] + def format_quarter_label(period_item): """ Formats period literals to match UI quarter headers (e.g. '1º trimestre 2022'). @@ -101,23 +116,26 @@ def format_quarter_label(period_item): q = int(p_id[4:]) return f"{q}º trimestre {year}" + def fetch_aggregate_series(agg_id, var_id, geo_code, period_query, classif=None): """ - Helper function to query IBGE aggregate API endpoint. + Helper function to query IBGE aggregate API endpoint using robust SESSION. """ 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: r = SESSION.get(url, headers=headers, timeout=30) if r.status_code != 200: return {} data = r.json() + + # Guard check to ensure valid list structure returned from API if not isinstance(data, list) or not data or "resultados" not in data[0]: return {} - + result_map = {} for res in data[0]["resultados"]: cat_key = "Total" @@ -133,6 +151,7 @@ def fetch_aggregate_series(agg_id, var_id, geo_code, period_query, classif=None) logging.warning(f"Error fetching agg {agg_id} var {var_id}: {e}") return {} + def fetch_panel_data(place_name, geo_code, panel_index, periods): """ Fetches SIDRA data for 2022Q1 to the latest available period and reshapes the output @@ -145,7 +164,7 @@ def fetch_panel_data(place_name, geo_code, panel_index, periods): folder_name = PANEL_FOLDER_MAP[panel_index] dest_dir = os.path.join(DOWNLOAD_DIR, folder_name) Path(dest_dir).mkdir(parents=True, exist_ok=True) - + 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) @@ -183,7 +202,7 @@ def fetch_panel_data(place_name, geo_code, panel_index, periods): 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)) elif panel_index == 2: @@ -269,7 +288,7 @@ def fetch_panel_data(place_name, geo_code, panel_index, periods): 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)) @@ -281,7 +300,9 @@ def fetch_panel_data(place_name, geo_code, panel_index, periods): logging.info(f"Saved: '{filepath}'") + def main(argv): + """Main function to orchestrate downloading and processing data.""" del argv logging.info("Script started.") @@ -300,6 +321,7 @@ def main(argv): logging.info("Script finished successfully.") + if __name__ == "__main__": flags.FLAGS.log_dir = SCRIPT_DIR - app.run(main) + app.run(main) From d7ee36dd4c4d6c7588e69d7bece02179f8743815 Mon Sep 17 00:00:00 2001 From: Krishnam Maheshwari Date: Mon, 3 Aug 2026 07:47:33 +0000 Subject: [PATCH 6/8] Adding goldens and updated the readme file and downlaod script --- statvar_imports/brazil_sidra_ibge/README.md | 2 +- .../brazil_download_script.py | 477 +++++++++++------- ...olden_observations_average_real_income.csv | 34 ++ ...n_observations_employment_unemployment.csv | 34 ++ .../golden_observations_mass_income.csv | 34 ++ ...olden_observations_population_economic.csv | 34 ++ ...golden_summary_employment_unemployment.csv | 3 + .../golden_summary_mass_income.csv | 3 + .../golden_summary_population_economic.csv | 24 + ...den_summary_report_average_real_income.csv | 21 + .../brazil_sidra_ibge/manifest.json | 3 +- .../brazil_sidra_ibge/validation_config.json | 85 ++++ 12 files changed, 571 insertions(+), 183 deletions(-) create mode 100644 statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_average_real_income.csv create mode 100644 statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_employment_unemployment.csv create mode 100644 statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_mass_income.csv create mode 100644 statvar_imports/brazil_sidra_ibge/golden_data/golden_observations_population_economic.csv create mode 100644 statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_employment_unemployment.csv create mode 100644 statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_mass_income.csv create mode 100644 statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_population_economic.csv create mode 100644 statvar_imports/brazil_sidra_ibge/golden_data/golden_summary_report_average_real_income.csv create mode 100644 statvar_imports/brazil_sidra_ibge/validation_config.json diff --git a/statvar_imports/brazil_sidra_ibge/README.md b/statvar_imports/brazil_sidra_ibge/README.md index 513633fba7..44ff984748 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: 2022-03 to 2026-03 (quaterly 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 b108b2b3cb..81990ec4a8 100644 --- a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py +++ b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py @@ -20,16 +20,21 @@ import os import time -import requests -import pandas as pd -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 # --- Robust Session Setup --- def get_robust_session() -> requests.Session: - """Configures a global requests Session with retries and connection pooling.""" + """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, @@ -40,12 +45,14 @@ def get_robust_session() -> requests.Session: session.mount("https://", HTTPAdapter(max_retries=retries)) return session +# Global session instance SESSION = get_robust_session() -# --- Configuration --- +# --- Configuration Constants --- SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) DOWNLOAD_DIR = os.path.join(SCRIPT_DIR, "input_files") +# Maps panel indices (1 to 4) to their target folder names PANEL_FOLDER_MAP = { 1: "Employment_And_Unemployment_Labor_Force", 2: "Population_Economic_sector", @@ -53,6 +60,7 @@ def get_robust_session() -> requests.Session: 4: "Mass_Income" } +# Mapping of Brazilian location display names to IBGE geo-location codes LOCATIONS = { "Brasil": "N1[1]", "Norte": "N2[1]", @@ -89,37 +97,78 @@ def get_robust_session() -> requests.Session: "Distrito Federal": "N3[53]" } +# The starting quarter code (YYYYQQ) for filtering period metadata PERIOD_START = "202201" -def get_available_periods(): - """ - Fetches available period metadata starting from Q1 2022 to the latest available period. +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"} - res = SESSION.get(url, headers=headers, timeout=30) - res.raise_for_status() - periods_data = res.json() - return [p for p in periods_data if p["id"] >= PERIOD_START] + + try: + 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] + + 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}") + return [] -def format_quarter_label(period_item): - """ - Formats period literals to match UI quarter headers (e.g. '1º trimestre 2022'). - """ - for lit in period_item.get("literals", []): - if "trimestre" in lit.lower(): - return lit.lower().replace(" ", " ").strip() - p_id = period_item["id"] - year = p_id[:4] - q = int(p_id[4:]) - return f"{q}º trimestre {year}" +def format_quarter_label(period_item: Dict[str, Any]) -> str: + """Formats period literals to match UI quarter headers (e.g., '1º trimestre 2022'). -def fetch_aggregate_series(agg_id, var_id, geo_code, period_query, classif=None): + Args: + period_item: A dictionary containing period properties ('id', 'literals'). + + Returns: + str: Formatted string header for the quarter. """ - Helper function to query IBGE aggregate API endpoint using robust SESSION. + 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() + + # 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.warning(f"Failed to format quarter label for {period_item}: {e}") + return str(period_item.get("id", "Unknown Period")) + + +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: @@ -128,200 +177,266 @@ def fetch_aggregate_series(agg_id, var_id, geo_code, period_query, classif=None) headers = {"User-Agent": "Mozilla/5.0"} try: r = SESSION.get(url, headers=headers, timeout=30) + + # 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() # 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.warning(f"Error fetching agg {agg_id} var {var_id}: {e}") - return {} + logging.warning(f"Unexpected error fetching Agg {agg_id}, Var {var_id}: {e}") + return {} -def fetch_panel_data(place_name, geo_code, panel_index, periods): - """ - Fetches SIDRA data for 2022Q1 to the latest available period and reshapes the output - to match the original homepage UI export configuration. + +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. """ - 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) - Path(dest_dir).mkdir(parents=True, exist_ok=True) - - 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 = [] - - 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" - else: - subtitle_row = f"Massa de rendimento - Indicadores selecionados - Últimos {len(periods)} trimestres" - - 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) - - 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 = [ - ("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), - ] - 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)) - - 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 = [ - ("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)", {}), - ] - for name, serie in ind_specs: - vals = [serie.get(pid, '') for pid in period_ids] - rows.append([name] + vals) - - 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 = [ - ("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$)", {}), - ] - for name, serie in ind_specs: - vals = [serie.get(pid, '') for pid in period_ids] - rows.append([name] + vals) - - 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 = [ - ("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), - ] - 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)) - - df_out = pd.DataFrame(rows) - os.makedirs(dest_dir, exist_ok=True) - 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}'") + try: + 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" + else: + 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 = [ + ("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), + ] + 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 = [ + ("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)", {}), + ] + 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 = [ + ("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$)", {}), + ] + 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 = [ + ("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), + ] + 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 downloading and processing data.""" + """Main execution function to orchestrate downloading and processing data.""" del argv logging.info("Script started.") - 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) - + # Safely create input base directory structure + try: + 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 + + # 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(f"Fetched {len(periods)} available periods starting from {PERIOD_START}: {[p['id'] for p in periods]}") + # 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): - fetch_panel_data(place_name, geo_code, panel_index, periods) + 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}") + + # Short pause to reduce load on the IBGE REST API time.sleep(0.1) logging.info("Script finished successfully.") 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..cb2558f15b 100644 --- a/statvar_imports/brazil_sidra_ibge/manifest.json +++ b/statvar_imports/brazil_sidra_ibge/manifest.json @@ -38,7 +38,8 @@ "input_files/Population_Economic_sector/*.xlsx", "input_files/Employment_And_Unemployment_Labor_Force/*.xlsx" ], - "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 From 6e6a622d072f7666c1f6e78b1fbbe5a9937fd130 Mon Sep 17 00:00:00 2001 From: Krishnam Maheshwari Date: Mon, 3 Aug 2026 10:39:20 +0000 Subject: [PATCH 7/8] Modifications in downlaod and readme file and new vars.py file is added --- statvar_imports/brazil_sidra_ibge/README.md | 2 +- .../brazil_download_script.py | 112 +------ statvar_imports/brazil_sidra_ibge/vars.py | 311 ++++++++++++++++++ 3 files changed, 325 insertions(+), 100 deletions(-) create mode 100644 statvar_imports/brazil_sidra_ibge/vars.py diff --git a/statvar_imports/brazil_sidra_ibge/README.md b/statvar_imports/brazil_sidra_ibge/README.md index 44ff984748..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-03 to 2026-03 (quaterly data is added every 3 months). +- 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 81990ec4a8..864d22b306 100644 --- a/statvar_imports/brazil_sidra_ibge/brazil_download_script.py +++ b/statvar_imports/brazil_sidra_ibge/brazil_download_script.py @@ -29,6 +29,14 @@ 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, +) + # --- Robust Session Setup --- def get_robust_session() -> requests.Session: """Configures a global requests Session with automated retries and connection pooling. @@ -60,43 +68,6 @@ def get_robust_session() -> requests.Session: 4: "Mass_Income" } -# 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]" -} - # The starting quarter code (YYYYQQ) for filtering period metadata PERIOD_START = "202201" @@ -254,7 +225,7 @@ def fetch_panel_data(place_name: str, geo_code: str, panel_index: int, periods: 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" - else: + elif panel_index == 4: subtitle_row = f"Massa de rendimento - Indicadores selecionados - Últimos {len(periods)} trimestres" # Build table metadata header block @@ -273,12 +244,7 @@ def fetch_panel_data(place_name: str, geo_code: str, panel_index: int, periods: 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 = [ - ("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), - ] + 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) @@ -294,33 +260,7 @@ def fetch_panel_data(place_name: str, geo_code: str, panel_index: int, periods: 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 = [ - ("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)", {}), - ] + 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) @@ -335,30 +275,7 @@ def fetch_panel_data(place_name: str, geo_code: str, panel_index: int, periods: 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 = [ - ("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$)", {}), - ] + 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) @@ -370,10 +287,7 @@ def fetch_panel_data(place_name: str, geo_code: str, panel_index: int, periods: 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 = [ - ("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), - ] + 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) 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, + ), + ] From c56efe0a842451c7b4896494ce6f39600af4a961 Mon Sep 17 00:00:00 2001 From: Krishnam Maheshwari Date: Mon, 3 Aug 2026 11:55:48 +0000 Subject: [PATCH 8/8] counters path argument is added to the statvar command --- statvar_imports/brazil_sidra_ibge/manifest.json | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/statvar_imports/brazil_sidra_ibge/manifest.json b/statvar_imports/brazil_sidra_ibge/manifest.json index cb2558f15b..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,7 +36,9 @@ "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 * *", "validation_config_file": "validation_config.json"