yirgacheffe 1.7.9__py3-none-any.whl → 1.8.1__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 yirgacheffe might be problematic. Click here for more details.

@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
  import copy
3
3
  from pathlib import Path
4
- from typing import Any, List, Optional, Sequence, Union
4
+ from typing import Any, Sequence
5
5
 
6
6
  import numpy as np
7
7
  from numpy import ma
@@ -22,8 +22,8 @@ class GroupLayer(YirgacheffeLayer):
22
22
  @classmethod
23
23
  def layer_from_directory(
24
24
  cls,
25
- directory_path: Union[Path,str],
26
- name: Optional[str] = None,
25
+ directory_path: Path | str,
26
+ name: str | None = None,
27
27
  matching: str = "*.tif"
28
28
  ) -> GroupLayer:
29
29
  if directory_path is None:
@@ -38,20 +38,20 @@ class GroupLayer(YirgacheffeLayer):
38
38
  @classmethod
39
39
  def layer_from_files(
40
40
  cls,
41
- filenames: Sequence[Union[Path,str]],
42
- name: Optional[str] = None
41
+ filenames: Sequence[Path | str],
42
+ name: str | None = None
43
43
  ) -> GroupLayer:
44
44
  if filenames is None:
45
45
  raise ValueError("filenames argument is None")
46
- rasters: List[YirgacheffeLayer] = [RasterLayer.layer_from_file(x) for x in filenames]
46
+ rasters: list[YirgacheffeLayer] = [RasterLayer.layer_from_file(x) for x in filenames]
47
47
  if len(rasters) < 1:
48
48
  raise GroupLayerEmpty("No files found")
49
49
  return cls(rasters, name)
50
50
 
51
51
  def __init__(
52
52
  self,
53
- layers: List[YirgacheffeLayer],
54
- name: Optional[str] = None
53
+ layers: list[YirgacheffeLayer],
54
+ name: str | None = None
55
55
  ) -> None:
56
56
  if not layers:
57
57
  raise GroupLayerEmpty("Expected one or more layers")
@@ -255,7 +255,7 @@ class TiledGroupLayer(GroupLayer):
255
255
  ysize
256
256
  )
257
257
 
258
- partials: List[TileData] = []
258
+ partials: list[TileData] = []
259
259
  for layer in self.layers:
260
260
  # Normally this is hidden with set_window_for_...
261
261
  adjusted_layer_window = Window(
@@ -287,7 +287,7 @@ class TiledGroupLayer(GroupLayer):
287
287
  # the "obvious" tile. In which case, we should reject the smaller section. If we have
288
288
  # two tiles at the same offset and one is not a perfect subset of the other then the
289
289
  # tile set we were given is not regularly shaped, and so we should give up.
290
- combed_partials: List[TileData] = []
290
+ combed_partials: list[TileData] = []
291
291
  previous_tile = None
292
292
  for tile in sorted_partials:
293
293
  if previous_tile is None:
@@ -312,7 +312,7 @@ class TiledGroupLayer(GroupLayer):
312
312
  expected_next_x = 0
313
313
  expected_next_y = 0
314
314
  data = None
315
- row_chunk: Optional[np.ndarray] = None
315
+ row_chunk: np.ndarray | None = None
316
316
 
317
317
  # Allow for reading off top
318
318
  if combed_partials:
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from math import ceil, floor
2
- from typing import Any, Tuple
4
+ from typing import Any
3
5
 
4
6
  import h3
5
7
  import numpy as np
@@ -75,7 +77,7 @@ class H3CellLayer(YirgacheffeLayer):
75
77
  )
76
78
 
77
79
  @property
78
- def _raster_dimensions(self) -> Tuple[int,int]:
80
+ def _raster_dimensions(self) -> tuple[int, int]:
79
81
  return (self._raster_xsize, self._raster_ysize)
80
82
 
81
83
  @property
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
  import math
3
3
  from pathlib import Path
4
- from typing import Any, Optional, Tuple, Union
4
+ from typing import Any
5
5
 
6
6
  import numpy as np
7
7
  from osgeo import gdal
@@ -26,14 +26,14 @@ class RasterLayer(YirgacheffeLayer):
26
26
  def empty_raster_layer(
27
27
  area: Area,
28
28
  scale: PixelScale,
29
- datatype: Union[int, DataType],
30
- filename: Optional[Union[Path,str]]=None,
29
+ datatype: int | DataType,
30
+ filename: Path | str | None = None,
31
31
  projection: str=WGS_84_PROJECTION,
32
- name: Optional[str]=None,
32
+ name: str | None = None,
33
33
  compress: bool=True,
34
- nodata: Optional[Union[float,int]]=None,
35
- nbits: Optional[int]=None,
36
- threads: Optional[int]=None,
34
+ nodata: float | int | None = None,
35
+ nbits: int | None = None,
36
+ threads: int | None = None,
37
37
  bands: int=1
38
38
  ) -> RasterLayer:
39
39
  abs_xstep, abs_ystep = abs(scale.xstep), abs(scale.ystep)
@@ -88,13 +88,13 @@ class RasterLayer(YirgacheffeLayer):
88
88
  @staticmethod
89
89
  def empty_raster_layer_like(
90
90
  layer: Any,
91
- filename: Optional[Union[Path,str]]=None,
92
- area: Optional[Area]=None,
93
- datatype: Optional[Union[int, DataType]]=None,
91
+ filename: Path | str | None = None,
92
+ area: Area | None = None,
93
+ datatype: int | DataType | None = None,
94
94
  compress: bool=True,
95
- nodata: Optional[Union[float,int]]=None,
96
- nbits: Optional[int]=None,
97
- threads: Optional[int]=None,
95
+ nodata: float | int | None = None,
96
+ nbits: int | None = None,
97
+ threads: int | None = None,
98
98
  bands: int=1
99
99
  ) -> RasterLayer:
100
100
  if area is None:
@@ -165,7 +165,7 @@ class RasterLayer(YirgacheffeLayer):
165
165
  cls,
166
166
  source: RasterLayer,
167
167
  new_pixel_scale: PixelScale,
168
- filename: Optional[Union[Path,str]]=None,
168
+ filename: Path | str | None = None,
169
169
  compress: bool=True,
170
170
  algorithm: int=gdal.GRA_NearestNeighbour,
171
171
  ) -> RasterLayer:
@@ -220,7 +220,7 @@ class RasterLayer(YirgacheffeLayer):
220
220
  @classmethod
221
221
  def layer_from_file(
222
222
  cls,
223
- filename: Union[Path,str],
223
+ filename: Path | str,
224
224
  band: int = 1,
225
225
  ignore_nodata: bool = False,
226
226
  ) -> RasterLayer:
@@ -238,7 +238,7 @@ class RasterLayer(YirgacheffeLayer):
238
238
  def __init__(
239
239
  self,
240
240
  dataset: gdal.Dataset,
241
- name: Optional[str] = None,
241
+ name: str | None = None,
242
242
  band: int = 1,
243
243
  ignore_nodata: bool = False,
244
244
  ) -> None:
@@ -273,7 +273,7 @@ class RasterLayer(YirgacheffeLayer):
273
273
  self._ignore_nodata = ignore_nodata
274
274
 
275
275
  @property
276
- def _raster_dimensions(self) -> Tuple[int,int]:
276
+ def _raster_dimensions(self) -> tuple[int, int]:
277
277
  return (self._raster_xsize, self._raster_ysize)
278
278
 
279
279
  def close(self):
@@ -321,7 +321,7 @@ class RasterLayer(YirgacheffeLayer):
321
321
  return DataType.of_gdal(self._dataset.GetRasterBand(1).DataType)
322
322
 
323
323
  @property
324
- def nodata(self) -> Optional[Any]:
324
+ def nodata(self) -> Any | None:
325
325
  if self._dataset is None:
326
326
  self._unpark()
327
327
  assert self._dataset
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
  from math import floor, ceil
3
3
  from pathlib import Path
4
- from typing import Any, Optional, Union
4
+ from typing import Any
5
5
 
6
6
  from skimage import transform
7
7
 
@@ -18,7 +18,7 @@ class RescaledRasterLayer(YirgacheffeLayer):
18
18
  @classmethod
19
19
  def layer_from_file(
20
20
  cls,
21
- filename: Union[Path,str],
21
+ filename: Path | str,
22
22
  pixel_scale: PixelScale,
23
23
  band: int = 1,
24
24
  nearest_neighbour: bool = True,
@@ -35,7 +35,7 @@ class RescaledRasterLayer(YirgacheffeLayer):
35
35
  src: RasterLayer,
36
36
  target_projection: MapProjection,
37
37
  nearest_neighbour: bool = True,
38
- name: Optional[str] = None,
38
+ name: str | None = None,
39
39
  ):
40
40
  super().__init__(
41
41
  src.area,
@@ -1,8 +1,7 @@
1
1
  from __future__ import annotations
2
2
  from math import ceil, floor
3
3
  from pathlib import Path
4
- from typing import Any, Optional, Tuple, Union
5
- from typing_extensions import NotRequired
4
+ from typing import Any
6
5
 
7
6
  import deprecation
8
7
  from osgeo import gdal, ogr
@@ -70,12 +69,12 @@ class RasteredVectorLayer(RasterLayer):
70
69
  )
71
70
  def layer_from_file( # type: ignore[override] # pylint: disable=W0221
72
71
  cls,
73
- filename: Union[Path,str],
74
- where_filter: Optional[str],
72
+ filename: Path | str,
73
+ where_filter: str | None,
75
74
  scale: PixelScale,
76
75
  projection: str,
77
- datatype: Optional[Union[int, DataType]] = None,
78
- burn_value: Union[int,float,str] = 1,
76
+ datatype: int | DataType | None = None,
77
+ burn_value: int | float | str = 1,
79
78
  ) -> RasteredVectorLayer:
80
79
  vectors = ogr.Open(filename)
81
80
  if vectors is None:
@@ -111,14 +110,14 @@ class RasteredVectorLayer(RasterLayer):
111
110
  self,
112
111
  layer: ogr.Layer,
113
112
  projection: MapProjection,
114
- datatype: Union[int, DataType] = DataType.Byte,
115
- burn_value: Union[int,float,str] = 1,
113
+ datatype: int | DataType = DataType.Byte,
114
+ burn_value: int | float | str = 1,
116
115
  ):
117
116
  if layer is None:
118
117
  raise ValueError('No layer provided')
119
118
  self.layer = layer
120
119
 
121
- self._original: Optional[Any] = None
120
+ self._original: Any | None = None
122
121
 
123
122
  if isinstance(datatype, int):
124
123
  datatype_arg = DataType.of_gdal(datatype)
@@ -180,11 +179,11 @@ class VectorLayer(YirgacheffeLayer):
180
179
  @classmethod
181
180
  def layer_from_file_like(
182
181
  cls,
183
- filename: Union[Path,str],
182
+ filename: Path | str,
184
183
  other_layer: YirgacheffeLayer,
185
- where_filter: Optional[str]=None,
186
- datatype: Optional[Union[int, DataType]] = None,
187
- burn_value: Union[int,float,str] = 1,
184
+ where_filter: str | None = None,
185
+ datatype: int | DataType | None = None,
186
+ burn_value: int | float | str = 1,
188
187
  ) -> VectorLayer:
189
188
  if other_layer is None:
190
189
  raise ValueError("like layer can not be None")
@@ -223,13 +222,13 @@ class VectorLayer(YirgacheffeLayer):
223
222
  @classmethod
224
223
  def layer_from_file(
225
224
  cls,
226
- filename: Union[Path,str],
227
- where_filter: Optional[str],
228
- scale: Optional[PixelScale],
229
- projection: Optional[str],
230
- datatype: Optional[Union[int, DataType]] = None,
231
- burn_value: Union[int,float,str] = 1,
232
- anchor: Tuple[float,float] = (0.0, 0.0)
225
+ filename: Path | str,
226
+ where_filter: str | None,
227
+ scale: PixelScale | None,
228
+ projection: str | None,
229
+ datatype: int | DataType | None = None,
230
+ burn_value: int | float | str = 1,
231
+ anchor: tuple[float, float] = (0.0, 0.0)
233
232
  ) -> VectorLayer:
234
233
  # In 2.0 we need to remove this and migrate to the MapProjection version
235
234
  if (projection is None) ^ (scale is None):
@@ -250,12 +249,12 @@ class VectorLayer(YirgacheffeLayer):
250
249
  @classmethod
251
250
  def _future_layer_from_file(
252
251
  cls,
253
- filename: Union[Path,str],
254
- where_filter: Optional[str],
255
- projection: Optional[MapProjection],
256
- datatype: Optional[Union[int, DataType]] = None,
257
- burn_value: Union[int,float,str] = 1,
258
- anchor: Tuple[float,float] = (0.0, 0.0)
252
+ filename: Path | str,
253
+ where_filter: str | None,
254
+ projection: MapProjection | None,
255
+ datatype: int | DataType | None = None,
256
+ burn_value: int | float | str = 1,
257
+ anchor: tuple[float, float] = (0.0, 0.0)
259
258
  ) -> VectorLayer:
260
259
  try:
261
260
  vectors = ogr.Open(filename)
@@ -295,11 +294,11 @@ class VectorLayer(YirgacheffeLayer):
295
294
  def __init__(
296
295
  self,
297
296
  layer: ogr.Layer,
298
- projection: Optional[MapProjection],
299
- name: Optional[str] = None,
300
- datatype: Union[int,DataType] = DataType.Byte,
301
- burn_value: Union[int,float,str] = 1,
302
- anchor: Tuple[float,float] = (0.0, 0.0)
297
+ projection: MapProjection | None,
298
+ name: str | None = None,
299
+ datatype: int | DataType = DataType.Byte,
300
+ burn_value: int | float | str = 1,
301
+ anchor: tuple[float, float] = (0.0, 0.0)
303
302
  ):
304
303
  if layer is None:
305
304
  raise ValueError('No layer provided')
@@ -316,9 +315,9 @@ class VectorLayer(YirgacheffeLayer):
316
315
  self.burn_value = burn_value
317
316
 
318
317
  self._original = None
319
- self._dataset_path: Optional[Path] = None
320
- self._filter: Optional[str] = None
321
- self._anchor: Tuple[float,float] = (0.0, 0.0)
318
+ self._dataset_path: Path | None = None
319
+ self._filter: str | None = None
320
+ self._anchor: tuple[float, float] = (0.0, 0.0)
322
321
 
323
322
  # work out region for mask
324
323
  envelopes = []
@@ -334,41 +333,41 @@ class VectorLayer(YirgacheffeLayer):
334
333
  self._anchor = anchor
335
334
  self._envelopes = envelopes
336
335
 
337
- # if projection is not None:
338
- # # Get the area, but scale it to the pixel resolution that we're using. Note that
339
- # # the pixel scale GDAL uses can have -ve values, but those will mess up the
340
- # # ceil/floor math, so we use absolute versions when trying to round.
341
- # abs_xstep, abs_ystep = abs(projection.xstep), abs(projection.ystep)
342
- #
343
- # # Lacking any other reference, we will make the raster align with
344
- # # (0.0, 0.0), if sometimes we want to align with an existing raster, so if
345
- # # an anchor is specified, ensure we use that as our pixel space alignment
346
- # x_anchor = anchor[0]
347
- # y_anchor = anchor[1]
348
- # left_shift = x_anchor - abs_xstep
349
- # right_shift = x_anchor
350
- # top_shift = y_anchor
351
- # bottom_shift = y_anchor - abs_ystep
352
- #
353
- # area = Area(
354
- # left=(floor((min(x[0] for x in envelopes) - left_shift) / abs_xstep) * abs_xstep) + left_shift,
355
- # top=(ceil((max(x[3] for x in envelopes) - top_shift) / abs_ystep) * abs_ystep) + top_shift,
356
- # right=(ceil((max(x[1] for x in envelopes) - right_shift) / abs_xstep) * abs_xstep) + right_shift,
357
- # bottom=(floor((min(x[2] for x in envelopes) - bottom_shift) / abs_ystep) * abs_ystep) + bottom_shift,
358
- # )
359
- # else:
336
+ if projection is not None:
337
+ # Get the area, but scale it to the pixel resolution that we're using. Note that
338
+ # the pixel scale GDAL uses can have -ve values, but those will mess up the
339
+ # ceil/floor math, so we use absolute versions when trying to round.
340
+ abs_xstep, abs_ystep = abs(projection.xstep), abs(projection.ystep)
341
+
342
+ # Lacking any other reference, we will make the raster align with
343
+ # (0.0, 0.0), if sometimes we want to align with an existing raster, so if
344
+ # an anchor is specified, ensure we use that as our pixel space alignment
345
+ x_anchor = anchor[0]
346
+ y_anchor = anchor[1]
347
+ left_shift = x_anchor - abs_xstep
348
+ right_shift = x_anchor
349
+ top_shift = y_anchor
350
+ bottom_shift = y_anchor - abs_ystep
351
+
352
+ area = Area(
353
+ left=(floor((min(x[0] for x in envelopes) - left_shift) / abs_xstep) * abs_xstep) + left_shift,
354
+ top=(ceil((max(x[3] for x in envelopes) - top_shift) / abs_ystep) * abs_ystep) + top_shift,
355
+ right=(ceil((max(x[1] for x in envelopes) - right_shift) / abs_xstep) * abs_xstep) + right_shift,
356
+ bottom=(floor((min(x[2] for x in envelopes) - bottom_shift) / abs_ystep) * abs_ystep) + bottom_shift,
357
+ )
358
+ else:
360
359
  # If we don't have a projection just go with the idealised area
361
- area = Area(
362
- left=floor(min(x[0] for x in envelopes)),
363
- top=ceil(max(x[3] for x in envelopes)),
364
- right=ceil(max(x[1] for x in envelopes)),
365
- bottom=floor(min(x[2] for x in envelopes)),
366
- )
360
+ area = Area(
361
+ left=floor(min(x[0] for x in envelopes)),
362
+ top=ceil(max(x[3] for x in envelopes)),
363
+ right=ceil(max(x[1] for x in envelopes)),
364
+ bottom=floor(min(x[2] for x in envelopes)),
365
+ )
367
366
 
368
367
  super().__init__(area, projection)
369
368
 
370
369
 
371
- def _get_operation_area(self, projection: Optional[MapProjection]=None) -> Area:
370
+ def _get_operation_area(self, projection: MapProjection | None = None) -> Area:
372
371
  if self._projection is not None and projection is not None and self._projection != projection:
373
372
  raise ValueError("Calculation projection does not match layer projection")
374
373
 
@@ -449,7 +448,7 @@ class VectorLayer(YirgacheffeLayer):
449
448
  def _read_array_for_area(
450
449
  self,
451
450
  target_area: Area,
452
- target_projection: Optional[MapProjection],
451
+ target_projection: MapProjection | None,
453
452
  x: int,
454
453
  y: int,
455
454
  width: int,
@@ -496,7 +495,7 @@ class VectorLayer(YirgacheffeLayer):
496
495
  return res
497
496
 
498
497
  def _read_array_with_window(self, _x, _y, _width, _height, _window) -> Any:
499
- assert NotRequired
498
+ raise NotImplementedError("VectorLayer does not support windowed reading")
500
499
 
501
500
  def _read_array(self, x: int, y: int, width: int, height: int) -> Any:
502
501
  return self._read_array_for_area(self.area, None, x, y, width, height)
yirgacheffe/rounding.py CHANGED
@@ -1,6 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  import math
2
4
  import sys
3
- from typing import List, Optional
4
5
 
5
6
  from .window import PixelScale
6
7
 
@@ -39,10 +40,10 @@ def round_down_pixels(value: float, pixelscale: float) -> int:
39
40
  else:
40
41
  return math.floor(value)
41
42
 
42
- def are_pixel_scales_equal_enough(pixel_scales: List[Optional[PixelScale]]) -> bool:
43
+ def are_pixel_scales_equal_enough(pixel_scales: list[PixelScale | None]) -> bool:
43
44
  # some layers (e.g., constant layers) have no scale, and always work, so filter
44
45
  # them out first
45
- cleaned_pixel_scales: List[PixelScale] = [x for x in pixel_scales if x is not None]
46
+ cleaned_pixel_scales: list[PixelScale] = [x for x in pixel_scales if x is not None]
46
47
 
47
48
  try:
48
49
  first = cleaned_pixel_scales[0]