kuva-reader 1.1.1__py3-none-any.whl → 1.1.3__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 kuva-reader might be problematic. Click here for more details.

kuva_reader/__init__.py CHANGED
@@ -22,7 +22,7 @@ Dependencies
22
22
  visualization.
23
23
  """
24
24
 
25
- __version__ = "0.1.0"
25
+ __version__ = "1.1.2"
26
26
 
27
27
  from .reader.image import (
28
28
  image_footprint,
@@ -61,11 +61,12 @@ class Level0Product(ProductBase[MetadataLevel0]):
61
61
  ) -> None:
62
62
  super().__init__(image_path, metadata, target_ureg)
63
63
 
64
- self.images = {
64
+ self._images = {
65
65
  camera: cast(
66
66
  rio.DatasetReader,
67
67
  rio.open(
68
68
  self.image_path / (cube.camera.name + ".tif"),
69
+ num_threads='16',
69
70
  ),
70
71
  )
71
72
  for camera, cube in self.metadata.image.data_cubes.items() # type: ignore
@@ -97,6 +98,12 @@ class Level0Product(ProductBase[MetadataLevel0]):
97
98
  """Return the datarray for the chosen camera."""
98
99
  return self.images[camera]
99
100
 
101
+ @property
102
+ def images(self) -> dict[str, rio.DatasetReader]:
103
+ if self._images is None:
104
+ raise RuntimeError("Images has been released.")
105
+ return self._images
106
+
100
107
  def keys(self) -> list[str]:
101
108
  """Easy access to the camera keys."""
102
109
  return list(self.images.keys())
@@ -230,11 +237,14 @@ class Level0Product(ProductBase[MetadataLevel0]):
230
237
  """Explicitely closes the Rasterio DatasetReaders and releases the memory of
231
238
  the `images` variable.
232
239
  """
233
- for k in self.images.keys():
234
- self.images[k].close()
235
-
236
- del self.images
237
- self.images = None
240
+ if self._images is not None:
241
+ for k in self._images.keys():
242
+ self._images[k].close()
243
+
244
+ del self._images
245
+ # We know that images are not None as long as somebody doesn't call
246
+ # this function beforehand....
247
+ self._images = None
238
248
 
239
249
 
240
250
  def generate_level_0_metafile():
@@ -50,9 +50,9 @@ class Level1ABProduct(ProductBase[MetadataLevel1AB]):
50
50
  ) -> None:
51
51
  super().__init__(image_path, metadata, target_ureg)
52
52
 
53
- self.image = cast(
53
+ self._image = cast(
54
54
  rio.DatasetReader,
55
- rio.open(self.image_path / "L1B.tif"),
55
+ rio.open(self.image_path / "L1B.tif", num_threads='16'),
56
56
  )
57
57
 
58
58
  self.data_tags = self.image.tags()
@@ -73,6 +73,12 @@ class Level1ABProduct(ProductBase[MetadataLevel1AB]):
73
73
  else:
74
74
  return f"{self.__class__.__name__} loaded from '{self.image_path}'"
75
75
 
76
+ @property
77
+ def image(self) -> rio.DatasetReader:
78
+ if self._image is None:
79
+ raise RuntimeError("Images has been released.")
80
+ return self._image
81
+
76
82
  def footprint(self, crs="") -> Polygon:
77
83
  """The product footprint as a Shapely polygon."""
78
84
  return image_footprint(self.image, crs)
@@ -130,8 +136,35 @@ class Level1ABProduct(ProductBase[MetadataLevel1AB]):
130
136
  """Explicitely closes the Rasterio DatasetReader and releases the memory of
131
137
  the `image` variable.
132
138
  """
133
- del self.image
134
- self.image = None
139
+ if self._image is not None:
140
+ self._image.close()
141
+ del self._image
142
+ self._image = None
143
+
144
+ def generate_metadata_file(self) -> None:
145
+ """Write the sidecar files next to the product."""
146
+ metadata_file_name = self.image_path.name + ".json"
147
+
148
+ with rio.open(self.image_path / "L1B.tif") as src:
149
+ shape = (src.height, src.width)
150
+ crs_epsg = src.crs.to_epsg()
151
+ geotransform = src.transform
152
+ gsd_w, gsd_h = src.res
153
+
154
+
155
+ with (self.image_path / metadata_file_name).open("w") as fh:
156
+ fh.write(
157
+ self.metadata.model_dump_json(
158
+ indent=2,
159
+ context={
160
+ "shape": shape,
161
+ "epsg": crs_epsg,
162
+ "transform": geotransform,
163
+ "gsd_w": gsd_w,
164
+ "gsd_h": gsd_h,
165
+ },
166
+ )
167
+ )
135
168
 
136
169
 
137
170
  class Level1CProduct(ProductBase[MetadataLevel1C]):
@@ -170,9 +203,9 @@ class Level1CProduct(ProductBase[MetadataLevel1C]):
170
203
  ) -> None:
171
204
  super().__init__(image_path, metadata, target_ureg)
172
205
 
173
- self.image = cast(
206
+ self._image = cast(
174
207
  rio.DatasetReader,
175
- rio.open(self.image_path / "L1C.tif"),
208
+ rio.open(self.image_path / "L1C.tif", num_threads='16'),
176
209
  )
177
210
  self.data_tags = self.image.tags()
178
211
 
@@ -193,6 +226,12 @@ class Level1CProduct(ProductBase[MetadataLevel1C]):
193
226
  else:
194
227
  return f"{self.__class__.__name__} loaded from '{self.image_path}'"
195
228
 
229
+ @property
230
+ def image(self) -> rio.DatasetReader:
231
+ if self._image is None:
232
+ raise RuntimeError("Images has been released.")
233
+ return self._image
234
+
196
235
  def footprint(self, crs="") -> Polygon:
197
236
  """The product footprint as a Shapely polygon."""
198
237
  return image_footprint(self.image, crs)
@@ -231,9 +270,35 @@ class Level1CProduct(ProductBase[MetadataLevel1C]):
231
270
  """Explicitely closes the Rasterio DatasetReader and releases the memory of
232
271
  the `image` variable.
233
272
  """
234
- self.image.close()
235
- del self.image
236
- self.image = None
273
+ if self._image is not None:
274
+ self._image.close()
275
+ del self._image
276
+ self._image = None
277
+
278
+ def generate_metadata_file(self) -> None:
279
+ """Write the sidecar files next to the product."""
280
+ metadata_file_name = self.image_path.name + ".json"
281
+
282
+ with rio.open(self.image_path / "L1C.tif") as src:
283
+ shape = (src.height, src.width)
284
+ crs_epsg = src.crs.to_epsg()
285
+ geotransform = src.transform
286
+ gsd_w, gsd_h = src.res
287
+
288
+
289
+ with (self.image_path / metadata_file_name).open("w") as fh:
290
+ fh.write(
291
+ self.metadata.model_dump_json(
292
+ indent=2,
293
+ context={
294
+ "shape": shape,
295
+ "epsg": crs_epsg,
296
+ "transform": geotransform,
297
+ "gsd_w": gsd_w,
298
+ "gsd_h": gsd_h,
299
+ },
300
+ )
301
+ )
237
302
 
238
303
 
239
304
  def generate_level_1_metafile():
@@ -47,9 +47,9 @@ class Level2AProduct(ProductBase[MetadataLevel2A]):
47
47
  ) -> None:
48
48
  super().__init__(image_path, metadata, target_ureg)
49
49
 
50
- self.image = cast(
50
+ self._image = cast(
51
51
  rio.DatasetReader,
52
- rio.open(self.image_path / "L2A.tif"),
52
+ rio.open(self.image_path / "L2A.tif", num_threads='16'),
53
53
  )
54
54
  self.data_tags = self.image.tags()
55
55
 
@@ -70,6 +70,12 @@ class Level2AProduct(ProductBase[MetadataLevel2A]):
70
70
  else:
71
71
  return f"{self.__class__.__name__} loaded from '{self.image_path}'"
72
72
 
73
+ @property
74
+ def image(self) -> rio.DatasetReader:
75
+ if self._image is None:
76
+ raise RuntimeError("Images has been released.")
77
+ return self._image
78
+
73
79
  def footprint(self, crs="") -> Polygon:
74
80
  """The product footprint as a Shapely polygon."""
75
81
  return image_footprint(self.image, crs)
@@ -108,9 +114,35 @@ class Level2AProduct(ProductBase[MetadataLevel2A]):
108
114
  """Explicitely closes the Rasterio DatasetReader and releases the memory of
109
115
  the `image` variable.
110
116
  """
111
- self.image.close()
112
- del self.image
113
- self.image = None
117
+ if self._image is not None:
118
+ self._image.close()
119
+ del self._image
120
+ self._image = None
121
+
122
+ def generate_metadata_file(self) -> None:
123
+ """Write the sidecar files next to the product."""
124
+ metadata_file_name = self.image_path.name + ".json"
125
+
126
+ with rio.open(self.image_path / "L2A.tif") as src:
127
+ shape = (src.height, src.width)
128
+ crs_epsg = src.crs.to_epsg()
129
+ geotransform = src.transform
130
+ gsd_w, gsd_h = src.res
131
+
132
+
133
+ with (self.image_path / metadata_file_name).open("w") as fh:
134
+ fh.write(
135
+ self.metadata.model_dump_json(
136
+ indent=2,
137
+ context={
138
+ "shape": shape,
139
+ "epsg": crs_epsg,
140
+ "transform": geotransform,
141
+ "gsd_w": gsd_w,
142
+ "gsd_h": gsd_h,
143
+ },
144
+ )
145
+ )
114
146
 
115
147
 
116
148
  def generate_level_2_metafile():
@@ -35,7 +35,7 @@ class ProductBase(Generic[TMetadata], metaclass=ABCMeta):
35
35
  def __init__(
36
36
  self,
37
37
  image_path: Path,
38
- metadata: MetadataBase | None = None,
38
+ metadata: TMetadata | None = None,
39
39
  target_ureg: UnitRegistry | None = None,
40
40
  ):
41
41
  self.image_path = Path(image_path)
@@ -1,22 +1,16 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: kuva-reader
3
- Version: 1.1.1
3
+ Version: 1.1.3
4
4
  Summary: Manipulate the Kuva Space image and metadata formats
5
- License: MIT
6
- Author: Guillem Ballesteros
7
- Author-email: guillem@kuvaspace.com
8
- Requires-Python: >=3.10,<=3.13
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Requires-Dist: kuva-geometry (>=1.0.1,<2.0.0)
15
- Requires-Dist: kuva-metadata (>=1.1.1,<2.0.0)
16
- Requires-Dist: numpy (>=1.26.4,<2.0.0)
17
- Requires-Dist: numpy-quaternion (>=2022.4.4,<2023.0.0)
18
- Requires-Dist: pint (>=0.22,<0.23)
19
- Requires-Dist: rasterio (>=1.4.1,<2.0.0)
5
+ Author-email: Guillem Ballesteros <guillem@kuvaspace.com>, Lennert Antson <lennert.antson@kuvaspace.com>, Arthur Vandenhoeke <arthur.vandenhoeke@kuvaspace.com>, Olli Eloranta <olli.eloranta@kuvaspace.com>
6
+ License-Expression: MIT
7
+ Requires-Python: <=3.13,>=3.10
8
+ Requires-Dist: kuva-geometry<2.0.0,>=1.0.1
9
+ Requires-Dist: kuva-metadata<2.0.0,>=1.1.1
10
+ Requires-Dist: numpy-quaternion>=2023.4.4
11
+ Requires-Dist: numpy>=1.26.4
12
+ Requires-Dist: pint<1.0.0,>=0.22
13
+ Requires-Dist: rasterio<2,>=1.4.3
20
14
  Description-Content-Type: text/markdown
21
15
 
22
16
  <div align="center">
@@ -128,4 +122,3 @@ The `kuva-reader` project software is under the [MIT license](https://github.com
128
122
  # Status of unit tests
129
123
 
130
124
  [![Unit tests for kuva-reader](https://github.com/KuvaSpace/kuva-data-processing/actions/workflows/test-kuva-reader.yml/badge.svg)](https://github.com/KuvaSpace/kuva-data-processing/actions/workflows/test-kuva-reader.yml)
131
-
@@ -0,0 +1,15 @@
1
+ kuva_reader/__init__.py,sha256=7OSXrTPW3RTjctJZqyGTekuHRb_5aQNJaG_c-KFac_s,1389
2
+ kuva_reader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ kuva_reader/reader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ kuva_reader/reader/image.py,sha256=rqzs5C7nzRArFfVepydRUECd3u55McTZlKINg76nMX4,785
5
+ kuva_reader/reader/level0.py,sha256=Dvf3I8Vv4UIFMd5DgR8JZx51zhjx4aKbt64TGYqXxk4,9761
6
+ kuva_reader/reader/level1.py,sha256=tTQBqzXK1Wna2s866gjHzsYKwJ0evAhaoKFXk0jHPBo,10584
7
+ kuva_reader/reader/level2.py,sha256=3SiD1lEPNi4mG7yR2omY9YkrPFbv-nxGFViuN2pig6U,5207
8
+ kuva_reader/reader/product_base.py,sha256=OuV69tm53j6terSWb7ViXDYkGeK5mWwcbfwIVuZqVg4,4296
9
+ kuva_reader/reader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ kuva_reader/reader/read.py,sha256=b5hGFbeJ-7sg-iilSJn29Hcqj4e7kiWT2S0BH2JwcDE,1761
11
+ kuva_reader/reader/utils.py,sha256=oZ1G43nm8lCxzfbdqBs0KhKaXWe_uf-78uBXWvmZigs,1566
12
+ kuva_reader-1.1.3.dist-info/METADATA,sha256=pDBBjplO1sTSq-_HOs-WQwjmPyUgb5Z-bX47XmbU-kk,4902
13
+ kuva_reader-1.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
+ kuva_reader-1.1.3.dist-info/entry_points.txt,sha256=KB_U0ziK5k7o8en_7lMtx3Jb1LRHhp39Wpt5MWbZuB0,152
15
+ kuva_reader-1.1.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ make-l0-meta = kuva_reader.reader.level0:generate_level_0_metafile
3
+ make-l1-meta = kuva_reader.reader.level1:generate_level_1_metafile
@@ -1,15 +0,0 @@
1
- kuva_reader/__init__.py,sha256=y0ViXqCoRSWvGPXEUFP9TOohcJIS24-WIarkZrDgcKs,1389
2
- kuva_reader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- kuva_reader/reader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- kuva_reader/reader/image.py,sha256=rqzs5C7nzRArFfVepydRUECd3u55McTZlKINg76nMX4,785
5
- kuva_reader/reader/level0.py,sha256=u61sKRXmx4uljlnqPfuLdtdEGfkw5NdtiR9N6XfUsrA,9352
6
- kuva_reader/reader/level1.py,sha256=HRvhSasDEzB03qJi6wrQiv-r9kSdWITuWIf-2IbYqX4,8355
7
- kuva_reader/reader/level2.py,sha256=kGd-6qTZXiNWuYwwLf_-UWS0Oeng8iTpeQFXtAfyPXA,4106
8
- kuva_reader/reader/product_base.py,sha256=4NpZQk3FvSPsN2kKde8lHJA_0Wwy6DQBMfOh4ItlO00,4299
9
- kuva_reader/reader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- kuva_reader/reader/read.py,sha256=b5hGFbeJ-7sg-iilSJn29Hcqj4e7kiWT2S0BH2JwcDE,1761
11
- kuva_reader/reader/utils.py,sha256=oZ1G43nm8lCxzfbdqBs0KhKaXWe_uf-78uBXWvmZigs,1566
12
- kuva_reader-1.1.1.dist-info/METADATA,sha256=RPbtVfnAl3B3uZ2gKpMJUj40CSAQuLKkqvWQ0vEnCZ0,5041
13
- kuva_reader-1.1.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
14
- kuva_reader-1.1.1.dist-info/entry_points.txt,sha256=YJysY9EChfOb1W_IEht2oE5Z8Y9jA0J6-kofaPv-NdI,149
15
- kuva_reader-1.1.1.dist-info/RECORD,,
@@ -1,4 +0,0 @@
1
- [console_scripts]
2
- make-l0-meta=kuva_reader.reader.level0:generate_level_0_metafile
3
- make-l1-meta=kuva_reader.reader.level1:generate_level_1_metafile
4
-