diff --git a/README_pypi.md b/README_pypi.md index e01e6ff..51eb032 100644 --- a/README_pypi.md +++ b/README_pypi.md @@ -463,7 +463,7 @@ Options: The `validate` command will check that a Batch can be created from a given CSV and if your user account has permission to upload the samples, the individual FastQ files are then checked for validity. These checks are already performed -by default with the `upload` command but using this can ensure validity without commiting to the subsequent upload +by default with the `upload` command but using this can ensure validity without committing to the subsequent upload if you're looking to check a CSV during writing it. ## `pathogena query-raw` diff --git a/src/pathogena/cli.py b/src/pathogena/cli.py index 3c2f018..0b0d977 100644 --- a/src/pathogena/cli.py +++ b/src/pathogena/cli.py @@ -321,7 +321,7 @@ def validate(upload_csv: Path, *, host: str | None = None) -> None: """Validate a given upload CSV.""" host = lib.get_host(host) batch = models.create_batch_from_csv(upload_csv) - lib.upload_batch(batch=batch, host=host, save=False, validate_only=True) + lib.validate_csv(host=host, batch=batch) lib.validate_upload_permissions(batch=batch, protocol=lib.get_protocol(), host=host) batch.validate_all_sample_fastqs() logging.info(f"Successfully validated {upload_csv}") diff --git a/src/pathogena/lib.py b/src/pathogena/lib.py index 96ae4bc..195a7d6 100644 --- a/src/pathogena/lib.py +++ b/src/pathogena/lib.py @@ -163,11 +163,77 @@ def get_credit_balance(host: str) -> None: ) +def validate_csv(host: str, batch: UploadBatch): + """Validates the CSV prior to upload. + + Calls `/validate_creation` in Portal to validate payload - endpoint returns 422 if issues are found. + + Args: + batch (models.UploadBatch): The batch of samples to decontaminate + host (str): The host server. + + Returns: + None + """ + instrument_platform = batch.samples[0].instrument_platform + collection_date = batch.samples[0].collection_date + country = batch.samples[0].country + telemetry_data = { + "client": { + "name": "pathogena-client", + "version": pathogena.__version__, + }, + "decontamination": { + "name": "hostile", + "version": hostile.__version__, + }, + "specimen_organism": batch.samples[0].specimen_organism, + } + + local_batch_name = ( + batch.samples[0].batch_name + if batch.samples[0].batch_name not in ["", " ", None] + else f"batch_{collection_date}" + ) + data = { + "collection_date": str(collection_date), + "instrument": instrument_platform, + "country": country, + "name": local_batch_name, + "amplicon_scheme": "amplicon_scheme", + "telemetry_data": telemetry_data, + } + try: + with httpx.Client( + event_hooks=httpx_hooks, + transport=httpx.HTTPTransport(retries=5), + timeout=60, + follow_redirects=True, + ) as client: + try: + validation_response = client.post( + f"{get_protocol()}://{host}/api/v1/batches/validate_creation", + headers={ + "Authorization": f"Bearer {util.get_access_token(host)}", + "accept": "application/json", + }, + json=data, + follow_redirects=True, + ) + except Exception as e: + logging.error(f"Error validating CSV: {e}") + assert validation_response.status_code == 200 + except AssertionError: + logging.error( + f"Unexpected response code from CSV validation. Response: {validation_response}" + ) + exit(1) + + def create_batch_on_server( batch: UploadBatch, host: str, amplicon_scheme: str | None, - validate_only: bool = False, ) -> tuple[str, str, str, str]: """Create batch on server, return batch id. @@ -175,10 +241,9 @@ def create_batch_on_server( total samples in the BatchModel. Args: + batch (models.UploadBatch): The batch of samples to decontaminate host (str): The host server. - number_of_samples (int): The expected number of samples in the batch. amplicon_scheme (str | None): The amplicon scheme to use. - validate_only (bool): Whether to validate only. Defaults to False. Returns: tuple[str, str]: The batch ID and name. @@ -213,9 +278,7 @@ def create_batch_on_server( "telemetry_data": telemetry_data, } - url = f"{get_protocol()}://{host}/api/v1/batches" - if validate_only: - url += "/validate_creation" + url = f"{get_protocol()}://{get_upload_host()}/api/v1/batches/" try: with httpx.Client( event_hooks=httpx_hooks, @@ -224,7 +287,7 @@ def create_batch_on_server( follow_redirects=True, ) as client: batch_create_response = client.post( - f"{get_protocol()}://{get_upload_host()}/api/v1/batches/", + url, headers={ "Authorization": f"Bearer {util.get_access_token(host)}", "accept": "application/json", @@ -232,9 +295,6 @@ def create_batch_on_server( json=data, follow_redirects=True, ) - if validate_only: - # Don't attempt to return data if just validating (as there's none there) - return None, None, None, None # type: ignore created_batch = batch_create_response.json() batch_id = created_batch["id"]