def test_label_classes(self) -> None: # Get label_item = pystac.Item.from_file(self.label_example_1_uri) label_classes = LabelExtension.ext(label_item).label_classes self.assertEqual(len(get_opt(label_classes)), 2) self.assertEqual(get_opt(label_classes)[1].classes, ["three", "four"]) # Set new_classes = [ LabelClasses.create(name="label2", classes=["five", "six"]), LabelClasses.create(name="label", classes=["seven", "eight"]), ] label_ext = LabelExtension.ext(label_item) label_ext.label_classes = new_classes self.assertEqual( [ class_name for lc in label_item.properties["label:classes"] for class_name in lc["classes"] ], ["five", "six", "seven", "eight"], ) self.assertListEqual([lc.name for lc in label_ext.label_classes], ["label2", "label"]) first_lc = label_ext.label_classes[0] self.assertEqual("<ClassObject classes=five,six>", first_lc.__repr__()) label_item.validate()
def test_merge_label_overviews_empty_counts(self) -> None: # Right side is empty overview_1 = LabelOverview.create( property_key="label", counts=[ LabelCount.create(name="water", count=25), LabelCount.create(name="land", count=17), ], ) overview_2 = LabelOverview.create( property_key="label", counts=None, ) merged_overview_1 = overview_1.merge_counts(overview_2) expected_counts = [c.to_dict() for c in get_opt(overview_1.counts)] actual_counts = [ c.to_dict() for c in get_opt(merged_overview_1.counts) ] self.assertListEqual(expected_counts, actual_counts) # Left side is empty merged_overview_2 = overview_2.merge_counts(overview_1) expected_counts = [c.to_dict() for c in get_opt(overview_1.counts)] actual_counts = [ c.to_dict() for c in get_opt(merged_overview_2.counts) ] self.assertEqual(expected_counts, actual_counts)
def test_null_datetime(self) -> None: item = pystac.Item.from_file( TestCases.get_path("data-files/item/sample-item.json")) with self.assertRaises(pystac.STACError): Item( "test", geometry=item.geometry, bbox=item.bbox, datetime=None, properties={}, ) null_dt_item = Item( "test", geometry=item.geometry, bbox=item.bbox, datetime=None, properties={ "start_datetime": datetime_to_str(get_opt(item.datetime)), "end_datetime": datetime_to_str(get_opt(item.datetime)), }, ) null_dt_item.validate()
def test_common_metadata_providers(self) -> None: x = self.ITEM_2.clone() providers_dict_list: List[Dict[str, Any]] = [{ "name": "CoolSat", "roles": ["producer", "licensor"], "url": "https://cool-sat.com/", }] providers_object_list = [ Provider.from_dict(d) for d in providers_dict_list ] example_providers_dict_list: List[Dict[str, Any]] = [ { "name": "ExampleProvider_1", "roles": ["example_role_1", "example_role_2"], "url": "https://exampleprovider1.com/", }, { "name": "ExampleProvider_2", "roles": ["example_role_1", "example_role_2"], "url": "https://exampleprovider2.com/", }, ] example_providers_object_list = [ Provider.from_dict(d) for d in example_providers_dict_list ] for i in range(len(utils.get_opt(x.common_metadata.providers))): p1 = utils.get_opt(x.common_metadata.providers)[i] p2 = providers_object_list[i] self.assertIsInstance(p1, Provider) self.assertIsInstance(p2, Provider) self.assertDictEqual(p1.to_dict(), p2.to_dict()) pd1 = x.properties["providers"][i] pd2 = providers_dict_list[i] self.assertIsInstance(pd1, dict) self.assertIsInstance(pd2, dict) self.assertDictEqual(pd1, pd2) x.common_metadata.providers = example_providers_object_list for i in range(len(x.common_metadata.providers)): p1 = x.common_metadata.providers[i] p2 = example_providers_object_list[i] self.assertIsInstance(p1, Provider) self.assertIsInstance(p2, Provider) self.assertDictEqual(p1.to_dict(), p2.to_dict()) pd1 = x.properties["providers"][i] pd2 = example_providers_dict_list[i] self.assertIsInstance(pd1, dict) self.assertIsInstance(pd2, dict) self.assertDictEqual(pd1, pd2)
def test_asset_bands(self) -> None: item = pystac.Item.from_file(self.LANDSAT_EXAMPLE_URI) # Get b1_asset = item.assets["B1"] asset_bands = EOExtension.ext(b1_asset).bands assert asset_bands is not None self.assertEqual(len(asset_bands), 1) self.assertEqual(asset_bands[0].name, "B1") self.assertEqual(asset_bands[0].solar_illumination, 2000) index_asset = item.assets["index"] asset_bands = EOExtension.ext(index_asset).bands self.assertIs(None, asset_bands) # No asset specified item_bands = EOExtension.ext(item).bands self.assertIsNot(None, item_bands) # Set b2_asset = item.assets["B2"] self.assertEqual(get_opt(EOExtension.ext(b2_asset).bands)[0].name, "B2") EOExtension.ext(b2_asset).bands = EOExtension.ext(b1_asset).bands new_b2_asset_bands = EOExtension.ext(item.assets["B2"]).bands self.assertEqual(get_opt(new_b2_asset_bands)[0].name, "B1") item.validate() # Check adding a new asset new_bands = [ Band.create( name="red", description=Band.band_description("red"), solar_illumination=1900, ), Band.create( name="green", description=Band.band_description("green"), solar_illumination=1950, ), Band.create( name="blue", description=Band.band_description("blue"), solar_illumination=2000, ), ] asset = pystac.Asset(href="some/path.tif", media_type=pystac.MediaType.GEOTIFF) EOExtension.ext(asset).bands = new_bands item.add_asset("test", asset) self.assertEqual(len(item.assets["test"].extra_fields["eo:bands"]), 3)
def test_from_file(self) -> None: label_example_1 = Item.from_file(self.label_example_1_uri) overviews = get_opt( LabelExtension.ext(label_example_1).label_overviews) self.assertEqual(len(get_opt(overviews[0].counts)), 2) label_example_1.validate() label_example_2 = Item.from_file(self.label_example_2_uri) overviews2 = get_opt( LabelExtension.ext(label_example_2).label_overviews) self.assertEqual(len(get_opt(overviews2[0].counts)), 2) label_example_2.validate()
def statistics(self) -> Optional[Statistics]: """Get or sets the average spatial resolution (in meters) of the pixels in the band. Returns: [Statistics] """ return Statistics.from_dict(get_opt(self.properties.get("statistics")))
def test_wkt2(self) -> None: proj_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("proj:wkt2", proj_item.properties) proj_wkt2 = ProjectionExtension.ext(proj_item).wkt2 self.assertEqual(proj_wkt2, proj_item.properties["proj:wkt2"]) # Set ProjectionExtension.ext(proj_item).wkt2 = WKT2 self.assertEqual(WKT2, proj_item.properties["proj:wkt2"]) # Get from Asset asset_no_prop = proj_item.assets["B1"] asset_prop = proj_item.assets["B8"] self.assertEqual( ProjectionExtension.ext(asset_no_prop).wkt2, ProjectionExtension.ext(proj_item).wkt2, ) self.assertTrue( "TEST_TEXT" in get_opt(ProjectionExtension.ext(asset_prop).wkt2) ) # Set to Asset asset_value = "TEST TEXT 2" ProjectionExtension.ext(asset_no_prop).wkt2 = asset_value self.assertNotEqual( ProjectionExtension.ext(asset_no_prop).wkt2, ProjectionExtension.ext(proj_item).wkt2, ) self.assertEqual(ProjectionExtension.ext(asset_no_prop).wkt2, asset_value) # Validate proj_item.validate()
def test_merge_label_overviews(self) -> None: overview_1 = LabelOverview.create( property_key="label", counts=[ LabelCount.create(name="water", count=25), LabelCount.create(name="land", count=17), ], ) overview_2 = LabelOverview.create( property_key="label", counts=[ LabelCount.create(name="water", count=10), LabelCount.create(name="unknown", count=4), ], ) merged_overview = overview_1.merge_counts(overview_2) merged_counts = get_opt(merged_overview.counts) water_count = next(c for c in merged_counts if c.name == "water") land_count = next(c for c in merged_counts if c.name == "land") unknown_count = next(c for c in merged_counts if c.name == "unknown") self.assertEqual(35, water_count.count) self.assertEqual(17, land_count.count) self.assertEqual(4, unknown_count.count)
def histogram(self) -> Optional[Histogram]: """Get or sets the histogram distribution information of the pixels values in the band Returns: [Histogram] """ return Histogram.from_dict(get_opt(self.properties.get("histogram")))
def test_reads_asset_bands_in_pre_1_0_version(self) -> None: item = pystac.Item.from_file( TestCases.get_path( "data-files/examples/0.9.0/item-spec/examples/" "landsat8-sample.json" ) ) bands = EOExtension.ext(item.assets["B9"]).bands self.assertEqual(len(bands or []), 1) self.assertEqual(get_opt(bands)[0].common_name, "cirrus")
def test_validate_error_contains_href(self) -> None: # Test that the exception message contains the HREF of the object if available. cat = TestCases.test_case_1() item = cat.get_item("area-1-1-labels", recursive=True) assert item is not None assert item.get_self_href() is not None item.geometry = {"type": "INVALID"} with self.assertRaises(pystac.STACValidationError): try: item.validate() except pystac.STACValidationError as e: self.assertTrue(get_opt(item.get_self_href()) in str(e)) raise e
def test_merge(self) -> None: cat1 = create_catalog(1, include_href=False) cat2 = create_catalog(2) cat3 = create_catalog(3, include_href=False) cat4 = create_catalog(4) identical_cat1 = create_catalog(1, include_href=False) identical_cat2 = create_catalog(2) cached_ids_1: Dict[str, Any] = {cat1.id: cat1} cached_hrefs_1: Dict[str, Any] = {get_opt(cat2.get_self_href()): cat2} cached_ids_2: Dict[str, Any] = {cat3.id: cat3, cat1.id: identical_cat1} cached_hrefs_2: Dict[str, Any] = { get_opt(cat4.get_self_href()): cat4, get_opt(cat2.get_self_href()): identical_cat2, } cache1 = ResolvedObjectCollectionCache( ResolvedObjectCache(), cached_ids=cached_ids_1, cached_hrefs=cached_hrefs_1 ) cache2 = ResolvedObjectCollectionCache( ResolvedObjectCache(), cached_ids=cached_ids_2, cached_hrefs=cached_hrefs_2 ) merged = ResolvedObjectCollectionCache.merge( ResolvedObjectCache(), cache1, cache2 ) self.assertEqual( set(merged.cached_ids.keys()), set([cat.id for cat in [cat1, cat3]]) ) self.assertIs(merged.get_by_id(cat1.id), cat1) self.assertEqual( set(merged.cached_hrefs.keys()), set([cat.get_self_href() for cat in [cat2, cat4]]), ) self.assertIs(merged.get_by_href(get_opt(cat2.get_self_href())), cat2)
def test_published(self) -> None: timestamps_item = pystac.Item.from_file(self.example_uri) # Get self.assertIn("published", timestamps_item.properties) timestamps_published = TimestampsExtension.ext( timestamps_item).published self.assertIsInstance(timestamps_published, datetime) self.assertEqual( datetime_to_str(get_opt(timestamps_published)), timestamps_item.properties["published"], ) # Set TimestampsExtension.ext( timestamps_item).published = self.sample_datetime self.assertEqual(self.sample_datetime_str, timestamps_item.properties["published"]) # Get from Asset asset_no_prop = timestamps_item.assets["red"] asset_prop = timestamps_item.assets["blue"] self.assertEqual( TimestampsExtension.ext(asset_no_prop).published, TimestampsExtension.ext(timestamps_item).published, ) self.assertEqual( TimestampsExtension.ext(asset_prop).published, str_to_datetime("2018-11-02T00:00:00Z"), ) # # Set to Asset asset_value = str_to_datetime("2019-02-02T00:00:00Z") TimestampsExtension.ext(asset_no_prop).published = asset_value self.assertNotEqual( TimestampsExtension.ext(asset_no_prop).published, TimestampsExtension.ext(timestamps_item).published, ) self.assertEqual( TimestampsExtension.ext(asset_no_prop).published, asset_value) # Validate timestamps_item.validate()
def test_validate_all(self) -> None: for test_case in TestCases.all_test_catalogs(): catalog_href = test_case.get_self_href() if catalog_href is not None: stac_dict = pystac.StacIO.default().read_json(catalog_href) pystac.validation.validate_all(stac_dict, catalog_href) # Modify a 0.8.1 collection in a catalog to be invalid with a # since-renamed extension and make sure it catches the validation error. with tempfile.TemporaryDirectory() as tmp_dir: dst_dir = os.path.join(tmp_dir, "catalog") # Copy test case 7 to the temporary directory catalog_href = get_opt(TestCases.test_case_7().get_self_href()) shutil.copytree(os.path.dirname(catalog_href), dst_dir) new_cat_href = os.path.join(dst_dir, "catalog.json") # Make sure it's valid before modification pystac.validation.validate_all( pystac.StacIO.default().read_json(new_cat_href), new_cat_href) # Modify a contained collection to add an extension for which the # collection is invalid. with open(os.path.join(dst_dir, "acc/collection.json"), encoding="utf-8") as f: col = json.load(f) col["stac_extensions"] = ["asset"] with open(os.path.join(dst_dir, "acc/collection.json"), "w", encoding="utf-8") as f: json.dump(col, f) stac_dict = pystac.StacIO.default().read_json(new_cat_href) with self.assertRaises(pystac.STACValidationError): pystac.validation.validate_all(stac_dict, new_cat_href)
def test_label_overviews(self) -> None: # Get label_item = pystac.Item.from_file(self.label_example_1_uri) label_ext = LabelExtension.ext(label_item) label_overviews = get_opt(label_ext.label_overviews) label_item2 = pystac.Item.from_file(self.label_example_2_uri) label_ext2 = LabelExtension.ext(label_item2) label_overviews2 = get_opt(label_ext2.label_overviews) self.assertEqual(len(label_overviews), 2) self.assertEqual(label_overviews[1].property_key, "label-reg") self.assertEqual(label_overviews2[1].property_key, None) # Raster label_counts = get_opt(label_overviews[0].counts) self.assertEqual(label_counts[1].count, 17) first_overview_counts = get_opt(label_ext.label_overviews)[0].counts assert first_overview_counts is not None first_overview_counts[1].count = 18 self.assertEqual( label_item.properties["label:overviews"][0]["counts"][1]["count"], 18) self.assertEqual(first_overview_counts[1].name, "two") label_statistics = get_opt(label_overviews[1].statistics) self.assertEqual(label_statistics[0].name, "mean") second_overview_statistics = get_opt( label_ext.label_overviews)[1].statistics assert second_overview_statistics is not None second_overview_statistics[0].name = "avg" self.assertEqual( label_item.properties["label:overviews"][1]["statistics"][0] ["name"], "avg") # Set new_overviews = [ LabelOverview.create( property_key="label2", counts=[ LabelCount.create(name="one", count=1), LabelCount.create(name="two", count=1), ], ), LabelOverview.create( property_key="label-reg", statistics=[ LabelStatistics.create(name="min", value=0.1), LabelStatistics.create(name="max", value=1.0), ], ), ] label_ext.label_overviews = new_overviews self.assertEqual( [(count["name"], count["count"]) for count in label_item.properties["label:overviews"][0]["counts"] ], [("one", 1), ("two", 1)], ) self.assertEqual( [(count["name"], count["value"]) for count in label_item.properties["label:overviews"][1]["statistics"]], [("min", 0.1), ("max", 1.0)], ) label_item.validate()
def test_asset_bands(self) -> None: item = pystac.Item.from_file(self.PLANET_EXAMPLE_URI) item2 = pystac.Item.from_file(self.SENTINEL2_EXAMPLE_URI) # Get data_asset = item.assets["data"] asset_bands = RasterExtension.ext(data_asset).bands assert asset_bands is not None self.assertEqual(len(asset_bands), 4) self.assertEqual(asset_bands[0].nodata, 0) self.assertEqual(asset_bands[0].sampling, Sampling.AREA) self.assertEqual(asset_bands[0].unit, "W⋅sr−1⋅m−2⋅nm−1") self.assertEqual(asset_bands[0].data_type, DataType.UINT16) self.assertEqual(asset_bands[0].scale, 0.01) self.assertEqual(asset_bands[0].offset, 0) self.assertEqual(asset_bands[0].spatial_resolution, 3) band0_stats = asset_bands[0].statistics assert band0_stats is not None self.assertEqual(band0_stats.minimum, 1962) self.assertEqual(band0_stats.maximum, 32925) self.assertEqual(band0_stats.mean, 8498.9400644319) self.assertEqual(band0_stats.stddev, 5056.1292002722) self.assertEqual(band0_stats.valid_percent, 61.09) band0_hist = asset_bands[0].histogram assert band0_hist is not None self.assertEqual(band0_hist.count, 256) self.assertEqual(band0_hist.min, 1901.288235294118) self.assertEqual(band0_hist.max, 32985.71176470588) self.assertEqual(len(band0_hist.buckets), band0_hist.count) index_asset = item.assets["metadata"] asset_bands = RasterExtension.ext(index_asset).bands self.assertIs(None, asset_bands) b09_asset = item2.assets["B09"] b09_bands = RasterExtension.ext(b09_asset).bands assert b09_bands is not None self.assertEqual(b09_bands[0].nodata, "nan") # Set b2_asset = item2.assets["B02"] self.assertEqual( get_opt( get_opt(RasterExtension.ext(b2_asset).bands) [0].statistics).maximum, 19264, ) b1_asset = item2.assets["B01"] RasterExtension.ext(b2_asset).bands = RasterExtension.ext( b1_asset).bands new_b2_asset_bands = RasterExtension.ext(item2.assets["B02"]).bands self.assertEqual( get_opt(get_opt(new_b2_asset_bands)[0].statistics).maximum, 20567) new_b2_asset_band0 = get_opt(new_b2_asset_bands)[0] new_b2_asset_band0.nodata = NoDataStrings.INF item2.validate() # Check adding a new asset new_stats = [ Statistics.create(minimum=0, maximum=10000, mean=5000, stddev=10, valid_percent=88), Statistics.create(minimum=-1, maximum=1, mean=0, stddev=1, valid_percent=100), Statistics.create(minimum=1, maximum=255, mean=200, stddev=3, valid_percent=100), ] # new_histograms = [] with open(self.GDALINFO_EXAMPLE_URI) as gdaljson_file: gdaljson_data = json.load(gdaljson_file) new_histograms = list( map( lambda band: Histogram.from_dict(band["histogram"]), gdaljson_data["bands"], )) new_bands = [ RasterBand.create( nodata=1, unit="test1", statistics=new_stats[0], histogram=new_histograms[0], ), RasterBand.create( nodata=2, unit="test2", statistics=new_stats[1], histogram=new_histograms[1], ), RasterBand.create( nodata=NoDataStrings.NINF, unit="test3", statistics=new_stats[2], histogram=new_histograms[2], ), ] asset = pystac.Asset(href="some/path.tif", media_type=pystac.MediaType.GEOTIFF) RasterExtension.ext(asset).bands = new_bands item.add_asset("test", asset) self.assertEqual(len(item.assets["test"].extra_fields["raster:bands"]), 3) self.assertEqual( item.assets["test"].extra_fields["raster:bands"][1]["statistics"] ["minimum"], -1, ) self.assertEqual( item.assets["test"].extra_fields["raster:bands"][1]["histogram"] ["min"], 3848.354901960784, ) self.assertEqual( item.assets["test"].extra_fields["raster:bands"][2]["nodata"], "-inf") for s in new_stats: s.minimum = None s.maximum = None s.mean = None s.stddev = None s.valid_percent = None self.assertEqual(len(s.properties), 0) for b in new_bands: b.bits_per_sample = None b.data_type = None b.histogram = None b.nodata = None b.sampling = None b.scale = None b.spatial_resolution = None b.statistics = None b.unit = None b.offset = None self.assertEqual(len(b.properties), 0) new_stats[2].apply(minimum=0, maximum=10000, mean=5000, stddev=10, valid_percent=88) new_stats[1].apply(minimum=-1, maximum=1, mean=0, stddev=1, valid_percent=100) new_stats[0].apply(minimum=1, maximum=255, mean=200, stddev=3, valid_percent=100) new_bands[2].apply( nodata=1, unit="test1", statistics=new_stats[2], histogram=new_histograms[0], ) new_bands[1].apply( nodata=2, unit="test2", statistics=new_stats[1], histogram=new_histograms[1], ) new_bands[0].apply( nodata=NoDataStrings.NAN, unit="test3", statistics=new_stats[0], histogram=new_histograms[2], ) RasterExtension.ext(item.assets["test"]).apply(new_bands) self.assertEqual( item.assets["test"].extra_fields["raster:bands"][0]["statistics"] ["minimum"], 1, ) self.assertEqual( item.assets["test"].extra_fields["raster:bands"][0]["nodata"], "nan")