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

@@ -1,6 +1,346 @@
1
+ # import asyncio
2
+ # import concurrent.futures
3
+ # import threading
4
+ # import functools
5
+ # import inspect
6
+ # from typing import Optional, Dict, Any, Union
7
+ # from geopandas import GeoDataFrame
8
+ # from shapely.geometry.base import BaseGeometry as ShapelyGeometry
9
+ # from .async_client import AsyncClient
10
+ # from typing import TYPE_CHECKING
11
+
12
+ # # # Add this after your other imports
13
+ # # if TYPE_CHECKING:
14
+ # # from .endpoints.dataset_management import DatasetManagement
15
+ # # from .endpoints.user_management import UserManagement
16
+ # # from .endpoints.mass_stats import MassStats
17
+ # # from .endpoints.group_management import GroupManagement
18
+ # # from .endpoints.space_management import SpaceManagement
19
+ # # from .endpoints.model_management import ModelManagement
20
+ # # from .endpoints.auth import AuthClient
21
+
22
+
23
+ # class SyncWrapper:
24
+ # """Generic synchronous wrapper with __dir__ support for runtime autocomplete."""
25
+
26
+ # def __init__(self, async_obj, sync_client):
27
+ # self._async_obj = async_obj
28
+ # self._sync_client = sync_client
29
+
30
+ # def __dir__(self):
31
+ # """Return list of attributes for autocomplete in interactive environments."""
32
+ # async_attrs = [attr for attr in dir(self._async_obj) if not attr.startswith('_')]
33
+ # wrapper_attrs = [attr for attr in object.__dir__(self) if not attr.startswith('_')]
34
+ # return list(set(async_attrs + wrapper_attrs))
35
+
36
+ # def __getattr__(self, name):
37
+ # """Dynamically wrap any method call to convert async to sync."""
38
+ # attr = getattr(self._async_obj, name)
39
+
40
+ # if callable(attr):
41
+ # @functools.wraps(attr)
42
+ # def sync_wrapper(*args, **kwargs):
43
+ # result = attr(*args, **kwargs)
44
+ # if hasattr(result, '__await__'):
45
+ # return self._sync_client._run_async(result)
46
+ # return result
47
+ # return sync_wrapper
48
+
49
+ # return attr
50
+
51
+
52
+ # class SyncClient:
53
+ # """
54
+ # Thread-safe synchronous wrapper for AsyncClient.
55
+ # Uses a persistent event loop in a dedicated thread to avoid event loop conflicts.
56
+ # """
57
+
58
+ # # datasets: 'DatasetManagement'
59
+ # # users: 'UserManagement'
60
+ # # mass_stats: 'MassStats'
61
+ # # groups: 'GroupManagement'
62
+ # # space: 'SpaceManagement'
63
+ # # model: 'ModelManagement'
64
+ # # auth: 'AuthClient'
65
+
66
+ # def __init__(self, url: Optional[str] = None, api_key: Optional[str] = None, verbose: bool = False):
67
+ # self._async_client = AsyncClient(url=url, api_key=api_key, verbose=verbose)
68
+ # self._context_entered = False
69
+ # self._closed = False
70
+
71
+ # # Thread and event loop management
72
+ # self._loop = None
73
+ # self._thread = None
74
+ # self._loop_ready = None
75
+ # self._loop_exception = None
76
+
77
+ # # Initialize endpoint managers
78
+ # print("we are here!!!!!!!!!!!!!!!!!")
79
+ # self.datasets = SyncWrapper(self._async_client.datasets, self)
80
+ # self.users = SyncWrapper(self._async_client.users, self)
81
+ # self.mass_stats = SyncWrapper(self._async_client.mass_stats, self)
82
+ # self.groups = SyncWrapper(self._async_client.groups, self)
83
+ # self.space = SyncWrapper(self._async_client.space, self)
84
+ # self.model = SyncWrapper(self._async_client.model, self)
85
+ # self.auth = SyncWrapper(self._async_client.auth, self)
86
+
87
+ # # Register cleanup
88
+ # import atexit
89
+ # atexit.register(self._cleanup)
90
+
91
+ # def _ensure_event_loop(self):
92
+ # """Ensure we have a persistent event loop in a dedicated thread."""
93
+ # if self._loop is None or self._loop.is_closed():
94
+ # self._loop_ready = threading.Event()
95
+ # self._loop_exception = None
96
+
97
+ # def run_loop():
98
+ # """Run the event loop in a dedicated thread."""
99
+ # try:
100
+ # # Create a new event loop for this thread
101
+ # self._loop = asyncio.new_event_loop()
102
+ # asyncio.set_event_loop(self._loop)
103
+
104
+ # # Signal that the loop is ready
105
+ # self._loop_ready.set()
106
+
107
+ # # Run the loop forever (until stopped)
108
+ # self._loop.run_forever()
109
+ # except Exception as e:
110
+ # self._loop_exception = e
111
+ # self._loop_ready.set()
112
+ # finally:
113
+ # # Clean up when the loop stops
114
+ # if self._loop and not self._loop.is_closed():
115
+ # self._loop.close()
116
+
117
+ # # Start the thread
118
+ # self._thread = threading.Thread(target=run_loop, daemon=True)
119
+ # self._thread.start()
120
+
121
+ # # Wait for the loop to be ready
122
+ # self._loop_ready.wait(timeout=10)
123
+
124
+ # if self._loop_exception:
125
+ # raise self._loop_exception
126
+
127
+ # if not self._loop_ready.is_set():
128
+ # raise RuntimeError("Event loop failed to start within timeout")
129
+
130
+ # def _run_async(self, coro):
131
+ # """
132
+ # Run async coroutine using persistent event loop.
133
+ # This is the core method that makes everything work.
134
+ # """
135
+ # # Ensure we have an event loop
136
+ # self._ensure_event_loop()
137
+
138
+ # if self._loop.is_closed():
139
+ # raise RuntimeError("Event loop is closed")
140
+
141
+ # # Create a future to get the result back from the event loop thread
142
+ # future = concurrent.futures.Future()
143
+
144
+ # async def run_with_context():
145
+ # """Run the coroutine with proper context management."""
146
+ # try:
147
+ # # Ensure the async client is properly initialized
148
+ # await self._ensure_context()
149
+
150
+ # # Run the actual coroutine
151
+ # result = await coro
152
+
153
+ # # Set the result on the future
154
+ # future.set_result(result)
155
+ # except Exception as e:
156
+ # # Set the exception on the future
157
+ # future.set_exception(e)
158
+
159
+ # # Schedule the coroutine on the persistent event loop
160
+ # self._loop.call_soon_threadsafe(
161
+ # lambda: asyncio.create_task(run_with_context())
162
+ # )
163
+
164
+ # # Wait for the result (with timeout to avoid hanging)
165
+ # try:
166
+ # return future.result(timeout=300) # 5 minute timeout
167
+ # except concurrent.futures.TimeoutError:
168
+ # raise RuntimeError("Async operation timed out after 5 minutes")
169
+
170
+ # async def _ensure_context(self):
171
+ # """Ensure the async client context is entered."""
172
+ # if not self._context_entered and not self._closed:
173
+ # await self._async_client.__aenter__()
174
+ # self._context_entered = True
175
+
176
+ # async def _exit_context(self):
177
+ # """Exit the async client context."""
178
+ # if self._context_entered and not self._closed:
179
+ # await self._async_client.__aexit__(None, None, None)
180
+ # self._context_entered = False
181
+
182
+ # def close(self):
183
+ # """Close the underlying async client session and stop the event loop."""
184
+ # if not self._closed:
185
+ # if self._loop and not self._loop.is_closed():
186
+ # # Schedule cleanup on the event loop
187
+ # future = concurrent.futures.Future()
188
+
189
+ # async def cleanup():
190
+ # """Clean up the async client."""
191
+ # try:
192
+ # await self._exit_context()
193
+ # future.set_result(None)
194
+ # except Exception as e:
195
+ # future.set_exception(e)
196
+
197
+ # # Run cleanup
198
+ # self._loop.call_soon_threadsafe(
199
+ # lambda: asyncio.create_task(cleanup())
200
+ # )
201
+
202
+ # # Wait for cleanup to complete
203
+ # try:
204
+ # future.result(timeout=10)
205
+ # except:
206
+ # pass # Ignore cleanup errors
207
+
208
+ # # Stop the event loop
209
+ # self._loop.call_soon_threadsafe(self._loop.stop)
210
+
211
+ # # Wait for thread to finish
212
+ # if self._thread and self._thread.is_alive():
213
+ # self._thread.join(timeout=5)
214
+
215
+ # self._closed = True
216
+
217
+ # def _cleanup(self):
218
+ # """Internal cleanup method called by atexit."""
219
+ # if not self._closed:
220
+ # try:
221
+ # self.close()
222
+ # except Exception:
223
+ # pass # Ignore cleanup errors
224
+
225
+ # def __dir__(self):
226
+ # """Return list of attributes for autocomplete in interactive environments."""
227
+ # default_attrs = [attr for attr in object.__dir__(self) if not attr.startswith('_')]
228
+ # async_client_attrs = [attr for attr in dir(self._async_client) if not attr.startswith('_')]
229
+ # endpoint_attrs = ['datasets', 'users', 'mass_stats', 'groups', 'space', 'model', 'auth']
230
+ # all_attrs = default_attrs + async_client_attrs + endpoint_attrs
231
+ # return list(set(all_attrs))
232
+
233
+ # # Your existing methods (geoquery, zonal_stats, etc.)
234
+ # def geoquery(
235
+ # self,
236
+ # expr: str,
237
+ # feature: Union[Dict[str, Any], ShapelyGeometry],
238
+ # in_crs: str = "epsg:4326",
239
+ # out_crs: str = "epsg:4326",
240
+ # resolution: int = -1,
241
+ # geom_fix: bool = False,
242
+ # **kwargs
243
+ # ):
244
+ # """Compute WCS query for a single geometry (synchronous version)."""
245
+ # coro = self._async_client.geoquery(
246
+ # expr=expr,
247
+ # feature=feature,
248
+ # in_crs=in_crs,
249
+ # out_crs=out_crs,
250
+ # output="netcdf",
251
+ # resolution=resolution,
252
+ # geom_fix=geom_fix,
253
+ # **kwargs
254
+ # )
255
+ # return self._run_async(coro)
256
+
257
+ # def zonal_stats(
258
+ # self,
259
+ # gdf: GeoDataFrame,
260
+ # expr: str,
261
+ # conc: int = 20,
262
+ # inplace: bool = False,
263
+ # in_crs: str = "epsg:4326",
264
+ # out_crs: str = "epsg:4326",
265
+ # resolution: int = -1,
266
+ # geom_fix: bool = False,
267
+ # drop_nan: bool = False,
268
+ # spatial_reduction: str = None,
269
+ # temporal_reduction: str = None,
270
+ # max_memory_mb: int = 500,
271
+ # stream_to_disk: bool = False,
272
+ # ):
273
+ # """Compute zonal statistics for all geometries in a GeoDataFrame (synchronous version)."""
274
+ # coro = self._async_client.zonal_stats(
275
+ # gdf=gdf,
276
+ # expr=expr,
277
+ # conc=conc,
278
+ # inplace=inplace,
279
+ # in_crs=in_crs,
280
+ # out_crs=out_crs,
281
+ # resolution=resolution,
282
+ # geom_fix=geom_fix,
283
+ # drop_nan=drop_nan,
284
+ # spatial_reduction=spatial_reduction,
285
+ # temporal_reduction=temporal_reduction,
286
+ # max_memory_mb=max_memory_mb,
287
+ # stream_to_disk=stream_to_disk
288
+ # )
289
+ # return self._run_async(coro)
290
+
291
+ # def create_dataset_file(
292
+ # self,
293
+ # aoi: str,
294
+ # expression: str,
295
+ # output: str,
296
+ # in_crs: str = "epsg:4326",
297
+ # res: float = 0.0001,
298
+ # region: str = "aus",
299
+ # to_crs: str = "epsg:4326",
300
+ # overwrite: bool = True,
301
+ # skip_existing: bool = False,
302
+ # non_interactive: bool = True,
303
+ # poll_interval: int = 30,
304
+ # download_path: str = "/home/user/Downloads",
305
+ # ) -> dict:
306
+ # """Create a dataset file using mass stats operations (synchronous version)."""
307
+ # coro = self._async_client.create_dataset_file(
308
+ # aoi=aoi,
309
+ # expression=expression,
310
+ # output=output,
311
+ # in_crs=in_crs,
312
+ # res=res,
313
+ # region=region,
314
+ # to_crs=to_crs,
315
+ # overwrite=overwrite,
316
+ # skip_existing=skip_existing,
317
+ # non_interactive=non_interactive,
318
+ # poll_interval=poll_interval,
319
+ # download_path=download_path,
320
+ # )
321
+ # return self._run_async(coro)
322
+
323
+ # # Context manager support
324
+ # def __enter__(self):
325
+ # """Context manager entry."""
326
+ # return self
327
+
328
+ # def __exit__(self, exc_type, exc_val, exc_tb):
329
+ # """Context manager exit."""
330
+ # self.close()
331
+
332
+ # def __del__(self):
333
+ # """Destructor to ensure session is closed."""
334
+ # if not self._closed:
335
+ # try:
336
+ # self._cleanup()
337
+ # except Exception:
338
+ # pass
339
+
340
+
1
341
  import asyncio
2
342
  import functools
3
- import inspect
343
+ import concurrent.futures
4
344
  from typing import Optional, Dict, Any, Union
5
345
  from geopandas import GeoDataFrame
6
346
  from shapely.geometry.base import BaseGeometry as ShapelyGeometry
@@ -21,13 +361,10 @@ class SyncWrapper:
21
361
  Return list of attributes for autocomplete in interactive environments.
22
362
  This enables autocomplete in Jupyter/iPython after instantiation.
23
363
  """
24
- # Get all public attributes from the wrapped async object
25
364
  async_attrs = [attr for attr in dir(self._async_obj) if not attr.startswith('_')]
26
365
 
27
- # Get all attributes from this wrapper instance
28
366
  wrapper_attrs = [attr for attr in object.__dir__(self) if not attr.startswith('_')]
29
367
 
30
- # Combine and return unique attributes
31
368
  return list(set(async_attrs + wrapper_attrs))
32
369
 
33
370
  def __getattr__(self, name):
@@ -59,7 +396,6 @@ class SyncClient:
59
396
  self._context_entered = False
60
397
  self._closed = False
61
398
 
62
- # Initialize endpoint managers
63
399
  self.datasets = SyncWrapper(self._async_client.datasets, self)
64
400
  self.users = SyncWrapper(self._async_client.users, self)
65
401
  self.mass_stats = SyncWrapper(self._async_client.mass_stats, self)
@@ -68,7 +404,6 @@ class SyncClient:
68
404
  self.model = SyncWrapper(self._async_client.model, self)
69
405
  self.auth = SyncWrapper(self._async_client.auth, self)
70
406
 
71
- # Register cleanup
72
407
  import atexit
73
408
  atexit.register(self._cleanup)
74
409
 
@@ -77,16 +412,12 @@ class SyncClient:
77
412
  Return list of attributes for autocomplete in interactive environments.
78
413
  This includes all methods from the async client plus the endpoint managers.
79
414
  """
80
- # Get default attributes from this class
81
415
  default_attrs = [attr for attr in object.__dir__(self) if not attr.startswith('_')]
82
416
 
83
- # Get all public methods from the async client
84
417
  async_client_attrs = [attr for attr in dir(self._async_client) if not attr.startswith('_')]
85
418
 
86
- # Add endpoint managers
87
419
  endpoint_attrs = ['datasets', 'users', 'mass_stats', 'groups', 'space', 'model', 'auth']
88
420
 
89
- # Combine all attributes
90
421
  all_attrs = default_attrs + async_client_attrs + endpoint_attrs
91
422
 
92
423
  return list(set(all_attrs))
@@ -119,16 +450,10 @@ class SyncClient:
119
450
  gdf: GeoDataFrame,
120
451
  expr: str,
121
452
  conc: int = 20,
122
- inplace: bool = False,
123
453
  in_crs: str = "epsg:4326",
124
454
  out_crs: str = "epsg:4326",
125
455
  resolution: int = -1,
126
456
  geom_fix: bool = False,
127
- drop_nan: bool = False,
128
- spatial_reduction: str = None,
129
- temporal_reduction: str = None,
130
- max_memory_mb: int = 500,
131
- stream_to_disk: bool = False,
132
457
  ):
133
458
  """
134
459
  Compute zonal statistics for all geometries in a GeoDataFrame (synchronous version).
@@ -137,22 +462,13 @@ class SyncClient:
137
462
  gdf (GeoDataFrame): GeoDataFrame containing geometries
138
463
  expr (str): Terrakio expression to evaluate, can include spatial aggregations
139
464
  conc (int): Number of concurrent requests to make
140
- inplace (bool): Whether to modify the input GeoDataFrame in place
141
465
  in_crs (str): Input coordinate reference system
142
466
  out_crs (str): Output coordinate reference system
143
467
  resolution (int): Resolution parameter
144
468
  geom_fix (bool): Whether to fix the geometry (default False)
145
- drop_nan (bool): Whether to drop NaN values from the results (default False)
146
- spatial_reduction (str): Reduction operation for spatial dimensions (x, y).
147
- Options: 'mean', 'median', 'min', 'max', 'std', 'var', 'sum', 'count'
148
- temporal_reduction (str): Reduction operation for temporal dimension (time).
149
- Options: 'mean', 'median', 'min', 'max', 'std', 'var', 'sum', 'count'
150
- max_memory_mb (int): Maximum memory threshold in MB (default 500MB)
151
- stream_to_disk (bool): Whether to stream datasets to disk as NetCDF files (default False)
152
469
 
153
470
  Returns:
154
- geopandas.GeoDataFrame: GeoDataFrame with added columns for results, or None if inplace=True
155
- If stream_to_disk=True, large datasets are saved as NetCDF files with file paths stored.
471
+ geopandas.GeoDataFrame: GeoDataFrame with added columns for results
156
472
 
157
473
  Raises:
158
474
  ValueError: If concurrency is too high or if data exceeds memory limit without streaming
@@ -162,16 +478,10 @@ class SyncClient:
162
478
  gdf=gdf,
163
479
  expr=expr,
164
480
  conc=conc,
165
- inplace=inplace,
166
481
  in_crs=in_crs,
167
482
  out_crs=out_crs,
168
483
  resolution=resolution,
169
484
  geom_fix=geom_fix,
170
- drop_nan=drop_nan,
171
- spatial_reduction=spatial_reduction,
172
- temporal_reduction=temporal_reduction,
173
- max_memory_mb=max_memory_mb,
174
- stream_to_disk=stream_to_disk
175
485
  )
176
486
  return self._run_async(coro)
177
487
 
@@ -207,7 +517,49 @@ class SyncClient:
207
517
  )
208
518
  return self._run_async(coro)
209
519
 
210
- # Rest of the methods remain the same...
520
+ def geo_queries(
521
+ self,
522
+ queries: list[dict],
523
+ conc: int = 20,
524
+ ):
525
+ """
526
+ Execute multiple geo queries concurrently (synchronous version).
527
+
528
+ Args:
529
+ queries (list[dict]): List of dictionaries containing query parameters.
530
+ Each query must have 'expr', 'feature', and 'in_crs' keys.
531
+ conc (int): Number of concurrent requests to make (default 20, max 100)
532
+
533
+ Returns:
534
+ Union[float, geopandas.GeoDataFrame]:
535
+ - float: Average of all results if results are integers
536
+ - GeoDataFrame: GeoDataFrame with geometry and dataset columns if results are xarray datasets
537
+
538
+ Raises:
539
+ ValueError: If queries list is empty, concurrency is too high, or queries are malformed
540
+ APIError: If the API request fails
541
+
542
+ Example:
543
+ queries = [
544
+ {
545
+ 'expr': 'WCF.wcf',
546
+ 'feature': {'type': 'Feature', 'geometry': {...}, 'properties': {}},
547
+ 'in_crs': 'epsg:4326'
548
+ },
549
+ {
550
+ 'expr': 'NDVI.ndvi',
551
+ 'feature': {'type': 'Feature', 'geometry': {...}, 'properties': {}},
552
+ 'in_crs': 'epsg:4326'
553
+ }
554
+ ]
555
+ result = client.geo_queries(queries)
556
+ """
557
+ coro = self._async_client.geo_queries(
558
+ queries=queries,
559
+ conc=conc,
560
+ )
561
+ return self._run_async(coro)
562
+
211
563
  async def _ensure_context(self):
212
564
  """Ensure the async client context is entered."""
213
565
  if not self._context_entered and not self._closed:
@@ -221,18 +573,36 @@ class SyncClient:
221
573
  self._context_entered = False
222
574
 
223
575
  def _run_async(self, coro):
224
- """Run an async coroutine and return the result synchronously."""
576
+ """
577
+ Run an async coroutine and return the result synchronously.
578
+ This version handles both Jupyter notebook environments and regular Python environments.
579
+ """
225
580
  async def run_with_context():
226
581
  await self._ensure_context()
227
582
  return await coro
228
583
 
229
584
  try:
585
+ # Check if we're in a running event loop (like Jupyter)
230
586
  loop = asyncio.get_running_loop()
231
- import concurrent.futures
587
+
588
+ # Method 1: Try using nest_asyncio if available
589
+ try:
590
+ import nest_asyncio
591
+ nest_asyncio.apply()
592
+ return asyncio.run(run_with_context())
593
+ except ImportError:
594
+ pass
595
+
596
+ # Method 2: Use ThreadPoolExecutor to run in a separate thread
597
+ def run_in_thread():
598
+ return asyncio.run(run_with_context())
599
+
232
600
  with concurrent.futures.ThreadPoolExecutor() as executor:
233
- future = executor.submit(asyncio.run, run_with_context())
601
+ future = executor.submit(run_in_thread)
234
602
  return future.result()
603
+
235
604
  except RuntimeError:
605
+ # No running loop, safe to use asyncio.run()
236
606
  return asyncio.run(run_with_context())
237
607
 
238
608
  def close(self):
@@ -243,10 +613,21 @@ class SyncClient:
243
613
 
244
614
  try:
245
615
  loop = asyncio.get_running_loop()
246
- import concurrent.futures
247
- with concurrent.futures.ThreadPoolExecutor() as executor:
248
- future = executor.submit(asyncio.run, close_async())
249
- future.result()
616
+
617
+ # Try nest_asyncio first
618
+ try:
619
+ import nest_asyncio
620
+ nest_asyncio.apply()
621
+ asyncio.run(close_async())
622
+ except ImportError:
623
+ # Fall back to ThreadPoolExecutor
624
+ def run_in_thread():
625
+ return asyncio.run(close_async())
626
+
627
+ with concurrent.futures.ThreadPoolExecutor() as executor:
628
+ future = executor.submit(run_in_thread)
629
+ future.result()
630
+
250
631
  except RuntimeError:
251
632
  asyncio.run(close_async())
252
633
 
@@ -267,10 +648,21 @@ class SyncClient:
267
648
 
268
649
  try:
269
650
  loop = asyncio.get_running_loop()
270
- import concurrent.futures
271
- with concurrent.futures.ThreadPoolExecutor() as executor:
272
- future = executor.submit(asyncio.run, enter_async())
273
- future.result()
651
+
652
+ # Try nest_asyncio first
653
+ try:
654
+ import nest_asyncio
655
+ nest_asyncio.apply()
656
+ asyncio.run(enter_async())
657
+ except ImportError:
658
+ # Fall back to ThreadPoolExecutor
659
+ def run_in_thread():
660
+ return asyncio.run(enter_async())
661
+
662
+ with concurrent.futures.ThreadPoolExecutor() as executor:
663
+ future = executor.submit(run_in_thread)
664
+ future.result()
665
+
274
666
  except RuntimeError:
275
667
  asyncio.run(enter_async())
276
668
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: terrakio-core
3
- Version: 0.4.3
3
+ Version: 0.4.5
4
4
  Summary: Core components for Terrakio API clients
5
5
  Author-email: Yupeng Chao <yupeng@haizea.com.au>
6
6
  Project-URL: Homepage, https://github.com/HaizeaAnalytics/terrakio-python-api
@@ -24,6 +24,7 @@ Requires-Dist: geopandas>=0.13.0
24
24
  Requires-Dist: google-cloud-storage>=2.0.0
25
25
  Requires-Dist: scipy>=1.7.0
26
26
  Requires-Dist: nest_asyncio
27
+ Requires-Dist: onnxruntime>=1.10.0
27
28
  Provides-Extra: ml
28
29
  Requires-Dist: torch>=2.7.1; extra == "ml"
29
30
  Requires-Dist: scikit-learn>=1.7.0; extra == "ml"
@@ -0,0 +1,22 @@
1
+ terrakio_core/__init__.py,sha256=snOTpM6-GxHvvDJ6hjlsWywgIago1JbE8QDfsWMRlPI,273
2
+ terrakio_core/accessors.py,sha256=qWLljU83YO7EUOefo_f6_P6ba6uiYMXwou0ihAHKBHQ,23706
3
+ terrakio_core/async_client.py,sha256=M7C6by-GCW9AvDRhIwpBG12fO5--NG5qrHdSC6Fjkrc,14082
4
+ terrakio_core/client.py,sha256=VXP7BtJWIfpPPZR7_yNdSTcGwNgTwhb7KorusqkQrzk,5603
5
+ terrakio_core/config.py,sha256=r8NARVYOca4AuM88VP_j-8wQxOk1s7VcRdyEdseBlLE,4193
6
+ terrakio_core/exceptions.py,sha256=4qnpOM1gOxsNIXDXY4qwY1d3I4Myhp7HBh7b2D0SVrU,529
7
+ terrakio_core/sync_client.py,sha256=wsVKjaIDZW4AC2-81RXseE9mFbXu90T5Bbwrgw37x6k,24864
8
+ terrakio_core/convenience_functions/convenience_functions.py,sha256=B7qbObjP4OuAUtrVf4Gi58c0q2EkTwOCOE568P0Q-EE,18607
9
+ terrakio_core/endpoints/auth.py,sha256=FdLsPScPIBo-Gxl6ZnE-46cp2molggAJtL72LssN3fg,6049
10
+ terrakio_core/endpoints/dataset_management.py,sha256=BUm8IIlW_Q45vDiQp16CiJGeSLheI8uWRVRQtMdhaNk,13161
11
+ terrakio_core/endpoints/group_management.py,sha256=VFl3jakjQa9OPi351D3DZvLU9M7fHdfjCzGhmyJsx3U,6309
12
+ terrakio_core/endpoints/mass_stats.py,sha256=6PSWWCpKLKMcFOoXfOAuROX8iSuG_dLyTYcw7gzhhZ4,23464
13
+ terrakio_core/endpoints/model_management.py,sha256=LH_gHPrqYA-_45KWpDBRcFbwHgm-Kg0zk1ealy7P_C0,52379
14
+ terrakio_core/endpoints/space_management.py,sha256=YWb55nkJnFJGlALJ520DvurxDqVqwYtsvqQPWzxzhDs,2266
15
+ terrakio_core/endpoints/user_management.py,sha256=WlFr3EfK8iI6DfkpMuYLHZUPk2n7_DHHO6z1hndmZB4,3816
16
+ terrakio_core/helper/bounded_taskgroup.py,sha256=wiTH10jhKZgrsgrFUNG6gig8bFkUEPHkGRT2XY7Rgmo,677
17
+ terrakio_core/helper/decorators.py,sha256=L6om7wmWNgCei3Wy5U0aZ-70OzsCwclkjIf7SfQuhCg,2289
18
+ terrakio_core/helper/tiles.py,sha256=xNtp3oDD912PN_FQV5fb6uQYhwfHANuXyIcxoVCCfZU,2632
19
+ terrakio_core-0.4.5.dist-info/METADATA,sha256=5_6bPROpM38AJ7NJDqFzORJFG2HJR-j_X0Rg4KwriUY,1791
20
+ terrakio_core-0.4.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ terrakio_core-0.4.5.dist-info/top_level.txt,sha256=5cBj6O7rNWyn97ND4YuvvXm0Crv4RxttT4JZvNdOG6Q,14
22
+ terrakio_core-0.4.5.dist-info/RECORD,,
@@ -1,21 +0,0 @@
1
- terrakio_core/__init__.py,sha256=GDUYT7cudfxltFZZ-2_5xM4Pd7o-pkQx1O8K9HrE5f0,248
2
- terrakio_core/async_client.py,sha256=ffLKMbzclHfyBZBJn4uR8nlMW5E-96PX-4O5EghaSPE,13805
3
- terrakio_core/client.py,sha256=-tGffOKGMyuowsvBwaV7Wtc_EZSWuSwv26_I5FkUank,5446
4
- terrakio_core/config.py,sha256=r8NARVYOca4AuM88VP_j-8wQxOk1s7VcRdyEdseBlLE,4193
5
- terrakio_core/exceptions.py,sha256=4qnpOM1gOxsNIXDXY4qwY1d3I4Myhp7HBh7b2D0SVrU,529
6
- terrakio_core/sync_client.py,sha256=UpPn9rHp6x6otxj3QJ1Scnac4stgIpTtb__gmXszYCA,10787
7
- terrakio_core/convenience_functions/convenience_functions.py,sha256=sBY2g7Vv3jakkuXnuFomXBWP0y6Q7q1K4ay3g4TxIoQ,21068
8
- terrakio_core/endpoints/auth.py,sha256=e_hdNE6JOGhRVlQMFdEoOmoMHp5EzK6CclOEnc_AmZw,5863
9
- terrakio_core/endpoints/dataset_management.py,sha256=BUm8IIlW_Q45vDiQp16CiJGeSLheI8uWRVRQtMdhaNk,13161
10
- terrakio_core/endpoints/group_management.py,sha256=VFl3jakjQa9OPi351D3DZvLU9M7fHdfjCzGhmyJsx3U,6309
11
- terrakio_core/endpoints/mass_stats.py,sha256=IZEozQ9GyOmUhd7V8M66Bz2OWsyq-VKzOw_sj_i-dng,23154
12
- terrakio_core/endpoints/model_management.py,sha256=PF-2f6mW_RtkPWSL-N56kbgLeB6Z4EhU2N2qFqPan7o,70365
13
- terrakio_core/endpoints/space_management.py,sha256=YWb55nkJnFJGlALJ520DvurxDqVqwYtsvqQPWzxzhDs,2266
14
- terrakio_core/endpoints/user_management.py,sha256=WlFr3EfK8iI6DfkpMuYLHZUPk2n7_DHHO6z1hndmZB4,3816
15
- terrakio_core/helper/bounded_taskgroup.py,sha256=wiTH10jhKZgrsgrFUNG6gig8bFkUEPHkGRT2XY7Rgmo,677
16
- terrakio_core/helper/decorators.py,sha256=L6om7wmWNgCei3Wy5U0aZ-70OzsCwclkjIf7SfQuhCg,2289
17
- terrakio_core/helper/tiles.py,sha256=xNtp3oDD912PN_FQV5fb6uQYhwfHANuXyIcxoVCCfZU,2632
18
- terrakio_core-0.4.3.dist-info/METADATA,sha256=201kTjM26SSTmtRPBohs9GlBsP_3U3tUw6ja2X0D6uM,1756
19
- terrakio_core-0.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
20
- terrakio_core-0.4.3.dist-info/top_level.txt,sha256=5cBj6O7rNWyn97ND4YuvvXm0Crv4RxttT4JZvNdOG6Q,14
21
- terrakio_core-0.4.3.dist-info/RECORD,,