or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

callbacks-handles.mdcore-ffi.mddata-conversion.mderror-handling.mdindex.mdmemory-management.mdsource-generation.mdtype-system.md

error-handling.mddocs/

0

# Error Handling and Utilities

1

2

Error management, system integration utilities, and platform-specific functionality including errno handling and Windows Unicode support.

3

4

## Capabilities

5

6

### System Error Handling

7

8

Access and manipulation of C library error codes through the errno mechanism.

9

10

```python { .api }

11

errno: property # Property for C errno access

12

13

def _get_errno(self):

14

"""Get current errno value"""

15

16

def _set_errno(self, errno):

17

"""Set errno value"""

18

```

19

20

**Usage Examples:**

21

22

```python

23

import os

24

25

# Access C errno

26

ffi = FFI()

27

ffi.cdef("FILE* fopen(const char* filename, const char* mode);")

28

libc = ffi.dlopen(None)

29

30

# Try to open non-existent file

31

result = libc.fopen(b"/nonexistent/file.txt", b"r")

32

if result == ffi.NULL:

33

error_code = ffi.errno

34

print(f"C errno: {error_code}")

35

print(f"Python equivalent: {os.strerror(error_code)}")

36

37

# Set errno manually

38

ffi.errno = 42

39

print(f"Set errno to: {ffi.errno}")

40

```

41

42

### Windows Error Handling

43

44

Windows-specific error code retrieval and formatting.

45

46

```python { .api }

47

def getwinerror(self, code=-1):

48

"""

49

Get Windows error information.

50

51

Parameters:

52

- code (int): Error code (-1 for GetLastError())

53

54

Returns:

55

tuple: (error_code, error_message) on Windows, OSError on other platforms

56

"""

57

```

58

59

**Usage Example:**

60

61

```python

62

# Windows-specific error handling

63

if sys.platform == "win32":

64

try:

65

# Some Windows API call that might fail

66

ffi.cdef("void* CreateFileA(const char* name, int access, int share, void* security, int creation, int flags, void* template);")

67

kernel32 = ffi.dlopen("kernel32.dll")

68

69

handle = kernel32.CreateFileA(b"invalid\\path\\file.txt", 0x80000000, 0, ffi.NULL, 3, 0, ffi.NULL)

70

if handle == ffi.cast("void*", -1): # INVALID_HANDLE_VALUE

71

error_code, error_msg = ffi.getwinerror()

72

print(f"Windows Error {error_code}: {error_msg}")

73

except OSError:

74

print("Not on Windows platform")

75

```

76

77

### FFI Instance Inclusion

78

79

Includes type definitions from another FFI instance for modular design.

80

81

```python { .api }

82

def include(self, ffi_to_include):

83

"""

84

Include types from another FFI instance.

85

86

Parameters:

87

- ffi_to_include: Another FFI instance to include types from

88

89

Returns:

90

None

91

92

Note: Only includes types, not functions or variables

93

"""

94

```

95

96

**Usage Example:**

97

98

```python

99

# Base types FFI

100

base_ffi = FFI()

101

base_ffi.cdef("""

102

typedef struct {

103

int x, y;

104

} point_t;

105

106

typedef struct {

107

point_t top_left;

108

point_t bottom_right;

109

} rect_t;

110

""")

111

112

# Graphics FFI that uses base types

113

graphics_ffi = FFI()

114

graphics_ffi.include(base_ffi) # Include point_t and rect_t

115

graphics_ffi.cdef("""

116

// Can now use point_t and rect_t

117

void draw_rect(rect_t rect);

118

point_t get_center(rect_t rect);

119

""")

120

```

121

122

### Windows Unicode Support

123

124

Configures Windows-specific Unicode type definitions and macros.

125

126

```python { .api }

127

def set_unicode(self, enabled_flag):

128

"""

129

Configure Windows Unicode support.

130

131

Parameters:

132

- enabled_flag (bool): Enable Unicode types and macros

133

134

Returns:

135

None

136

137

Note: Can only be called once per FFI instance

138

"""

139

```

140

141

**Usage Example:**

142

143

```python

144

# Configure for Unicode Windows API

145

ffi = FFI()

146

ffi.set_unicode(True) # Enables UNICODE and _UNICODE macros

147

148

# Now TCHAR maps to wchar_t, LPTSTR to wchar_t*, etc.

149

ffi.cdef("""

150

int MessageBoxW(void* hWnd, const TCHAR* text, const TCHAR* caption, unsigned int type);

151

""")

152

153

# For ANSI API

154

ansi_ffi = FFI()

155

ansi_ffi.set_unicode(False) # TCHAR maps to char

156

157

ansi_ffi.cdef("""

158

int MessageBoxA(void* hWnd, const TCHAR* text, const TCHAR* caption, unsigned int type);

159

""")

160

```

161

162

### One-Time Initialization

163

164

Executes functions exactly once per tag, useful for expensive initialization operations.

165

166

```python { .api }

167

def init_once(self, func, tag):

168

"""

169

Execute function once per tag.

170

171

Parameters:

172

- func: Function to execute

173

- tag: Unique identifier for this initialization

174

175

Returns:

176

Result of func() on first call, cached result on subsequent calls

177

"""

178

```

179

180

**Usage Example:**

181

182

```python

183

# Expensive initialization

184

def initialize_crypto():

185

print("Initializing cryptographic library...")

186

# Expensive setup code here

187

return {"initialized": True, "algorithms": ["AES", "RSA"]}

188

189

ffi = FFI()

190

191

# Called multiple times, but initialization happens only once

192

result1 = ffi.init_once(initialize_crypto, "crypto_init")

193

result2 = ffi.init_once(initialize_crypto, "crypto_init") # Uses cached result

194

195

print(result1 is result2) # True - same object returned

196

```

197

198

### Embedding Support

199

200

Advanced features for embedding Python in C applications.

201

202

```python { .api }

203

def embedding_api(self, csource, packed=False, pack=None):

204

"""

205

Define API for embedding Python in C.

206

207

Parameters:

208

- csource (str): C declarations for embedding API

209

- packed (bool): Pack structures

210

- pack (int): Packing alignment

211

212

Returns:

213

None

214

"""

215

216

def embedding_init_code(self, pysource):

217

"""

218

Set Python initialization code for embedding.

219

220

Parameters:

221

- pysource (str): Python code to execute on embedding initialization

222

223

Returns:

224

None

225

"""

226

227

def def_extern(self, *args, **kwds):

228

"""

229

Define external function for API mode (embedding).

230

231

Note: Only available on API-mode FFI objects

232

"""

233

```

234

235

**Usage Example:**

236

237

```python

238

# Embedding setup

239

embed_ffi = FFI()

240

241

# Define embedding API

242

embed_ffi.embedding_api("""

243

int process_data(int* input, int count);

244

char* get_status();

245

""")

246

247

# Set initialization code

248

embed_ffi.embedding_init_code("""

249

def process_data(input_ptr, count):

250

# Convert C array to Python list

251

data = ffi.unpack(ffi.cast("int*", input_ptr), count)

252

253

# Process in Python

254

result = sum(x * 2 for x in data)

255

return result

256

257

def get_status():

258

return ffi.new("char[]", b"Ready")

259

260

# Register functions

261

ffi.def_extern(process_data)

262

ffi.def_extern(get_status)

263

""")

264

```

265

266

## Exception Classes and Handling

267

268

### Exception Hierarchy

269

270

```python { .api }

271

class FFIError(Exception):

272

"""Base exception for CFFI errors"""

273

274

class CDefError(Exception):

275

"""C declaration parsing errors"""

276

277

class VerificationError(Exception):

278

"""Code verification and compilation errors"""

279

280

class VerificationMissing(Exception):

281

"""Incomplete structure definition errors"""

282

283

class PkgConfigError(Exception):

284

"""Package configuration errors"""

285

```

286

287

**Usage Examples:**

288

289

```python

290

try:

291

ffi = FFI()

292

ffi.cdef("invalid C syntax here")

293

except CDefError as e:

294

print(f"C definition error: {e}")

295

296

try:

297

ffi.cdef("struct incomplete;")

298

incomplete = ffi.new("struct incomplete *") # Error: incomplete type

299

except VerificationMissing as e:

300

print(f"Incomplete structure: {e}")

301

302

try:

303

ffi.verify("int func() { syntax error }")

304

except VerificationError as e:

305

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

306

```

307

308

## Advanced Error Handling Patterns

309

310

### Error Context Management

311

312

```python

313

class CFfiErrorContext:

314

def __init__(self, ffi, operation_name):

315

self.ffi = ffi

316

self.operation_name = operation_name

317

self.saved_errno = None

318

319

def __enter__(self):

320

# Save current errno

321

self.saved_errno = self.ffi.errno

322

return self

323

324

def __exit__(self, exc_type, exc_val, exc_tb):

325

if exc_type is None:

326

return

327

328

# Add context to exceptions

329

if isinstance(exc_val, (OSError, FFIError)):

330

current_errno = self.ffi.errno

331

if current_errno != self.saved_errno:

332

exc_val.args = exc_val.args + (f"errno changed to {current_errno} during {self.operation_name}",)

333

334

# Restore errno

335

self.ffi.errno = self.saved_errno

336

337

# Usage

338

with CFfiErrorContext(ffi, "file operations"):

339

# File operations that might change errno

340

pass

341

```

342

343

### Comprehensive Error Checking

344

345

```python

346

def safe_library_call(ffi, lib, func_name, *args, check_errno=True, check_return=None):

347

"""Safely call C library function with error checking"""

348

349

# Save errno

350

old_errno = ffi.errno if check_errno else None

351

if check_errno:

352

ffi.errno = 0

353

354

try:

355

# Get function

356

func = getattr(lib, func_name)

357

358

# Call function

359

result = func(*args)

360

361

# Check return value

362

if check_return and not check_return(result):

363

raise RuntimeError(f"{func_name} returned error value: {result}")

364

365

# Check errno

366

if check_errno and ffi.errno != 0:

367

error_msg = os.strerror(ffi.errno)

368

raise OSError(ffi.errno, f"{func_name} failed: {error_msg}")

369

370

return result

371

372

finally:

373

# Restore errno

374

if check_errno and old_errno is not None:

375

ffi.errno = old_errno

376

377

# Usage

378

ffi.cdef("FILE* fopen(const char* name, const char* mode);")

379

libc = ffi.dlopen(None)

380

381

try:

382

file_ptr = safe_library_call(

383

ffi, libc, "fopen",

384

b"test.txt", b"r",

385

check_return=lambda x: x != ffi.NULL

386

)

387

print("File opened successfully")

388

except (OSError, RuntimeError) as e:

389

print(f"Failed to open file: {e}")

390

```

391

392

### Cross-Platform Error Handling

393

394

```python

395

def get_system_error(ffi):

396

"""Get system error in a cross-platform way"""

397

if sys.platform == "win32":

398

try:

399

error_code, error_msg = ffi.getwinerror()

400

return f"Windows Error {error_code}: {error_msg}"

401

except OSError:

402

pass

403

404

# Fall back to errno

405

errno_val = ffi.errno

406

if errno_val != 0:

407

return f"System Error {errno_val}: {os.strerror(errno_val)}"

408

409

return "No system error"

410

411

# Usage in error handling

412

try:

413

# Some system operation

414

pass

415

except Exception as e:

416

system_error = get_system_error(ffi)

417

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

418

print(f"System error: {system_error}")

419

```

420

421

### Logging Integration

422

423

```python

424

import logging

425

426

class CFfiLogger:

427

def __init__(self, ffi, logger_name="cffi"):

428

self.ffi = ffi

429

self.logger = logging.getLogger(logger_name)

430

431

def log_system_state(self, level=logging.DEBUG):

432

"""Log current system error state"""

433

errno_val = self.ffi.errno

434

self.logger.log(level, f"Current errno: {errno_val}")

435

436

if sys.platform == "win32":

437

try:

438

win_error = self.ffi.getwinerror()

439

self.logger.log(level, f"Windows error: {win_error}")

440

except OSError:

441

pass

442

443

def wrap_call(self, func, *args, **kwargs):

444

"""Wrap function call with logging"""

445

self.logger.debug(f"Calling {func.__name__} with args: {args}")

446

self.log_system_state()

447

448

try:

449

result = func(*args, **kwargs)

450

self.logger.debug(f"{func.__name__} returned: {result}")

451

return result

452

except Exception as e:

453

self.logger.error(f"{func.__name__} failed: {e}")

454

self.log_system_state(logging.ERROR)

455

raise

456

457

# Usage

458

logger = CFfiLogger(ffi)

459

logger.wrap_call(libc.fopen, b"test.txt", b"r")

460

```