Source code for laser_measles.demographics.base
from collections import defaultdict
from pathlib import Path
from typing import Protocol
import polars as pl
from pydantic import BaseModel
from pydantic import field_validator
from shapefile import Reader
[docs]
class DemographicsGeneratorProtocol(Protocol):
[docs]
    def generate_population(self) -> pl.DataFrame: ... 
[docs]
    def generate_birth_rates(self) -> pl.DataFrame: ... 
[docs]
    def generate_mortality_rates(self) -> pl.DataFrame: ... 
 
[docs]
class ShapefileProtocol(Protocol):
[docs]
    def add_dotname(self) -> None: ... 
[docs]
    def get_dataframe(self) -> pl.DataFrame: ... 
 
[docs]
class BaseShapefile(BaseModel):
    shapefile: Path
[docs]
    @classmethod
    @field_validator("shapefile", mode="before")
    def convert_to_path(cls, v):
        p = Path(v) if not isinstance(v, Path) else v
        if not p.exists():
            raise FileNotFoundError(f"Shapefile {p} does not exist")
        return p 
[docs]
    def add_dotname(self) -> None: ... 
[docs]
    def get_dataframe(self) -> pl.DataFrame:
        """
        Get a Polars DataFrame containing the shapefile data and fields.
        Returns:
            A Polars DataFrame.
        """
        with Reader(self.shapefile) as sf:
            # Get all records and shapes
            records = []
            shapes = []
            for shaperec in sf.iterShapeRecords():
                records.append(shaperec.record)
                shapes.append(shaperec.shape)
            record_dict = defaultdict(list)
            for record in records:
                for key, value in record.as_dict().items():
                    record_dict[key].append(value)
            # Convert to DataFrame
            df = pl.DataFrame(record_dict)
            # Add shape column
            df = df.with_columns(pl.Series(name="shape", values=shapes))
            return df