1
- import os
1
+ from __future__ import annotations
2
+
2
3
import sqlite3
3
4
import threading
5
+ from typing import TYPE_CHECKING
4
6
5
7
from _error import Timeout
8
+
6
9
from filelock ._api import BaseFileLock
7
10
11
+ if TYPE_CHECKING :
12
+ import os
13
+
14
+
8
15
class _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 :
10
17
super ().__init__ (lock_file , timeout , blocking )
11
18
self .procLock = threading .Lock ()
12
19
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
20
27
# it seems, it's possible to do this read-write locking without table data
21
28
# modification at each exclusive lock.
22
29
# 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;" )
24
31
self .cur = None
25
-
26
- def _release (self ):
32
+
33
+ def _release (self ) -> None :
27
34
with self .procLock :
28
35
if self .cur is None :
29
36
return # Nothing to release
30
37
try :
31
- self .cur .execute (' ROLLBACK TRANSACTION;' )
38
+ self .cur .execute (" ROLLBACK TRANSACTION;" )
32
39
except sqlite3 .ProgrammingError :
33
40
pass # Already rolled back or transaction not active
34
41
finally :
35
42
self .cur .close ()
36
43
self .cur = None
37
44
45
+
38
46
class WriteLock (_SQLiteLock ):
39
47
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
41
49
with self .procLock :
42
50
if self .cur is not None :
43
51
return
44
- self .con .execute (' PRAGMA busy_timeout=?;' , (timeout_ms ,))
52
+ self .con .execute (" PRAGMA busy_timeout=?;" , (timeout_ms ,))
45
53
try :
46
- self .cur = self .con .execute (' BEGIN EXCLUSIVE TRANSACTION;' )
54
+ self .cur = self .con .execute (" BEGIN EXCLUSIVE TRANSACTION;" )
47
55
except sqlite3 .OperationalError as e :
48
- if ' database is locked' not in str (e ):
56
+ if " database is locked" not in str (e ):
49
57
raise # Re-raise unexpected errors
50
58
raise Timeout (self ._context .lock_file )
51
59
60
+
52
61
class ReadLock (_SQLiteLock ):
53
- def _acquire (self ):
62
+ def _acquire (self ) -> None :
54
63
timeout_ms = int (self ._context .timeout * 1000 ) if self ._context .blocking else 0
55
64
with self .procLock :
56
65
if self .cur is not None :
57
66
return
58
- self .con .execute (' PRAGMA busy_timeout=?;' , (timeout_ms ,))
67
+ self .con .execute (" PRAGMA busy_timeout=?;" , (timeout_ms ,))
59
68
cur = None # Initialize cur to avoid potential UnboundLocalError
60
69
try :
61
- cur = self .con .execute (' BEGIN TRANSACTION;' )
70
+ cur = self .con .execute (" BEGIN TRANSACTION;" )
62
71
# BEGIN doesn't itself acquire a SHARED lock on the db, that is needed for
63
72
# 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;" )
65
74
self .cur = cur
66
75
except sqlite3 .OperationalError as e :
67
- if ' database is locked' not in str (e ):
76
+ if " database is locked" not in str (e ):
68
77
raise # Re-raise unexpected errors
69
78
if cur is not None :
70
79
cur .close ()
71
80
raise Timeout (self ._context .lock_file )
72
-
73
-
74
-
0 commit comments