Skip to content
4 changes: 4 additions & 0 deletions python/grass/temporal/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,10 @@ def init(
c_library_interface.stop()
c_library_interface = None

# Set defaults for the TGIS DB (overwritten later if initialized)
tgis_backend = "sqlite"
tgis_database_string = None

# Set the global variable for faster access
current_mapset = new_mapset
current_location = new_location
Expand Down
17 changes: 15 additions & 2 deletions python/grass/temporal/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@
"""

from .base import SQLDatabaseInterface
from .core import SQLDatabaseInterfaceConnection, get_tgis_db_version_from_metadata
from .core import (
SQLDatabaseInterfaceConnection,
get_tgis_database_string,
get_tgis_db_version,
get_tgis_db_version_from_metadata,
)

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

Expand Down Expand Up @@ -1457,7 +1462,15 @@ def __init__(
self, "strds_metadata", ident, title, description
)

if get_tgis_db_version_from_metadata() > 2:
# TGIS metadata is only available with an accessible temporal database
# initialized with tgis.init(). Initialization with tgis.init(skip_db_init=True)
# will result in an empty tgis_database_string is empty, fall back to a global
# tgis_db_version if tgis is not fully initialized.
if get_tgis_database_string() is not None:
tgis_db_version_ = get_tgis_db_version_from_metadata()
else:
tgis_db_version_ = get_tgis_db_version()
if tgis_db_version_ > 2:
self.D["number_of_semantic_labels"] = None

self.set_raster_register(raster_register)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,19 @@
import grass.script as gs
import grass.temporal as tgis

ds_types_dict = {
"strds": ("strds"),
"str3ds": ("str3ds"),
"stvds": ("stvds"),
"rast": ("raster", "rast"),
"raster": ("raster", "rast"),
"raster_3d": ("raster_3d", "rast3d", "raster3d"),
"rast3d": ("raster_3d", "rast3d", "raster3d"),
"raster3d": ("raster_3d", "rast3d", "raster3d"),
"vect": ("vector", "vect"),
"vector": ("vector", "vect"),
}


@pytest.fixture
def simple_mapset(tmp_path):
Expand Down Expand Up @@ -51,7 +64,7 @@ def test_init_creates_tgis_db_if_not_skipped(simple_mapset):
assert (
sqlite3.connect(tgis_db)
.execute(
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%strds%';"
"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%strds%';",
)
.fetchall()
!= []
Expand All @@ -74,3 +87,65 @@ def test_init_succeeds_without_db_creation(simple_mapset):
assert tgis.get_sql_template_path().endswith("sql")
assert not var_file.exists()
assert not tgis_db.exists()


@pytest.mark.parametrize("ident", [None, "test@c"])
def test_stds_construction_without_tgis_db_initialization(
simple_mapset,
ident: str | None,
):
"""STDS objects can be constructed even if the temporal DB is not initialized.

Empty STDS objects are constructed in several temporal modules, also where a
temporal database is not necessarily initialized. This test verifies that
STDS objects can be constructed even when tgis is initialized with
tgis.init(skip_db_init=True).
Methods that require access to the temporal database (e.g., is_in_db())
are not tested (they would raise exceptions).
"""
with gs.setup.init(simple_mapset):
tgis.init(skip_db_init=True)
# None of these must raise if the temporal database is not initialized
strds = tgis.SpaceTimeRasterDataset(ident)
assert "number_of_semantic_labels" in strds.metadata.D
tgis.SpaceTimeRaster3DDataset(ident)
tgis.SpaceTimeVectorDataset(ident)
# Test dataset_factory for all dataset types, which should be constructed without DB access
for ds_type, valid_ds_types in ds_types_dict.items():
stds = tgis.dataset_factory(ds_type, ident)
assert stds.get_id() == ident
assert stds.get_type() in valid_ds_types


@pytest.mark.parametrize("ident", [None, "test"])
def test_stds_construction_with_tgis_db_initialization(
simple_mapset,
ident: str | None,
):
"""STDS objects are constructed with access to the temporal DB if initialized.

This is the counterpart to test_stds_construction_without_tgis_db_initialization:
When tgis.init() is called without skip_db_init=True, the temporal database is
accessible and STDS objects can access TGIS metadata from the DB (not the dataset).
Methods that require access to the temporal database (e.g., is_in_db())
are tested to return successfully and valid.

"""
with gs.setup.init(simple_mapset):
tgis.init()
dbif, _connection_state_changes = tgis.init_dbif(None)
if ident is not None:
ident = f"{ident}@{tgis.get_current_mapset()}"
assert tgis.get_tgis_metadata() is not None
assert tgis.get_tgis_db_version_from_metadata() == tgis.get_tgis_db_version()
tgis.get_current_mapset()
strds = tgis.SpaceTimeRasterDataset(ident)
assert strds.get_id() == ident
assert strds.is_in_db() is False
assert "number_of_semantic_labels" in strds.metadata.D
# Test dataset_factory for all dataset types, which should be constructed with DB access
for ds_type, valid_ds_types in ds_types_dict.items():
stds = tgis.dataset_factory(ds_type, ident)
assert stds.get_id() == ident
assert stds.get_type() in valid_ds_types
assert stds.is_in_db(dbif) is False
Loading