Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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/codecov_main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
run: uv lock --check

- name: Install library
run: uv sync --extra dev
run: uv sync

- name: Run tests
run: uv run pytest tests
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-documentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
uv lock --directory backend --check

- name: Install Dependencies
run: uv sync --directory backend --extra dev
run: uv sync --directory backend

- name: Build Documentation
run: make docs
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-backend.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:

- name: Install library
run: |
uv sync --extra dev
uv sync

- name: Run tests
run: |
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ install: install-backend install-frontend
.PHONY: install-backend
install-backend:
cd backend && \
uv sync --extra dev && \
uv sync && \
uv pip install -e .[dev]


Expand All @@ -78,7 +78,7 @@ install-frontend:

.PHONY: model
model: install-backend
$(RUN) gen-pydantic --meta None --extra-fields allow $(SCHEMADIR)/model.yaml > $(SCHEMADIR)/model.py
$(RUN) gen-pydantic --meta NONE --extra-fields allow $(SCHEMADIR)/model.yaml > $(SCHEMADIR)/model.py
$(RUN) gen-typescript $(SCHEMADIR)/model.yaml > $(ROOTDIR)/frontend/src/api/model.ts
make format

Expand Down
4 changes: 2 additions & 2 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ dependencies = [
"docker>=7.1.0",
"fastapi>=0.115.12,<1",
"gunicorn>=23.0.0",
"linkml==1.8.3",
"linkml==1.9.2",
"loguru",
"oaklib>=0.6.6",
"prefixmaps==0.2.4",
Expand All @@ -32,7 +32,7 @@ dependencies = [
"typer>=0.12.0",
]

[project.optional-dependencies]
[dependency-groups]
dev = [
"pytest>=8.2.0",
"mkdocs>=1.6.0",
Expand Down
91 changes: 91 additions & 0 deletions backend/src/monarch_py/api/infores.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from typing import Union, List

from fastapi import APIRouter, HTTPException, Path, Query, Response

from monarch_py.api.config import solr
from monarch_py.api.additional_models import OutputFormat
from monarch_py.datamodels.model import InformationResource

router = APIRouter(tags=["infores"], responses={404: {"description": "Not Found"}})


@router.get("/")
async def _get_infores_catalog(
format: OutputFormat = Query(
default=OutputFormat.json,
title="Output format for the response",
examples=["json", "tsv"],
),
) -> Union[List[InformationResource], str]:
"""Retrieves all information resources from the catalog

<b>Returns:</b> <br>
List[InformationResource]: Complete collection of information resources
"""
response = solr().get_infores_catalog()
if format == OutputFormat.json:
return response
elif format == OutputFormat.tsv:
if not response:
return Response(content="", media_type="text/tab-separated-values")

# Create TSV from pydantic models
headers = list(response[0].model_dump().keys()) if response else []
tsv_lines = ["\t".join(headers)]

for item in response:
row = []
for header in headers:
value = getattr(item, header, "")
if isinstance(value, list):
value = ";".join(str(v) for v in value) if value else ""
row.append(str(value) if value is not None else "")
tsv_lines.append("\t".join(row))

tsv_content = "\n".join(tsv_lines)
return Response(content=tsv_content, media_type="text/tab-separated-values")


@router.get("/{id}")
async def _get_entity(
id: str = Path(
title="ID of the information resource to retrieve",
examples=["infores:zfin"],
),
format: OutputFormat = Query(
default=OutputFormat.json,
title="Output format for the response",
examples=["json", "tsv"],
),
) -> Union[InformationResource, str]:
"""Retrieves the information resource with the specified id

<b>Args:</b> <br>
id (str): ID for the entity to retrieve, ex: infores:zfin

<b>Raises:</b> <br>
HTTPException: 404 if the entity is not found

<b>Returns:</b> <br>
InformationResource: Information resource details for the specified id
"""
response = solr().get_infores(id)
if response is None:
raise HTTPException(status_code=404, detail="Information resource not found")
if format == OutputFormat.json:
return response
elif format == OutputFormat.tsv:
# Create TSV from pydantic model
headers = list(response.model_dump().keys())
tsv_lines = ["\t".join(headers)]

row = []
for header in headers:
value = getattr(response, header, "")
if isinstance(value, list):
value = ";".join(str(v) for v in value) if value else ""
row.append(str(value) if value is not None else "")
tsv_lines.append("\t".join(row))

tsv_content = "\n".join(tsv_lines)
return Response(content=tsv_content, media_type="text/tab-separated-values")
4 changes: 3 additions & 1 deletion backend/src/monarch_py/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import RedirectResponse

from monarch_py.api import association, entity, histopheno, search, semsim, text_annotation
from monarch_py.api import association, entity, histopheno, infores, search, semsim, text_annotation
from monarch_py.api.config import semsimian, spacyner, settings

from monarch_py.api.middleware.logging_middleware import LoggingMiddleware
from monarch_py.utils.utils import get_release_metadata, get_release_versions

Expand All @@ -28,6 +29,7 @@ async def lifespan(app: FastAPI):
app.include_router(association.router, prefix=f"{PREFIX}/association")
app.include_router(entity.router, prefix=f"{PREFIX}/entity")
app.include_router(histopheno.router, prefix=f"{PREFIX}/histopheno")
app.include_router(infores.router, prefix=f"{PREFIX}/infores")
app.include_router(search.router, prefix=PREFIX)
app.include_router(semsim.router, prefix=f"{PREFIX}/semsim")
app.include_router(text_annotation.router, prefix=PREFIX)
Expand Down
Loading