Skip to content

Commit

Permalink
[feat] Add ability to create reports (#3189)
Browse files Browse the repository at this point in the history
  • Loading branch information
mihran113 authored Sep 27, 2024
1 parent e3cb26c commit 2b06dff
Show file tree
Hide file tree
Showing 191 changed files with 11,249 additions and 482 deletions.
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# Changelog

## Unreleased

### Enhancements
### Enhancements:
- Add ability to create reports (mihran113)
- Add support for self-signed SSL certificates (mihran113)


## 3.24.0 Aug 14, 2024

### Enhancements
### Enhancements:
- Add read-only mode for Aim UI (mihran113)
- Support of mass updates in remote tracking (peter-sk)

### Fixes
### Fixes:
- Fix bug in bookmark page where it was not scrollable if there was too many bookmarks (vinayan3)
- Fix exception name in `storage/union.pyx` (sulan)

Expand Down
3 changes: 2 additions & 1 deletion aim/storage/migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from logging.config import fileConfig

from aim.storage.structured.sql_engine.models import Base
from aim.storage.structured.db import DB
from aim.storage.structured.sql_engine.models import *
from aim.web.configs import AIM_ENV_MODE_KEY
from alembic import context
from alembic.config import Config
Expand Down
2 changes: 2 additions & 0 deletions aim/web/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def create_app():
from aim.web.api.experiments.views import experiment_router
from aim.web.api.projects.project import Project
from aim.web.api.projects.views import projects_router
from aim.web.api.reports.views import reports_router
from aim.web.api.runs.views import add_api_routes, runs_router
from aim.web.api.tags.views import tags_router
from aim.web.api.utils import ResourceCleanupMiddleware
Expand Down Expand Up @@ -59,6 +60,7 @@ def create_app():
api_app.include_router(projects_router, prefix='/projects')
api_app.include_router(runs_router, prefix='/runs')
api_app.include_router(tags_router, prefix='/tags')
api_app.include_router(reports_router, prefix='/reports')

base_path = os.environ.get(AIM_UI_BASE_PATH, '')

Expand Down
Empty file added aim/web/api/reports/__init__.py
Empty file.
23 changes: 23 additions & 0 deletions aim/web/api/reports/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import uuid

import sqlalchemy as sa

from aim.web.api.db import Base
from aim.web.api.utils import datetime_now


class Report(Base):
__tablename__ = 'reports'
uuid = sa.Column(sa.Text, primary_key=True)
code = sa.Column(sa.Text)
name = sa.Column(sa.Text)
description = sa.Column(sa.Text)

created_at = sa.Column(sa.DateTime, default=datetime_now)
updated_at = sa.Column(sa.DateTime, default=datetime_now, onupdate=datetime_now)

def __init__(self, code, name, description):
self.uuid = str(uuid.uuid1())
self.code = code
self.name = name
self.description = description
31 changes: 31 additions & 0 deletions aim/web/api/reports/pydantic_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from datetime import datetime
from typing import List, Optional
from uuid import UUID

from pydantic import BaseModel


# response models
class ReportOut(BaseModel):
id: UUID
name: str
code: Optional[str] = None
description: Optional[str] = None
updated_at: datetime = 'Wed, 01 Jan 2021 16:12:07 GMT'
created_at: datetime = 'Wed, 01 Jan 2021 16:12:07 GMT'


# request models
class ReportUpdateIn(BaseModel):
name: Optional[str] = None
code: Optional[str] = None
description: Optional[str] = None


class ReportCreateIn(BaseModel):
name: str
code: Optional[str] = None
description: Optional[str] = None


ReportListOut = List[ReportOut]
17 changes: 17 additions & 0 deletions aim/web/api/reports/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from aim.web.api.reports.models import Report


def report_response_serializer(report_object):
if not isinstance(report_object, Report):
return None

response = {
'id': report_object.uuid,
'code': report_object.code,
'name': report_object.name,
'description': report_object.description,
'updated_at': report_object.updated_at,
'created_at': report_object.created_at,
}

return response
62 changes: 62 additions & 0 deletions aim/web/api/reports/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from aim.web.api.db import get_session
from aim.web.api.reports.models import Report
from aim.web.api.reports.pydantic_models import (
ReportCreateIn,
ReportListOut,
ReportOut,
ReportUpdateIn,
)
from aim.web.api.reports.serializers import report_response_serializer
from aim.web.api.utils import APIRouter # wrapper for fastapi.APIRouter
from fastapi import Depends, HTTPException
from sqlalchemy.orm import Session


reports_router = APIRouter()


@reports_router.get('/', response_model=ReportListOut)
async def reports_list_api(session: Session = Depends(get_session)):
reports_query = session.query(Report).order_by(Report.updated_at)
result = [report_response_serializer(report) for report in reports_query]
return result


@reports_router.post('/', status_code=201, response_model=ReportOut)
async def reports_post_api(request_data: ReportCreateIn, session: Session = Depends(get_session)):
report = Report(request_data.code, request_data.name, request_data.description)
session.add(report)
session.commit()
return report_response_serializer(report)


@reports_router.get('/{report_id}/', response_model=ReportOut)
async def reports_get_api(report_id: str, session: Session = Depends(get_session)):
report = session.query(Report).filter(Report.uuid == report_id).first()
if not report:
raise HTTPException(status_code=404)
return report_response_serializer(report)


@reports_router.put('/{report_id}/', response_model=ReportOut)
async def reports_put_api(report_id: str, request_data: ReportUpdateIn, session: Session = Depends(get_session)):
report = session.query(Report).filter(Report.uuid == report_id).first()
if not report:
raise HTTPException(status_code=404)
if request_data.code is not None:
report.code = request_data.code
if request_data.name is not None:
report.name = request_data.name
if request_data.description is not None:
report.description = request_data.description
session.commit()
return report_response_serializer(report)


@reports_router.delete('/{report_id}/')
async def reports_delete_api(report_id: str, session: Session = Depends(get_session)):
report = session.query(Report).filter(Report.uuid == report_id).first()
if not report:
raise HTTPException(status_code=404)
session.delete(report)
session.commit()
4 changes: 4 additions & 0 deletions aim/web/migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
from alembic import context
from alembic.config import Config

from aim.web.api.dashboards import models
from aim.web.api.dashboard_apps import models
from aim.web.api.reports import models


# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
Expand Down
36 changes: 36 additions & 0 deletions aim/web/migrations/versions/3d5fd76e8485_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""empty message
Revision ID: 3d5fd76e8485
Revises: 517a45b2e62c
Create Date: 2024-07-03 20:56:10.622375
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '3d5fd76e8485'
down_revision = '517a45b2e62c'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('reports',
sa.Column('uuid', sa.Text(), nullable=False),
sa.Column('code', sa.Text(), nullable=True),
sa.Column('name', sa.Text(), nullable=True),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('uuid')
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('reports')
# ### end Alembic commands ###
Loading

0 comments on commit 2b06dff

Please sign in to comment.