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.
- application_sdk/activities/__init__.py +3 -2
- application_sdk/activities/common/utils.py +21 -1
- application_sdk/activities/metadata_extraction/base.py +4 -2
- application_sdk/activities/metadata_extraction/sql.py +13 -12
- application_sdk/activities/query_extraction/sql.py +24 -20
- application_sdk/clients/atlan_auth.py +2 -2
- application_sdk/clients/temporal.py +6 -10
- application_sdk/inputs/json.py +6 -4
- application_sdk/inputs/parquet.py +16 -13
- application_sdk/outputs/__init__.py +6 -3
- application_sdk/outputs/json.py +9 -6
- application_sdk/outputs/parquet.py +10 -36
- application_sdk/server/fastapi/__init__.py +4 -5
- application_sdk/services/__init__.py +18 -0
- application_sdk/{outputs → services}/atlan_storage.py +64 -16
- application_sdk/{outputs → services}/eventstore.py +68 -6
- application_sdk/services/objectstore.py +407 -0
- application_sdk/services/secretstore.py +344 -0
- application_sdk/services/statestore.py +267 -0
- application_sdk/version.py +1 -1
- application_sdk/worker.py +1 -1
- {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/METADATA +1 -1
- {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/RECORD +26 -29
- application_sdk/common/credential_utils.py +0 -85
- application_sdk/inputs/objectstore.py +0 -238
- application_sdk/inputs/secretstore.py +0 -130
- application_sdk/inputs/statestore.py +0 -101
- application_sdk/outputs/objectstore.py +0 -125
- application_sdk/outputs/secretstore.py +0 -38
- application_sdk/outputs/statestore.py +0 -113
- {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/WHEEL +0 -0
- {atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/licenses/LICENSE +0 -0
- {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
|
{atlan_application_sdk-0.1.1rc34.dist-info → atlan_application_sdk-0.1.1rc35.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|