diff --git a/planet/cli/subscriptions.py b/planet/cli/subscriptions.py index 7884247f..b267f448 100644 --- a/planet/cli/subscriptions.py +++ b/planet/cli/subscriptions.py @@ -518,6 +518,18 @@ def request(name, @click.option('--time-range-type', type=click.Choice(["acquired", "published"]), help="Subscribe by acquisition time or time of publication.") +@click.option( + '--geometry-relation', + type=click.Choice(["intersects", "contains", "within"]), + help= # noqa: E251 + ('\b\n' + 'The relationship between the subscription geometry and the item geometry.\n' + 'intersects (default): Returns items whose footprint geometry partially or \n' + 'fully overlaps with the subscription geometry.\n' + 'contains: Returns items where the footprint geometry fully encloses the \n' + 'subscription geometry.\n' + 'within: Returns items whose entire footprint geometry is fully contained \n' + 'within the subscription geometry.')) @pretty def request_catalog(item_types, asset_types, @@ -528,6 +540,7 @@ def request_catalog(item_types, filter, publishing_stages, time_range_type, + geometry_relation, pretty): """Generate a subscriptions request catalog source description.""" @@ -540,7 +553,8 @@ def request_catalog(item_types, rrule=rrule, filter=filter, publishing_stages=publishing_stages, - time_range_type=time_range_type) + time_range_type=time_range_type, + geometry_relation=geometry_relation) echo_json(res, pretty) diff --git a/planet/subscription_request.py b/planet/subscription_request.py index ae5dbf19..ab53136e 100644 --- a/planet/subscription_request.py +++ b/planet/subscription_request.py @@ -169,6 +169,8 @@ def catalog_source( "standard", "finalized"]]] = None, time_range_type: Optional[Literal["acquired", "published"]] = None, + geometry_relation: Optional[Literal["intersects", "contains", + "within"]] = None, ) -> dict: """Construct a Catalog subscription source. @@ -195,6 +197,10 @@ def catalog_source( publishing_stages: A sequence of one or more of the values "preview", "standard", or "finalized". time_range_type: "acquired" (new in 2.1.0) or "published". + geometry_relation: The relationship between the subscription geometry and the item geometry. + 'intersects' (default): Returns items whose footprint geometry partially or fully overlaps with the subscription geometry. + 'contains': Returns items where the footprint geometry fully encloses the AOI. + 'within': Returns items whose entire footprint geometry is fully contained within the AOI. Returns: dict: a representation of a subscription source. @@ -270,6 +276,9 @@ def catalog_source( if time_range_type: parameters['time_range_type'] = time_range_type + if geometry_relation: + parameters['geometry_relation'] = geometry_relation + return {"parameters": parameters} diff --git a/tests/integration/test_subscriptions_cli.py b/tests/integration/test_subscriptions_cli.py index f40ce048..acafc652 100644 --- a/tests/integration/test_subscriptions_cli.py +++ b/tests/integration/test_subscriptions_cli.py @@ -487,6 +487,27 @@ def test_catalog_source_time_range_type(mock_bundles, assert req['parameters']['time_range_type'] == time_range_type +@pytest.mark.parametrize("geometry_relation", + ["intersects", "contains", "within"]) +def test_catalog_source_geometry_relation(mock_bundles, + invoke, + geom_geojson, + geometry_relation): + """Catalog source geometry relation is configured.""" + result = invoke([ + 'request-catalog', + '--item-types=PSScene', + '--asset-types=ortho_analytic_4b', + f"--geometry={json.dumps(geom_geojson)}", + '--start-time=2021-03-01T00:00:00', + f'--geometry-relation={geometry_relation}', + ]) + + assert result.exit_code == 0 # success. + req = json.loads(result.output) + assert req['parameters']['geometry_relation'] == geometry_relation + + @pytest.mark.parametrize( "hosting_option, collection_id_option, configuration_option, expected_success", [ diff --git a/tests/unit/test_subscription_request.py b/tests/unit/test_subscription_request.py index d7661e11..49393c0b 100644 --- a/tests/unit/test_subscription_request.py +++ b/tests/unit/test_subscription_request.py @@ -617,6 +617,20 @@ def test_catalog_source_time_range_type_acquired(geom_geojson, mock_bundles): assert source["parameters"]["time_range_type"] == "acquired" +@respx.mock +def test_catalog_source_geometry_relation_contains(geom_geojson, mock_bundles): + """Configure 'contains' geometry relation for a catalog source.""" + source = subscription_request.catalog_source( + item_types=["PSScene"], + asset_types=["ortho_analytic_4b"], + start_time=datetime(2021, 3, 1), + geometry_relation="contains", + geometry=geom_geojson, + ) + + assert source["parameters"]["geometry_relation"] == "contains" + + def test_cloud_filter_tool_success(): res = subscription_request.cloud_filter_tool( clear_percent=subscription_request.FilterValue(gte=90),