or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

file-locking.mdindex.mdlock-classes.mdredis-locking.mdsemaphores.mdutilities.md

lock-classes.mddocs/

0

# Lock Classes

1

2

High-level lock managers with built-in timeout, context manager support, and advanced features like reentrant locks and temporary file locks. These classes provide a more convenient interface than the low-level lock/unlock functions.

3

4

## Capabilities

5

6

### Lock Class

7

8

The primary high-level lock manager with automatic file handling, timeout support, and context manager interface.

9

10

```python { .api }

11

class Lock:

12

"""

13

Lock manager with built-in timeout and context manager support.

14

15

Parameters:

16

- filename: Path to file to lock (str or pathlib.Path)

17

- mode: File open mode ('a', 'r+', 'w+', etc.). 'w' modes truncate after lock acquisition

18

- timeout: Timeout in seconds when trying to acquire lock (default: 5.0)

19

- check_interval: Check interval while waiting for lock (default: 0.25)

20

- fail_when_locked: Fail immediately if initial lock fails (default: False)

21

- flags: Lock flags (default: LOCK_EX | LOCK_NB)

22

- **file_open_kwargs: Additional arguments passed to open()

23

"""

24

25

def __init__(self, filename: Filename, mode: str = 'a', timeout: float | None = None,

26

check_interval: float = 0.25, fail_when_locked: bool = False,

27

flags: LockFlags = LOCK_EX | LOCK_NB, **file_open_kwargs) -> None: ...

28

29

def acquire(self, timeout: float | None = None, check_interval: float | None = None,

30

fail_when_locked: bool | None = None) -> typing.IO:

31

"""

32

Acquire the file lock and return file handle.

33

34

Parameters:

35

- timeout: Override default timeout

36

- check_interval: Override default check interval

37

- fail_when_locked: Override default fail_when_locked behavior

38

39

Returns:

40

- File handle for the locked file

41

42

Raises:

43

- AlreadyLocked: If lock cannot be acquired and fail_when_locked=True

44

- LockException: If locking fails due to system error

45

"""

46

47

def release(self) -> None:

48

"""Release the currently held lock and close file handle"""

49

50

def __enter__(self) -> typing.IO:

51

"""Context manager entry - acquire lock and return file handle"""

52

53

def __exit__(self, exc_type, exc_value, traceback) -> None:

54

"""Context manager exit - release lock"""

55

```

56

57

### Reentrant Lock (RLock)

58

59

A reentrant lock that can be acquired multiple times by the same process, similar to threading.RLock.

60

61

```python { .api }

62

class RLock(Lock):

63

"""

64

Reentrant lock that can be acquired multiple times by the same process.

65

Must be released the same number of times it was acquired.

66

"""

67

68

def __init__(self, filename: Filename, mode: str = 'a', timeout: float = 5.0,

69

check_interval: float = 0.25, fail_when_locked: bool = False,

70

flags: LockFlags = LOCK_EX | LOCK_NB) -> None: ...

71

72

def acquire(self, timeout: float | None = None, check_interval: float | None = None,

73

fail_when_locked: bool | None = None) -> typing.IO:

74

"""Acquire lock (can be called multiple times by same process)"""

75

76

def release(self) -> None:

77

"""Release lock (must match number of acquire() calls)"""

78

```

79

80

### Temporary File Lock

81

82

A lock that uses a temporary file and automatically cleans up the lock file when released.

83

84

```python { .api }

85

class TemporaryFileLock(Lock):

86

"""

87

Temporary file lock that auto-deletes the lock file on release.

88

Automatically registers cleanup with atexit.

89

"""

90

91

def __init__(self, filename: str = '.lock', timeout: float = 5.0,

92

check_interval: float = 0.25, fail_when_locked: bool = True,

93

flags: LockFlags = LOCK_EX | LOCK_NB) -> None: ...

94

95

def release(self) -> None:

96

"""Release lock and delete the temporary lock file"""

97

```

98

99

### Usage Examples

100

101

Basic usage with context manager:

102

103

```python

104

import portalocker

105

106

# Simple file locking with automatic cleanup

107

with portalocker.Lock('data.txt', 'r+', timeout=10.0) as fh:

108

# File is automatically locked here

109

data = fh.read()

110

fh.seek(0)

111

fh.write('modified: ' + data)

112

fh.truncate()

113

# File is automatically unlocked and closed here

114

```

115

116

Manual lock management:

117

118

```python

119

import portalocker

120

121

# Create lock object

122

lock = portalocker.Lock('data.txt', mode='r+', timeout=5.0)

123

124

try:

125

# Acquire lock

126

fh = lock.acquire()

127

128

# Work with file

129

data = fh.read()

130

fh.write('new data')

131

132

finally:

133

# Always release lock

134

lock.release()

135

```

136

137

Reentrant locking:

138

139

```python

140

import portalocker

141

142

def process_file_nested():

143

with portalocker.RLock('data.txt', 'r+') as fh1:

144

# First lock acquisition

145

data = fh1.read()

146

147

# Nested function that also needs the same lock

148

with portalocker.RLock('data.txt', 'r+') as fh2:

149

# Second lock acquisition by same process - succeeds

150

fh2.write('nested access: ' + data)

151

152

# First lock still held here

153

fh1.write('outer access completed')

154

# All locks released here

155

```

156

157

Temporary lock files:

158

159

```python

160

import portalocker

161

162

# Create a temporary lock for process coordination

163

with portalocker.TemporaryFileLock('/tmp/my_process.lock') as fh:

164

# Only one instance of this process can run

165

print("Starting exclusive process...")

166

do_exclusive_work()

167

print("Process completed")

168

# Lock file is automatically deleted

169

```

170

171

Non-blocking behavior:

172

173

```python

174

import portalocker

175

176

try:

177

# Fail immediately if file is already locked

178

with portalocker.Lock('data.txt', fail_when_locked=True, timeout=0) as fh:

179

process_file(fh)

180

except portalocker.AlreadyLocked:

181

print("File is currently being processed by another instance")

182

```

183

184

Custom file open parameters:

185

186

```python

187

import portalocker

188

189

# Pass additional parameters to open()

190

with portalocker.Lock('data.txt', 'r+', encoding='utf-8', buffering=1) as fh:

191

# File opened with custom encoding and line buffering

192

text_data = fh.read()

193

fh.write('unicode data: ' + text_data)

194

```

195

196

Timeout and retry behavior:

197

198

```python

199

import portalocker

200

import time

201

202

# Custom timeout and check intervals

203

lock = portalocker.Lock(

204

'data.txt',

205

timeout=30.0, # Wait up to 30 seconds

206

check_interval=0.5, # Check every 500ms

207

fail_when_locked=False # Keep retrying until timeout

208

)

209

210

try:

211

with lock:

212

# Will retry acquiring lock for up to 30 seconds

213

process_file()

214

except portalocker.LockException:

215

print("Could not acquire lock within 30 seconds")

216

```

217

218

## Error Handling

219

220

Lock classes raise the same exceptions as the low-level functions:

221

222

```python

223

try:

224

with portalocker.Lock('data.txt', fail_when_locked=True) as fh:

225

process_file(fh)

226

except portalocker.AlreadyLocked as e:

227

print(f"File is locked: {e}")

228

except portalocker.LockException as e:

229

print(f"Lock failed: {e}")

230

except FileNotFoundError:

231

print("File does not exist")

232

```

233

234

## Type Definitions

235

236

```python { .api }

237

from typing import Union

238

import pathlib

239

import typing

240

241

Filename = Union[str, pathlib.Path]

242

243

class LockFlags(enum.IntFlag):

244

EXCLUSIVE: int

245

SHARED: int

246

NON_BLOCKING: int

247

UNBLOCK: int

248

249

# Default lock method used by Lock classes

250

LOCK_METHOD = LockFlags.EXCLUSIVE | LockFlags.NON_BLOCKING

251

```