atlan-application-sdk 0.1.1rc34__py3-none-any.whl → 0.1.1rc35__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 (33) hide show
  1. application_sdk/activities/__init__.py +3 -2
  2. application_sdk/activities/common/utils.py +21 -1
  3. application_sdk/activities/metadata_extraction/base.py +4 -2
  4. application_sdk/activities/metadata_extraction/sql.py +13 -12
  5. application_sdk/activities/query_extraction/sql.py +24 -20
  6. application_sdk/clients/atlan_auth.py +2 -2
  7. application_sdk/clients/temporal.py +6 -10
  8. application_sdk/inputs/json.py +6 -4
  9. application_sdk/inputs/parquet.py +16 -13
  10. application_sdk/outputs/__init__.py +6 -3
  11. application_sdk/outputs/json.py +9 -6
  12. application_sdk/outputs/parquet.py +10 -36
  13. application_sdk/server/fastapi/__init__.py +4 -5
  14. application_sdk/services/__init__.py +18 -0
  15. application_sdk/{outputs → services}/atlan_storage.py +64 -16
  16. application_sdk/{outputs → services}/eventstore.py +68 -6
  17. application_sdk/services/objectstore.py +407 -0
  18. application_sdk/services/secretstore.py +344 -0
  19. application_sdk/services/statestore.py +267 -0
  20. application_sdk/version.py +1 -1
  21. application_sdk/worker.py +1 -1
  22. {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/METADATA +1 -1
  23. {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/RECORD +26 -29
  24. application_sdk/common/credential_utils.py +0 -85
  25. application_sdk/inputs/objectstore.py +0 -238
  26. application_sdk/inputs/secretstore.py +0 -130
  27. application_sdk/inputs/statestore.py +0 -101
  28. application_sdk/outputs/objectstore.py +0 -125
  29. application_sdk/outputs/secretstore.py +0 -38
  30. application_sdk/outputs/statestore.py +0 -113
  31. {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/WHEEL +0 -0
  32. {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/licenses/LICENSE +0 -0
  33. {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/licenses/NOTICE +0 -0
@@ -1,125 +0,0 @@
1
- """Object store interface for the application."""
2
-
3
- import os
4
- import shutil
5
-
6
- from dapr.clients import DaprClient
7
- from temporalio import activity
8
-
9
- from application_sdk.constants import DEPLOYMENT_OBJECT_STORE_NAME
10
- from application_sdk.observability.logger_adaptor import get_logger
11
-
12
- logger = get_logger(__name__)
13
- activity.logger = logger
14
-
15
-
16
- class ObjectStoreOutput:
17
- OBJECT_CREATE_OPERATION = "create"
18
-
19
- @staticmethod
20
- def _cleanup_local_path(path: str) -> None:
21
- """Remove a file or directory (recursively). Ignores if doesn't exist.
22
- Args:
23
- path (str): The path to the file or directory to remove.
24
- """
25
- try:
26
- if os.path.isfile(path) or os.path.islink(path):
27
- os.remove(path)
28
- elif os.path.isdir(path):
29
- shutil.rmtree(path)
30
- except FileNotFoundError:
31
- pass # ignore if the file or directory doesn't exist
32
- except Exception as e:
33
- logger.warning(f"Error cleaning up {path}: {str(e)}")
34
-
35
- @classmethod
36
- async def push_file_to_object_store(
37
- cls,
38
- output_prefix: str,
39
- file_path: str,
40
- object_store_name: str = DEPLOYMENT_OBJECT_STORE_NAME,
41
- ) -> None:
42
- """Pushes a single file to the object store.
43
-
44
- Args:
45
- output_prefix (str): The base path to calculate relative paths from.
46
- example: /tmp/output
47
- file_path (str): The full path to the file to be pushed.
48
- example: /tmp/output/persistent-artifacts/apps/myapp/data/wf-123/state.json
49
-
50
- Raises:
51
- IOError: If there's an error reading the file.
52
- Exception: If there's an error pushing the file to the object store.
53
- """
54
- with DaprClient() as client:
55
- try:
56
- with open(file_path, "rb") as f:
57
- file_content = f.read()
58
- except IOError as e:
59
- logger.error(f"Error reading file {file_path}: {str(e)}")
60
- raise e
61
-
62
- relative_path = os.path.relpath(file_path, output_prefix)
63
- metadata = {
64
- "key": relative_path,
65
- "blobName": relative_path,
66
- "fileName": relative_path,
67
- }
68
-
69
- try:
70
- client.invoke_binding(
71
- binding_name=object_store_name,
72
- operation=cls.OBJECT_CREATE_OPERATION,
73
- data=file_content,
74
- binding_metadata=metadata,
75
- )
76
- logger.debug(f"Successfully pushed file: {relative_path}")
77
- except Exception as e:
78
- logger.error(
79
- f"Error pushing file {relative_path} to object store: {str(e)}"
80
- )
81
- raise e
82
- cls._cleanup_local_path(file_path)
83
-
84
- @classmethod
85
- async def push_files_to_object_store(
86
- cls,
87
- output_prefix: str,
88
- input_files_path: str,
89
- object_store_name: str = DEPLOYMENT_OBJECT_STORE_NAME,
90
- ) -> None:
91
- """Pushes files from a directory to the object store.
92
-
93
- Args:
94
- output_prefix (str): The base path to calculate relative paths from.
95
- input_files_path (str): The path to the directory containing files to push.
96
-
97
- Raises:
98
- ValueError: If the input_files_path doesn't exist or is not a directory.
99
- IOError: If there's an error reading files.
100
- Exception: If there's an error with the Dapr client operations.
101
-
102
- Example:
103
- >>> ObjectStoreOutput.push_files_to_object_store("logs", "/tmp/observability")
104
- """
105
- if not os.path.isdir(input_files_path):
106
- raise ValueError(
107
- f"The provided output_path '{input_files_path}' is not a valid directory."
108
- )
109
-
110
- try:
111
- for root, _, files in os.walk(input_files_path):
112
- for file in files:
113
- file_path = os.path.join(root, file)
114
- await cls.push_file_to_object_store(
115
- output_prefix, file_path, object_store_name
116
- )
117
-
118
- logger.info(
119
- f"Completed pushing data from {input_files_path} to object store"
120
- )
121
- except Exception as e:
122
- logger.error(
123
- f"An unexpected error occurred while pushing files to object store: {str(e)}"
124
- )
125
- raise e
@@ -1,38 +0,0 @@
1
- """Secret store for the application."""
2
-
3
- import uuid
4
- from typing import Any, Dict
5
-
6
- from application_sdk.constants import DEPLOYMENT_NAME, LOCAL_ENVIRONMENT
7
- from application_sdk.inputs.statestore import StateType
8
- from application_sdk.outputs.statestore import StateStoreOutput
9
-
10
-
11
- class SecretStoreOutput:
12
- @classmethod
13
- async def save_secret(cls, config: Dict[str, Any]) -> str:
14
- """Store credentials in the state store.
15
-
16
- Args:
17
- config: The credentials to store.
18
-
19
- Returns:
20
- str: The generated credential GUID.
21
-
22
- Raises:
23
- Exception: If there's an error with the Dapr client operations.
24
-
25
- Examples:
26
- >>> SecretStoreOutput.save_secret({"username": "admin", "password": "password"})
27
- "1234567890"
28
- """
29
- if DEPLOYMENT_NAME == LOCAL_ENVIRONMENT:
30
- # NOTE: (development) temporary solution to store the credentials in the state store.
31
- # In production, dapr doesn't support creating secrets.
32
- credential_guid = str(uuid.uuid4())
33
- await StateStoreOutput.save_state_object(
34
- id=credential_guid, value=config, type=StateType.CREDENTIALS
35
- )
36
- return credential_guid
37
- else:
38
- raise ValueError("Storing credentials is not supported in production.")
@@ -1,113 +0,0 @@
1
- """State store for the application."""
2
-
3
- import json
4
- import os
5
- from typing import Any, Dict
6
-
7
- from temporalio import activity
8
-
9
- from application_sdk.constants import TEMPORARY_PATH, UPSTREAM_OBJECT_STORE_NAME
10
- from application_sdk.inputs.statestore import (
11
- StateStoreInput,
12
- StateType,
13
- build_state_store_path,
14
- )
15
- from application_sdk.observability.logger_adaptor import get_logger
16
- from application_sdk.outputs.objectstore import ObjectStoreOutput
17
-
18
- logger = get_logger(__name__)
19
- activity.logger = logger
20
-
21
-
22
- class StateStoreOutput:
23
- @classmethod
24
- async def save_state(cls, key: str, value: Any, id: str, type: StateType) -> None:
25
- """Save state to the store.
26
-
27
- Args:
28
- key: The key to store the state under.
29
- value: The dictionary value to store.
30
-
31
- Raises:
32
- Exception: If there's an error with the Dapr client operations.
33
-
34
- Example:
35
- >>> from application_sdk.outputs.statestore import StateStoreOutput
36
-
37
- >>> await StateStoreOutput.save_state("test", {"test": "test"}, "wf-123")
38
- """
39
- try:
40
- # get the current state from object store
41
- current_state = StateStoreInput.get_state(id, type)
42
- state_file_path = build_state_store_path(id, type)
43
-
44
- # update the state with the new value
45
- current_state[key] = value
46
-
47
- local_state_file_path = os.path.join(TEMPORARY_PATH, state_file_path)
48
- os.makedirs(os.path.dirname(local_state_file_path), exist_ok=True)
49
-
50
- # save the state to a local file
51
- with open(local_state_file_path, "w") as file:
52
- json.dump(current_state, file)
53
-
54
- # save the state to the object store
55
- await ObjectStoreOutput.push_file_to_object_store(
56
- output_prefix=TEMPORARY_PATH,
57
- file_path=local_state_file_path,
58
- object_store_name=UPSTREAM_OBJECT_STORE_NAME,
59
- )
60
-
61
- except Exception as e:
62
- logger.error(f"Failed to store state: {str(e)}")
63
- raise e
64
-
65
- @classmethod
66
- async def save_state_object(
67
- cls, id: str, value: Dict[str, Any], type: StateType
68
- ) -> Dict[str, Any]:
69
- """Save the entire state object to the object store.
70
-
71
- Args:
72
- id: The id of the state.
73
- value: The value of the state.
74
- type: The type of the state.
75
-
76
- Returns:
77
- Dict[str, Any]: The updated state.
78
-
79
- Raises:
80
- ValueError: If the type is invalid.
81
- Exception: If there's an error with the Dapr client operations.
82
-
83
- Example:
84
- >>> from application_sdk.outputs.statestore import StateStoreOutput
85
- >>> await StateStoreOutput.save_state_object("wf-123", {"test": "test"}, "workflow")
86
- """
87
- try:
88
- logger.info(f"Saving state object for {id} with type {type}")
89
- # get the current state from object store
90
- current_state = StateStoreInput.get_state(id, type)
91
- state_file_path = build_state_store_path(id, type)
92
-
93
- # update the state with the new value
94
- current_state.update(value)
95
-
96
- local_state_file_path = os.path.join(TEMPORARY_PATH, state_file_path)
97
- os.makedirs(os.path.dirname(local_state_file_path), exist_ok=True)
98
-
99
- # save the state to a local file
100
- with open(local_state_file_path, "w") as file:
101
- json.dump(current_state, file)
102
-
103
- # save the state to the object store
104
- await ObjectStoreOutput.push_file_to_object_store(
105
- output_prefix=TEMPORARY_PATH,
106
- file_path=local_state_file_path,
107
- object_store_name=UPSTREAM_OBJECT_STORE_NAME,
108
- )
109
- logger.info(f"State object saved for {id} with type {type}")
110
- return current_state
111
- except Exception as e:
112
- logger.error(f"Failed to store state: {str(e)}")
113
- raise e