aplos-nca-saas-sdk 0.0.11__py3-none-any.whl → 0.0.13__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 (49) 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 +88 -0
  3. aplos_nca_saas_sdk/integration_testing/configs/config_sample.json +31 -18
  4. aplos_nca_saas_sdk/integration_testing/configs/file_upload_config.py +94 -0
  5. aplos_nca_saas_sdk/integration_testing/configs/{login.py → login_config.py} +36 -23
  6. aplos_nca_saas_sdk/integration_testing/configs/nca_execution_config.py +186 -0
  7. aplos_nca_saas_sdk/integration_testing/files/executions/config1.json +46 -0
  8. aplos_nca_saas_sdk/integration_testing/integration_test_base.py +10 -3
  9. aplos_nca_saas_sdk/integration_testing/integration_test_configurations.py +15 -7
  10. aplos_nca_saas_sdk/integration_testing/integration_test_factory.py +1 -1
  11. aplos_nca_saas_sdk/integration_testing/integration_test_response.py +1 -1
  12. aplos_nca_saas_sdk/integration_testing/integration_test_suite.py +10 -3
  13. aplos_nca_saas_sdk/integration_testing/main.py +6 -6
  14. aplos_nca_saas_sdk/integration_testing/readme.md +1 -1
  15. aplos_nca_saas_sdk/integration_testing/tests/app_configuration_test.py +3 -3
  16. aplos_nca_saas_sdk/integration_testing/tests/app_login_test.py +4 -4
  17. aplos_nca_saas_sdk/integration_testing/tests/file_upload_test.py +44 -92
  18. aplos_nca_saas_sdk/integration_testing/tests/nca_analysis_test.py +89 -0
  19. aplos_nca_saas_sdk/integration_testing/tests/{app_execution_test.py → validation_test.py} +1 -1
  20. aplos_nca_saas_sdk/nca_resources/_api_base.py +44 -0
  21. aplos_nca_saas_sdk/{aws_resources → nca_resources}/aws_cognito.py +13 -7
  22. aplos_nca_saas_sdk/{aws_resources → nca_resources}/aws_s3_presigned_payload.py +3 -3
  23. aplos_nca_saas_sdk/{aws_resources → nca_resources}/aws_s3_presigned_upload.py +28 -22
  24. aplos_nca_saas_sdk/nca_resources/nca_analysis.py +304 -0
  25. aplos_nca_saas_sdk/nca_resources/nca_app_configuration.py +4 -4
  26. aplos_nca_saas_sdk/nca_resources/{nca_login.py → nca_authenticator.py} +26 -23
  27. aplos_nca_saas_sdk/nca_resources/nca_endpoints.py +56 -30
  28. aplos_nca_saas_sdk/nca_resources/nca_file_download.py +130 -0
  29. aplos_nca_saas_sdk/nca_resources/nca_file_upload.py +27 -29
  30. aplos_nca_saas_sdk/nca_resources/nca_validations.py +34 -0
  31. aplos_nca_saas_sdk/run_analysis_execution.py +148 -0
  32. aplos_nca_saas_sdk/utilities/commandline_args.py +32 -38
  33. aplos_nca_saas_sdk/utilities/environment_services.py +3 -2
  34. aplos_nca_saas_sdk/utilities/environment_vars.py +17 -4
  35. aplos_nca_saas_sdk/utilities/file_utility.py +33 -0
  36. aplos_nca_saas_sdk/utilities/http_utility.py +5 -14
  37. aplos_nca_saas_sdk/version.py +1 -1
  38. {aplos_nca_saas_sdk-0.0.11.dist-info → aplos_nca_saas_sdk-0.0.13.dist-info}/METADATA +1 -1
  39. aplos_nca_saas_sdk-0.0.13.dist-info/RECORD +51 -0
  40. {aplos_nca_saas_sdk-0.0.11.dist-info → aplos_nca_saas_sdk-0.0.13.dist-info}/licenses/LICENSE +1 -1
  41. aplos_nca_saas_sdk/integration_testing/configs/app_settings.py +0 -88
  42. aplos_nca_saas_sdk/integration_testing/configs/file_upload.py +0 -104
  43. aplos_nca_saas_sdk/integration_testing/tests/app_validation_test.py +0 -5
  44. aplos_nca_saas_sdk/nca_resources/nca_executions.py +0 -387
  45. aplos_nca_saas_sdk-0.0.11.dist-info/RECORD +0 -44
  46. /aplos_nca_saas_sdk/{files/analysis_files/single_ev/configuration_single_ev.json → sample_files/analysis_files/single_ev/config.json} +0 -0
  47. /aplos_nca_saas_sdk/{files/analysis_files/single_ev/single_ev.csv → sample_files/analysis_files/single_ev/input.csv} +0 -0
  48. /aplos_nca_saas_sdk/{files → sample_files}/analysis_files/single_ev/meta_data.json +0 -0
  49. {aplos_nca_saas_sdk-0.0.11.dist-info → aplos_nca_saas_sdk-0.0.13.dist-info}/WHEEL +0 -0
@@ -0,0 +1,51 @@
1
+ aplos_nca_saas_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ aplos_nca_saas_sdk/run_analysis_execution.py,sha256=cYzGdAHOriDI7UHNFwzeaR6sHhiwNysx3__eMze8hZc,4445
3
+ aplos_nca_saas_sdk/version.py,sha256=jlXzv0jZuOy0IB5ancPlhN-0-xre_EGv3QEfLys8N-c,172
4
+ aplos_nca_saas_sdk/integration_testing/integration_test_base.py,sha256=ci3oOfz_McdDKGSrqOHF7F_vrvgTWo7HzxydNdPSHLs,2787
5
+ aplos_nca_saas_sdk/integration_testing/integration_test_configurations.py,sha256=gHQE1l9l7qunlg0APfYE2JZzdhYHMz-RJiXIiQu6l2U,1634
6
+ aplos_nca_saas_sdk/integration_testing/integration_test_factory.py,sha256=HdcGQycsBNv-cLGXfL3yVpRjLaj-QkAv1ih0L8yVXA0,2203
7
+ aplos_nca_saas_sdk/integration_testing/integration_test_response.py,sha256=Ocn2q_kdgEJB-4Ol-V3dh8MEkf6CJdrIiQVURUeM62o,819
8
+ aplos_nca_saas_sdk/integration_testing/integration_test_suite.py,sha256=L1ZFp3tE9zUnaCyzfTfKTYkgR_ksrIOi5YK7qViwKes,4413
9
+ aplos_nca_saas_sdk/integration_testing/main.py,sha256=ACYtOZS-S0d1ZXZGzIMKxo1MPkK9CnsSzq7E5nMwhYE,2040
10
+ aplos_nca_saas_sdk/integration_testing/readme.md,sha256=USg_Z8C3hYgOGgmDsv7DNR2IxRV0Xg6NvOYrwTBqZRE,626
11
+ aplos_nca_saas_sdk/integration_testing/configs/_config_base.py,sha256=PyXCiEbvM5usN8sbtVSEL0g1iqGh9bdE31kPORMJBIs,480
12
+ aplos_nca_saas_sdk/integration_testing/configs/app_settings_config.py,sha256=wgRjf98enkob2mfAV0bzjmfhMbovFsuMiURKyW9n83w,2611
13
+ aplos_nca_saas_sdk/integration_testing/configs/config_sample.json,sha256=5n56K0mh33n5Po8uFbYE_ChIGbLuuxhVlhFwrbdrqNA,3568
14
+ aplos_nca_saas_sdk/integration_testing/configs/file_upload_config.py,sha256=kODsim7yQVnXthBtbWwmRGfZFVN-QIevhQjSHdep6_4,3066
15
+ aplos_nca_saas_sdk/integration_testing/configs/login_config.py,sha256=HqPjYBiagGSKaPFForO_eF0oKQqZzc3WEr4jEzh9kBc,3560
16
+ aplos_nca_saas_sdk/integration_testing/configs/nca_execution_config.py,sha256=gS9W6nJ4ypgGqWcRTpVHpiEVcKsTuyI6zmvL_U5Bqhs,5769
17
+ aplos_nca_saas_sdk/integration_testing/files/executions/config1.json,sha256=m6-wSzfrB-7w4CgIGpmT9y0_zevp-Q6So9eXU9HsVpQ,945
18
+ aplos_nca_saas_sdk/integration_testing/files/uploads/input1.csv,sha256=9TGDiMkft7ltFFKk_8RyzuhuloIpe_fZs0Nw0PN3BkM,263
19
+ aplos_nca_saas_sdk/integration_testing/files/uploads/input1.dat,sha256=9TGDiMkft7ltFFKk_8RyzuhuloIpe_fZs0Nw0PN3BkM,263
20
+ aplos_nca_saas_sdk/integration_testing/files/uploads/input1.sas7bdat,sha256=bh4w5QPHwjgLEhk752BmUwztkcBmx8iAywZdiiWZuw0,16384
21
+ aplos_nca_saas_sdk/integration_testing/files/uploads/input1.xls,sha256=ymFgWvoUC--OxsXrj2JInjK3eSbR7jnGbpHEpiadNCI,26624
22
+ aplos_nca_saas_sdk/integration_testing/files/uploads/input1.xlsx,sha256=i8pOYfA-muNxrtCKfUfi4Hi3JvSx49ZgtfvIUQTzRJo,10481
23
+ aplos_nca_saas_sdk/integration_testing/files/uploads/input1.xpt,sha256=vve5eYrs3nEuGGQgm710tzzYkhrn3cfcy3--CVe4IGs,1920
24
+ aplos_nca_saas_sdk/integration_testing/tests/app_configuration_test.py,sha256=rzGWSCJPah7C8htp1atsaWKtkyRdfyd3ku8UTYQ20mc,1569
25
+ aplos_nca_saas_sdk/integration_testing/tests/app_login_test.py,sha256=NLI4DUICspa_uZi-w2Q3XufDL0ERLVvn1DavNpYDK7I,1650
26
+ aplos_nca_saas_sdk/integration_testing/tests/file_upload_test.py,sha256=v3-5vEVPVREQDBColJeAGg2grG3c8A4WTxZnE3_ki9c,3936
27
+ aplos_nca_saas_sdk/integration_testing/tests/nca_analysis_test.py,sha256=RIxarfp_ggD4HgVb8xnMynIDZG2HZ0hmv6sZj1-T73c,3261
28
+ aplos_nca_saas_sdk/integration_testing/tests/validation_test.py,sha256=68BRZbjPa7p_n5CQeEzSP5hwPAZ921NP8vbmCaCn2pQ,150
29
+ aplos_nca_saas_sdk/nca_resources/_api_base.py,sha256=qxMSiHV4014L733ii4EJ2JUwQwKkuHi5Rm6cPEdS3cA,1278
30
+ aplos_nca_saas_sdk/nca_resources/aws_cognito.py,sha256=lc6GCvoTBx_Dmezoxt80xksiuxXjSwkynj-1Sg0vzwY,6576
31
+ aplos_nca_saas_sdk/nca_resources/aws_s3_presigned_payload.py,sha256=S9LvUEjzJqLYob-JmNXdIe0Uj__fVtcF4LDQB5538vk,2001
32
+ aplos_nca_saas_sdk/nca_resources/aws_s3_presigned_upload.py,sha256=ExZUjJ4Yyu-oQyVMNtyl7KqxFfr4hIwIN31RFxg6EfM,4476
33
+ aplos_nca_saas_sdk/nca_resources/nca_analysis.py,sha256=Fx-M7mkNKho0IbxLz7swSgexAlIXm-XeDxFchTOhHrI,10630
34
+ aplos_nca_saas_sdk/nca_resources/nca_app_configuration.py,sha256=VZNZi0_NV4QjNgBSM9csq5qedc6-qvzaXwXyLfymB6M,1845
35
+ aplos_nca_saas_sdk/nca_resources/nca_authenticator.py,sha256=3mXHs2zMsvo2zirudpgynC3Y9woFrfkmo3mysqfJyxk,3126
36
+ aplos_nca_saas_sdk/nca_resources/nca_endpoints.py,sha256=lYtktEG0yXleRoFLkab3fw7MaaaZIjdvPB2iZVlIg1s,2373
37
+ aplos_nca_saas_sdk/nca_resources/nca_file_download.py,sha256=_ryJta9f6CBOh0OsE6P4FMGZggjYWu_kj1ZuzVVuruc,4190
38
+ aplos_nca_saas_sdk/nca_resources/nca_file_upload.py,sha256=dqETMtnzYZilPlFfLKW7o3DrrBLObeIGgILWPyD-3ZI,1653
39
+ aplos_nca_saas_sdk/nca_resources/nca_validations.py,sha256=INv3bIHH3caOjByDknTqogDjqaYmHtZCDldc2AKpqOM,785
40
+ aplos_nca_saas_sdk/sample_files/analysis_files/single_ev/config.json,sha256=lLnRV0jwzaSn32D8NlOekOF5oGFfUwugUlvlwoKz540,986
41
+ aplos_nca_saas_sdk/sample_files/analysis_files/single_ev/input.csv,sha256=qFSAlgLOmERsabMmp1X6PAZa-8yFthZlHacM_f7_AOY,6528
42
+ aplos_nca_saas_sdk/sample_files/analysis_files/single_ev/meta_data.json,sha256=p1KYOAe5Cl3rjtfF1t96oRG-QtFJJCo9otReRPNtvIk,447
43
+ aplos_nca_saas_sdk/utilities/commandline_args.py,sha256=7HgB4AhQHHovqz_VOf6ndLubPhHQFHX5DhWz7Dx0OMo,10909
44
+ aplos_nca_saas_sdk/utilities/environment_services.py,sha256=eKlaz-3VAPHUe-MN0rc_AdJfzdiej86vhARE-ulWL5A,3375
45
+ aplos_nca_saas_sdk/utilities/environment_vars.py,sha256=aXheFXg6FVMaSYLe2LmoWRF5Ks9vwxDazO4XYb4vLjc,1132
46
+ aplos_nca_saas_sdk/utilities/file_utility.py,sha256=EUvQ65aXN6OdILniuiDQ2rPRA9sFmvUoAehifEjRgUY,1025
47
+ aplos_nca_saas_sdk/utilities/http_utility.py,sha256=DQ-ClLOmNoyPn5vhrSh4q-2wi4ViP_gplJD9asEKDM8,464
48
+ aplos_nca_saas_sdk-0.0.13.dist-info/METADATA,sha256=pZU_i1FxKlTBfAeTwcrBdN9ix9OA1tG4Jt4PeGb4ZRU,3792
49
+ aplos_nca_saas_sdk-0.0.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
50
+ aplos_nca_saas_sdk-0.0.13.dist-info/licenses/LICENSE,sha256=JQMpBrnqu_m2tISmyh6_dTgb8-m3HNnA51fuOh2TzkE,1076
51
+ aplos_nca_saas_sdk-0.0.13.dist-info/RECORD,,
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) [year] [fullname]
3
+ Copyright (c) 2024-2025 Aplos Analytics
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,88 +0,0 @@
1
- """
2
- Copyright 2024 Aplos Analytics
3
- All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
- Property of Aplos Analytics, Utah, USA
5
- """
6
-
7
- from typing import List, Dict, Any
8
- from aplos_nca_saas_sdk.integration_testing.configs._config_base import ConfigBase
9
-
10
-
11
- class ApplicationDomain(ConfigBase):
12
- """
13
- Application Domain: Defines the domains that the application configuration tests will check against
14
-
15
- """
16
-
17
- def __init__(self, domain: str | None = None):
18
- super().__init__()
19
- self.__domain: str | None = domain
20
-
21
- @property
22
- def domain(self) -> str:
23
- """The domain to validate"""
24
- if self.__domain is None:
25
- raise RuntimeError("Domain is not set")
26
- return self.__domain
27
-
28
- @domain.setter
29
- def domain(self, value: str):
30
- self.__domain = value
31
-
32
-
33
- class ApplicationDomains(ConfigBase):
34
- """
35
- Application ApplicationDomain: Defines the Domains that the application configuration tests will check against
36
-
37
- """
38
-
39
- def __init__(self):
40
- super().__init__()
41
- self.__domains: List[ApplicationDomain] = []
42
-
43
- @property
44
- def list(self) -> List[ApplicationDomain]:
45
- """List the logins"""
46
- return self.__domains
47
-
48
- def add(self, *, domain: str, enabled: bool = True):
49
- """Add a loging"""
50
- app_domain = ApplicationDomain()
51
- app_domain.domain = domain
52
- app_domain.enabled = enabled
53
- self.__domains.append(app_domain)
54
-
55
- def load(self, test_config: Dict[str, Any]):
56
- """Load the logins from a list of dictionaries"""
57
- # self.enabled = bool(test_config.get("enabled", True))
58
- super().load(test_config)
59
- domains: List[Dict[str, Any]] = test_config.get("domains", [])
60
-
61
- domain: Dict[str, Any]
62
- for domain in domains:
63
- app_domain = ApplicationDomain()
64
- app_domain.domain = domain.get("domain", None)
65
- app_domain.enabled = bool(domain.get("enabled", True))
66
-
67
- self.__domains.append(app_domain)
68
-
69
-
70
- class ApplicationSettings(ConfigBase):
71
- """
72
- Application Settings: Defines the domains that the application settings (configuration endpoint) tests will check against
73
-
74
- """
75
-
76
- def __init__(self):
77
- super().__init__()
78
- self.__domains: ApplicationDomains = ApplicationDomains()
79
-
80
- @property
81
- def domains(self) -> ApplicationDomains:
82
- """List of the domain"""
83
- return self.__domains
84
-
85
- def load(self, test_config: Dict[str, Any]):
86
- """Load the domains from the config"""
87
- super().load(test_config)
88
- self.domains.load(test_config)
@@ -1,104 +0,0 @@
1
- """
2
- Copyright 2024 Aplos Analytics
3
- All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
- Property of Aplos Analytics, Utah, USA
5
- """
6
-
7
- import os
8
- from typing import List, Dict, Any
9
- from aplos_nca_saas_sdk.integration_testing.configs._config_base import ConfigBase
10
- from aplos_nca_saas_sdk.integration_testing.configs.login import Login
11
- from aplos_nca_saas_sdk.utilities.environment_services import EnvironmentServices
12
-
13
-
14
- class FileUpload(ConfigBase):
15
- """
16
- File Upload: Defines the login that the application configuration tests will check against
17
-
18
- """
19
-
20
- def __init__(self, login: Login, filepath: str):
21
- super().__init__()
22
- if login is None:
23
- raise RuntimeError("Login is required")
24
- self.__login = login
25
- if filepath is None:
26
- raise RuntimeError("Filepath is required")
27
- self.__filepath = filepath
28
-
29
- @property
30
- def login(self) -> Login:
31
- """The users login"""
32
- return self.__login
33
-
34
- @property
35
- def filepath(self) -> str:
36
- """The file path to file being uploaded"""
37
- path = self.__load_filepath(self.__filepath)
38
-
39
- if not os.path.exists(path):
40
- raise RuntimeError(f"The Upload File was not found: {path}")
41
-
42
- return path
43
-
44
- def __load_filepath(self, filepath: str) -> str:
45
- """Load the filepath"""
46
- if filepath is None:
47
- raise RuntimeError("Filepath is required")
48
- elif filepath.startswith("${module}"):
49
- # find the path
50
- es: EnvironmentServices = EnvironmentServices()
51
- root = es.find_module_path()
52
- filepath = filepath.replace("${module}", root)
53
-
54
- # get the correct os path separator
55
- filepath = os.path.normpath(filepath)
56
- return filepath
57
-
58
-
59
- class FileUploads(ConfigBase):
60
- """
61
- File Uploads: Defines the files that the application file upload tests will check against
62
-
63
- """
64
-
65
- def __init__(self):
66
- super().__init__()
67
- self.__fileuploads: List[FileUpload] = []
68
-
69
- @property
70
- def list(self) -> List[FileUpload]:
71
- """List the file uploads"""
72
- return filter(lambda x: x.enabled, self.__fileuploads)
73
-
74
- def add(self, *, filepath: str, login: Login, enabled: bool = True):
75
- """Add a file upload"""
76
- fileupload = FileUpload(login, filepath)
77
- fileupload.enabled = enabled
78
- self.__fileuploads.append(fileupload)
79
-
80
- def load(self, test_config: Dict[str, Any]):
81
- """Load the file uploads from a list of dictionaries"""
82
-
83
- super().load(test_config)
84
- test_config_login: Login = self.try_load_login(test_config.get("login", None))
85
- fileuploads: List[Dict[str, Any]] = test_config.get("files", [])
86
- login: Login = None
87
- for fileupload in fileuploads:
88
- enabled = bool(fileupload.get("enabled", True))
89
- if "login" in fileupload:
90
- login = self.try_load_login(fileupload["login"])
91
- else:
92
- login = test_config_login
93
-
94
- self.add(filepath=fileupload["file"], login=login, enabled=enabled)
95
-
96
- def try_load_login(self, login_config: Dict[str, Any]) -> Login | None:
97
- """Attempts to intialize a Login from a configuration object"""
98
- login: Login = None
99
- if login_config is not None:
100
- username = login_config.get("username", None)
101
- password = login_config.get("password", None)
102
- domain = login_config.get("domain", None)
103
- login = Login(username, password, domain)
104
- return login
@@ -1,5 +0,0 @@
1
- """
2
- Copyright 2024 Aplos Analytics
3
- All Rights Reserved. www.aplosanalytics.com LICENSED MATERIALS
4
- Property of Aplos Analytics, Utah, USA
5
- """
@@ -1,387 +0,0 @@
1
- """
2
- Copyright 2024 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
- import time
10
- import zipfile
11
- from datetime import datetime, timedelta
12
- from pathlib import Path
13
- from typing import Any, Dict
14
-
15
- import requests
16
-
17
- from aplos_nca_saas_sdk.aws_resources.aws_cognito import CognitoAuthenication
18
- from aplos_nca_saas_sdk.aws_resources.aws_s3_presigned_upload import (
19
- S3PresignedUpload,
20
- )
21
- from aplos_nca_saas_sdk.utilities.commandline_args import CommandlineArgs
22
- from aplos_nca_saas_sdk.utilities.http_utility import HttpUtilities, Routes
23
-
24
-
25
- class NCAEngine:
26
- """NCA Engine Access"""
27
-
28
- def __init__(
29
- self, api_domain: str | None, cognito_client_id: str | None, region: str | None
30
- ) -> None:
31
- self.jwt: str
32
- self.access_token: str | None = None
33
- self.refresh_token: str | None = None
34
- self.__api_domain: str | None = api_domain
35
- self.verbose: bool = False
36
-
37
- self.cognito: CognitoAuthenication = CognitoAuthenication(
38
- client_id=cognito_client_id, region=region
39
- )
40
-
41
- if not self.__api_domain:
42
- raise RuntimeError(
43
- "Missing Aplos Api Domain. "
44
- "Pass in the api_domain as a command arg or set the APLOS_API_DOMAIN environment var."
45
- )
46
-
47
- @property
48
- def api_root(self) -> str:
49
- """Gets the base url"""
50
- if self.__api_domain is None:
51
- raise RuntimeError("Missing Aplos Api Domain")
52
-
53
- url = HttpUtilities.build_url(self.__api_domain)
54
- if isinstance(url, str):
55
- return (
56
- f"{url}/tenants/{self.cognito.tenant_id}/users/{self.cognito.user_id}"
57
- )
58
-
59
- raise RuntimeError("Missing Aplos Api Domain")
60
-
61
- def execute(
62
- self,
63
- username: str,
64
- password: str,
65
- input_file_path: str,
66
- config_data: dict,
67
- *,
68
- meta_data: str | dict | None = None,
69
- wait_for_results: bool = True,
70
- output_directory: str | None = None,
71
- unzip_after_download: bool = False,
72
- ) -> None:
73
- """_summary_
74
-
75
- Args:
76
- username (str): the username
77
- password (str): the users password
78
- input_file_path (str): the path to the input (anlysis) file
79
- config_data (dict): analysis configuration infomration
80
- meta_data (str | dict | None, optional): meta data attached to the execution. Defaults to None.
81
- wait_for_results (bool, optional): should the program wait for results. Defaults to True.
82
- output_directory (str, optional): the output directory. Defaults to None (the local directy is used)
83
- unzip_after_download (bool): Results are downloaded as a zip file, this option will unzip them automatically. Defaults to False
84
- """
85
- if self.verbose:
86
- print("\tLogging in.")
87
- self.jwt = self.cognito.login(username=username, password=password)
88
-
89
- if self.verbose:
90
- print("\tUploading the analysis file.")
91
- uploader: S3PresignedUpload = S3PresignedUpload(self.jwt, str(self.api_root))
92
- upload_response: Dict[str, Any] = uploader.upload_file(input_file_path)
93
-
94
- if self.verbose:
95
- print("\tStarting the execution.")
96
- execution_id = self.run_analysis(
97
- file_id=upload_response.get("file_id", ""),
98
- config_data=config_data,
99
- meta_data=meta_data,
100
- )
101
-
102
- if execution_id and wait_for_results:
103
- # wait for it
104
- download_url = self.wait_for_results(execution_id=execution_id)
105
- # download the files
106
- if download_url:
107
- if self.verbose:
108
- print("\tDownloading the results.")
109
- self.download_file(
110
- download_url,
111
- output_directory=output_directory,
112
- do_unzip=unzip_after_download,
113
- )
114
-
115
- def run_analysis(
116
- self,
117
- file_id: str,
118
- config_data: dict,
119
- meta_data: str | dict | None = None,
120
- ) -> str:
121
- """
122
- Run the analysis
123
-
124
- Args:
125
- bucket_name (str): s3 bucket name for your organization. this is returned to you
126
- object_key (str): 3s object key for the file you are running an analysis on.
127
- config_data (dict): the config_data for the analysis file
128
- meta_data (str | dict): Optional. Any meta data you'd like attached to this execution
129
- Returns:
130
- str: the execution id
131
- """
132
-
133
- if not file_id:
134
- raise ValueError("Missing file_id. Please provide a valid file_id.")
135
-
136
- if not config_data:
137
- raise ValueError(
138
- "Missing config_data. Please provide a valid config_data."
139
- )
140
- headers = HttpUtilities.get_headers(self.jwt)
141
- # to start a new execution we need the location of the file (s3 bucket and object key)
142
- # you basic configuration
143
- # optional meta data
144
-
145
- submission = {
146
- "file": {"id": file_id},
147
- "configuration": config_data,
148
- "meta_data": meta_data,
149
- }
150
- url = f"{str(self.api_root)}/{Routes.NCA_EXECUTIONS}"
151
- response: requests.Response = requests.post(
152
- url, headers=headers, data=json.dumps(submission), timeout=30
153
- )
154
- json_response: dict = response.json()
155
-
156
- if response.status_code == 403:
157
- raise PermissionError(
158
- "Failed to execute. A 403 response occured. "
159
- "This could a token issue or a url path issue "
160
- "By default unknown gateway calls return 403 errors. "
161
- )
162
- elif response.status_code != 200:
163
- raise RuntimeError(
164
- f"Unknown Error occured during executions: {response.status_code}. "
165
- f"Reason: {response.reason}"
166
- )
167
-
168
- execution_id = str(json_response.get("execution_id"))
169
- if self.verbose:
170
- print(f"\tExecution {execution_id} started.")
171
-
172
- return execution_id
173
-
174
- def wait_for_results(
175
- self, execution_id: str, max_wait_in_minutes: int = 15
176
- ) -> str | None:
177
- """
178
- Wait for results
179
- Args:
180
- execution_id (str): the analysis execution id
181
-
182
- Returns:
183
- str | None: on success: a url for download, on failure: None
184
- """
185
-
186
- url = f"{self.api_root}/{Routes.NCA_EXECUTIONS}/{execution_id}"
187
-
188
- headers = HttpUtilities.get_headers(self.jwt)
189
- current_time = datetime.now()
190
- # Create a timedelta object representing 15 minutes
191
- time_delta = timedelta(minutes=max_wait_in_minutes)
192
-
193
- # Add the timedelta to the current time
194
- max_time = current_time + time_delta
195
-
196
- complete = False
197
- while not complete:
198
- response = requests.get(url, headers=headers, timeout=30)
199
- json_response: dict = response.json()
200
- status = json_response.get("status")
201
- complete = status == "complete"
202
- elapsed = (
203
- json_response.get("times", {}).get("elapsed", "0:00:00") or "--:--"
204
- )
205
- if status == "failed" or complete:
206
- break
207
- if not complete:
208
- if self.verbose:
209
- print(f"\t\twaiting for results.... {status}: {elapsed}")
210
- time.sleep(5)
211
- if datetime.now() > max_time:
212
- status = "timeout"
213
- break
214
- if status is None and elapsed is None:
215
- # we have a problem
216
- status = "unknown issue"
217
- break
218
-
219
- if status == "complete":
220
- if self.verbose:
221
- print("\tExecution complete.")
222
- print(f"\tExecution duration = {elapsed}.")
223
- return json_response["presigned"]["url"]
224
- else:
225
- if self.verbose:
226
- print(
227
- f"\tExecution failed. Execution ID = {execution_id}. reason: {json_response.get('errors')}"
228
- )
229
- return None
230
-
231
- def download_file(
232
- self,
233
- presigned_download_url: str,
234
- output_directory: str | None = None,
235
- do_unzip: bool = False,
236
- ) -> str | None:
237
- """
238
- # Step 5
239
- Download completed analysis files
240
-
241
- Args:
242
- presigned_download_url (str): presigned download url
243
- output_directory (str | None): optional output directory
244
-
245
- Returns:
246
- str: file path to results or None
247
- """
248
- if output_directory is None:
249
- output_directory = str(Path(__file__).parent.parent)
250
- output_directory = os.path.join(output_directory, ".aplos-nca-output")
251
-
252
- if presigned_download_url:
253
- output_file = f"results-{time.strftime('%Y-%m-%d-%Hh%Mm%Ss')}.zip"
254
-
255
- output_file = os.path.join(output_directory, output_file)
256
- os.makedirs(output_directory, exist_ok=True)
257
-
258
- response = requests.get(presigned_download_url, timeout=60)
259
- # write the zip to a file
260
- with open(output_file, "wb") as f:
261
- f.write(response.content)
262
-
263
- # optionally, extract all the files from the zip
264
- if do_unzip:
265
- with zipfile.ZipFile(output_file, "r") as zip_ref:
266
- zip_ref.extractall(output_file.replace(".zip", ""))
267
-
268
- unzipped_state = "and unzipped" if do_unzip else "in zip format"
269
-
270
- if self.verbose:
271
- print(f"\tResults file downloaded {unzipped_state}.")
272
- print(f"\t\tResults are available in: {output_directory}")
273
-
274
- return output_directory
275
- else:
276
- return None
277
-
278
-
279
- def main():
280
- try:
281
- print("Welcome to the NCA Engine Upload & Execution Demo")
282
- args = CommandlineArgs()
283
- files_path = os.path.join(Path(__file__).parent, "files")
284
-
285
- args.analysis_file_default = os.path.join(files_path, "single_ev.csv")
286
- args.config_file_default = os.path.join(
287
- files_path, "configuration_single_ev.json"
288
- )
289
- args.metadata_file_default = os.path.join(files_path, "meta_data.json")
290
- if not args.is_valid():
291
- print("\n\n")
292
- print("Missing some arguments.")
293
- exit()
294
-
295
- engine = NCAEngine(
296
- api_domain=args.api_domain,
297
- cognito_client_id=args.cognito_client_id,
298
- region=args.aws_region,
299
- )
300
-
301
- print("\tLoading analysis configurations")
302
- print(f"\t\t{args.config_file}")
303
- config_data: dict = read_json_file(str(args.config_file))
304
-
305
- print("\tLoading analysis meta data")
306
- print(f"\t\t{args.metadata_file}")
307
- meta_data = optional_json_loads(read_text_file(str(args.metadata_file)))
308
-
309
- engine.execute(
310
- username=str(args.username),
311
- password=str(args.password),
312
- input_file_path=str(args.analysis_file),
313
- config_data=config_data,
314
- meta_data=meta_data,
315
- output_directory=str(args.output_directory),
316
- )
317
- print("Thank you for using the NCA Engine Upload and Execution Demo")
318
- except Exception as e: # pylint: disable=w0718
319
- print("An error occured ... exiting with an error")
320
- print(str(e))
321
-
322
-
323
- def optional_json_loads(data: str | dict) -> str | dict:
324
- """
325
- Attempts to load the data as json, fails gracefull and retuns the data is if it fails
326
- Args:
327
- data (str): data as string
328
-
329
- Returns:
330
- str | dict: either the data as is or a converted dictionary/json object
331
- """
332
- if isinstance(data, dict):
333
- return data
334
-
335
- try:
336
- data = json.loads(str(data))
337
- finally:
338
- pass
339
- return data
340
-
341
-
342
- def read_json_file(file_path: str) -> dict:
343
- """
344
- Reads a file and returns the json
345
- Args:
346
- file_path (str): _description_
347
-
348
- Raises:
349
- FileNotFoundError: _description_
350
-
351
- Returns:
352
- dict: _description_
353
- """
354
- if not os.path.exists(file_path):
355
- raise FileNotFoundError(f"File Not Found: {file_path}")
356
-
357
- data = None
358
- with open(file_path, mode="r", encoding="utf8") as file:
359
- data = json.load(file)
360
-
361
- return data
362
-
363
-
364
- def read_text_file(file_path: str) -> str:
365
- """
366
- Read files contents
367
- Args:
368
- file_path (str): path to the file
369
-
370
- Raises:
371
- FileNotFoundError: if the file is not found
372
-
373
- Returns:
374
- str: the files data
375
- """
376
- if not os.path.exists(file_path):
377
- raise FileNotFoundError(f"File Not Found: {file_path}")
378
-
379
- data = None
380
- with open(file_path, mode="r", encoding="utf8") as file:
381
- data = file.read()
382
-
383
- return data
384
-
385
-
386
- if __name__ == "__main__":
387
- main()