geometamaker 0.2.0__tar.gz → 0.2.1__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.
- {geometamaker-0.2.0 → geometamaker-0.2.1}/.github/workflows/test.yml +1 -1
- {geometamaker-0.2.0 → geometamaker-0.2.1}/HISTORY.rst +10 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/PKG-INFO +3 -3
- {geometamaker-0.2.0 → geometamaker-0.2.1}/pyproject.toml +2 -2
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker/geometamaker.py +23 -8
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker.egg-info/PKG-INFO +3 -3
- {geometamaker-0.2.0 → geometamaker-0.2.1}/tests/test_geometamaker.py +29 -5
- {geometamaker-0.2.0 → geometamaker-0.2.1}/.readthedocs.yml +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/LICENSE.txt +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/README.md +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/Makefile +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/environment-rtd.yml +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/make.bat +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/archive_resource.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/basic_usage.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/collection_resource.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/conf.py +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/index.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/installation.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/metadata_resources.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/profile.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/raster_resource.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/table_resource.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/docs/source/vector_resource.rst +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/requirements.txt +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/setup.cfg +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker/__init__.py +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker/cli.py +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker/config.py +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker/models.py +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker/utils.py +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker.egg-info/SOURCES.txt +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker.egg-info/dependency_links.txt +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker.egg-info/entry_points.txt +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker.egg-info/requires.txt +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/src/geometamaker.egg-info/top_level.txt +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/tests/data/0.1.2/vector.geojson +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/tests/data/0.1.2/vector.geojson.yml +0 -0
- {geometamaker-0.2.0 → geometamaker-0.2.1}/tests/test_migrations.py +0 -0
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
Release History
|
|
2
2
|
===============
|
|
3
3
|
|
|
4
|
+
0.2.1 (2026-02-02)
|
|
5
|
+
------------------
|
|
6
|
+
* Make sure that the option to compute band statistics will include
|
|
7
|
+
STATISTICS_VALID_PERCENT. https://github.com/natcap/geometamaker/issues/106
|
|
8
|
+
* Improve the error message if frictionless raises an exception while
|
|
9
|
+
trying to detect a filetype.
|
|
10
|
+
https://github.com/natcap/geometamaker/issues/107
|
|
11
|
+
* Fixed bug where non-ascii characters in filepaths raised an exception
|
|
12
|
+
in ``describe``. https://github.com/natcap/geometamaker/issues/112
|
|
13
|
+
|
|
4
14
|
0.2.0 (2025-07-22)
|
|
5
15
|
------------------
|
|
6
16
|
* Allow CLI to ``describe`` remote datasets.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: geometamaker
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: metadata creation for geospatial data
|
|
5
|
-
Maintainer: Natural Capital
|
|
5
|
+
Maintainer: Natural Capital Alliance Software Team
|
|
6
6
|
License:
|
|
7
7
|
Apache License
|
|
8
8
|
Version 2.0, January 2004
|
|
@@ -215,11 +215,11 @@ Classifier: Operating System :: MacOS :: MacOS X
|
|
|
215
215
|
Classifier: Operating System :: Microsoft
|
|
216
216
|
Classifier: Operating System :: POSIX
|
|
217
217
|
Classifier: Programming Language :: Python :: 3
|
|
218
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
219
218
|
Classifier: Programming Language :: Python :: 3.10
|
|
220
219
|
Classifier: Programming Language :: Python :: 3.11
|
|
221
220
|
Classifier: Programming Language :: Python :: 3.12
|
|
222
221
|
Classifier: Programming Language :: Python :: 3.13
|
|
222
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
223
223
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
224
224
|
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
225
225
|
Requires-Python: >=3.9
|
|
@@ -5,7 +5,7 @@ readme = "README.md"
|
|
|
5
5
|
requires-python = ">=3.9"
|
|
6
6
|
license = {file = "LICENSE.txt"}
|
|
7
7
|
maintainers = [
|
|
8
|
-
{name = "Natural Capital
|
|
8
|
+
{name = "Natural Capital Alliance Software Team"}
|
|
9
9
|
]
|
|
10
10
|
keywords = ["gis", "geospatial", "metadata"]
|
|
11
11
|
classifiers = [
|
|
@@ -17,11 +17,11 @@ classifiers = [
|
|
|
17
17
|
"Operating System :: Microsoft",
|
|
18
18
|
"Operating System :: POSIX",
|
|
19
19
|
"Programming Language :: Python :: 3",
|
|
20
|
-
"Programming Language :: Python :: 3.9",
|
|
21
20
|
"Programming Language :: Python :: 3.10",
|
|
22
21
|
"Programming Language :: Python :: 3.11",
|
|
23
22
|
"Programming Language :: Python :: 3.12",
|
|
24
23
|
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
25
|
"License :: OSI Approved :: Apache Software License",
|
|
26
26
|
"Topic :: Scientific/Engineering :: GIS"
|
|
27
27
|
]
|
|
@@ -39,6 +39,12 @@ PROTOCOLS = [
|
|
|
39
39
|
DT_FMT = '%Y-%m-%d %H:%M:%S %Z'
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
def _gdal_progress_callback(complete, message, data):
|
|
43
|
+
percentage = complete * 100
|
|
44
|
+
if (percentage > 0) & (percentage % 5 == 0):
|
|
45
|
+
LOGGER.info(f'{message} {percentage}%')
|
|
46
|
+
|
|
47
|
+
|
|
42
48
|
# TODO: In the future we can remove these exception managers in favor of the
|
|
43
49
|
# builtin gdal.ExceptionMgr. It was released in 3.7.0 and debugged in 3.9.1.
|
|
44
50
|
# https://github.com/OSGeo/gdal/blob/v3.9.3/NEWS.md#gdalogr-391-release-notes
|
|
@@ -203,7 +209,10 @@ def detect_file_type(filepath, scheme):
|
|
|
203
209
|
# We'll likely want a different data model for multi-dimensional arrays.
|
|
204
210
|
# Frictionless supports a wide range of formats. The quickest way to
|
|
205
211
|
# determine if a file is recognized as a table or archive is to call list.
|
|
206
|
-
|
|
212
|
+
try:
|
|
213
|
+
info = frictionless.list(filepath)[0]
|
|
214
|
+
except frictionless.FrictionlessException:
|
|
215
|
+
raise RuntimeError(f'Cannot detect file type of "{filepath}"')
|
|
207
216
|
if info.type == 'table':
|
|
208
217
|
return 'table'
|
|
209
218
|
# Frictionless doesn't recognize .tgz compression (but does recognize .tar.gz)
|
|
@@ -259,7 +268,7 @@ def describe_file(source_dataset_path, scheme):
|
|
|
259
268
|
hash_func = hashlib.new('sha256')
|
|
260
269
|
hash_func.update(
|
|
261
270
|
f'{description["bytes"]}{description["last_modified"]}\
|
|
262
|
-
{description["path"]}'.encode('
|
|
271
|
+
{description["path"]}'.encode('utf-8'))
|
|
263
272
|
description['uid'] = f'sizetimestamp:{hash_func.hexdigest()}'
|
|
264
273
|
|
|
265
274
|
# We don't have a use for including these attributes in our metadata:
|
|
@@ -388,18 +397,24 @@ def describe_raster(source_dataset_path, scheme, **kwargs):
|
|
|
388
397
|
for i in range(info['n_bands']):
|
|
389
398
|
b = i + 1
|
|
390
399
|
band = raster.GetRasterBand(b)
|
|
400
|
+
band_gdal_metadata = band.GetMetadata()
|
|
391
401
|
if compute_stats:
|
|
392
402
|
try:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
403
|
+
if not 'STATISTICS_VALID_PERCENT' in band_gdal_metadata:
|
|
404
|
+
# Sometimes some stats exist, but not all. If this one doesn't,
|
|
405
|
+
# it's important enough that we want to force computation.
|
|
406
|
+
_ = band.ComputeStatistics(0, callback=_gdal_progress_callback)
|
|
407
|
+
else:
|
|
408
|
+
# 0=do not approximate stats, 1=calculate if they don't exist
|
|
409
|
+
# If exact stats exist they will be retrieved without
|
|
410
|
+
# computing them, otherwise, this forces computation.
|
|
411
|
+
# https://github.com/OSGeo/gdal/blob/master/gcore/gdalrasterband.cpp
|
|
412
|
+
_ = band.GetStatistics(0, 1)
|
|
413
|
+
band_gdal_metadata = band.GetMetadata()
|
|
398
414
|
except RuntimeError as e:
|
|
399
415
|
LOGGER.warning(
|
|
400
416
|
f'Could not compute statistics for band {b} of '
|
|
401
417
|
f'{source_dataset_path}: {e}')
|
|
402
|
-
band_gdal_metadata = band.GetMetadata()
|
|
403
418
|
|
|
404
419
|
bands.append(models.BandSchema(
|
|
405
420
|
index=b,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: geometamaker
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: metadata creation for geospatial data
|
|
5
|
-
Maintainer: Natural Capital
|
|
5
|
+
Maintainer: Natural Capital Alliance Software Team
|
|
6
6
|
License:
|
|
7
7
|
Apache License
|
|
8
8
|
Version 2.0, January 2004
|
|
@@ -215,11 +215,11 @@ Classifier: Operating System :: MacOS :: MacOS X
|
|
|
215
215
|
Classifier: Operating System :: Microsoft
|
|
216
216
|
Classifier: Operating System :: POSIX
|
|
217
217
|
Classifier: Programming Language :: Python :: 3
|
|
218
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
219
218
|
Classifier: Programming Language :: Python :: 3.10
|
|
220
219
|
Classifier: Programming Language :: Python :: 3.11
|
|
221
220
|
Classifier: Programming Language :: Python :: 3.12
|
|
222
221
|
Classifier: Programming Language :: Python :: 3.13
|
|
222
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
223
223
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
224
224
|
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
225
225
|
Requires-Python: >=3.9
|
|
@@ -59,11 +59,11 @@ def create_vector(target_filepath, field_map=None, driver='GEOJSON'):
|
|
|
59
59
|
|
|
60
60
|
def create_raster(
|
|
61
61
|
numpy_dtype, target_path,
|
|
62
|
-
pixel_size=(1, 1), projection_epsg=4326,
|
|
62
|
+
pixel_size=(1, 1), raster_size=(2, 2), projection_epsg=4326,
|
|
63
63
|
origin=(0, 0), n_bands=2, define_nodata=True):
|
|
64
64
|
driver_name, creation_options = DEFAULT_GTIFF_CREATION_TUPLE_OPTIONS
|
|
65
65
|
raster_driver = gdal.GetDriverByName(driver_name)
|
|
66
|
-
|
|
66
|
+
nx, ny = raster_size
|
|
67
67
|
gdal_type = gdal_array.NumericTypeCodeToGDALTypeCode(numpy_dtype)
|
|
68
68
|
raster = raster_driver.Create(
|
|
69
69
|
target_path, nx, ny, n_bands, gdal_type)
|
|
@@ -78,7 +78,7 @@ def create_raster(
|
|
|
78
78
|
if projection_wkt is not None:
|
|
79
79
|
raster.SetProjection(projection_wkt)
|
|
80
80
|
|
|
81
|
-
base_array = numpy.full((
|
|
81
|
+
base_array = numpy.full((nx, ny), 1, dtype=numpy_dtype)
|
|
82
82
|
|
|
83
83
|
target_nodata = pygeoprocessing.choose_nodata(numpy_dtype)
|
|
84
84
|
|
|
@@ -96,7 +96,8 @@ class GeometamakerTests(unittest.TestCase):
|
|
|
96
96
|
|
|
97
97
|
def setUp(self):
|
|
98
98
|
"""Override setUp function to create temp workspace directory."""
|
|
99
|
-
self.workspace_dir = tempfile.mkdtemp(
|
|
99
|
+
self.workspace_dir = tempfile.mkdtemp(
|
|
100
|
+
suffix='\U0001f60e') # ensure unicode support
|
|
100
101
|
self.patcher = patch('geometamaker.config.platformdirs.user_config_dir')
|
|
101
102
|
self.mock_user_config_dir = self.patcher.start()
|
|
102
103
|
self.mock_user_config_dir.return_value = self.workspace_dir
|
|
@@ -315,11 +316,34 @@ class GeometamakerTests(unittest.TestCase):
|
|
|
315
316
|
'STATISTICS_VALID_PERCENT': '100'})
|
|
316
317
|
|
|
317
318
|
def test_describe_raster_band_compute_statistics(self):
|
|
318
|
-
"""Test band statistics will be
|
|
319
|
+
"""Test band statistics will be computed if they do not already exist."""
|
|
320
|
+
import geometamaker
|
|
321
|
+
|
|
322
|
+
datasource_path = os.path.join(self.workspace_dir, 'raster.tif')
|
|
323
|
+
create_raster(numpy.int16, datasource_path, n_bands=1)
|
|
324
|
+
|
|
325
|
+
resource = geometamaker.describe(datasource_path, compute_stats=True)
|
|
326
|
+
self.assertEqual(
|
|
327
|
+
resource.data_model.bands[0].gdal_metadata,
|
|
328
|
+
{'STATISTICS_MINIMUM': '1',
|
|
329
|
+
'STATISTICS_MAXIMUM': '1',
|
|
330
|
+
'STATISTICS_MEAN': '1',
|
|
331
|
+
'STATISTICS_STDDEV': '0',
|
|
332
|
+
'STATISTICS_VALID_PERCENT': '100'})
|
|
333
|
+
|
|
334
|
+
def test_describe_raster_band_compute_statistics_valid_percent(self):
|
|
335
|
+
"""Test band statistics will be computed if VALID_PERCENT is missing."""
|
|
319
336
|
import geometamaker
|
|
320
337
|
|
|
321
338
|
datasource_path = os.path.join(self.workspace_dir, 'raster.tif')
|
|
322
339
|
create_raster(numpy.int16, datasource_path, n_bands=1)
|
|
340
|
+
raster = gdal.OpenEx(datasource_path)
|
|
341
|
+
band = raster.GetRasterBand(1)
|
|
342
|
+
# Deliberately set stats metadata that do not include VALID_PERCENT
|
|
343
|
+
band.SetMetadataItem('STATISTICS_MINIMUM', '1')
|
|
344
|
+
band.SetMetadataItem('STATISTICS_MAXIMUM', '1')
|
|
345
|
+
band.SetMetadataItem('STATISTICS_MEAN', '1')
|
|
346
|
+
band.SetMetadataItem('STATISTICS_STDDEV', '0')
|
|
323
347
|
|
|
324
348
|
resource = geometamaker.describe(datasource_path, compute_stats=True)
|
|
325
349
|
self.assertEqual(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|