Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
python-version: 3.13
- name: Install Linters
run: |
pip install \
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ jobs:
python-test:
runs-on: ubuntu-latest
steps:
- run: sudo apt-get install graphviz
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
Expand All @@ -29,10 +28,10 @@ jobs:
python-test-install:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- run: sudo apt-get install graphviz
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
Expand All @@ -52,10 +51,10 @@ jobs:
python-edge-test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
steps:
- run: sudo apt-get install graphviz
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
Expand Down
23 changes: 7 additions & 16 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@
# pattern is able to reduce each image to ~250MB but takes considerable
# time to build and is considerably more complex for scipy and pandas.

FROM node:20.19-bullseye AS frontend
FROM node:24.10-trixie AS frontend
WORKDIR /app
COPY ./nereid/nereid/static/frontend .
RUN npm install . && npm run build
CMD ["bash", "-c", "while true; do sleep 1; done"]


FROM python:3.11.12-bullseye AS nereid_install
RUN apt-get update -y \
&& apt-get install -y --no-install-recommends graphviz \
&& rm -rf /var/lib/apt/lists/*
FROM python:3.13.8-trixie AS nereid_install
WORKDIR /nereid
CMD ["bash", "-c", "while true; do sleep 1; done"]

Expand All @@ -24,9 +21,9 @@ COPY nereid/redis.conf /redis.conf
CMD ["redis-server", "/redis.conf"]


FROM python:3.11.12-alpine3.21 AS flower
FROM python:3.13.8-alpine3.22 AS flower
RUN apk add --no-cache ca-certificates tzdata && update-ca-certificates
RUN pip install --no-cache-dir redis==4.6.0 flower==1.0.0 celery==5.3.4
RUN pip install --no-cache-dir redis==5.2.1 flower==2.0.1 celery==5.5.3
ENV PYTHONUNBUFFERED=1 PYTHONHASHSEED=random PYTHONDONTWRITEBYTECODE=1
ENV FLOWER_DATA_DIR=/data
ENV PYTHONPATH=${FLOWER_DATA_DIR}
Expand All @@ -45,7 +42,7 @@ EXPOSE 5555
CMD ["celery", "flower"]


FROM python:3.11.12-bullseye AS core-env
FROM python:3.13.8-trixie AS core-env
RUN apt-get update && apt-get install -y build-essential curl
ADD https://astral.sh/uv/0.6.14/install.sh /install.sh
RUN sh /install.sh && rm /install.sh
Expand All @@ -70,10 +67,7 @@ RUN uv pip install --no-cache \
-r /requirements_dev.txt


FROM python:3.11.12-slim-bullseye AS core-runtime
RUN apt-get update -y \
&& apt-get install -y --no-install-recommends graphviz \
&& rm -rf /var/lib/apt/lists/*
FROM python:3.13.8-slim-trixie AS core-runtime
WORKDIR /nereid
ENV PYTHONPATH=/nereid
ENV PATH=/opt/venv/bin:$PATH
Expand Down Expand Up @@ -111,10 +105,7 @@ COPY --chmod=755 nereid/scripts /
CMD ["bash", "-c", "while true; do sleep 1; done"]


FROM python:3.12-bullseye AS nereid-edge
RUN apt-get update -y \
&& apt-get install -y graphviz build-essential curl \
&& rm -rf /var/lib/apt/lists/*
FROM python:3.14-trixie AS nereid-edge
ADD https://astral.sh/uv/0.6.14/install.sh /install.sh
RUN sh /install.sh && rm /install.sh
ENV PATH=/opt/venv/bin:/root/.local/bin/:$PATH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async def calculate_loading(
) -> dict[str, Any]:
land_surfaces_req = land_surfaces.model_dump(by_alias=True)

task = bg.land_surface_loading.s(
task = bg.land_surface_loading.s( # type: ignore
land_surfaces=land_surfaces_req, details=details, context=context
)

Expand All @@ -45,7 +45,7 @@ async def get_land_surface_loading_result(
request: Request,
task_id: str,
) -> dict[str, Any]:
task = bg.land_surface_loading.AsyncResult(task_id, app=router)
task = bg.land_surface_loading.AsyncResult(task_id, app=router) # type: ignore
return await standard_json_response(
request, task, "get_land_surface_loading_result"
)
31 changes: 16 additions & 15 deletions nereid/nereid/api/api_v1/endpoints_async/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ async def validate_network(
openapi_examples=network_models.GraphExamples, # type: ignore[arg-type]
),
) -> dict[str, Any]:
task = bg.validate_network.s(graph=graph.model_dump(by_alias=True))
task = bg.validate_network.s(graph=graph.model_dump(by_alias=True)) # type: ignore
return await run_task(request, task, "get_validate_network_result")


Expand All @@ -40,7 +40,7 @@ async def validate_network(
response_class=ORJSONResponse,
)
async def get_validate_network_result(request: Request, task_id: str) -> dict[str, Any]:
task = bg.validate_network.AsyncResult(task_id, app=router)
task = bg.validate_network.AsyncResult(task_id, app=router) # type: ignore
return await standard_json_response(request, task, "get_validate_network_result")


Expand All @@ -54,7 +54,7 @@ async def subgraph_network(
request: Request,
subgraph_req: network_models.SubgraphRequest = Body(...),
) -> dict[str, Any]:
task = bg.network_subgraphs.s(**subgraph_req.model_dump(by_alias=True))
task = bg.network_subgraphs.s(**subgraph_req.model_dump(by_alias=True)) # type: ignore

return await run_task(request, task, "get_subgraph_network_result")

Expand All @@ -66,7 +66,7 @@ async def subgraph_network(
response_class=ORJSONResponse,
)
async def get_subgraph_network_result(request: Request, task_id: str) -> dict[str, Any]:
task = bg.network_subgraphs.AsyncResult(task_id, app=router)
task = bg.network_subgraphs.AsyncResult(task_id, app=router) # type: ignore
return await standard_json_response(request, task, "get_subgraph_network_result")


Expand All @@ -81,26 +81,26 @@ async def get_subgraph_network_as_img(
task_id: str,
media_type: str = Query("svg"),
npi: float = Query(4.0),
timeout: float | None = Query(None, le=10.0, gt=0.0),
) -> dict[str, Any] | Any:
if media_type != "svg":
detail = f"media_type not supported: '{media_type}'."
raise HTTPException(status_code=400, detail=detail)

task = bg.network_subgraphs.AsyncResult(task_id, app=router)
task = bg.network_subgraphs.AsyncResult(task_id, app=router) # type: ignore
response = {"task_id": task.task_id, "status": task.status}

if task.successful():
result = task.result
response["data"] = task.result
render_task_id = task.task_id + f"-{media_type}-{npi}"

render_task = bg.render_subgraph_svg.AsyncResult(render_task_id, app=router)
render_task = bg.render_subgraph_svg.AsyncResult(render_task_id, app=router) # type: ignore
if not render_task.ready() and render_task.status.lower() != "started":
render_task = bg.render_subgraph_svg.apply_async(
render_task = bg.render_subgraph_svg.apply_async( # type: ignore
args=(result, npi), task_id=render_task_id
)
_ = await wait_a_sec_and_see_if_we_can_return_some_data(
render_task, timeout=10
render_task, timeout=timeout or 5.0
)

if render_task.successful():
Expand All @@ -125,7 +125,7 @@ async def network_solution_sequence(
),
min_branch_size: int = Query(4),
) -> dict[str, Any]:
task = bg.solution_sequence.s(
task = bg.solution_sequence.s( # type: ignore
graph=graph.model_dump(by_alias=True), min_branch_size=min_branch_size
)

Expand All @@ -141,7 +141,7 @@ async def network_solution_sequence(
async def get_network_solution_sequence(
request: Request, task_id: str
) -> dict[str, Any]:
task = bg.solution_sequence.AsyncResult(task_id, app=router)
task = bg.solution_sequence.AsyncResult(task_id, app=router) # type: ignore
return await standard_json_response(request, task, "get_network_solution_sequence")


Expand All @@ -156,28 +156,29 @@ async def get_network_solution_sequence_as_img(
task_id: str,
media_type: str = Query("svg"),
npi: float = Query(4.0),
timeout: float | None = Query(None, le=10.0, gt=0.0),
) -> dict[str, Any] | Any:
if media_type != "svg":
detail = f"media_type not supported: '{media_type}'."
raise HTTPException(status_code=400, detail=detail)

task = bg.solution_sequence.AsyncResult(task_id, app=router)
task = bg.solution_sequence.AsyncResult(task_id, app=router) # type: ignore
response = {"task_id": task.task_id, "status": task.status}

if task.successful():
result = task.result
response["data"] = task.result
render_task_id = task.task_id + f"-{media_type}-{npi}"

render_task = bg.render_solution_sequence_svg.AsyncResult(
render_task = bg.render_solution_sequence_svg.AsyncResult( # type: ignore
render_task_id, app=router
)
if not render_task.ready() and render_task.status.lower() != "started":
render_task = bg.render_solution_sequence_svg.apply_async(
render_task = bg.render_solution_sequence_svg.apply_async( # type: ignore
args=(result, npi), task_id=render_task_id
)
_ = await wait_a_sec_and_see_if_we_can_return_some_data(
render_task, timeout=10
render_task, timeout=timeout or 5.0
)

if render_task.successful():
Expand Down
4 changes: 2 additions & 2 deletions nereid/nereid/api/api_v1/endpoints_async/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@

@router.get("/ping", response_model=JSONAPIResponse)
async def get_ping(request: Request) -> dict[str, Any]: # pragma: no cover
task = bg.background_ping.apply_async()
task = bg.background_ping.apply_async() # type: ignore
return await standard_json_response(request, task)


@router.get("/sleep", response_model=JSONAPIResponse)
async def get_sleep(request: Request, s: int = 1) -> dict[str, Any]: # pragma: no cover
task = bg.background_sleep.s(seconds=s).apply_async()
task = bg.background_sleep.s(seconds=s).apply_async() # type: ignore
return await standard_json_response(request, task)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ async def initialize_treatment_facility_parameters(
) -> dict[str, Any]:
treatment_facilities, context = tmnt_facility_req

task = bg.initialize_treatment_facilities.s(
task = bg.initialize_treatment_facilities.s( # type: ignore
treatment_facilities=treatment_facilities.model_dump(),
pre_validated=True,
context=context,
Expand All @@ -60,7 +60,7 @@ async def initialize_treatment_facility_parameters(
async def get_treatment_facility_parameters(
request: Request, task_id: str
) -> dict[str, Any]:
task = bg.initialize_treatment_facilities.AsyncResult(task_id, app=router)
task = bg.initialize_treatment_facilities.AsyncResult(task_id, app=router) # type: ignore
return await standard_json_response(
request, task, "get_treatment_facility_parameters"
)
4 changes: 2 additions & 2 deletions nereid/nereid/api/api_v1/endpoints_async/treatment_sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ async def initialize_treatment_site(
treatment_sites: TreatmentSites = Body(...),
context: dict = Depends(get_valid_context),
) -> dict[str, Any]:
task = bg.initialize_treatment_sites.s(
task = bg.initialize_treatment_sites.s( # type: ignore
treatment_sites.model_dump(), context=context
)

Expand All @@ -41,5 +41,5 @@ async def initialize_treatment_site(
async def get_treatment_site_parameters(
request: Request, task_id: str
) -> dict[str, Any]:
task = bg.initialize_treatment_sites.AsyncResult(task_id, app=router)
task = bg.initialize_treatment_sites.AsyncResult(task_id, app=router) # type: ignore
return await standard_json_response(request, task, "get_treatment_site_parameters")
4 changes: 2 additions & 2 deletions nereid/nereid/api/api_v1/endpoints_async/watershed.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ async def post_solve_watershed(
),
) -> dict[str, Any]:
watershed, context = watershed_pkg
task = bg.solve_watershed.s(
task = bg.solve_watershed.s( # type: ignore
watershed=watershed, treatment_pre_validated=True, context=context
)
return await run_task(request, task, "get_watershed_result")
Expand All @@ -57,5 +57,5 @@ async def post_solve_watershed(
response_class=ORJSONResponse,
)
async def get_watershed_result(request: Request, task_id: str) -> dict[str, Any]:
task = bg.solve_watershed.AsyncResult(task_id, app=router)
task = bg.solve_watershed.AsyncResult(task_id, app=router) # type: ignore
return await standard_json_response(request, task, "get_watershed_result")
Loading