Skip to content

Commit 0bd163b

Browse files
authored
refactor: improve typing of RESET (#1100)
1 parent fabb472 commit 0bd163b

5 files changed

Lines changed: 38 additions & 22 deletions

File tree

components/renku_data_services/base_models/core.py

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import unicodedata
77
from dataclasses import dataclass, field
88
from datetime import datetime
9-
from enum import Enum, StrEnum
10-
from typing import ClassVar, Never, NewType, Optional, Protocol, Self, TypeVar, overload
9+
from enum import Enum, StrEnum, auto
10+
from typing import ClassVar, Never, Optional, Protocol, Self, TypeVar, overload
1111

1212
from sanic import Request
1313

@@ -400,13 +400,31 @@ async def authenticate(self, access_token: str, request: Request) -> AnyAPIUser:
400400
...
401401

402402

403-
ResetType = NewType("ResetType", object)
404-
"""This type represents that a value that may be None should be reset back to None or null.
405-
This type should have only one instance, defined in the same file as this type.
406-
"""
403+
class ResetType(Enum):
404+
"""This type represents that a value that may be None should be reset back to None.
407405
408-
RESET: ResetType = ResetType(object())
409-
"""The single instance of the ResetType, can be compared to similar to None, i.e. `if value is RESET`"""
406+
This type has a single instance, 'RESET', defined in the same file as this type.
407+
408+
Discussion about implementation: There is a in-progress PEP which once accepted would
409+
make it simpler to define 'ResetType' and 'RESET'. Until that change is adopted,
410+
using an enum with a single value comes with clear type-checking advantages.
411+
412+
See:
413+
* PEP 661 - Sentinel Values: https://peps.python.org/pep-0661/
414+
* Discussion about PEP 661: https://discuss.python.org/t/pep-661-sentinel-values/9126
415+
"""
416+
417+
Reset = auto()
418+
419+
def __repr__(self) -> str:
420+
return "RESET"
421+
422+
def __str__(self) -> str:
423+
return "RESET"
424+
425+
426+
RESET = ResetType.Reset
427+
"""The single instance of the ResetType, can be compared to similar to None, i.e. `if value is RESET`."""
410428

411429

412430
class ResourceType(StrEnum):

components/renku_data_services/crc/core.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def validate_resource_pool_update(existing: models.ResourcePool, update: models.
260260
quota: models.Quota | models.UnsavedQuota | ResetType = existing.quota if existing.quota else RESET
261261
if update.quota is RESET:
262262
quota = RESET
263-
elif isinstance(update.quota, models.QuotaPatch) and existing.quota is None:
263+
elif update.quota is not None and existing.quota is None:
264264
# The quota patch needs to contain all required fields
265265
cpu = update.quota.cpu
266266
if cpu is None:
@@ -294,7 +294,7 @@ def validate_resource_pool_update(existing: models.ResourcePool, update: models.
294294
remote: models.RemoteConfigurationFirecrest | ResetType = existing.remote if existing.remote else RESET
295295
if update.remote is RESET:
296296
remote = RESET
297-
elif isinstance(update.remote, models.RemoteConfigurationFirecrestPatch) and existing.remote is None:
297+
elif update.remote is not None and existing.remote is None:
298298
# The remote patch needs to contain all required fields
299299
kind = update.remote.kind
300300
if kind is None:

components/renku_data_services/crc/db.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ async def update_resource_pool(
426426

427427
if update.cluster_id is RESET:
428428
rp.cluster_id = None
429-
elif isinstance(update.cluster_id, ULID):
429+
elif update.cluster_id is not None:
430430
cluster = await self.__cluster_repo.select(update.cluster_id)
431431
rp.cluster_id = cluster.id
432432

@@ -471,7 +471,7 @@ async def update_resource_pool(
471471
if update.remote is RESET:
472472
rp.remote_provider_id = None
473473
rp.remote_json = None
474-
elif isinstance(update.remote, models.RemoteConfigurationFirecrestPatch):
474+
elif update.remote is not None:
475475
rp.remote_provider_id = (
476476
update.remote.provider_id if update.remote.provider_id is not None else rp.remote_provider_id
477477
)

components/renku_data_services/project/db.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import string
88
from collections.abc import AsyncGenerator, Awaitable, Callable
99
from datetime import UTC, datetime
10-
from pathlib import PurePosixPath
1110
from typing import Concatenate, ParamSpec, TypeVar
1211

1312
from cryptography.hazmat.primitives.asymmetric import rsa
@@ -368,9 +367,9 @@ async def update_project(
368367
project.template_id = None
369368
if patch.is_template is not None:
370369
project.is_template = patch.is_template
371-
if patch.secrets_mount_directory is not None and patch.secrets_mount_directory is RESET:
370+
if patch.secrets_mount_directory is RESET:
372371
project.secrets_mount_directory = constants.DEFAULT_SESSION_SECRETS_MOUNT_DIR
373-
elif patch.secrets_mount_directory is not None and isinstance(patch.secrets_mount_directory, PurePosixPath):
372+
elif patch.secrets_mount_directory is not None:
374373
project.secrets_mount_directory = patch.secrets_mount_directory
375374

376375
await session.flush()

components/renku_data_services/session/db.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from collections.abc import Callable
66
from contextlib import AbstractAsyncContextManager, nullcontext
77
from datetime import UTC, datetime
8-
from pathlib import PurePosixPath
98
from typing import TYPE_CHECKING
109

1110
from sqlalchemy import select
@@ -230,25 +229,25 @@ def __update_environment(
230229
environment.default_url = update.default_url
231230
if update.port is not None:
232231
environment.port = update.port
233-
if update.working_directory is not None and update.working_directory is RESET:
232+
if update.working_directory is RESET:
234233
environment.working_directory = None
235-
elif update.working_directory is not None and isinstance(update.working_directory, PurePosixPath):
234+
elif update.working_directory is not None:
236235
environment.working_directory = update.working_directory
237-
if update.mount_directory is not None and update.mount_directory is RESET:
236+
if update.mount_directory is RESET:
238237
environment.mount_directory = None
239-
elif update.mount_directory is not None and isinstance(update.mount_directory, PurePosixPath):
238+
elif update.mount_directory is not None:
240239
environment.mount_directory = update.mount_directory
241240
if update.uid is not None:
242241
environment.uid = update.uid
243242
if update.gid is not None:
244243
environment.gid = update.gid
245244
if update.args is RESET:
246245
environment.args = None
247-
elif isinstance(update.args, list):
246+
elif update.args is not None:
248247
environment.args = update.args
249248
if update.command is RESET:
250249
environment.command = None
251-
elif isinstance(update.command, list):
250+
elif update.command is not None:
252251
environment.command = update.command
253252
if update.is_archived is not None:
254253
environment.is_archived = update.is_archived

0 commit comments

Comments
 (0)