From 934acda1e13655808ece671003035c79184ae456 Mon Sep 17 00:00:00 2001 From: Anne Schuth Date: Thu, 10 Oct 2024 20:52:37 +0200 Subject: [PATCH 1/2] Implement lifecycle --- amt/api/lifecycles.py | 54 +++++++++++ amt/api/routes/project.py | 2 + amt/api/routes/projects.py | 2 + amt/locale/base.pot | 78 ++++++++++++--- amt/locale/en_US/LC_MESSAGES/messages.mo | Bin 451 -> 451 bytes amt/locale/en_US/LC_MESSAGES/messages.po | 87 +++++++++++++---- amt/locale/nl_NL/LC_MESSAGES/messages.mo | Bin 5344 -> 6171 bytes amt/locale/nl_NL/LC_MESSAGES/messages.po | 89 +++++++++++++----- .../versions/14240ff670e2_add_lifecycle.py | 50 ++++++++++ amt/models/project.py | 5 +- amt/schema/lifecycle.py | 6 ++ amt/schema/project.py | 1 + amt/services/projects.py | 2 +- .../templates/projects/details_info.html.j2 | 2 +- amt/site/templates/projects/new.html.j2 | 20 ++++ tests/services/test_projects_service.py | 9 +- 16 files changed, 350 insertions(+), 57 deletions(-) create mode 100644 amt/api/lifecycles.py create mode 100644 amt/migrations/versions/14240ff670e2_add_lifecycle.py create mode 100644 amt/schema/lifecycle.py diff --git a/amt/api/lifecycles.py b/amt/api/lifecycles.py new file mode 100644 index 00000000..cfe4a5b5 --- /dev/null +++ b/amt/api/lifecycles.py @@ -0,0 +1,54 @@ +import logging +from enum import Enum + +from fastapi import Request + +from amt.core.internationalization import get_current_translation +from amt.schema.lifecycle import Lifecycle + +logger = logging.getLogger(__name__) + + +class Lifecycles(Enum): + ORGANIZATIONAL_RESPONSIBILITIES = "ORGANIZATIONAL_RESPONSIBILITIES" + PROBLEM_ANALYSIS = "PROBLEM_ANALYSIS" + DESIGN = "DESIGN" + DATA_EXPLORATION_AND_PREPARATION = "DATA_EXPLORATION_AND_PREPARATION" + DEVELOPMENT = "DEVELOPMENT" + VERIFICATION_AND_VALIDATION = "VERIFICATION_AND_VALIDATION" + IMPLEMENTATION = "IMPLEMENTATION" + MONITORING_AND_MANAGEMENT = "MONITORING_AND_MANAGEMENT" + PHASING_OUT = "PHASING_OUT" + + +def get_lifecycle(key: Lifecycles | None, request: Request) -> Lifecycle | None: + """ + Given the key and translation, returns the translated text. + :param key: the key + :param request: request to get the current language + :return: a Lifecycle model with the correct translation + """ + + if key is None: + return None + + translations = get_current_translation(request) + _ = translations.gettext + # translations are determined at runtime, which is why we use the dictionary below + keys = { + Lifecycles.ORGANIZATIONAL_RESPONSIBILITIES: _("Organizational Responsibilities"), + Lifecycles.PROBLEM_ANALYSIS: _("Problem Analysis"), + Lifecycles.DESIGN: _("Design"), + Lifecycles.DATA_EXPLORATION_AND_PREPARATION: _("Data Exploration and Preparation"), + Lifecycles.DEVELOPMENT: _("Development"), + Lifecycles.VERIFICATION_AND_VALIDATION: _("Verification and Validation"), + Lifecycles.IMPLEMENTATION: _("Implementation"), + Lifecycles.MONITORING_AND_MANAGEMENT: _("Monitoring and Management"), + Lifecycles.PHASING_OUT: _("Phasing Out"), + } + return Lifecycle(id=key.value, name=keys[key]) + + +def get_lifecycles(request: Request) -> list[Lifecycle | None]: + lifecycles: list[Lifecycle | None] = [get_lifecycle(lifecycle, request) for lifecycle in Lifecycles] + return lifecycles diff --git a/amt/api/routes/project.py b/amt/api/routes/project.py index cf5e8abf..fd7d814b 100644 --- a/amt/api/routes/project.py +++ b/amt/api/routes/project.py @@ -6,6 +6,7 @@ from fastapi.responses import HTMLResponse from amt.api.deps import templates +from amt.api.lifecycles import get_lifecycle from amt.api.navigation import ( BaseNavigationItem, Navigation, @@ -161,6 +162,7 @@ async def get_project_details( tab_items = get_project_details_tabs(request) context = { + "lifecycle": get_lifecycle(project.lifecycle, request), "system_card": system_card_data, "instrument_state": instrument_state, "project": project, diff --git a/amt/api/routes/projects.py b/amt/api/routes/projects.py index 7db6f2da..990f9640 100644 --- a/amt/api/routes/projects.py +++ b/amt/api/routes/projects.py @@ -6,6 +6,7 @@ from amt.api.ai_act_profile import get_ai_act_profile_selector from amt.api.deps import templates +from amt.api.lifecycles import get_lifecycles from amt.api.navigation import Navigation, resolve_base_navigation_items, resolve_navigation_items from amt.schema.project import ProjectNew from amt.services.instruments import InstrumentsService @@ -61,6 +62,7 @@ async def get_new( "ai_act_profile": ai_act_profile, "breadcrumbs": breadcrumbs, "sub_menu_items": {}, # sub_menu_items disabled for now, + "lifecycles": get_lifecycles(request), } response = templates.TemplateResponse(request, "projects/new.html.j2", context) diff --git a/amt/locale/base.pot b/amt/locale/base.pot index 67deec0d..81c81140 100644 --- a/amt/locale/base.pot +++ b/amt/locale/base.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-10-10 11:00+0200\n" +"POT-Creation-Date: 2024-10-10 21:27+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -41,6 +41,42 @@ msgstr "" msgid "Role" msgstr "" +#: amt/api/lifecycles.py:39 +msgid "Organizational Responsibilities" +msgstr "" + +#: amt/api/lifecycles.py:40 +msgid "Problem Analysis" +msgstr "" + +#: amt/api/lifecycles.py:41 +msgid "Design" +msgstr "" + +#: amt/api/lifecycles.py:42 +msgid "Data Exploration and Preparation" +msgstr "" + +#: amt/api/lifecycles.py:43 +msgid "Development" +msgstr "" + +#: amt/api/lifecycles.py:44 +msgid "Verification and Validation" +msgstr "" + +#: amt/api/lifecycles.py:45 +msgid "Implementation" +msgstr "" + +#: amt/api/lifecycles.py:46 +msgid "Monitoring and Management" +msgstr "" + +#: amt/api/lifecycles.py:47 +msgid "Phasing Out" +msgstr "" + #: amt/api/navigation.py:45 msgid "Home" msgstr "" @@ -97,7 +133,7 @@ msgstr "" msgid "Model" msgstr "" -#: amt/api/navigation.py:59 amt/site/templates/projects/new.html.j2:114 +#: amt/api/navigation.py:59 amt/site/templates/projects/new.html.j2:134 msgid "Instruments" msgstr "" @@ -304,11 +340,31 @@ msgstr "" msgid "Your project name here" msgstr "" -#: amt/site/templates/projects/new.html.j2:35 +#: amt/site/templates/projects/new.html.j2:37 +msgid "Lifecycle" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Select the lifecycle your project is currently in" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Read" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Algorithm Framework on lifecycles" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "for background information" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:55 msgid "AI Act Profile" msgstr "" -#: amt/site/templates/projects/new.html.j2:37 +#: amt/site/templates/projects/new.html.j2:57 msgid "" "The AI Act profile provides insight into, among other things, the type of" " AI system and the associated obligations from the European AI Act. If " @@ -317,33 +373,33 @@ msgid "" "tree." msgstr "" -#: amt/site/templates/projects/new.html.j2:42 +#: amt/site/templates/projects/new.html.j2:62 msgid "Find your AI Act profile" msgstr "" -#: amt/site/templates/projects/new.html.j2:97 +#: amt/site/templates/projects/new.html.j2:117 msgid "Yes" msgstr "" -#: amt/site/templates/projects/new.html.j2:107 +#: amt/site/templates/projects/new.html.j2:127 msgid "No" msgstr "" -#: amt/site/templates/projects/new.html.j2:116 +#: amt/site/templates/projects/new.html.j2:136 msgid "" "Overview of instruments for the responsible development, deployment, " "assessment and monitoring of algorithms and AI-systems." msgstr "" -#: amt/site/templates/projects/new.html.j2:124 +#: amt/site/templates/projects/new.html.j2:144 msgid "Choose one or more instruments" msgstr "" -#: amt/site/templates/projects/new.html.j2:138 +#: amt/site/templates/projects/new.html.j2:158 msgid "Create Project" msgstr "" -#: amt/site/templates/projects/new.html.j2:152 +#: amt/site/templates/projects/new.html.j2:172 msgid "Copy results and close" msgstr "" diff --git a/amt/locale/en_US/LC_MESSAGES/messages.mo b/amt/locale/en_US/LC_MESSAGES/messages.mo index 888525f508e901e3484a22677fe6a02c8b064892..e7be948a99898285e30cf94336889203a8952b77 100644 GIT binary patch delta 16 XcmX@ie3*H{WL6_XD\n" "Language: en_US\n" @@ -42,6 +42,42 @@ msgstr "" msgid "Role" msgstr "" +#: amt/api/lifecycles.py:39 +msgid "Organizational Responsibilities" +msgstr "" + +#: amt/api/lifecycles.py:40 +msgid "Problem Analysis" +msgstr "" + +#: amt/api/lifecycles.py:41 +msgid "Design" +msgstr "" + +#: amt/api/lifecycles.py:42 +msgid "Data Exploration and Preparation" +msgstr "" + +#: amt/api/lifecycles.py:43 +msgid "Development" +msgstr "" + +#: amt/api/lifecycles.py:44 +msgid "Verification and Validation" +msgstr "" + +#: amt/api/lifecycles.py:45 +msgid "Implementation" +msgstr "" + +#: amt/api/lifecycles.py:46 +msgid "Monitoring and Management" +msgstr "" + +#: amt/api/lifecycles.py:47 +msgid "Phasing Out" +msgstr "" + #: amt/api/navigation.py:45 msgid "Home" msgstr "" @@ -98,7 +134,7 @@ msgstr "" msgid "Model" msgstr "" -#: amt/api/navigation.py:59 amt/site/templates/projects/new.html.j2:114 +#: amt/api/navigation.py:59 amt/site/templates/projects/new.html.j2:134 msgid "Instruments" msgstr "" @@ -305,11 +341,31 @@ msgstr "" msgid "Your project name here" msgstr "" -#: amt/site/templates/projects/new.html.j2:35 +#: amt/site/templates/projects/new.html.j2:37 +msgid "Lifecycle" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Select the lifecycle your project is currently in" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Read" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Algorithm Framework on lifecycles" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "for background information" +msgstr "" + +#: amt/site/templates/projects/new.html.j2:55 msgid "AI Act Profile" msgstr "" -#: amt/site/templates/projects/new.html.j2:37 +#: amt/site/templates/projects/new.html.j2:57 msgid "" "The AI Act profile provides insight into, among other things, the type of" " AI system and the associated obligations from the European AI Act. If " @@ -318,42 +374,33 @@ msgid "" "tree." msgstr "" -#: amt/site/templates/projects/new.html.j2:42 +#: amt/site/templates/projects/new.html.j2:62 msgid "Find your AI Act profile" msgstr "" -#: amt/site/templates/projects/new.html.j2:97 +#: amt/site/templates/projects/new.html.j2:117 msgid "Yes" msgstr "" -#: amt/site/templates/projects/new.html.j2:107 +#: amt/site/templates/projects/new.html.j2:127 msgid "No" msgstr "" -#: amt/site/templates/projects/new.html.j2:116 +#: amt/site/templates/projects/new.html.j2:136 msgid "" "Overview of instruments for the responsible development, deployment, " "assessment and monitoring of algorithms and AI-systems." msgstr "" -#: amt/site/templates/projects/new.html.j2:124 +#: amt/site/templates/projects/new.html.j2:144 msgid "Choose one or more instruments" msgstr "" -#: amt/site/templates/projects/new.html.j2:138 +#: amt/site/templates/projects/new.html.j2:158 msgid "Create Project" msgstr "" -#: amt/site/templates/projects/new.html.j2:152 +#: amt/site/templates/projects/new.html.j2:172 msgid "Copy results and close" msgstr "" -#~ msgid "TEST" -#~ msgstr "" - -#~ msgid "Algorithmic Management Toolkit (AMT)" -#~ msgstr "" - -#~ msgid "done" -#~ msgstr "" - diff --git a/amt/locale/nl_NL/LC_MESSAGES/messages.mo b/amt/locale/nl_NL/LC_MESSAGES/messages.mo index f675f2e1e78e5ef086219d6d0083d0735cb3fc2f..217cf3e26eb9850965bb869166db908376f52b7d 100644 GIT binary patch delta 2206 zcmYk*e`r-@7{Kv&bJIJwsk@s$m+rJJbx`IMtrm%aKbmP1p`jVd*}d=XeeXT@oa;H~ z&ZfoHh>DV^9YkoMK@>z5!uq44BoHBrG^7v<(#it=NQM5$MM2-^-Xn9IozMH8_q@;h zzRz>+m7ejH<)4#vM-_j&_`i$)tF_Xb`a4;#)GWFmVi$gn7GA*w)=XFGZk&lS|6Xjt ze(c8GasLoz=#SwR{0DoKDyxk%l-kJy4|%4(!r6Ep8}KqF@ft3{f00YIv-&*jLfK#+ zwqZZk;U2Uwg^lhI529r7C`!CfaXRa(3p9wWE@2b?id^bO{CpB+W3@9$GbXr6 zz*d}w_n|D{`f%( zCDjLztf@mN3%`c4p$He_+jtM2#%{bCKX2eek)PKxlzA&qPQDst{>IoHDC_J+He6Pk z2AA3w54?!7fg>ojeG^yUakTJTl#^e_m+%(K$9Ra}rkwCql#Gm{Ec_12`=^k-s?Sh1 za1QIFh~LwY0GCi+yc+kfqikRjm*amZ0hf|L39uU9#fLD9mr)jeY<|`4NEOshly4!A zlA#c#)CY0?8XDs?1#B1iXpz)!#x1(6%7@x-K_wlW!OFe$UTao@+T~ zSf@r)j-FUv-&ecI4sC1WGeyVq?a(l6yJ>5?uZwoIuQuo)<(s06N!w(E&^AthBiiwb z1?`4WIAg52P;|6(DuJT9#K~!_61|^jU%1V4P3ZZ?%~axVvt2t=c{MtdSi8i}*seKH znPofH4jmLdH!wrSF`>~x^mpRr_N*PqsXJvwlf--AbPH0L#>^TPB-+d z)Q(PtR+!aOr?f`Bl5Z7#FDFALuu>)8XOqsTW!#D18@{V)AJo1XHmRxe5894NS5NVA z}Zy?hQ)^ohHD_9R^0SlLQb zh^agT)`;y|Ieoht(c;zzCk9*B)y$^?)dFZ)aU@Q^j-s~Bo$ST3Q`u1ajW{zgPW4bUAY=~} zg~uRT5FZK}D2S#h!%uGBKrRDQp1_^x#yncf6o8jd#dJbb?S|O z>~X`df&XOwNw-@6e-FnRlS^|D%kdSKsoP^rHcUg!n~4*#9xHH@)83D*w2$E`{DsxH zG|QNc#-vP?3yK+_%ELh%kFU{>AF&iia2ys>72-71#^zxF>yf>g&FI4>q?jm`0`5X$ zn_kqovzSMGljdR)H*R1MpP&MKLJib0r3baJ7pGz&7Go_cGwV?6B$2(EBSl$Ddrc|K6H^DEx6zD5UT$KDieK9`zm^A-$ISQ zj}-HQN(Xv}DFyt%g?97<%UuM*M%t6<)ct*^37w7yk>r@ePJa)U&_0RE%oWsuo}n^1 zs>)u`03MrCk2Zp9Bc7nk!Q z$-Ss`E}`b%K+a|!qT)W!W44~%7j9^06Z1z;P>f31eAK`?R0g&<_qU_J=!~6OohJx%_GrN!+ZgcMuD}ZWHBjZ=m9Ry@P{FovJf0w6I95i9#$%DB-4ZOf er-JkCP_WX@D6GwFE?nfYnWDO^aH1m;Hh%$rx3<;* diff --git a/amt/locale/nl_NL/LC_MESSAGES/messages.po b/amt/locale/nl_NL/LC_MESSAGES/messages.po index 9cf6c9c3..c0897b60 100644 --- a/amt/locale/nl_NL/LC_MESSAGES/messages.po +++ b/amt/locale/nl_NL/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-10-10 11:00+0200\n" +"POT-Creation-Date: 2024-10-10 21:27+0200\n" "PO-Revision-Date: 2024-07-25 21:01+0200\n" "Last-Translator: FULL NAME \n" "Language: nl_NL\n" @@ -42,6 +42,42 @@ msgstr "Zijn er transparantieverplichtingen?" msgid "Role" msgstr "Rol" +#: amt/api/lifecycles.py:39 +msgid "Organizational Responsibilities" +msgstr "Organisatieverantwoordelijkheden" + +#: amt/api/lifecycles.py:40 +msgid "Problem Analysis" +msgstr "Probleemanalyse" + +#: amt/api/lifecycles.py:41 +msgid "Design" +msgstr "Ontwerpen" + +#: amt/api/lifecycles.py:42 +msgid "Data Exploration and Preparation" +msgstr "Dataverkenning en datapreparatie" + +#: amt/api/lifecycles.py:43 +msgid "Development" +msgstr "Ontwikkelen" + +#: amt/api/lifecycles.py:44 +msgid "Verification and Validation" +msgstr "Verficatie en validatie" + +#: amt/api/lifecycles.py:45 +msgid "Implementation" +msgstr "Implementeren" + +#: amt/api/lifecycles.py:46 +msgid "Monitoring and Management" +msgstr "Monitoring en beheer" + +#: amt/api/lifecycles.py:47 +msgid "Phasing Out" +msgstr "Uitfaseren" + #: amt/api/navigation.py:45 msgid "Home" msgstr "Start" @@ -98,7 +134,7 @@ msgstr "Data" msgid "Model" msgstr "Model" -#: amt/api/navigation.py:59 amt/site/templates/projects/new.html.j2:114 +#: amt/api/navigation.py:59 amt/site/templates/projects/new.html.j2:134 msgid "Instruments" msgstr "Instrumenten" @@ -311,11 +347,31 @@ msgstr "Project naam" msgid "Your project name here" msgstr "Jouw projectnaam hier" -#: amt/site/templates/projects/new.html.j2:35 +#: amt/site/templates/projects/new.html.j2:37 +msgid "Lifecycle" +msgstr "Levenscyclus" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Select the lifecycle your project is currently in" +msgstr "Selecteer de levenscyclus van je project" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Read" +msgstr "Lees" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "Algorithm Framework on lifecycles" +msgstr "Algoritmekader over levenscyclus" + +#: amt/site/templates/projects/new.html.j2:38 +msgid "for background information" +msgstr "voor achtergrond informatie" + +#: amt/site/templates/projects/new.html.j2:55 msgid "AI Act Profile" msgstr "AI Verordening Profiel" -#: amt/site/templates/projects/new.html.j2:37 +#: amt/site/templates/projects/new.html.j2:57 msgid "" "The AI Act profile provides insight into, among other things, the type of" " AI system and the associated obligations from the European AI Act. If " @@ -323,23 +379,23 @@ msgid "" "Otherwise, you can find your AI Act Profile with the AI Act Decision " "tree." msgstr "" -"Het profiel van je toepassing, gebasseerd op de AI Act, geeft inzicht in " +"Het profiel van je toepassing, gebaseerd op de AI Act, geeft inzicht in " "onder andere het type AI systeem, de regelgeving die van toepassing is en" " de risicocategorie." -#: amt/site/templates/projects/new.html.j2:42 +#: amt/site/templates/projects/new.html.j2:62 msgid "Find your AI Act profile" msgstr "Vind uw AI Act profiel" -#: amt/site/templates/projects/new.html.j2:97 +#: amt/site/templates/projects/new.html.j2:117 msgid "Yes" msgstr "Ja" -#: amt/site/templates/projects/new.html.j2:107 +#: amt/site/templates/projects/new.html.j2:127 msgid "No" msgstr "Nee" -#: amt/site/templates/projects/new.html.j2:116 +#: amt/site/templates/projects/new.html.j2:136 msgid "" "Overview of instruments for the responsible development, deployment, " "assessment and monitoring of algorithms and AI-systems." @@ -347,24 +403,15 @@ msgstr "" "Overzicht van aanbevolen instrument voor het verantwoord ontwikkelen, " "gebruiken, beoordelen en monitoren van algoritmes en AI-systemen." -#: amt/site/templates/projects/new.html.j2:124 +#: amt/site/templates/projects/new.html.j2:144 msgid "Choose one or more instruments" msgstr "Kies één of meerdere instrumenten" -#: amt/site/templates/projects/new.html.j2:138 +#: amt/site/templates/projects/new.html.j2:158 msgid "Create Project" msgstr "Maak project" -#: amt/site/templates/projects/new.html.j2:152 +#: amt/site/templates/projects/new.html.j2:172 msgid "Copy results and close" msgstr "Resultaten overnemen en sluiten" -#~ msgid "TEST" -#~ msgstr "" - -#~ msgid "Algorithmic Management Toolkit (AMT)" -#~ msgstr "Algoritme Management Toolkit (AMT)" - -#~ msgid "done" -#~ msgstr "Afgerond" - diff --git a/amt/migrations/versions/14240ff670e2_add_lifecycle.py b/amt/migrations/versions/14240ff670e2_add_lifecycle.py new file mode 100644 index 00000000..e3617241 --- /dev/null +++ b/amt/migrations/versions/14240ff670e2_add_lifecycle.py @@ -0,0 +1,50 @@ +"""Add lifecycle field to project table + +Revision ID: 14240ff670e2 +Revises: 66cf279a7f62 +Create Date: 2024-10-10 16:26:52.294477 + +""" + +from collections.abc import Sequence + +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision: str = "14240ff670e2" +down_revision: str | None = "66cf279a7f62" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + +# Define the Lifecycle enum values +lifecycle_values = [ + 'ORGANIZATIONAL_RESPONSIBILITIES', + 'PROBLEM_ANALYSIS', + 'DESIGN', + 'DATA_EXPLORATION_AND_PREPARATION', + 'DEVELOPMENT', + 'VERIFICATION_AND_VALIDATION', + 'IMPLEMENTATION', + 'MONITORING_AND_MANAGEMENT', + 'PHASING_OUT' +] + + +def upgrade() -> None: + # Create the enum type + lifecycle_enum = postgresql.ENUM(*lifecycle_values, name='lifecycle') + lifecycle_enum.create(op.get_bind()) + + # Add the lifecycle column + op.add_column('project', sa.Column('lifecycle', lifecycle_enum, nullable=True)) + + +def downgrade() -> None: + # Remove the lifecycle column + op.drop_column('project', 'lifecycle') + + # Drop the enum type + lifecycle_enum = postgresql.ENUM(*lifecycle_values, name='lifecycle') + lifecycle_enum.drop(op.get_bind()) diff --git a/amt/models/project.py b/amt/models/project.py index 8252abf8..225a19f9 100644 --- a/amt/models/project.py +++ b/amt/models/project.py @@ -1,8 +1,10 @@ from typing import TypeVar from sqlalchemy import String +from sqlalchemy.dialects.postgresql import ENUM from sqlalchemy.orm import Mapped, mapped_column +from amt.api.lifecycles import Lifecycles from amt.models.base import Base T = TypeVar("T", bound="Project") @@ -12,5 +14,6 @@ class Project(Base): __tablename__ = "project" id: Mapped[int] = mapped_column(primary_key=True) - name: Mapped[str] = mapped_column(String(255)) # TODO: (Christopher) how to set min_length? + name: Mapped[str] = mapped_column(String(255)) + lifecycle: Mapped[Lifecycles | None] = mapped_column(ENUM(Lifecycles), nullable=True) model_card: Mapped[str | None] = mapped_column(default=None) diff --git a/amt/schema/lifecycle.py b/amt/schema/lifecycle.py new file mode 100644 index 00000000..5ef405dc --- /dev/null +++ b/amt/schema/lifecycle.py @@ -0,0 +1,6 @@ +from pydantic import BaseModel + + +class Lifecycle(BaseModel): + id: str + name: str diff --git a/amt/schema/project.py b/amt/schema/project.py index bd6dc19e..e353e099 100644 --- a/amt/schema/project.py +++ b/amt/schema/project.py @@ -4,6 +4,7 @@ class ProjectBase(BaseModel): name: str = Field(min_length=3, max_length=255) + lifecycle: str = Field(default=None) class ProjectNew(ProjectBase): diff --git a/amt/services/projects.py b/amt/services/projects.py index 18602692..ca1ded72 100644 --- a/amt/services/projects.py +++ b/amt/services/projects.py @@ -31,7 +31,7 @@ def get(self, project_id: int) -> Project: return self.repository.find_by_id(project_id) def create(self, project_new: ProjectNew) -> Project: - project = Project(name=project_new.name) + project = Project(name=project_new.name, lifecycle=project_new.lifecycle) self.repository.save(project) diff --git a/amt/site/templates/projects/details_info.html.j2 b/amt/site/templates/projects/details_info.html.j2 index 943e2cae..33229d4f 100644 --- a/amt/site/templates/projects/details_info.html.j2 +++ b/amt/site/templates/projects/details_info.html.j2 @@ -33,7 +33,7 @@ role="img" aria-label="Bevestiging" > - {{ system_card.status }} + {{ lifecycle.name }} diff --git a/amt/site/templates/projects/new.html.j2 b/amt/site/templates/projects/new.html.j2 index 661695ff..0f4cc41f 100644 --- a/amt/site/templates/projects/new.html.j2 +++ b/amt/site/templates/projects/new.html.j2 @@ -30,6 +30,26 @@ dir="auto" value="" /> +
+
+ +

{% trans %}Select the lifecycle your project is currently in{% endtrans %}. {% trans %}Read{% endtrans %} {% trans %}Algorithm Framework on lifecycles{% endtrans %} {% trans %}for background information{% endtrans %}.

+
+ {% for lifecycle in lifecycles %} +
+ +
+ {% endfor %} +

{% trans %}AI Act Profile{% endtrans %}

diff --git a/tests/services/test_projects_service.py b/tests/services/test_projects_service.py index 0b02c41c..9fd27a5c 100644 --- a/tests/services/test_projects_service.py +++ b/tests/services/test_projects_service.py @@ -14,6 +14,7 @@ def test_get_project(): # Given project_id = 1 project_name = "Project 1" + project_lifecycle = "development" project_model_card = "model_card_path" projects_service = ProjectsService( repository=Mock(spec=ProjectsRepository), @@ -21,7 +22,7 @@ def test_get_project(): instrument_service=Mock(spec=InstrumentsService), ) projects_service.repository.find_by_id.return_value = Project( # type: ignore - id=project_id, name=project_name, model_card=project_model_card + id=project_id, name=project_name, lifecycle=project_lifecycle, model_card=project_model_card ) # When @@ -30,6 +31,7 @@ def test_get_project(): # Then assert project.id == project_id assert project.name == project_name + assert project.lifecycle == project_lifecycle assert project.model_card == project_model_card projects_service.repository.find_by_id.assert_called_once_with(project_id) # type: ignore @@ -37,6 +39,7 @@ def test_get_project(): def test_create_project(): project_id = 1 project_name = "Project 1" + project_lifecycle = "development" project_model_card = Path("model_card_path") projects_service = ProjectsService( repository=Mock(spec=ProjectsRepository), @@ -44,13 +47,14 @@ def test_create_project(): instrument_service=Mock(spec=InstrumentsService), ) projects_service.repository.save.return_value = Project( # type: ignore - id=project_id, name=project_name, model_card=str(project_model_card) + id=project_id, name=project_name, lifecycle=project_lifecycle, model_card=str(project_model_card) ) projects_service.instrument_service.fetch_instruments.return_value = [default_instrument()] # type: ignore # When project_new = ProjectNew( name=project_name, + lifecycle=project_lifecycle, instruments=[], type="project_type", open_source="project_open_source", @@ -64,4 +68,5 @@ def test_create_project(): # Then assert project.id == project_id assert project.name == project_name + assert project.lifecycle == project_lifecycle projects_service.repository.save.assert_called() # type: ignore From 968214ec6597b15bcf638e4aec018fe4c77e9a0b Mon Sep 17 00:00:00 2001 From: Anne Schuth Date: Fri, 11 Oct 2024 09:28:17 +0200 Subject: [PATCH 2/2] Update tests with required lifecycle --- amt/schema/project.py | 2 +- amt/site/templates/projects/new.html.j2 | 2 +- tests/api/routes/test_projects.py | 2 ++ tests/core/test_exception_handlers.py | 4 ++-- tests/e2e/test_create_project.py | 6 ++++++ tests/schema/test_schema_project.py | 2 ++ 6 files changed, 14 insertions(+), 4 deletions(-) diff --git a/amt/schema/project.py b/amt/schema/project.py index e353e099..f9ea2ff9 100644 --- a/amt/schema/project.py +++ b/amt/schema/project.py @@ -4,7 +4,7 @@ class ProjectBase(BaseModel): name: str = Field(min_length=3, max_length=255) - lifecycle: str = Field(default=None) + lifecycle: str = Field() class ProjectNew(ProjectBase): diff --git a/amt/site/templates/projects/new.html.j2 b/amt/site/templates/projects/new.html.j2 index 0f4cc41f..c1bf5992 100644 --- a/amt/site/templates/projects/new.html.j2 +++ b/amt/site/templates/projects/new.html.j2 @@ -40,7 +40,7 @@ {% for lifecycle in lifecycles %}