pypncp 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.
- pypncp-0.1.0/PKG-INFO +236 -0
- pypncp-0.1.0/README.md +218 -0
- pypncp-0.1.0/pyproject.toml +94 -0
- pypncp-0.1.0/setup.cfg +4 -0
- pypncp-0.1.0/src/pypncp/__init__.py +34 -0
- pypncp-0.1.0/src/pypncp/_internal/__init__.py +5 -0
- pypncp-0.1.0/src/pypncp/_internal/http.py +157 -0
- pypncp-0.1.0/src/pypncp/client.py +105 -0
- pypncp-0.1.0/src/pypncp/exceptions.py +29 -0
- pypncp-0.1.0/src/pypncp/models.py +221 -0
- pypncp-0.1.0/src/pypncp/py.typed +0 -0
- pypncp-0.1.0/src/pypncp/resources/__init__.py +5 -0
- pypncp-0.1.0/src/pypncp/resources/atas.py +99 -0
- pypncp-0.1.0/src/pypncp/resources/base.py +61 -0
- pypncp-0.1.0/src/pypncp/resources/contratacoes.py +157 -0
- pypncp-0.1.0/src/pypncp/resources/contratos.py +122 -0
- pypncp-0.1.0/src/pypncp.egg-info/PKG-INFO +236 -0
- pypncp-0.1.0/src/pypncp.egg-info/SOURCES.txt +26 -0
- pypncp-0.1.0/src/pypncp.egg-info/dependency_links.txt +1 -0
- pypncp-0.1.0/src/pypncp.egg-info/requires.txt +11 -0
- pypncp-0.1.0/src/pypncp.egg-info/top_level.txt +1 -0
- pypncp-0.1.0/tests/test_atas_resource.py +61 -0
- pypncp-0.1.0/tests/test_client.py +53 -0
- pypncp-0.1.0/tests/test_contratacoes_resource.py +62 -0
- pypncp-0.1.0/tests/test_contratos_resource.py +121 -0
- pypncp-0.1.0/tests/test_exceptions.py +38 -0
- pypncp-0.1.0/tests/test_http_client.py +179 -0
- pypncp-0.1.0/tests/test_models.py +178 -0
pypncp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pypncp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: pypncp — Cliente Python assíncrono para a API de Consulta do PNCP
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: httpx>=0.28.1
|
|
9
|
+
Requires-Dist: pydantic>=2.13.4
|
|
10
|
+
Requires-Dist: tenacity>=9.0.0
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
13
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
|
|
14
|
+
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest-httpx>=0.35.0; extra == "dev"
|
|
16
|
+
Requires-Dist: ruff>=0.11.0; extra == "dev"
|
|
17
|
+
Requires-Dist: mypy>=1.15.0; extra == "dev"
|
|
18
|
+
|
|
19
|
+
# pypncp
|
|
20
|
+
|
|
21
|
+
  
|
|
22
|
+
|
|
23
|
+
**Cliente Python assíncrono para a API de Consulta do PNCP** — Portal Nacional de Contratações Públicas.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Como usar
|
|
28
|
+
|
|
29
|
+
### Adicionar ao projeto
|
|
30
|
+
|
|
31
|
+
Com `uv` (recomendado):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
uv add pypncp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Com `pip`:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install pypncp
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Ou direto no `pyproject.toml`:
|
|
44
|
+
|
|
45
|
+
```toml
|
|
46
|
+
[project]
|
|
47
|
+
dependencies = [
|
|
48
|
+
"pypncp>=0.1",
|
|
49
|
+
]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Criar o cliente
|
|
53
|
+
|
|
54
|
+
O cliente é a entrada única para a API. Use `async with` pra gerenciar o ciclo de vida:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from pypncp import PNCPClient
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
async def buscar_dados():
|
|
61
|
+
async with PNCPClient() as client:
|
|
62
|
+
# client está pronto — usa os resources abaixo
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
# Fora de async def, use asyncio.run():
|
|
66
|
+
# asyncio.run(buscar_dados())
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Exemplos por recurso
|
|
70
|
+
|
|
71
|
+
**Contratos** — busque contratos por período de publicação:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
async with PNCPClient() as client:
|
|
75
|
+
# Uma página
|
|
76
|
+
page = await client.contratos.list(
|
|
77
|
+
data_inicial="2025-01-01",
|
|
78
|
+
data_final="2025-03-31",
|
|
79
|
+
)
|
|
80
|
+
for contrato in page.data:
|
|
81
|
+
print(contrato.numero_contrato_empenho, contrato.valor_global)
|
|
82
|
+
|
|
83
|
+
# Todas as páginas (paginação automática)
|
|
84
|
+
async for contrato in client.contratos.list_all(
|
|
85
|
+
data_inicial="2025-01-01",
|
|
86
|
+
data_final="2025-03-31",
|
|
87
|
+
):
|
|
88
|
+
print(contrato.objeto_contrato)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Contratações (licitações)** — filtre por modalidade (código 1 = pregão):
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
async with PNCPClient() as client:
|
|
95
|
+
async for compra in client.contratacoes.list_all_publicacao(
|
|
96
|
+
data_inicial="2025-01-01",
|
|
97
|
+
data_final="2025-03-31",
|
|
98
|
+
codigo_modalidade=1, # 1 = Pregão
|
|
99
|
+
):
|
|
100
|
+
print(compra.objeto_compra, compra.orgao_nome)
|
|
101
|
+
|
|
102
|
+
# Com propostas abertas (apenas data_final)
|
|
103
|
+
async for compra in client.contratacoes.list_all_com_proposta(
|
|
104
|
+
data_final="2025-12-31",
|
|
105
|
+
):
|
|
106
|
+
print(compra.objeto_compra, compra.data_abertura_proposta)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Atas de registro de preço:**
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
async with PNCPClient() as client:
|
|
113
|
+
async for ata in client.atas.list_all(
|
|
114
|
+
data_inicial="2025-01-01",
|
|
115
|
+
data_final="2025-12-31",
|
|
116
|
+
):
|
|
117
|
+
print(ata.objeto_contratacao, ata.orgao_nome)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Paginação
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# Automática — use list_all*() (async generator)
|
|
124
|
+
async for contrato in client.contratos.list_all(
|
|
125
|
+
data_inicial="2025-01-01",
|
|
126
|
+
data_final="2025-12-31",
|
|
127
|
+
):
|
|
128
|
+
...
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
# Manual — use list() e controle a página
|
|
132
|
+
page = await client.contratos.list(
|
|
133
|
+
data_inicial="2025-01-01",
|
|
134
|
+
data_final="2025-12-31",
|
|
135
|
+
pagina=1,
|
|
136
|
+
)
|
|
137
|
+
print(f"Página {page.numero_pagina} de {page.total_paginas}")
|
|
138
|
+
print(f"Itens nesta página: {len(page.data)}")
|
|
139
|
+
|
|
140
|
+
# Propriedades úteis de Page[T]:
|
|
141
|
+
# page.data → list[T]
|
|
142
|
+
# page.numero_pagina
|
|
143
|
+
# page.total_paginas
|
|
144
|
+
# page.has_more → True se há mais páginas
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Tratamento de erros
|
|
148
|
+
|
|
149
|
+
Todas as exceções herdam de `PNCPError` — nunca vazam exceções de transporte:
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from pypncp import PNCPError, NotFoundError, RateLimitError
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
page = await client.contratos.list(
|
|
156
|
+
data_inicial="2025-01-01",
|
|
157
|
+
data_final="2025-12-31",
|
|
158
|
+
)
|
|
159
|
+
except NotFoundError:
|
|
160
|
+
print("Recurso não encontrado (HTTP 404)")
|
|
161
|
+
except RateLimitError:
|
|
162
|
+
print("Muitas requisições (HTTP 429)")
|
|
163
|
+
except PNCPError as e:
|
|
164
|
+
print(f"Erro na API: {e}")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Exemplo completo com FastAPI
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from fastapi import FastAPI, HTTPException
|
|
171
|
+
from pypncp import PNCPClient, NotFoundError
|
|
172
|
+
|
|
173
|
+
app = FastAPI()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@app.get("/contratos")
|
|
177
|
+
async def listar_contratos(
|
|
178
|
+
data_inicial: str,
|
|
179
|
+
data_final: str,
|
|
180
|
+
pagina: int = 1,
|
|
181
|
+
):
|
|
182
|
+
async with PNCPClient() as client:
|
|
183
|
+
page = await client.contratos.list(
|
|
184
|
+
data_inicial=data_inicial,
|
|
185
|
+
data_final=data_final,
|
|
186
|
+
pagina=pagina,
|
|
187
|
+
)
|
|
188
|
+
return {
|
|
189
|
+
"contratos": [c.model_dump() for c in page.data],
|
|
190
|
+
"pagina": page.numero_pagina,
|
|
191
|
+
"total_paginas": page.total_paginas,
|
|
192
|
+
"total_registros": page.total_registros,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@app.get("/contratos/{orgao_cnpj}/{ano}/{sequencial}")
|
|
197
|
+
async def get_contrato(orgao_cnpj: str, ano: int, sequencial: int):
|
|
198
|
+
async with PNCPClient() as client:
|
|
199
|
+
try:
|
|
200
|
+
contrato = await client.contratos.get(
|
|
201
|
+
orgao_cnpj=orgao_cnpj,
|
|
202
|
+
ano=ano,
|
|
203
|
+
sequencial=sequencial,
|
|
204
|
+
)
|
|
205
|
+
return contrato.model_dump()
|
|
206
|
+
except NotFoundError:
|
|
207
|
+
raise HTTPException(status_code=404, detail="Contrato não encontrado")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Para contribuir
|
|
213
|
+
|
|
214
|
+
### Requisitos
|
|
215
|
+
|
|
216
|
+
- Python **3.12+**
|
|
217
|
+
- [uv](https://docs.astral.sh/uv/) — gerenciador de projetos e pacotes
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
uv sync
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Rodar verificações
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
git clone https://github.com/gabrielgz0/pypncp
|
|
227
|
+
cd pypncp
|
|
228
|
+
uv sync # instala tudo — dev deps inclusas
|
|
229
|
+
uv run pytest -v # tests
|
|
230
|
+
uv run ruff check src/ tests/
|
|
231
|
+
uv run mypy src/
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Licença
|
|
235
|
+
|
|
236
|
+
MIT
|
pypncp-0.1.0/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# pypncp
|
|
2
|
+
|
|
3
|
+
  
|
|
4
|
+
|
|
5
|
+
**Cliente Python assíncrono para a API de Consulta do PNCP** — Portal Nacional de Contratações Públicas.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Como usar
|
|
10
|
+
|
|
11
|
+
### Adicionar ao projeto
|
|
12
|
+
|
|
13
|
+
Com `uv` (recomendado):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
uv add pypncp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Com `pip`:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install pypncp
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Ou direto no `pyproject.toml`:
|
|
26
|
+
|
|
27
|
+
```toml
|
|
28
|
+
[project]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"pypncp>=0.1",
|
|
31
|
+
]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Criar o cliente
|
|
35
|
+
|
|
36
|
+
O cliente é a entrada única para a API. Use `async with` pra gerenciar o ciclo de vida:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from pypncp import PNCPClient
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
async def buscar_dados():
|
|
43
|
+
async with PNCPClient() as client:
|
|
44
|
+
# client está pronto — usa os resources abaixo
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
# Fora de async def, use asyncio.run():
|
|
48
|
+
# asyncio.run(buscar_dados())
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Exemplos por recurso
|
|
52
|
+
|
|
53
|
+
**Contratos** — busque contratos por período de publicação:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
async with PNCPClient() as client:
|
|
57
|
+
# Uma página
|
|
58
|
+
page = await client.contratos.list(
|
|
59
|
+
data_inicial="2025-01-01",
|
|
60
|
+
data_final="2025-03-31",
|
|
61
|
+
)
|
|
62
|
+
for contrato in page.data:
|
|
63
|
+
print(contrato.numero_contrato_empenho, contrato.valor_global)
|
|
64
|
+
|
|
65
|
+
# Todas as páginas (paginação automática)
|
|
66
|
+
async for contrato in client.contratos.list_all(
|
|
67
|
+
data_inicial="2025-01-01",
|
|
68
|
+
data_final="2025-03-31",
|
|
69
|
+
):
|
|
70
|
+
print(contrato.objeto_contrato)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Contratações (licitações)** — filtre por modalidade (código 1 = pregão):
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
async with PNCPClient() as client:
|
|
77
|
+
async for compra in client.contratacoes.list_all_publicacao(
|
|
78
|
+
data_inicial="2025-01-01",
|
|
79
|
+
data_final="2025-03-31",
|
|
80
|
+
codigo_modalidade=1, # 1 = Pregão
|
|
81
|
+
):
|
|
82
|
+
print(compra.objeto_compra, compra.orgao_nome)
|
|
83
|
+
|
|
84
|
+
# Com propostas abertas (apenas data_final)
|
|
85
|
+
async for compra in client.contratacoes.list_all_com_proposta(
|
|
86
|
+
data_final="2025-12-31",
|
|
87
|
+
):
|
|
88
|
+
print(compra.objeto_compra, compra.data_abertura_proposta)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Atas de registro de preço:**
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
async with PNCPClient() as client:
|
|
95
|
+
async for ata in client.atas.list_all(
|
|
96
|
+
data_inicial="2025-01-01",
|
|
97
|
+
data_final="2025-12-31",
|
|
98
|
+
):
|
|
99
|
+
print(ata.objeto_contratacao, ata.orgao_nome)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Paginação
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# Automática — use list_all*() (async generator)
|
|
106
|
+
async for contrato in client.contratos.list_all(
|
|
107
|
+
data_inicial="2025-01-01",
|
|
108
|
+
data_final="2025-12-31",
|
|
109
|
+
):
|
|
110
|
+
...
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# Manual — use list() e controle a página
|
|
114
|
+
page = await client.contratos.list(
|
|
115
|
+
data_inicial="2025-01-01",
|
|
116
|
+
data_final="2025-12-31",
|
|
117
|
+
pagina=1,
|
|
118
|
+
)
|
|
119
|
+
print(f"Página {page.numero_pagina} de {page.total_paginas}")
|
|
120
|
+
print(f"Itens nesta página: {len(page.data)}")
|
|
121
|
+
|
|
122
|
+
# Propriedades úteis de Page[T]:
|
|
123
|
+
# page.data → list[T]
|
|
124
|
+
# page.numero_pagina
|
|
125
|
+
# page.total_paginas
|
|
126
|
+
# page.has_more → True se há mais páginas
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Tratamento de erros
|
|
130
|
+
|
|
131
|
+
Todas as exceções herdam de `PNCPError` — nunca vazam exceções de transporte:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from pypncp import PNCPError, NotFoundError, RateLimitError
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
page = await client.contratos.list(
|
|
138
|
+
data_inicial="2025-01-01",
|
|
139
|
+
data_final="2025-12-31",
|
|
140
|
+
)
|
|
141
|
+
except NotFoundError:
|
|
142
|
+
print("Recurso não encontrado (HTTP 404)")
|
|
143
|
+
except RateLimitError:
|
|
144
|
+
print("Muitas requisições (HTTP 429)")
|
|
145
|
+
except PNCPError as e:
|
|
146
|
+
print(f"Erro na API: {e}")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Exemplo completo com FastAPI
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from fastapi import FastAPI, HTTPException
|
|
153
|
+
from pypncp import PNCPClient, NotFoundError
|
|
154
|
+
|
|
155
|
+
app = FastAPI()
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@app.get("/contratos")
|
|
159
|
+
async def listar_contratos(
|
|
160
|
+
data_inicial: str,
|
|
161
|
+
data_final: str,
|
|
162
|
+
pagina: int = 1,
|
|
163
|
+
):
|
|
164
|
+
async with PNCPClient() as client:
|
|
165
|
+
page = await client.contratos.list(
|
|
166
|
+
data_inicial=data_inicial,
|
|
167
|
+
data_final=data_final,
|
|
168
|
+
pagina=pagina,
|
|
169
|
+
)
|
|
170
|
+
return {
|
|
171
|
+
"contratos": [c.model_dump() for c in page.data],
|
|
172
|
+
"pagina": page.numero_pagina,
|
|
173
|
+
"total_paginas": page.total_paginas,
|
|
174
|
+
"total_registros": page.total_registros,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@app.get("/contratos/{orgao_cnpj}/{ano}/{sequencial}")
|
|
179
|
+
async def get_contrato(orgao_cnpj: str, ano: int, sequencial: int):
|
|
180
|
+
async with PNCPClient() as client:
|
|
181
|
+
try:
|
|
182
|
+
contrato = await client.contratos.get(
|
|
183
|
+
orgao_cnpj=orgao_cnpj,
|
|
184
|
+
ano=ano,
|
|
185
|
+
sequencial=sequencial,
|
|
186
|
+
)
|
|
187
|
+
return contrato.model_dump()
|
|
188
|
+
except NotFoundError:
|
|
189
|
+
raise HTTPException(status_code=404, detail="Contrato não encontrado")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Para contribuir
|
|
195
|
+
|
|
196
|
+
### Requisitos
|
|
197
|
+
|
|
198
|
+
- Python **3.12+**
|
|
199
|
+
- [uv](https://docs.astral.sh/uv/) — gerenciador de projetos e pacotes
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
uv sync
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Rodar verificações
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
git clone https://github.com/gabrielgz0/pypncp
|
|
209
|
+
cd pypncp
|
|
210
|
+
uv sync # instala tudo — dev deps inclusas
|
|
211
|
+
uv run pytest -v # tests
|
|
212
|
+
uv run ruff check src/ tests/
|
|
213
|
+
uv run mypy src/
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Licença
|
|
217
|
+
|
|
218
|
+
MIT
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=70.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pypncp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "pypncp — Cliente Python assíncrono para a API de Consulta do PNCP"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"httpx>=0.28.1",
|
|
14
|
+
"pydantic>=2.13.4",
|
|
15
|
+
"tenacity>=9.0.0",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
dev = [
|
|
20
|
+
"pytest>=8.0.0",
|
|
21
|
+
"pytest-asyncio>=0.24.0",
|
|
22
|
+
"pytest-cov>=6.0.0",
|
|
23
|
+
"pytest-httpx>=0.35.0",
|
|
24
|
+
"ruff>=0.11.0",
|
|
25
|
+
"mypy>=1.15.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.packages.find]
|
|
29
|
+
where = ["src"]
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.package-data]
|
|
32
|
+
pypncp = ["py.typed"]
|
|
33
|
+
|
|
34
|
+
# --------------------------------------------------------------------------- #
|
|
35
|
+
# Ruff — linter + formatador
|
|
36
|
+
# --------------------------------------------------------------------------- #
|
|
37
|
+
|
|
38
|
+
[tool.ruff]
|
|
39
|
+
line-length = 88
|
|
40
|
+
target-version = "py312"
|
|
41
|
+
|
|
42
|
+
[tool.ruff.lint]
|
|
43
|
+
select = [
|
|
44
|
+
"E", # pycodestyle errors
|
|
45
|
+
"W", # pycodestyle warnings
|
|
46
|
+
"F", # pyflakes
|
|
47
|
+
"I", # isort
|
|
48
|
+
"UP", # pyupgrade
|
|
49
|
+
"B", # flake8-bugbear
|
|
50
|
+
"SIM", # flake8-simplify
|
|
51
|
+
]
|
|
52
|
+
ignore = [
|
|
53
|
+
"B905", # zip() sem strict= — comum em kwargs dinâmicos
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[tool.ruff.format]
|
|
57
|
+
quote-style = "double"
|
|
58
|
+
indent-style = "space"
|
|
59
|
+
line-ending = "lf"
|
|
60
|
+
|
|
61
|
+
# --------------------------------------------------------------------------- #
|
|
62
|
+
# mypy — type checker
|
|
63
|
+
# --------------------------------------------------------------------------- #
|
|
64
|
+
|
|
65
|
+
[tool.mypy]
|
|
66
|
+
strict = true
|
|
67
|
+
python_version = "3.12"
|
|
68
|
+
exclude = [
|
|
69
|
+
"tests/",
|
|
70
|
+
".venv/",
|
|
71
|
+
]
|
|
72
|
+
[[tool.mypy.overrides]]
|
|
73
|
+
module = [
|
|
74
|
+
"httpx.*",
|
|
75
|
+
"pydantic.*",
|
|
76
|
+
"tenacity.*",
|
|
77
|
+
]
|
|
78
|
+
ignore_missing_imports = true
|
|
79
|
+
|
|
80
|
+
# --------------------------------------------------------------------------- #
|
|
81
|
+
# pytest
|
|
82
|
+
# --------------------------------------------------------------------------- #
|
|
83
|
+
|
|
84
|
+
[tool.pytest.ini_options]
|
|
85
|
+
asyncio_mode = "auto"
|
|
86
|
+
testpaths = ["tests"]
|
|
87
|
+
|
|
88
|
+
# --------------------------------------------------------------------------- #
|
|
89
|
+
# Cobertura
|
|
90
|
+
# --------------------------------------------------------------------------- #
|
|
91
|
+
|
|
92
|
+
[tool.coverage.report]
|
|
93
|
+
fail_under = 80
|
|
94
|
+
show_missing = true
|
pypncp-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""pypncp — Cliente Python assíncrono para a API de Consulta do PNCP.
|
|
2
|
+
|
|
3
|
+
API pública — apenas o que está em __all__ é suportado por semver.
|
|
4
|
+
|
|
5
|
+
Uso básico:
|
|
6
|
+
from pypncp import PNCPClient
|
|
7
|
+
|
|
8
|
+
async with PNCPClient() as client:
|
|
9
|
+
async for contrato in client.contratos.list_all(
|
|
10
|
+
data_inicial="2024-01-01",
|
|
11
|
+
data_final="2024-12-31",
|
|
12
|
+
):
|
|
13
|
+
print(contrato.objeto_contrato)
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .client import PNCPClient
|
|
17
|
+
from .exceptions import (
|
|
18
|
+
AuthError,
|
|
19
|
+
NotFoundError,
|
|
20
|
+
PNCPError,
|
|
21
|
+
RateLimitError,
|
|
22
|
+
ServerError,
|
|
23
|
+
ValidationError,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"PNCPClient",
|
|
28
|
+
"PNCPError",
|
|
29
|
+
"NotFoundError",
|
|
30
|
+
"AuthError",
|
|
31
|
+
"RateLimitError",
|
|
32
|
+
"ServerError",
|
|
33
|
+
"ValidationError",
|
|
34
|
+
]
|