Skip to content

XarrayReader/Reader conflicting parameters  #4

@vincentsarago

Description

@vincentsarago

with rasterio.Env(**env):
with self.reader(
url=api_params["api_url"],
headers=api_params.get("headers", {}),
tms=tms,
reader_options={**reader_params},
**backend_params,
) as src_dst:
if MOSAIC_STRICT_ZOOM and (
z < src_dst.minzoom or z > src_dst.maxzoom
):
raise HTTPException(
400,
f"Invalid ZOOM level {z}. Should be between {src_dst.minzoom} and {src_dst.maxzoom}",
)
image, assets = src_dst.tile(
x,
y,
z,
search_query=search_query,
tilesize=scale * 256,
pixel_selection=pixel_selection,
threads=MOSAIC_THREADS,
**tile_params,
**layer_params,
**dataset_params,
)

recap:

In titiler-pgstac/stacfastapi tilers we have 3 levels of reader. One to access the Mosaic (backend), one to access the Item and then a last one to access the data itself.

  • backend: pgstac or stacapi mosaic backend, will merge request to different item reader
  • reader (item): STAC item reader, will merge request to different asset reader
  • reader (asset): Xarray or Raster dataset reader

Dependency unpacking issue

Most of the dependencies are defined using DefaultDependency which is then unpacked (**dep) within the endpoints. This worked well because usually all the asset's reader are all the same, and thus when we define the reader in the backend we know which options can be passed. The issue we have right now, is that both rio_tiler.io.xarray.XarrayReader and rio_tiler.io.rasterio.Reader are quite different and we are trying to use them within the same tiler factory, so it's really hard because we now have set of QueryParameters which can be passed to one reader but not the other (e.g the variable init xarray reader parameter).

# titiler.core.dependencies. DefaultDependency
@dataclass
class DefaultDependency:
    """Dataclass with dict unpacking"""

    def keys(self):
        """Return Keys."""
        return self.__dict__.keys()

    def __getitem__(self, key):
        """Return value."""
        return self.__dict__[key]

class dep(DefaultDependency):
    value: str = Query("value")
    value2: str = Query("value2")

@get("/yo")
def yo(params=Depends(dep):
    return func(**params)
  • backend.reader.reader_options (L203), will get values from reader_params defined with reader_dependency.

The reader_options is then forwarded to the Asset's reader

with self.reader(item, tms=self.tms, **self.reader_options) as src_dst:

It default to DefaultDependency so nothing will be passed to the Asset reader. But for XarrayReader we will want to have variable (and more https://github.com/developmentseed/titiler-xarray/blob/dev/titiler/xarray/factory.py#L84-L121).

If we create a dependency like

class dep(DefaultDependency):
    variable: Optional[str] = Query(None)

⚠️ This will pass variable=None to the rasterio Reader and errors because variable= is not a Rasterio's reader option.

⚠️ buffer and padding options are not available in the XarrayReader.tile method (https://github.com/cogeotiff/rio-tiler/blob/main/rio_tiler/io/xarray.py#L200-L210)

  • layer_params (L223), defined with layer_dependency and default to AssetsBidxExprParams (defined in the Factory). This will be used both by the Item's reader (assets=["asset1"]) and the Asset's reader (asset_bidx=["asset1|1,2,3"])

⚠️ indexes option is not in the XarrayReader.tile method (https://github.com/cogeotiff/rio-tiler/blob/main/rio_tiler/io/xarray.py#L200-L210)

  • dataset_params (L224), defined with dataset_dependency and default to DatasetParams. This will be forwarded to the asset's reader

⚠️ unscale option is not in the XarrayReader.tile method

Solution

To avoid conflicting parameters to be passed, we are proposing a change in titiler developmentseed/titiler#819

This PR will change the way we pass the dependency values to the reader method, by not using unpacking but a new .kwargs method which will only pass values not set to None (e.g variable= will only be passed if set by the user).

This doesn't avoid parameter conflict because the endpoint has not idea which asset's reader will be used (because it will be defined dynamically within the Item's reader).

If you read this line, consider yourself a titiler expert now 🙏

cc @abarciauskas-bgse

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions