# Path: mapchete/io/_path.py
# def fs_from_path(path, timeout=5, session=None, username=None, password=None, **kwargs):
#     """Guess fsspec FileSystem from path and initialize using the desired options."""
#     if path.startswith("s3://"):
#         return fsspec.filesystem(
#             "s3",
#             requester_pays=os.environ.get("AWS_REQUEST_PAYER") == "requester",
#             config_kwargs=dict(connect_timeout=timeout, read_timeout=timeout),
#             session=session,
#             client_kwargs=kwargs,
#         )
#     elif path.startswith(("http://", "https://")):
#         if username:  # pragma: no cover
#             from aiohttp import BasicAuth
# 
#             auth = BasicAuth(username, password)
#         else:
#             auth = None
#         return fsspec.filesystem("https", auth=auth, asynchronous=False, **kwargs)
#     else:
#         return fsspec.filesystem("file", asynchronous=False, **kwargs)
# 
# def tiles_exist(
#     config=None,
#     output_tiles=None,
#     output_tiles_batches=None,
#     process_tiles=None,
#     process_tiles_batches=None,
#     **kwargs,
# ):
#     """
#     Yield tiles and whether their output already exists or not.
# 
#     Either "output_tiles" or "process_tiles" have to be provided.
# 
#     The S3 part of the function are loosely inspired by
#     https://alexwlchan.net/2019/07/listing-s3-keys/
# 
#     Parameters
#     ----------
#     config : mapchete.config.MapcheteConfig
#     process_tiles : iterator
# 
#     Yields
#     ------
#     tuple : (tile, exists)
#     """
#     if (
#         sum(
#             [
#                 0 if t is None else 1
#                 for t in [
#                     output_tiles,
#                     output_tiles_batches,
#                     process_tiles,
#                     process_tiles_batches,
#                 ]
#             ]
#         )
#         != 1
#     ):  # pragma: no cover
#         raise ValueError(
#             "exactly one of 'output_tiles', 'output_tiles_batches', 'process_tiles' or 'process_tiles_batches' is allowed"
#         )
# 
#     basepath = config.output_reader.path
# 
#     # for single file outputs:
#     if basepath.endswith(config.output_reader.file_extension):
# 
#         def _exists(tile):
#             return (
#                 tile,
#                 config.output_reader.tiles_exist(
#                     **{"process_tile" if process_tiles else "output_tile": tile}
#                 ),
#             )
# 
#         def _tiles():
#             if process_tiles or output_tiles:  # pragma: no cover
#                 yield from process_tiles or output_tiles
#             else:
#                 for batch in process_tiles_batches or output_tiles_batches:
#                     yield from batch
# 
#         for tile in _tiles():
#             yield _exists(tile=tile)
# 
#     # for tile directory outputs:
#     elif process_tiles:
#         logger.debug("sort process tiles by row, this could take a while")
#         process_tiles_batches = _batch_tiles_by_row(process_tiles)
#     elif output_tiles:
#         logger.debug("sort output tiles by row, this could take a while")
#         output_tiles_batches = _batch_tiles_by_row(output_tiles)
# 
#     if process_tiles_batches:
#         yield from _process_tiles_batches_exist(process_tiles_batches, config)
#     elif output_tiles_batches:
#         yield from _output_tiles_batches_exist(output_tiles_batches, config)


import logging
import mapchete
from typing import Callable, List, Tuple, Union
from rasterio.crs import CRS
from shapely.geometry.base import BaseGeometry
from mapchete.io import fs_from_path, tiles_exist
    """

    def _empty_callback(*_):
        pass

    msg_callback = msg_callback or _empty_callback
    fs_opts = fs_opts or {}
    if zoom is None:  # pragma: no cover
        raise ValueError("zoom level(s) required")

    fs = fs_from_path(tiledir, **fs_opts)

    with mapchete.open(
        tiledir,
        zoom=zoom,
        area=area,
        area_crs=area_crs,
        bounds=bounds,
        bounds_crs=bounds_crs,
        fs=fs,
        fs_kwargs=fs_opts,
        mode="readonly",
    ) as mp:
        tp = mp.config.output_pyramid

        tiles = {}
        for zoom in mp.config.init_zoom_levels:
            tiles[zoom] = []
            # check which source tiles exist
            logger.debug("looking for existing source tiles in zoom %s...", zoom)

# Path: mapchete/io/_path.py
# def fs_from_path(path, timeout=5, session=None, username=None, password=None, **kwargs):
#     """Guess fsspec FileSystem from path and initialize using the desired options."""
#     if path.startswith("s3://"):
#         return fsspec.filesystem(
#             "s3",
#             requester_pays=os.environ.get("AWS_REQUEST_PAYER") == "requester",
#             config_kwargs=dict(connect_timeout=timeout, read_timeout=timeout),
#             session=session,
#             client_kwargs=kwargs,
#         )
#     elif path.startswith(("http://", "https://")):
#         if username:  # pragma: no cover
#             from aiohttp import BasicAuth
# 
#             auth = BasicAuth(username, password)
#         else:
#             auth = None
#         return fsspec.filesystem("https", auth=auth, asynchronous=False, **kwargs)
#     else:
#         return fsspec.filesystem("file", asynchronous=False, **kwargs)
# 
# def tiles_exist(
#     config=None,
#     output_tiles=None,
#     output_tiles_batches=None,
#     process_tiles=None,
#     process_tiles_batches=None,
#     **kwargs,
# ):
#     """
#     Yield tiles and whether their output already exists or not.
# 
#     Either "output_tiles" or "process_tiles" have to be provided.
# 
#     The S3 part of the function are loosely inspired by
#     https://alexwlchan.net/2019/07/listing-s3-keys/
# 
#     Parameters
#     ----------
#     config : mapchete.config.MapcheteConfig
#     process_tiles : iterator
# 
#     Yields
#     ------
#     tuple : (tile, exists)
#     """
#     if (
#         sum(
#             [
#                 0 if t is None else 1
#                 for t in [
#                     output_tiles,
#                     output_tiles_batches,
#                     process_tiles,
#                     process_tiles_batches,
#                 ]
#             ]
#         )
#         != 1
#     ):  # pragma: no cover
#         raise ValueError(
#             "exactly one of 'output_tiles', 'output_tiles_batches', 'process_tiles' or 'process_tiles_batches' is allowed"
#         )
# 
#     basepath = config.output_reader.path
# 
#     # for single file outputs:
#     if basepath.endswith(config.output_reader.file_extension):
# 
#         def _exists(tile):
#             return (
#                 tile,
#                 config.output_reader.tiles_exist(
#                     **{"process_tile" if process_tiles else "output_tile": tile}
#                 ),
#             )
# 
#         def _tiles():
#             if process_tiles or output_tiles:  # pragma: no cover
#                 yield from process_tiles or output_tiles
#             else:
#                 for batch in process_tiles_batches or output_tiles_batches:
#                     yield from batch
# 
#         for tile in _tiles():
#             yield _exists(tile=tile)
# 
#     # for tile directory outputs:
#     elif process_tiles:
#         logger.debug("sort process tiles by row, this could take a while")
#         process_tiles_batches = _batch_tiles_by_row(process_tiles)
#     elif output_tiles:
#         logger.debug("sort output tiles by row, this could take a while")
#         output_tiles_batches = _batch_tiles_by_row(output_tiles)
# 
#     if process_tiles_batches:
#         yield from _process_tiles_batches_exist(process_tiles_batches, config)
#     elif output_tiles_batches:
#         yield from _output_tiles_batches_exist(output_tiles_batches, config)


# Path: mapchete/commands/_rm.py
import logging
import mapchete
from typing import Callable, List, Tuple, Union
from rasterio.crs import CRS
from shapely.geometry.base import BaseGeometry
from mapchete.io import fs_from_path, tiles_exist

    """

    def _empty_callback(*_):
        pass

    msg_callback = msg_callback or _empty_callback
    fs_opts = fs_opts or {}
    if zoom is None:  # pragma: no cover
        raise ValueError("zoom level(s) required")

    fs = fs_from_path(tiledir, **fs_opts)

    with mapchete.open(
        tiledir,
        zoom=zoom,
        area=area,
        area_crs=area_crs,
        bounds=bounds,
        bounds_crs=bounds_crs,
        fs=fs,
        fs_kwargs=fs_opts,
        mode="readonly",
    ) as mp:
        tp = mp.config.output_pyramid

        tiles = {}
        for zoom in mp.config.init_zoom_levels:
            tiles[zoom] = []
            # check which source tiles exist
            logger.debug("looking for existing source tiles in zoom %s...", zoom)

            for tile, exists in tiles_exist(