Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove GDAL's Python bindings #222

Merged
merged 5 commits into from
Jan 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Use [pytest](https://docs.pytest.org/) for unit testing instead of `unittest` ([#220](https://github.com/stac-utils/stactools/pull/220))
- Signature of `stactools.core.utils.convert.cogify` ([#222](https://github.com/stac-utils/stactools/pull/222))

### Removed

- GDAL Python bindings dependency ([#222](https://github.com/stac-utils/stactools/pull/222))

## [0.2.5] - 2022-01-03

Expand Down
9 changes: 4 additions & 5 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,15 @@ packages = find_namespace:
zip_safe = False
include_package_data = True
install_requires =
pystac[validation] ~= 1.2
Shapely ~= 1.7
aiohttp ~= 3.7
click ~= 8.0
fsspec ~= 2021.7
requests ~= 2.25
Shapely ~= 1.7
lxml ~= 4.6
pyproj ~= 3.0
pystac[validation] ~= 1.2
rasterio ~= 1.2
lxml ~= 4.6
GDAL ~= 3.3.2
requests ~= 2.25

[options.extras_require]
all =
Expand Down
48 changes: 26 additions & 22 deletions src/stactools/core/addraster.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import logging
from typing import List

from osgeo import gdal
import numpy
from pystac import Item
from pystac.utils import make_absolute_href
from pystac.extensions.raster import (DataType, Histogram, RasterBand,
RasterExtension, Statistics)
import rasterio

logger = logging.getLogger(__name__)

NUM_BUCKETS = 256
BINS = 256


def add_raster_to_item(item: Item) -> Item:
Expand All @@ -25,27 +27,29 @@ def add_raster_to_item(item: Item) -> Item:
for asset in item.assets.values():
if asset.roles and "data" in asset.roles:
raster = RasterExtension.ext(asset)
bands = []
href = make_absolute_href(asset.href, item.get_self_href())
dataset = gdal.Open(href, gdal.GA_ReadOnly)
for nband in range(dataset.RasterCount):
gdal_band = dataset.GetRasterBand(nband + 1)
band = RasterBand.create()
band.nodata = gdal_band.GetNoDataValue()
band.spatial_resolution = dataset.GetGeoTransform()[1]
band.data_type = DataType(
gdal.GetDataTypeName(gdal_band.DataType).lower())
minimum = gdal_band.GetMinimum()
maximum = gdal_band.GetMaximum()
if not minimum or not max:
minimum, maximum = gdal_band.ComputeRasterMinMax(True)
band.statistics = Statistics.create(minimum=minimum,
maximum=maximum)
hist_data = gdal_band.GetHistogram(minimum, maximum,
NUM_BUCKETS)
band.histogram = Histogram.create(NUM_BUCKETS, minimum,
maximum, hist_data)
bands.append(band)
bands = _read_bands(href)
if bands:
raster.apply(bands)
return item


def _read_bands(href: str) -> List[RasterBand]:
bands = []
with rasterio.open(href) as dataset:
for (i, index) in enumerate(dataset.indexes):
data = dataset.read(index, masked=True)
band = RasterBand.create()
band.nodata = dataset.nodatavals[i]
band.spatial_resolution = dataset.transform[0]
band.data_type = DataType(dataset.dtypes[i])
minimum = float(numpy.min(data)) # type: ignore
maximum = float(numpy.max(data)) # type: ignore
gadomski marked this conversation as resolved.
Show resolved Hide resolved
band.statistics = Statistics.create(minimum=minimum,
maximum=maximum)
hist_data, _ = numpy.histogram( # type: ignore
gadomski marked this conversation as resolved.
Show resolved Hide resolved
data, range=(minimum, maximum), bins=BINS)
band.histogram = Histogram.create(BINS, minimum, maximum,
hist_data.tolist())
bands.append(band)
return bands
38 changes: 20 additions & 18 deletions src/stactools/core/utils/convert.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
from typing import List, Optional
from typing import Dict, Any, Optional

from stactools.core.utils.subprocess import call
from stactools.core.utils import gdal_driver_is_enabled
import rasterio
import rasterio.shutil
from rasterio.errors import DriverRegistrationError

DEFAULT_COGIFY_ARGS = ["-co", "compress=deflate"]
from stactools.core import utils

DEFAULT_PROFILE = {
"compress": "deflate",
"driver": "COG",
"blocksize": 512,
}


def cogify(infile: str,
outfile: str,
args: Optional[List[str]] = None,
extra_args: Optional[List[str]] = None) -> int:
profile: Optional[Dict[str, Any]] = None) -> None:
"""Creates a COG from a GDAL-readable file."""
if not gdal_driver_is_enabled("COG"):
raise Exception(
"GDAL's COG driver is not enabled. "
"Please make sure your GDAL version is 3.1 or greater.")
if args is None:
args = DEFAULT_COGIFY_ARGS[:]
args = ["gdal_translate", "-of", "COG"] + args
if extra_args:
args.extend(extra_args)
args.append(infile)
args.append(outfile)
return call(args)
if not utils.gdal_driver_is_enabled("COG"):
raise DriverRegistrationError(
"GDAL's COG driver is not enabled, make sure you're using GDAL >= 3.1"
)
destination_profile = DEFAULT_PROFILE.copy()
if profile:
destination_profile.update(profile)
rasterio.shutil.copy(infile, outfile, **destination_profile)
8 changes: 4 additions & 4 deletions tests/cli/commands/expected/rasterbands.json
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@
0,
0,
1,
2
3
]
}
},
Expand Down Expand Up @@ -539,7 +539,7 @@
2,
7,
7,
7
8
]
}
},
Expand Down Expand Up @@ -811,7 +811,7 @@
0,
1,
1,
2
3
]
}
},
Expand Down Expand Up @@ -1083,7 +1083,7 @@
0,
1,
0,
0
1
]
}
}
Expand Down
4 changes: 3 additions & 1 deletion tests/cli/commands/test_addraster.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ def test_add_raster_to_item(self):
asset = item.get_assets().get("analytic")
assert asset is not None
expected = expected_json("rasterbands.json")
assert expected == asset.to_dict().get("raster:bands")
self.maxDiff = None
for a, b in zip(expected, asset.to_dict().get("raster:bands")):
self.assertDictEqual(a, b)
gadomski marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 2 additions & 8 deletions tests/core/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,9 @@ def test_default(self):
self.assertEqual(dataset.compression,
rasterio.enums.Compression.deflate)

def test_override_default(self):
with self.cogify(args=["-co", "compress=lzw"]) as outfile:
def test_profile(self):
with self.cogify(profile={"compress": "lzw"}) as outfile:
self.assertTrue(os.path.exists(outfile))
with rasterio.open(outfile) as dataset:
self.assertEqual(dataset.compression,
rasterio.enums.Compression.lzw)

def test_extra_args(self):
with self.cogify(
extra_args=["-mo", "TIFFTAG_ARTIST=prince"]) as outfile:
with rasterio.open(outfile) as dataset:
self.assertEqual(dataset.tags()["TIFFTAG_ARTIST"], "prince")
gadomski marked this conversation as resolved.
Show resolved Hide resolved