separador-rreo
Biblioteca e CLI em Python para separar anexos RREO publicados em diários oficiais da FEMURN (Federação dos Municípios do Rio Grande do Norte).
A partir de um PDF do diário com texto selecionável, o pacote:
- Localiza cabeçalhos
PREFEITURA MUNICIPAL DE … - Reconhece títulos de anexos RREO (padrões observados em publicações como Angicos, Bodó e Coronel João Pessoa)
- Recorta cada anexo em PDF individual por município
- Gera a planilha
Controle_Publicacoes.xlsxpara conferência manual - Empacota tudo em um
.zip
Instalação
pip install separador-rreo
Em desenvolvimento (clone local):
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Uso pela linha de comando
separador-rreo diario.pdf --municipios "Bodó" "Coronel João Pessoa" "Angicos"
Opções:
| Opção | Descrição |
|---|---|
pdf |
Caminho do diário FEMURN (obrigatório se houver mais de um PDF na pasta) |
--municipios |
Um ou mais nomes de municípios |
--saida |
Pasta de saída (padrão: RREO_separados) |
--version |
Mostra a versão |
Sem argumentos, o comando pergunta interativamente pelo PDF e pelos municípios:
separador-rreo
Também é possível executar como módulo:
python -m separador_rreo diario.pdf --municipios "Bodó"
Saída gerada
RREO_separados/
├── BODO/
│ ├── RREO_01_BODO.pdf
│ ├── RREO_03_BODO.pdf
│ └── …
├── Controle_Publicacoes.xlsx
RREO_separados.zip
A coluna Situacao da planilha indica:
Encontrado— recorte delimitado pelo código identificadorVerificar limite final— código ausente; vale conferência manualNao localizado— anexo não encontrado para aquele município- variações com
partes reunidas/multiplas publicacoesquando há fusão ou mais de uma publicação
Uso como biblioteca
Separação completa
from separador_rreo import separar_rreo
resultado = separar_rreo(
"diario.pdf",
municipios=["Bodó", "Angicos"],
destino="saida_rreo",
)
print(resultado.quantidade_pdfs)
print(resultado.planilha)
print(resultado.arquivo_zip)
Análise e exportação separadas
from separador_rreo import SeparadorRreo
separador = SeparadorRreo()
analise, exportacao = separador.executar(
"diario.pdf",
municipios=["Bodó"],
destino="saida_rreo",
)
for ocorrencia in analise.do_municipio("Bodó"):
print(
ocorrencia.anexo,
ocorrencia.pagina_inicial,
ocorrencia.pagina_final,
ocorrencia.situacao.value,
)
Tipos do domínio
Os anexos e as situações são representados por enums. Isso reduz erros de digitação e facilita comparações:
from separador_rreo import AnexoRreo, SituacaoOcorrencia
if ocorrencia.anexo is AnexoRreo.BALANCO_ORCAMENTARIO:
print("Balanço orçamentário localizado")
if ocorrencia.situacao is SituacaoOcorrencia.VERIFICAR_LIMITE_FINAL:
print("É necessário conferir manualmente o fim do recorte")
Ensinar um título novo ao reconhecedor
O pacote já conhece vários jeitos de um anexo RREO aparecer no diário
(por exemplo ANEXO 01_RREO ou RREO - 4º BIM - BALANÇO ORÇAMENTÁRIO).
Se um município publicar com um texto de título diferente, o pacote pode
não achar esse anexo. Nesse caso você pode passar uma função pequena que
olha cada linha do PDF e devolve o número do anexo (ou None se a linha
não for um título):
from separador_rreo import (
AnalisadorRreo,
AnexoRreo,
ReconhecedorTituloRreo,
SeparadorRreo,
)
def reconhecer_titulo_do_meu_municipio(linha: str) -> int | None:
# Exemplo: se a linha for um título do Anexo 9, retorne 9
if "DEMONSTRATIVO X DO ANEXO 9" in linha.upper():
return AnexoRreo.RECEITAS_OPERACOES_CREDITO
return None
reconhecedor = ReconhecedorTituloRreo(
regras_adicionais=[reconhecer_titulo_do_meu_municipio]
)
separador = SeparadorRreo(
analisador=AnalisadorRreo(reconhecedor=reconhecedor)
)
analise, exportacao = separador.executar(
"diario.pdf", ["Meu Município"], "saida_rreo"
)
As regras adicionais são executadas junto com as regras já fornecidas pelo pacote. Assim você amplia o reconhecimento sem alterar o código interno.
Organização do código
analisador.pylocaliza municípios, títulos e limites dos anexos;reconhecimento.pycontém as regras de reconhecimento de títulos;exportacao.pycoordena a geração dos artefatos;planilha.py,compactacao.pyeagrupamento.pycuidam de tarefas específicas;documento_pdf.pyisola a dependência do PyMuPDF;contratos.py,modelos.pyeenumeracoes.pydefinem os contratos e o domínio.
Requisitos
- Python 3.10+
- Dependências:
pymupdf,openpyxl - PDF com texto selecionável (OCR prévio se o diário for só imagem)
Testes
pytest
ruff check src tests
Há um diário de exemplo em tests/fixtures/publicado_117684.pdf usado no teste de integração.
Autores
- Ana Cláudia Medeiros de Carvalho — anaclaudiaengmat@gmail.com
- Yuri Henrique Sales da Costa — yuri.sales@protonmail.com
Licença
MIT — veja LICENSE.
Metadata
Release files for separador-rreo 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| separador_rreo-0.2.0.tar.gz | 13.4 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| separador_rreo-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.4 MB
Release files / separador_rreo-0.2.0.tar.gz
| Download URL | separador_rreo-0.2.0.tar.gz |
|---|---|
| Size | 13.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bfd0babcc98a22e3b9743d2bcf66750071dceb3934e6a7d38bfa0717de139bdf
|
|
BLAKE2b-256 checksum How to use checksums |
9f11b2cea877183a0b856a932b3750e196ea6ac12679cc79f71c57b46ca9df2c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / separador_rreo-0.2.0-py3-none-any.whl
| Download URL | separador_rreo-0.2.0-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b0de688e47b620849488164e9e76b5dc09f9ea10abe951db31fe7c434f225ff0
|
|
BLAKE2b-256 checksum How to use checksums |
034548a651c8b3744020ae711a2b7d92f4f277c86781fc7d1bef1464ecfdb2a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|