Coverage for src\pncp\instrumentos_convocatorios\busca.py: 100%

212 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-07-22 21:34 -0300

1from typing import Iterable 

2 

3import pncp.utils 

4from pncp.tipos import Lista 

5 

6from .tipos import ( 

7 Ano, 

8 CamposDeBusca, 

9 Esfera, 

10 FonteOrcamentaria, 

11 Id, 

12 InstrumentoConvocatorio, 

13 ModalidadeDeContratacao, 

14 Municipio, 

15 Orgao, 

16 Poder, 

17 Resultado, 

18 Status, 

19 Unidade, 

20 UnidadeDaFederacao, 

21) 

22 

23 

24class Busca: 

25 _url_filtros = "https://pncp.gov.br/api/search/filters?tipos_documento=edital" 

26 _url_busca = "https://pncp.gov.br/api/search" 

27 

28 def __init__(self): 

29 self._filtros = None 

30 self._campos_de_busca = CamposDeBusca() 

31 self._resultados: Lista[Resultado] | None = None 

32 

33 def _carregar_filtros(self): 

34 if self._filtros is None: 

35 data = pncp.utils.get_one(self._url_filtros) 

36 self._filtros = data["filters"] 

37 

38 def _verificar_se_existem_resultados(self) -> None: 

39 if self._resultados is not None: 

40 raise ValueError("Não é possível modificar uma busca já realizada.") 

41 

42 def listar_status(self) -> Lista[Status]: 

43 return Status.listar() 

44 

45 def listar_instrumentos_convocatorios(self) -> Lista[InstrumentoConvocatorio]: 

46 self._carregar_filtros() 

47 

48 if not self._filtros or "tipos" not in self._filtros: 

49 return Lista() 

50 

51 return Lista( 

52 InstrumentoConvocatorio(**instrumento_convocatorio) 

53 for instrumento_convocatorio in self._filtros["tipos"] 

54 ) 

55 

56 def listar_modalidades_de_contratacao(self) -> Lista[ModalidadeDeContratacao]: 

57 self._carregar_filtros() 

58 

59 if not self._filtros or "modalidades" not in self._filtros: 

60 return Lista() 

61 

62 return Lista( 

63 ModalidadeDeContratacao(**modalidade_de_contratacao) 

64 for modalidade_de_contratacao in self._filtros["modalidades"] 

65 ) 

66 

67 def listar_orgaos(self) -> Lista[Orgao]: 

68 self._carregar_filtros() 

69 

70 if not self._filtros or "orgaos" not in self._filtros: 

71 return Lista() 

72 

73 return Lista(Orgao(**orgao) for orgao in self._filtros["orgaos"]) 

74 

75 def listar_unidades(self) -> Lista[Unidade]: 

76 self._carregar_filtros() 

77 

78 if not self._filtros or "unidades" not in self._filtros: 

79 return Lista() 

80 

81 return Lista(Unidade(**unidade) for unidade in self._filtros["unidades"]) 

82 

83 def listar_ufs(self) -> Lista[UnidadeDaFederacao]: 

84 self._carregar_filtros() 

85 

86 if not self._filtros or "ufs" not in self._filtros: 

87 return Lista() 

88 

89 return Lista(UnidadeDaFederacao(**uf) for uf in self._filtros["ufs"]) 

90 

91 def listar_municipios(self) -> Lista[Municipio]: 

92 self._carregar_filtros() 

93 

94 if not self._filtros or "municipios" not in self._filtros: 

95 return Lista() 

96 

97 return Lista(Municipio(**municipio) for municipio in self._filtros["municipios"]) 

98 

99 def listar_esferas(self) -> Lista[Esfera]: 

100 self._carregar_filtros() 

101 

102 if not self._filtros or "esferas" not in self._filtros: 

103 return Lista() 

104 

105 return Lista(Esfera(**esfera) for esfera in self._filtros["esferas"]) 

106 

107 def listar_poderes(self) -> Lista[Poder]: 

108 self._carregar_filtros() 

109 

110 if not self._filtros or "poderes" not in self._filtros: 

111 return Lista() 

112 

113 return Lista(Poder(**poder) for poder in self._filtros["poderes"]) 

114 

115 def listar_anos(self) -> Lista[Ano]: 

116 self._carregar_filtros() 

117 

118 if not self._filtros or "anos" not in self._filtros: 

119 return Lista() 

120 

121 return Lista(Ano(**ano) for ano in self._filtros["anos"]) 

122 

123 def listar_fontes_orcamentarias(self) -> Lista[FonteOrcamentaria]: 

124 self._carregar_filtros() 

125 

126 if not self._filtros or "fontes_orcamentarias" not in self._filtros: 

127 return Lista() 

128 

129 return Lista( 

130 FonteOrcamentaria(**fonte_orcamentaria) 

131 for fonte_orcamentaria in self._filtros["fontes_orcamentarias"] 

132 ) 

133 

134 @property 

135 def texto(self) -> str: 

136 return self._campos_de_busca.q 

137 

138 @property 

139 def pagina(self) -> int: 

140 return self._campos_de_busca.pagina 

141 

142 @property 

143 def tam_pagina(self) -> int: 

144 return self._campos_de_busca.tam_pagina 

145 

146 @property 

147 def status(self) -> Status: 

148 return ( 

149 self.listar_status() 

150 .filtrar(lambda status: status.id == self._campos_de_busca.status) 

151 .pop() 

152 ) 

153 

154 @property 

155 def instrumentos_convocatorios(self) -> Lista[InstrumentoConvocatorio]: 

156 return Lista( 

157 instrumento_convocatorio 

158 for instrumento_convocatorio in self.listar_instrumentos_convocatorios() 

159 if instrumento_convocatorio.id in self._campos_de_busca.tipos 

160 ) 

161 

162 @property 

163 def modalidades_de_contratacao(self) -> Lista[ModalidadeDeContratacao]: 

164 return Lista( 

165 modalidade_de_contratacao 

166 for modalidade_de_contratacao in self.listar_modalidades_de_contratacao() 

167 if modalidade_de_contratacao.id in self._campos_de_busca.modalidades 

168 ) 

169 

170 @property 

171 def orgaos(self) -> Lista[Orgao]: 

172 return Lista( 

173 orgao for orgao in self.listar_orgaos() if orgao.id in self._campos_de_busca.orgaos 

174 ) 

175 

176 @property 

177 def unidades(self) -> Lista[Unidade]: 

178 return Lista( 

179 unidade 

180 for unidade in self.listar_unidades() 

181 if unidade.id in self._campos_de_busca.unidades 

182 ) 

183 

184 @property 

185 def ufs(self) -> Lista[UnidadeDaFederacao]: 

186 return Lista(uf for uf in self.listar_ufs() if uf.id in self._campos_de_busca.ufs) 

187 

188 @property 

189 def municipios(self) -> Lista[Municipio]: 

190 return Lista( 

191 municipio 

192 for municipio in self.listar_municipios() 

193 if municipio.id in self._campos_de_busca.municipios 

194 ) 

195 

196 @property 

197 def esferas(self) -> Lista[Esfera]: 

198 return Lista( 

199 esfera for esfera in self.listar_esferas() if esfera.id in self._campos_de_busca.esferas 

200 ) 

201 

202 @property 

203 def poderes(self) -> Lista[Poder]: 

204 return Lista( 

205 poder for poder in self.listar_poderes() if poder.id in self._campos_de_busca.poderes 

206 ) 

207 

208 @property 

209 def anos(self) -> Lista[Ano]: 

210 return Lista(ano for ano in self.listar_anos() if ano.ano in self._campos_de_busca.anos) 

211 

212 @property 

213 def fontes_orcamentarias(self) -> Lista[FonteOrcamentaria]: 

214 return Lista( 

215 fonte_orcamentaria 

216 for fonte_orcamentaria in self.listar_fontes_orcamentarias() 

217 if fonte_orcamentaria.id in self._campos_de_busca.fontes_orcamentarias 

218 ) 

219 

220 @property 

221 def resultados(self) -> Lista[Resultado]: 

222 if self._resultados is not None: 

223 return self._resultados 

224 data = pncp.utils.get_one( 

225 self._url_busca, 

226 params=self._campos_de_busca.como_dicionario(), 

227 ) 

228 self._resultados = Lista(Resultado(**resultado) for resultado in data["items"]) 

229 return self._resultados 

230 

231 @texto.setter 

232 def texto(self, texto: str): 

233 self._verificar_se_existem_resultados() 

234 self._campos_de_busca.q = texto 

235 

236 @pagina.setter 

237 def pagina(self, pagina: int): 

238 self._verificar_se_existem_resultados() 

239 self._campos_de_busca.pagina = pagina 

240 

241 @tam_pagina.setter 

242 def tam_pagina(self, tam_pagina: int): 

243 self._verificar_se_existem_resultados() 

244 self._campos_de_busca.tam_pagina = tam_pagina 

245 

246 @status.setter 

247 def status(self, status: Id | Status): 

248 self._verificar_se_existem_resultados() 

249 

250 status_id = status.id if isinstance(status, Status) else status 

251 valid_ids = [s.id for s in self.listar_status()] 

252 if status_id not in valid_ids: 

253 raise ValueError(f"Status inválido: {status}") 

254 

255 self._campos_de_busca.status = status_id 

256 

257 @instrumentos_convocatorios.setter 

258 def instrumentos_convocatorios( 

259 self, instrumentos_convocatorios: Iterable[Id] | Iterable[InstrumentoConvocatorio] 

260 ): 

261 self._verificar_se_existem_resultados() 

262 self._campos_de_busca.tipos = Lista( 

263 instrumento.id if isinstance(instrumento, InstrumentoConvocatorio) else instrumento 

264 for instrumento in instrumentos_convocatorios 

265 ) 

266 

267 @modalidades_de_contratacao.setter 

268 def modalidades_de_contratacao( 

269 self, modalidades_de_contratacao: Iterable[Id] | Iterable[ModalidadeDeContratacao] 

270 ): 

271 self._verificar_se_existem_resultados() 

272 self._campos_de_busca.modalidades = Lista( 

273 modalidade.id if isinstance(modalidade, ModalidadeDeContratacao) else modalidade 

274 for modalidade in modalidades_de_contratacao 

275 ) 

276 

277 @orgaos.setter 

278 def orgaos(self, orgaos: Iterable[Id] | Iterable[Orgao]): 

279 self._verificar_se_existem_resultados() 

280 self._campos_de_busca.orgaos = Lista( 

281 orgao.id if isinstance(orgao, Orgao) else orgao for orgao in orgaos 

282 ) 

283 

284 @unidades.setter 

285 def unidades(self, unidades: Iterable[Id] | Iterable[Unidade]): 

286 self._campos_de_busca.unidades = Lista( 

287 unidade.id if isinstance(unidade, Unidade) else unidade for unidade in unidades 

288 ) 

289 

290 @ufs.setter 

291 def ufs(self, ufs: Iterable[Id] | Iterable[UnidadeDaFederacao]): 

292 self._verificar_se_existem_resultados() 

293 self._campos_de_busca.ufs = Lista( 

294 uf.id if isinstance(uf, UnidadeDaFederacao) else uf for uf in ufs 

295 ) 

296 

297 @municipios.setter 

298 def municipios(self, municipios: Iterable[Id] | Iterable[Municipio]): 

299 self._verificar_se_existem_resultados() 

300 self._campos_de_busca.municipios = Lista( 

301 municipio.id if isinstance(municipio, Municipio) else municipio 

302 for municipio in municipios 

303 ) 

304 

305 @esferas.setter 

306 def esferas(self, esferas: Iterable[Id] | Iterable[Esfera]): 

307 self._verificar_se_existem_resultados() 

308 self._campos_de_busca.esferas = Lista( 

309 esfera.id if isinstance(esfera, Esfera) else esfera for esfera in esferas 

310 ) 

311 

312 @poderes.setter 

313 def poderes(self, poderes: Iterable[Id] | Iterable[Poder]): 

314 self._verificar_se_existem_resultados() 

315 self._campos_de_busca.poderes = Lista( 

316 poder.id if isinstance(poder, Poder) else poder for poder in poderes 

317 ) 

318 

319 @anos.setter 

320 def anos(self, anos: Iterable[Id] | Iterable[Ano]): 

321 self._verificar_se_existem_resultados() 

322 self._campos_de_busca.anos = Lista(ano.ano if isinstance(ano, Ano) else ano for ano in anos) 

323 

324 @fontes_orcamentarias.setter 

325 def fontes_orcamentarias( 

326 self, fontes_orcamentarias: Iterable[Id] | Iterable[FonteOrcamentaria] 

327 ): 

328 self._verificar_se_existem_resultados() 

329 self._campos_de_busca.fontes_orcamentarias = Lista( 

330 fonte.id if isinstance(fonte, FonteOrcamentaria) else fonte 

331 for fonte in fontes_orcamentarias 

332 ) 

333 

334 def preencher_texto(self, texto: str): 

335 self.texto = texto 

336 

337 def preencher_pagina(self, pagina: int): 

338 self.pagina = pagina 

339 

340 def preencher_tam_pagina(self, tam_pagina: int): 

341 self.tam_pagina = tam_pagina 

342 

343 def preencher_status(self, status: Id | Status): 

344 self.status = status 

345 

346 def preencher_instrumentos_convocatorios( 

347 self, instrumentos_convocatorios: Iterable[Id] | Iterable[InstrumentoConvocatorio] 

348 ): 

349 self.instrumentos_convocatorios = instrumentos_convocatorios 

350 

351 def preencher_modalidades_de_contratacao( 

352 self, modalidades_de_contratacao: Iterable[Id] | Iterable[ModalidadeDeContratacao] 

353 ): 

354 self.modalidades_de_contratacao = modalidades_de_contratacao 

355 

356 def preencher_orgaos(self, orgaos: Iterable[Id] | Iterable[Orgao]): 

357 self.orgaos = orgaos 

358 

359 def preencher_unidades(self, unidades: Iterable[Id] | Iterable[Unidade]): 

360 self.unidades = unidades 

361 

362 def preencher_ufs(self, ufs: Iterable[Id] | Iterable[UnidadeDaFederacao]): 

363 self.ufs = ufs 

364 

365 def preencher_municipios(self, municipios: Iterable[Id] | Iterable[Municipio]): 

366 self.municipios = municipios 

367 

368 def preencher_esferas(self, esferas: Iterable[Id] | Iterable[Esfera]): 

369 self.esferas = esferas 

370 

371 def preencher_poderes(self, poderes: Iterable[Id] | Iterable[Poder]): 

372 self.poderes = poderes 

373 

374 def preencher_anos(self, anos: Iterable[Id] | Iterable[Ano]): 

375 self.anos = anos 

376 

377 def preencher_fontes_orcamentarias( 

378 self, fontes_orcamentarias: Iterable[Id] | Iterable[FonteOrcamentaria] 

379 ): 

380 self.fontes_orcamentarias = fontes_orcamentarias 

381 

382 def preencher( 

383 self, 

384 texto: str | None = None, 

385 pagina: int | None = None, 

386 tam_pagina: int | None = None, 

387 status: Id | Status | None = None, 

388 instrumentos_convocatorios: Iterable[Id] | Iterable[InstrumentoConvocatorio] | None = None, 

389 modalidades_de_contratacao: Iterable[Id] | Iterable[ModalidadeDeContratacao] | None = None, 

390 orgaos: Iterable[Id] | Iterable[Orgao] | None = None, 

391 unidades: Iterable[Id] | Iterable[Unidade] | None = None, 

392 ufs: Iterable[Id] | Iterable[UnidadeDaFederacao] | None = None, 

393 municipios: Iterable[Id] | Iterable[Municipio] | None = None, 

394 esferas: Iterable[Id] | Iterable[Esfera] | None = None, 

395 poderes: Iterable[Id] | Iterable[Poder] | None = None, 

396 anos: Iterable[Id] | Iterable[Ano] | None = None, 

397 fontes_orcamentarias: Iterable[Id] | Iterable[FonteOrcamentaria] | None = None, 

398 ): 

399 kwargs = {k: v for k, v in locals().items() if k != "self" and v is not None} 

400 for key, value in kwargs.items(): 

401 setattr(self, key, value) 

402 

403 def buscar(self): 

404 return self.resultados