terrakio-core 0.2.3__py3-none-any.whl → 0.2.4__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.

Potentially problematic release.


This version of terrakio-core might be problematic. Click here for more details.

@@ -0,0 +1,81 @@
1
+ import os
2
+ import json
3
+ from pathlib import Path
4
+ from typing import Dict, Any, Optional
5
+
6
+ from .exceptions import ConfigurationError
7
+
8
+ # Default configuration file locations
9
+ DEFAULT_CONFIG_FILE = os.path.join(os.environ.get("HOME", ""), ".tkio_config.json")
10
+ DEFAULT_API_URL = "https://api.terrak.io"
11
+
12
+ def read_config_file(config_file: str = DEFAULT_CONFIG_FILE) -> Dict[str, Any]:
13
+ """
14
+ Read and parse the configuration file.
15
+
16
+ Args:
17
+ config_file: Path to the configuration file
18
+
19
+ Returns:
20
+ Dict[str, Any]: Configuration parameters
21
+
22
+ Raises:
23
+ ConfigurationError: If the configuration file can't be read or parsed
24
+ """
25
+ config_path = Path(os.path.expanduser(config_file))
26
+
27
+ if not config_path.exists():
28
+ raise ConfigurationError(
29
+ f"Configuration file not found: {config_file}\n"
30
+ f"Please create a file at {config_file} with the following format:\n"
31
+ '{\n "EMAIL": "your-email@example.com",\n "TERRAKIO_API_KEY": "your-api-key-here"\n}'
32
+ )
33
+
34
+ try:
35
+ with open(config_path, 'r') as f:
36
+ config_data = json.load(f)
37
+
38
+ # Convert the JSON config to our expected format
39
+ config = {
40
+ # Allow config to override default URL if provided
41
+ 'url': config_data.get('TERRAKIO_API_URL', DEFAULT_API_URL),
42
+ 'key': config_data.get('TERRAKIO_API_KEY')
43
+ }
44
+ return config
45
+
46
+ except Exception as e:
47
+ raise ConfigurationError(f"Failed to parse configuration file: {e}")
48
+
49
+ def create_default_config(email: str, api_key: str, api_url: Optional[str] = None, config_file: str = DEFAULT_CONFIG_FILE) -> None:
50
+ """
51
+ Create a default configuration file in JSON format.
52
+
53
+ Args:
54
+ email: User email
55
+ api_key: Terrakio API key
56
+ api_url: Optional API URL (if different from default)
57
+ config_file: Path to configuration file
58
+
59
+ Raises:
60
+ ConfigurationError: If the configuration file can't be created
61
+ """
62
+ config_path = Path(os.path.expanduser(config_file))
63
+
64
+ # Ensure directory exists
65
+ config_path.parent.mkdir(parents=True, exist_ok=True)
66
+
67
+ try:
68
+ config_data = {
69
+ "EMAIL": email,
70
+ "TERRAKIO_API_KEY": api_key
71
+ }
72
+
73
+ # Add API URL if provided
74
+ if api_url:
75
+ config_data["TERRAKIO_API_URL"] = api_url
76
+
77
+ with open(config_path, 'w') as f:
78
+ json.dump(config_data, f, indent=2)
79
+
80
+ except Exception as e:
81
+ raise ConfigurationError(f"Failed to create configuration file: {e}")
@@ -0,0 +1,235 @@
1
+ import requests
2
+ from typing import Dict, Any, List, Optional
3
+ from .exceptions import APIError
4
+
5
+ class DatasetManagement:
6
+ def __init__(self, api_url: str, api_key: str, verify: bool = True, timeout: int = 60):
7
+ """
8
+ Initialize the Dataset Management client.
9
+
10
+ Args:
11
+ api_url: API base URL
12
+ api_key: API key for authentication
13
+ verify: Verify SSL certificates
14
+ timeout: Request timeout in seconds
15
+ """
16
+ self.api_url = api_url.rstrip('/')
17
+ self.api_key = api_key
18
+ self.verify = verify
19
+ self.timeout = timeout
20
+ self.session = requests.Session()
21
+ self.session.headers.update({
22
+ 'x-api-key': self.api_key,
23
+ 'Content-Type': 'application/json'
24
+ })
25
+
26
+ def get_dataset(self, name: str, collection: str = "terrakio-datasets") -> Dict[str, Any]:
27
+ """
28
+ Retrieve dataset info by dataset name.
29
+
30
+ Args:
31
+ name: The name of the dataset (required)
32
+ collection: The dataset collection (default: 'terrakio-datasets')
33
+
34
+ Returns:
35
+ Dataset information as a dictionary
36
+
37
+ Raises:
38
+ APIError: If the API request fails
39
+ """
40
+ endpoint = f"{self.api_url}/datasets/{name}"
41
+ params = {"collection": collection} if collection else {}
42
+ try:
43
+ response = self.session.get(
44
+ endpoint,
45
+ params=params,
46
+ timeout=self.timeout,
47
+ verify=self.verify
48
+ )
49
+ if not response.ok:
50
+ raise APIError(f"API request failed: {response.status_code} {response.reason}")
51
+ return response.json()
52
+ except requests.RequestException as e:
53
+ raise APIError(f"Request failed: {str(e)}")
54
+
55
+ def list_datasets(self, substring: Optional[str] = None, collection: str = "terrakio-datasets") -> List[Dict[str, Any]]:
56
+ """
57
+ List datasets, optionally filtering by a substring and collection.
58
+
59
+ Args:
60
+ substring: Substring to filter by (optional)
61
+ collection: Dataset collection (default: 'terrakio-datasets')
62
+
63
+ Returns:
64
+ List of datasets matching the criteria
65
+
66
+ Raises:
67
+ APIError: If the API request fails
68
+ """
69
+ endpoint = f"{self.api_url}/datasets"
70
+ params = {"collection": collection}
71
+ if substring:
72
+ params["substring"] = substring
73
+ try:
74
+ response = self.session.get(
75
+ endpoint,
76
+ params=params,
77
+ timeout=self.timeout,
78
+ verify=self.verify
79
+ )
80
+ if not response.ok:
81
+ raise APIError(f"API request failed: {response.status_code} {response.reason}")
82
+ return response.json()
83
+ except requests.RequestException as e:
84
+ raise APIError(f"Request failed: {str(e)}")
85
+
86
+ def create_dataset(self, name: str, collection: str = "terrakio-datasets", **kwargs) -> Dict[str, Any]:
87
+ """
88
+ Create a new dataset.
89
+
90
+ Args:
91
+ name: Name of the dataset (required)
92
+ collection: Dataset collection (default: 'terrakio-datasets')
93
+ **kwargs: Additional dataset parameters including:
94
+ - products: List of products
95
+ - dates_iso8601: List of dates
96
+ - bucket: Storage bucket
97
+ - path: Storage path
98
+ - data_type: Data type
99
+ - no_data: No data value
100
+ - l_max: Maximum level
101
+ - y_size: Y size
102
+ - x_size: X size
103
+ - proj4: Projection string
104
+ - abstract: Dataset abstract
105
+ - geotransform: Geotransform parameters
106
+
107
+ Returns:
108
+ Created dataset information
109
+
110
+ Raises:
111
+ APIError: If the API request fails
112
+ """
113
+ endpoint = f"{self.api_url}/datasets"
114
+ params = {"collection": collection}
115
+ # Create payload with required name parameter
116
+ payload = {"name": name}
117
+
118
+ # Add optional parameters if provided
119
+ for param in ["products", "dates_iso8601", "bucket", "path", "data_type",
120
+ "no_data", "l_max", "y_size", "x_size", "proj4", "abstract", "geotransform"]:
121
+ if param in kwargs:
122
+ payload[param] = kwargs[param]
123
+
124
+ try:
125
+ response = self.session.post(
126
+ endpoint,
127
+ params=params,
128
+ json=payload,
129
+ timeout=self.timeout,
130
+ verify=self.verify
131
+ )
132
+
133
+ if not response.ok:
134
+ raise APIError(f"API request failed: {response.status_code} {response.reason}")
135
+ return response.json()
136
+ except requests.RequestException as e:
137
+ raise APIError(f"Request failed: {str(e)}")
138
+
139
+ def update_dataset(self, name: str, append: bool = True, collection: str = "terrakio-datasets", **kwargs) -> Dict[str, Any]:
140
+ """
141
+ Update a dataset. By default, values are appended unless append is set to False.
142
+
143
+ Args:
144
+ name: Name of the dataset (required)
145
+ append: Whether to append values (default: True)
146
+ collection: Dataset collection (default: 'terrakio-datasets')
147
+ **kwargs: Additional dataset parameters to update
148
+
149
+ Returns:
150
+ Updated dataset information
151
+
152
+ Raises:
153
+ APIError: If the API request fails
154
+ """
155
+ endpoint = f"{self.api_url}/datasets"
156
+ params = {"append": str(append).lower(), "collection": collection}
157
+ payload = {"name": name}
158
+ payload.update(kwargs)
159
+ try:
160
+ response = self.session.patch(
161
+ endpoint,
162
+ params=params,
163
+ json=payload,
164
+ timeout=self.timeout,
165
+ verify=self.verify
166
+ )
167
+ if not response.ok:
168
+ raise APIError(f"API request failed: {response.status_code} {response.reason}")
169
+ return response.json()
170
+ except requests.RequestException as e:
171
+ raise APIError(f"Request failed: {str(e)}")
172
+
173
+ def overwrite_dataset(self, name: str, collection: str = "terrakio-datasets", **kwargs) -> Dict[str, Any]:
174
+ """
175
+ Overwrite a dataset (replace all values).
176
+
177
+ Args:
178
+ name: Name of the dataset (required)
179
+ collection: Dataset collection (default: 'terrakio-datasets')
180
+ **kwargs: New dataset parameters
181
+
182
+ Returns:
183
+ Updated dataset information
184
+
185
+ Raises:
186
+ APIError: If the API request fails
187
+ """
188
+ endpoint = f"{self.api_url}/datasets"
189
+ params = {"collection": collection}
190
+ payload = {"name": name}
191
+ payload.update(kwargs)
192
+ try:
193
+ response = self.session.put(
194
+ endpoint,
195
+ params=params,
196
+ json=payload,
197
+ timeout=self.timeout,
198
+ verify=self.verify
199
+ )
200
+ if not response.ok:
201
+ raise APIError(f"API request failed: {response.status_code} {response.reason}")
202
+ return response.json()
203
+ except requests.RequestException as e:
204
+ raise APIError(f"Request failed: {str(e)}")
205
+
206
+ def delete_dataset(self, name: str, collection: str = "terrakio-datasets") -> Dict[str, Any]:
207
+ """
208
+ Delete a dataset by name.
209
+
210
+ Args:
211
+ name: The name of the dataset (required)
212
+ collection: Dataset collection (default: 'terrakio-datasets')
213
+
214
+ Returns:
215
+ API response as a dictionary
216
+
217
+ Raises:
218
+ APIError: If the API request fails
219
+ """
220
+ endpoint = f"{self.api_url}/datasets/{name}"
221
+ params = {"collection": collection}
222
+ try:
223
+ response = self.session.delete(
224
+ endpoint,
225
+ params=params,
226
+ timeout=self.timeout,
227
+ verify=self.verify
228
+ )
229
+ if response.status_code == 404:
230
+ return {"status": "error", "message": f"Dataset '{name}' does not exist in collection '{collection}'"}
231
+ if not response.ok:
232
+ raise APIError(f"API request failed: {response.status_code} {response.reason}")
233
+ return response.json()
234
+ except requests.RequestException as e:
235
+ raise APIError(f"Request failed: {str(e)}")
@@ -0,0 +1,18 @@
1
+ class APIError(Exception):
2
+ """Exception raised for errors in the API responses."""
3
+ pass
4
+
5
+
6
+ class ConfigurationError(Exception):
7
+ """Exception raised for errors in the configuration."""
8
+ pass
9
+
10
+
11
+ class DownloadError(Exception):
12
+ """Exception raised for errors during data download."""
13
+ pass
14
+
15
+
16
+ class ValidationError(Exception):
17
+ """Exception raised for invalid request parameters."""
18
+ pass
@@ -0,0 +1,232 @@
1
+ import requests
2
+ from typing import Dict, Any, List
3
+ from .exceptions import APIError
4
+
5
+ class GroupAccessManagement:
6
+ def __init__(self, api_url: str, api_key: str, verify: bool = True, timeout: int = 60):
7
+ """
8
+ Initialize the Group Access Management client.
9
+
10
+ Args:
11
+ api_url: API base URL
12
+ api_key: API key for authentication
13
+ verify: Verify SSL certificates
14
+ timeout: Request timeout in seconds
15
+ """
16
+ self.api_url = api_url.rstrip('/')
17
+ self.api_key = api_key
18
+ self.verify = verify
19
+ self.timeout = timeout
20
+ self.session = requests.Session()
21
+ self.session.headers.update({
22
+ 'x-api-key': self.api_key,
23
+ 'Content-Type': 'application/json'
24
+ })
25
+
26
+ def get_group_users_and_datasets(self, group_name: str) -> Dict[str, Any]:
27
+ """
28
+ Get users and datasets of a group.
29
+
30
+ Args:
31
+ group_name: Name of the group
32
+
33
+ Returns:
34
+ Dictionary containing lists of users and datasets associated with the group
35
+ {
36
+ "users": [UID, ...],
37
+ "datasets": [DATASET_NAME, ...]
38
+ }
39
+
40
+ Raises:
41
+ APIError: If the API request fails
42
+ """
43
+ endpoint = f"https://dev-au.terrak.io/groups/{group_name}"
44
+ print("the endpoint is ", endpoint)
45
+ print
46
+ try:
47
+ response = self.session.get(
48
+ endpoint,
49
+ timeout=self.timeout,
50
+ verify=self.verify
51
+ )
52
+ print("the response is ", response.text)
53
+ if not response.ok:
54
+ error_msg = f"API request failed: {response.status_code} {response.reason}"
55
+ try:
56
+ error_data = response.json()
57
+ if "detail" in error_data:
58
+ error_msg += f" - {error_data['detail']}"
59
+ except:
60
+ pass
61
+ raise APIError(error_msg)
62
+
63
+ return response.json()
64
+
65
+ except requests.RequestException as e:
66
+ raise APIError(f"Request failed: {str(e)}")
67
+
68
+ def add_group_to_dataset(self, dataset: str, group: str) -> Dict[str, Any]:
69
+ """
70
+ Add a group to a dataset.
71
+
72
+ Args:
73
+ dataset: Name of the dataset
74
+ group: Name of the group to add to the dataset
75
+
76
+ Returns:
77
+ API response data
78
+
79
+ Raises:
80
+ APIError: If the API request fails
81
+ """
82
+ endpoint = f"{self.api_url}/groups/dataset/{dataset}"
83
+ print("hello")
84
+ print("the endpoint is ", endpoint)
85
+ params = {"group": group}
86
+ print("the endpoint is ", endpoint)
87
+ print("!!!!!!!!!!!")
88
+ print("the params are ", params)
89
+ try:
90
+ response = self.session.post(
91
+ endpoint,
92
+ params=params,
93
+ timeout=self.timeout,
94
+ verify=self.verify
95
+ )
96
+
97
+ if not response.ok:
98
+ error_msg = f"API request failed: {response.status_code} {response.reason}"
99
+ try:
100
+ error_data = response.json()
101
+ if "detail" in error_data:
102
+ error_msg += f" - {error_data['detail']}"
103
+ except:
104
+ pass
105
+ raise APIError(error_msg)
106
+
107
+ return response.json()
108
+
109
+ except requests.RequestException as e:
110
+ raise APIError(f"Request failed: {str(e)}")
111
+
112
+ def add_group_to_user(self, uid: str, group: str) -> Dict[str, Any]:
113
+ """
114
+ Add a group to a user.
115
+
116
+ Args:
117
+ uid: User UID
118
+ group: Name of the group to add to the user
119
+
120
+ Returns:
121
+ API response data
122
+
123
+ Raises:
124
+ APIError: If the API request fails
125
+ """
126
+ endpoint = f"{self.api_url}/groups/users/{uid}"
127
+ params = {"group": group}
128
+ print("the endpoint is ", endpoint)
129
+ print("the params are ", params)
130
+ try:
131
+ response = self.session.post(
132
+ endpoint,
133
+ params=params,
134
+ timeout=self.timeout,
135
+ verify=self.verify
136
+ )
137
+
138
+ if not response.ok:
139
+ error_msg = f"API request failed: {response.status_code} {response.reason}"
140
+ try:
141
+ error_data = response.json()
142
+ if "detail" in error_data:
143
+ error_msg += f" - {error_data['detail']}"
144
+ except:
145
+ pass
146
+ raise APIError(error_msg)
147
+
148
+ return response.json()
149
+
150
+ except requests.RequestException as e:
151
+ raise APIError(f"Request failed: {str(e)}")
152
+
153
+ def delete_group_from_user(self, uid: str, group: str) -> Dict[str, Any]:
154
+ """
155
+ Delete a group from a user.
156
+
157
+ Args:
158
+ uid: User UID
159
+ group: Name of the group to remove from the user
160
+
161
+ Returns:
162
+ API response data
163
+
164
+ Raises:
165
+ APIError: If the API request fails
166
+ """
167
+ endpoint = f"{self.api_url}/groups/users/{uid}"
168
+ params = {"group": group}
169
+
170
+ try:
171
+ response = self.session.delete(
172
+ endpoint,
173
+ params=params,
174
+ timeout=self.timeout,
175
+ verify=self.verify
176
+ )
177
+
178
+ if not response.ok:
179
+ error_msg = f"API request failed: {response.status_code} {response.reason}"
180
+ try:
181
+ error_data = response.json()
182
+ if "detail" in error_data:
183
+ error_msg += f" - {error_data['detail']}"
184
+ except:
185
+ pass
186
+ raise APIError(error_msg)
187
+
188
+ return response.json()
189
+
190
+ except requests.RequestException as e:
191
+ raise APIError(f"Request failed: {str(e)}")
192
+
193
+ def delete_group_from_dataset(self, dataset: str, group: str) -> Dict[str, Any]:
194
+ """
195
+ Delete a group from a dataset.
196
+
197
+ Args:
198
+ dataset: Name of the dataset
199
+ group: Name of the group to remove from the dataset
200
+
201
+ Returns:
202
+ API response data
203
+
204
+ Raises:
205
+ APIError: If the API request fails
206
+ """
207
+ endpoint = f"{self.api_url}/groups/datasets/{dataset}"
208
+ params = {"group": group}
209
+
210
+ try:
211
+ response = self.session.delete(
212
+ endpoint,
213
+ params=params,
214
+ timeout=self.timeout,
215
+ verify=self.verify
216
+ )
217
+
218
+ if not response.ok:
219
+ error_msg = f"API request failed: {response.status_code} {response.reason}"
220
+ try:
221
+ error_data = response.json()
222
+ if "detail" in error_data:
223
+ error_msg += f" - {error_data['detail']}"
224
+ except:
225
+ pass
226
+ raise APIError(error_msg)
227
+
228
+ return response.json()
229
+
230
+ except requests.RequestException as e:
231
+ raise APIError(f"Request failed: {str(e)}")
232
+