fixing bugs with ci pipeline

This commit is contained in:
GotthardG
2024-12-16 22:50:04 +01:00
parent e0e176881b
commit 0178de96fd
14 changed files with 145 additions and 96 deletions

View File

@ -1,4 +1,8 @@
import os, tempfile, time, random, hashlib
import os
import tempfile
import time
import random
import hashlib
from fastapi import APIRouter, HTTPException, status, Depends, Response
from sqlalchemy.orm import Session, joinedload
from typing import List
@ -21,14 +25,12 @@ from app.models import (
Sample as SampleModel,
DewarType as DewarTypeModel,
DewarSerialNumber as DewarSerialNumberModel,
Shipment as ShipmentModel, # Clearer name for model
)
from app.dependencies import get_db
import uuid
import qrcode
import io
from io import BytesIO
from PIL import ImageFont, ImageDraw, Image
from PIL import Image
from reportlab.lib.pagesizes import A5, landscape
from reportlab.lib.units import cm
from reportlab.pdfgen import canvas
@ -211,7 +213,7 @@ def generate_label(dewar):
c.drawString(2 * cm, y_position, f"Country: {return_address.country}")
y_position -= line_height
c.drawString(2 * cm, y_position, f"Beamtime Information: Placeholder")
c.drawString(2 * cm, y_position, "Beamtime Information: Placeholder")
# Generate QR code
qr = qrcode.QRCode(version=1, box_size=10, border=4)

View File

@ -34,7 +34,8 @@ def calculate_time_until_refill(
@router.post("/dewars/return", response_model=DewarSchema)
async def return_to_storage(data: LogisticsEventCreate, db: Session = Depends(get_db)):
logger.info(
f"Returning dewar to storage: {data.dewar_qr_code} at location {data.location_qr_code}"
f"Returning dewar to storage: {data.dewar_qr_code}"
f"at location {data.location_qr_code}"
)
try:
@ -57,11 +58,13 @@ async def return_to_storage(data: LogisticsEventCreate, db: Session = Depends(ge
)
if original_slot and original_slot.qr_code != data.location_qr_code:
logger.error(
f"Dewar {data.dewar_qr_code} is associated with slot {original_slot.qr_code}"
f"Dewar {data.dewar_qr_code} is"
f"associated with slot {original_slot.qr_code}"
)
raise HTTPException(
status_code=400,
detail=f"Dewar {data.dewar_qr_code} is associated with a different slot {original_slot.qr_code}.",
detail=f"Dewar {data.dewar_qr_code} is associated"
f"with a different slot {original_slot.qr_code}.",
)
slot = (
@ -87,12 +90,16 @@ async def return_to_storage(data: LogisticsEventCreate, db: Session = Depends(ge
slot.occupied = True
dewar.last_retrieved_timestamp = None
# Set the `at_beamline` attribute to False
dewar.at_beamline = False
# Log the event
log_event(db, dewar.id, slot.id, "returned")
db.commit()
logger.info(
f"Dewar {data.dewar_qr_code} successfully returned to storage slot {slot.qr_code}."
f"Dewar {data.dewar_qr_code} successfully"
f"returned to storage slot {slot.qr_code}."
)
db.refresh(dewar)
return dewar
@ -174,7 +181,8 @@ async def scan_dewar(event_data: LogisticsEventCreate, db: Session = Depends(get
log_event(db, dewar.id, slot.id if slot else None, transaction_type)
db.commit()
logger.info(
f"Transaction completed: {transaction_type} for dewar {dewar_qr_code} in slot {slot.qr_code if slot else 'N/A'}"
f"Transaction completed: {transaction_type}"
f"for dewar {dewar_qr_code} in slot {slot.qr_code if slot else 'N/A'}"
)
return {"message": "Status updated successfully"}
@ -191,7 +199,6 @@ async def get_all_slots(db: Session = Depends(get_db)):
retrievedTimestamp = None
beamlineLocation = None
at_beamline = False
retrieved = False
if slot.dewar_unique_id:
# Calculate time until refill
@ -212,32 +219,32 @@ async def get_all_slots(db: Session = Depends(get_db)):
else:
time_until_refill = -1
# Fetch the latest beamline event
last_beamline_event = (
# Fetch the latest event for the dewar
last_event = (
db.query(LogisticsEventModel)
.join(DewarModel, DewarModel.id == LogisticsEventModel.dewar_id)
.filter(
DewarModel.unique_id == slot.dewar.unique_id,
LogisticsEventModel.event_type == "beamline",
)
.filter(DewarModel.unique_id == slot.dewar.unique_id)
.order_by(LogisticsEventModel.timestamp.desc())
.first()
)
if last_beamline_event:
# Set retrievedTimestamp to the timestamp of the beamline event
retrievedTimestamp = last_beamline_event.timestamp.isoformat()
# Fetch the associated slot's label for beamlineLocation
associated_slot = (
db.query(SlotModel)
.filter(SlotModel.id == last_beamline_event.slot_id)
.first()
)
beamlineLocation = associated_slot.label if associated_slot else None
# Mark as being at a beamline
at_beamline = True
# Determine if the dewar is at the beamline
if last_event:
if last_event.event_type == "beamline":
at_beamline = True
# Optionally set retrievedTimestamp and beamlineLocation for
# beamline events
retrievedTimestamp = last_event.timestamp.isoformat()
associated_slot = (
db.query(SlotModel)
.filter(SlotModel.id == last_event.slot_id)
.first()
)
beamlineLocation = (
associated_slot.label if associated_slot else None
)
elif last_event.event_type == "returned":
at_beamline = False
# Correct the contact_person assignment
contact_person = None
@ -296,7 +303,8 @@ async def refill_dewar(qr_code: str, db: Session = Depends(get_db)):
time_until_refill_seconds = calculate_time_until_refill(now)
logger.info(
f"Dewar refilled successfully with time_until_refill: {time_until_refill_seconds}"
f"Dewar refilled successfully"
f"with time_until_refill: {time_until_refill_seconds}"
)
return {
@ -334,5 +342,6 @@ def log_event(db: Session, dewar_id: int, slot_id: Optional[int], event_type: st
db.add(new_event)
db.commit()
logger.info(
f"Logged event: {event_type} for dewar: {dewar_id} in slot: {slot_id if slot_id else 'N/A'}"
f"Logged event: {event_type} for dewar: {dewar_id} "
f"in slot: {slot_id if slot_id else 'N/A'}"
)

View File

@ -7,7 +7,6 @@ from app.schemas import (
PuckCreate,
PuckUpdate,
SetTellPosition,
PuckEvent,
)
from app.models import (
Puck as PuckModel,
@ -35,7 +34,8 @@ async def get_pucks(db: Session = Depends(get_db)):
@router.get("/with-tell-position", response_model=List[dict])
async def get_pucks_with_tell_position(db: Session = Depends(get_db)):
"""
Retrieve all pucks with a `tell_position` set (not null) and their associated samples.
Retrieve all pucks with a `tell_position`
set (not null) and their associated samples.
"""
# Query all pucks that have an event with a non-null tell_position
pucks = (
@ -157,8 +157,10 @@ async def set_tell_position(
# Create a new PuckEvent (always a new event, even with null/None)
new_puck_event = PuckEventModel(
puck_id=puck_id,
tell_position=actual_position, # Null for disassociation, else the valid position
event_type="tell_position_set", # Example event type
tell_position=actual_position,
# Null for disassociation, else the valid position
event_type="tell_position_set",
# Example event type
timestamp=datetime.utcnow(),
)
db.add(new_puck_event)
@ -232,7 +234,9 @@ async def get_pucks_by_slot(slot_identifier: str, db: Session = Depends(get_db))
if not slot_id:
raise HTTPException(
status_code=400,
detail="Invalid slot identifier. Must be an ID or one of the following: PXI, PXII, PXIII, X06SA, X10SA, X06DA.",
detail="Invalid slot identifier."
"Must be an ID or one of the following:"
"PXI, PXII, PXIII, X06SA, X10SA, X06DA.",
)
# Verify that the slot exists

View File

@ -1,7 +1,7 @@
from fastapi import APIRouter, HTTPException, status, Depends
from fastapi import APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session
from typing import List
from app.schemas import Puck as PuckSchema, Sample as SampleSchema, SampleEventCreate
from app.schemas import Puck as PuckSchema, Sample as SampleSchema
from app.models import (
Puck as PuckModel,
Sample as SampleModel,

View File

@ -2,9 +2,10 @@ from fastapi import APIRouter, HTTPException, status, Query, Depends
from sqlalchemy.orm import Session
from typing import List, Optional
import logging
from pydantic import BaseModel, ValidationError
from pydantic import ValidationError
from datetime import date
from sqlalchemy.exc import SQLAlchemyError
import json
from app.models import (
Shipment as ShipmentModel,
@ -19,12 +20,9 @@ from app.schemas import (
ShipmentCreate,
UpdateShipmentComments,
Shipment as ShipmentSchema,
DewarUpdate,
ContactPerson as ContactPersonSchema,
Sample as SampleSchema,
DewarCreate,
PuckCreate,
SampleCreate,
DewarSchema,
)
from app.database import get_db
@ -185,7 +183,8 @@ async def update_shipment(
if not contact_person:
raise HTTPException(
status_code=404,
detail=f"Contact person with ID {value} for Dewar {dewar_data.dewar_id} not found",
detail=f"Contact person with ID {value}"
f"for Dewar {dewar_data.dewar_id} not found",
)
if key == "return_address_id":
address = (
@ -194,7 +193,8 @@ async def update_shipment(
if not address:
raise HTTPException(
status_code=404,
detail=f"Address with ID {value} for Dewar {dewar_data.dewar_id} not found",
detail=f"Address with ID {value}"
f"for Dewar {dewar_data.dewar_id} not found",
)
for key, value in update_fields.items():

View File

@ -51,9 +51,12 @@ async def upload_file(file: UploadFile = File(...)):
)
# Initialize the importer and process the spreadsheet
validated_model, errors, raw_data, headers = (
importer.import_spreadsheet_with_errors(file)
)
(
validated_model,
errors,
raw_data,
headers,
) = importer.import_spreadsheet_with_errors(file)
# Extract unique values for dewars, pucks, and samples
dewars = {sample.dewarname for sample in validated_model if sample.dewarname}
@ -82,7 +85,8 @@ async def upload_file(file: UploadFile = File(...)):
row_storage.set_row(row_num, row.dict())
logger.info(
f"Returning response with {len(validated_model)} records and {len(errors)} errors."
f"Returning response with {len(validated_model)}"
f"records and {len(errors)} errors."
)
return response_data
@ -121,7 +125,9 @@ async def validate_cell(data: dict):
try:
# Ensure we're using the full row data context for validation
validated_row = SpreadsheetModel(**current_row_data)
SpreadsheetModel(
**current_row_data
) # Instantiates the Pydantic model, performing validation
logger.info(f"Validation succeeded for row {row_num}, column {col_name}")
return {"is_valid": True, "message": ""}
except ValidationError as e: