Source code for sertit.types

from collections.abc import Iterable
from pathlib import Path
from typing import Any

import geopandas as gpd
import numpy as np
import xarray as xr
from cloudpathlib import CloudPath
from shapely import MultiPolygon, Polygon

try:
    from rasterio.io import DatasetReader, DatasetWriter
except ModuleNotFoundError:  # pragma: no cover
    DatasetReader = Any
    DatasetWriter = Any

AnyPathType = CloudPath | Path
"""Any Path Type (derived from Pathlib and CloudpathLib)"""

AnyPathStrType = str | CloudPath | Path
"""Same as :code:`AnyPathType` but appened with :code:`str`"""

AnyXrDataStructure = xr.DataArray | xr.Dataset
"""Xarray's DataArray or Dataset"""

AnyNumpyArray = np.ndarray | np.ma.masked_array
"""Numpy array or masked array"""

AnyPolygonType = Polygon | MultiPolygon
"""Shapely Polygon or MultiPolygon"""

AnyRioDatasetType = DatasetReader | DatasetWriter
""" Any Rasterio Dataset Type (both Reader | Writer) """

AnyRasterType = (
    AnyPathStrType | tuple[AnyNumpyArray, dict] | AnyXrDataStructure | AnyRioDatasetType
)

"""
Any object potentially describing a raster:

- its path,
- its ``xarray`` representation (:class:`xarray:xarray.Dataset` or :class:`xarray:xarray.DataArray`),
- its ``rasterio`` representation (``DatasetReader`` or ``DatasetWriter``)
- or its array + metadata (``np.ndarray`` + dict)
"""

AnyVectorType = AnyPathStrType | gpd.GeoDataFrame
"""
Any object potentially describing a vector:

- its path,
- its :class:`geopandas:geopandas.GeoDataFrame`
"""


[docs] def is_iterable(obj: Any, str_allowed: bool = False): """ Is the object an iterable? Useful to replace this kind of code: >>> if isinstance(my_items, (list, tuple)): >>> do... by: >>> if is_iterable(my_items): >>> do... It allows not to forget checking for some iterables you aren't aware of. Args: obj (Any): Object to check str_allowed (bool): If set, strings are considered as iterable. If not, they are not considered as iterable. Returns: bool: True if the iobject is iterable Examples: >>> is_iterable((1, 2, 3)) True >>> is_iterable([1, 2, 3]) True >>> is_iterable({1, 2, 3}) True >>> is_iterable(np.array([1, 2, 3])) True >>> is_iterable("1, 2, 3") False >>> is_iterable("1, 2, 3", str_allowed=True) True >>> is_iterable(1) False >>> is_iterable(AnyPath("1, 2, 3")) False """ if isinstance(obj, str) and not str_allowed: return False else: return isinstance(obj, Iterable)
[docs] def make_iterable( obj: Any, str_allowed: bool = False, convert_none: bool = False ) -> list: """ Convert the object to a list if this object is not iterable Useful to replace this kind of code: >>> if to_convert is not None and not isinstance(to_convert, (list, tuple)): >>> to_convert = [to_convert] by: >>> to_convert = make_iterable(to_convert) or: >>> if isinstance(my_items, (list, tuple)): >>> first_item = my_items[0] >>> else: >>> first_item = my_items by: >>> first_item = make_iterable(to_convert)[0] Args: obj (Any): Object to check str_allowed (bool): If set, strings are considered as iterable. If not, they are not considered as iterable. convert_none (bool): If true, if obj is None, then it won't be converted into a list. By default, Nones are not converted to list. Returns: list: Object as an iterable Examples: >>> make_interable((1, 2, 3)) (1, 2, 3) >>> make_interable([1, 2, 3]) [1, 2, 3] >>> make_interable({1, 2, 3}) {1, 2, 3} >>> make_interable(np.array([1, 2, 3])) np.array([1, 2, 3]) >>> make_interable("1, 2, 3", str_allowed=True) "1, 2, 3" >>> make_interable("1, 2, 3", str_allowed=False) ["1, 2, 3"] >>> make_interable(1) [1] >>> make_interable(AnyPath("1, 2, 3")) [AnyPath("1, 2, 3")] >>> make_interable(None) None >>> make_interable(None, convert_none=True) [None] """ if (convert_none and obj is None) or not is_iterable(obj, str_allowed): obj = [obj] return obj