api-doacao-sangue 1.0.1__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.
Files changed (39) hide show
  1. api_doacao_sangue-1.0.1/PKG-INFO +98 -0
  2. api_doacao_sangue-1.0.1/README.md +82 -0
  3. api_doacao_sangue-1.0.1/api_doacao_sangue/__init__.py +0 -0
  4. api_doacao_sangue-1.0.1/api_doacao_sangue/__main__.py +4 -0
  5. api_doacao_sangue-1.0.1/api_doacao_sangue/cli.py +6 -0
  6. api_doacao_sangue-1.0.1/api_doacao_sangue/config.py +6 -0
  7. api_doacao_sangue-1.0.1/api_doacao_sangue/database.py +22 -0
  8. api_doacao_sangue-1.0.1/api_doacao_sangue/main.py +34 -0
  9. api_doacao_sangue-1.0.1/api_doacao_sangue/models.py +63 -0
  10. api_doacao_sangue-1.0.1/api_doacao_sangue/routes/__init__.py +0 -0
  11. api_doacao_sangue-1.0.1/api_doacao_sangue/routes/campanhas.py +112 -0
  12. api_doacao_sangue-1.0.1/api_doacao_sangue/routes/cidades.py +41 -0
  13. api_doacao_sangue-1.0.1/api_doacao_sangue/routes/compatibilidade.py +58 -0
  14. api_doacao_sangue-1.0.1/api_doacao_sangue/routes/estoques.py +173 -0
  15. api_doacao_sangue-1.0.1/api_doacao_sangue/routes/fontes.py +101 -0
  16. api_doacao_sangue-1.0.1/api_doacao_sangue/routes/hemocentros.py +109 -0
  17. api_doacao_sangue-1.0.1/api_doacao_sangue/routes/integracoes.py +547 -0
  18. api_doacao_sangue-1.0.1/api_doacao_sangue/scheduler.py +60 -0
  19. api_doacao_sangue-1.0.1/api_doacao_sangue/schemas.py +99 -0
  20. api_doacao_sangue-1.0.1/api_doacao_sangue/services/__init__.py +0 -0
  21. api_doacao_sangue-1.0.1/api_doacao_sangue/services/hemepar.py +44 -0
  22. api_doacao_sangue-1.0.1/api_doacao_sangue/services/hemoba.py +54 -0
  23. api_doacao_sangue-1.0.1/api_doacao_sangue/services/hemoce.py +51 -0
  24. api_doacao_sangue-1.0.1/api_doacao_sangue/services/hemoes.py +47 -0
  25. api_doacao_sangue-1.0.1/api_doacao_sangue/services/hemominas.py +79 -0
  26. api_doacao_sangue-1.0.1/api_doacao_sangue/services/hemopa.py +54 -0
  27. api_doacao_sangue-1.0.1/api_doacao_sangue/services/hemosc.py +42 -0
  28. api_doacao_sangue-1.0.1/api_doacao_sangue/services/hemosul.py +54 -0
  29. api_doacao_sangue-1.0.1/api_doacao_sangue/services/scraper.py +6 -0
  30. api_doacao_sangue-1.0.1/api_doacao_sangue/utils/__init__.py +0 -0
  31. api_doacao_sangue-1.0.1/api_doacao_sangue/utils/helpers.py +2 -0
  32. api_doacao_sangue-1.0.1/api_doacao_sangue.egg-info/PKG-INFO +98 -0
  33. api_doacao_sangue-1.0.1/api_doacao_sangue.egg-info/SOURCES.txt +37 -0
  34. api_doacao_sangue-1.0.1/api_doacao_sangue.egg-info/dependency_links.txt +1 -0
  35. api_doacao_sangue-1.0.1/api_doacao_sangue.egg-info/entry_points.txt +2 -0
  36. api_doacao_sangue-1.0.1/api_doacao_sangue.egg-info/requires.txt +9 -0
  37. api_doacao_sangue-1.0.1/api_doacao_sangue.egg-info/top_level.txt +1 -0
  38. api_doacao_sangue-1.0.1/pyproject.toml +28 -0
  39. api_doacao_sangue-1.0.1/setup.cfg +4 -0
@@ -0,0 +1,98 @@
1
+ Metadata-Version: 2.4
2
+ Name: api-doacao-sangue
3
+ Version: 1.0.1
4
+ Summary: API aberta para integração e padronização de dados sobre doação de sangue no Brasil.
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: APScheduler<4,>=3.10
8
+ Requires-Dist: beautifulsoup4>=4.12
9
+ Requires-Dist: fastapi>=0.115
10
+ Requires-Dist: pydantic>=2.0
11
+ Requires-Dist: python-dotenv>=1.0
12
+ Requires-Dist: requests>=2.31
13
+ Requires-Dist: selenium>=4.20
14
+ Requires-Dist: SQLAlchemy>=2.0
15
+ Requires-Dist: uvicorn[standard]>=0.30
16
+
17
+ # API Aberta de Doação de Sangue
18
+
19
+ API REST para integração, padronização e disponibilização de dados públicos sobre doação de sangue no Brasil.
20
+
21
+ ## Instalação como pacote Python
22
+
23
+ Requer Python 3.10 ou superior.
24
+
25
+ ```bash
26
+ python -m venv .venv
27
+ ```
28
+
29
+ Ative o ambiente virtual:
30
+
31
+ - Windows: `.venv\\Scripts\\activate`
32
+ - Linux/macOS: `source .venv/bin/activate`
33
+
34
+ Instale diretamente do diretório do projeto:
35
+
36
+ ```bash
37
+ python -m pip install .
38
+ ```
39
+
40
+ ## Execução
41
+
42
+ Depois da instalação, inicie a API com:
43
+
44
+ ```bash
45
+ api-doacao-sangue
46
+ ```
47
+
48
+ Alternativamente:
49
+
50
+ ```bash
51
+ python -m api_doacao_sangue
52
+ ```
53
+
54
+ A API ficará disponível localmente em `http://127.0.0.1:8000`.
55
+
56
+ - Documentação Swagger: `http://127.0.0.1:8000/docs`
57
+ - Documentação ReDoc: `http://127.0.0.1:8000/redoc`
58
+
59
+ Para desenvolvimento, também é possível executar:
60
+
61
+ ```bash
62
+ uvicorn api_doacao_sangue.main:app --reload
63
+ ```
64
+
65
+ ## Banco de dados
66
+
67
+ Por padrão, o SQLite cria o arquivo `api_doacao_sangue.db` no diretório de execução. Para configurar outro banco compatível com SQLAlchemy, defina a variável de ambiente `DATABASE_URL`.
68
+
69
+ Exemplo no PowerShell:
70
+
71
+ ```powershell
72
+ $env:DATABASE_URL="sqlite:///./meu_banco.db"
73
+ ```
74
+
75
+ Exemplo no Linux/macOS:
76
+
77
+ ```bash
78
+ export DATABASE_URL="sqlite:///./meu_banco.db"
79
+ ```
80
+
81
+ ## Funcionalidades
82
+
83
+ - CRUD de hemocentros, estoques, campanhas e fontes de dados
84
+ - Consulta de compatibilidade sanguínea
85
+ - Integrações com Hemominas (MG), HEMOSC (SC), HEMEPAR (PR), HEMOES (ES), HEMOCE (CE), HEMOPA (PA), HEMOBA (BA) e HEMOSUL (MS)
86
+ - Consulta nacional de estoques
87
+ - Atualização agendada para as integrações configuradas no scheduler
88
+
89
+ ## Observações
90
+
91
+ - A instalação do pacote não hospeda a API na internet. Ela executa o servidor no computador ou ambiente do próprio usuário.
92
+ - A coleta da Hemominas utiliza Selenium; para essa integração, também é necessário ter um navegador compatível e seu WebDriver configurados no ambiente.
93
+ - O scheduler atual está configurado para executar atualizações de Hemominas, HEMOSC e HEMEPAR.
94
+ - O projeto utiliza SQLite por padrão. Cada instalação mantém seu próprio banco local, salvo configuração diferente por `DATABASE_URL`.
95
+
96
+ ## Tecnologias
97
+
98
+ Python, FastAPI, SQLAlchemy, SQLite, APScheduler, Requests, BeautifulSoup e Selenium.
@@ -0,0 +1,82 @@
1
+ # API Aberta de Doação de Sangue
2
+
3
+ API REST para integração, padronização e disponibilização de dados públicos sobre doação de sangue no Brasil.
4
+
5
+ ## Instalação como pacote Python
6
+
7
+ Requer Python 3.10 ou superior.
8
+
9
+ ```bash
10
+ python -m venv .venv
11
+ ```
12
+
13
+ Ative o ambiente virtual:
14
+
15
+ - Windows: `.venv\\Scripts\\activate`
16
+ - Linux/macOS: `source .venv/bin/activate`
17
+
18
+ Instale diretamente do diretório do projeto:
19
+
20
+ ```bash
21
+ python -m pip install .
22
+ ```
23
+
24
+ ## Execução
25
+
26
+ Depois da instalação, inicie a API com:
27
+
28
+ ```bash
29
+ api-doacao-sangue
30
+ ```
31
+
32
+ Alternativamente:
33
+
34
+ ```bash
35
+ python -m api_doacao_sangue
36
+ ```
37
+
38
+ A API ficará disponível localmente em `http://127.0.0.1:8000`.
39
+
40
+ - Documentação Swagger: `http://127.0.0.1:8000/docs`
41
+ - Documentação ReDoc: `http://127.0.0.1:8000/redoc`
42
+
43
+ Para desenvolvimento, também é possível executar:
44
+
45
+ ```bash
46
+ uvicorn api_doacao_sangue.main:app --reload
47
+ ```
48
+
49
+ ## Banco de dados
50
+
51
+ Por padrão, o SQLite cria o arquivo `api_doacao_sangue.db` no diretório de execução. Para configurar outro banco compatível com SQLAlchemy, defina a variável de ambiente `DATABASE_URL`.
52
+
53
+ Exemplo no PowerShell:
54
+
55
+ ```powershell
56
+ $env:DATABASE_URL="sqlite:///./meu_banco.db"
57
+ ```
58
+
59
+ Exemplo no Linux/macOS:
60
+
61
+ ```bash
62
+ export DATABASE_URL="sqlite:///./meu_banco.db"
63
+ ```
64
+
65
+ ## Funcionalidades
66
+
67
+ - CRUD de hemocentros, estoques, campanhas e fontes de dados
68
+ - Consulta de compatibilidade sanguínea
69
+ - Integrações com Hemominas (MG), HEMOSC (SC), HEMEPAR (PR), HEMOES (ES), HEMOCE (CE), HEMOPA (PA), HEMOBA (BA) e HEMOSUL (MS)
70
+ - Consulta nacional de estoques
71
+ - Atualização agendada para as integrações configuradas no scheduler
72
+
73
+ ## Observações
74
+
75
+ - A instalação do pacote não hospeda a API na internet. Ela executa o servidor no computador ou ambiente do próprio usuário.
76
+ - A coleta da Hemominas utiliza Selenium; para essa integração, também é necessário ter um navegador compatível e seu WebDriver configurados no ambiente.
77
+ - O scheduler atual está configurado para executar atualizações de Hemominas, HEMOSC e HEMEPAR.
78
+ - O projeto utiliza SQLite por padrão. Cada instalação mantém seu próprio banco local, salvo configuração diferente por `DATABASE_URL`.
79
+
80
+ ## Tecnologias
81
+
82
+ Python, FastAPI, SQLAlchemy, SQLite, APScheduler, Requests, BeautifulSoup e Selenium.
File without changes
@@ -0,0 +1,4 @@
1
+ from api_doacao_sangue.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,6 @@
1
+ import uvicorn
2
+
3
+
4
+ def main():
5
+ """Inicia a API localmente."""
6
+ uvicorn.run("api_doacao_sangue.main:app", host="127.0.0.1", port=8000)
@@ -0,0 +1,6 @@
1
+ import os
2
+ from dotenv import load_dotenv
3
+
4
+ load_dotenv()
5
+
6
+ DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./api_doacao_sangue.db")
@@ -0,0 +1,22 @@
1
+ from sqlalchemy import create_engine
2
+ from sqlalchemy.orm import sessionmaker
3
+
4
+ from api_doacao_sangue.config import DATABASE_URL
5
+
6
+ connect_args = {"check_same_thread": False} if DATABASE_URL.startswith("sqlite") else {}
7
+
8
+ engine = create_engine(DATABASE_URL, connect_args=connect_args)
9
+
10
+ SessionLocal = sessionmaker(
11
+ autocommit=False,
12
+ autoflush=False,
13
+ bind=engine
14
+ )
15
+
16
+
17
+ def get_db():
18
+ db = SessionLocal()
19
+ try:
20
+ yield db
21
+ finally:
22
+ db.close()
@@ -0,0 +1,34 @@
1
+ from fastapi import FastAPI
2
+ from api_doacao_sangue.database import engine
3
+ from api_doacao_sangue.models import Base
4
+ from api_doacao_sangue.scheduler import iniciar_scheduler
5
+
6
+ from api_doacao_sangue.routes import hemocentros, estoques, campanhas, compatibilidade, cidades, fontes, integracoes
7
+
8
+ Base.metadata.create_all(bind=engine)
9
+
10
+ app = FastAPI(
11
+ title="API Aberta de Doação de Sangue",
12
+ description="API para integração, padronização e disponibilização de dados sobre doação de sangue.",
13
+ version="1.0.0"
14
+ )
15
+
16
+ @app.on_event("startup")
17
+ def startup_event():
18
+ iniciar_scheduler()
19
+
20
+ app.include_router(fontes.router)
21
+ app.include_router(integracoes.router)
22
+ app.include_router(hemocentros.router)
23
+ app.include_router(estoques.router)
24
+ app.include_router(campanhas.router)
25
+ app.include_router(compatibilidade.router)
26
+ app.include_router(cidades.router)
27
+
28
+
29
+ @app.get("/")
30
+ def home():
31
+ return {
32
+ "mensagem": "API Doação de Sangue funcionando!",
33
+ "documentacao": "/docs"
34
+ }
@@ -0,0 +1,63 @@
1
+ from sqlalchemy.orm import DeclarativeBase
2
+ from sqlalchemy import (
3
+ Column,
4
+ Integer,
5
+ String,
6
+ Float,
7
+ ForeignKey,
8
+ DateTime,
9
+ Boolean,
10
+ )
11
+ from datetime import datetime
12
+
13
+
14
+ class Base(DeclarativeBase):
15
+ pass
16
+
17
+
18
+ class Hemocentro(Base):
19
+ __tablename__ = "hemocentros"
20
+
21
+ id = Column(Integer, primary_key=True, index=True)
22
+ nome = Column(String, nullable=False)
23
+ estado = Column(String, nullable=False)
24
+ cidade = Column(String, nullable=False)
25
+ endereco = Column(String)
26
+ telefone = Column(String)
27
+ site = Column(String)
28
+ latitude = Column(Float)
29
+ longitude = Column(Float)
30
+
31
+
32
+ class Estoque(Base):
33
+ __tablename__ = "estoques"
34
+
35
+ id = Column(Integer, primary_key=True, index=True)
36
+ hemocentro_id = Column(Integer, ForeignKey("hemocentros.id"))
37
+ tipo_sanguineo = Column(String, nullable=False)
38
+ status = Column(String, nullable=False)
39
+ fonte = Column(String)
40
+ ultima_atualizacao = Column(DateTime, default=datetime.now)
41
+
42
+
43
+ class Campanha(Base):
44
+ __tablename__ = "campanhas"
45
+
46
+ id = Column(Integer, primary_key=True, index=True)
47
+ titulo = Column(String, nullable=False)
48
+ descricao = Column(String)
49
+ estado = Column(String, nullable=False)
50
+ cidade = Column(String, nullable=False)
51
+ data_inicio = Column(DateTime)
52
+ data_fim = Column(DateTime)
53
+ ativa = Column(Boolean, default=True)
54
+
55
+
56
+ class FonteDados(Base):
57
+ __tablename__ = "fontes_dados"
58
+
59
+ id = Column(Integer, primary_key=True, index=True)
60
+ nome = Column(String, nullable=False)
61
+ url = Column(String, nullable=False)
62
+ estado = Column(String)
63
+ descricao = Column(String)
@@ -0,0 +1,112 @@
1
+ from fastapi import APIRouter, Depends, HTTPException
2
+ from sqlalchemy.orm import Session
3
+
4
+ from api_doacao_sangue.database import get_db
5
+ from api_doacao_sangue.models import Campanha
6
+ from api_doacao_sangue.schemas import (
7
+ CampanhaCreate,
8
+ CampanhaUpdate,
9
+ CampanhaResponse
10
+ )
11
+
12
+ router = APIRouter(
13
+ prefix="/campanhas",
14
+ tags=["Campanhas"]
15
+ )
16
+
17
+
18
+ @router.post("/", response_model=CampanhaResponse)
19
+ def criar_campanha(
20
+ dados: CampanhaCreate,
21
+ db: Session = Depends(get_db)
22
+ ):
23
+ campanha = Campanha(**dados.model_dump())
24
+
25
+ db.add(campanha)
26
+ db.commit()
27
+ db.refresh(campanha)
28
+
29
+ return campanha
30
+
31
+
32
+ @router.get("/", response_model=list[CampanhaResponse])
33
+ def listar_campanhas(
34
+ estado: str | None = None,
35
+ cidade: str | None = None,
36
+ db: Session = Depends(get_db)
37
+ ):
38
+ consulta = db.query(Campanha)
39
+
40
+ if estado:
41
+ consulta = consulta.filter(Campanha.estado == estado)
42
+
43
+ if cidade:
44
+ consulta = consulta.filter(Campanha.cidade == cidade)
45
+
46
+ return consulta.all()
47
+
48
+
49
+ @router.get("/ativas", response_model=list[CampanhaResponse])
50
+ def campanhas_ativas(
51
+ db: Session = Depends(get_db)
52
+ ):
53
+ return db.query(Campanha).filter(
54
+ Campanha.ativa == True
55
+ ).all()
56
+
57
+
58
+ @router.get("/{campanha_id}", response_model=CampanhaResponse)
59
+ def buscar_campanha(
60
+ campanha_id: int,
61
+ db: Session = Depends(get_db)
62
+ ):
63
+ campanha = db.query(Campanha).filter(
64
+ Campanha.id == campanha_id
65
+ ).first()
66
+
67
+ if not campanha:
68
+ raise HTTPException(404, "Campanha não encontrada")
69
+
70
+ return campanha
71
+
72
+
73
+ @router.put("/{campanha_id}", response_model=CampanhaResponse)
74
+ def atualizar_campanha(
75
+ campanha_id: int,
76
+ dados: CampanhaUpdate,
77
+ db: Session = Depends(get_db)
78
+ ):
79
+ campanha = db.query(Campanha).filter(
80
+ Campanha.id == campanha_id
81
+ ).first()
82
+
83
+ if not campanha:
84
+ raise HTTPException(404, "Campanha não encontrada")
85
+
86
+ for campo, valor in dados.model_dump().items():
87
+ setattr(campanha, campo, valor)
88
+
89
+ db.commit()
90
+ db.refresh(campanha)
91
+
92
+ return campanha
93
+
94
+
95
+ @router.delete("/{campanha_id}")
96
+ def deletar_campanha(
97
+ campanha_id: int,
98
+ db: Session = Depends(get_db)
99
+ ):
100
+ campanha = db.query(Campanha).filter(
101
+ Campanha.id == campanha_id
102
+ ).first()
103
+
104
+ if not campanha:
105
+ raise HTTPException(404, "Campanha não encontrada")
106
+
107
+ db.delete(campanha)
108
+ db.commit()
109
+
110
+ return {
111
+ "mensagem": "Campanha removida com sucesso"
112
+ }
@@ -0,0 +1,41 @@
1
+ from fastapi import APIRouter, Depends
2
+ from sqlalchemy.orm import Session
3
+
4
+ from api_doacao_sangue.database import get_db
5
+ from api_doacao_sangue.models import Hemocentro
6
+
7
+ router = APIRouter(
8
+ prefix="/cidades",
9
+ tags=["Cidades"]
10
+ )
11
+
12
+
13
+ @router.get("/")
14
+ def listar_cidades(db: Session = Depends(get_db)):
15
+ cidades = db.query(
16
+ Hemocentro.estado,
17
+ Hemocentro.cidade
18
+ ).distinct().all()
19
+
20
+ return [
21
+ {
22
+ "estado": estado,
23
+ "cidade": cidade
24
+ }
25
+ for estado, cidade in cidades
26
+ ]
27
+
28
+
29
+ @router.get("/{estado}")
30
+ def listar_cidades_por_estado(
31
+ estado: str,
32
+ db: Session = Depends(get_db)
33
+ ):
34
+ cidades = db.query(Hemocentro.cidade).filter(
35
+ Hemocentro.estado == estado.upper()
36
+ ).distinct().all()
37
+
38
+ return [
39
+ cidade[0]
40
+ for cidade in cidades
41
+ ]
@@ -0,0 +1,58 @@
1
+ from fastapi import APIRouter, HTTPException
2
+
3
+ router = APIRouter(
4
+ prefix="/compatibilidade",
5
+ tags=["Compatibilidade"]
6
+ )
7
+
8
+ COMPATIBILIDADE = {
9
+ "O-": {
10
+ "recebe_de": ["O-"],
11
+ "doa_para": ["O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"]
12
+ },
13
+ "O+": {
14
+ "recebe_de": ["O-", "O+"],
15
+ "doa_para": ["O+", "A+", "B+", "AB+"]
16
+ },
17
+ "A-": {
18
+ "recebe_de": ["O-", "A-"],
19
+ "doa_para": ["A-", "A+", "AB-", "AB+"]
20
+ },
21
+ "A+": {
22
+ "recebe_de": ["O-", "O+", "A-", "A+"],
23
+ "doa_para": ["A+", "AB+"]
24
+ },
25
+ "B-": {
26
+ "recebe_de": ["O-", "B-"],
27
+ "doa_para": ["B-", "B+", "AB-", "AB+"]
28
+ },
29
+ "B+": {
30
+ "recebe_de": ["O-", "O+", "B-", "B+"],
31
+ "doa_para": ["B+", "AB+"]
32
+ },
33
+ "AB-": {
34
+ "recebe_de": ["O-", "A-", "B-", "AB-"],
35
+ "doa_para": ["AB-", "AB+"]
36
+ },
37
+ "AB+": {
38
+ "recebe_de": ["O-", "O+", "A-", "A+", "B-", "B+", "AB-", "AB+"],
39
+ "doa_para": ["AB+"]
40
+ }
41
+ }
42
+
43
+
44
+ @router.get("/{tipo}")
45
+ def consultar_compatibilidade(tipo: str):
46
+ tipo = tipo.upper()
47
+
48
+ if tipo not in COMPATIBILIDADE:
49
+ raise HTTPException(
50
+ status_code=404,
51
+ detail="Tipo sanguíneo inválido"
52
+ )
53
+
54
+ return {
55
+ "tipo_sanguineo": tipo,
56
+ "recebe_de": COMPATIBILIDADE[tipo]["recebe_de"],
57
+ "doa_para": COMPATIBILIDADE[tipo]["doa_para"]
58
+ }