"""Validador dos elementos obrigatórios da NOBRADE, por nível. Obrigatórios: 1.1, 1.2, 1.3 (data de produção), 1.4, 1.5, 2.1; 4.1 só nos níveis 0 e 1. Além deles, lista avisos que não reprovam mas pedem revisão. Escreve descricao/pendencias.md e devolve o número de pendências. """ from __future__ import annotations from collections import Counter, defaultdict from .config import SAIDA def verifica(u: dict) -> tuple[list[str], list[str]]: erros, avisos = [], [] n = u['nivel'] if not u.get('1.1'): erros.append('1.1 código de referência ausente') if not (u.get('1.2') or {}).get('titulo', '').strip(): erros.append('1.2 título ausente') prod = (u.get('1.3') or {}).get('producao') or {} if not prod.get('inicio') and not prod.get('fim'): erros.append('1.3 data de produção ausente') if not (u.get('1.4') or {}).get('nome'): erros.append('1.4 nível ausente') if not (u.get('1.5') or {}).get('texto'): erros.append('1.5 dimensão e suporte ausente') if not u.get('2.1'): erros.append('2.1 produtor ausente') if n <= 1 and not u.get('4.1'): erros.append('4.1 condições de acesso ausente (obrigatório nos níveis 0 e 1)') if n == 4: if prod.get('qualidade') == 'atribuída pelo arquivista' or (prod.get('notas') or [''])[0].startswith('data atribuída'): avisos.append('1.3 data atribuída pelo arquivista — conferir') if prod.get('motivo') == 'ilegível': avisos.append('1.3 data da origem ilegível') if all(p.get('id') is None for p in u.get('2.1') or []): avisos.append('2.1 autoria não identificada') if u['id'].split('.')[-2] == 'AV': avisos.append('nível 3 em Avulsos — série de origem não identificada') if any('presumida' in x for x in u.get('6.2') or []): avisos.append('1.5 espécie presumida') if any('corrompidos' in x for x in u.get('6.2') or []): avisos.append('valores corrompidos na origem') if u.get('6.1'): avisos.append('6.1 preservação indisponível na origem') if (u.get('4.2') or {}).get('categoria') == 'consultar o detentor': avisos.append('4.2 condição de reprodução não informada na origem') if not (u.get('3.1') or '').strip(): avisos.append('3.1 sem âmbito e conteúdo') return erros, avisos def valida(unidades) -> int: erros, avisos = defaultdict(list), defaultdict(list) por_nivel = Counter() for u in unidades: por_nivel[u['nivel']] += 1 e, a = verifica(u) for x in e: erros[x].append(u['id']) for x in a: avisos[x].append(u['id']) total = sum(len(v) for v in erros.values()) linhas = ['# Pendências da descrição NOBRADE', '', 'Gerado por `python -m nobrade`. Obrigatórios reprovam; avisos pedem revisão.', '', '| Nível | Unidades |', '|---|--:|'] nomes = {0: 'acervo', 1: 'coleção', 2: 'seção', 3: 'série', 4: 'dossiê', 5: 'item'} linhas += [f'| {n} {nomes[n]} | {c:,} |'.replace(',', '.') for n, c in sorted(por_nivel.items())] linhas += ['', f'## Obrigatórios faltando: {total}', ''] if not erros: linhas.append('Nenhum. Todas as unidades têm os elementos obrigatórios do seu nível.') for k, ids in sorted(erros.items(), key=lambda kv: -len(kv[1])): linhas += [f'### {k} — {len(ids)}', '', *[f'- `{i}`' for i in ids[:50]]] if len(ids) > 50: linhas.append(f'- … e mais {len(ids) - 50}') linhas.append('') linhas += ['', '## Avisos', '', '| Aviso | Dossiês |', '|---|--:|'] linhas += [f'| {k} | {len(v):,} |'.replace(',', '.') for k, v in sorted(avisos.items(), key=lambda kv: -len(kv[1]))] linhas.append('') (SAIDA / 'pendencias.md').write_text('\n'.join(linhas), encoding='utf-8') return total