Skip to content

Commit

Permalink
Switches to a more strict mypy config
Browse files Browse the repository at this point in the history
  • Loading branch information
Daverball committed Jan 15, 2025
1 parent 99e5162 commit 0d0976a
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 26 deletions.
8 changes: 3 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,12 @@ replace = """

[tool.mypy]
python_version = "3.9"
follow_imports = "silent"
namespace_packages = true
explicit_package_bases = true
warn_unused_ignores = true
warn_redundant_casts = true
strict = true
warn_unreachable = true
disallow_any_generics = true
disallow_untyped_defs = true
# FIXME: remove this exclusion when upgrading to SQlAlchemy 2.0
untyped_calls_exclude = "sqlalchemy"
plugins = "sqlmypy"
mypy_path = "$MYPY_CONFIG_FILE_DIR/src"

Expand Down
10 changes: 5 additions & 5 deletions src/libres/context/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ class ContextServicesMixin:

@cached_property
def is_allocation_exposed(self) -> Callable[[Allocation], bool]:
return self.context.get_service('exposure').is_allocation_exposed
return self.context.get_service('exposure').is_allocation_exposed # type: ignore[no-any-return]

@cached_property
def generate_uuid(self) -> Callable[[str], UUID]:
return self.context.get_service('uuid_generator')
return self.context.get_service('uuid_generator') # type: ignore[no-any-return]

@cached_property
def validate_email(self) -> Callable[[str], bool]:
return self.context.get_service('email_validator')
return self.context.get_service('email_validator') # type: ignore[no-any-return]

def clear_cache(self) -> None:
""" Clears the cache of the mixin. """
Expand All @@ -91,12 +91,12 @@ def clear_cache(self) -> None:

@property
def session_provider(self) -> SessionProvider:
return self.context.get_service('session_provider')
return self.context.get_service('session_provider') # type: ignore[no-any-return]

@property
def session(self) -> Session:
""" Returns the current session. """
return self.session_provider.session()
return self.session_provider.session() # type: ignore[no-any-return]

def close(self) -> None:
""" Closes the current session. """
Expand Down
2 changes: 1 addition & 1 deletion src/libres/context/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def current_context(self) -> Context:
if not hasattr(self.local, 'current_context'):
self.local.current_context = self.master_context

return self.local.current_context
return self.local.current_context # type: ignore[no-any-return]

def is_existing_context(self, name: str) -> bool:
return name in self.contexts
Expand Down
17 changes: 13 additions & 4 deletions src/libres/db/models/allocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,18 @@
from collections.abc import Iterator
from sedate.types import TzInfoOrName
from sqlalchemy.orm import Query
from typing import NamedTuple
from typing_extensions import Self

from libres.db.models import Reservation, ReservedSlot
from libres.db.models import ReservedSlot
from libres.modules.rasterizer import Raster

_OptDT1 = TypeVar('_OptDT1', 'datetime | None', datetime, None)
_OptDT2 = TypeVar('_OptDT2', 'datetime | None', datetime, None)

class _ReservationIdRow(NamedTuple):
id: int


class Allocation(TimestampMixin, ORMBase, OtherModels):
"""Describes a timespan within which one or many timeslots can be
Expand Down Expand Up @@ -470,7 +474,7 @@ def limit_timespan(
return self.display_start(timezone), self.display_end(timezone)

@property
def pending_reservations(self) -> Query[Reservation]:
def pending_reservations(self) -> Query[_ReservationIdRow]:
""" Returns the pending reservations query for this allocation.
As the pending reservations target the group and not a specific
allocation this function returns the same value for masters and
Expand All @@ -482,6 +486,7 @@ def pending_reservations(self) -> Query[Reservation]:
)

Reservation = self.models.Reservation # noqa: N806
query: Query[_ReservationIdRow]
query = object_session(self).query(Reservation.id)
query = query.filter(Reservation.target == self.group)
query = query.filter(Reservation.status == 'pending')
Expand Down Expand Up @@ -794,7 +799,9 @@ def get_master(self) -> Self:
if self.is_master:
return self
else:
query = object_session(self).query(Allocation)
# FIXME: This should either query `self.__class__` or
# we need to return `Allocation` rather than `Self`
query: Query[Self] = object_session(self).query(Allocation)
query = query.filter(Allocation._start == self._start)
query = query.filter(Allocation.resource == self.mirror_of)

Expand All @@ -818,7 +825,9 @@ def siblings(self, imaginary: bool = True) -> list[Self]:
assert self.is_master
return [self]

query = object_session(self).query(Allocation)
# FIXME: This should either query `self.__class__` or
# we need to return `Allocation` rather than `Self`
query: Query[Self] = object_session(self).query(Allocation)
query = query.filter(Allocation.mirror_of == self.mirror_of)
query = query.filter(Allocation._start == self._start)

Expand Down
4 changes: 2 additions & 2 deletions src/libres/db/models/reservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def _target_allocations(self) -> Query[Allocation]:
# order by date
query = query.order_by(Allocation._start)

return query
return query # type: ignore[no-any-return]

def display_start(
self,
Expand Down Expand Up @@ -212,4 +212,4 @@ def autoapprovable(self) -> bool:
# A reservation is deemed autoapprovable if no allocation
# requires explicit approval

return object_session(self).query(~query.exists()).scalar()
return object_session(self).query(~query.exists()).scalar() # type: ignore[no-any-return]
8 changes: 3 additions & 5 deletions src/libres/db/models/types/json_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ class JSON(_Base):
"""

# Use TEXT for now to stay compatible with Postgres 9.1. In the future
# this will be replaced by JSON (or JSONB) though that requires that we
# require a later Postgres release. For now we stay backwards compatible
# with a version that's still widely used (9.1).
# FIXME: We should switch to JSONB now, but we will need to
# add a database migration to OneGov at the same time
impl = TEXT

def process_bind_param(
Expand All @@ -37,7 +35,7 @@ def process_bind_param(
if value is not None:
value = (dialect._json_serializer or dumps)(value) # type:ignore

return value
return value # type: ignore[no-any-return]

def process_result_value(
self,
Expand Down
12 changes: 8 additions & 4 deletions src/libres/db/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,10 @@ def allocation_dates_by_group(
) -> list[tuple[datetime, datetime]]:

query = self.allocations_by_group(group)
dates_query = query.with_entities(Allocation._start, Allocation._end)
dates_query: Query[tuple[datetime, datetime]] = query.with_entities(
Allocation._start,
Allocation._end
)
return dates_query.all()

def allocation_mirrors_by_master(
Expand Down Expand Up @@ -336,7 +339,7 @@ def manual_approval_required(self, ids: Collection[int]) -> bool:
query = self.allocations_by_ids(ids)
query = query.filter(Allocation.approve_manually == True)

return self.session.query(query.exists()).scalar()
return self.session.query(query.exists()).scalar() # type: ignore[no-any-return]

def allocate(
self,
Expand Down Expand Up @@ -1273,8 +1276,9 @@ def new_reservations_by_dates(
# reservation twice on a single session
if session_id:
found = self.queries.reservations_by_session(session_id)
found = found.with_entities(Reservation.target, Reservation.start)
found_set = set(found)
found_set: set[tuple[UUID, datetime | None]] = set(
found.with_entities(Reservation.target, Reservation.start)
)

for reservation in reservations:
if (reservation.target, reservation.start) in found_set:
Expand Down

0 comments on commit 0d0976a

Please sign in to comment.