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/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