Skip to content

Commit

Permalink
grass.temporal: Annotate abstract and concrete classes with generic t…
Browse files Browse the repository at this point in the history
…ypes
  • Loading branch information
echoix committed Nov 3, 2024
1 parent 7f4968a commit 1439aee
Show file tree
Hide file tree
Showing 8 changed files with 422 additions and 128 deletions.
47 changes: 47 additions & 0 deletions python/grass/temporal/_typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from __future__ import annotations

from typing import Generic, Literal, TypeVar, Union

Check failure on line 3 in python/grass/temporal/_typing.py

View workflow job for this annotation

GitHub Actions / Python Code Quality Checks (ubuntu-22.04)

Ruff (F401)

python/grass/temporal/_typing.py:3:29: F401 `typing.Literal` imported but unused


class RasterT:
pass


class Raster3DT:
pass


class VectorT:
pass


# AnyRasterT = RasterT | Raster3DT
AnyRasterT = Union[RasterT, Raster3DT]
# RTT = TypeVar("RTT", AnyRasterT)
RTT = TypeVar("RTT", RasterT, Raster3DT)
# RTT = TypeVar("RTT", bound=AnyRasterT)
# TT = TypeVar("TT", RasterT, Raster3DT, VectorT)
# TT = TypeVar("TT", bound=AnyRasterT | VectorT)
# TT = TypeVar("TT", RTT, VectorT)
TT = TypeVar("TT", AnyRasterT, VectorT)


class SpaceTimeT(Generic[TT]):
pass


STT = TypeVar("STT", bound=SpaceTimeT)
# AnyTTST = Union[TT, STT]
# AnyTTST = TypeVar("AnyTTST", bound=TT|STT)
# AnyTTST = TypeVar("AnyTTST", bound=Union[TT, STT])
AnyTTST2 = TypeVar(
"AnyTTST2",
RasterT,
Raster3DT,
VectorT,
SpaceTimeT[RasterT],
SpaceTimeT[Raster3DT],
SpaceTimeT[VectorT],
)
# AnyTTST = TypeVar("AnyTTST", RasterT, Raster3DT, VectorT, SpaceTimeT)
AnyTTST = TypeVar("AnyTTST", AnyRasterT, VectorT, SpaceTimeT)
32 changes: 23 additions & 9 deletions python/grass/temporal/abstract_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,21 @@
from __future__ import annotations

from abc import ABCMeta, abstractmethod
from typing import Literal
from typing import TYPE_CHECKING, Generic, Literal

from ._typing import TT, AnyTTST, SpaceTimeT

Check failure on line 18 in python/grass/temporal/abstract_dataset.py

View workflow job for this annotation

GitHub Actions / Python Code Quality Checks (ubuntu-22.04)

Ruff (F401)

python/grass/temporal/abstract_dataset.py:18:22: F401 `._typing.TT` imported but unused

Check failure on line 18 in python/grass/temporal/abstract_dataset.py

View workflow job for this annotation

GitHub Actions / Python Code Quality Checks (ubuntu-22.04)

Ruff (F401)

python/grass/temporal/abstract_dataset.py:18:35: F401 `._typing.SpaceTimeT` imported but unused
from .core import get_current_mapset, get_tgis_message_interface, init_dbif
from .spatial_topology_dataset_connector import SpatialTopologyDatasetConnector
from .temporal_topology_dataset_connector import TemporalTopologyDatasetConnector

if TYPE_CHECKING:
from .spatial_extent import SpatialExtent

###############################################################################


class AbstractDataset(
SpatialTopologyDatasetConnector, TemporalTopologyDatasetConnector
SpatialTopologyDatasetConnector, TemporalTopologyDatasetConnector, Generic[AnyTTST]
):
"""This is the base class for all datasets
(raster, vector, raster3d, strds, stvds, str3ds)"""
Expand Down Expand Up @@ -164,23 +168,23 @@ def get_type(
"""

@abstractmethod
def get_new_instance(self, ident):
def get_new_instance(self, ident) -> AbstractDataset[AnyTTST]:
"""Return a new instance with the type of this class
:param ident: The identifier of the new dataset instance
:return: A new instance with the type of this object
"""

@abstractmethod
def spatial_overlapping(self, dataset):
def spatial_overlapping(self, dataset) -> bool:
"""Return True if the spatial extents overlap
:param dataset: The abstract dataset to check spatial overlapping
:return: True if self and the provided dataset spatial overlap
"""

@abstractmethod
def spatial_intersection(self, dataset):
def spatial_intersection(self, dataset) -> SpatialExtent | None:
"""Return the spatial intersection as spatial_extent
object or None in case no intersection was found.
Expand All @@ -189,7 +193,7 @@ def spatial_intersection(self, dataset):
"""

@abstractmethod
def spatial_union(self, dataset):
def spatial_union(self, dataset) -> SpatialExtent | None:
"""Return the spatial union as spatial_extent
object or None in case the extents does not overlap or meet.
Expand All @@ -198,15 +202,25 @@ def spatial_union(self, dataset):
"""

@abstractmethod
def spatial_disjoint_union(self, dataset):
def spatial_disjoint_union(self, dataset) -> SpatialExtent:
"""Return the spatial union as spatial_extent object.
:param dataset: The abstract dataset to create a union with
:return: The union spatial extent
"""

@abstractmethod
def spatial_relation(self, dataset):
def spatial_relation(self, dataset) -> Literal[
"equivalent",
"contain",
"in",
"cover",
"covered",
"overlap",
"meet",
"disjoint",
"unknown",
]:
"""Return the spatial relationship between self and dataset
:param dataset: The abstract dataset to compute the spatial
Expand Down Expand Up @@ -282,7 +296,7 @@ def get_absolute_time(self):

return (start, end)

def get_relative_time(self):
def get_relative_time(self) -> tuple:
"""Returns the start time, the end
time and the temporal unit of the dataset as tuple
Expand Down
88 changes: 67 additions & 21 deletions python/grass/temporal/abstract_map_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@

from abc import ABCMeta, abstractmethod
from datetime import datetime
from typing import TYPE_CHECKING, Generic, TypeVar

import grass.script as gs
from grass.exceptions import ImplementationError

from ._typing import TT
from .abstract_dataset import AbstractDataset
from .core import (
get_current_mapset,
Expand All @@ -31,10 +33,32 @@
decrement_datetime_by_string,
increment_datetime_by_string,
)
from .space_time_datasets import MapDatasetType

Check failure on line 36 in python/grass/temporal/abstract_map_dataset.py

View workflow job for this annotation

GitHub Actions / Python Code Quality Checks (ubuntu-22.04)

Ruff (F401)

python/grass/temporal/abstract_map_dataset.py:36:34: F401 `.space_time_datasets.MapDatasetType` imported but unused
from .temporal_extent import AbsoluteTemporalExtent, RelativeTemporalExtent

# from python.grass.temporal.space_time_datasets import MapDatasetType

class AbstractMapDataset(AbstractDataset):

if TYPE_CHECKING:
from .abstract_space_time_dataset import AbstractSpaceTimeDataset
from .metadata import MetadataBase
from .spatial_extent import SpatialExtent

AbsoluteTemporalExtentType = TypeVar(
"AbsoluteTemporalExtentType", bound=AbsoluteTemporalExtent
)
RelativeTemporalExtentType = TypeVar(
"RelativeTemporalExtentType", bound=RelativeTemporalExtent
)
# RelativeTemporalExtentType = TypeVar(
# "RelativeTemporalExtentType", bound="RelativeTemporalExtent"
# )
# MapDatasetType = TypeVar("MapDatasetType")


# class AbstractMapDataset(AbstractDataset):
# class AbstractMapDataset(AbstractDataset, Generic[MapDatasetType]):
class AbstractMapDataset(AbstractDataset, Generic[TT]):
"""This is the base class for all maps (raster, vector, raster3d).
The temporal extent, the spatial extent and the metadata of maps
Expand All @@ -58,13 +82,42 @@ class AbstractMapDataset(AbstractDataset):
"""

__metaclass__ = ABCMeta

def __init__(self):
# absolute_time: AbsoluteTemporalExtent
# absolute_time: type[AbsoluteTemporalExtentType]
# relative_time: RelativeTemporalExtentType | None
# relative_time: RelativeTemporalExtent[TT] | None = None
absolute_time: AbsoluteTemporalExtent[TT]
relative_time: RelativeTemporalExtent[TT]
spatial_extent: SpatialExtent[TT]
metadata: MetadataBase[TT]

# self.base = RasterBase(ident=ident)
# self.absolute_time = RasterAbsoluteTime(ident=ident)
# self.relative_time = RasterRelativeTime(ident=ident)
# self.spatial_extent = RasterSpatialExtent(ident=ident)
# self.metadata = RasterMetadata(ident=ident)
# self.stds_register = RasterSTDSRegister(ident=ident)

# def __init__[RelT: RelativeTemporalExtentType](self) -> None:
# AbstractDataset.__init__(self)
# self.relative_time: RelT
# self.ciface = get_tgis_c_library_interface()
def __init__(self) -> None:
AbstractDataset.__init__(self)
# self.relative_time: type[RelativeTemporalExtentType] | None = None
# self.absolute_time: AbsoluteTemporalExtent[TT] | None = None
# self.relative_time: RelativeTemporalExtent[TT] | None = None
# self.absolute_time: AbsoluteTemporalExtent[MapDatasetType] | None = None
# self.relative_time: RelativeTemporalExtent[MapDatasetType] | None = None
self.ciface = get_tgis_c_library_interface()

# @property
# @abstractmethod
# def relative_time(self) -> RelativeTemporalExtent:
# pass

@abstractmethod
def get_new_stds_instance(self, ident):
def get_new_stds_instance(self, ident) -> AbstractSpaceTimeDataset[TT]:
"""Return a new space time dataset instance that store maps with the
type of this map object (raster, raster_3d or vector)
Expand All @@ -89,11 +142,10 @@ def check_resolution_with_current_region(self):
raise ImplementationError("This method must be implemented in the subclasses")

@abstractmethod
def has_grass_timestamp(self):
def has_grass_timestamp(self) -> bool:
"""Check if a grass file based time stamp exists for this map.
:return: True is the grass file based time stamped exists for this map
"""

@abstractmethod
Expand All @@ -111,22 +163,19 @@ def read_timestamp_from_grass(self):
"""

@abstractmethod
def remove_timestamp_from_grass(self):
"""Remove the timestamp from the grass file
system based spatial database
"""
def remove_timestamp_from_grass(self) -> bool:
"""Remove the timestamp from the grass file system based spatial database"""

@abstractmethod
def map_exists(self):
def map_exists(self) -> bool:
"""Return True in case the map exists in the grass spatial database
:return: True if map exists, False otherwise
"""

@abstractmethod
def load(self):
"""Load the content of this object from the grass
file system based database"""
def load(self) -> bool:
"""Load the content of this object from the grass file system based database"""

def _convert_timestamp(self):
"""Convert the valid time into a grass datetime library
Expand Down Expand Up @@ -203,7 +252,7 @@ def split_name(
@staticmethod
def build_id_from_search_path(name, element):
"""Convenient method to build the unique identifier while
checking the current seach path for the correct mapset.
checking the current search path for the correct mapset.
Existing mapset definitions in the name string will be reused.
Expand Down Expand Up @@ -245,16 +294,13 @@ def build_id_from_search_path(name, element):
def build_id(name, mapset, layer=None):
"""Convenient method to build the unique identifier
Existing layer and mapset definitions in the name
string will be reused
Existing layer and mapset definitions in the name string will be reused
:param name: The name of the map
:param mapset: The mapset in which the map is located
:param layer: The layer of the vector map, use None in case no
layer exists
:param layer: The layer of the vector map, use None in case no layer exists
:return: the id of the map as "name(:layer)@mapset" where layer is
optional
:return: the id of the map as "name(:layer)@mapset" where layer is optional
"""

# Split given name into relevant parts
Expand Down
18 changes: 16 additions & 2 deletions python/grass/temporal/abstract_space_time_dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ class that is the base class for all space time datasets.
:authors: Soeren Gebbert
"""

from __future__ import annotations

import copy
import os
import sys
import uuid
from abc import ABCMeta, abstractmethod
from datetime import datetime
from pathlib import Path
from typing import Generic

from ._typing import STT, TT, SpaceTimeT

Check failure on line 24 in python/grass/temporal/abstract_space_time_dataset.py

View workflow job for this annotation

GitHub Actions / Python Code Quality Checks (ubuntu-22.04)

Ruff (F401)

python/grass/temporal/abstract_space_time_dataset.py:24:22: F401 `._typing.STT` imported but unused
from .abstract_dataset import AbstractDataset, AbstractDatasetComparisonKeyStartTime
from .core import (
get_current_mapset,
Expand All @@ -42,7 +46,10 @@ class that is the base class for all space time datasets.
###############################################################################


class AbstractSpaceTimeDataset(AbstractDataset):
# class AbstractSpaceTimeDataset(AbstractDataset[SpaceTimeT[TT]], Generic[TT, STT]):
# class AbstractSpaceTimeDataset(AbstractDataset[SpaceTimeT[TT]], Generic[TT]):
# class AbstractSpaceTimeDataset(AbstractDataset[STT], Generic[TT, STT]):
class AbstractSpaceTimeDataset(AbstractDataset[SpaceTimeT[TT]], Generic[TT]):
"""Abstract space time dataset class
Base class for all space time datasets.
Expand Down Expand Up @@ -101,8 +108,15 @@ def create_map_register_name(self):

return self.get_new_map_instance(None).get_type() + "_map_register_" + uuid_rand

# @abstractmethod
# def get_new_instance(self, ident) -> AbstractDataset[SpaceTimeT[TT]]:
# """Return a new instance with the type of this class"""
@abstractmethod
def get_new_instance(self, ident) -> AbstractSpaceTimeDataset[TT]:
"""Return a new instance with the type of this class"""

@abstractmethod
def get_new_map_instance(self, ident=None):
def get_new_map_instance(self, ident=None) -> AbstractDataset[TT]:
"""Return a new instance of a map which is associated
with the type of this object
Expand Down
Loading

0 comments on commit 1439aee

Please sign in to comment.