• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine-python / 16367912334

18 Jul 2025 10:06AM UTC coverage: 76.934% (+0.1%) from 76.806%
16367912334

push

github

web-flow
ci: use Ruff as new formatter and linter (#233)

* wip

* pycodestyle

* update dependencies

* skl2onnx

* use ruff

* apply formatter

* apply lint auto fixes

* manually apply lints

* change check

* ruff ci from branch

2805 of 3646 relevant lines covered (76.93%)

0.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.45
geoengine/datasets.py
1
"""
2
Module for working with datasets and source definitions
3
"""
4

5
from __future__ import annotations
1✔
6

7
import tempfile
1✔
8
from abc import abstractmethod
1✔
9
from enum import Enum
1✔
10
from pathlib import Path
1✔
11
from typing import Literal, NamedTuple
1✔
12
from uuid import UUID
1✔
13

14
import geoengine_openapi_client
1✔
15
import geoengine_openapi_client.exceptions
1✔
16
import geoengine_openapi_client.models
1✔
17
import geopandas as gpd
1✔
18
import numpy as np
1✔
19
from attr import dataclass
1✔
20

21
from geoengine import api
1✔
22
from geoengine.auth import get_session
1✔
23
from geoengine.error import InputException, MissingFieldInResponseException
1✔
24
from geoengine.permissions import Permission, RoleId, add_permission
1✔
25
from geoengine.resource_identifier import DatasetName, Resource, UploadId
1✔
26
from geoengine.types import (
1✔
27
    FeatureDataType,
28
    Provenance,
29
    RasterSymbology,
30
    TimeStep,
31
    TimeStepGranularity,
32
    UnitlessMeasurement,
33
    VectorColumnInfo,
34
    VectorDataType,
35
    VectorResultDescriptor,
36
)
37

38

39
class UnixTimeStampType(Enum):
1✔
40
    """A unix time stamp type"""
41

42
    EPOCHSECONDS = "epochSeconds"
1✔
43
    EPOCHMILLISECONDS = "epochMilliseconds"
1✔
44

45
    def to_api_enum(self) -> geoengine_openapi_client.UnixTimeStampType:
1✔
46
        return geoengine_openapi_client.UnixTimeStampType(self.value)
×
47

48

49
class OgrSourceTimeFormat:
1✔
50
    """Base class for OGR time formats"""
51

52
    @abstractmethod
1✔
53
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceTimeFormat:
1✔
54
        pass
×
55

56
    @classmethod
1✔
57
    def seconds(cls, timestamp_type: UnixTimeStampType) -> UnixTimeStampOgrSourceTimeFormat:
1✔
58
        return UnixTimeStampOgrSourceTimeFormat(timestamp_type)
×
59

60
    @classmethod
1✔
61
    def auto(cls) -> AutoOgrSourceTimeFormat:
1✔
62
        return AutoOgrSourceTimeFormat()
1✔
63

64
    @classmethod
1✔
65
    def custom(cls, format_string: str) -> CustomOgrSourceTimeFormat:
1✔
66
        return CustomOgrSourceTimeFormat(format_string)
×
67

68

69
@dataclass
1✔
70
class UnixTimeStampOgrSourceTimeFormat(OgrSourceTimeFormat):
1✔
71
    """An OGR time format specified in seconds (UNIX time)"""
72

73
    timestampType: UnixTimeStampType
1✔
74

75
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceTimeFormat:
1✔
76
        return geoengine_openapi_client.OgrSourceTimeFormat(
×
77
            geoengine_openapi_client.OgrSourceTimeFormatUnixTimeStamp(
78
                format="unixTimeStamp",
79
                timestamp_type=self.timestampType.to_api_enum(),
80
            )
81
        )
82

83

84
@dataclass
1✔
85
class AutoOgrSourceTimeFormat(OgrSourceTimeFormat):
1✔
86
    """An auto detection OGR time format"""
87

88
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceTimeFormat:
1✔
89
        return geoengine_openapi_client.OgrSourceTimeFormat(
1✔
90
            geoengine_openapi_client.OgrSourceTimeFormatAuto(format="auto")
91
        )
92

93

94
@dataclass
1✔
95
class CustomOgrSourceTimeFormat(OgrSourceTimeFormat):
1✔
96
    """A custom OGR time format"""
97

98
    custom_format: str
1✔
99

100
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceTimeFormat:
1✔
101
        return geoengine_openapi_client.OgrSourceTimeFormat(
×
102
            geoengine_openapi_client.OgrSourceTimeFormatCustom(format="custom", custom_format=self.custom_format)
103
        )
104

105

106
class OgrSourceDuration:
1✔
107
    """Base class for the duration part of a OGR time format"""
108

109
    @abstractmethod
1✔
110
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDurationSpec:
1✔
111
        pass
×
112

113
    @classmethod
1✔
114
    def zero(cls) -> ZeroOgrSourceDurationSpec:
1✔
115
        return ZeroOgrSourceDurationSpec()
×
116

117
    @classmethod
1✔
118
    def infinite(cls) -> InfiniteOgrSourceDurationSpec:
1✔
119
        return InfiniteOgrSourceDurationSpec()
×
120

121
    @classmethod
1✔
122
    def value(
1✔
123
        cls, value: int, granularity: TimeStepGranularity = TimeStepGranularity.SECONDS
124
    ) -> ValueOgrSourceDurationSpec:
125
        """Returns the value of the duration"""
126
        return ValueOgrSourceDurationSpec(TimeStep(value, granularity))
1✔
127

128

129
class ValueOgrSourceDurationSpec(OgrSourceDuration):
1✔
130
    """A fixed value for a source duration"""
131

132
    step: TimeStep
1✔
133

134
    def __init__(self, step: TimeStep):
1✔
135
        self.step = step
1✔
136

137
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDurationSpec:
1✔
138
        return geoengine_openapi_client.OgrSourceDurationSpec(
1✔
139
            geoengine_openapi_client.OgrSourceDurationSpecValue(
140
                type="value",
141
                step=self.step.step,
142
                granularity=self.step.granularity.to_api_enum(),
143
            )
144
        )
145

146

147
class ZeroOgrSourceDurationSpec(OgrSourceDuration):
1✔
148
    """An instant, i.e. no duration"""
149

150
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDurationSpec:
1✔
151
        return geoengine_openapi_client.OgrSourceDurationSpec(
×
152
            geoengine_openapi_client.OgrSourceDurationSpecZero(
153
                type="zero",
154
            )
155
        )
156

157

158
class InfiniteOgrSourceDurationSpec(OgrSourceDuration):
1✔
159
    """An open-ended time duration"""
160

161
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDurationSpec:
1✔
162
        return geoengine_openapi_client.OgrSourceDurationSpec(
×
163
            geoengine_openapi_client.OgrSourceDurationSpecInfinite(
164
                type="infinite",
165
            )
166
        )
167

168

169
class OgrSourceDatasetTimeType:
1✔
170
    """A time type specification for OGR dataset definitions"""
171

172
    @abstractmethod
1✔
173
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDatasetTimeType:
1✔
174
        pass
×
175

176
    @classmethod
1✔
177
    def none(cls) -> NoneOgrSourceDatasetTimeType:
1✔
178
        return NoneOgrSourceDatasetTimeType()
1✔
179

180
    @classmethod
1✔
181
    def start(
1✔
182
        cls, start_field: str, start_format: OgrSourceTimeFormat, duration: OgrSourceDuration
183
    ) -> StartOgrSourceDatasetTimeType:
184
        """Specify a start column and a fixed duration"""
185
        return StartOgrSourceDatasetTimeType(start_field, start_format, duration)
1✔
186

187
    @classmethod
1✔
188
    def start_end(
1✔
189
        cls, start_field: str, start_format: OgrSourceTimeFormat, end_field: str, end_format: OgrSourceTimeFormat
190
    ) -> StartEndOgrSourceDatasetTimeType:
191
        """The dataset contains start and end column"""
192
        return StartEndOgrSourceDatasetTimeType(start_field, start_format, end_field, end_format)
×
193

194
    @classmethod
1✔
195
    def start_duration(
1✔
196
        cls, start_field: str, start_format: OgrSourceTimeFormat, duration_field: str
197
    ) -> StartDurationOgrSourceDatasetTimeType:
198
        """The dataset contains start and a duration column"""
199
        return StartDurationOgrSourceDatasetTimeType(start_field, start_format, duration_field)
×
200

201

202
@dataclass
1✔
203
class NoneOgrSourceDatasetTimeType(OgrSourceDatasetTimeType):
1✔
204
    """Specify no time information"""
205

206
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDatasetTimeType:
1✔
207
        return geoengine_openapi_client.OgrSourceDatasetTimeType(
1✔
208
            geoengine_openapi_client.OgrSourceDatasetTimeTypeNone(
209
                type="none",
210
            )
211
        )
212

213

214
@dataclass
1✔
215
class StartOgrSourceDatasetTimeType(OgrSourceDatasetTimeType):
1✔
216
    """Specify a start column and a fixed duration"""
217

218
    start_field: str
1✔
219
    start_format: OgrSourceTimeFormat
1✔
220
    duration: OgrSourceDuration
1✔
221

222
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDatasetTimeType:
1✔
223
        return geoengine_openapi_client.OgrSourceDatasetTimeType(
1✔
224
            geoengine_openapi_client.OgrSourceDatasetTimeTypeStart(
225
                type="start",
226
                start_field=self.start_field,
227
                start_format=self.start_format.to_api_dict(),
228
                duration=self.duration.to_api_dict(),
229
            )
230
        )
231

232

233
@dataclass
1✔
234
class StartEndOgrSourceDatasetTimeType(OgrSourceDatasetTimeType):
1✔
235
    """The dataset contains start and end column"""
236

237
    start_field: str
1✔
238
    start_format: OgrSourceTimeFormat
1✔
239
    end_field: str
1✔
240
    end_format: OgrSourceTimeFormat
1✔
241

242
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDatasetTimeType:
1✔
243
        return geoengine_openapi_client.OgrSourceDatasetTimeType(
×
244
            geoengine_openapi_client.OgrSourceDatasetTimeTypeStartEnd(
245
                type="startEnd",
246
                start_field=self.start_field,
247
                start_format=self.start_format.to_api_dict(),
248
                end_field=self.end_field,
249
                end_format=self.end_format.to_api_dict(),
250
            )
251
        )
252

253

254
@dataclass
1✔
255
class StartDurationOgrSourceDatasetTimeType(OgrSourceDatasetTimeType):
1✔
256
    """The dataset contains start and a duration column"""
257

258
    start_field: str
1✔
259
    start_format: OgrSourceTimeFormat
1✔
260
    duration_field: str
1✔
261

262
    def to_api_dict(self) -> geoengine_openapi_client.OgrSourceDatasetTimeType:
1✔
263
        return geoengine_openapi_client.OgrSourceDatasetTimeType(
×
264
            geoengine_openapi_client.OgrSourceDatasetTimeTypeStartDuration(
265
                type="startDuration",
266
                start_field=self.start_field,
267
                start_format=self.start_format.to_api_dict(),
268
                duration_field=self.duration_field,
269
            )
270
        )
271

272

273
class OgrOnError(Enum):
1✔
274
    """How to handle errors when loading an OGR dataset"""
275

276
    IGNORE = "ignore"
1✔
277
    ABORT = "abort"
1✔
278

279
    def to_api_enum(self) -> geoengine_openapi_client.OgrSourceErrorSpec:
1✔
280
        return geoengine_openapi_client.OgrSourceErrorSpec(self.value)
1✔
281

282

283
class AddDatasetProperties:
1✔
284
    """The properties for adding a dataset"""
285

286
    name: str | None
1✔
287
    display_name: str
1✔
288
    description: str
1✔
289
    source_operator: Literal["GdalSource", "OgrSource"]  # TODO: add more operators
1✔
290
    symbology: RasterSymbology | None  # TODO: add vector symbology if needed
1✔
291
    provenance: list[Provenance] | None
1✔
292

293
    def __init__(
1✔
294
        # pylint: disable=too-many-arguments,too-many-positional-arguments
295
        self,
296
        display_name: str,
297
        description: str,
298
        source_operator: Literal["GdalSource", "OgrSource"] = "GdalSource",
299
        symbology: RasterSymbology | None = None,
300
        provenance: list[Provenance] | None = None,
301
        name: str | None = None,
302
    ):
303
        """Creates a new `AddDatasetProperties` object"""
304
        self.name = name
1✔
305
        self.display_name = display_name
1✔
306
        self.description = description
1✔
307
        self.source_operator = source_operator
1✔
308
        self.symbology = symbology
1✔
309
        self.provenance = provenance
1✔
310

311
    def to_api_dict(self) -> geoengine_openapi_client.AddDataset:
1✔
312
        """Converts the properties to a dictionary"""
313
        return geoengine_openapi_client.AddDataset(
1✔
314
            name=str(self.name) if self.name is not None else None,
315
            display_name=self.display_name,
316
            description=self.description,
317
            source_operator=self.source_operator,
318
            symbology=self.symbology.to_api_dict() if self.symbology is not None else None,
319
            provenance=[p.to_api_dict() for p in self.provenance] if self.provenance is not None else None,
320
        )
321

322

323
class VolumeId:
1✔
324
    """A wrapper for an volume id"""
325

326
    __volume_id: UUID
1✔
327

328
    def __init__(self, volume_id: UUID) -> None:
1✔
329
        self.__volume_id = volume_id
×
330

331
    def __str__(self) -> str:
1✔
332
        return str(self.__volume_id)
×
333

334
    def __repr__(self) -> str:
1✔
335
        return str(self)
×
336

337
    def __eq__(self, other) -> bool:
1✔
338
        """Checks if two volume ids are equal"""
339
        if not isinstance(other, self.__class__):
×
340
            return False
×
341

342
        return self.__volume_id == other.__volume_id  # pylint: disable=protected-access
×
343

344

345
def pandas_dtype_to_column_type(dtype: np.dtype) -> FeatureDataType:
1✔
346
    """Convert a pandas `dtype` to a column type"""
347

348
    if np.issubdtype(dtype, np.integer):
1✔
349
        return FeatureDataType.INT
1✔
350

351
    if np.issubdtype(dtype, np.floating):
1✔
352
        return FeatureDataType.FLOAT
1✔
353

354
    if str(dtype) == "object":
1✔
355
        return FeatureDataType.TEXT
1✔
356

357
    raise InputException(f"pandas dtype {dtype} has no corresponding column type")
×
358

359

360
def upload_dataframe(
1✔
361
    df: gpd.GeoDataFrame,
362
    display_name: str = "Upload from Python",
363
    name: str | None = None,
364
    time: OgrSourceDatasetTimeType | None = None,
365
    on_error: OgrOnError = OgrOnError.ABORT,
366
    timeout: int = 3600,
367
) -> DatasetName:
368
    """
369
    Uploads a given dataframe to Geo Engine.
370

371
    Parameters
372
    ----------
373
    df
374
        The dataframe to upload.
375
    display_name
376
        The display name of the dataset. Defaults to "Upload from Python".
377
    name
378
        The name the dataset should have. If not given, a random name (UUID) will be generated.
379
    time
380
        A time configuration for the dataset. Defaults to `OgrSourceDatasetTimeType.none()`.
381
    on_error
382
        The error handling strategy. Defaults to `OgrOnError.ABORT`.
383
    timeout
384
        The upload timeout in seconds. Defaults to 3600.
385

386
    Returns
387
    -------
388
    DatasetName
389
        The name of the uploaded dataset
390

391
    Raises
392
    ------
393
    GeoEngineException
394
        If the dataset could not be uploaded or the name is already taken.
395
    """
396
    # pylint: disable=too-many-arguments,too-many-locals,too-many-positional-arguments
397

398
    if time is None:
1✔
399
        time = OgrSourceDatasetTimeType.none()
1✔
400

401
    if len(df) == 0:
1✔
402
        raise InputException("Cannot upload empty dataframe")
×
403

404
    if df.crs is None:
1✔
405
        raise InputException("Dataframe must have a specified crs")
×
406

407
    session = get_session()
1✔
408

409
    df_json = df.to_json()
1✔
410

411
    with (
1✔
412
        tempfile.TemporaryDirectory() as temp_dir,
413
        geoengine_openapi_client.ApiClient(session.configuration) as api_client,
414
    ):
415
        json_file_name = Path(temp_dir) / "geo.json"
1✔
416
        with open(json_file_name, "w", encoding="utf8") as json_file:
1✔
417
            json_file.write(df_json)
1✔
418

419
        uploads_api = geoengine_openapi_client.UploadsApi(api_client)
1✔
420
        response = uploads_api.upload_handler([str(json_file_name)], _request_timeout=timeout)
1✔
421

422
    upload_id = UploadId.from_response(response)
1✔
423

424
    vector_type = VectorDataType.from_geopandas_type_name(df.geom_type[0])
1✔
425

426
    columns = {
1✔
427
        key: VectorColumnInfo(data_type=pandas_dtype_to_column_type(value), measurement=UnitlessMeasurement())
428
        for (key, value) in df.dtypes.items()
429
        if str(value) != "geometry"
430
    }
431

432
    floats = [key for (key, value) in columns.items() if value.data_type == "float"]
1✔
433
    ints = [key for (key, value) in columns.items() if value.data_type == "int"]
1✔
434
    texts = [key for (key, value) in columns.items() if value.data_type == "text"]
1✔
435

436
    result_descriptor = (
1✔
437
        VectorResultDescriptor(
438
            data_type=vector_type,
439
            spatial_reference=df.crs.to_string(),
440
            columns=columns,
441
        )
442
        .to_api_dict()
443
        .actual_instance
444
    )
445
    if not isinstance(result_descriptor, geoengine_openapi_client.TypedVectorResultDescriptor):
1✔
446
        raise TypeError("Expected TypedVectorResultDescriptor")
×
447

448
    create = geoengine_openapi_client.CreateDataset(
1✔
449
        data_path=geoengine_openapi_client.DataPath(geoengine_openapi_client.DataPathOneOf1(upload=str(upload_id))),
450
        definition=geoengine_openapi_client.DatasetDefinition(
451
            properties=AddDatasetProperties(
452
                display_name=display_name,
453
                name=name,
454
                description="Upload from Python",
455
                source_operator="OgrSource",
456
            ).to_api_dict(),
457
            meta_data=geoengine_openapi_client.MetaDataDefinition(
458
                geoengine_openapi_client.OgrMetaData(
459
                    type="OgrMetaData",
460
                    loading_info=geoengine_openapi_client.OgrSourceDataset(
461
                        file_name="geo.json",
462
                        layer_name="geo",
463
                        data_type=vector_type.to_api_enum(),
464
                        time=time.to_api_dict(),
465
                        columns=geoengine_openapi_client.OgrSourceColumnSpec(
466
                            y="",
467
                            x="",
468
                            float=floats,
469
                            int=ints,
470
                            text=texts,
471
                        ),
472
                        on_error=on_error.to_api_enum(),
473
                    ),
474
                    result_descriptor=geoengine_openapi_client.VectorResultDescriptor.from_dict(
475
                        result_descriptor.to_dict()
476
                    ),
477
                )
478
            ),
479
        ),
480
    )
481

482
    with geoengine_openapi_client.ApiClient(session.configuration) as api_client:
1✔
483
        datasets_api = geoengine_openapi_client.DatasetsApi(api_client)
1✔
484
        response2 = datasets_api.create_dataset_handler(create, _request_timeout=timeout)
1✔
485

486
    return DatasetName.from_response(response2)
1✔
487

488

489
class StoredDataset(NamedTuple):
1✔
490
    """The result of a store dataset request is a combination of `upload_id` and `dataset_name`"""
491

492
    dataset_name: DatasetName
1✔
493
    upload_id: UploadId
1✔
494

495
    @classmethod
1✔
496
    def from_response(cls, response: api.StoredDataset) -> StoredDataset:
1✔
497
        """Parse a http response to an `StoredDataset`"""
498

499
        if "dataset" not in response:  # TODO: improve error handling
1✔
500
            raise MissingFieldInResponseException("dataset", response)
×
501
        if "upload" not in response:
1✔
502
            raise MissingFieldInResponseException("upload", response)
×
503

504
        return StoredDataset(
1✔
505
            dataset_name=DatasetName(response["dataset"]), upload_id=UploadId(UUID(response["upload"]))
506
        )
507

508
    def to_api_dict(self) -> api.StoredDataset:
1✔
509
        return api.StoredDataset(dataset=str(self.dataset_name), upload=str(self.upload_id))
×
510

511

512
@dataclass
1✔
513
class Volume:
1✔
514
    """A volume"""
515

516
    name: str
1✔
517
    path: str | None
1✔
518

519
    @classmethod
1✔
520
    def from_response(cls, response: geoengine_openapi_client.Volume) -> Volume:
1✔
521
        """Parse a http response to an `Volume`"""
522
        return Volume(response.name, response.path)
1✔
523

524
    def to_api_dict(self) -> geoengine_openapi_client.Volume:
1✔
525
        return geoengine_openapi_client.Volume(name=self.name, path=self.path)
×
526

527

528
def volumes(timeout: int = 60) -> list[Volume]:
1✔
529
    """Returns a list of all volumes"""
530

531
    session = get_session()
1✔
532

533
    with geoengine_openapi_client.ApiClient(session.configuration) as api_client:
1✔
534
        datasets_api = geoengine_openapi_client.DatasetsApi(api_client)
1✔
535
        response = datasets_api.list_volumes_handler(_request_timeout=timeout)
1✔
536

537
    return [Volume.from_response(v) for v in response]
1✔
538

539

540
def add_dataset(
1✔
541
    data_store: Volume | UploadId,
542
    properties: AddDatasetProperties,
543
    meta_data: geoengine_openapi_client.MetaDataDefinition,
544
    timeout: int = 60,
545
) -> DatasetName:
546
    """Adds a dataset to the Geo Engine"""
547

548
    if isinstance(data_store, Volume):
1✔
549
        dataset_path = geoengine_openapi_client.DataPath(geoengine_openapi_client.DataPathOneOf(volume=data_store.name))
1✔
550
    else:
551
        dataset_path = geoengine_openapi_client.DataPath(
×
552
            geoengine_openapi_client.DataPathOneOf1(upload=str(data_store))
553
        )
554

555
    create = geoengine_openapi_client.CreateDataset(
1✔
556
        data_path=dataset_path,
557
        definition=geoengine_openapi_client.DatasetDefinition(properties=properties.to_api_dict(), meta_data=meta_data),
558
    )
559

560
    session = get_session()
1✔
561

562
    with geoengine_openapi_client.ApiClient(session.configuration) as api_client:
1✔
563
        datasets_api = geoengine_openapi_client.DatasetsApi(api_client)
1✔
564
        response = datasets_api.create_dataset_handler(create, _request_timeout=timeout)
1✔
565

566
    return DatasetName.from_response(response)
1✔
567

568

569
def add_or_replace_dataset_with_permissions(
1✔
570
    data_store: Volume | UploadId,
571
    properties: AddDatasetProperties,
572
    meta_data: geoengine_openapi_client.MetaDataDefinition,
573
    permission_tuples: list[tuple[RoleId, Permission]] | None = None,
574
    replace_existing=False,
575
    timeout: int = 60,
576
) -> DatasetName:
577
    """
578
    Add a dataset to the Geo Engine and set permissions.
579
    Replaces existing datasets if forced!
580
    """
581
    # pylint: disable=too-many-arguments,too-many-positional-arguments
582

583
    def add_dataset_and_permissions() -> DatasetName:
1✔
584
        dataset_name = add_dataset(data_store=data_store, properties=properties, meta_data=meta_data, timeout=timeout)
1✔
585
        if permission_tuples is not None:
1✔
586
            dataset_res = Resource.from_dataset_name(dataset_name)
1✔
587
            for role, perm in permission_tuples:
1✔
588
                add_permission(role, dataset_res, perm, timeout=timeout)
1✔
589
        return dataset_name
1✔
590

591
    if properties.name is None:
1✔
592
        dataset_name = add_dataset_and_permissions()
×
593

594
    else:
595
        dataset_name = DatasetName(properties.name)
1✔
596
        dataset_info = dataset_info_by_name(dataset_name)
1✔
597
        if dataset_info is None:  # dataset is not existing
1✔
598
            dataset_name = add_dataset_and_permissions()
1✔
599
        else:
600
            if replace_existing:  # dataset exists and we overwrite it
1✔
601
                delete_dataset(dataset_name)
1✔
602
                dataset_name = add_dataset_and_permissions()
1✔
603

604
    return dataset_name
1✔
605

606

607
def delete_dataset(dataset_name: DatasetName, timeout: int = 60) -> None:
1✔
608
    """Delete a dataset. The dataset must be owned by the caller."""
609

610
    session = get_session()
1✔
611

612
    with geoengine_openapi_client.ApiClient(session.configuration) as api_client:
1✔
613
        datasets_api = geoengine_openapi_client.DatasetsApi(api_client)
1✔
614
        datasets_api.delete_dataset_handler(str(dataset_name), _request_timeout=timeout)
1✔
615

616

617
class DatasetListOrder(Enum):
1✔
618
    NAME_ASC = "NameAsc"
1✔
619
    NAME_DESC = "NameDesc"
1✔
620

621

622
def list_datasets(
1✔
623
    offset: int = 0,
624
    limit: int = 20,
625
    order: DatasetListOrder = DatasetListOrder.NAME_ASC,
626
    name_filter: str | None = None,
627
    timeout: int = 60,
628
) -> list[geoengine_openapi_client.DatasetListing]:
629
    """List datasets"""
630

631
    session = get_session()
1✔
632

633
    with geoengine_openapi_client.ApiClient(session.configuration) as api_client:
1✔
634
        datasets_api = geoengine_openapi_client.DatasetsApi(api_client)
1✔
635
        response = datasets_api.list_datasets_handler(
1✔
636
            offset=offset,
637
            limit=limit,
638
            order=geoengine_openapi_client.OrderBy(order.value),
639
            filter=name_filter,
640
            _request_timeout=timeout,
641
        )
642

643
    return response
1✔
644

645

646
def dataset_info_by_name(
1✔
647
    dataset_name: DatasetName | str, timeout: int = 60
648
) -> geoengine_openapi_client.models.Dataset | None:
649
    """Get dataset information."""
650

651
    if not isinstance(dataset_name, DatasetName):
1✔
652
        dataset_name = DatasetName(dataset_name)
×
653

654
    session = get_session()
1✔
655

656
    with geoengine_openapi_client.ApiClient(session.configuration) as api_client:
1✔
657
        datasets_api = geoengine_openapi_client.DatasetsApi(api_client)
1✔
658
        res = None
1✔
659
        try:
1✔
660
            res = datasets_api.get_dataset_handler(str(dataset_name), _request_timeout=timeout)
1✔
661
        except geoengine_openapi_client.exceptions.BadRequestException as e:
1✔
662
            e_body = e.body
1✔
663
            if isinstance(e_body, str) and "CannotLoadDataset" not in e_body:
1✔
664
                raise e
×
665
        return res
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc