From bf5f310ddce40c1975532bf1242f713004a48b61 Mon Sep 17 00:00:00 2001 From: Peter Bednarik Date: Mon, 26 Jan 2026 13:57:27 +0200 Subject: [PATCH 1/3] Documentation returned, small fixes. --- desdeo/api/routers/emo.py | 4 + desdeo/api/routers/nimbus.py | 38 +++++---- desdeo/api/routers/problem.py | 85 ++++++++++++++++---- desdeo/api/routers/reference_point_method.py | 17 +++- desdeo/api/routers/utils.py | 43 ++++++---- desdeo/api/routers/utopia.py | 7 +- 6 files changed, 139 insertions(+), 55 deletions(-) diff --git a/desdeo/api/routers/emo.py b/desdeo/api/routers/emo.py index e0f0c11a0..b7a49647d 100644 --- a/desdeo/api/routers/emo.py +++ b/desdeo/api/routers/emo.py @@ -158,6 +158,10 @@ def iterate( Args: request (EMOIterateRequest): The request object containing parameters for fetching results. context (Annotated[SessionContext, Depends]): The session context. + + Raises: HTTPException: If the request is invalid or the EMO method fails. + Returns: IterateResponse: A response object containing a list of IDs to be used for websocket communication. + Also contains the StateDB id where the results will be stored. """ # 1) Get context objects db_session = context.db_session diff --git a/desdeo/api/routers/nimbus.py b/desdeo/api/routers/nimbus.py index 63921a639..18bf58fb1 100644 --- a/desdeo/api/routers/nimbus.py +++ b/desdeo/api/routers/nimbus.py @@ -351,7 +351,9 @@ def solve_nimbus_intermediate( # Forward to generic endpoint intermediate_response = solve_intermediate(request, context) + # Get saved solutions for this user and problem saved_solutions = collect_saved_solutions(user, request.problem_id, db_session) + # Get all solutions including the newly generated intermediate ones all_solutions = collect_all_solutions(user, request.problem_id, db_session) return NIMBUSIntermediateSolutionResponse( @@ -369,7 +371,7 @@ def get_or_initialize( context: Annotated[SessionContext, Depends(get_session_context)], ) -> NIMBUSInitializationResponse | NIMBUSClassificationResponse | \ NIMBUSIntermediateSolutionResponse | NIMBUSFinalizeResponse: - + """Get the latest NIMBUS state if it exists, or initialize a new one if it doesn't.""" db_session = context.db_session user = context.user interactive_session = context.interactive_session @@ -385,6 +387,7 @@ def get_or_initialize( ) states = db_session.exec(statement).all() + # Find the latest relevant state (NIMBUS classification, initialization, or intermediate with NIMBUS context) latest_state = None for state in states: if isinstance(state.state, (NIMBUSClassificationState | NIMBUSInitializationState | NIMBUSFinalState)) or ( @@ -441,7 +444,7 @@ def get_or_initialize( saved_solutions=saved_solutions, all_solutions=all_solutions, ) - + # NIMBUSInitializationState return NIMBUSInitializationResponse( state_id=latest_state.id, current_solutions=current_solutions, @@ -457,29 +460,24 @@ def finalize_nimbus( request: NIMBUSFinalizeRequest, context: Annotated[SessionContext, Depends(get_session_context)] ) -> NIMBUSFinalizeResponse: + """An endpoint for finishing up the nimbus process. + + Args: + request (NIMBUSFinalizeRequest): The request containing the final solution, etc. + user (Annotated[User, Depends): The current user. + session (Annotated[Session, Depends): The database session. + + Raises: + HTTPException + Returns: + NIMBUSFinalizeResponse: Response containing info on the final solution. + """ db_session = context.db_session user = context.user interactive_session = context.interactive_session parent_state = context.parent_state - - if request.parent_state_id is None: - parent_state = None - else: - parent_state = db_session.exec(select(StateDB).where(StateDB.id == request.parent_state_id)).first() - if parent_state is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Could not find state with id={request.parent_state_id}" - ) - - # fetch problem - problem_db = db_session.exec(select(ProblemDB).where(ProblemDB.user_id == user.id, ProblemDB.id == request.problem_id)).first() - if problem_db is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Problem with id={request.problem_id} could not be found." - ) + problem_db = context.problem_db solution_state_id = request.solution_info.state_id solution_index = request.solution_info.solution_index diff --git a/desdeo/api/routers/problem.py b/desdeo/api/routers/problem.py index 1bf2a145f..a25d944bc 100644 --- a/desdeo/api/routers/problem.py +++ b/desdeo/api/routers/problem.py @@ -29,7 +29,6 @@ router = APIRouter(prefix="/problem") - def check_solver(problem_db: ProblemDB): """Check if a preferred solver is set in the metadata. @@ -91,18 +90,21 @@ def get_problem( ) -> ProblemInfo: """Get the model of a specific problem. - Args: request (ProblemGetRequest): the request containing the problem's id `problem_id`. + Args: + request (ProblemGetRequest): the request containing the problem's id `problem_id`. user (Annotated[User, Depends): the current user. session (Annotated[Session, Depends): the database session. - Raises: HTTPException: could not find a problem with the given id. - Returns: ProblemInfo: detailed information on the requested problem. + + Raises: + HTTPException: could not find a problem with the given id. + + Returns: + ProblemInfo: detailed information on the requested problem. """ - db_session = context.db_session + # db_session = context.db_session problem_db = context.problem_db - # ----------------------------- # Ensure problem exists - # ----------------------------- if problem_db is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -116,7 +118,21 @@ def add_problem( request: Annotated[Problem, Depends(parse_problem_json)], context: Annotated[SessionContext, Depends(get_session_context_base)], ) -> ProblemInfo: - """Add a newly defined problem to the database.""" + """Add a newly defined problem to the database. + + Args: + request (Problem): the JSON representation of the problem. + context (Annotated[SessionContext, Depends): the session context. + + Note: + Users with the role 'guest' may not add new problems. + + Raises: + HTTPException: when any issue with defining the problem arises. + + Returns: + ProblemInfo: the information about the problem added. + """ user = context.user db_session = context.db_session @@ -145,7 +161,19 @@ def add_problem_json( json_file: UploadFile, context: Annotated[SessionContext, Depends(get_session_context_base)], ) -> ProblemInfo: - """Adds a problem to the database based on its JSON definition.""" + """Adds a problem to the database based on its JSON definition. + + Args: + json_file (UploadFile): a file in JSON format describing the problem. + context (Annotated[SessionContext, Depends): the session context. + + Raises: + HTTPException: if the provided `json_file` is empty. + HTTPException: if the content in the provided `json_file` is not in JSON format.__annotations__ + + Returns: + ProblemInfo: a description of the added problem. + """ user = context.user db_session = context.db_session @@ -173,7 +201,22 @@ def get_metadata( request: ProblemMetaDataGetRequest, context: Annotated[SessionContext, Depends(get_session_context)], ) -> list[ForestProblemMetaData | RepresentativeNonDominatedSolutions | SolverSelectionMetadata]: - """Fetch specific metadata for a specific problem.""" + """Fetch specific metadata for a specific problem. + + Fetch specific metadata for a specific problem. See all the possible + metadata types from DESDEO/desdeo/api/models/problem.py Problem Metadata + section. + + Args: + request (MetaDataGetRequest): the requested metadata type. + user (Annotated[User, Depends]): the current user. + context (Annotated[SessionContext, Depends]): the session context. + + Returns: + list[ForestProblemMetadata | RepresentativeNonDominatedSolutions]: list containing all the metadata + defined for the problem with the requested metadata type. If no match is found, + returns an empty list. + """ db_session = context.db_session problem_from_db = db_session.exec( @@ -189,8 +232,9 @@ def get_metadata( problem_metadata = problem_from_db.problem_metadata if problem_metadata is None: + # no metadata define for the problem return [] - + # metadata is defined, try to find matching types based on request return [ metadata for metadata in problem_metadata.all_metadata @@ -207,7 +251,19 @@ def select_solver( request: ProblemSelectSolverRequest, context: Annotated[SessionContext, Depends(get_session_context)], ) -> JSONResponse: - """Assign a specific solver for a problem.""" + """Assign a specific solver for a problem. + + Args: + request: ProblemSelectSolverRequest: The request containing problem id and string representation of the solver + user: Annotated[User, Depends(get_current_user): The user that is logged in. + context: Annotated[SessionContext, Depends(get_session)]: The session context. + + Raises: + HTTPException: Unknown solver, unauthorized user + + Returns: + JSONResponse: A simple confirmation. + """ db_session = context.db_session user = context.user @@ -229,16 +285,17 @@ def select_solver( status_code=status.HTTP_404_NOT_FOUND, ) - # Authorization + # Auth the user if user.id != problem_db.user_id: raise HTTPException( detail="Unauthorized user!", status_code=status.HTTP_401_UNAUTHORIZED, ) - # Ensure metadata exists + # All good, get on with it. problem_metadata = problem_db.problem_metadata if problem_metadata is None: + # There's no metadata for this problem! Create some. problem_metadata = ProblemMetaDataDB(problem_id=problem_db.id, problem=problem_db) db_session.add(problem_metadata) db_session.commit() diff --git a/desdeo/api/routers/reference_point_method.py b/desdeo/api/routers/reference_point_method.py index 68d2d49b1..644034031 100644 --- a/desdeo/api/routers/reference_point_method.py +++ b/desdeo/api/routers/reference_point_method.py @@ -30,7 +30,17 @@ def solve_solutions( request: RPMSolveRequest, context: Annotated[SessionContext, Depends(get_session_context)], ) -> RPMState: - """Runs an iteration of the reference point method.""" + """Runs an iteration of the reference point method. + + Args: + request (RPMSolveRequest): a request with the needed information to run the method. + user (Annotated[User, Depends): the current user. + context (Annotated[SessionContext, Depends): the current session context. + + Returns: + RPMState: a state with information on the results of iterating the reference point method + once. + """ user = context.user db_session = context.db_session problem_db = context.problem_db @@ -55,6 +65,7 @@ def solve_solutions( request.solver_options, ) + # create DB preference preference_db = PreferenceDB( user_id=user.id, problem_id=problem_db.id, @@ -65,7 +76,7 @@ def solve_solutions( db_session.commit() db_session.refresh(preference_db) - # create RPM state (API model) + # create state and add to DB rpm_state = RPMState( scalarization_options=request.scalarization_options, solver=request.solver, @@ -73,7 +84,7 @@ def solve_solutions( solver_results=solver_results, ) - # create DB state + # create DB state and add it to the DB state = StateDB( problem_id=problem_db.id, preference_id=preference_db.id, diff --git a/desdeo/api/routers/utils.py b/desdeo/api/routers/utils.py index c2f2cef43..23a9cab1a 100644 --- a/desdeo/api/routers/utils.py +++ b/desdeo/api/routers/utils.py @@ -4,7 +4,7 @@ """ from dataclasses import dataclass -from typing import Annotated, Optional +from typing import Annotated from fastapi import Depends, HTTPException, status from sqlmodel import Session, select @@ -20,10 +20,6 @@ ) from desdeo.api.routers.user_authentication import get_current_user -# --------------------------------------------------------------------- -# Request protocol used by session utilities -# --------------------------------------------------------------------- - RequestType = RPMSolveRequest | ENautilusStepRequest def fetch_interactive_session(user: User, request: RequestType, session: Session) -> InteractiveSessionDB | None: @@ -95,7 +91,15 @@ def fetch_parent_state( session: Session, interactive_session: InteractiveSessionDB | None = None, ) -> StateDB | None: - """Fetches the parent state if defined. + """Fetches the parent state, if an id is given, or if defined in the given interactive session. + + Determines the appropriate parent `StateDB` instance to associate with a new + state or operation. It first checks whether the `request` explicitly + provides a `parent_state_id`. If so, it attempts to retrieve the + corresponding `StateDB` entry from the database. If no such id is provided, + the function defaults to returning the most recently added state from the + given `interactive_session`, if available. If neither source provides a + parent state, `None` is returned. Args: user (User): the user for which the parent state is fetched. @@ -115,15 +119,20 @@ def fetch_parent_state( If both `request.parent_state_id` and `interactive_session` are `None`, then returns `None`. """ if request.parent_state_id is None: + # parent state is assumed to be the last sate added to the session. + # if `interactive_session` is None, then parent state is set to None. return ( interactive_session.states[-1] if interactive_session and interactive_session.states else None ) + # request.parent_state_id is not None statement = select(StateDB).where(StateDB.id == request.parent_state_id) parent_state = session.exec(statement).first() + # this error is raised because if a parent_state_id is given, it is assumed that the + # user wished to use that state explicitly as the parent. if parent_state is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -138,15 +147,15 @@ class SessionContext: user: User db_session: Session - problem_db: Optional[ProblemDB] = None - interactive_session: Optional[InteractiveSessionDB] = None, - parent_state: Optional[StateDB] = None, + problem_db: ProblemDB | None = None + interactive_session: InteractiveSessionDB | None = None + parent_state: StateDB | None = None def get_session_context( - request: RequestType, user: Annotated[User, Depends(get_current_user)], db_session: Annotated[Session, Depends(get_session)], + request: RequestType | None = None, ) -> SessionContext: """Gets the current session context. Should be used as a dep. @@ -159,9 +168,14 @@ def get_session_context( SessionContext: the current session context with the relevant instances of `User`, `Session`, `ProblemDB`, `InteractiveSessionDB`, and `StateDB`. """ - problem_db = fetch_user_problem(user, request, db_session) - interactive_session = fetch_interactive_session(user, request, db_session) - parent_state = fetch_parent_state(user, request, db_session, interactive_session=interactive_session) + problem_db = None + interactive_session = None + parent_state = None + + if request is not None: + problem_db = fetch_user_problem(user, request, db_session) + interactive_session = fetch_interactive_session(user, request, db_session) + parent_state = fetch_parent_state(user, request, db_session, interactive_session=interactive_session) return SessionContext( user=user, @@ -176,5 +190,4 @@ def get_session_context_base( db_session: Annotated[Session, Depends(get_session)], ) -> SessionContext: """Gets the current session context. Should be used as a dep.""" - return SessionContext(user=user, db_session=db_session) - + return SessionContext(user=user, db_session=db_session) \ No newline at end of file diff --git a/desdeo/api/routers/utopia.py b/desdeo/api/routers/utopia.py index 2abba3e51..6e367edab 100644 --- a/desdeo/api/routers/utopia.py +++ b/desdeo/api/routers/utopia.py @@ -19,7 +19,8 @@ UtopiaResponse, ) from desdeo.api.routers.user_authentication import get_current_user -from desdeo.api.routers.utils import get_session_context_base, SessionContext +from desdeo.api.routers.utils import get_session_context, SessionContext +# get_session_context_base router = APIRouter(prefix="/utopia") @@ -27,14 +28,14 @@ @router.post("/") def get_utopia_data( request: UtopiaRequest, - context: Annotated[SessionContext, Depends(get_session_context_base)], + context: Annotated[SessionContext, Depends(get_session_context)], ) -> UtopiaResponse: """Request and receive the Utopia map corresponding to the decision variables sent. Args: request (UtopiaRequest): the set of decision variables and problem for which the utopia forest map is requested for. - context (Annotated[SessionContext, Depends(get_session_context_base)]) the current session context + context (Annotated[SessionContext, Depends(get_session_context)]) the current session context Raises: HTTPException: Returns: From 98f459d0ed29bf12f4d817ef7a71cdf900b72ee4 Mon Sep 17 00:00:00 2001 From: Peter Bednarik Date: Mon, 26 Jan 2026 14:56:40 +0200 Subject: [PATCH 2/3] Other fixes. --- desdeo/api/routers/problem.py | 5 +---- desdeo/api/routers/utils.py | 13 ++++--------- desdeo/api/routers/utopia.py | 1 - 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/desdeo/api/routers/problem.py b/desdeo/api/routers/problem.py index a25d944bc..c3d17e698 100644 --- a/desdeo/api/routers/problem.py +++ b/desdeo/api/routers/problem.py @@ -92,8 +92,7 @@ def get_problem( Args: request (ProblemGetRequest): the request containing the problem's id `problem_id`. - user (Annotated[User, Depends): the current user. - session (Annotated[Session, Depends): the database session. + context (Annotated[SessionContext, Depends): the session context. Raises: HTTPException: could not find a problem with the given id. @@ -209,7 +208,6 @@ def get_metadata( Args: request (MetaDataGetRequest): the requested metadata type. - user (Annotated[User, Depends]): the current user. context (Annotated[SessionContext, Depends]): the session context. Returns: @@ -255,7 +253,6 @@ def select_solver( Args: request: ProblemSelectSolverRequest: The request containing problem id and string representation of the solver - user: Annotated[User, Depends(get_current_user): The user that is logged in. context: Annotated[SessionContext, Depends(get_session)]: The session context. Raises: diff --git a/desdeo/api/routers/utils.py b/desdeo/api/routers/utils.py index 23a9cab1a..79503d48e 100644 --- a/desdeo/api/routers/utils.py +++ b/desdeo/api/routers/utils.py @@ -153,9 +153,9 @@ class SessionContext: def get_session_context( + request: RequestType, user: Annotated[User, Depends(get_current_user)], db_session: Annotated[Session, Depends(get_session)], - request: RequestType | None = None, ) -> SessionContext: """Gets the current session context. Should be used as a dep. @@ -168,14 +168,9 @@ def get_session_context( SessionContext: the current session context with the relevant instances of `User`, `Session`, `ProblemDB`, `InteractiveSessionDB`, and `StateDB`. """ - problem_db = None - interactive_session = None - parent_state = None - - if request is not None: - problem_db = fetch_user_problem(user, request, db_session) - interactive_session = fetch_interactive_session(user, request, db_session) - parent_state = fetch_parent_state(user, request, db_session, interactive_session=interactive_session) + problem_db = fetch_user_problem(user, request, db_session) + interactive_session = fetch_interactive_session(user, request, db_session) + parent_state = fetch_parent_state(user, request, db_session, interactive_session=interactive_session) return SessionContext( user=user, diff --git a/desdeo/api/routers/utopia.py b/desdeo/api/routers/utopia.py index 6e367edab..fdd7a66bd 100644 --- a/desdeo/api/routers/utopia.py +++ b/desdeo/api/routers/utopia.py @@ -20,7 +20,6 @@ ) from desdeo.api.routers.user_authentication import get_current_user from desdeo.api.routers.utils import get_session_context, SessionContext -# get_session_context_base router = APIRouter(prefix="/utopia") From 15de6c3e85307d9da8bfad1d74265d5836adf1d1 Mon Sep 17 00:00:00 2001 From: Peter Bednarik Date: Tue, 27 Jan 2026 09:42:35 +0200 Subject: [PATCH 3/3] Ruff repairs. --- desdeo/api/routers/emo.py | 11 ++++------- desdeo/api/routers/generic.py | 2 +- desdeo/api/routers/nimbus.py | 7 +++---- desdeo/api/routers/utopia.py | 13 +++++++------ desdeo/api/tests/test_routes.py | 8 ++++---- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/desdeo/api/routers/emo.py b/desdeo/api/routers/emo.py index b7a49647d..72d7c9b80 100644 --- a/desdeo/api/routers/emo.py +++ b/desdeo/api/routers/emo.py @@ -113,7 +113,7 @@ async def websocket_endpoint( try: while True: data = await websocket.receive_json() - print(data) + # print(data) if "send_to" in data: try: await ws_manager.send_private_message(data, data["send_to"]) @@ -226,7 +226,7 @@ def iterate( return EMOIterateResponse(method_ids=web_socket_ids, client_id=client_id, state_id=state_id) -def _spawn_emo_process( +def _spawn_emo_process( # noqa: PLR0913 problem: Problem, templates: list[TemplateOptions], preference_options: PreferenceOptions | None, @@ -423,7 +423,7 @@ async def fetch_score_bands( ) -> EMOScoreResponse: """Fetches results from a completed EMO method. - Args: request (EMOFetchRequest): The request object containing parameters for fetching + Args: request (EMOFetchRequest): The request object containing parameters for fetching results and of the SCORE bands visualization. context (Annotated[SessionContext, Depends]): The session context. @@ -447,10 +447,7 @@ async def fetch_score_bands( if not (state.state.objective_values and state.state.decision_variables): raise ValueError("State does not contain results yet.") - if request.config is None: - score_config = SCOREBandsConfig() - else: - score_config = request.config + score_config = SCOREBandsConfig() if request.config is None else request.config raw_objs: dict[str, list[float]] = state.state.objective_values objs = pl.DataFrame(raw_objs) diff --git a/desdeo/api/routers/generic.py b/desdeo/api/routers/generic.py index bed234def..ac4d76f7c 100644 --- a/desdeo/api/routers/generic.py +++ b/desdeo/api/routers/generic.py @@ -42,7 +42,7 @@ def solve_intermediate( context (Annotated[SessionContext, Depends]): The session context. """ db_session = context.db_session - user = context.user + user = context.user # noqa: F841 problem_db = context.problem_db interactive_session = context.interactive_session parent_state = context.parent_state diff --git a/desdeo/api/routers/nimbus.py b/desdeo/api/routers/nimbus.py index 18bf58fb1..10aa2f4a3 100644 --- a/desdeo/api/routers/nimbus.py +++ b/desdeo/api/routers/nimbus.py @@ -50,7 +50,7 @@ def filter_duplicates(solutions: list[SavedSolutionReference]) -> list[SavedSolutionReference]: """Filters out the duplicate values of objectives.""" # No solutions or only one solution. There can not be any duplicates. - if len(solutions) < 2: + if len(solutions) < 2: # noqa: PLR2004 return solutions # Get the objective values @@ -464,8 +464,7 @@ def finalize_nimbus( Args: request (NIMBUSFinalizeRequest): The request containing the final solution, etc. - user (Annotated[User, Depends): The current user. - session (Annotated[Session, Depends): The database session. + context (Annotated[SessionContext, Depends): The session context. Raises: HTTPException @@ -572,4 +571,4 @@ def delete_save( return NIMBUSDeleteSaveResponse( message="Save deleted." - ) \ No newline at end of file + ) diff --git a/desdeo/api/routers/utopia.py b/desdeo/api/routers/utopia.py index fdd7a66bd..a474730ec 100644 --- a/desdeo/api/routers/utopia.py +++ b/desdeo/api/routers/utopia.py @@ -25,16 +25,17 @@ @router.post("/") -def get_utopia_data( +def get_utopia_data( # noqa: C901 request: UtopiaRequest, context: Annotated[SessionContext, Depends(get_session_context)], ) -> UtopiaResponse: """Request and receive the Utopia map corresponding to the decision variables sent. Args: - request (UtopiaRequest): the set of decision variables and problem for which the utopia forest map is requested - for. - context (Annotated[SessionContext, Depends(get_session_context)]) the current session context + request (UtopiaRequest): the set of decision variables and problem for which + the utopia forest map is requested for. + context (Annotated[SessionContext, Depends]): The session context. + Raises: HTTPException: Returns: @@ -106,7 +107,7 @@ def treatment_index(part: str) -> str: # The dict keys get converted to ints to strings when it's loaded from database try: treatments = forest_metadata.schedule_dict[key][str(decision_variables[key].index(1))] - except ValueError as e: + except ValueError: # if the optimization didn't choose any decision alternative, it's safe to assume # that nothing is being done at that forest stand treatments = forest_metadata.schedule_dict[key]["0"] @@ -228,4 +229,4 @@ def treatment_index(part: str) -> str: map_json=json.loads(forest_metadata.map_json), description=map_description, years=forest_metadata.years, - ) \ No newline at end of file + ) diff --git a/desdeo/api/tests/test_routes.py b/desdeo/api/tests/test_routes.py index 15b90762d..483d198b2 100644 --- a/desdeo/api/tests/test_routes.py +++ b/desdeo/api/tests/test_routes.py @@ -930,9 +930,9 @@ def test_preferred_solver(client: TestClient): response = post_json(client, "/method/nimbus/initialize", request.model_dump(), access_token) model = NIMBUSInitializationResponse.model_validate(response.json()) except Exception as e: - print(e) - print("^ This outcome is expected since pyomo_cbc doesn't support nonlinear problems.") - print(" As that solver is what we set it to be in the start, we can verify that they actually get used.") + print(e) # noqa: T201 + print("^ This outcome is expected since pyomo_cbc doesn't support nonlinear problems.") # noqa: T201 + print(" As that solver is what we set it to be in the start, we can verify that they actually get used.") # noqa: T201 def test_get_available_solvers(client: TestClient): @@ -1027,7 +1027,7 @@ def test_gdm_score_bands(client: TestClient): response = post_json(client=client, endpoint="/gdm/add_to_group", json=req, access_token=access_token) assert response.status_code == 200 - access_token = login(client=client, username="dm", password="dm") + access_token = login(client=client, username="dm", password="dm") # noqa: S106 # Now we have a group, so let's get on with making stuff with gdm score bands. req = GDMScoreBandsInitializationRequest(