Skip to content
This repository has been archived by the owner on Aug 2, 2023. It is now read-only.

Commit

Permalink
Update mypy to 0.930 (#508)
Browse files Browse the repository at this point in the history
* setup: Set the minimum mypy version to 0.930
* fix: New typecheck errors due to stricter enum validation
* fix: Workaround limitation of type variable usage in ClassVar

  We just fallback to `typing.Any` and make an explicit type-cast, instead of
  resolving the generic type argument at runtime to automatically get
  the reference to `uuid_subtype_func`.

  Here is the story:

  Currently Python does not allow introspection of generic type arguments
  in runtime.  For some limited cases, we could refer `__orig_bases__`, but
  somehow it does not work for us and it is a known limitation that we
  cann t resolve it early in the object lifecycle.
  (ref: https://stackoverflow.com/questions/57706180, python/typing#658)

  Moreover, SQLAlchemy's `TypeDecorator` also involves its own metaclass logic
  from `TraversibleType`, which makes `__orig_class__` unavailable.
  • Loading branch information
achimnol authored Dec 27, 2021
1 parent a508ebc commit cf1ef92
Show file tree
Hide file tree
Showing 6 changed files with 13 additions and 8 deletions.
1 change: 1 addition & 0 deletions changes/508.fix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update mypy to 0.930 and fix newly discovered type errors
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ lint =
flake8>=4.0.1
flake8-commas>=2.1
typecheck =
mypy>=0.910
mypy>=0.930
types-click
types-Jinja2
types-pkg_resources
Expand Down
2 changes: 1 addition & 1 deletion src/ai/backend/manager/defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

# PostgreSQL session-level advisory lock indentifiers
class AdvisoryLock(enum.IntEnum):
LOCKID_TEST = 1
LOCKID_TEST = 42
LOCKID_SCHEDULE = 91
LOCKID_PREPARE = 92
LOCKID_SCHEDULE_TIMER = 191
Expand Down
4 changes: 3 additions & 1 deletion src/ai/backend/manager/distributed.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
TYPE_CHECKING,
)

from .defs import AdvisoryLock

if TYPE_CHECKING:
from ai.backend.manager.models.utils import ExtendedAsyncSAEngine
from ai.backend.common.events import AbstractEvent, EventProducer
Expand Down Expand Up @@ -41,7 +43,7 @@ async def generate_tick(self) -> None:
try:
await asyncio.sleep(self.initial_delay)
while True:
async with self.db.advisory_lock(self.timer_id):
async with self.db.advisory_lock(AdvisoryLock(self.timer_id)):
await self._event_producer.produce_event(self._event_factory())
await asyncio.sleep(self.interval)
except asyncio.CancelledError:
Expand Down
9 changes: 5 additions & 4 deletions src/ai/backend/manager/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
Type,
TypeVar,
Union,
cast,
)
import sys
import uuid
Expand Down Expand Up @@ -204,7 +205,7 @@ class GUID(TypeDecorator, Generic[UUID_SubType]):
Uses PostgreSQL's UUID type, otherwise uses CHAR(16) storing as raw bytes.
"""
impl = CHAR
uuid_subtype_func: ClassVar[Callable[[Any], UUID_SubType]] = lambda v: v
uuid_subtype_func: ClassVar[Callable[[Any], Any]] = lambda v: v
cache_ok = True

def load_dialect_impl(self, dialect):
Expand Down Expand Up @@ -236,14 +237,14 @@ def process_result_value(self, value: Any, dialect) -> Optional[UUID_SubType]:
return value
else:
cls = type(self)
return cls.uuid_subtype_func(uuid.UUID(value))
return cast(UUID_SubType, cls.uuid_subtype_func(uuid.UUID(value)))


class SessionIDColumnType(GUID):
class SessionIDColumnType(GUID[SessionId]):
uuid_subtype_func = SessionId


class KernelIDColumnType(GUID):
class KernelIDColumnType(GUID[KernelId]):
uuid_subtype_func = KernelId


Expand Down
3 changes: 2 additions & 1 deletion tests/test_advisory_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pytest

from ai.backend.manager.defs import AdvisoryLock
from ai.backend.manager.models.utils import ExtendedAsyncSAEngine


Expand All @@ -13,7 +14,7 @@ async def test_lock(database_engine: ExtendedAsyncSAEngine) -> None:

async def critical_section(db: ExtendedAsyncSAEngine) -> None:
nonlocal enter_count
async with db.advisory_lock(42):
async with db.advisory_lock(AdvisoryLock.LOCKID_TEST):
enter_count += 1
await asyncio.sleep(1.0)

Expand Down

0 comments on commit cf1ef92

Please # to comment.