pystac icon indicating copy to clipboard operation
pystac copied to clipboard

Automatically modifying STAC objects using a custom `StacIO`

Open bmcandr opened this issue 7 months ago • 1 comments

Following up from this discussion in the STAC Gitter. I created this issue for a discussion on the topic of ~automatically modifying STAC objects read with pystac a la pystac_client's support for automatically modifying results.


It is possible to define a custom StacIO class that overrides the StacIO.stac_object_from_dict method to pass the deserialized STAC object to a modifier function (e.g., planetary_computer.sign_inplace) before returning it:

from functools import wraps

import planetary_computer
import pystac
from pystac.stac_io import DefaultStacIO, StacIO

# Define custom StacIO that overrides stac_object_from_dict to pass StacObject to signing modifier
class PCStacIO(DefaultStacIO):
    @wraps(StacIO.stac_object_from_dict)
    def stac_object_from_dict(
        self,
        *args,
        **kwargs,
    ) -> pystac.STACObject:
        return planetary_computer.sign_inplace(
            super().stac_object_from_dict(*args, **kwargs)
        )


# Usage:

item_href = "https://planetarycomputer.microsoft.com/api/stac/v1/collections/sentinel-2-l2a/items/S2B_MSIL2A_20240723T205029_R057_T16XDN_20240723T231445"

item = pystac.read_file(
    item_href,
    stac_io=PCStacIO(),  # pass instance of PCStacIO
)

# Asset HREFs have been signed
print(item.assets)

# Alternatively, set PCStacIO as default StacIO
StacIO.set_default(PCStacIO)

item = pystac.read_file(item_href)

print(item.assets)

When I wrote the custom StacIO class I naively expected that the pystac.Item.from_file would use the StacIO.stac_object_from_dict method, but that is not the case. Invoking the modifier requires reading the STAC objects with the pystac.read_file method. This is because the pystac.STACObject.from_file methods do not rely on StacIO.stac_object_from_dict (in fact the latter relies on the former).

Thinking "out loud" about how to enable the pystac.STACObject.from_file... add a _modifier class variable that is a Callable[[Modifiable], STACObject] and have the STACObject.from_file methods optionally apply the _modifier if it is set? I don't love it...

That said, it's not clear whether there is any demand for enabling this functionality when using the pystac.read_file or separately and explicitly passing STAC objects to a modifier function approaches work just as well. Using the from_file approach would appease mypy w/o the need for casting, but that's a pretty minor DevX nit tbh. Maybe this example is informative enough for the docs?

All feedback is welcome.

bmcandr avatar Jul 25 '24 18:07 bmcandr