From a1db3e57cee438c00c3b719fdfa4c8f60fb984fc Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 19 Jan 2026 00:43:04 +0000 Subject: [PATCH] Add Streamlit CEP search app with robust validation - Implemented CEPValidator class with comprehensive validation - Sanitizes input (removes non-numeric characters) - Validates 8-digit format - Detects invalid CEPs (all same digits) - Formats CEP in XXXXX-XXX pattern - Integrated ViaCEPAPI with automatic retry system - Up to 3 retry attempts on network failures - Configurable 10-second timeout - Comprehensive error handling (timeout, connection, HTTP errors) - Created intuitive Streamlit interface - Responsive layout with visual feedback - Sidebar with examples and documentation - Formatted address display in columns - User-friendly error messages - Added test suite for CEP validation - 13 test cases covering valid and invalid scenarios - All tests passing - Included complete documentation (README.md, SKILL.md) - Added .gitignore and requirements.txt --- cep-search-app/.gitignore | 40 +++++ cep-search-app/README.md | 178 ++++++++++++++++++++ cep-search-app/SKILL.md | 90 +++++++++++ cep-search-app/app.py | 260 ++++++++++++++++++++++++++++++ cep-search-app/requirements.txt | 2 + cep-search-app/test_validation.py | 107 ++++++++++++ 6 files changed, 677 insertions(+) create mode 100644 cep-search-app/.gitignore create mode 100644 cep-search-app/README.md create mode 100644 cep-search-app/SKILL.md create mode 100644 cep-search-app/app.py create mode 100644 cep-search-app/requirements.txt create mode 100644 cep-search-app/test_validation.py diff --git a/cep-search-app/.gitignore b/cep-search-app/.gitignore new file mode 100644 index 00000000..1716bfe7 --- /dev/null +++ b/cep-search-app/.gitignore @@ -0,0 +1,40 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual Environment +venv/ +env/ +ENV/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Streamlit +.streamlit/ diff --git a/cep-search-app/README.md b/cep-search-app/README.md new file mode 100644 index 00000000..756d3d89 --- /dev/null +++ b/cep-search-app/README.md @@ -0,0 +1,178 @@ +# 📮 App Streamlit de Busca de CEP + +Um aplicativo web profissional desenvolvido com Streamlit para buscar informações de endereço através do CEP brasileiro, com validação robusta e integração com a API ViaCEP. + +![Python](https://img.shields.io/badge/Python-3.8+-blue.svg) +![Streamlit](https://img.shields.io/badge/Streamlit-1.31+-red.svg) +![License](https://img.shields.io/badge/License-MIT-green.svg) + +## ✨ Recursos + +- ✅ **Validação Robusta de CEP** + - Valida formato (8 dígitos) + - Remove caracteres especiais automaticamente + - Detecta CEPs inválidos + - Aceita formato com ou sem hífen + +- 🔄 **Sistema de Retry Automático** + - Até 3 tentativas em caso de falha + - Timeout configurável (10 segundos) + - Tratamento de erros de conexão + +- 📊 **Interface Intuitiva** + - Layout responsivo e moderno + - Feedback visual em tempo real + - Exemplos integrados na sidebar + - Mensagens de erro amigáveis + +- 🚀 **Integração com ViaCEP** + - API pública brasileira + - Dados completos de endereço + - Informações de IBGE, DDD, GIA e SIAFI + +## 🚀 Início Rápido + +### Pré-requisitos + +- Python 3.8 ou superior +- pip (gerenciador de pacotes Python) + +### Instalação + +1. Clone o repositório ou baixe os arquivos + +2. Instale as dependências: +```bash +pip install -r requirements.txt +``` + +### Executar o Aplicativo + +```bash +streamlit run app.py +``` + +O aplicativo será aberto automaticamente no navegador em `http://localhost:8501` + +## 📖 Como Usar + +1. **Digite um CEP** no campo de entrada + - Formatos aceitos: `12345-678` ou `12345678` + +2. **Clique em "Buscar"** para consultar o endereço + +3. **Visualize os resultados** organizados em colunas: + - Informações do endereço (logradouro, complemento, bairro) + - Localização (cidade, estado, códigos) + +4. **Use "Limpar"** para fazer uma nova busca + +## 🎯 Exemplos de CEPs Válidos + +| CEP | Endereço | +|-----|----------| +| `01310-100` | Av. Paulista - São Paulo/SP | +| `20040-020` | Centro - Rio de Janeiro/RJ | +| `30130-010` | Centro - Belo Horizonte/MG | +| `40020-000` | Centro - Salvador/BA | +| `80010-000` | Centro - Curitiba/PR | + +## 🏗️ Arquitetura + +### Classes Principais + +#### `CEPValidator` +Responsável pela validação e formatação de CEP: +- `sanitize_cep()`: Remove caracteres não numéricos +- `validate_format()`: Valida formato do CEP +- `format_cep()`: Formata CEP no padrão XXXXX-XXX + +#### `ViaCEPAPI` +Gerencia a integração com a API ViaCEP: +- `search_cep()`: Busca informações do endereço +- Sistema de retry automático +- Tratamento completo de erros + +### Validações Implementadas + +```python +✅ CEP com 8 dígitos +✅ Apenas números após sanitização +✅ Rejeita CEPs com todos dígitos iguais +✅ Aceita formatos: XXXXX-XXX ou XXXXXXXX +``` + +### Tratamento de Erros + +- ⏱️ **Timeout**: Mensagem amigável após timeout de conexão +- 🔌 **Conexão**: Detecção de problemas de rede +- ❌ **HTTP**: Tratamento de erros de status HTTP +- ⚠️ **CEP não encontrado**: Validação de existência do CEP +- 🔧 **Formato inválido**: Validação antes da consulta + +## 📊 Dados Retornados + +O aplicativo exibe as seguintes informações quando o CEP é encontrado: + +- **CEP**: Código postal formatado +- **Logradouro**: Nome da rua/avenida +- **Complemento**: Informações adicionais +- **Bairro**: Nome do bairro +- **Cidade**: Nome da cidade (localidade) +- **Estado**: UF (sigla do estado) +- **IBGE**: Código do município +- **DDD**: Código de área telefônico +- **GIA**: Guia de Informação e Apuração (SP) +- **SIAFI**: Sistema Integrado de Administração Financeira + +## 🛠️ Tecnologias + +- **[Streamlit](https://streamlit.io/)** - Framework para aplicativos web em Python +- **[Requests](https://requests.readthedocs.io/)** - Biblioteca HTTP para Python +- **[ViaCEP](https://viacep.com.br/)** - API pública de consulta de CEP + +## 📝 Estrutura de Arquivos + +``` +cep-search-app/ +├── app.py # Aplicativo principal +├── requirements.txt # Dependências do projeto +├── SKILL.md # Documentação da skill +└── README.md # Este arquivo +``` + +## 🔒 Segurança + +- Validação de entrada antes de fazer requisições +- Sanitização de dados do usuário +- Timeout para evitar travamentos +- Tratamento seguro de exceções + +## 🤝 Contribuindo + +Contribuições são bem-vindas! Sinta-se à vontade para: +- Reportar bugs +- Sugerir novas funcionalidades +- Enviar pull requests + +## 📄 Licença + +Este projeto está sob a licença MIT. + +## 🙏 Créditos + +- Dados fornecidos pela API [ViaCEP](https://viacep.com.br/) +- Desenvolvido com [Streamlit](https://streamlit.io/) + +## 📞 Suporte + +Se encontrar algum problema ou tiver dúvidas: +1. Verifique se o CEP está correto +2. Confirme sua conexão com a internet +3. Verifique se as dependências estão instaladas corretamente + +--- + +
+Desenvolvido com ❤️ usando Streamlit +
diff --git a/cep-search-app/SKILL.md b/cep-search-app/SKILL.md new file mode 100644 index 00000000..6a3fcdeb --- /dev/null +++ b/cep-search-app/SKILL.md @@ -0,0 +1,90 @@ +--- +name: cep-search-app +description: App Streamlit de busca de CEP com validação robusta e integração com ViaCEP. Use quando precisar criar ou modificar aplicativos de busca de endereço por CEP brasileiro. +--- + +# App Streamlit de Busca de CEP + +Este é um aplicativo Streamlit profissional para busca de informações de endereço através do CEP brasileiro, com validação robusta e integração com a API ViaCEP. + +## Recursos + +- **Validação Robusta**: Valida formato do CEP, remove caracteres especiais e detecta CEPs inválidos +- **Integração com ViaCEP**: Busca automática de endereços através da API ViaCEP +- **Retry Automático**: Sistema de retry com até 3 tentativas em caso de falha de rede +- **Tratamento de Erros**: Tratamento completo de erros com mensagens amigáveis +- **Interface Intuitiva**: Layout responsivo com feedback visual para o usuário +- **Exemplos Integrados**: Sidebar com exemplos de CEPs válidos + +## Como Usar + +### Instalação + +```bash +pip install -r requirements.txt +``` + +### Executar o Aplicativo + +```bash +streamlit run app.py +``` + +O aplicativo será aberto automaticamente no navegador em `http://localhost:8501` + +## Funcionalidades + +### Validação de CEP + +O aplicativo valida: +- Formato do CEP (8 dígitos) +- Remove automaticamente caracteres não numéricos +- Detecta CEPs inválidos (ex: 00000000) +- Aceita formato com ou sem hífen (XXXXX-XXX ou XXXXXXXX) + +### Busca de Endereço + +Retorna informações completas: +- CEP formatado +- Logradouro +- Complemento +- Bairro +- Cidade +- Estado (UF) +- Código IBGE +- DDD +- GIA (se disponível) +- SIAFI (se disponível) + +### Tratamento de Erros + +- Timeout de conexão +- Erros de rede +- CEP não encontrado +- Validação de formato +- Mensagens de erro amigáveis + +## Estrutura do Código + +- `CEPValidator`: Classe para validação e formatação de CEP +- `ViaCEPAPI`: Classe para integração com a API ViaCEP +- `display_address()`: Função para exibir informações formatadas +- `main()`: Função principal do aplicativo + +## Tecnologias Utilizadas + +- **Streamlit**: Framework para criação de aplicativos web +- **Requests**: Biblioteca para requisições HTTP +- **ViaCEP API**: API pública brasileira de consulta de CEP + +## Exemplos de CEPs Válidos + +- `01310-100` - Av. Paulista, São Paulo/SP +- `20040-020` - Centro, Rio de Janeiro/RJ +- `30130-010` - Centro, Belo Horizonte/MG +- `40020-000` - Centro, Salvador/BA +- `80010-000` - Centro, Curitiba/PR + +## Créditos + +Dados fornecidos por [ViaCEP](https://viacep.com.br/) diff --git a/cep-search-app/app.py b/cep-search-app/app.py new file mode 100644 index 00000000..f4f7c541 --- /dev/null +++ b/cep-search-app/app.py @@ -0,0 +1,260 @@ +""" +App Streamlit de Busca de CEP +Aplicativo para buscar informações de endereço através do CEP brasileiro +com validação robusta e integração com a API ViaCEP. +""" + +import streamlit as st +import requests +import re +from typing import Optional, Dict, Any +import time + + +class CEPValidator: + """Classe para validação de CEP brasileiro.""" + + @staticmethod + def sanitize_cep(cep: str) -> str: + """ + Remove caracteres não numéricos do CEP. + + Args: + cep: String do CEP a ser sanitizado + + Returns: + CEP contendo apenas dígitos + """ + return re.sub(r'\D', '', cep) + + @staticmethod + def validate_format(cep: str) -> bool: + """ + Valida o formato do CEP. + + Args: + cep: String do CEP a ser validado + + Returns: + True se o formato é válido, False caso contrário + """ + # Remove caracteres não numéricos + clean_cep = CEPValidator.sanitize_cep(cep) + + # CEP deve ter exatamente 8 dígitos + if len(clean_cep) != 8: + return False + + # Verifica se contém apenas dígitos + if not clean_cep.isdigit(): + return False + + # Verifica se não é um CEP inválido (todos os dígitos iguais) + if len(set(clean_cep)) == 1: + return False + + return True + + @staticmethod + def format_cep(cep: str) -> str: + """ + Formata o CEP no padrão XXXXX-XXX. + + Args: + cep: String do CEP a ser formatado + + Returns: + CEP formatado + """ + clean_cep = CEPValidator.sanitize_cep(cep) + return f"{clean_cep[:5]}-{clean_cep[5:]}" + + +class ViaCEPAPI: + """Classe para interação com a API ViaCEP.""" + + BASE_URL = "https://viacep.com.br/ws" + TIMEOUT = 10 + MAX_RETRIES = 3 + + @staticmethod + def search_cep(cep: str) -> Optional[Dict[str, Any]]: + """ + Busca informações de endereço através do CEP. + + Args: + cep: String do CEP a ser buscado + + Returns: + Dicionário com informações do endereço ou None em caso de erro + """ + clean_cep = CEPValidator.sanitize_cep(cep) + url = f"{ViaCEPAPI.BASE_URL}/{clean_cep}/json/" + + for attempt in range(ViaCEPAPI.MAX_RETRIES): + try: + response = requests.get(url, timeout=ViaCEPAPI.TIMEOUT) + response.raise_for_status() + + data = response.json() + + # ViaCEP retorna {"erro": true} quando o CEP não existe + if data.get("erro"): + return None + + return data + + except requests.exceptions.Timeout: + if attempt < ViaCEPAPI.MAX_RETRIES - 1: + time.sleep(1) + continue + st.error("⏱️ Tempo de espera excedido. Tente novamente.") + return None + + except requests.exceptions.ConnectionError: + if attempt < ViaCEPAPI.MAX_RETRIES - 1: + time.sleep(1) + continue + st.error("🔌 Erro de conexão. Verifique sua internet.") + return None + + except requests.exceptions.HTTPError as e: + st.error(f"❌ Erro HTTP: {e}") + return None + + except requests.exceptions.RequestException as e: + st.error(f"❌ Erro na requisição: {e}") + return None + + except ValueError: + st.error("❌ Erro ao processar resposta da API.") + return None + + return None + + +def display_address(data: Dict[str, Any]) -> None: + """ + Exibe as informações de endereço formatadas. + + Args: + data: Dicionário com informações do endereço + """ + st.success("✅ CEP encontrado!") + + # Criar colunas para melhor visualização + col1, col2 = st.columns(2) + + with col1: + st.markdown("### 📍 Informações do Endereço") + st.markdown(f"**CEP:** {data.get('cep', 'N/A')}") + st.markdown(f"**Logradouro:** {data.get('logradouro', 'N/A')}") + st.markdown(f"**Complemento:** {data.get('complemento', 'N/A')}") + st.markdown(f"**Bairro:** {data.get('bairro', 'N/A')}") + + with col2: + st.markdown("### 🏙️ Localização") + st.markdown(f"**Cidade:** {data.get('localidade', 'N/A')}") + st.markdown(f"**Estado:** {data.get('uf', 'N/A')}") + st.markdown(f"**IBGE:** {data.get('ibge', 'N/A')}") + st.markdown(f"**DDD:** {data.get('ddd', 'N/A')}") + + # Informações adicionais se disponíveis + if data.get('gia'): + st.markdown(f"**GIA:** {data.get('gia')}") + + if data.get('siafi'): + st.markdown(f"**SIAFI:** {data.get('siafi')}") + + +def main(): + """Função principal do aplicativo.""" + + # Configuração da página + st.set_page_config( + page_title="Busca de CEP", + page_icon="📮", + layout="centered", + initial_sidebar_state="collapsed" + ) + + # Título e descrição + st.title("📮 Busca de CEP") + st.markdown(""" + Busque informações de endereço através do CEP brasileiro. + Digite um CEP válido no formato **XXXXX-XXX** ou **XXXXXXXX**. + """) + + # Sidebar com informações + with st.sidebar: + st.header("ℹ️ Sobre") + st.markdown(""" + Este aplicativo permite buscar informações de endereço através do CEP. + + **Recursos:** + - ✅ Validação robusta de CEP + - 🔄 Retry automático em caso de falha + - 📊 Interface intuitiva + - 🚀 Integração com ViaCEP + + **Formato aceito:** + - 12345-678 + - 12345678 + """) + + st.header("📋 Exemplos") + st.code("01310-100 # Av. Paulista, SP") + st.code("20040-020 # Centro, RJ") + st.code("30130-010 # Centro, BH") + + # Formulário de busca + with st.form(key="cep_form", clear_on_submit=False): + cep_input = st.text_input( + "Digite o CEP:", + max_chars=9, + placeholder="Ex: 01310-100", + help="Digite o CEP com ou sem hífen" + ) + + col1, col2, col3 = st.columns([1, 1, 2]) + with col1: + search_button = st.form_submit_button("🔍 Buscar", use_container_width=True) + with col2: + clear_button = st.form_submit_button("🗑️ Limpar", use_container_width=True) + + # Processar busca + if search_button and cep_input: + # Validar formato + if not CEPValidator.validate_format(cep_input): + st.error("❌ CEP inválido! Digite um CEP válido com 8 dígitos.") + st.info("💡 Exemplos válidos: 01310-100, 01310100") + else: + # Mostrar CEP formatado + formatted_cep = CEPValidator.format_cep(cep_input) + st.info(f"🔎 Buscando informações para o CEP: **{formatted_cep}**") + + # Buscar na API + with st.spinner("Consultando API..."): + result = ViaCEPAPI.search_cep(cep_input) + + # Exibir resultado + if result: + display_address(result) + else: + st.warning("⚠️ CEP não encontrado. Verifique se o CEP está correto.") + + elif search_button and not cep_input: + st.warning("⚠️ Por favor, digite um CEP para buscar.") + + # Rodapé + st.markdown("---") + st.markdown( + "
" + "Desenvolvido com Streamlit | Dados fornecidos por ViaCEP" + "
", + unsafe_allow_html=True + ) + + +if __name__ == "__main__": + main() diff --git a/cep-search-app/requirements.txt b/cep-search-app/requirements.txt new file mode 100644 index 00000000..e341d0a2 --- /dev/null +++ b/cep-search-app/requirements.txt @@ -0,0 +1,2 @@ +streamlit>=1.31.0 +requests>=2.31.0 diff --git a/cep-search-app/test_validation.py b/cep-search-app/test_validation.py new file mode 100644 index 00000000..963ba218 --- /dev/null +++ b/cep-search-app/test_validation.py @@ -0,0 +1,107 @@ +""" +Script de teste para validação de CEP +Demonstra as funcionalidades de validação implementadas +""" + +import sys +import os + +# Adiciona o diretório ao path para importar as classes +sys.path.insert(0, os.path.dirname(__file__)) + +# Importa apenas as classes necessárias para teste sem rodar o Streamlit +import re +from typing import Optional + + +class CEPValidator: + """Classe para validação de CEP brasileiro.""" + + @staticmethod + def sanitize_cep(cep: str) -> str: + """Remove caracteres não numéricos do CEP.""" + return re.sub(r'\D', '', cep) + + @staticmethod + def validate_format(cep: str) -> bool: + """Valida o formato do CEP.""" + clean_cep = CEPValidator.sanitize_cep(cep) + + if len(clean_cep) != 8: + return False + + if not clean_cep.isdigit(): + return False + + if len(set(clean_cep)) == 1: + return False + + return True + + @staticmethod + def format_cep(cep: str) -> str: + """Formata o CEP no padrão XXXXX-XXX.""" + clean_cep = CEPValidator.sanitize_cep(cep) + return f"{clean_cep[:5]}-{clean_cep[5:]}" + + +def test_cep_validation(): + """Testa a validação de CEP com vários casos.""" + + test_cases = [ + # (CEP de entrada, esperado válido, descrição) + ("01310-100", True, "CEP válido com hífen"), + ("01310100", True, "CEP válido sem hífen"), + ("12345-678", True, "CEP válido formato padrão"), + ("12345678", True, "CEP válido 8 dígitos"), + ("1234567", False, "CEP com 7 dígitos"), + ("123456789", False, "CEP com 9 dígitos"), + ("00000000", False, "CEP com todos dígitos iguais"), + ("11111-111", False, "CEP com todos dígitos iguais"), + ("abcd-efgh", False, "CEP com letras"), + ("", False, "CEP vazio"), + ("12345", False, "CEP muito curto"), + ("20040-020", True, "CEP Rio de Janeiro"), + ("30130-010", True, "CEP Belo Horizonte"), + ] + + print("=" * 70) + print("TESTE DE VALIDAÇÃO DE CEP") + print("=" * 70) + print() + + passed = 0 + failed = 0 + + for cep, expected_valid, description in test_cases: + is_valid = CEPValidator.validate_format(cep) + status = "✅ PASSOU" if is_valid == expected_valid else "❌ FALHOU" + + if is_valid == expected_valid: + passed += 1 + else: + failed += 1 + + print(f"{status} | {description}") + print(f" Entrada: '{cep}'") + print(f" Esperado: {'Válido' if expected_valid else 'Inválido'}") + print(f" Resultado: {'Válido' if is_valid else 'Inválido'}") + + if is_valid: + formatted = CEPValidator.format_cep(cep) + sanitized = CEPValidator.sanitize_cep(cep) + print(f" Sanitizado: '{sanitized}'") + print(f" Formatado: '{formatted}'") + + print() + + print("=" * 70) + print(f"RESULTADO FINAL: {passed} passou, {failed} falhou de {len(test_cases)} testes") + print("=" * 70) + + return failed == 0 + + +if __name__ == "__main__": + success = test_cep_validation() + sys.exit(0 if success else 1)