Skip to content

Commit

Permalink
InfoMander JSON encoder
Browse files Browse the repository at this point in the history
  • Loading branch information
rouk1 committed Jul 11, 2024
1 parent 205bb4e commit 8a28e1a
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 22 deletions.
13 changes: 9 additions & 4 deletions src/mandr/dashboard/webapp.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
"""A FastAPI based webapp to serve a local dashboard."""

import json
import os
from pathlib import Path

from fastapi import FastAPI, HTTPException, Request
from fastapi import FastAPI, HTTPException, Request, Response
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates

from mandr.infomander import InfoManderRepository
from mandr.infomander import InfoManderRepository, JSONInfoManderEncoder

_DASHBOARD_PATH = Path(__file__).resolve().parent
_STATIC_PATH = _DASHBOARD_PATH / "static"
Expand Down Expand Up @@ -43,8 +44,12 @@ async def list_mandrs(request: Request) -> list[str]:

@app.get("/mandrs/{mander_path:path}")
async def get_mandr(request: Request, mander_path: str):
"""Return on mandr."""
"""Return one mandr."""
mander = InfoManderRepository.get(path=mander_path)
if mander is None:
raise HTTPException(status_code=404, detail=f"No mandr found in {mander_path}")
return {"path": mander.project_path}
serializable_mander = {"path": mander.project_path} | mander.fetch()
json_str = json.dumps(serializable_mander, cls=JSONInfoManderEncoder).encode(
"utf-8"
)
return Response(media_type="application/json", content=json_str)
76 changes: 58 additions & 18 deletions src/mandr/infomander.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
"""Contains the code for the main InfoMander class."""

from pathlib import Path
from json import JSONEncoder
from pathlib import Path, PurePath
from time import time
from typing import Any

import numpy as np
from diskcache import Cache
from joblib import dump
from rich.console import Console
Expand Down Expand Up @@ -316,27 +319,64 @@ def get_all_paths(cls) -> list[Path]:
if folder in target_folders and root_str not in matching_paths:
matching_paths.append(root_str)

# return as relative to `root_path` Path objects
# return as relative to `_get_storage_path` Path objects
return sorted([Path(p).relative_to(storage_path) for p in matching_paths])

@classmethod
def get(cls, path: str) -> InfoMander | None:
"""Get an `InfoMander` by it's path."""
"""Get an `InfoMander` by it's path.
Parameters
----------
path : str
The path in which the function will look for a mander.
Returns
-------
Infomander | None
The InfoMander or None if nothing is found at this path.
"""
mander_path = _get_storage_path() / path
sub_folder_names = [
f"{p.relative_to(mander_path)}" for p in mander_path.iterdir()
]
does_path_contain_mander_folder = any(
[
STATS_FOLDER in sub_folder_names,
ARTIFACTS_FOLDER in sub_folder_names,
LOGS_FOLDER in sub_folder_names,
if mander_path.exists():
sub_folder_names = [
f"{p.relative_to(mander_path)}" for p in mander_path.iterdir()
]
)
if (
not mander_path.exists()
or not mander_path.is_dir()
or not does_path_contain_mander_folder
):
does_path_contain_mander_folder = any(
[
STATS_FOLDER in sub_folder_names,
ARTIFACTS_FOLDER in sub_folder_names,
LOGS_FOLDER in sub_folder_names,
]
)
if mander_path.is_dir() or not does_path_contain_mander_folder:
return InfoMander(path)
return None


class JSONInfoManderEncoder(JSONEncoder):
"""A dedicated to InfoMander JSON encoder.
usage:
```
import json
json.dumps(mandr, cls=JSONInfoManderEncoder)
```
"""

def default(self, o: Any) -> Any:
"""Try to encode everything that is in an InfoMander.
Unsupported type are ignored.
"""
if isinstance(o, PurePath):
return f"{o.relative_to(_get_storage_path())}"

if isinstance(o, (np.ndarray, np.generic)):
return o.tolist()

try:
encoded_by_default = super().default(o)
return encoded_by_default
except TypeError:
return None
return InfoMander(path)
3 changes: 3 additions & 0 deletions tests/integration/dashboard/test_webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ def test_get_mandr(client: TestClient):
mander_json = response.json()
assert mander_path in mander_json.get("path")
assert response.status_code == 200

response = client.get("/mandrs/i/do/not/exists")
assert response.status_code == 404

0 comments on commit 8a28e1a

Please sign in to comment.