aind-data-transfer-service 1.17.0__py3-none-any.whl → 1.17.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  """Init package"""
2
2
  import os
3
3
 
4
- __version__ = "1.17.0"
4
+ __version__ = "1.17.2"
5
5
 
6
6
  # Global constants
7
7
  OPEN_DATA_BUCKET_NAME = os.getenv("OPEN_DATA_BUCKET_NAME", "open")
@@ -3,10 +3,9 @@
3
3
  import json
4
4
  from typing import List, Optional, Union
5
5
 
6
- import requests
6
+ from httpx import AsyncClient, Response
7
7
  from pydantic import Field, SecretStr, field_validator
8
8
  from pydantic_settings import BaseSettings
9
- from requests.models import Response
10
9
 
11
10
  from aind_data_transfer_service.hpc.models import HpcJobSubmitSettings
12
11
 
@@ -75,37 +74,41 @@ class HpcClient:
75
74
  "X-SLURM-USER-TOKEN": self.configs.hpc_token.get_secret_value(),
76
75
  }
77
76
 
78
- def get_node_status(self) -> Response:
77
+ async def get_node_status(self) -> Response:
79
78
  """Get status of nodes"""
80
- response = requests.get(
81
- url=self._node_status_url, headers=self.__headers
82
- )
79
+ async with AsyncClient() as async_client:
80
+ response = await async_client.get(
81
+ url=self._node_status_url, headers=self.__headers
82
+ )
83
83
  return response
84
84
 
85
- def get_job_status(self, job_id: Union[str, int]) -> Response:
85
+ async def get_job_status(self, job_id: Union[str, int]) -> Response:
86
86
  """Get status of job"""
87
- response = requests.get(
88
- url=self._job_status_url + "/" + str(job_id),
89
- headers=self.__headers,
90
- )
87
+ async with AsyncClient() as async_client:
88
+ response = await async_client.get(
89
+ url=self._job_status_url + "/" + str(job_id),
90
+ headers=self.__headers,
91
+ )
91
92
  return response
92
93
 
93
- def get_jobs(self) -> Response:
94
+ async def get_jobs(self) -> Response:
94
95
  """Get status of job"""
95
- response = requests.get(
96
- url=self._jobs_url,
97
- headers=self.__headers,
98
- )
96
+ async with AsyncClient() as async_client:
97
+ response = await async_client.get(
98
+ url=self._jobs_url,
99
+ headers=self.__headers,
100
+ )
99
101
  return response
100
102
 
101
- def submit_job(self, job_def: dict) -> Response:
103
+ async def submit_job(self, job_def: dict) -> Response:
102
104
  """Submit a job defined by job def"""
103
- response = requests.post(
104
- url=self._job_submit_url, json=job_def, headers=self.__headers
105
- )
105
+ async with AsyncClient() as async_client:
106
+ response = await async_client.post(
107
+ url=self._job_submit_url, json=job_def, headers=self.__headers
108
+ )
106
109
  return response
107
110
 
108
- def submit_hpc_job(
111
+ async def submit_hpc_job(
109
112
  self,
110
113
  script: str,
111
114
  job: Optional[HpcJobSubmitSettings] = None,
@@ -144,8 +147,8 @@ class HpcClient:
144
147
  ],
145
148
  "script": script,
146
149
  }
147
-
148
- response = requests.post(
149
- url=self._job_submit_url, json=job_def, headers=self.__headers
150
- )
150
+ async with AsyncClient() as async_client:
151
+ response = await async_client.post(
152
+ url=self._job_submit_url, json=job_def, headers=self.__headers
153
+ )
151
154
  return response
@@ -10,7 +10,6 @@ from pathlib import PurePosixPath
10
10
  from typing import Any, List, Optional, Union
11
11
 
12
12
  import boto3
13
- import requests
14
13
  from aind_data_transfer_models import (
15
14
  __version__ as aind_data_transfer_models_version,
16
15
  )
@@ -96,12 +95,13 @@ logger = get_logger(log_configs=LoggingConfigs())
96
95
  project_names_url = os.getenv("AIND_METADATA_SERVICE_PROJECT_NAMES_URL")
97
96
 
98
97
 
99
- def get_project_names() -> List[str]:
98
+ async def get_project_names() -> List[str]:
100
99
  """Get a list of project_names"""
101
100
  # TODO: Cache response for 5 minutes
102
- response = requests.get(project_names_url)
103
- response.raise_for_status()
104
- project_names = response.json()["data"]
101
+ async with AsyncClient() as async_client:
102
+ response = await async_client.get(project_names_url)
103
+ response.raise_for_status()
104
+ project_names = response.json()["data"]
105
105
  return project_names
106
106
 
107
107
 
@@ -281,7 +281,7 @@ async def validate_csv(request: Request):
281
281
  )
282
282
  context = {
283
283
  "job_types": get_job_types("v2"),
284
- "project_names": get_project_names(),
284
+ "project_names": await get_project_names(),
285
285
  "current_jobs": current_jobs,
286
286
  }
287
287
  for row in csv_reader:
@@ -375,7 +375,7 @@ async def validate_json_v2(request: Request):
375
375
  _, current_jobs = await get_airflow_jobs(params=params, get_confs=True)
376
376
  context = {
377
377
  "job_types": get_job_types("v2"),
378
- "project_names": get_project_names(),
378
+ "project_names": await get_project_names(),
379
379
  "current_jobs": current_jobs,
380
380
  }
381
381
  with validation_context_v2(context):
@@ -431,7 +431,7 @@ async def validate_json(request: Request):
431
431
  logger.info("Received request to validate json")
432
432
  content = await request.json()
433
433
  try:
434
- project_names = get_project_names()
434
+ project_names = await get_project_names()
435
435
  with validation_context({"project_names": project_names}):
436
436
  validated_model = SubmitJobRequest.model_validate_json(
437
437
  json.dumps(content)
@@ -491,7 +491,7 @@ async def submit_jobs_v2(request: Request):
491
491
  _, current_jobs = await get_airflow_jobs(params=params, get_confs=True)
492
492
  context = {
493
493
  "job_types": get_job_types("v2"),
494
- "project_names": get_project_names(),
494
+ "project_names": await get_project_names(),
495
495
  "current_jobs": current_jobs,
496
496
  }
497
497
  with validation_context_v2(context):
@@ -499,7 +499,6 @@ async def submit_jobs_v2(request: Request):
499
499
  full_content = json.loads(
500
500
  model.model_dump_json(warnings=False, exclude_none=True)
501
501
  )
502
- # TODO: Replace with httpx async client
503
502
  logger.info(
504
503
  f"Valid request detected. Sending list of jobs. "
505
504
  f"dag_id: {model.dag_id}"
@@ -511,19 +510,23 @@ async def submit_jobs_v2(request: Request):
511
510
  f"{job_index} of {total_jobs}."
512
511
  )
513
512
 
514
- response = requests.post(
515
- url=os.getenv("AIND_AIRFLOW_SERVICE_URL"),
513
+ async with AsyncClient(
516
514
  auth=(
517
515
  os.getenv("AIND_AIRFLOW_SERVICE_USER"),
518
516
  os.getenv("AIND_AIRFLOW_SERVICE_PASSWORD"),
519
- ),
520
- json={"conf": full_content},
521
- )
517
+ )
518
+ ) as async_client:
519
+ response = await async_client.post(
520
+ url=os.getenv("AIND_AIRFLOW_SERVICE_URL"),
521
+ json={"conf": full_content},
522
+ )
523
+ status_code = response.status_code
524
+ response_json = response.json()
522
525
  return JSONResponse(
523
- status_code=response.status_code,
526
+ status_code=status_code,
524
527
  content={
525
528
  "message": "Submitted request to airflow",
526
- "data": {"responses": [response.json()], "errors": []},
529
+ "data": {"responses": [response_json], "errors": []},
527
530
  },
528
531
  )
529
532
  except ValidationError as e:
@@ -551,13 +554,12 @@ async def submit_jobs(request: Request):
551
554
  logger.info("Received request to submit jobs")
552
555
  content = await request.json()
553
556
  try:
554
- project_names = get_project_names()
557
+ project_names = await get_project_names()
555
558
  with validation_context({"project_names": project_names}):
556
559
  model = SubmitJobRequest.model_validate_json(json.dumps(content))
557
560
  full_content = json.loads(
558
561
  model.model_dump_json(warnings=False, exclude_none=True)
559
562
  )
560
- # TODO: Replace with httpx async client
561
563
  logger.info(
562
564
  f"Valid request detected. Sending list of jobs. "
563
565
  f"Job Type: {model.job_type}"
@@ -569,19 +571,23 @@ async def submit_jobs(request: Request):
569
571
  f"{job_index} of {total_jobs}."
570
572
  )
571
573
 
572
- response = requests.post(
573
- url=os.getenv("AIND_AIRFLOW_SERVICE_URL"),
574
+ async with AsyncClient(
574
575
  auth=(
575
576
  os.getenv("AIND_AIRFLOW_SERVICE_USER"),
576
577
  os.getenv("AIND_AIRFLOW_SERVICE_PASSWORD"),
577
- ),
578
- json={"conf": full_content},
579
- )
578
+ )
579
+ ) as async_client:
580
+ response = await async_client.post(
581
+ url=os.getenv("AIND_AIRFLOW_SERVICE_URL"),
582
+ json={"conf": full_content},
583
+ )
584
+ status_code = response.status_code
585
+ response_json = response.json()
580
586
  return JSONResponse(
581
- status_code=response.status_code,
587
+ status_code=status_code,
582
588
  content={
583
589
  "message": "Submitted request to airflow",
584
- "data": {"responses": [response.json()], "errors": []},
590
+ "data": {"responses": [response_json], "errors": []},
585
591
  },
586
592
  )
587
593
 
@@ -645,7 +651,7 @@ async def submit_basic_jobs(request: Request):
645
651
  for hpc_job in hpc_jobs:
646
652
  try:
647
653
  job_def = hpc_job.job_definition
648
- response = hpc_client.submit_job(job_def)
654
+ response = await hpc_client.submit_job(job_def)
649
655
  response_json = response.json()
650
656
  responses.append(response_json)
651
657
  # Add pause to stagger job requests to the hpc
@@ -769,7 +775,7 @@ async def submit_hpc_jobs(request: Request): # noqa: C901
769
775
  hpc_job_def = hpc_job[0]
770
776
  try:
771
777
  script = hpc_job[1]
772
- response = hpc_client.submit_hpc_job(
778
+ response = await hpc_client.submit_hpc_job(
773
779
  job=hpc_job_def, script=script
774
780
  )
775
781
  response_json = response.json()
@@ -842,20 +848,23 @@ async def get_tasks_list(request: Request):
842
848
  request.query_params
843
849
  )
844
850
  params_dict = json.loads(params.model_dump_json())
845
- response_tasks = requests.get(
846
- url=(
847
- f"{url}/{params.dag_id}/dagRuns/{params.dag_run_id}/"
848
- "taskInstances"
849
- ),
851
+ async with AsyncClient(
850
852
  auth=(
851
853
  os.getenv("AIND_AIRFLOW_SERVICE_USER"),
852
854
  os.getenv("AIND_AIRFLOW_SERVICE_PASSWORD"),
853
- ),
854
- )
855
- status_code = response_tasks.status_code
856
- if response_tasks.status_code == 200:
855
+ )
856
+ ) as async_client:
857
+ response_tasks = await async_client.get(
858
+ url=(
859
+ f"{url}/{params.dag_id}/dagRuns/{params.dag_run_id}/"
860
+ "taskInstances"
861
+ ),
862
+ )
863
+ status_code = response_tasks.status_code
864
+ response_json = response_tasks.json()
865
+ if status_code == 200:
857
866
  task_instances = AirflowTaskInstancesResponse.model_validate_json(
858
- json.dumps(response_tasks.json())
867
+ json.dumps(response_json)
859
868
  )
860
869
  job_tasks_list = sorted(
861
870
  [
@@ -876,7 +885,7 @@ async def get_tasks_list(request: Request):
876
885
  message = "Error retrieving job tasks list from airflow"
877
886
  data = {
878
887
  "params": params_dict,
879
- "errors": [response_tasks.json()],
888
+ "errors": [response_json],
880
889
  }
881
890
  except ValidationError as e:
882
891
  logger.warning(f"There was a validation error process task_list: {e}")
@@ -906,27 +915,29 @@ async def get_task_logs(request: Request):
906
915
  )
907
916
  params_dict = json.loads(params.model_dump_json())
908
917
  params_full = dict(params)
909
- response_logs = requests.get(
910
- url=(
911
- f"{url}/{params.dag_id}/dagRuns/{params.dag_run_id}"
912
- f"/taskInstances/{params.task_id}/logs/{params.try_number}"
913
- ),
918
+ async with AsyncClient(
914
919
  auth=(
915
920
  os.getenv("AIND_AIRFLOW_SERVICE_USER"),
916
921
  os.getenv("AIND_AIRFLOW_SERVICE_PASSWORD"),
917
- ),
918
- params=params_dict,
919
- )
920
- status_code = response_logs.status_code
921
- if response_logs.status_code == 200:
922
- message = "Retrieved task logs from airflow"
923
- data = {"params": params_full, "logs": response_logs.text}
924
- else:
925
- message = "Error retrieving task logs from airflow"
926
- data = {
927
- "params": params_full,
928
- "errors": [response_logs.json()],
929
- }
922
+ )
923
+ ) as async_client:
924
+ response_logs = await async_client.get(
925
+ url=(
926
+ f"{url}/{params.dag_id}/dagRuns/{params.dag_run_id}"
927
+ f"/taskInstances/{params.task_id}/logs/{params.try_number}"
928
+ ),
929
+ params=params_dict,
930
+ )
931
+ status_code = response_logs.status_code
932
+ if status_code == 200:
933
+ message = "Retrieved task logs from airflow"
934
+ data = {"params": params_full, "logs": response_logs.text}
935
+ else:
936
+ message = "Error retrieving task logs from airflow"
937
+ data = {
938
+ "params": params_full,
939
+ "errors": [response_logs.json()],
940
+ }
930
941
  except ValidationError as e:
931
942
  logger.warning(f"Error validating request parameters: {e}")
932
943
  status_code = 406
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aind-data-transfer-service
3
- Version: 1.17.0
3
+ Version: 1.17.2
4
4
  Summary: Service that handles requests to upload data to the cloud
5
5
  Author: Allen Institute for Neural Dynamics
6
6
  License: MIT
@@ -0,0 +1,18 @@
1
+ aind_data_transfer_service/__init__.py,sha256=cCMYl-lxHhXlEMAHdJ7INgHPd0O6ETEp9wsqf6DT8TQ,272
2
+ aind_data_transfer_service/log_handler.py,sha256=c7a-gLmZeRpeCUBwCz6XsTszWXQeQdR7eKZtas4llXM,1700
3
+ aind_data_transfer_service/server.py,sha256=CQdOkX86qn8RQm36NqS5b0aUyNCjvaEbTIObaza6RY0,48910
4
+ aind_data_transfer_service/configs/__init__.py,sha256=9W5GTuso9Is1B9X16RXcdb_GxasZvj6qDzOBDv0AbTc,36
5
+ aind_data_transfer_service/configs/csv_handler.py,sha256=hCdfAYZW_49-l1rbua5On2Tw2ks674Z-MgB_NJlIkU4,5746
6
+ aind_data_transfer_service/configs/job_configs.py,sha256=T-h5N6lyY9xTZ_xg_5FxkyYuMdagApbE6xalxFQ-bqA,18848
7
+ aind_data_transfer_service/configs/job_upload_template.py,sha256=aC5m1uD_YcpbggFQ-yZ7ZJSUUGX1yQqQLF3SwmljrLk,5127
8
+ aind_data_transfer_service/hpc/__init__.py,sha256=YNc68YNlmXwKIPFMIViz_K4XzVVHkLPEBOFyO5DKMKI,53
9
+ aind_data_transfer_service/hpc/client.py,sha256=-WwNjpV2FAJMiXT3Y_JCllSbXPyvqrkPxpNWE0BAWzY,5084
10
+ aind_data_transfer_service/hpc/models.py,sha256=-7HhV16s_MUyKPy0x0FGIbnq8DPL2qJAzJO5G7003AE,16184
11
+ aind_data_transfer_service/models/__init__.py,sha256=Meym73bEZ9nQr4QoeyhQmV3nRTYtd_4kWKPNygsBfJg,25
12
+ aind_data_transfer_service/models/core.py,sha256=uXtPUqjxKalg-sE8MxaJr11w_T_KKBRBSJuUgwoMZlQ,10135
13
+ aind_data_transfer_service/models/internal.py,sha256=tWO1yRMu9hHLv0mt7QhOwTPWGbKApWmCf1wwajx5qjI,10681
14
+ aind_data_transfer_service-1.17.2.dist-info/licenses/LICENSE,sha256=U0Y7B3gZJHXpjJVLgTQjM8e_c8w4JJpLgGhIdsoFR1Y,1092
15
+ aind_data_transfer_service-1.17.2.dist-info/METADATA,sha256=DotVNzRhHX0woD5qMefPipnYAja4EbXje8luub37g9I,2478
16
+ aind_data_transfer_service-1.17.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ aind_data_transfer_service-1.17.2.dist-info/top_level.txt,sha256=XmxH0q27Jholj2-VYh-6WMrh9Lw6kkuCX_fdsj3SaFE,27
18
+ aind_data_transfer_service-1.17.2.dist-info/RECORD,,
@@ -1,45 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8">
5
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
6
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
7
- <title>{% block title %} {% endblock %} AIND Data Transfer Service Admin</title>
8
- <style>
9
- body {
10
- margin: 20px;
11
- font-family: arial, sans-serif;
12
- }
13
- nav {
14
- height: 40px;
15
- }
16
- </style>
17
- </head>
18
- <body>
19
- <nav>
20
- <a href="/">Submit Jobs</a> |
21
- <a href="/jobs">Job Status</a> |
22
- <a href="/job_params">Job Parameters</a> |
23
- <a title="Download job template as .xslx" href="/api/job_upload_template" download>Job Submit Template</a> |
24
- <a title="List of project names" href="{{ project_names_url }}" target="_blank">Project Names</a> |
25
- <a title="For more information click here" href="https://aind-data-transfer-service.readthedocs.io"
26
- target="_blank">Help</a> |
27
- <a href="/admin">Admin</a>
28
- <a href="/logout" class="float-end">Log out</a>
29
- </nav>
30
- <div>
31
- <h3>Admin</h3>
32
- <div>Hello {{user_name}}, welcome to the admin page</div>
33
- <div>Email: {{user_email}}</div>
34
- <h4 class="mt-4">Job Type Parameters</h4>
35
- <div class="mb-2">
36
- <div class="alert alert-info mb-0 p-4" role="alert">
37
- To manage job type parameters, go to the <a href="/job_params" class="alert-link">Job Parameters</a> page.
38
- Select an existing parameter, or click the
39
- <button type="button" class="btn btn-success btn-sm" disabled><i class="bi bi-plus-circle"></i> Add New Parameter</button>
40
- button.
41
- </div>
42
- </div>
43
- </div>
44
- </body>
45
- </html>