|
36 | 36 | from datacube.drivers.postgres._fields import PgDocField, RangeDocField
|
37 | 37 |
|
38 | 38 | from datacube.index import Index
|
39 |
| -from datacube.model import DatasetType, Field, MetadataType |
| 39 | +from datacube.model import DatasetType, Field, MetadataType, Dataset |
40 | 40 |
|
41 | 41 | _LOG = structlog.get_logger()
|
42 | 42 |
|
@@ -527,7 +527,9 @@ def __init__(
|
527 | 527 | units_label: str = "regions"
|
528 | 528 |
|
529 | 529 | @classmethod
|
530 |
| - def for_product(cls, dt: DatasetType, region_shapes: Dict[str, GeometryCollection]): |
| 530 | + def for_product( |
| 531 | + cls, dt: DatasetType, region_shapes: Dict[str, GeometryCollection] = None |
| 532 | + ): |
531 | 533 | region_code_field: Field = dt.metadata_type.dataset_fields.get("region_code")
|
532 | 534 | grid_spec = dt.grid_spec
|
533 | 535 | # Ingested grids trump the "region_code" field because they've probably sliced it up smaller.
|
@@ -557,7 +559,23 @@ def geojson_extent(self, region_code):
|
557 | 559 | "properties": {"region_code": region_code},
|
558 | 560 | }
|
559 | 561 |
|
| 562 | + def dataset_region_code(self, dataset: Dataset) -> Optional[str]: |
| 563 | + """ |
| 564 | + Get the region code for a dataset. |
| 565 | +
|
| 566 | + This should always give the same result as the alchemy_expression() function, |
| 567 | + but is computed in pure python. |
| 568 | +
|
| 569 | + Classes that override alchemy_expression should override this to match. |
| 570 | + """ |
| 571 | + return dataset.metadata.region_code |
| 572 | + |
560 | 573 | def alchemy_expression(self):
|
| 574 | + """ |
| 575 | + Get an alchemy expression that computes dataset's region code |
| 576 | +
|
| 577 | + Classes that override this should also override dataset_region_code to match. |
| 578 | + """ |
561 | 579 | dt = self.product
|
562 | 580 | region_code_field: Field = dt.metadata_type.dataset_fields.get("region_code")
|
563 | 581 | # `alchemy_expression` is part of the postgres driver (PgDocField),
|
@@ -625,6 +643,21 @@ def alchemy_expression(self):
|
625 | 643 | func.floor((func.ST_Y(center_point) - origin_y) / size_y).cast(String),
|
626 | 644 | )
|
627 | 645 |
|
| 646 | + def dataset_region_code(self, dataset: Dataset) -> Optional[str]: |
| 647 | + tiles = [ |
| 648 | + tile |
| 649 | + for tile, _ in dataset.type.grid_spec.tiles( |
| 650 | + dataset.extent.centroid.boundingbox |
| 651 | + ) |
| 652 | + ] |
| 653 | + if not len(tiles) == 1: |
| 654 | + raise ValueError( |
| 655 | + "Tiled dataset should only have one tile? " |
| 656 | + f"Got {tiles!r} for {dataset!r}" |
| 657 | + ) |
| 658 | + x, y = tiles[0] |
| 659 | + return f"{x}_{y}" |
| 660 | + |
628 | 661 |
|
629 | 662 | def _from_xy_region_code(region_code: str):
|
630 | 663 | """
|
@@ -676,6 +709,19 @@ def alchemy_expression(self):
|
676 | 709 | else_=path_field.lower.alchemy_expression.cast(String),
|
677 | 710 | )
|
678 | 711 |
|
| 712 | + def dataset_region_code(self, dataset: Dataset) -> Optional[str]: |
| 713 | + path_range = dataset.metadata.fields["sat_path"] |
| 714 | + row_range = dataset.metadata.fields["sat_row"] |
| 715 | + if row_range is None and path_range is None: |
| 716 | + return None |
| 717 | + |
| 718 | + # If it's just one scene? Include it specifically |
| 719 | + if row_range[0] == row_range[1]: |
| 720 | + return f"{path_range[0]}_{row_range[1]}" |
| 721 | + # Otherwise it's a range of rows, so we say the whole path. |
| 722 | + else: |
| 723 | + return f"{path_range[0]}" |
| 724 | + |
679 | 725 |
|
680 | 726 | def _region_code_field(dt: DatasetType):
|
681 | 727 | """
|
|
0 commit comments