terrakio-core 0.3.4__tar.gz → 0.3.6__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.
Potentially problematic release.
This version of terrakio-core might be problematic. Click here for more details.
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/PKG-INFO +1 -1
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/pyproject.toml +1 -1
- terrakio_core-0.3.6/terrakio_core/__init__.py +16 -0
- terrakio_core-0.3.6/terrakio_core/async_client.py +304 -0
- terrakio_core-0.3.6/terrakio_core/client.py +36 -0
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/terrakio_core/config.py +8 -15
- terrakio_core-0.3.6/terrakio_core/convenience_functions/convenience_functions.py +296 -0
- terrakio_core-0.3.6/terrakio_core/endpoints/auth.py +180 -0
- terrakio_core-0.3.6/terrakio_core/endpoints/dataset_management.py +369 -0
- terrakio_core-0.3.6/terrakio_core/endpoints/group_management.py +228 -0
- terrakio_core-0.3.6/terrakio_core/endpoints/mass_stats.py +594 -0
- terrakio_core-0.3.6/terrakio_core/endpoints/model_management.py +385 -0
- terrakio_core-0.3.6/terrakio_core/endpoints/space_management.py +72 -0
- terrakio_core-0.3.6/terrakio_core/endpoints/user_management.py +131 -0
- terrakio_core-0.3.6/terrakio_core/helper/bounded_taskgroup.py +20 -0
- terrakio_core-0.3.6/terrakio_core/helper/decorators.py +58 -0
- {terrakio_core-0.3.4/terrakio_core/generation → terrakio_core-0.3.6/terrakio_core/helper}/tiles.py +1 -12
- terrakio_core-0.3.6/terrakio_core/sync_client.py +370 -0
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/terrakio_core.egg-info/PKG-INFO +1 -1
- terrakio_core-0.3.6/terrakio_core.egg-info/SOURCES.txt +24 -0
- terrakio_core-0.3.4/terrakio_core/__init__.py +0 -7
- terrakio_core-0.3.4/terrakio_core/auth.py +0 -223
- terrakio_core-0.3.4/terrakio_core/client.py +0 -1727
- terrakio_core-0.3.4/terrakio_core/dataset_management.py +0 -287
- terrakio_core-0.3.4/terrakio_core/decorators.py +0 -18
- terrakio_core-0.3.4/terrakio_core/group_access_management.py +0 -232
- terrakio_core-0.3.4/terrakio_core/mass_stats.py +0 -504
- terrakio_core-0.3.4/terrakio_core/space_management.py +0 -101
- terrakio_core-0.3.4/terrakio_core/user_management.py +0 -227
- terrakio_core-0.3.4/terrakio_core.egg-info/SOURCES.txt +0 -19
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/README.md +0 -0
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/setup.cfg +0 -0
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/terrakio_core/exceptions.py +0 -0
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/terrakio_core.egg-info/dependency_links.txt +0 -0
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/terrakio_core.egg-info/requires.txt +0 -0
- {terrakio_core-0.3.4 → terrakio_core-0.3.6}/terrakio_core.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# terrakio_core/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
Terrakio Core
|
|
4
|
+
|
|
5
|
+
Core components for Terrakio API clients.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.3.4"
|
|
9
|
+
|
|
10
|
+
from .async_client import AsyncClient
|
|
11
|
+
from .sync_client import SyncClient
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"AsyncClient",
|
|
15
|
+
"SyncClient"
|
|
16
|
+
]
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import aiohttp
|
|
2
|
+
import asyncio
|
|
3
|
+
import json
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import xarray as xr
|
|
6
|
+
from io import BytesIO
|
|
7
|
+
from typing import Optional, Dict, Any, Union
|
|
8
|
+
from geopandas import GeoDataFrame
|
|
9
|
+
from shapely.geometry.base import BaseGeometry as ShapelyGeometry
|
|
10
|
+
from shapely.geometry import mapping
|
|
11
|
+
from .client import BaseClient
|
|
12
|
+
from .exceptions import APIError
|
|
13
|
+
from .endpoints.dataset_management import DatasetManagement
|
|
14
|
+
from .endpoints.user_management import UserManagement
|
|
15
|
+
from .endpoints.mass_stats import MassStats
|
|
16
|
+
from .endpoints.group_management import GroupManagement
|
|
17
|
+
from .endpoints.space_management import SpaceManagement
|
|
18
|
+
from .endpoints.model_management import ModelManagement
|
|
19
|
+
from .endpoints.auth import AuthClient
|
|
20
|
+
from .convenience_functions.convenience_functions import zonal_stats as _zonal_stats, create_dataset_file as _create_dataset_file
|
|
21
|
+
|
|
22
|
+
class AsyncClient(BaseClient):
|
|
23
|
+
def __init__(self, url: Optional[str] = None, api_key: Optional[str] = None, verbose: bool = False, session: Optional[aiohttp.ClientSession] = None):
|
|
24
|
+
super().__init__(url, api_key, verbose)
|
|
25
|
+
self.datasets = DatasetManagement(self)
|
|
26
|
+
self.users = UserManagement(self)
|
|
27
|
+
self.mass_stats = MassStats(self)
|
|
28
|
+
self.groups = GroupManagement(self)
|
|
29
|
+
self.space = SpaceManagement(self)
|
|
30
|
+
self.model = ModelManagement(self)
|
|
31
|
+
self.auth = AuthClient(self)
|
|
32
|
+
self._session = session
|
|
33
|
+
self._owns_session = session is None
|
|
34
|
+
|
|
35
|
+
async def _terrakio_request(self, method: str, endpoint: str, **kwargs):
|
|
36
|
+
# if self.session is None:
|
|
37
|
+
if self.session is None:
|
|
38
|
+
headers = {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
'x-api-key': self.key,
|
|
41
|
+
'Authorization': self.token
|
|
42
|
+
}
|
|
43
|
+
clean_headers = {k: v for k, v in headers.items() if v is not None}
|
|
44
|
+
async with aiohttp.ClientSession(headers=clean_headers, timeout=aiohttp.ClientTimeout(total=self.timeout)) as session:
|
|
45
|
+
return await self._make_request_with_retry(session, method, endpoint, **kwargs)
|
|
46
|
+
else:
|
|
47
|
+
return await self._make_request_with_retry(self._session, method, endpoint, **kwargs)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def _make_request_with_retry(self, session: aiohttp.ClientSession, method: str, endpoint: str, **kwargs) -> Dict[Any, Any]:
|
|
51
|
+
url = f"{self.url}/{endpoint.lstrip('/')}"
|
|
52
|
+
for attempt in range(self.retry + 1):
|
|
53
|
+
try:
|
|
54
|
+
async with session.request(method, url, **kwargs) as response:
|
|
55
|
+
response_text = await response.text()
|
|
56
|
+
if not response.ok:
|
|
57
|
+
should_retry = False
|
|
58
|
+
|
|
59
|
+
if response.status == 400:
|
|
60
|
+
should_retry = False
|
|
61
|
+
else:
|
|
62
|
+
if response.status in [408, 502, 503, 504]:
|
|
63
|
+
should_retry = True
|
|
64
|
+
elif response.status == 500:
|
|
65
|
+
try:
|
|
66
|
+
response_text = await response.text()
|
|
67
|
+
if "Internal server error" not in response_text:
|
|
68
|
+
should_retry = True
|
|
69
|
+
except:
|
|
70
|
+
should_retry = True
|
|
71
|
+
|
|
72
|
+
if should_retry and attempt < self.retry:
|
|
73
|
+
self.logger.info(f"Request failed (attempt {attempt+1}/{self.retry+1}): {response.status} {response.reason}. Retrying...")
|
|
74
|
+
continue
|
|
75
|
+
else:
|
|
76
|
+
error_msg = f"API request failed: {response.status} {response.reason}"
|
|
77
|
+
try:
|
|
78
|
+
error_data = await response.json()
|
|
79
|
+
if "detail" in error_data:
|
|
80
|
+
error_msg += f" - {error_data['detail']}"
|
|
81
|
+
except:
|
|
82
|
+
pass
|
|
83
|
+
raise APIError(error_msg, status_code=response.status)
|
|
84
|
+
|
|
85
|
+
content_type = response.headers.get('content-type', '').lower()
|
|
86
|
+
content = await response.read()
|
|
87
|
+
if 'json' in content_type:
|
|
88
|
+
return json.loads(content.decode('utf-8'))
|
|
89
|
+
elif 'csv' in content_type:
|
|
90
|
+
return pd.read_csv(BytesIO(content))
|
|
91
|
+
elif 'image/' in content_type:
|
|
92
|
+
return content
|
|
93
|
+
elif 'text' in content_type:
|
|
94
|
+
return content.decode('utf-8')
|
|
95
|
+
else:
|
|
96
|
+
try:
|
|
97
|
+
return xr.open_dataset(BytesIO(content))
|
|
98
|
+
except:
|
|
99
|
+
raise APIError(f"Unknown response format. Content-Type: {response.headers.get('content-type', 'unknown')}", status_code=response.status)
|
|
100
|
+
except aiohttp.ClientError as e:
|
|
101
|
+
if attempt < self.retry:
|
|
102
|
+
self.logger.info(f"Request failed (attempt {attempt+1}/{self.retry+1}): {e}. Retrying...")
|
|
103
|
+
continue
|
|
104
|
+
else:
|
|
105
|
+
raise APIError(f"Request failed after {self.retry+1} attempts: {e}", status_code=None)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
async def _regular_request(self, method: str, endpoint: str, **kwargs):
|
|
109
|
+
url = endpoint.lstrip('/')
|
|
110
|
+
if self._session is None:
|
|
111
|
+
|
|
112
|
+
async with aiohttp.ClientSession() as session:
|
|
113
|
+
try:
|
|
114
|
+
async with session.request(method, url, **kwargs) as response:
|
|
115
|
+
response.raise_for_status()
|
|
116
|
+
return response
|
|
117
|
+
except aiohttp.ClientError as e:
|
|
118
|
+
raise APIError(f"Request failed: {e}")
|
|
119
|
+
else:
|
|
120
|
+
# this means that we used the with statement, and we already have a session
|
|
121
|
+
try:
|
|
122
|
+
async with self._session.request(method, url, **kwargs) as response:
|
|
123
|
+
response.raise_for_status()
|
|
124
|
+
return response
|
|
125
|
+
except aiohttp.ClientError as e:
|
|
126
|
+
raise APIError(f"Request failed: {e}")
|
|
127
|
+
|
|
128
|
+
async def geoquery(
|
|
129
|
+
self,
|
|
130
|
+
expr: str,
|
|
131
|
+
feature: Union[Dict[str, Any], ShapelyGeometry],
|
|
132
|
+
in_crs: str = "epsg:4326",
|
|
133
|
+
out_crs: str = "epsg:4326",
|
|
134
|
+
output: str = "csv",
|
|
135
|
+
resolution: int = -1,
|
|
136
|
+
geom_fix: bool = False,
|
|
137
|
+
**kwargs
|
|
138
|
+
):
|
|
139
|
+
"""
|
|
140
|
+
Compute WCS query for a single geometry.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
expr (str): The WCS expression to evaluate
|
|
144
|
+
feature (Union[Dict[str, Any], ShapelyGeometry]): The geographic feature
|
|
145
|
+
in_crs (str): Input coordinate reference system
|
|
146
|
+
out_crs (str): Output coordinate reference system
|
|
147
|
+
output (str): Output format ('csv' or 'netcdf')
|
|
148
|
+
resolution (int): Resolution parameter
|
|
149
|
+
geom_fix (bool): Whether to fix the geometry (default False)
|
|
150
|
+
**kwargs: Additional parameters to pass to the WCS request
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
Union[pd.DataFrame, xr.Dataset, bytes]: The response data in the requested format
|
|
154
|
+
|
|
155
|
+
Raises:
|
|
156
|
+
APIError: If the API request fails
|
|
157
|
+
"""
|
|
158
|
+
if hasattr(feature, 'is_valid'):
|
|
159
|
+
feature = {
|
|
160
|
+
"type": "Feature",
|
|
161
|
+
"geometry": mapping(feature),
|
|
162
|
+
"properties": {}
|
|
163
|
+
}
|
|
164
|
+
payload = {
|
|
165
|
+
"feature": feature,
|
|
166
|
+
"in_crs": in_crs,
|
|
167
|
+
"out_crs": out_crs,
|
|
168
|
+
"output": output,
|
|
169
|
+
"resolution": resolution,
|
|
170
|
+
"expr": expr,
|
|
171
|
+
"buffer": geom_fix,
|
|
172
|
+
**kwargs
|
|
173
|
+
}
|
|
174
|
+
return await self._terrakio_request("POST", "geoquery", json=payload)
|
|
175
|
+
|
|
176
|
+
async def zonal_stats(
|
|
177
|
+
self,
|
|
178
|
+
gdf: GeoDataFrame,
|
|
179
|
+
expr: str,
|
|
180
|
+
conc: int = 20,
|
|
181
|
+
inplace: bool = False,
|
|
182
|
+
in_crs: str = "epsg:4326",
|
|
183
|
+
out_crs: str = "epsg:4326",
|
|
184
|
+
resolution: int = -1,
|
|
185
|
+
geom_fix: bool = False,
|
|
186
|
+
):
|
|
187
|
+
"""
|
|
188
|
+
Compute zonal statistics for all geometries in a GeoDataFrame.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
gdf (GeoDataFrame): GeoDataFrame containing geometries
|
|
192
|
+
expr (str): Terrakio expression to evaluate, can include spatial aggregations
|
|
193
|
+
conc (int): Number of concurrent requests to make
|
|
194
|
+
inplace (bool): Whether to modify the input GeoDataFrame in place
|
|
195
|
+
in_crs (str): Input coordinate reference system
|
|
196
|
+
out_crs (str): Output coordinate reference system
|
|
197
|
+
resolution (int): Resolution parameter
|
|
198
|
+
geom_fix (bool): Whether to fix the geometry (default False)
|
|
199
|
+
Returns:
|
|
200
|
+
geopandas.GeoDataFrame: GeoDataFrame with added columns for results, or None if inplace=True
|
|
201
|
+
|
|
202
|
+
Raises:
|
|
203
|
+
ValueError: If concurrency is too high
|
|
204
|
+
APIError: If the API request fails
|
|
205
|
+
"""
|
|
206
|
+
return await _zonal_stats(
|
|
207
|
+
client=self,
|
|
208
|
+
gdf=gdf,
|
|
209
|
+
expr=expr,
|
|
210
|
+
conc=conc,
|
|
211
|
+
inplace=inplace,
|
|
212
|
+
in_crs=in_crs,
|
|
213
|
+
out_crs=out_crs,
|
|
214
|
+
resolution=resolution,
|
|
215
|
+
geom_fix=geom_fix
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
async def create_dataset_file(
|
|
219
|
+
self,
|
|
220
|
+
aoi: str,
|
|
221
|
+
expression: str,
|
|
222
|
+
output: str,
|
|
223
|
+
in_crs: str = "epsg:4326",
|
|
224
|
+
res: float = 0.0001,
|
|
225
|
+
region: str = "aus",
|
|
226
|
+
to_crs: str = "epsg:4326",
|
|
227
|
+
overwrite: bool = True,
|
|
228
|
+
skip_existing: bool = False,
|
|
229
|
+
non_interactive: bool = True,
|
|
230
|
+
poll_interval: int = 30,
|
|
231
|
+
download_path: str = "/home/user/Downloads",
|
|
232
|
+
) -> dict:
|
|
233
|
+
"""
|
|
234
|
+
Create a dataset file using mass stats operations.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
aoi (str): Area of interest
|
|
238
|
+
expression (str): Terrakio expression to evaluate
|
|
239
|
+
output (str): Output format
|
|
240
|
+
in_crs (str): Input coordinate reference system (default "epsg:4326")
|
|
241
|
+
res (float): Resolution (default 0.0001)
|
|
242
|
+
region (str): Region (default "aus")
|
|
243
|
+
to_crs (str): Target coordinate reference system (default "epsg:4326")
|
|
244
|
+
overwrite (bool): Whether to overwrite existing files (default True)
|
|
245
|
+
skip_existing (bool): Whether to skip existing files (default False)
|
|
246
|
+
non_interactive (bool): Whether to run non-interactively (default True)
|
|
247
|
+
poll_interval (int): Polling interval in seconds (default 30)
|
|
248
|
+
download_path (str): Download path (default "/home/user/Downloads")
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
dict: Dictionary containing generation_task_id and combine_task_id
|
|
252
|
+
|
|
253
|
+
Raises:
|
|
254
|
+
ConfigurationError: If mass stats client is not properly configured
|
|
255
|
+
RuntimeError: If job fails
|
|
256
|
+
"""
|
|
257
|
+
return await _create_dataset_file(
|
|
258
|
+
client=self,
|
|
259
|
+
aoi=aoi,
|
|
260
|
+
expression=expression,
|
|
261
|
+
output=output,
|
|
262
|
+
in_crs=in_crs,
|
|
263
|
+
res=res,
|
|
264
|
+
region=region,
|
|
265
|
+
to_crs=to_crs,
|
|
266
|
+
overwrite=overwrite,
|
|
267
|
+
skip_existing=skip_existing,
|
|
268
|
+
non_interactive=non_interactive,
|
|
269
|
+
poll_interval=poll_interval,
|
|
270
|
+
download_path=download_path,
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
async def __aenter__(self):
|
|
274
|
+
# if there is no session, we create a session
|
|
275
|
+
if self._session is None:
|
|
276
|
+
headers = {
|
|
277
|
+
'Content-Type': 'application/json',
|
|
278
|
+
'x-api-key': self.key,
|
|
279
|
+
'Authorization': self.token
|
|
280
|
+
}
|
|
281
|
+
# Remove None values from headers
|
|
282
|
+
clean_headers = {k: v for k, v in headers.items() if v is not None}
|
|
283
|
+
# we are creating the header and clean any value that is none
|
|
284
|
+
# now we create the session
|
|
285
|
+
self._session = aiohttp.ClientSession(
|
|
286
|
+
headers=clean_headers,
|
|
287
|
+
timeout=aiohttp.ClientTimeout(total=self.timeout)
|
|
288
|
+
)
|
|
289
|
+
return self
|
|
290
|
+
# if there is no session, we create a session
|
|
291
|
+
|
|
292
|
+
# now lets create the aexit function, this function is used when a user uses with, and this function will be automatically called when the with statement is done
|
|
293
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
294
|
+
# so if the session is not being passed in, and we created it by ourselves, we are responsible for closing the session
|
|
295
|
+
# if the session is being passed in, we are not responsible for closing the session
|
|
296
|
+
if self._owns_session and self._session:
|
|
297
|
+
await self._session.close()
|
|
298
|
+
self._session = None
|
|
299
|
+
# we close the session and set the session value to none
|
|
300
|
+
|
|
301
|
+
async def close(self):
|
|
302
|
+
if self._owns_session and self._session:
|
|
303
|
+
await self._session.close()
|
|
304
|
+
self._session = None
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
import logging
|
|
3
|
+
from terrakio_core.config import read_config_file, DEFAULT_CONFIG_FILE
|
|
4
|
+
from abc import abstractmethod
|
|
5
|
+
|
|
6
|
+
class BaseClient():
|
|
7
|
+
def __init__(self, url: Optional[str] = None, api_key: Optional[str] = None, verbose: bool = False):
|
|
8
|
+
|
|
9
|
+
self.verbose = verbose
|
|
10
|
+
self.logger = logging.getLogger("terrakio")
|
|
11
|
+
if verbose:
|
|
12
|
+
self.logger.setLevel(logging.INFO)
|
|
13
|
+
else:
|
|
14
|
+
self.logger.setLevel(logging.WARNING)
|
|
15
|
+
|
|
16
|
+
self.timeout = 300
|
|
17
|
+
self.retry = 3
|
|
18
|
+
|
|
19
|
+
self.session = None
|
|
20
|
+
|
|
21
|
+
self.url = url
|
|
22
|
+
self.key = api_key
|
|
23
|
+
|
|
24
|
+
config = read_config_file( DEFAULT_CONFIG_FILE, logger = self.logger)
|
|
25
|
+
if self.url is None:
|
|
26
|
+
self.url = config.get('url')
|
|
27
|
+
|
|
28
|
+
self.key = config.get('key')
|
|
29
|
+
|
|
30
|
+
self.token = config.get('token')
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def _setup_session(self):
|
|
35
|
+
"""Initialize the HTTP session - implemented by sync/async clients"""
|
|
36
|
+
pass
|
|
@@ -2,21 +2,20 @@ import os
|
|
|
2
2
|
import json
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Dict, Any, Optional
|
|
5
|
-
|
|
5
|
+
import logging
|
|
6
6
|
from .exceptions import ConfigurationError
|
|
7
7
|
|
|
8
8
|
# Default configuration file locations
|
|
9
9
|
DEFAULT_CONFIG_FILE = os.path.join(os.environ.get("HOME", ""), ".tkio_config.json")
|
|
10
10
|
DEFAULT_API_URL = "https://api.terrak.io"
|
|
11
11
|
|
|
12
|
-
def read_config_file(config_file: str = DEFAULT_CONFIG_FILE,
|
|
12
|
+
def read_config_file(config_file: str = DEFAULT_CONFIG_FILE, logger: logging.Logger = None) -> Dict[str, Any]:
|
|
13
13
|
"""
|
|
14
14
|
Read and parse the configuration file.
|
|
15
15
|
|
|
16
16
|
Args:
|
|
17
17
|
config_file: Path to the configuration file
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
logger: Logger object to log messages
|
|
20
19
|
Returns:
|
|
21
20
|
Dict[str, Any]: Configuration parameters with additional flags:
|
|
22
21
|
'is_logged_in': True if user is logged in
|
|
@@ -36,8 +35,7 @@ def read_config_file(config_file: str = DEFAULT_CONFIG_FILE, quiet: bool = False
|
|
|
36
35
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
37
36
|
with open(config_path, 'w') as f:
|
|
38
37
|
json.dump({}, f)
|
|
39
|
-
|
|
40
|
-
print("No API key found. Please provide an API key to use this client.")
|
|
38
|
+
logger.info("No API key found. Please provide an API key to use this client.")
|
|
41
39
|
return {
|
|
42
40
|
'url': DEFAULT_API_URL,
|
|
43
41
|
'key': None,
|
|
@@ -54,8 +52,7 @@ def read_config_file(config_file: str = DEFAULT_CONFIG_FILE, quiet: bool = False
|
|
|
54
52
|
# Read the config file data
|
|
55
53
|
# Check if config has an API key
|
|
56
54
|
if not config_data or 'TERRAKIO_API_KEY' not in config_data or not config_data.get('TERRAKIO_API_KEY'):
|
|
57
|
-
|
|
58
|
-
print("No API key found. Please provide an API key to use this client.")
|
|
55
|
+
logger.info("No API key found. Please provide an API key to use this client.")
|
|
59
56
|
return {
|
|
60
57
|
'url': DEFAULT_API_URL,
|
|
61
58
|
'key': None,
|
|
@@ -63,10 +60,7 @@ def read_config_file(config_file: str = DEFAULT_CONFIG_FILE, quiet: bool = False
|
|
|
63
60
|
'user_email': None,
|
|
64
61
|
'token': config_data.get('PERSONAL_TOKEN')
|
|
65
62
|
}
|
|
66
|
-
|
|
67
|
-
# If we have config values, use them
|
|
68
|
-
if not quiet:
|
|
69
|
-
print(f"Currently logged in as: {config_data.get('EMAIL')}")
|
|
63
|
+
logger.info(f"Currently logged in as: {config_data.get('EMAIL')}")
|
|
70
64
|
# this meanb that we have already logged in to the tkio account
|
|
71
65
|
|
|
72
66
|
# Convert the JSON config to our expected format
|
|
@@ -82,9 +76,8 @@ def read_config_file(config_file: str = DEFAULT_CONFIG_FILE, quiet: bool = False
|
|
|
82
76
|
|
|
83
77
|
|
|
84
78
|
except Exception as e:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
print("No API key found. Please provide an API key to use this client.")
|
|
79
|
+
logger.info(f"Error reading config: {e}")
|
|
80
|
+
logger.info("No API key found. Please provide an API key to use this client.")
|
|
88
81
|
return {
|
|
89
82
|
'url': DEFAULT_API_URL,
|
|
90
83
|
'key': None,
|