1- import os
1+ from __future__ import annotations
2+
23import sqlite3
34import threading
5+ from typing import TYPE_CHECKING
46
57from _error import Timeout
8+
69from filelock ._api import BaseFileLock
710
11+ if TYPE_CHECKING :
12+ import os
13+
14+
815class _SQLiteLock (BaseFileLock ):
9- def __init__ (self , lock_file : str | os .PathLike [str ], timeout : float = - 1 , blocking : bool = True ):
16+ def __init__ (self , lock_file : str | os .PathLike [str ], timeout : float = - 1 , blocking : bool = True ) -> None :
1017 super ().__init__ (lock_file , timeout , blocking )
1118 self .procLock = threading .Lock ()
1219 self .con = sqlite3 .connect (self ._context .lock_file , check_same_thread = False )
@@ -20,55 +27,54 @@ def __init__(self, lock_file: str | os.PathLike[str], timeout: float = -1, block
2027 # it seems, it's possible to do this read-write locking without table data
2128 # modification at each exclusive lock.
2229 # See https://sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
23- self .con .execute (' PRAGMA journal_mode=DELETE;' )
30+ self .con .execute (" PRAGMA journal_mode=DELETE;" )
2431 self .cur = None
25-
26- def _release (self ):
32+
33+ def _release (self ) -> None :
2734 with self .procLock :
2835 if self .cur is None :
2936 return # Nothing to release
3037 try :
31- self .cur .execute (' ROLLBACK TRANSACTION;' )
38+ self .cur .execute (" ROLLBACK TRANSACTION;" )
3239 except sqlite3 .ProgrammingError :
3340 pass # Already rolled back or transaction not active
3441 finally :
3542 self .cur .close ()
3643 self .cur = None
3744
45+
3846class WriteLock (_SQLiteLock ):
3947 def _acquire (self ) -> None :
40- timeout_ms = int (self ._context .timeout * 1000 ) if self ._context .blocking else 0
48+ timeout_ms = int (self ._context .timeout * 1000 ) if self ._context .blocking else 0
4149 with self .procLock :
4250 if self .cur is not None :
4351 return
44- self .con .execute (' PRAGMA busy_timeout=?;' , (timeout_ms ,))
52+ self .con .execute (" PRAGMA busy_timeout=?;" , (timeout_ms ,))
4553 try :
46- self .cur = self .con .execute (' BEGIN EXCLUSIVE TRANSACTION;' )
54+ self .cur = self .con .execute (" BEGIN EXCLUSIVE TRANSACTION;" )
4755 except sqlite3 .OperationalError as e :
48- if ' database is locked' not in str (e ):
56+ if " database is locked" not in str (e ):
4957 raise # Re-raise unexpected errors
5058 raise Timeout (self ._context .lock_file )
5159
60+
5261class ReadLock (_SQLiteLock ):
53- def _acquire (self ):
62+ def _acquire (self ) -> None :
5463 timeout_ms = int (self ._context .timeout * 1000 ) if self ._context .blocking else 0
5564 with self .procLock :
5665 if self .cur is not None :
5766 return
58- self .con .execute (' PRAGMA busy_timeout=?;' , (timeout_ms ,))
67+ self .con .execute (" PRAGMA busy_timeout=?;" , (timeout_ms ,))
5968 cur = None # Initialize cur to avoid potential UnboundLocalError
6069 try :
61- cur = self .con .execute (' BEGIN TRANSACTION;' )
70+ cur = self .con .execute (" BEGIN TRANSACTION;" )
6271 # BEGIN doesn't itself acquire a SHARED lock on the db, that is needed for
6372 # effective exclusion with writeLock(). A SELECT is needed.
64- cur .execute (' SELECT name from sqlite_schema LIMIT 1;' )
73+ cur .execute (" SELECT name from sqlite_schema LIMIT 1;" )
6574 self .cur = cur
6675 except sqlite3 .OperationalError as e :
67- if ' database is locked' not in str (e ):
76+ if " database is locked" not in str (e ):
6877 raise # Re-raise unexpected errors
6978 if cur is not None :
7079 cur .close ()
7180 raise Timeout (self ._context .lock_file )
72-
73-
74-
0 commit comments