automizor 0.3.0__tar.gz → 0.4.0__tar.gz
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.
- {automizor-0.3.0/automizor.egg-info → automizor-0.4.0}/PKG-INFO +1 -1
- automizor-0.4.0/automizor/__init__.py +1 -0
- automizor-0.4.0/automizor/exceptions.py +69 -0
- {automizor-0.3.0 → automizor-0.4.0}/automizor/job/__init__.py +0 -2
- {automizor-0.3.0 → automizor-0.4.0}/automizor/job/_job.py +14 -17
- automizor-0.4.0/automizor/storage/__init__.py +179 -0
- automizor-0.4.0/automizor/storage/_storage.py +300 -0
- automizor-0.4.0/automizor/utils/__init__.py +31 -0
- automizor-0.4.0/automizor/vault/__init__.py +86 -0
- automizor-0.4.0/automizor/vault/_container.py +69 -0
- automizor-0.4.0/automizor/vault/_vault.py +139 -0
- {automizor-0.3.0 → automizor-0.4.0/automizor.egg-info}/PKG-INFO +1 -1
- {automizor-0.3.0 → automizor-0.4.0}/automizor.egg-info/SOURCES.txt +3 -4
- {automizor-0.3.0 → automizor-0.4.0}/setup.py +1 -2
- automizor-0.3.0/automizor/__init__.py +0 -1
- automizor-0.3.0/automizor/job/_exceptions.py +0 -2
- automizor-0.3.0/automizor/storage/__init__.py +0 -81
- automizor-0.3.0/automizor/storage/_exceptions.py +0 -2
- automizor-0.3.0/automizor/storage/_storage.py +0 -165
- automizor-0.3.0/automizor/vault/__init__.py +0 -57
- automizor-0.3.0/automizor/vault/_exceptions.py +0 -2
- automizor-0.3.0/automizor/vault/_secret.py +0 -45
- automizor-0.3.0/automizor/vault/_vault.py +0 -139
- {automizor-0.3.0 → automizor-0.4.0}/LICENSE +0 -0
- {automizor-0.3.0 → automizor-0.4.0}/MANIFEST.in +0 -0
- {automizor-0.3.0 → automizor-0.4.0}/README.md +0 -0
- {automizor-0.3.0 → automizor-0.4.0}/automizor.egg-info/dependency_links.txt +0 -0
- {automizor-0.3.0 → automizor-0.4.0}/automizor.egg-info/requires.txt +0 -0
- {automizor-0.3.0 → automizor-0.4.0}/automizor.egg-info/top_level.txt +0 -0
- {automizor-0.3.0 → automizor-0.4.0}/setup.cfg +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
version = "0.4.0"
|
@@ -0,0 +1,69 @@
|
|
1
|
+
from requests import Response
|
2
|
+
|
3
|
+
|
4
|
+
class AutomizorError(Exception):
|
5
|
+
def __init__(self, message, error=None):
|
6
|
+
if error:
|
7
|
+
message = f"{message}: {error}"
|
8
|
+
super().__init__(message)
|
9
|
+
|
10
|
+
def __str__(self):
|
11
|
+
return f"{self.args[0]}"
|
12
|
+
|
13
|
+
@classmethod
|
14
|
+
def from_response(cls, response: Response, message: str):
|
15
|
+
_STATUS_EXCEPTION_MAP = {
|
16
|
+
400: InvalidRequest,
|
17
|
+
401: Unauthorized,
|
18
|
+
403: Forbidden,
|
19
|
+
404: NotFound,
|
20
|
+
429: RateLimitExceeded,
|
21
|
+
500: InternalServerError,
|
22
|
+
502: BadGateway,
|
23
|
+
503: ServiceUnavailable,
|
24
|
+
}
|
25
|
+
|
26
|
+
try:
|
27
|
+
error = dict(response.json()).get("detail", "Unknown error.")
|
28
|
+
except Exception: # pylint: disable=broad-except
|
29
|
+
error = response.text
|
30
|
+
|
31
|
+
return _STATUS_EXCEPTION_MAP.get(response.status_code, UnexpectedError)(
|
32
|
+
message, error
|
33
|
+
)
|
34
|
+
|
35
|
+
|
36
|
+
class BadGateway(AutomizorError):
|
37
|
+
pass
|
38
|
+
|
39
|
+
|
40
|
+
class Forbidden(AutomizorError):
|
41
|
+
pass
|
42
|
+
|
43
|
+
|
44
|
+
class InternalServerError(AutomizorError):
|
45
|
+
pass
|
46
|
+
|
47
|
+
|
48
|
+
class InvalidRequest(AutomizorError):
|
49
|
+
pass
|
50
|
+
|
51
|
+
|
52
|
+
class NotFound(AutomizorError):
|
53
|
+
pass
|
54
|
+
|
55
|
+
|
56
|
+
class RateLimitExceeded(AutomizorError):
|
57
|
+
pass
|
58
|
+
|
59
|
+
|
60
|
+
class ServiceUnavailable(AutomizorError):
|
61
|
+
pass
|
62
|
+
|
63
|
+
|
64
|
+
class Unauthorized(AutomizorError):
|
65
|
+
pass
|
66
|
+
|
67
|
+
|
68
|
+
class UnexpectedError(AutomizorError):
|
69
|
+
pass
|
@@ -1,6 +1,5 @@
|
|
1
1
|
from functools import lru_cache
|
2
2
|
|
3
|
-
from ._exceptions import AutomizorJobError
|
4
3
|
from ._job import JSON
|
5
4
|
|
6
5
|
|
@@ -44,7 +43,6 @@ def set_result(name: str, value: JSON):
|
|
44
43
|
|
45
44
|
|
46
45
|
__all__ = [
|
47
|
-
"AutomizorJobError",
|
48
46
|
"get_context",
|
49
47
|
"set_result",
|
50
48
|
]
|
@@ -4,7 +4,8 @@ from typing import Dict, List, Union
|
|
4
4
|
|
5
5
|
import requests
|
6
6
|
|
7
|
-
from .
|
7
|
+
from automizor.exceptions import AutomizorError
|
8
|
+
from automizor.utils import get_api_config, get_headers
|
8
9
|
|
9
10
|
JSON = Union[str, int, float, bool, None, Dict[str, "JSON"], List["JSON"]]
|
10
11
|
|
@@ -30,8 +31,7 @@ class Job:
|
|
30
31
|
To use this class effectively, ensure that the following environment variables are
|
31
32
|
set in your environment:
|
32
33
|
|
33
|
-
- ``
|
34
|
-
- ``AUTOMIZOR_API_TOKEN``: The authentication token for API access.
|
34
|
+
- ``AUTOMIZOR_AGENT_TOKEN``: The token for authenticating against the `Automizor API`.
|
35
35
|
- ``AUTOMIZOR_CONTEXT_FILE``: The path to a local file containing job context, if used.
|
36
36
|
- ``AUTOMIZOR_JOB_ID``: The identifier for the current job, used when fetching context via API.
|
37
37
|
|
@@ -50,18 +50,12 @@ class Job:
|
|
50
50
|
"""
|
51
51
|
|
52
52
|
def __init__(self):
|
53
|
-
self.
|
54
|
-
self.
|
55
|
-
self._context_file = os.getenv("AUTOMIZOR_CONTEXT_FILE")
|
56
|
-
self._job_id = os.getenv("AUTOMIZOR_JOB_ID")
|
53
|
+
self._context_file = os.getenv("AUTOMIZOR_CONTEXT_FILE", None)
|
54
|
+
self._job_id = os.getenv("AUTOMIZOR_JOB_ID", None)
|
57
55
|
|
56
|
+
self.url, self.token = get_api_config()
|
58
57
|
self.session = requests.Session()
|
59
|
-
self.session.headers.update(
|
60
|
-
{
|
61
|
-
"Authorization": f"Token {self._api_token}",
|
62
|
-
"Content-Type": "application/json",
|
63
|
-
}
|
64
|
-
)
|
58
|
+
self.session.headers.update(get_headers(self.token))
|
65
59
|
|
66
60
|
def get_context(self) -> dict:
|
67
61
|
"""
|
@@ -73,8 +67,7 @@ class Job:
|
|
73
67
|
This is useful in environments where direct access to the `Automizor API` is
|
74
68
|
not possible or preferred.
|
75
69
|
2. The `Automizor API`, using the job ID (`AUTOMIZOR_JOB_ID`) to fetch the specific
|
76
|
-
job context.
|
77
|
-
(`AUTOMIZOR_API_TOKEN`) settings.
|
70
|
+
job context.
|
78
71
|
|
79
72
|
Returns:
|
80
73
|
A dictionary containing the job context.
|
@@ -125,10 +118,14 @@ class Job:
|
|
125
118
|
return json.load(file)
|
126
119
|
|
127
120
|
def _read_job_context(self) -> dict:
|
128
|
-
url = f"https://{self.
|
121
|
+
url = f"https://{self.url}/api/v1/rpa/job/{self._job_id}/"
|
129
122
|
try:
|
130
123
|
response = self.session.get(url, timeout=10)
|
131
124
|
response.raise_for_status()
|
132
125
|
return response.json().get("context", {})
|
126
|
+
except requests.HTTPError as exc:
|
127
|
+
raise AutomizorError.from_response(
|
128
|
+
exc.response, "Failed to get job context"
|
129
|
+
) from exc
|
133
130
|
except Exception as exc:
|
134
|
-
raise
|
131
|
+
raise AutomizorError("Failed to get job context") from exc
|
@@ -0,0 +1,179 @@
|
|
1
|
+
import json
|
2
|
+
import mimetypes
|
3
|
+
from functools import lru_cache
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
from ._storage import JSON
|
7
|
+
|
8
|
+
|
9
|
+
@lru_cache
|
10
|
+
def _get_storage():
|
11
|
+
from ._storage import Storage
|
12
|
+
|
13
|
+
return Storage()
|
14
|
+
|
15
|
+
|
16
|
+
def list_assets() -> list[str]:
|
17
|
+
"""
|
18
|
+
Retrieves a list of all asset names.
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
A list of all asset names.
|
22
|
+
"""
|
23
|
+
|
24
|
+
storage = _get_storage()
|
25
|
+
return storage.list_assets()
|
26
|
+
|
27
|
+
|
28
|
+
def delete_asset(name: str) -> None:
|
29
|
+
"""
|
30
|
+
Deletes the specified asset.
|
31
|
+
|
32
|
+
Parameters:
|
33
|
+
name: The name identifier of the asset to delete.
|
34
|
+
"""
|
35
|
+
|
36
|
+
storage = _get_storage()
|
37
|
+
storage.delete_asset(name)
|
38
|
+
|
39
|
+
|
40
|
+
def get_bytes(name: str) -> bytes:
|
41
|
+
"""
|
42
|
+
Retrieves the specified asset as raw bytes.
|
43
|
+
|
44
|
+
Parameters:
|
45
|
+
name: The name identifier of the asset to retrieve.
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
The raw byte content of the asset.
|
49
|
+
"""
|
50
|
+
|
51
|
+
storage = _get_storage()
|
52
|
+
return storage.get_bytes(name)
|
53
|
+
|
54
|
+
|
55
|
+
def get_file(name: str, path: str) -> str:
|
56
|
+
"""
|
57
|
+
Downloads the specified asset and saves it to a file.
|
58
|
+
|
59
|
+
Parameters:
|
60
|
+
name: The name identifier of the asset to retrieve.
|
61
|
+
path: The filesystem path where the file will be saved.
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
The path to the saved file, confirming the operation's success.
|
65
|
+
"""
|
66
|
+
|
67
|
+
storage = _get_storage()
|
68
|
+
return storage.get_file(name, path)
|
69
|
+
|
70
|
+
|
71
|
+
def get_json(name: str) -> JSON:
|
72
|
+
"""
|
73
|
+
Retrieves the specified asset and parses it as JSON.
|
74
|
+
|
75
|
+
Parameters:
|
76
|
+
name: The name identifier of the asset to retrieve.
|
77
|
+
|
78
|
+
Returns:
|
79
|
+
The parsed JSON data, which can be a dict, list, or primitive data type.
|
80
|
+
"""
|
81
|
+
|
82
|
+
storage = _get_storage()
|
83
|
+
return storage.get_json(name)
|
84
|
+
|
85
|
+
|
86
|
+
def get_text(name: str) -> str:
|
87
|
+
"""
|
88
|
+
Retrieves the specified asset as a text string.
|
89
|
+
|
90
|
+
Parameters:
|
91
|
+
name: The name identifier of the asset to retrieve.
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
The content of the asset as a text string.
|
95
|
+
"""
|
96
|
+
|
97
|
+
storage = _get_storage()
|
98
|
+
return storage.get_text(name)
|
99
|
+
|
100
|
+
|
101
|
+
def set_bytes(name: str, data: bytes, content_type="application/octet-stream") -> None:
|
102
|
+
"""
|
103
|
+
Uploads raw bytes as an asset.
|
104
|
+
|
105
|
+
Parameters:
|
106
|
+
name: The name identifier of the asset to upload.
|
107
|
+
data: The raw byte content to upload.
|
108
|
+
content_type: The MIME type of the asset.
|
109
|
+
"""
|
110
|
+
|
111
|
+
storage = _get_storage()
|
112
|
+
storage.set_bytes(name, data, content_type)
|
113
|
+
|
114
|
+
|
115
|
+
def set_file(name: str, path: str, content_type: str = None) -> None:
|
116
|
+
"""
|
117
|
+
Uploads a file as an asset.
|
118
|
+
|
119
|
+
Parameters:
|
120
|
+
name: The name identifier of the asset to upload.
|
121
|
+
path: The filesystem path of the file to upload.
|
122
|
+
content_type: The MIME type of the asset.
|
123
|
+
"""
|
124
|
+
|
125
|
+
content = Path(path).read_bytes()
|
126
|
+
if content_type is None:
|
127
|
+
content_type, _ = mimetypes.guess_type(path)
|
128
|
+
if content_type is None:
|
129
|
+
content_type = "application/octet-stream"
|
130
|
+
|
131
|
+
storage = _get_storage()
|
132
|
+
storage.set_bytes(name, content, content_type)
|
133
|
+
|
134
|
+
|
135
|
+
def set_json(name: str, value: JSON, **kwargs) -> None:
|
136
|
+
"""
|
137
|
+
Uploads JSON data as an asset.
|
138
|
+
|
139
|
+
Parameters:
|
140
|
+
name: The name identifier of the asset to upload.
|
141
|
+
value: The JSON data to upload.
|
142
|
+
kwargs: Additional keyword arguments to pass to json.dumps.
|
143
|
+
"""
|
144
|
+
|
145
|
+
content = json.dumps(value, **kwargs).encode("utf-8")
|
146
|
+
content_type = "application/json"
|
147
|
+
|
148
|
+
storage = _get_storage()
|
149
|
+
storage.set_bytes(name, content, content_type)
|
150
|
+
|
151
|
+
|
152
|
+
def set_text(name: str, text: str) -> None:
|
153
|
+
"""
|
154
|
+
Uploads text content as an asset.
|
155
|
+
|
156
|
+
Parameters:
|
157
|
+
name: The name identifier of the asset to upload.
|
158
|
+
text: The text content to upload.
|
159
|
+
"""
|
160
|
+
|
161
|
+
content = text.encode("utf-8")
|
162
|
+
content_type = "text/plain"
|
163
|
+
|
164
|
+
storage = _get_storage()
|
165
|
+
storage.set_bytes(name, content, content_type)
|
166
|
+
|
167
|
+
|
168
|
+
__all__ = [
|
169
|
+
"list_assets",
|
170
|
+
"delete_asset",
|
171
|
+
"get_bytes",
|
172
|
+
"get_file",
|
173
|
+
"get_json",
|
174
|
+
"get_text",
|
175
|
+
"set_bytes",
|
176
|
+
"set_file",
|
177
|
+
"set_json",
|
178
|
+
"set_text",
|
179
|
+
]
|
@@ -0,0 +1,300 @@
|
|
1
|
+
from typing import Dict, List, Union
|
2
|
+
|
3
|
+
import requests
|
4
|
+
|
5
|
+
from automizor.exceptions import AutomizorError, NotFound
|
6
|
+
from automizor.utils import get_api_config, get_headers
|
7
|
+
|
8
|
+
JSON = Union[str, int, float, bool, None, Dict[str, "JSON"], List["JSON"]]
|
9
|
+
|
10
|
+
|
11
|
+
class Storage:
|
12
|
+
"""
|
13
|
+
`Storage` is a class designed to interact with the `Automizor Platform` for managing
|
14
|
+
digital assets, facilitating the retrieval of files in various formats such as bytes,
|
15
|
+
files, JSON, and text. It leverages the `Automizor Storage API` to access and download
|
16
|
+
these assets securely.
|
17
|
+
|
18
|
+
This class utilizes environment variables for configuration, specifically for setting
|
19
|
+
up the API host and API token, which are essential for authenticating requests made
|
20
|
+
to the `Automizor Storage API`. These variables are typically configured by the
|
21
|
+
`Automizor Agent`.
|
22
|
+
|
23
|
+
To use this class effectively, ensure that the following environment variables are
|
24
|
+
set in your environment:
|
25
|
+
|
26
|
+
- ``AUTOMIZOR_AGENT_TOKEN``: The token for authenticating against the `Automizor API`.
|
27
|
+
|
28
|
+
Example usage:
|
29
|
+
|
30
|
+
.. code-block:: python
|
31
|
+
|
32
|
+
from automizor import storage
|
33
|
+
|
34
|
+
# To list all assets
|
35
|
+
asset_names = storage.list_assets()
|
36
|
+
|
37
|
+
# To delete an asset
|
38
|
+
storage.delete_asset("AssetName")
|
39
|
+
|
40
|
+
# Save an asset
|
41
|
+
storage.set_bytes("AssetName", b"Hello, World!")
|
42
|
+
storage.set_file("AssetName", "/path/to/file")
|
43
|
+
storage.set_json("AssetName", {"key": "value"})
|
44
|
+
storage.set_text("AssetName", "Hello, World!")
|
45
|
+
|
46
|
+
# Get an asset
|
47
|
+
bytes_data = storage.get_bytes("AssetName")
|
48
|
+
file_path = storage.get_file("AssetName", "/path/to/save/file")
|
49
|
+
json_data = storage.get_json("AssetName")
|
50
|
+
text_data = storage.get_text("AssetName")
|
51
|
+
"""
|
52
|
+
|
53
|
+
def __init__(self):
|
54
|
+
self.url, self.token = get_api_config()
|
55
|
+
self.session = requests.Session()
|
56
|
+
self.session.headers.update(get_headers(self.token))
|
57
|
+
|
58
|
+
def list_assets(self) -> List[str]:
|
59
|
+
"""
|
60
|
+
Retrieves a list of all asset names.
|
61
|
+
|
62
|
+
This function fetches the names of all assets stored in the storage service,
|
63
|
+
providing a convenient way to list and identify the available assets.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
A list of all asset names.
|
67
|
+
"""
|
68
|
+
url = f"https://{self.url}/api/v1/storage/asset/"
|
69
|
+
asset_names = []
|
70
|
+
|
71
|
+
try:
|
72
|
+
while url:
|
73
|
+
response = self.session.get(url, timeout=10)
|
74
|
+
response.raise_for_status()
|
75
|
+
data = response.json()
|
76
|
+
|
77
|
+
for asset in data["results"]:
|
78
|
+
asset_names.append(asset["name"])
|
79
|
+
url = data["next"]
|
80
|
+
except requests.HTTPError as exc:
|
81
|
+
raise AutomizorError.from_response(
|
82
|
+
exc.response, "Failed to list assets"
|
83
|
+
) from exc
|
84
|
+
except Exception as exc:
|
85
|
+
raise AutomizorError("Failed to list assets") from exc
|
86
|
+
return asset_names
|
87
|
+
|
88
|
+
def delete_asset(self, name: str) -> None:
|
89
|
+
"""
|
90
|
+
Deletes the specified asset.
|
91
|
+
|
92
|
+
This function deletes the asset identified by `name` from the storage service.
|
93
|
+
It is useful for removing assets that are no longer needed or should be cleaned
|
94
|
+
up to free up storage space.
|
95
|
+
|
96
|
+
Parameters:
|
97
|
+
name: The name identifier of the asset to delete.
|
98
|
+
"""
|
99
|
+
|
100
|
+
url = f"https://{self.url}/api/v1/storage/asset/{name}/"
|
101
|
+
try:
|
102
|
+
response = self.session.delete(url, timeout=10)
|
103
|
+
response.raise_for_status()
|
104
|
+
except requests.HTTPError as exc:
|
105
|
+
raise AutomizorError.from_response(
|
106
|
+
exc.response, "Failed to delete asset"
|
107
|
+
) from exc
|
108
|
+
except Exception as exc:
|
109
|
+
raise AutomizorError("Failed to delete asset") from exc
|
110
|
+
|
111
|
+
def get_bytes(self, name: str) -> bytes:
|
112
|
+
"""
|
113
|
+
Retrieves the specified asset as raw bytes.
|
114
|
+
|
115
|
+
This function fetches the asset identified by `name` from the storage service
|
116
|
+
and returns it as a byte stream. It is useful for binary files or for data
|
117
|
+
that is intended to be processed or stored in its raw form.
|
118
|
+
|
119
|
+
Parameters:
|
120
|
+
name: The name identifier of the asset to retrieve.
|
121
|
+
|
122
|
+
Returns:
|
123
|
+
The raw byte content of the asset.
|
124
|
+
"""
|
125
|
+
|
126
|
+
return self._download_file(name, mode="content")
|
127
|
+
|
128
|
+
def get_file(self, name: str, path: str) -> str:
|
129
|
+
"""
|
130
|
+
Downloads the specified asset and saves it to a file.
|
131
|
+
|
132
|
+
This function fetches the asset identified by `name` and saves it directly
|
133
|
+
to the filesystem at the location specified by `path`. It is useful for
|
134
|
+
downloading files that need to be preserved in the file system, such as
|
135
|
+
documents, images, or other files.
|
136
|
+
|
137
|
+
Parameters:
|
138
|
+
name: The name identifier of the asset to retrieve.
|
139
|
+
path: The filesystem path where the file will be saved.
|
140
|
+
|
141
|
+
Returns:
|
142
|
+
The path to the saved file, confirming the operation's success.
|
143
|
+
"""
|
144
|
+
|
145
|
+
content = self._download_file(name, mode="content")
|
146
|
+
with open(path, "wb") as file:
|
147
|
+
file.write(content)
|
148
|
+
return path
|
149
|
+
|
150
|
+
def get_json(self, name: str) -> JSON:
|
151
|
+
"""
|
152
|
+
Retrieves the specified asset and parses it as JSON.
|
153
|
+
|
154
|
+
This function fetches the asset identified by `name` from the storage service
|
155
|
+
and parses it as JSON. It is useful for assets stored in JSON format, allowing
|
156
|
+
for easy access and manipulation of structured data.
|
157
|
+
|
158
|
+
Parameters:
|
159
|
+
name: The name identifier of the asset to retrieve.
|
160
|
+
|
161
|
+
Returns:
|
162
|
+
The parsed JSON data, which can be a dict, list, or primitive data type.
|
163
|
+
"""
|
164
|
+
|
165
|
+
return self._download_file(name, mode="json")
|
166
|
+
|
167
|
+
def get_text(self, name: str) -> str:
|
168
|
+
"""
|
169
|
+
Retrieves the specified asset as a text string.
|
170
|
+
|
171
|
+
This function fetches the asset identified by `name` from the storage service
|
172
|
+
and returns it as a text string. It is useful for text-based files, such as
|
173
|
+
configuration files, CSVs, or plain text documents.
|
174
|
+
|
175
|
+
Parameters:
|
176
|
+
name: The name identifier of the asset to retrieve.
|
177
|
+
|
178
|
+
Returns:
|
179
|
+
The content of the asset as a text string.
|
180
|
+
"""
|
181
|
+
|
182
|
+
return self._download_file(name, mode="text")
|
183
|
+
|
184
|
+
def set_bytes(self, name: str, content: bytes, content_type: str) -> None:
|
185
|
+
"""
|
186
|
+
Uploads the specified content as a new asset.
|
187
|
+
|
188
|
+
This function uploads the provided `content` as a new asset with the specified
|
189
|
+
`name`. It is useful for creating new assets or updating existing ones with
|
190
|
+
fresh content.
|
191
|
+
|
192
|
+
Parameters:
|
193
|
+
name: The name identifier of the asset to create.
|
194
|
+
content: The raw byte content of the asset.
|
195
|
+
content_type: The MIME type of the asset content.
|
196
|
+
"""
|
197
|
+
|
198
|
+
try:
|
199
|
+
self._update_asset(name, content, content_type)
|
200
|
+
except NotFound:
|
201
|
+
self._create_asset(name, content, content_type)
|
202
|
+
|
203
|
+
def _create_asset(self, name: str, content: bytes, content_type: str) -> None:
|
204
|
+
"""
|
205
|
+
Creates a new asset with the specified content.
|
206
|
+
|
207
|
+
This function creates a new asset with the specified `name` and `content` in the
|
208
|
+
storage service. It is useful for uploading new assets or updating existing ones
|
209
|
+
with fresh content.
|
210
|
+
|
211
|
+
Parameters:
|
212
|
+
name: The name identifier of the asset to create.
|
213
|
+
content: The raw byte content of the asset.
|
214
|
+
content_type: The MIME type of the asset content.
|
215
|
+
"""
|
216
|
+
|
217
|
+
url = f"https://{self.url}/api/v1/storage/asset/"
|
218
|
+
try:
|
219
|
+
data = {
|
220
|
+
"content_type": content_type,
|
221
|
+
"name": name,
|
222
|
+
}
|
223
|
+
files = {"file": ("text.txt", content, content_type)}
|
224
|
+
response = self.session.post(url, files=files, data=data, timeout=10)
|
225
|
+
response.raise_for_status()
|
226
|
+
except requests.HTTPError as exc:
|
227
|
+
raise AutomizorError.from_response(
|
228
|
+
exc.response, "Failed to create asset"
|
229
|
+
) from exc
|
230
|
+
except Exception as exc:
|
231
|
+
raise AutomizorError("Failed to create asset") from exc
|
232
|
+
|
233
|
+
def _download_file(self, name: str, mode: str = "content"):
|
234
|
+
url = self._get_asset_url(name)
|
235
|
+
|
236
|
+
try:
|
237
|
+
response = requests.get(url=url, timeout=10)
|
238
|
+
response.raise_for_status()
|
239
|
+
|
240
|
+
match mode:
|
241
|
+
case "content":
|
242
|
+
return response.content
|
243
|
+
case "json":
|
244
|
+
return response.json()
|
245
|
+
case "text":
|
246
|
+
return response.text
|
247
|
+
raise RuntimeError(f"Invalid mode {mode}")
|
248
|
+
except requests.HTTPError as exc:
|
249
|
+
raise AutomizorError.from_response(
|
250
|
+
exc.response, "Failed to download asset"
|
251
|
+
) from exc
|
252
|
+
except Exception as exc:
|
253
|
+
raise AutomizorError("Failed to download asset") from exc
|
254
|
+
|
255
|
+
def _get_asset_url(self, name: str) -> str:
|
256
|
+
url = f"https://{self.url}/api/v1/storage/asset/{name}/"
|
257
|
+
try:
|
258
|
+
response = self.session.get(url, timeout=10)
|
259
|
+
response.raise_for_status()
|
260
|
+
|
261
|
+
url = response.json().get("file")
|
262
|
+
if url:
|
263
|
+
return url
|
264
|
+
raise RuntimeError("Url not found")
|
265
|
+
except requests.HTTPError as exc:
|
266
|
+
raise AutomizorError.from_response(
|
267
|
+
exc.response, "Failed to get asset URL"
|
268
|
+
) from exc
|
269
|
+
except Exception as exc:
|
270
|
+
raise AutomizorError("Failed to get asset URL") from exc
|
271
|
+
|
272
|
+
def _update_asset(self, name: str, content: bytes, content_type: str) -> None:
|
273
|
+
"""
|
274
|
+
Updates the specified asset with new content.
|
275
|
+
|
276
|
+
This function updates the asset identified by `name` with fresh content
|
277
|
+
provided as `content`. It is useful for modifying existing assets without
|
278
|
+
creating a new asset, ensuring that the asset's content is up-to-date.
|
279
|
+
|
280
|
+
Parameters:
|
281
|
+
name: The name identifier of the asset to update.
|
282
|
+
content: The raw byte content of the asset.
|
283
|
+
content_type: The MIME type of the asset content.
|
284
|
+
"""
|
285
|
+
|
286
|
+
url = f"https://{self.url}/api/v1/storage/asset/{name}/"
|
287
|
+
try:
|
288
|
+
data = {
|
289
|
+
"content_type": content_type,
|
290
|
+
"name": name,
|
291
|
+
}
|
292
|
+
files = {"file": ("text.txt", content, content_type)}
|
293
|
+
response = self.session.put(url, files=files, data=data, timeout=10)
|
294
|
+
response.raise_for_status()
|
295
|
+
except requests.HTTPError as exc:
|
296
|
+
raise AutomizorError.from_response(
|
297
|
+
exc.response, "Failed to update asset"
|
298
|
+
) from exc
|
299
|
+
except Exception as exc:
|
300
|
+
raise AutomizorError("Failed to update asset") from exc
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import os
|
2
|
+
import platform
|
3
|
+
|
4
|
+
from automizor import version
|
5
|
+
from automizor.exceptions import AutomizorError
|
6
|
+
|
7
|
+
OS_SYSTEM, OS_RELEASE, _ = platform.system_alias(
|
8
|
+
platform.system(), platform.release(), platform.version()
|
9
|
+
)
|
10
|
+
|
11
|
+
|
12
|
+
def get_api_config() -> tuple[str, str]:
|
13
|
+
token_string = os.getenv("AUTOMIZOR_AGENT_TOKEN")
|
14
|
+
|
15
|
+
if not token_string:
|
16
|
+
raise AutomizorError("AUTOMIZOR_AGENT_TOKEN is not set.")
|
17
|
+
|
18
|
+
try:
|
19
|
+
token, url = token_string.strip().split("@")
|
20
|
+
except ValueError as exc:
|
21
|
+
raise AutomizorError(
|
22
|
+
"AUTOMIZOR_AGENT_TOKEN is not in the correct format."
|
23
|
+
) from exc
|
24
|
+
return url, token
|
25
|
+
|
26
|
+
|
27
|
+
def get_headers(token: str) -> dict:
|
28
|
+
return {
|
29
|
+
"Authorization": f"Token {token}",
|
30
|
+
"User-Agent": f"Automizor/{version} {OS_SYSTEM}/{OS_RELEASE}",
|
31
|
+
}
|