From 930e0984130bfe5176b3a9833cee4347793e474d Mon Sep 17 00:00:00 2001 From: RAYemelyanova <90774497+RAYemelyanova@users.noreply.github.com> Date: Wed, 30 Nov 2022 12:10:30 +0000 Subject: [PATCH] Remove Unions (#137) * removed union response models from getters of surface normals and reference vectors * removed CoordinateResponse object and separated into other response models --- src/diffcalc_api/models/response.py | 29 ++++++++--- src/diffcalc_api/routes/hkl.py | 8 +-- src/diffcalc_api/routes/ub.py | 75 ++++++++++++++--------------- tests/test_ubcalc.py | 9 ++++ 4 files changed, 71 insertions(+), 50 deletions(-) diff --git a/src/diffcalc_api/models/response.py b/src/diffcalc_api/models/response.py index 12c26ea..1ae7f3a 100644 --- a/src/diffcalc_api/models/response.py +++ b/src/diffcalc_api/models/response.py @@ -1,5 +1,5 @@ """Pydantic models relating to all endpoint responses.""" -from typing import Dict, List, Union +from typing import Dict, List from pydantic import BaseModel @@ -46,14 +46,31 @@ class DiffractorAnglesResponse(BaseModel): payload: List[Dict[str, float]] -class CoordinateResponse(BaseModel): - """Coordinate response model. +class SphericalResponse(BaseModel): + """Spherical coordinate response model. - Returns coordinates, in three dimensions, for a given coordinate system. - Supported systems include spherical coordinates, reciprocal and real space. + Returns a payload in spherical coordinates. """ - payload: Union[SphericalCoordinates, HklModel, XyzModel] + payload: SphericalCoordinates + + +class ReciprocalSpaceResponse(BaseModel): + """Reciprocal space coordinate response model. + + Returns a payload in reciprocal space (hkl) coordinates. + """ + + payload: HklModel + + +class RealSpaceResponse(BaseModel): + """Reciprocal space coordinate response model. + + Returns a payload in xyz coordinates. + """ + + payload: XyzModel class MiscutResponse(BaseModel): diff --git a/src/diffcalc_api/routes/hkl.py b/src/diffcalc_api/routes/hkl.py index f5a9207..fd800ed 100644 --- a/src/diffcalc_api/routes/hkl.py +++ b/src/diffcalc_api/routes/hkl.py @@ -7,8 +7,8 @@ from diffcalc_api.errors.hkl import InvalidSolutionBoundsError from diffcalc_api.models.hkl import SolutionConstraints from diffcalc_api.models.response import ( - CoordinateResponse, DiffractorAnglesResponse, + ReciprocalSpaceResponse, ScanResponse, ) from diffcalc_api.models.ub import HklModel, PositionModel @@ -60,7 +60,7 @@ async def lab_position_from_miller_indices( return DiffractorAnglesResponse(payload=positions) -@router.get("/{name}/position/hkl", response_model=CoordinateResponse) +@router.get("/{name}/position/hkl", response_model=ReciprocalSpaceResponse) async def miller_indices_from_lab_position( name: str, pos: PositionModel = Depends(), @@ -78,12 +78,12 @@ async def miller_indices_from_lab_position( collection: collection within which the hkl object resides. Returns: - CoordinateResponse containing the miller indices. + ReciprocalSpaceResponse containing the miller indices. """ hkl = await service.miller_indices_from_lab_position( name, pos, wavelength, store, collection ) - return CoordinateResponse(payload=hkl) + return ReciprocalSpaceResponse(payload=hkl) @router.get("/{name}/scan/hkl", response_model=ScanResponse) diff --git a/src/diffcalc_api/routes/ub.py b/src/diffcalc_api/routes/ub.py index 19cb98d..96bd73e 100644 --- a/src/diffcalc_api/routes/ub.py +++ b/src/diffcalc_api/routes/ub.py @@ -1,6 +1,6 @@ """Endpoints relating to the management of setting up the UB calculation.""" -from typing import List, Optional, Union +from typing import List, Optional, cast from fastapi import APIRouter, Body, Depends, Query @@ -12,9 +12,10 @@ from diffcalc_api.examples import ub as examples from diffcalc_api.models.response import ( ArrayResponse, - CoordinateResponse, InfoResponse, MiscutResponse, + ReciprocalSpaceResponse, + SphericalResponse, StringResponse, ) from diffcalc_api.models.ub import ( @@ -611,7 +612,7 @@ async def set_miller_surface_normal( ) -@router.get("/{name}/nphi", response_model=Union[ArrayResponse, InfoResponse]) +@router.get("/{name}/nphi", response_model=ArrayResponse) async def get_lab_reference_vector( name: str, store: HklCalcStore = Depends(get_store), @@ -625,20 +626,20 @@ async def get_lab_reference_vector( collection: collection within which the hkl object resides. Returns: - ArrayResponse with the vector, or - InfoResponse if it doesn't exist + ArrayResponse with the vector. If it doesn't exist, a null vector is returned. """ - lab_vector: Optional[List[List[float]]] = await service.get_lab_reference_vector( + vector: Optional[List[List[float]]] = await service.get_lab_reference_vector( name, store, collection ) - if lab_vector is not None: - return ArrayResponse(payload=lab_vector) - else: - return InfoResponse(message="This vector does not exist.") + if vector is None: + return ArrayResponse(payload=[[]]) -@router.get("/{name}/nhkl", response_model=Union[ArrayResponse, InfoResponse]) + return ArrayResponse(payload=vector) + + +@router.get("/{name}/nhkl", response_model=ArrayResponse) async def get_miller_reference_vector( name: str, store: HklCalcStore = Depends(get_store), @@ -652,20 +653,18 @@ async def get_miller_reference_vector( collection: collection within which the hkl object resides. Returns: - ArrayResponse with the vector, or - InfoResponse if it doesn't exist + ArrayResponse with the vector. By default, newly instantiated + Hkl objects always have this vector. """ - lab_vector: Optional[List[List[float]]] = await service.get_miller_reference_vector( + vector: Optional[List[List[float]]] = await service.get_miller_reference_vector( name, store, collection ) - if lab_vector is not None: - return ArrayResponse(payload=lab_vector) - else: - return InfoResponse(message="This vector does not exist.") + return ArrayResponse(payload=cast(List[List[float]], vector)) -@router.get("/{name}/surface/nphi", response_model=Union[ArrayResponse, InfoResponse]) + +@router.get("/{name}/surface/nphi", response_model=ArrayResponse) async def get_lab_surface_normal( name: str, store: HklCalcStore = Depends(get_store), @@ -679,20 +678,17 @@ async def get_lab_surface_normal( collection: collection within which the hkl object resides. Returns: - ArrayResponse with the vector, or - InfoResponse if it doesn't exist + ArrayResponse with the vector. By default, newly instantiated + Hkl objects always have this vector. """ - lab_vector: Optional[List[List[float]]] = await service.get_lab_surface_normal( + vector: Optional[List[List[float]]] = await service.get_lab_surface_normal( name, store, collection ) - if lab_vector is not None: - return ArrayResponse(payload=lab_vector) - else: - return InfoResponse(message="This vector does not exist.") + return ArrayResponse(payload=cast(List[List[float]], vector)) -@router.get("/{name}/surface/nhkl", response_model=Union[ArrayResponse, InfoResponse]) +@router.get("/{name}/surface/nhkl", response_model=ArrayResponse) async def get_miller_surface_normal( name: str, store: HklCalcStore = Depends(get_store), @@ -706,17 +702,14 @@ async def get_miller_surface_normal( collection: collection within which the hkl object resides. Returns: - ArrayResponse with the vector, or - InfoResponse if it doesn't exist + ArrayResponse with the vector. By default, newly instantiated + Hkl objects always have this vector. """ - lab_vector: Optional[List[List[float]]] = await service.get_miller_surface_normal( + vector: Optional[List[List[float]]] = await service.get_miller_surface_normal( name, store, collection ) - if lab_vector is not None: - return ArrayResponse(payload=lab_vector) - else: - return InfoResponse(message="This vector does not exist.") + return ArrayResponse(payload=cast(List[List[float]], vector)) ####################################################################################### @@ -724,7 +717,7 @@ async def get_miller_surface_normal( ####################################################################################### -@router.get("/{name}/vector", response_model=CoordinateResponse) +@router.get("/{name}/vector", response_model=ReciprocalSpaceResponse) async def calculate_vector_from_hkl_and_offset( name: str, hkl_ref: HklModel = Depends(), @@ -747,7 +740,7 @@ async def calculate_vector_from_hkl_and_offset( collection: collection within which the hkl object resides. Returns: - CoordinateResponse + ReciprocalSpaceResponse Containing the calculated reciprocal space vector as h, k, l indices. """ @@ -755,10 +748,12 @@ async def calculate_vector_from_hkl_and_offset( name, hkl_ref, polar_angle, azimuth_angle, store, collection ) - return CoordinateResponse(payload=HklModel(h=vector[0], k=vector[1], l=vector[2])) + return ReciprocalSpaceResponse( + payload=HklModel(h=vector[0], k=vector[1], l=vector[2]) + ) -@router.get("/{name}/offset", response_model=CoordinateResponse) +@router.get("/{name}/offset", response_model=SphericalResponse) async def calculate_offset_from_vector_and_hkl( name: str, h1: float = Query(..., example=0.0), @@ -787,7 +782,7 @@ async def calculate_offset_from_vector_and_hkl( collection: collection within which the hkl object resides. Returns: - CoordinateResponse + SphericalResponse The offset, in spherical coordinates, between the two reciprocal space vectors, containing the polar angle, azimuth angle and magnitude between them. @@ -799,7 +794,7 @@ async def calculate_offset_from_vector_and_hkl( name, hkl_offset, hkl_ref, store, collection ) - return CoordinateResponse( + return SphericalResponse( payload=SphericalCoordinates( polar_angle=vector[0], azimuth_angle=vector[1], magnitude=vector[2] ) diff --git a/tests/test_ubcalc.py b/tests/test_ubcalc.py index 2bef1f6..2aa0445 100644 --- a/tests/test_ubcalc.py +++ b/tests/test_ubcalc.py @@ -476,6 +476,15 @@ def test_get_and_set_reference_vectors_hkl( ) +def test_get_reference_vectors_for_null_vectors(): + ubcalc = UBCalculation() + hkl = HklCalculation(ubcalc, Constraints()) + client = Client(hkl).client + + response = client.get("/ub/test/nphi?collection=B07") + assert literal_eval(response.content.decode())["payload"] == [[]] + + def test_calculate_vector_from_hkl_and_offset(): ubcalc = UBCalculation() ubcalc.UB = np.identity(3)