Source code for shapelib.core.handlers.geopackage_handler

from pathlib import Path
from typing import Any

import fiona
import geopandas as gpd
from geopandas import GeoDataFrame

from shapelib.core.geometries.base import BaseShapes
from shapelib.core.handlers.geo_file_handler import GeoFileHandler
from shapelib.factories.registry import register_handler


[docs] @register_handler(file_extension=".gpkg") class GeopackageHandler(GeoFileHandler): """ A handler for GeoPackage (.gpkg) format. This class provides functionality for reading and validating GeoPackage files using the GeoPandas library and GDAL for additional checks. Attributes ---------- driver : str The GDAL driver used for handling GeoPackage files ("GPKG"). extension : str The file extension associated with GeoPackage files (".gpkg"). Methods ------- __init__(path) Initializes the handler with a given GeoPackage path. validate_file() Validates the GeoPackage to ensure it exists, is non-empty, and can be opened by GDAL. load_data(**kwargs) -> GeoDataFrame Loads the GeoPackage as a GeoDataFrame. create_obj(**kwargs) -> BaseShapes Creates and returns an appropriate geometry object based on the contents of the GeoPackage. """ driver: str = "GPKG" extension: str = ".gpkg" def __init__(self, path: Path) -> None: """ Initialize the GeopackageHandler with a given .gpkg file path. Parameters ---------- path : Path The path to the GeoPackage (.gpkg) file to be processed. Raises ------ FileNotFoundError If the .gpkg file does not exist or is not a valid file. ValueError If the file is empty or GDAL cannot recognize it as a GeoPackage. """ super().__init__(path) self.validate_file()
[docs] def validate_file(self) -> None: """ Validate the GeoPackage file to ensure it exists, is non-empty, and can be opened by GDAL. This method checks whether the file is empty based on file size and then tries to open the file with GDAL to confirm it is a valid GeoPackage. Raises ------ ValueError If the file is empty or cannot be recognized as a GeoPackage by GDAL. GDALException If GDAL encounters an error opening the file. """ try: layers = fiona.listlayers(self.path) if not layers: print(f"GeoPackage '{self.path.name}' has no layers.") except Exception as e: raise ValueError( f"Could not open the GeoPackage: {self.path.as_posix()}\n" f"Ensure the file is a valid .gpkg and not corrupted. ({e})" ) from e
[docs] def load_data(self, **kwargs: Any) -> GeoDataFrame: """ Load the GeoPackage using GeoPandas. Parameters ---------- **kwargs : dict of str, Any Additional keyword arguments to pass to :func:`geopandas.read_file`. For example, `layer="layer_name"` if the GeoPackage has multiple layers. Returns ------- GeoDataFrame The loaded GeoDataFrame from the GeoPackage. """ return gpd.read_file(self.path, **kwargs)
[docs] def create_obj(self, **kwargs: Any) -> BaseShapes: """ Create an object representing the GeoPackage's geometries based on the most common geometry type. This method uses ``create_appropriate_obj`` from the base class to generate Polygons, Lines, Points, or an Empty geometry object. Parameters ---------- **kwargs : dict of str, Any Additional keyword arguments passed to :meth:`load_data`. Returns ------- BaseShapes An instance of one of the geometry classes (Polygons, Lines, Points, or Empty), depending on the most common geometry type in the GeoPackage's data. """ data = self.load_data(**kwargs) return self.create_geometry_instance(data=data, driver=self.driver)