Skip to content

Commit

Permalink
Upgrade fastapi to 0.114.1
Browse files Browse the repository at this point in the history
Which triggers an upgrade to pydantic, and a bunch of validation failures
  • Loading branch information
rralcala committed Sep 14, 2024
1 parent 49c357f commit 39572bf
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 34 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ LINKA is an open source service to record air quality data from community sensor

## Install

Python 3.12 is not yet supported

```
$ sudo dnf install python3-virtualenv python-devel libpq-devel
$ virtualenv env
Expand Down
11 changes: 6 additions & 5 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ async def stats(db, query):
]
)

select = sqlalchemy.select(measurements_stats)
select = sqlalchemy.select(*measurements_stats)
select = select.group_by(
measurements.c.sensor,
measurements.c.source,
Expand Down Expand Up @@ -166,8 +166,9 @@ async def create_new_key(db: Database, provider: str) -> str:
@staticmethod
async def get_providers(db: Database) -> List[Tuple[str, int]]:
query = sqlalchemy.select(
[providers.c.provider, sqlalchemy.func.count(providers.c.provider)]
).group_by(providers.c.provider)
providers.c.provider, sqlalchemy.func.count(providers.c.provider)
)
query = query.group_by(providers.c.provider)
query = query.order_by(sqlalchemy.asc(providers.c.provider))
return await db.fetch_all(query)

Expand All @@ -187,14 +188,14 @@ async def revoke_all_keys(db: Database, provider: str) -> bool:

@staticmethod
async def get_all_keys(db: Database) -> Set[str]:
query = sqlalchemy.select([providers.c.api_key_hash])
query = sqlalchemy.select(providers.c.api_key_hash)
query = query.order_by(sqlalchemy.asc(providers.c.provider))
keys = await db.fetch_all(query)
return {k[0] for k in keys}

@staticmethod
async def get_provider_for_key(db: Database, api_key_hash: str) -> Union[str, None]:
query = sqlalchemy.select([providers.c.id, providers.c.api_key_hash])
query = sqlalchemy.select(providers.c.id, providers.c.api_key_hash)
query = query.where(providers.c.api_key_hash == api_key_hash)
provider = await db.fetch_one(query)
return provider[0] if provider else None
8 changes: 5 additions & 3 deletions app/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ def get_quality(source):
breakpoint_index = CONCENTRATIONS.index(concentration)
breakpoint = BREAKPOINTS[breakpoint_index]

index = (
(breakpoint[1] - breakpoint[0]) / (concentration[1] - concentration[0])
) * (source.pm2dot5_average - concentration[0]) + breakpoint[0]
index = int(
((breakpoint[1] - breakpoint[0]) / (concentration[1] - concentration[0]))
* (source.pm2dot5_average - concentration[0])
+ breakpoint[0]
)
index_breakpoint = next(
(b for b in BREAKPOINTS if index <= b[1]),
BREAKPOINTS[-1],
Expand Down
16 changes: 9 additions & 7 deletions app/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,36 +125,37 @@ def to_orm(self, provider):

class Config:
orm_mode = True
from_attributes = True


@dataclass
class QueryParams:
source: str = Query(
source: Optional[str] = Query(
None,
title="Source",
description="Include measurements from this source only",
)
start: datetime = Query(
start: Optional[datetime] = Query(
None,
title="Start",
description="Include measurements after this date and time",
)
end: datetime = Query(
end: Optional[datetime] = Query(
None,
title="End",
description="Include measurements before this date and time",
)
longitude: float = Query(
longitude: Optional[float] = Query(
None,
title="Longitude",
description="Target longitude coordinate",
)
latitude: float = Query(
latitude: Optional[float] = Query(
None,
title="Latitude",
description="Target latitude coordinate",
)
distance: float = Query(
distance: Optional[float] = Query(
None,
title="Distance",
description="Include measurements that are this kilometers far from the target",
Expand All @@ -175,6 +176,7 @@ class Provider(BaseModel):

class Config:
orm_mode = True
from_attributes = True


class APIKey(BaseModel):
Expand Down Expand Up @@ -233,7 +235,7 @@ class Report(BaseModel):
title="Latitude",
description="Target latitude coordinate",
)
quality: Quality = Field(
quality: Optional[Quality] = Field(
None,
title="Quality",
description="Quality according to AQI",
Expand Down
20 changes: 9 additions & 11 deletions app/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from contextlib import asynccontextmanager
from fastapi import FastAPI, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security.api_key import APIKey
Expand All @@ -25,7 +26,14 @@
from .authentication import validate_api_key, validate_master_key


app = FastAPI()
@asynccontextmanager
async def lifespan(app: FastAPI):
await db.connect()
yield
await db.disconnect()


app = FastAPI(lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
Expand All @@ -35,16 +43,6 @@
)


@app.on_event("startup")
async def startup():
await db.connect()


@app.on_event("shutdown")
async def shutdown():
await db.disconnect()


@app.post("/api/v1/providers", response_model=schemas.APIKey)
async def create_provider(
provider: schemas.Provider, key: APIKey = Depends(validate_master_key)
Expand Down
9 changes: 5 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fastapi==0.94.1
fastapi==0.114.1
httpx==0.23.3
uvicorn==0.21.0
gunicorn==20.1.0
Expand All @@ -9,8 +9,9 @@ black==23.1.0
aiosqlite==0.18.0
databases==0.7.0
SQLAlchemy==1.4.46
asyncpg==0.27.0
psycopg2-binary==2.9.5
asyncpg==0.29.0
psycopg2-binary==2.9.9
alembic==1.10.2
geopy==2.3.0
pytest-dependency==0.5.1
pytest-dependency==0.5.1
pydantic==2.9.1
8 changes: 4 additions & 4 deletions tests/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"co2": 1000.0,
"longitude": -57.521369,
"latitude": -25.194156,
"recorded": "2020-10-24T20:47:57.370721+00:00",
"recorded": "2020-10-24T20:47:57.370721Z",
},
{
"sensor": "nullable",
Expand All @@ -59,7 +59,7 @@
"co2": None,
"longitude": -57.521369,
"latitude": -25.194156,
"recorded": "2020-10-24T20:47:57.370721+00:00",
"recorded": "2020-10-24T20:47:57.370721Z",
},
{
"sensor": "test",
Expand All @@ -75,7 +75,7 @@
"co2": 200.0,
"longitude": -57.521369,
"latitude": -25.194156,
"recorded": "2020-10-24T20:47:57.370721+00:00",
"recorded": "2020-10-24T20:47:57.370721Z",
},
]
aqi = [
Expand Down Expand Up @@ -322,7 +322,7 @@ def test_delete_provider(client):
@pytest.mark.dependency(depends=["test_delete_provider"])
def test_empty_measurements(client):
query = {
"start": "1984-04-24T00:00:00",
"start": "2984-04-24T00:00:00",
}

response = client.get(f"/api/v1/measurements?{urlencode(query)}")
Expand Down

0 comments on commit 39572bf

Please sign in to comment.