1- # SQLModel declares columns as plain annotations (e.g. ``id: int | None``) rather
2- # than ``Mapped[int]``, so Pyright reads ``Column == value`` as ``bool`` and
3- # misjudges ``where()``/``select()``/``selectinload`` calls; nullable columns
4- # (``deleted_at``, ``released_at``) additionally trip ``reportOptionalMemberAccess``
5- # on ``.is_(None)``. These are framework false positives; the queries are valid at
6- # runtime. Other rules stay enabled so real bugs still surface.
7- # pyright: reportArgumentType=false, reportCallIssue=false, reportAttributeAccessIssue=false, reportOptionalMemberAccess=false
8-
91from __future__ import annotations
102
113import hashlib
@@ -179,7 +171,11 @@ def _generate_grid_over_aoi(
179171 # `intersection` can return a Polygon, MultiPolygon,
180172 # or GeometryCollection; retain polygon pieces only.
181173 geoms = (
182- list (clipped .geoms ) if hasattr (clipped , "geoms" ) else [clipped ]
174+ list (
175+ clipped .geoms # pyright: ignore[reportAttributeAccessIssue]
176+ )
177+ if hasattr (clipped , "geoms" )
178+ else [clipped ]
183179 )
184180 for piece in geoms :
185181 if isinstance (piece , ShapelyPolygon ) and piece .area > 0 :
@@ -215,7 +211,11 @@ async def _get_project(self, workspace_id: int, project_id: int) -> TaskingProje
215211 select (TaskingProject ).where (
216212 (TaskingProject .id == project_id )
217213 & (TaskingProject .workspace_id == workspace_id )
218- & (TaskingProject .deleted_at .is_ (None ))
214+ & (
215+ TaskingProject .deleted_at .is_ ( # pyright: ignore[reportAttributeAccessIssue, reportOptionalMemberAccess]
216+ None
217+ )
218+ )
219219 )
220220 )
221221 project = rs .scalar_one_or_none ()
@@ -226,7 +226,9 @@ async def _get_project(self, workspace_id: int, project_id: int) -> TaskingProje
226226 async def _get_task (self , project_id : int , task_number : int ) -> TaskingTask :
227227 rs = await self .session .execute (
228228 select (TaskingTask ).where (
229- (TaskingTask .project_id == project_id )
229+ (
230+ TaskingTask .project_id == project_id
231+ ) # pyright: ignore[reportArgumentType]
230232 & (TaskingTask .task_number == task_number )
231233 )
232234 )
@@ -240,7 +242,12 @@ async def _get_task(self, project_id: int, task_number: int) -> TaskingTask:
240242 async def _get_active_lock (self , task_id : int ) -> Optional [TaskingLock ]:
241243 rs = await self .session .execute (
242244 select (TaskingLock ).where (
243- (TaskingLock .task_id == task_id ) & (TaskingLock .released_at .is_ (None ))
245+ (TaskingLock .task_id == task_id )
246+ & (
247+ TaskingLock .released_at .is_ ( # pyright: ignore[reportAttributeAccessIssue, reportOptionalMemberAccess]
248+ None
249+ )
250+ )
244251 )
245252 )
246253 return rs .scalar_one_or_none ()
@@ -252,7 +259,11 @@ async def _get_active_lock_for_user_in_project(
252259 select (TaskingLock ).where (
253260 (TaskingLock .project_id == project_id )
254261 & (TaskingLock .user_auth_uid == user_auth_uid )
255- & (TaskingLock .released_at .is_ (None ))
262+ & (
263+ TaskingLock .released_at .is_ ( # pyright: ignore[reportAttributeAccessIssue, reportOptionalMemberAccess]
264+ None
265+ )
266+ )
256267 )
257268 )
258269 return rs .scalar_one_or_none ()
@@ -390,7 +401,9 @@ async def generate_grid(
390401 if isinstance (aoi_geom , ShapelyPolygon ):
391402 aoi_geom = ShapelyMultiPolygon ([aoi_geom ])
392403
393- cells = _generate_grid_over_aoi (aoi_geom , float (cell_size_m ))
404+ cells = _generate_grid_over_aoi (
405+ aoi_geom , float (cell_size_m ) # pyright: ignore[reportArgumentType]
406+ )
394407 if not cells :
395408 raise HTTPException (
396409 status_code = status .HTTP_422_UNPROCESSABLE_ENTITY ,
@@ -537,7 +550,9 @@ async def save(
537550 task = TaskingTask (
538551 project_id = project .id , # type: ignore[arg-type]
539552 task_number = idx + 1 ,
540- area_sqkm = round (_polygon_area_km2 (poly ), 4 ),
553+ area_sqkm = round (
554+ _polygon_area_km2 (poly ), 4
555+ ), # pyright: ignore[reportArgumentType]
541556 status = TaskStatus .TO_MAP ,
542557 geometry = from_shape (poly , srid = 4326 ),
543558 )
@@ -549,7 +564,9 @@ async def save(
549564 # Set boundary type + bump project updated_at.
550565 await self .session .execute (
551566 update (TaskingProject )
552- .where (TaskingProject .id == project .id )
567+ .where (
568+ TaskingProject .id == project .id # pyright: ignore[reportArgumentType]
569+ )
553570 .values (
554571 task_boundary_type = body .source ,
555572 updated_at = datetime .now (),
@@ -616,7 +633,9 @@ async def list_tasks(
616633 where = where & (TaskingTask .last_mapper_id == str (last_mapper_id ))
617634
618635 total_q = await self .session .execute (
619- select (func .count ()).select_from (TaskingTask ).where (where )
636+ select (func .count ())
637+ .select_from (TaskingTask )
638+ .where (where ) # pyright: ignore[reportArgumentType]
620639 )
621640 total = int (total_q .scalar () or 0 )
622641
@@ -626,8 +645,10 @@ async def list_tasks(
626645
627646 rows = await self .session .execute (
628647 select (TaskingTask )
629- .where (where )
630- .order_by (TaskingTask .task_number .asc ())
648+ .where (where ) # pyright: ignore[reportArgumentType]
649+ .order_by (
650+ TaskingTask .task_number .asc () # pyright: ignore[reportAttributeAccessIssue]
651+ )
631652 .limit (page_size )
632653 .offset (offset )
633654 )
@@ -727,7 +748,10 @@ async def lock_task(
727748 )
728749 if other is not None :
729750 other_task_rs = await self .session .execute (
730- select (TaskingTask ).where (TaskingTask .id == other .task_id )
751+ select (TaskingTask ).where (
752+ TaskingTask .id
753+ == other .task_id # pyright: ignore[reportArgumentType]
754+ )
731755 )
732756 other_task = other_task_rs .scalar_one ()
733757 summary = ExistingLockSummary (
@@ -803,7 +827,7 @@ async def unlock_task(
803827 now = datetime .now ()
804828 await self .session .execute (
805829 update (TaskingLock )
806- .where (TaskingLock .id == lock .id )
830+ .where (TaskingLock .id == lock .id ) # pyright: ignore[reportArgumentType]
807831 .values (released_at = now , release_reason = release_reason )
808832 )
809833 await self ._audit (
@@ -846,7 +870,7 @@ async def extend_lock(
846870 new_expiry = prev + timedelta (hours = project .lock_timeout_hours )
847871 await self .session .execute (
848872 update (TaskingLock )
849- .where (TaskingLock .id == lock .id )
873+ .where (TaskingLock .id == lock .id ) # pyright: ignore[reportArgumentType]
850874 .values (expires_at = new_expiry )
851875 )
852876 await self ._audit (
@@ -884,7 +908,7 @@ async def reset_task(
884908 if lock is not None :
885909 await self .session .execute (
886910 update (TaskingLock )
887- .where (TaskingLock .id == lock .id )
911+ .where (TaskingLock .id == lock .id ) # pyright: ignore[reportArgumentType]
888912 .values (
889913 released_at = now ,
890914 release_reason = LockReleaseReason .RESET ,
@@ -905,7 +929,7 @@ async def reset_task(
905929 if previous_status != TaskStatus .TO_MAP :
906930 await self .session .execute (
907931 update (TaskingTask )
908- .where (TaskingTask .id == task .id )
932+ .where (TaskingTask .id == task .id ) # pyright: ignore[reportArgumentType]
909933 .values (
910934 status = TaskStatus .TO_MAP ,
911935 last_mapper_id = None ,
@@ -927,7 +951,7 @@ async def reset_task(
927951 # Clear last_mapper_id even if state was already to_map.
928952 await self .session .execute (
929953 update (TaskingTask )
930- .where (TaskingTask .id == task .id )
954+ .where (TaskingTask .id == task .id ) # pyright: ignore[reportArgumentType]
931955 .values (last_mapper_id = None , updated_at = now )
932956 )
933957
@@ -1009,7 +1033,7 @@ async def submit(
10091033 new_expiry = now + timedelta (hours = project .lock_timeout_hours )
10101034 await self .session .execute (
10111035 update (TaskingLock )
1012- .where (TaskingLock .id == lock .id )
1036+ .where (TaskingLock .id == lock .id ) # pyright: ignore[reportArgumentType]
10131037 .values (expires_at = new_expiry )
10141038 )
10151039 await self ._audit (
@@ -1075,7 +1099,7 @@ async def submit(
10751099 # Release the lock (auto_unlock).
10761100 await self .session .execute (
10771101 update (TaskingLock )
1078- .where (TaskingLock .id == lock .id )
1102+ .where (TaskingLock .id == lock .id ) # pyright: ignore[reportArgumentType]
10791103 .values (
10801104 released_at = now ,
10811105 release_reason = LockReleaseReason .AUTO_UNLOCK ,
@@ -1095,7 +1119,7 @@ async def submit(
10951119 # Apply state transition.
10961120 await self .session .execute (
10971121 update (TaskingTask )
1098- .where (TaskingTask .id == task .id )
1122+ .where (TaskingTask .id == task .id ) # pyright: ignore[reportArgumentType]
10991123 .values (
11001124 status = new_status ,
11011125 last_mapper_id = new_last_mapper ,
0 commit comments