bncc 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
bncc-0.1.0/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ node_modules/
2
+ dist/
3
+ __pycache__/
4
+ *.pyc
5
+ .venv/
6
+ .DS_Store
7
+ python/dist/
8
+ python/.venv/
9
+ site/dist/
10
+ site/.astro/
bncc-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: bncc
3
+ Version: 0.1.0
4
+ Summary: A BNCC (Base Nacional Comum Curricular) como dados estruturados e verificados, com API de consulta em português. Dados embutidos, zero dependências, zero rede.
5
+ Project-URL: Homepage, https://github.com/bncc-dev/bncc-pacotes
6
+ Project-URL: Dados, https://github.com/bncc-dev/bncc-dados
7
+ Author-email: "bncc.dev (Profy)" <marcos@profy.com.br>
8
+ License-Expression: MIT
9
+ Keywords: base nacional comum curricular,bncc,brasil,curriculo,educacao,habilidades,mec
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: Natural Language :: Portuguese (Brazilian)
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Education
16
+ Requires-Python: >=3.10
17
+ Provides-Extra: pandas
18
+ Requires-Dist: pandas>=2; extra == 'pandas'
19
+ Description-Content-Type: text/markdown
20
+
21
+ # bncc
22
+
23
+ A BNCC (Base Nacional Comum Curricular) como dados estruturados e verificados, com API de consulta em português. Dados embutidos, zero dependências, zero rede.
24
+
25
+ Cada registro é rastreável à fonte oficial (planilha do MEC + página do PDF homologado). Fonte dos dados: [bncc-dados](https://github.com/bncc-dev/bncc-dados), extração reprodutível com validação em CI. Paridade com o pacote npm [@bncc/dados](https://www.npmjs.com/package/@bncc/dados) provada por consultas douradas compartilhadas.
26
+
27
+ **Pré-release.** A versão 1.0 sai junto da release `dados-v1.0.0` do bncc-dados, após o registro da revisão pedagógica.
28
+
29
+ ## Uso
30
+
31
+ ```python
32
+ import bncc
33
+
34
+ # registro completo, com nomes resolvidos e fonte oficial
35
+ h = bncc.por_codigo('EF67LP08')
36
+ h['texto'] # enunciado oficial verificado
37
+ h['organizacao']['nomes']['pratica_linguagem'] # 'Leitura'
38
+ h['fonte']['localizador_pdf'] # 'Base-Nacional-...pdf, página PDF 167'
39
+
40
+ # filtros estruturados
41
+ bncc.habilidades_ef(componente='LP', ano=6, pratica='Leitura') # 37 habilidades
42
+ bncc.habilidades_em(area='LGG', competencia=1)
43
+ bncc.objetivos_ei(campo='TS', grupo_etario='02')
44
+
45
+ # busca textual (acentos e caixa não importam)
46
+ bncc.buscar('frações', etapa='EF', componente='MA')
47
+
48
+ # decodificação de códigos (as três gramáticas oficiais)
49
+ bncc.decodificar('EM13LGG103')
50
+
51
+ # progressão oficial da Educação Infantil entre faixas etárias
52
+ bncc.progressao_ei('EI02TS01') # EI01TS01 -> EI02TS01 -> EI03TS01
53
+
54
+ # pandas (extra opcional: pip install bncc[pandas])
55
+ df = bncc.para_dataframe('EF') # 1.304 linhas
56
+ ```
57
+
58
+ ## API
59
+
60
+ `por_codigo` · `decodificar` · `habilidades_ef` · `habilidades_em` · `objetivos_ei` · `buscar` · `progressao_ei` · `estrutura` · `estatisticas` · `versao` · `para_dataframe`
61
+
62
+ Regras que o pacote respeita: códigos inexistentes lançam `ValueError` em vez de inventar; a numeração tem lacunas legítimas; registros trazem `vigencia` para filtrar aprendizagens revogadas em versões futuras.
63
+
64
+ ## Números
65
+
66
+ 1.580 aprendizagens (93 EI + 1.304 EF + 183 EM) · 10 competências gerais · 105 específicas.
67
+
68
+ Projeto **bncc.dev**, mantido pela Profy. Dados CC BY 4.0, código MIT.
bncc-0.1.0/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # bncc
2
+
3
+ A BNCC (Base Nacional Comum Curricular) como dados estruturados e verificados, com API de consulta em português. Dados embutidos, zero dependências, zero rede.
4
+
5
+ Cada registro é rastreável à fonte oficial (planilha do MEC + página do PDF homologado). Fonte dos dados: [bncc-dados](https://github.com/bncc-dev/bncc-dados), extração reprodutível com validação em CI. Paridade com o pacote npm [@bncc/dados](https://www.npmjs.com/package/@bncc/dados) provada por consultas douradas compartilhadas.
6
+
7
+ **Pré-release.** A versão 1.0 sai junto da release `dados-v1.0.0` do bncc-dados, após o registro da revisão pedagógica.
8
+
9
+ ## Uso
10
+
11
+ ```python
12
+ import bncc
13
+
14
+ # registro completo, com nomes resolvidos e fonte oficial
15
+ h = bncc.por_codigo('EF67LP08')
16
+ h['texto'] # enunciado oficial verificado
17
+ h['organizacao']['nomes']['pratica_linguagem'] # 'Leitura'
18
+ h['fonte']['localizador_pdf'] # 'Base-Nacional-...pdf, página PDF 167'
19
+
20
+ # filtros estruturados
21
+ bncc.habilidades_ef(componente='LP', ano=6, pratica='Leitura') # 37 habilidades
22
+ bncc.habilidades_em(area='LGG', competencia=1)
23
+ bncc.objetivos_ei(campo='TS', grupo_etario='02')
24
+
25
+ # busca textual (acentos e caixa não importam)
26
+ bncc.buscar('frações', etapa='EF', componente='MA')
27
+
28
+ # decodificação de códigos (as três gramáticas oficiais)
29
+ bncc.decodificar('EM13LGG103')
30
+
31
+ # progressão oficial da Educação Infantil entre faixas etárias
32
+ bncc.progressao_ei('EI02TS01') # EI01TS01 -> EI02TS01 -> EI03TS01
33
+
34
+ # pandas (extra opcional: pip install bncc[pandas])
35
+ df = bncc.para_dataframe('EF') # 1.304 linhas
36
+ ```
37
+
38
+ ## API
39
+
40
+ `por_codigo` · `decodificar` · `habilidades_ef` · `habilidades_em` · `objetivos_ei` · `buscar` · `progressao_ei` · `estrutura` · `estatisticas` · `versao` · `para_dataframe`
41
+
42
+ Regras que o pacote respeita: códigos inexistentes lançam `ValueError` em vez de inventar; a numeração tem lacunas legítimas; registros trazem `vigencia` para filtrar aprendizagens revogadas em versões futuras.
43
+
44
+ ## Números
45
+
46
+ 1.580 aprendizagens (93 EI + 1.304 EF + 183 EM) · 10 competências gerais · 105 específicas.
47
+
48
+ Projeto **bncc.dev**, mantido pela Profy. Dados CC BY 4.0, código MIT.
@@ -0,0 +1,18 @@
1
+ """bncc — a BNCC (Base Nacional Comum Curricular) como dados estruturados e
2
+ verificados, com API de consulta em português.
3
+
4
+ Dados embutidos, zero dependências, zero rede. Cada registro é rastreável à
5
+ fonte oficial. Projeto bncc.dev · dados CC BY 4.0 · código MIT.
6
+ """
7
+ from ._codigos import decodificar
8
+ from ._consultas import (
9
+ buscar, estatisticas, estrutura, habilidades_ef, habilidades_em,
10
+ objetivos_ei, por_codigo, progressao_ei, versao,
11
+ )
12
+ from ._pandas import para_dataframe
13
+
14
+ __all__ = [
15
+ 'buscar', 'decodificar', 'estatisticas', 'estrutura', 'habilidades_ef',
16
+ 'habilidades_em', 'objetivos_ei', 'para_dataframe', 'por_codigo',
17
+ 'progressao_ei', 'versao',
18
+ ]
@@ -0,0 +1,63 @@
1
+ """Decodificador de códigos da BNCC (as três gramáticas oficiais).
2
+
3
+ Cópia adaptada de bncc-dados/pipeline/codigos.py (mesma origem, mesmos erros),
4
+ onde é exercitado pelos 1.580 códigos do dataset a cada CI.
5
+ """
6
+ import re
7
+
8
+ CAMPOS_EI = {'EO': 'O eu, o outro e o nós', 'CG': 'Corpo, gestos e movimentos',
9
+ 'TS': 'Traços, sons, cores e formas', 'EF': 'Escuta, fala, pensamento e imaginação',
10
+ 'ET': 'Espaços, tempos, quantidades, relações e transformações'}
11
+ GRUPOS_EI = {'01': 'Bebês (0–1a6m)', '02': 'Crianças bem pequenas (1a7m–3a11m)',
12
+ '03': 'Crianças pequenas (4a–5a11m)'}
13
+ COMPONENTES_EF = {'AR': 'Arte', 'CI': 'Ciências', 'EF': 'Educação Física', 'ER': 'Ensino Religioso',
14
+ 'GE': 'Geografia', 'HI': 'História', 'LI': 'Língua Inglesa',
15
+ 'LP': 'Língua Portuguesa', 'MA': 'Matemática'}
16
+ BLOCOS_EF = {'15': [1, 2, 3, 4, 5], '69': [6, 7, 8, 9], '12': [1, 2], '35': [3, 4, 5],
17
+ '67': [6, 7], '89': [8, 9]}
18
+ BLOCOS_VALIDOS_POR_COMPONENTE = {'AR': {'15', '69'}, 'LP': {'15', '69', '12', '35', '67', '89'},
19
+ 'EF': {'12', '35', '67', '89'}}
20
+ AREAS_EM = {'LGG': 'Linguagens e suas Tecnologias', 'MAT': 'Matemática e suas Tecnologias',
21
+ 'CNT': 'Ciências da Natureza e suas Tecnologias', 'CHS': 'Ciências Humanas e Sociais Aplicadas'}
22
+
23
+
24
+ def decodificar(codigo):
25
+ """Decodifica um código BNCC → dict estruturado, ou lança ValueError."""
26
+ codigo = codigo.strip().upper()
27
+
28
+ m = re.fullmatch(r'EI(0[123])(EO|CG|TS|EF|ET)(\d{2})', codigo)
29
+ if m:
30
+ grupo, campo, seq = m.groups()
31
+ return {'codigo': codigo, 'etapa': 'EI', 'grupo_etario': grupo,
32
+ 'grupo_etario_nome': GRUPOS_EI[grupo], 'campo_experiencias': campo,
33
+ 'campo_experiencias_nome': CAMPOS_EI[campo], 'sequencia': int(seq)}
34
+
35
+ m = re.fullmatch(r'EF(\d{2})([A-Z]{2})(\d{2})', codigo)
36
+ if m:
37
+ anos_str, comp, seq = m.groups()
38
+ if comp not in COMPONENTES_EF:
39
+ raise ValueError(f'{codigo}: componente {comp!r} desconhecido')
40
+ if anos_str in BLOCOS_EF:
41
+ if anos_str not in BLOCOS_VALIDOS_POR_COMPONENTE.get(comp, set()):
42
+ raise ValueError(f'{codigo}: bloco {anos_str!r} inválido para {COMPONENTES_EF[comp]}')
43
+ anos = BLOCOS_EF[anos_str]
44
+ elif anos_str.startswith('0') and 1 <= int(anos_str) <= 9:
45
+ anos = [int(anos_str)]
46
+ else:
47
+ raise ValueError(f'{codigo}: ano/bloco {anos_str!r} inválido')
48
+ return {'codigo': codigo, 'etapa': 'EF', 'anos': anos, 'bloco': anos_str in BLOCOS_EF,
49
+ 'componente': comp, 'componente_nome': COMPONENTES_EF[comp], 'sequencia': int(seq)}
50
+
51
+ m = re.fullmatch(r'EM13([A-Z]{3})(\d)(\d{2})', codigo)
52
+ if m and m.group(1) in AREAS_EM:
53
+ area, ce, seq = m.groups()
54
+ return {'codigo': codigo, 'etapa': 'EM', 'seriacao': None, 'area': area,
55
+ 'area_nome': AREAS_EM[area], 'competencia_especifica': int(ce), 'sequencia': int(seq)}
56
+
57
+ m = re.fullmatch(r'EM13LP(\d{2})', codigo)
58
+ if m:
59
+ return {'codigo': codigo, 'etapa': 'EM', 'seriacao': None, 'area': 'LGG',
60
+ 'area_nome': AREAS_EM['LGG'], 'componente': 'LP',
61
+ 'competencia_especifica': None, 'sequencia': int(m.group(1))}
62
+
63
+ raise ValueError(f'{codigo}: não corresponde a nenhuma gramática BNCC (EI/EF/EM)')
@@ -0,0 +1,165 @@
1
+ """API de consulta em português — espelho 1:1 do pacote npm @bncc/dados (snake_case)."""
2
+ from ._codigos import decodificar
3
+ from ._indice import indice, normalizar_texto, resolver_nome, versao as _versao
4
+
5
+
6
+ def _resolver(reg):
7
+ i = indice()
8
+ etapa = decodificar(reg['codigo'])['etapa']
9
+ base = {'codigo': reg['codigo'], 'etapa': etapa, 'texto': reg['texto'],
10
+ 'vigencia': reg['vigencia'], 'fonte': reg['fonte']}
11
+
12
+ if etapa == 'EI':
13
+ return {**base,
14
+ 'campo_experiencias': {'id': reg['campo_experiencias'], 'nome': resolver_nome(reg['campo_experiencias'])},
15
+ 'grupo_etario': reg['grupo_etario'],
16
+ 'alinhamento': reg['alinhamento']}
17
+
18
+ if etapa == 'EF':
19
+ org = reg['organizacao']
20
+ nomes = {}
21
+ if 'unidade_tematica' in org:
22
+ nomes['unidade_tematica'] = resolver_nome(org['unidade_tematica'])
23
+ if org['tipo'] == 'campo_pratica':
24
+ nomes['campos_atuacao'] = [resolver_nome(c) for c in org['campos_atuacao']]
25
+ nomes['pratica_linguagem'] = resolver_nome(org['pratica_linguagem'])
26
+ if org['tipo'] == 'eixo':
27
+ nomes['eixo'] = resolver_nome(org['eixo'])
28
+ return {**base,
29
+ 'componente': {'id': reg['componente'], 'nome': resolver_nome(reg['componente'])},
30
+ 'anos': reg['anos'],
31
+ 'organizacao': {'tipo': org['tipo'], 'nomes': nomes},
32
+ 'objetos_conhecimento': [{'id': o, 'nome': resolver_nome(o)} for o in reg['objetos_conhecimento']]}
33
+
34
+ comps = []
35
+ for cid in reg['competencias_especificas']:
36
+ c = indice()['competencias'].get(cid, {})
37
+ comps.append({'id': cid, 'numero': c.get('numero', 0), 'texto': c.get('texto', '')})
38
+ return {**base,
39
+ 'area': {'id': reg['area'], 'nome': resolver_nome(reg['area'])},
40
+ 'componente': ({'id': reg['componente'], 'nome': resolver_nome(reg['componente'])}
41
+ if reg['componente'] else None),
42
+ 'competencias_especificas': comps,
43
+ 'campos_atuacao_social': ([{'id': c, 'nome': resolver_nome(c)} for c in reg['campos_atuacao_social']]
44
+ if reg['campos_atuacao_social'] else None)}
45
+
46
+
47
+ def por_codigo(codigo):
48
+ """Registro completo de uma aprendizagem pelo código (case-insensitive), com nomes resolvidos."""
49
+ cod = codigo.strip().upper()
50
+ reg = indice()['por_codigo'].get(cod)
51
+ if reg is None:
52
+ decodificar(cod) # gramática inválida gera o erro explicativo
53
+ raise ValueError(f'{cod}: código válido na forma, mas não existe na BNCC '
54
+ '(dica: a numeração tem lacunas legítimas)')
55
+ return _resolver(reg)
56
+
57
+
58
+ def _id_componente(componente):
59
+ if componente is None:
60
+ return None
61
+ return componente if componente.startswith('ef-comp-') else f'ef-comp-{componente.lower()}'
62
+
63
+
64
+ def habilidades_ef(componente=None, ano=None, unidade_tematica=None, pratica=None, campo_atuacao=None):
65
+ """Habilidades do Ensino Fundamental, com filtros opcionais (sigla ou id de componente)."""
66
+ comp = _id_componente(componente)
67
+ saida = []
68
+ for h in indice()['habilidades_ef']:
69
+ org = h['organizacao']
70
+ if comp and h['componente'] != comp:
71
+ continue
72
+ if ano and ano not in h['anos']:
73
+ continue
74
+ if unidade_tematica and not ('unidade_tematica' in org and resolver_nome(org['unidade_tematica']) == unidade_tematica):
75
+ continue
76
+ if pratica and not (org['tipo'] == 'campo_pratica' and resolver_nome(org['pratica_linguagem']) == pratica):
77
+ continue
78
+ if campo_atuacao and not (org['tipo'] == 'campo_pratica'
79
+ and any(resolver_nome(c) == campo_atuacao for c in org['campos_atuacao'])):
80
+ continue
81
+ saida.append(_resolver(h))
82
+ return saida
83
+
84
+
85
+ def habilidades_em(area=None, competencia=None, apenas_lp=False):
86
+ """Habilidades do Ensino Médio. `area` aceita id (em-area-lgg) ou sigla (LGG)."""
87
+ aid = area if (area is None or area.startswith('em-area-')) else f'em-area-{area.lower()}'
88
+ i = indice()
89
+ saida = []
90
+ for h in i['habilidades_em']:
91
+ if aid and h['area'] != aid:
92
+ continue
93
+ if apenas_lp and h['componente'] != 'em-comp-lp':
94
+ continue
95
+ if competencia and not any(i['competencias'].get(c, {}).get('numero') == competencia
96
+ for c in h['competencias_especificas']):
97
+ continue
98
+ saida.append(_resolver(h))
99
+ return saida
100
+
101
+
102
+ def objetivos_ei(campo=None, grupo_etario=None):
103
+ """Objetivos da Educação Infantil. `campo` aceita id (ei-campo-ts) ou sigla (TS)."""
104
+ cid = campo if (campo is None or campo.startswith('ei-campo-')) else f'ei-campo-{campo.lower()}'
105
+ gid = grupo_etario if (grupo_etario is None or grupo_etario.startswith('ei-grupo-')) else f'ei-grupo-{grupo_etario}'
106
+ return [_resolver(o) for o in indice()['objetivos_ei']
107
+ if (not cid or o['campo_experiencias'] == cid) and (not gid or o['grupo_etario'] == gid)]
108
+
109
+
110
+ def buscar(texto, etapa=None, componente=None, ano=None):
111
+ """Busca textual normalizada (sem acentos/caixa) nos enunciados. Sem rede."""
112
+ alvo = normalizar_texto(texto)
113
+ i = indice()
114
+ universo = []
115
+ if etapa in (None, 'EI'):
116
+ universo += i['objetivos_ei']
117
+ if etapa in (None, 'EF'):
118
+ universo += i['habilidades_ef']
119
+ if etapa in (None, 'EM'):
120
+ universo += i['habilidades_em']
121
+ comp = componente if (componente is None or '-comp-' in componente) else f'ef-comp-{componente.lower()}'
122
+ saida = []
123
+ for r in universo:
124
+ if alvo not in normalizar_texto(r['texto']):
125
+ continue
126
+ if comp and r.get('componente') != comp:
127
+ continue
128
+ if ano and ano not in r.get('anos', []):
129
+ continue
130
+ saida.append(_resolver(r))
131
+ return saida
132
+
133
+
134
+ def progressao_ei(codigo):
135
+ """Progressão oficial da EI: os objetivos do mesmo aspecto nas três faixas etárias."""
136
+ reg = por_codigo(codigo)
137
+ if reg['etapa'] != 'EI':
138
+ raise ValueError(f"{reg['codigo']}: progressão por alinhamento só existe na Educação Infantil")
139
+ al = indice()['alinhamento_por_id'][reg['alinhamento']]
140
+ return {'alinhamento': al['id'], 'objetivos': [por_codigo(c) for c in al['objetivos']],
141
+ 'nota': al.get('nota')}
142
+
143
+
144
+ def estrutura():
145
+ """A espinha estrutural completa (etapas, áreas, componentes, competências, recortes)."""
146
+ return indice()['estrutura']
147
+
148
+
149
+ def estatisticas():
150
+ """Contagens do dataset."""
151
+ i = indice()
152
+ return {
153
+ 'total': len(i['objetivos_ei']) + len(i['habilidades_ef']) + len(i['habilidades_em']),
154
+ 'educacao_infantil': len(i['objetivos_ei']),
155
+ 'ensino_fundamental': len(i['habilidades_ef']),
156
+ 'ensino_medio': len(i['habilidades_em']),
157
+ 'alinhamentos_ei': len(i['alinhamentos']),
158
+ 'competencias_gerais': len(i['estrutura']['competencias_gerais']),
159
+ 'competencias_especificas': len(i['estrutura']['competencias_especificas']),
160
+ }
161
+
162
+
163
+ def versao():
164
+ """Data-version, commit de origem e checksums dos dados embutidos."""
165
+ return _versao()
@@ -0,0 +1,61 @@
1
+ """Carregamento lazy dos dados embutidos e índices em memória."""
2
+ import json
3
+ import re
4
+ import unicodedata
5
+ from functools import lru_cache
6
+ from pathlib import Path
7
+
8
+ _DADOS = Path(__file__).parent / 'dados'
9
+
10
+
11
+ def _carregar(arquivo):
12
+ return json.loads((_DADOS / f'{arquivo}.json').read_text(encoding='utf-8'))
13
+
14
+
15
+ @lru_cache(maxsize=1)
16
+ def indice():
17
+ estrutura = _carregar('estrutura')
18
+ ei = _carregar('educacao-infantil')
19
+ ef = _carregar('ensino-fundamental')
20
+ em = _carregar('ensino-medio')
21
+
22
+ por_codigo = {}
23
+ for o in ei['objetivos']:
24
+ por_codigo[o['codigo']] = o
25
+ for h in ef['habilidades'] + em['habilidades']:
26
+ por_codigo[h['codigo']] = h
27
+
28
+ contextos = {c['id']: c for c in ef['contextos_organizacao'] + em['contextos_organizacao']}
29
+ competencias = {c['id']: c for c in estrutura['competencias_especificas']}
30
+ alinhamentos = {a['id']: a for a in ei['alinhamentos']}
31
+ nomes = {}
32
+ for c in estrutura['componentes_curriculares'] + estrutura['areas_conhecimento'] + estrutura['campos_experiencias']:
33
+ nomes[c['id']] = c['nome']
34
+
35
+ return {
36
+ 'estrutura': estrutura,
37
+ 'objetivos_ei': ei['objetivos'], 'alinhamentos': ei['alinhamentos'],
38
+ 'habilidades_ef': ef['habilidades'], 'habilidades_em': em['habilidades'],
39
+ 'por_codigo': por_codigo, 'contextos': contextos,
40
+ 'competencias': competencias, 'alinhamento_por_id': alinhamentos, 'nomes': nomes,
41
+ }
42
+
43
+
44
+ def versao():
45
+ """Metadados dos dados embutidos: data-version, commit de origem, checksums."""
46
+ return json.loads((_DADOS / 'VERSAO.json').read_text(encoding='utf-8'))
47
+
48
+
49
+ def normalizar_texto(t):
50
+ """Normalização de busca: sem acentos, minúsculas, espaços únicos (mesma regra do @bncc/dados)."""
51
+ t = unicodedata.normalize('NFD', t)
52
+ t = ''.join(ch for ch in t if not unicodedata.combining(ch))
53
+ return re.sub(r'\s+', ' ', t.casefold()).strip()
54
+
55
+
56
+ def resolver_nome(id_):
57
+ i = indice()
58
+ ctx = i['contextos'].get(id_)
59
+ if ctx:
60
+ return ctx['nome']
61
+ return i['nomes'].get(id_, id_)
@@ -0,0 +1,38 @@
1
+ """Integração opcional com pandas (extra `bncc[pandas]`)."""
2
+
3
+
4
+ def para_dataframe(etapa='EF'):
5
+ """DataFrame plano das aprendizagens de uma etapa ('EI', 'EF' ou 'EM').
6
+
7
+ Requer o extra: pip install bncc[pandas]
8
+ """
9
+ try:
10
+ import pandas as pd
11
+ except ImportError as e:
12
+ raise ImportError('para_dataframe requer pandas: pip install bncc[pandas]') from e
13
+
14
+ from ._consultas import habilidades_ef, habilidades_em, objetivos_ei
15
+
16
+ if etapa == 'EF':
17
+ registros = habilidades_ef()
18
+ linhas = [{
19
+ 'codigo': r['codigo'], 'componente': r['componente']['nome'],
20
+ 'anos': ' | '.join(map(str, r['anos'])),
21
+ 'organizacao': r['organizacao']['tipo'],
22
+ 'texto': r['texto'],
23
+ } for r in registros]
24
+ elif etapa == 'EM':
25
+ linhas = [{
26
+ 'codigo': r['codigo'], 'area': r['area']['nome'],
27
+ 'componente': r['componente']['nome'] if r['componente'] else None,
28
+ 'competencias': ' | '.join(str(c['numero']) for c in r['competencias_especificas']),
29
+ 'texto': r['texto'],
30
+ } for r in habilidades_em()]
31
+ elif etapa == 'EI':
32
+ linhas = [{
33
+ 'codigo': r['codigo'], 'campo': r['campo_experiencias']['nome'],
34
+ 'grupo_etario': r['grupo_etario'], 'texto': r['texto'],
35
+ } for r in objetivos_ei()]
36
+ else:
37
+ raise ValueError(f"etapa {etapa!r} inválida; use 'EI', 'EF' ou 'EM'")
38
+ return pd.DataFrame(linhas)
@@ -0,0 +1,12 @@
1
+ {
2
+ "data_version": "dados-2026.07",
3
+ "origem": "github.com/bncc-dev/bncc-dados",
4
+ "commit": "46accba58c68af21235c0b3d1d5ab3855834f739",
5
+ "sincronizado_de": "/Users/marcosbeto/Dev/bncc-dados",
6
+ "checksums_sha256": {
7
+ "estrutura.json": "0c499251a18a08508a74b1f4fa3ce4aae79ab9871bf0be65e4384629fb30b665",
8
+ "educacao-infantil.json": "e8549b4e35313b18d4fa02eb07b4ff603c3fef173224528a7aadd965680892e9",
9
+ "ensino-fundamental.json": "e18f7573a5c80ca326292160b8cc431992db80371923f2851974b919ac925817",
10
+ "ensino-medio.json": "380ff4761d5e287791de025ed806bcf343936a6398dbbab2e9265a2c42917adf"
11
+ }
12
+ }