terrakio-core 0.3.8__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.

Potentially problematic release.


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

Files changed (28) hide show
  1. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/PKG-INFO +2 -1
  2. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/pyproject.toml +2 -1
  3. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/__init__.py +3 -3
  4. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/async_client.py +22 -7
  5. terrakio_core-0.4.0/terrakio_core/client.py +134 -0
  6. terrakio_core-0.4.0/terrakio_core/convenience_functions/convenience_functions.py +529 -0
  7. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/endpoints/mass_stats.py +71 -16
  8. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/endpoints/model_management.py +388 -217
  9. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/endpoints/user_management.py +5 -5
  10. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/sync_client.py +107 -188
  11. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core.egg-info/PKG-INFO +2 -1
  12. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core.egg-info/requires.txt +1 -0
  13. terrakio_core-0.3.8/terrakio_core/client.py +0 -36
  14. terrakio_core-0.3.8/terrakio_core/convenience_functions/convenience_functions.py +0 -296
  15. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/README.md +0 -0
  16. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/setup.cfg +0 -0
  17. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/config.py +0 -0
  18. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/endpoints/auth.py +0 -0
  19. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/endpoints/dataset_management.py +0 -0
  20. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/endpoints/group_management.py +0 -0
  21. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/endpoints/space_management.py +0 -0
  22. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/exceptions.py +0 -0
  23. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/helper/bounded_taskgroup.py +0 -0
  24. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/helper/decorators.py +0 -0
  25. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core/helper/tiles.py +0 -0
  26. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core.egg-info/SOURCES.txt +0 -0
  27. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core.egg-info/dependency_links.txt +0 -0
  28. {terrakio_core-0.3.8 → terrakio_core-0.4.0}/terrakio_core.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: terrakio-core
3
- Version: 0.3.8
3
+ Version: 0.4.0
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
@@ -22,6 +22,7 @@ Requires-Dist: xarray>=2023.1.0
22
22
  Requires-Dist: shapely>=2.0.0
23
23
  Requires-Dist: geopandas>=0.13.0
24
24
  Requires-Dist: google-cloud-storage>=2.0.0
25
+ Requires-Dist: scipy>=1.7.0
25
26
  Requires-Dist: nest_asyncio
26
27
  Provides-Extra: ml
27
28
  Requires-Dist: torch>=2.7.1; extra == "ml"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "terrakio-core"
7
- version = "0.3.8"
7
+ version = "0.4.0"
8
8
  authors = [
9
9
  {name = "Yupeng Chao", email = "yupeng@haizea.com.au"},
10
10
  ]
@@ -29,6 +29,7 @@ dependencies = [
29
29
  "shapely>=2.0.0",
30
30
  "geopandas>=0.13.0",
31
31
  "google-cloud-storage>=2.0.0",
32
+ "scipy>=1.7.0",
32
33
  "nest_asyncio",
33
34
  ]
34
35
 
@@ -5,12 +5,12 @@ Terrakio Core
5
5
  Core components for Terrakio API clients.
6
6
  """
7
7
 
8
- __version__ = "0.3.8"
8
+ __version__ = "0.4.0"
9
9
 
10
10
  from .async_client import AsyncClient
11
- from .sync_client import SyncClient
11
+ from .sync_client import SyncClient as Client
12
12
 
13
13
  __all__ = [
14
14
  "AsyncClient",
15
- "SyncClient"
15
+ "Client"
16
16
  ]
@@ -90,7 +90,6 @@ class AsyncClient(BaseClient):
90
90
  """Parse response based on content type."""
91
91
  content_type = response.headers.get('content-type', '').lower()
92
92
  content = await response.read()
93
-
94
93
  if 'json' in content_type:
95
94
  return json.loads(content.decode('utf-8'))
96
95
  elif 'csv' in content_type:
@@ -117,7 +116,6 @@ class AsyncClient(BaseClient):
117
116
  except aiohttp.ClientError as e:
118
117
  raise APIError(f"Request failed: {e}")
119
118
  else:
120
- # this means that we used the with statement, and we already have a session
121
119
  try:
122
120
  async with self._session.request(method, url, **kwargs) as response:
123
121
  response.raise_for_status()
@@ -131,7 +129,6 @@ class AsyncClient(BaseClient):
131
129
  feature: Union[Dict[str, Any], ShapelyGeometry],
132
130
  in_crs: str = "epsg:4326",
133
131
  out_crs: str = "epsg:4326",
134
- output: str = "csv",
135
132
  resolution: int = -1,
136
133
  geom_fix: bool = False,
137
134
  validated: bool = True,
@@ -145,7 +142,6 @@ class AsyncClient(BaseClient):
145
142
  feature (Union[Dict[str, Any], ShapelyGeometry]): The geographic feature
146
143
  in_crs (str): Input coordinate reference system
147
144
  out_crs (str): Output coordinate reference system
148
- output (str): Output format ('csv' or 'netcdf')
149
145
  resolution (int): Resolution parameter
150
146
  geom_fix (bool): Whether to fix the geometry (default False)
151
147
  validated (bool): Whether to use validated data (default True)
@@ -167,7 +163,7 @@ class AsyncClient(BaseClient):
167
163
  "feature": feature,
168
164
  "in_crs": in_crs,
169
165
  "out_crs": out_crs,
170
- "output": output,
166
+ "output": "netcdf",
171
167
  "resolution": resolution,
172
168
  "expr": expr,
173
169
  "buffer": geom_fix,
@@ -186,6 +182,11 @@ class AsyncClient(BaseClient):
186
182
  out_crs: str = "epsg:4326",
187
183
  resolution: int = -1,
188
184
  geom_fix: bool = False,
185
+ drop_nan: bool = False,
186
+ spatial_reduction: str = None,
187
+ temporal_reduction: str = None,
188
+ max_memory_mb: int = 500,
189
+ stream_to_disk: bool = False,
189
190
  ):
190
191
  """
191
192
  Compute zonal statistics for all geometries in a GeoDataFrame.
@@ -199,11 +200,20 @@ class AsyncClient(BaseClient):
199
200
  out_crs (str): Output coordinate reference system
200
201
  resolution (int): Resolution parameter
201
202
  geom_fix (bool): Whether to fix the geometry (default False)
203
+ drop_nan (bool): Whether to drop NaN values from the results (default False)
204
+ spatial_reduction (str): Reduction operation for spatial dimensions (x, y).
205
+ Options: 'mean', 'median', 'min', 'max', 'std', 'var', 'sum', 'count'
206
+ temporal_reduction (str): Reduction operation for temporal dimension (time).
207
+ Options: 'mean', 'median', 'min', 'max', 'std', 'var', 'sum', 'count'
208
+ max_memory_mb (int): Maximum memory threshold in MB (default 500MB)
209
+ stream_to_disk (bool): Whether to stream datasets to disk as NetCDF files (default False)
210
+
202
211
  Returns:
203
212
  geopandas.GeoDataFrame: GeoDataFrame with added columns for results, or None if inplace=True
213
+ If stream_to_disk=True, large datasets are saved as NetCDF files with file paths stored.
204
214
 
205
215
  Raises:
206
- ValueError: If concurrency is too high
216
+ ValueError: If concurrency is too high or if data exceeds memory limit without streaming
207
217
  APIError: If the API request fails
208
218
  """
209
219
  return await _zonal_stats(
@@ -215,7 +225,12 @@ class AsyncClient(BaseClient):
215
225
  in_crs=in_crs,
216
226
  out_crs=out_crs,
217
227
  resolution=resolution,
218
- geom_fix=geom_fix
228
+ geom_fix=geom_fix,
229
+ drop_nan=drop_nan,
230
+ spatial_reduction=spatial_reduction,
231
+ temporal_reduction=temporal_reduction,
232
+ max_memory_mb=max_memory_mb,
233
+ stream_to_disk=stream_to_disk
219
234
  )
220
235
 
221
236
  async def create_dataset_file(
@@ -0,0 +1,134 @@
1
+ from typing import Optional
2
+ import logging
3
+ import warnings
4
+ from terrakio_core.config import read_config_file, DEFAULT_CONFIG_FILE
5
+ from abc import abstractmethod
6
+ import xarray as xr
7
+
8
+
9
+ class BaseClient():
10
+ def __init__(self, url: Optional[str] = None, api_key: Optional[str] = None, verbose: bool = False):
11
+
12
+ self.verbose = verbose
13
+ self.logger = logging.getLogger("terrakio")
14
+ if verbose:
15
+ self.logger.setLevel(logging.INFO)
16
+ else:
17
+ self.logger.setLevel(logging.WARNING)
18
+
19
+ self.timeout = 300
20
+ self.retry = 3
21
+
22
+ self.session = None
23
+
24
+ self.url = url
25
+ self.key = api_key
26
+
27
+ config = read_config_file(DEFAULT_CONFIG_FILE, logger=self.logger)
28
+
29
+ if self.url is None:
30
+ self.url = config.get('url')
31
+
32
+ if self.key is None:
33
+ self.key = config.get('key')
34
+
35
+ self.token = config.get('token')
36
+
37
+ # Apply xarray printing fix to prevent crashes with GeoDataFrames
38
+ self._apply_xarray_fix()
39
+
40
+ def _apply_xarray_fix(self):
41
+ """
42
+ Apply xarray printing fix to prevent crashes when GeoDataFrames contain xarray objects.
43
+ This fix is applied automatically when the client is initialized.
44
+ """
45
+ try:
46
+
47
+ # Check if fix is already applied globally
48
+ if hasattr(xr.DataArray, '_terrakio_fix_applied'):
49
+ if self.verbose:
50
+ self.logger.info("xarray printing fix already applied")
51
+ return
52
+
53
+ # Store original methods for potential restoration
54
+ if not hasattr(xr.DataArray, '_original_iter'):
55
+ xr.DataArray._original_iter = xr.DataArray.__iter__
56
+ xr.Dataset._original_iter = xr.Dataset.__iter__
57
+
58
+ # Define safe iteration methods that prevent pandas from iterating
59
+ # but leave __repr__ and __str__ untouched for normal xarray printing
60
+ def safe_dataarray_iter(self):
61
+ # Return infinite iterator that always yields the same safe value
62
+ name = getattr(self, 'name', None) or 'unnamed'
63
+ shape_str = 'x'.join(map(str, self.shape)) if hasattr(self, 'shape') else 'unknown'
64
+ placeholder = f"<DataArray '{name}' {shape_str}>"
65
+ while True:
66
+ yield placeholder
67
+
68
+ def safe_dataset_iter(self):
69
+ # Return infinite iterator that always yields the same safe value
70
+ num_vars = len(self.data_vars) if hasattr(self, 'data_vars') else 0
71
+ num_dims = len(self.dims) if hasattr(self, 'dims') else 0
72
+ placeholder = f"<Dataset: {num_vars} vars, {num_dims} dims>"
73
+ while True:
74
+ yield placeholder
75
+
76
+ # Apply only the iteration fix - leave __repr__ and __str__ untouched
77
+ xr.DataArray.__iter__ = safe_dataarray_iter
78
+ xr.Dataset.__iter__ = safe_dataset_iter
79
+
80
+ # Mark as applied to avoid duplicate applications
81
+ xr.DataArray._terrakio_fix_applied = True
82
+ xr.Dataset._terrakio_fix_applied = True
83
+
84
+ if self.verbose:
85
+ self.logger.info("xarray iteration fix applied - GeoDataFrames with xarray objects will print safely, direct xarray printing unchanged")
86
+
87
+ except ImportError:
88
+ # xarray not installed, skip the fix
89
+ if self.verbose:
90
+ self.logger.info("xarray not installed, skipping printing fix")
91
+ except Exception as e:
92
+ # Log warning but don't fail initialization
93
+ warning_msg = f"Failed to apply xarray printing fix: {e}"
94
+ warnings.warn(warning_msg)
95
+ if self.verbose:
96
+ self.logger.warning(warning_msg)
97
+
98
+ def restore_xarray_printing(self):
99
+ """
100
+ Restore original xarray printing behavior.
101
+ Call this method if you want to see full xarray representations again.
102
+ """
103
+ try:
104
+ import xarray as xr
105
+
106
+ if hasattr(xr.DataArray, '_original_iter'):
107
+ xr.DataArray.__iter__ = xr.DataArray._original_iter
108
+ xr.Dataset.__iter__ = xr.Dataset._original_iter
109
+
110
+ # Remove the fix markers
111
+ if hasattr(xr.DataArray, '_terrakio_fix_applied'):
112
+ delattr(xr.DataArray, '_terrakio_fix_applied')
113
+ if hasattr(xr.Dataset, '_terrakio_fix_applied'):
114
+ delattr(xr.Dataset, '_terrakio_fix_applied')
115
+
116
+ if self.verbose:
117
+ self.logger.info("Original xarray iteration behavior restored")
118
+ else:
119
+ if self.verbose:
120
+ self.logger.info("No xarray fix to restore")
121
+
122
+ except ImportError:
123
+ if self.verbose:
124
+ self.logger.info("xarray not available")
125
+ except Exception as e:
126
+ warning_msg = f"Failed to restore xarray printing: {e}"
127
+ warnings.warn(warning_msg)
128
+ if self.verbose:
129
+ self.logger.warning(warning_msg)
130
+
131
+ @abstractmethod
132
+ def _setup_session(self):
133
+ """Initialize the HTTP session - implemented by sync/async clients"""
134
+ pass