aplos-nca-saas-sdk 0.0.12__py3-none-any.whl → 0.0.14__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.
Files changed (44) hide show
  1. aplos_nca_saas_sdk/integration_testing/configs/_config_base.py +7 -2
  2. aplos_nca_saas_sdk/integration_testing/configs/app_settings_config.py +36 -36
  3. aplos_nca_saas_sdk/integration_testing/configs/config_sample.json +10 -10
  4. aplos_nca_saas_sdk/integration_testing/configs/file_upload_config.py +1 -1
  5. aplos_nca_saas_sdk/integration_testing/configs/login_config.py +15 -14
  6. aplos_nca_saas_sdk/integration_testing/configs/nca_execution_config.py +1 -1
  7. aplos_nca_saas_sdk/integration_testing/integration_test_base.py +2 -2
  8. aplos_nca_saas_sdk/integration_testing/integration_test_configurations.py +9 -5
  9. aplos_nca_saas_sdk/integration_testing/integration_test_factory.py +1 -1
  10. aplos_nca_saas_sdk/integration_testing/integration_test_response.py +1 -1
  11. aplos_nca_saas_sdk/integration_testing/integration_test_suite.py +10 -3
  12. aplos_nca_saas_sdk/integration_testing/main.py +9 -8
  13. aplos_nca_saas_sdk/integration_testing/readme.md +1 -1
  14. aplos_nca_saas_sdk/integration_testing/tests/app_configuration_test.py +4 -4
  15. aplos_nca_saas_sdk/integration_testing/tests/app_login_test.py +3 -3
  16. aplos_nca_saas_sdk/integration_testing/tests/file_upload_test.py +40 -91
  17. aplos_nca_saas_sdk/integration_testing/tests/nca_analysis_test.py +2 -2
  18. aplos_nca_saas_sdk/integration_testing/tests/validation_test.py +1 -1
  19. aplos_nca_saas_sdk/nca_resources/_api_base.py +44 -0
  20. aplos_nca_saas_sdk/{aws_resources → nca_resources}/aws_cognito.py +2 -2
  21. aplos_nca_saas_sdk/{aws_resources → nca_resources}/aws_s3_presigned_payload.py +3 -3
  22. aplos_nca_saas_sdk/{aws_resources → nca_resources}/aws_s3_presigned_upload.py +28 -22
  23. aplos_nca_saas_sdk/nca_resources/nca_analysis.py +23 -167
  24. aplos_nca_saas_sdk/nca_resources/nca_app_configuration.py +4 -4
  25. aplos_nca_saas_sdk/nca_resources/{nca_login.py → nca_authenticator.py} +23 -20
  26. aplos_nca_saas_sdk/nca_resources/nca_endpoints.py +56 -30
  27. aplos_nca_saas_sdk/nca_resources/nca_file_download.py +130 -0
  28. aplos_nca_saas_sdk/nca_resources/nca_file_upload.py +27 -29
  29. aplos_nca_saas_sdk/nca_resources/nca_validations.py +34 -0
  30. aplos_nca_saas_sdk/run_analysis_execution.py +148 -0
  31. aplos_nca_saas_sdk/utilities/commandline_args.py +29 -13
  32. aplos_nca_saas_sdk/utilities/environment_services.py +3 -2
  33. aplos_nca_saas_sdk/utilities/environment_vars.py +10 -4
  34. aplos_nca_saas_sdk/utilities/file_utility.py +1 -1
  35. aplos_nca_saas_sdk/utilities/http_utility.py +1 -26
  36. aplos_nca_saas_sdk/version.py +1 -1
  37. {aplos_nca_saas_sdk-0.0.12.dist-info → aplos_nca_saas_sdk-0.0.14.dist-info}/METADATA +1 -1
  38. aplos_nca_saas_sdk-0.0.14.dist-info/RECORD +51 -0
  39. {aplos_nca_saas_sdk-0.0.12.dist-info → aplos_nca_saas_sdk-0.0.14.dist-info}/licenses/LICENSE +1 -1
  40. aplos_nca_saas_sdk-0.0.12.dist-info/RECORD +0 -47
  41. /aplos_nca_saas_sdk/{files/analysis_files/single_ev/configuration_single_ev.json → sample_files/analysis_files/single_ev/config.json} +0 -0
  42. /aplos_nca_saas_sdk/{files/analysis_files/single_ev/single_ev.csv → sample_files/analysis_files/single_ev/input.csv} +0 -0
  43. /aplos_nca_saas_sdk/{files → sample_files}/analysis_files/single_ev/meta_data.json +0 -0
  44. {aplos_nca_saas_sdk-0.0.12.dist-info → aplos_nca_saas_sdk-0.0.14.dist-info}/WHEEL +0 -0
@@ -1,25 +1,25 @@
1
1
  """
2
- Copyright 2024 Aplos Analytics
2
+ Copyright 2024-2025 Aplos Analytics
3
3
  All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
4
  Property of Aplos Analytics, Utah, USA
5
5
  """
6
6
 
7
7
  from typing import Optional
8
- from aplos_nca_saas_sdk.aws_resources.aws_cognito import CognitoAuthentication
8
+ from aplos_nca_saas_sdk.nca_resources.aws_cognito import CognitoAuthentication
9
9
  from aplos_nca_saas_sdk.nca_resources.nca_app_configuration import (
10
10
  NCAAppConfiguration,
11
11
  )
12
12
 
13
13
 
14
- class NCALogin:
15
- """NCA Login"""
14
+ class NCAAuthenticator:
15
+ """NCA Authenticator"""
16
16
 
17
17
  def __init__(
18
18
  self,
19
19
  *,
20
20
  cognito_client_id: Optional[str] = None,
21
21
  cognito_region: Optional[str] = None,
22
- aplos_saas_domain: Optional[str] = None,
22
+ host: Optional[str] = None,
23
23
  ) -> None:
24
24
  """
25
25
  NCA SaaS Login
@@ -27,18 +27,16 @@ class NCALogin:
27
27
  Args:
28
28
  cognito_client_id (Optional[str], optional): Cognito Client Id. Defaults to None.
29
29
  cognito_region (Optional[str], optional): Cognito Region. Defaults to None.
30
- aplos_saas_domain (Optional[str], optional): Aplos NCA SaaS domain. Defaults to None.
30
+ host (Optional[str], optional): Aplos NCA SaaS host. Defaults to None.
31
31
 
32
32
  Requirements:
33
33
  Either pass in the cognito_client_id and cognito_region.
34
- or set the aplos_saas_domain to automatically get the client_id and region.
34
+ or set the host to automatically get the client_id and region.
35
35
  """
36
- self.jwt: str
37
- self.access_token: Optional[str] = None
38
- self.refresh_token: Optional[str] = None
36
+
39
37
  self.__cognito_client_id = cognito_client_id
40
38
  self.__region = cognito_region
41
- self.__domain: Optional[str] = aplos_saas_domain
39
+ self.__host: Optional[str] = host
42
40
  self.__cognito: Optional[CognitoAuthentication] = None
43
41
  self.__config: Optional[NCAAppConfiguration] = None
44
42
 
@@ -53,19 +51,19 @@ class NCALogin:
53
51
  self.__cognito = CognitoAuthentication(
54
52
  client_id=self.__cognito_client_id,
55
53
  region=self.__region,
56
- aplos_domain=self.__domain,
54
+ aplos_domain=self.__host,
57
55
  )
58
56
 
59
57
  return self.__cognito
60
58
 
61
59
  @property
62
- def domain(self) -> str | None:
60
+ def host(self) -> str | None:
63
61
  """
64
62
  Domain
65
63
  Returns:
66
- str: the domain
64
+ str: the host
67
65
  """
68
- return self.__domain
66
+ return self.__host
69
67
 
70
68
  @property
71
69
  def config(self) -> NCAAppConfiguration:
@@ -75,13 +73,13 @@ class NCALogin:
75
73
  NCAAppConfiguration: object to handle the NCA App Configuration
76
74
  """
77
75
  if self.__config is None:
78
- if self.__domain is None:
76
+ if self.__host is None:
79
77
  raise RuntimeError(
80
78
  "Failed to get Aplos Configuration. The Domain is not set."
81
79
  )
82
80
 
83
81
  self.__config = NCAAppConfiguration(
84
- aplos_saas_domain=self.__domain,
82
+ host=self.__host,
85
83
  )
86
84
 
87
85
  return self.__config
@@ -96,9 +94,14 @@ class NCALogin:
96
94
  Args:
97
95
  username (str): the username
98
96
  password (str): the users password
99
-
97
+ Returns:
98
+ str: JWT (JSON Web Token)
100
99
  """
100
+ if not username:
101
+ raise ValueError("Missing username. Please provide a valid username.")
102
+ if not password:
103
+ raise ValueError("Missing password. Please provide a valid password.")
101
104
 
102
- self.jwt = self.cognito.login(username=username, password=password)
105
+ self.cognito.login(username=username, password=password)
103
106
 
104
- return self.jwt
107
+ return self.cognito.jwt
@@ -1,5 +1,5 @@
1
1
  """
2
- Copyright 2024 Aplos Analytics
2
+ Copyright 2024-2025 Aplos Analytics
3
3
  All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
4
  Property of Aplos Analytics, Utah, USA
5
5
  """
@@ -8,51 +8,77 @@ Property of Aplos Analytics, Utah, USA
8
8
  class NCAEndpoints:
9
9
  """Aplos NCA SaaS Endpoints"""
10
10
 
11
- def __init__(self, *, aplos_saas_domain: str):
12
- self.__domain: str = aplos_saas_domain
11
+ def __init__(
12
+ self, *, host: str, tenant_id: str | None = None, user_id: str | None = None
13
+ ):
14
+ self.__host: str = host
13
15
  self.__protocal: str = "https://"
16
+ self.tenant_id: str | None = tenant_id
17
+ self.user_id: str | None = user_id
14
18
 
15
- def __base(self, tenant_id: str | None = None, user_id: str | None = None) -> str:
16
- """Returns the base endpoint"""
17
- route = f"{self.__protocal}{self.__domain}"
19
+ @property
20
+ def origin(self) -> str:
21
+ """The origin path e.g. https://api.aplos-nca.com"""
22
+ base = f"{self.__protocal}{self.__host}"
23
+ return base
18
24
 
19
- if tenant_id:
20
- route = f"{route}/tenants/{tenant_id}"
21
- if user_id:
22
- if not tenant_id:
23
- raise ValueError("Tenant ID is required on the users path")
24
- route = f"{route}/users/{user_id}"
25
+ @property
26
+ def tenant_path(self) -> str:
27
+ """Returns the tenant path"""
25
28
 
26
- return route
29
+ if not self.tenant_id:
30
+ raise ValueError("Missing Tenant Id")
27
31
 
28
- def tenant(self, tenant_id: str) -> str:
32
+ return f"{self.origin}/tenants/{self.tenant_id}"
33
+
34
+ @property
35
+ def user_path(self) -> str:
36
+ """Returns the user path"""
37
+
38
+ if not self.user_id:
39
+ raise ValueError("Missing User Id")
40
+ return f"{self.tenant_path}/users/{self.user_id}"
41
+
42
+ @property
43
+ def tenant(self) -> str:
29
44
  """Returns the tenant endpoint"""
30
- return f"{self.__base(tenant_id=tenant_id)}"
45
+ return f"{self.tenant_path}"
31
46
 
47
+ @property
32
48
  def app_configuration(self) -> str:
33
- """Returns the configuration endpoint"""
34
- return f"{self.__base()}/app/configuration"
49
+ """
50
+ Returns the configuration endpoint. This is a public endpoint.
51
+ """
52
+ return f"{self.origin}/app/configuration"
35
53
 
36
- def user(self, tenant_id: str, user_id: str) -> str:
54
+ @property
55
+ def user(self) -> str:
37
56
  """Returns the user endpoint"""
38
- return f"{self.__base(tenant_id=tenant_id, user_id=user_id)}"
57
+ return f"{self.user_path}"
39
58
 
40
- def executions(self, tenant_id: str, user_id: str) -> str:
59
+ @property
60
+ def executions(self) -> str:
41
61
  """Returns the executions endpoint"""
42
- return f"{self.__base(tenant_id=tenant_id, user_id=user_id)}/nca/executions"
62
+ return f"{self.user_path}/nca/executions"
43
63
 
44
- def execution(self, tenant_id: str, user_id: str, execution_id: str) -> str:
64
+ def execution(self, execution_id: str) -> str:
45
65
  """Returns the executions endpoint"""
46
- return f"{self.executions(tenant_id=tenant_id, user_id=user_id)}/{execution_id}"
66
+ return f"{self.executions}/{execution_id}"
47
67
 
48
- def files(self, tenant_id: str, user_id: str) -> str:
68
+ @property
69
+ def validations(self) -> str:
70
+ """Returns the validations endpoint"""
71
+ return f"{self.user_path}/nca/validations"
72
+
73
+ @property
74
+ def files(self) -> str:
49
75
  """Returns the files endpoint"""
50
- return f"{self.__base(tenant_id=tenant_id, user_id=user_id)}/nca/files"
76
+ return f"{self.user_path}/nca/files"
51
77
 
52
- def file(self, tenant_id: str, user_id: str, file_id: str) -> str:
78
+ def file(self, file_id: str) -> str:
53
79
  """Returns the file endpoint"""
54
- return f"{self.files(tenant_id=tenant_id, user_id=user_id)}/{file_id}"
55
-
56
- def file_data(self, tenant_id: str, user_id: str, file_id: str) -> str:
80
+ return f"{self.files}/{file_id}"
81
+
82
+ def file_data(self, file_id: str) -> str:
57
83
  """Returns get file data endpoint"""
58
- return f"{self.__base(tenant_id=tenant_id, user_id=user_id)}/nca/files/{file_id}/data"
84
+ return f"{self.files}/{file_id}/data"
@@ -0,0 +1,130 @@
1
+ """
2
+ Copyright 2024-2025 Aplos Analytics
3
+ All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
+ Property of Aplos Analytics, Utah, USA
5
+ """
6
+
7
+ import time
8
+ from typing import Any, Dict, List
9
+ from datetime import datetime, timedelta
10
+ from aws_lambda_powertools import Logger
11
+ from aplos_nca_saas_sdk.nca_resources._api_base import NCAApiBaseClass
12
+ from aplos_nca_saas_sdk.nca_resources.aws_s3_presigned_upload import (
13
+ S3PresignedUrlUpload,
14
+ )
15
+
16
+ from aplos_nca_saas_sdk.utilities.http_utility import HttpUtilities
17
+ import requests
18
+
19
+ logger = Logger(service="nca-file-download")
20
+
21
+
22
+ class NCAFileDownload(NCAApiBaseClass):
23
+ """NCA File Download"""
24
+
25
+ def __init__(self, host: str) -> None:
26
+ super().__init__(host)
27
+
28
+ def upload(
29
+ self,
30
+ input_file_path: str,
31
+ user_name: str | None = None,
32
+ password: str | None = None,
33
+ ) -> Dict[str, Any]:
34
+ """
35
+ Uploads a file to the Aplos NCA Cloud
36
+
37
+ Args:
38
+ input_file_path (str): local path to the file
39
+
40
+ Raises:
41
+ ValueError: _description_
42
+
43
+ Returns:
44
+ Dict: {"file_id": id, "statu_code": 204}
45
+ """
46
+ if input_file_path is None or not input_file_path:
47
+ raise ValueError("Valid input_file_path is required.")
48
+
49
+ if not self.authenticator.cognito.jwt:
50
+ if not user_name or not password:
51
+ raise ValueError(
52
+ "Valid user_name and password are required or you can set the authenticator object."
53
+ )
54
+ self.authenticator.authenticate(username=user_name, password=password)
55
+
56
+ uploader: S3PresignedUrlUpload = S3PresignedUrlUpload(self.host)
57
+ uploader.authenticator = self.authenticator
58
+
59
+ upload_response: Dict[str, Any] = uploader.upload_file(
60
+ input_file=input_file_path
61
+ )
62
+
63
+ return upload_response
64
+
65
+ def download(
66
+ self,
67
+ file_id: str,
68
+ user_name: str | None = None,
69
+ password: str | None = None,
70
+ ) -> Dict[str, Any]:
71
+ """
72
+ Downloads a file from the Aplos NCA Cloud
73
+
74
+ Args:
75
+ file_id (str): the id of the file to download
76
+
77
+ Raises:
78
+ ValueError: _description_
79
+
80
+ Returns:
81
+ Dict: {"file_id": id, "statu_code": 204}
82
+ """
83
+
84
+ logger.info({"message": "Downloading file", "file_id": file_id})
85
+
86
+ file_info_endpoint = self.endpoints.file(
87
+ file_id,
88
+ )
89
+
90
+ if not self.authenticator.cognito.jwt:
91
+ if not user_name or not password:
92
+ raise ValueError(
93
+ "Valid user_name and password are required or you can set the authenticator object."
94
+ )
95
+ self.authenticator.authenticate(username=user_name, password=password)
96
+
97
+ max_wait_in_minutes: int = 3
98
+ headers = HttpUtilities.get_headers(self.authenticator.cognito.jwt)
99
+ current_time = datetime.now()
100
+
101
+ # Create a timedelta object representing 3 minutes
102
+ time_delta = timedelta(minutes=max_wait_in_minutes)
103
+ # Add the timedelta to the current time
104
+ max_time = current_time + time_delta
105
+
106
+ complete = False
107
+ json_response: Dict[str, Any] = {}
108
+ while not complete:
109
+ response = requests.get(file_info_endpoint, headers=headers, timeout=60)
110
+ json_response: dict = response.json()
111
+ errors: List[Dict[str, Any]] = []
112
+ errors.extend(json_response.get("errors") or [])
113
+ status = json_response.get("workable_state")
114
+ complete = status == "ready"
115
+
116
+ if status == "invalid" or len(errors) > 0:
117
+ break
118
+ if complete:
119
+ break
120
+ if not complete:
121
+ time.sleep(5)
122
+ if datetime.now() > max_time:
123
+ error = (
124
+ "Timeout attempting to get conversion file status. "
125
+ f"The current timeout limit is {max_wait_in_minutes} minutes. "
126
+ "You may need to up the timeout period, or check for errors. "
127
+ )
128
+ raise RuntimeError(error)
129
+
130
+ return json_response
@@ -1,41 +1,28 @@
1
1
  """
2
- Copyright 2024 Aplos Analytics
2
+ Copyright 2024-2025 Aplos Analytics
3
3
  All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
4
  Property of Aplos Analytics, Utah, USA
5
5
  """
6
6
 
7
7
  from typing import Any, Dict
8
- from aplos_nca_saas_sdk.aws_resources.aws_s3_presigned_upload import S3PresignedUpload
9
- from aplos_nca_saas_sdk.nca_resources.nca_login import NCALogin
10
- from aplos_nca_saas_sdk.utilities.http_utility import HttpUtilities
8
+ from aplos_nca_saas_sdk.nca_resources._api_base import NCAApiBaseClass
9
+ from aplos_nca_saas_sdk.nca_resources.aws_s3_presigned_upload import (
10
+ S3PresignedUrlUpload,
11
+ )
11
12
 
12
13
 
13
- class NCAFileUpload:
14
+ class NCAFileUpload(NCAApiBaseClass):
14
15
  """NCA File Upload"""
15
16
 
16
- def __init__(self, nca_login: NCALogin) -> None:
17
- if nca_login is None or nca_login.jwt is None or not nca_login.jwt:
18
- raise ValueError("Authenticated nca_login is required.")
17
+ def __init__(self, host: str) -> None:
18
+ super().__init__(host)
19
19
 
20
- self.__api_domain: str = nca_login.domain or ""
21
- self.__tenant_id: str = nca_login.cognito.tenant_id
22
- self.__user_id: str = nca_login.cognito.user_id
23
- self.__jwt: str = nca_login.jwt
24
-
25
- @property
26
- def api_root(self) -> str:
27
- """Gets the base url"""
28
-
29
- if self.__api_domain is None:
30
- raise RuntimeError("Missing Aplos Api Domain")
31
-
32
- url = HttpUtilities.build_url(
33
- self.__api_domain, self.__tenant_id, self.__user_id
34
- )
35
-
36
- return url
37
-
38
- def upload(self, input_file_path: str) -> Dict[str, Any]:
20
+ def upload(
21
+ self,
22
+ input_file_path: str,
23
+ user_name: str | None = None,
24
+ password: str | None = None,
25
+ ) -> Dict[str, Any]:
39
26
  """
40
27
  Uploads a file to the Aplos NCA Cloud
41
28
 
@@ -51,7 +38,18 @@ class NCAFileUpload:
51
38
  if input_file_path is None or not input_file_path:
52
39
  raise ValueError("Valid input_file_path is required.")
53
40
 
54
- uploader: S3PresignedUpload = S3PresignedUpload(self.__jwt, str(self.api_root))
55
- upload_response: Dict[str, Any] = uploader.upload_file(input_file_path)
41
+ if not self.authenticator.cognito.jwt:
42
+ if not user_name or not password:
43
+ raise ValueError(
44
+ "Valid user_name and password are required or you can set the authenticator object."
45
+ )
46
+ self.authenticator.authenticate(username=user_name, password=password)
47
+
48
+ uploader: S3PresignedUrlUpload = S3PresignedUrlUpload(self.host)
49
+ uploader.authenticator = self.authenticator
50
+
51
+ upload_response: Dict[str, Any] = uploader.upload_file(
52
+ input_file=input_file_path
53
+ )
56
54
 
57
55
  return upload_response
@@ -0,0 +1,34 @@
1
+ """
2
+ Copyright 2024-2025 Aplos Analytics
3
+ All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
+ Property of Aplos Analytics, Utah, USA
5
+ """
6
+
7
+ import requests
8
+
9
+ from aplos_nca_saas_sdk.nca_resources._api_base import NCAApiBaseClass
10
+
11
+
12
+ class NCAValidation(NCAApiBaseClass):
13
+ """NCA Analysis Validation API"""
14
+
15
+ def __init__(self, host: str) -> None:
16
+ super().__init__(host)
17
+
18
+ def validate(self, jwt: str) -> bool:
19
+ """
20
+ Validates the JWT
21
+
22
+ Args:
23
+ jwt (str): JWT
24
+
25
+ Returns:
26
+ bool: True if the JWT is valid
27
+ """
28
+ url = self.endpoints.validations
29
+ response = requests.post(url, json={"jwt": jwt}, timeout=30)
30
+
31
+ if response.status_code != 200:
32
+ return False
33
+
34
+ return True
@@ -0,0 +1,148 @@
1
+ """
2
+ Copyright 2024-2025 Aplos Analytics
3
+ All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
+ Property of Aplos Analytics, Utah, USA
5
+ """
6
+
7
+ import json
8
+ import os
9
+ from pathlib import Path
10
+
11
+ from aws_lambda_powertools import Logger
12
+
13
+ from aplos_nca_saas_sdk.nca_resources.nca_analysis import NCAAnalysis
14
+ from aplos_nca_saas_sdk.utilities.commandline_args import CommandlineArgs
15
+
16
+ logger = Logger()
17
+
18
+
19
+ def main():
20
+ """Run Main when then file is run directly"""
21
+ try:
22
+ print("Welcome to the NCA Engine Upload & Execution Demo")
23
+ args = CommandlineArgs()
24
+ files_path = os.path.join(
25
+ Path(__file__).parent, "sample_files", "analysis_files", "single_ev"
26
+ )
27
+
28
+ # set up some defaults to make the demos quicker
29
+ args.analysis_file_default = os.path.join(files_path, "input.csv")
30
+ args.config_file_default = os.path.join(files_path, "config.json")
31
+ args.metadata_file_default = os.path.join(files_path, "meta_data.json")
32
+ args.output_directory_default = os.path.join(files_path, ".output")
33
+ if not args.is_valid():
34
+ print("\n\n")
35
+ print("Missing some arguments.")
36
+ exit()
37
+
38
+ analysis_api = NCAAnalysis(host=str(args.host))
39
+ analysis_api.verbose = True
40
+
41
+ print("\tLoading analysis configurations")
42
+ print(f"\t\t...{os.path.basename(args.config_file)}")
43
+ config_data: dict = read_json_file(str(args.config_file))
44
+
45
+ print("\tLoading analysis meta data")
46
+ print(f"\t\t...{os.path.basename(args.metadata_file)}")
47
+ meta_data = optional_json_loads(read_text_file(str(args.metadata_file)))
48
+
49
+ wait_for_results = True
50
+ max_wait_in_seconds = 900 # 15 minutes
51
+ resutls = analysis_api.execute(
52
+ username=str(args.username),
53
+ password=str(args.password),
54
+ input_file_path=str(args.analysis_file),
55
+ config_data=config_data,
56
+ meta_data=meta_data,
57
+ output_directory=str(args.output_directory),
58
+ wait_for_results=wait_for_results,
59
+ max_wait_in_seconds=max_wait_in_seconds,
60
+ )
61
+
62
+ if not wait_for_results:
63
+ exec_id = resutls.get("execution", {}).get("execution_id", "")
64
+ print(
65
+ "Analysis execution has been queued. We're not waiting for the results."
66
+ )
67
+ print(f"Please check your results with execution id {exec_id}.")
68
+
69
+ print("🙌 Thank you for using the NCA API for an Analysis Execution Demo. 🙌")
70
+ except Exception as e: # pylint: disable=w0718
71
+ print(
72
+ "🚨 An error occured ... exiting with an error. Please check your settings and try again."
73
+ )
74
+ print(
75
+ "If you believe this is bug please create a support ticket and include the execution id (if available)."
76
+ )
77
+ print(
78
+ "If it's not reported in the error below check your account for the failed execution."
79
+ )
80
+
81
+ print(str(e))
82
+
83
+
84
+ def optional_json_loads(data: str | dict) -> str | dict:
85
+ """
86
+ Attempts to load the data as json, fails gracefull and retuns the data is if it fails
87
+ Args:
88
+ data (str): data as string
89
+
90
+ Returns:
91
+ str | dict: either the data as is or a converted dictionary/json object
92
+ """
93
+ if isinstance(data, dict):
94
+ return data
95
+
96
+ try:
97
+ data = json.loads(str(data))
98
+ finally:
99
+ pass
100
+ return data
101
+
102
+
103
+ def read_json_file(file_path: str) -> dict:
104
+ """
105
+ Reads a file and returns the json
106
+ Args:
107
+ file_path (str): _description_
108
+
109
+ Raises:
110
+ FileNotFoundError: _description_
111
+
112
+ Returns:
113
+ dict: _description_
114
+ """
115
+ if not os.path.exists(file_path):
116
+ raise FileNotFoundError(f"File Not Found: {file_path}")
117
+
118
+ data = None
119
+ with open(file_path, mode="r", encoding="utf8") as file:
120
+ data = json.load(file)
121
+
122
+ return data
123
+
124
+
125
+ def read_text_file(file_path: str) -> str:
126
+ """
127
+ Read files contents
128
+ Args:
129
+ file_path (str): path to the file
130
+
131
+ Raises:
132
+ FileNotFoundError: if the file is not found
133
+
134
+ Returns:
135
+ str: the files data
136
+ """
137
+ if not os.path.exists(file_path):
138
+ raise FileNotFoundError(f"File Not Found: {file_path}")
139
+
140
+ data = None
141
+ with open(file_path, mode="r", encoding="utf8") as file:
142
+ data = file.read()
143
+
144
+ return data
145
+
146
+
147
+ if __name__ == "__main__":
148
+ main()