Skip to content

Commit

Permalink
refine: oton endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
MehmedGIT committed Nov 1, 2024
1 parent b5391bc commit 82f2f32
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 38 deletions.
36 changes: 8 additions & 28 deletions src/server/operandi_server/routers/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from operandi_utils.database import (
db_create_workflow, db_create_workflow_job, db_get_hpc_slurm_job, db_get_workflow, db_update_workspace,
db_increase_processing_stats_with_handling)
from operandi_utils.oton import OTONConverter
from operandi_utils.rabbitmq import (
get_connection_publisher, RABBITMQ_QUEUE_JOB_STATUSES, RABBITMQ_QUEUE_HARVESTER, RABBITMQ_QUEUE_USERS)
from operandi_server.constants import (
Expand All @@ -30,7 +29,8 @@
convert_oton_with_handling,
get_db_workflow_job_with_handling,
get_db_workflow_with_handling,
nf_script_uses_mets_server_with_handling
nf_script_uses_mets_server_with_handling,
validate_oton_with_handling
)
from .workspace_utils import check_if_file_group_exists_with_handling, get_db_workspace_with_handling
from .user import RouterUser
Expand All @@ -51,7 +51,7 @@ def __init__(self):
self.router = APIRouter(tags=[ServerApiTag.WORKFLOW])
self.router.add_api_route(
path=f"/workflow", endpoint=self.list_workflows, methods=["GET"], status_code=status.HTTP_200_OK,
summary="Get a list of existing nextflow workflows.",
summary="Get a list of existing nextflow from operandi_utils.oton import OTONConverter, OCRDValidatorworkflows.",
response_model=List[WorkflowRsrc], response_model_exclude_unset=True, response_model_exclude_none=True
)
self.router.add_api_route(
Expand Down Expand Up @@ -108,13 +108,12 @@ def __init__(self):
# Added by Faizan
self.router.add_api_route(
path="/convert_workflow",
endpoint=self.convert_txt_to_nextflow,
methods=["POST"],
status_code=status.HTTP_201_CREATED,
endpoint=self.convert_txt_to_nextflow, methods=["POST"], status_code=status.HTTP_201_CREATED,
summary="""
Upload a text file containing a workflow in ocrd process format and
convert it to a Nextflow script in the desired format (local/docker)
"""
""",
response_model=None, response_model_exclude_unset=False, response_model_exclude_none=False
)

def __del__(self):
Expand Down Expand Up @@ -448,12 +447,6 @@ async def convert_txt_to_nextflow(
# Authenticate the user
await self.user_authenticator.user_login(auth)

environments = ["local", "docker", "apptainer"]
if environment not in environments:
message = f"Unknown environment value: {environment}. Must be one of: {environments}"
self.logger.error(message)
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message)

oton_id, oton_dir = create_resource_dir(SERVER_OTON_CONVERSIONS, resource_id=None)
ocrd_process_txt = join(oton_dir, f"ocrd_process_input.txt")
nf_script_dest = join(oton_dir, f"nextflow_output.nf")
Expand All @@ -465,19 +458,6 @@ async def convert_txt_to_nextflow(
self.logger.error(f"{message}, error: {error}")
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message)

# Use the Converter's convert_OtoN function instead of directly calling OCRDValidator
converter = OTONConverter()
try:
# Call the conversion function (this will also perform validation inside)
if environment == "local":
converter.convert_oton_env_local(str(ocrd_process_txt), str(nf_script_dest))
elif environment == "docker":
converter.convert_oton_env_docker(str(ocrd_process_txt), str(nf_script_dest))
elif environment == "apptainer":
converter.convert_oton_env_apptainer(str(ocrd_process_txt), str(nf_script_dest))
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))

# Return the generated Nextflow (.nf) file as a response

await validate_oton_with_handling(self.logger, ocrd_process_txt)
await convert_oton_with_handling(self.logger, environment, ocrd_process_txt, nf_script_dest)
return FileResponse(nf_script_dest, filename=f'{oton_id}.nf')
31 changes: 29 additions & 2 deletions src/server/operandi_server/routers/workflow_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from operandi_utils.database import db_get_workflow, db_get_workflow_job
from operandi_utils.database.models import DBWorkflow, DBWorkflowJob
from operandi_utils.oton import OTONConverter, OCRDValidator


async def get_db_workflow_with_handling(
Expand Down Expand Up @@ -56,5 +57,31 @@ async def nf_script_uses_mets_server_with_handling(
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=message)


async def convert_oton_with_handling():
pass
async def validate_oton_with_handling(logger, ocrd_process_txt_path: str):
try:
# Separate validation for refined error logging
validator = OCRDValidator()
validator.validate(input_file=ocrd_process_txt_path)
except ValueError as error:
message = "Failed to validate the ocrd process workflow txt file"
logger.error(f"{message}, error: {error}")
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message)

async def convert_oton_with_handling(logger, environment: str, ocrd_process_txt_path: str, nf_script_dest_path: str):
environments = ["local", "docker", "apptainer"]
if environment not in environments:
message = f"Unknown environment value: {environment}. Must be one of: {environments}"
logger.error(message)
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message)
try:
converter = OTONConverter()
if environment == "local":
converter.convert_oton_env_local(str(ocrd_process_txt_path), str(nf_script_dest_path))
elif environment == "docker":
converter.convert_oton_env_docker(str(ocrd_process_txt_path), str(nf_script_dest_path))
elif environment == "apptainer":
converter.convert_oton_env_apptainer(str(ocrd_process_txt_path), str(nf_script_dest_path))
except ValueError as error:
message = "Failed to convert ocrd process workflow to nextflow workflow"
logger.error(f"{message}, error: {error}")
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=message)
4 changes: 3 additions & 1 deletion src/server/operandi_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from operandi_utils.database import db_initiate_database
from operandi_utils import safe_init_logging

from operandi_server.constants import SERVER_WORKFLOW_JOBS_ROUTER, SERVER_WORKFLOWS_ROUTER, SERVER_WORKSPACES_ROUTER
from operandi_server.constants import (
SERVER_OTON_CONVERSIONS, SERVER_WORKFLOW_JOBS_ROUTER, SERVER_WORKFLOWS_ROUTER, SERVER_WORKSPACES_ROUTER)
from operandi_server.files_manager import create_resource_base_dir
from operandi_server.routers import RouterAdminPanel, RouterDiscovery, RouterUser, RouterWorkflow, RouterWorkspace
from operandi_server.routers.user_utils import create_user_if_not_available
Expand Down Expand Up @@ -81,6 +82,7 @@ async def startup_event(self):
# Reconfigure all loggers to the same format
reconfigure_all_loggers(log_level=LOG_LEVEL_SERVER, log_file_path=log_file_path)

create_resource_base_dir(SERVER_OTON_CONVERSIONS)
create_resource_base_dir(SERVER_WORKFLOW_JOBS_ROUTER)
create_resource_base_dir(SERVER_WORKFLOWS_ROUTER)
create_resource_base_dir(SERVER_WORKSPACES_ROUTER)
Expand Down
2 changes: 1 addition & 1 deletion src/utils/operandi_utils/oton/ocrd_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def validate_processor_params(
report = ParameterValidator(processor_args.ocrd_tool_json).validate(processor_args.parameters)
if not report.is_valid:
self.logger.error(report.errors)
raise Exception(report.errors)
raise ValueError(report.errors)

# Remove the overwritten defaults to keep the produced NF executable file less populated
# Note: The defaults, still get overwritten in run-time
Expand Down
1 change: 0 additions & 1 deletion src/utils/operandi_utils/oton/oton_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ def __init__(self):
self.ocrd_validator = OCRDValidator()

def __convert_oton(self, input_path: str, output_path: str, environment: str):
self.ocrd_validator.validate(input_path)
list_processor_call_arguments = self.ocrd_validator.validate(input_path)
nf_file_executable = NextflowFileExecutable()
if environment == "local":
Expand Down
2 changes: 1 addition & 1 deletion tests/tests_server/test_endpoint_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def test_convert_txt_to_nextflow_validator_failure(operandi, auth):

response = operandi.post(url="/convert_workflow", files=files, auth=auth, params=params)
assert_response_status_code(response.status_code, expected_floor=4)
assert "Invalid first line. Expected: 'ocrd process', got: 'Invalid ocrd process text" in response.json()["detail"]
assert "Failed to validate the ocrd process workflow txt file" in response.json()["detail"]


# Added by Faizan
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ def test_falseness_basic(ocrd_parser, ocrd_validator):
def test_falseness_with_params_separated(ocrd_parser, ocrd_validator):
call_args: ProcessorCallArguments = ocrd_parser.parse_arguments(
"cis-ocropy-binarize -I OCR-D-IMG -O OCR-D-BIN -P dpi 177.0 -P non-existing-param 0.42")
with raises(Exception):
with raises(ValueError):
ocrd_validator.validate_processor_params(processor_args=call_args, overwrite_with_defaults=False)
with raises(Exception):
with raises(ValueError):
ocrd_validator.validate_processor_params(processor_args=call_args, overwrite_with_defaults=True)


def test_falseness_with_params_clustered(ocrd_parser, ocrd_validator):
call_args: ProcessorCallArguments = ocrd_parser.parse_arguments(
"""cis-ocropy-binarize -I OCR-D-IMG -O OCR-D-BIN -p '{"dpi": 177.0, "non-existing-param": 0.42}'""")
with raises(Exception):
with raises(ValueError):
ocrd_validator.validate_processor_params(processor_args=call_args, overwrite_with_defaults=False)
with raises(Exception):
with raises(ValueError):
ocrd_validator.validate_processor_params(processor_args=call_args, overwrite_with_defaults=True)

0 comments on commit 82f2f32

Please sign in to comment.