or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdcore-serialization.mddiagnostic-tools.mdindex.mdpickler-classes.mdsession-management.mdsource-analysis.mdtemp-operations.mdtype-registry.md

diagnostic-tools.mddocs/

0

# Diagnostic Tools

1

2

dill provides comprehensive diagnostic tools for analyzing serialization capabilities, identifying problematic objects, and debugging pickling issues with detailed error reporting and analysis.

3

4

## Core Diagnostic Functions

5

6

### Pickling Capability Testing

7

8

```python { .api }

9

def pickles(obj, exact=False, safe=False, **kwds):

10

"""

11

Check if an object can be pickled.

12

13

Tests whether an object can be successfully serialized and deserialized

14

using dill, providing a simple boolean result for compatibility checking.

15

16

Parameters:

17

- obj: object to test for pickling capability

18

- exact: bool, use exact type matching for compatibility testing

19

- safe: bool, use safe mode to avoid side effects during testing

20

- **kwds: additional keyword arguments passed to dumps/loads

21

22

Returns:

23

bool: True if object can be pickled and unpickled successfully

24

25

Raises:

26

- Exception: only when safe=False and testing encounters severe errors

27

"""

28

29

def check(obj, *args, **kwds):

30

"""

31

Check for pickling errors and print diagnostic information.

32

33

Performs comprehensive pickling analysis and displays detailed

34

information about any issues encountered during serialization testing.

35

36

Parameters:

37

- obj: object to check for pickling errors

38

- *args: positional arguments passed to pickles()

39

- **kwds: keyword arguments passed to pickles()

40

41

Returns:

42

bool: True if no errors found, False if pickling issues detected

43

"""

44

```

45

46

### Problem Object Detection

47

48

```python { .api }

49

def baditems(obj, exact=False, safe=False):

50

"""

51

Find objects that cannot be pickled within a complex structure.

52

53

Recursively analyzes an object to identify specific items that

54

prevent successful serialization, helping isolate problematic components.

55

56

Parameters:

57

- obj: object to analyze for unpickleable items

58

- exact: bool, use exact type matching for analysis

59

- safe: bool, use safe mode to avoid side effects

60

61

Returns:

62

list: list of unpickleable objects found in the structure

63

"""

64

65

def badobjects(obj, depth=0, exact=False, safe=False):

66

"""

67

Get objects that fail to pickle.

68

69

Analyzes object structure at specific depth levels to identify

70

problematic objects that prevent serialization at different nesting levels.

71

72

Parameters:

73

- obj: object to analyze

74

- depth: int, analysis depth (0 for immediate object only, >0 for recursive analysis)

75

- exact: bool, use exact type matching

76

- safe: bool, use safe mode to avoid side effects

77

78

Returns:

79

object or dict: at depth=0 returns the object if it fails to pickle (None if it pickles),

80

at depth>0 returns dict mapping attribute names to bad objects

81

"""

82

83

def badtypes(obj, depth=0, exact=False, safe=False):

84

"""

85

Get types for objects that fail to pickle.

86

87

Identifies specific types that cause pickling failures, providing

88

type-level analysis of serialization compatibility issues.

89

90

Parameters:

91

- obj: object to analyze for problematic types

92

- depth: int, analysis depth (0 for immediate object only, >0 for recursive analysis)

93

- exact: bool, use exact type matching

94

- safe: bool, use safe mode

95

96

Returns:

97

type or dict: at depth=0 returns the type if object fails to pickle (None if it pickles),

98

at depth>0 returns dict mapping attribute names to problematic types

99

"""

100

101

def errors(obj, depth=0, exact=False, safe=False):

102

"""

103

Get detailed pickling error information.

104

105

Provides comprehensive error analysis including specific error messages,

106

problematic objects, and suggested solutions for pickling failures.

107

108

Parameters:

109

- obj: object to analyze for errors

110

- depth: int, maximum analysis depth (0 for unlimited)

111

- exact: bool, use exact type matching

112

- safe: bool, use safe mode to avoid side effects

113

114

Returns:

115

list: list of detailed error descriptions and diagnostic information

116

"""

117

```

118

119

## Usage Examples

120

121

### Basic Compatibility Testing

122

123

```python

124

import dill

125

126

# Test various object types

127

def test_function():

128

return "Hello from function"

129

130

class TestClass:

131

def __init__(self, value):

132

self.value = value

133

134

def method(self):

135

return self.value * 2

136

137

# Test individual objects

138

print(dill.pickles(test_function)) # True

139

print(dill.pickles(TestClass)) # True

140

print(dill.pickles(TestClass(42))) # True

141

142

# Test problematic objects

143

import threading

144

lock = threading.Lock()

145

print(dill.pickles(lock)) # False (locks can't be pickled)

146

147

# Use safe mode for testing

148

print(dill.pickles(dangerous_object, safe=True))

149

```

150

151

### Comprehensive Error Analysis

152

153

```python

154

import dill

155

156

# Complex object with potential issues

157

class ComplexObject:

158

def __init__(self):

159

self.data = [1, 2, 3]

160

self.function = lambda x: x + 1

161

self.lock = threading.Lock() # Problematic

162

self.nested = {

163

'good': 'string',

164

'bad': open('/dev/null', 'r') # File handle - problematic

165

}

166

167

complex_obj = ComplexObject()

168

169

# Quick check

170

if not dill.check(complex_obj):

171

print("Object has pickling issues")

172

173

# Find problematic items

174

bad_items = dill.baditems(complex_obj)

175

print(f"Found {len(bad_items)} unpickleable items:")

176

for item in bad_items:

177

print(f" {type(item)}: {item}")

178

179

# Get detailed error information

180

error_details = dill.errors(complex_obj)

181

print("\nDetailed errors:")

182

for error in error_details:

183

print(f" {error}")

184

```

185

186

### Automated Testing Suite

187

188

```python

189

import dill

190

191

def comprehensive_pickle_test(obj, name="object"):

192

"""Comprehensive pickling analysis for an object."""

193

print(f"\nTesting {name}...")

194

print("=" * 50)

195

196

# Basic pickling test

197

can_pickle = dill.pickles(obj, safe=True)

198

print(f"Can pickle: {can_pickle}")

199

200

if not can_pickle:

201

# Detailed analysis

202

print("\nProblematic items:")

203

bad_items = dill.baditems(obj, safe=True)

204

for i, item in enumerate(bad_items):

205

print(f" {i+1}. {type(item).__name__}: {repr(item)[:50]}...")

206

207

print("\nProblematic types:")

208

bad_types = dill.badtypes(obj, safe=True)

209

for i, bad_type in enumerate(bad_types):

210

print(f" {i+1}. {bad_type}")

211

212

print("\nError details:")

213

error_list = dill.errors(obj, safe=True)

214

for i, error in enumerate(error_list):

215

print(f" {i+1}. {error}")

216

217

return can_pickle

218

219

# Test various objects

220

test_objects = {

221

'simple_function': lambda x: x + 1,

222

'complex_class': ComplexObject(),

223

'nested_structure': {'functions': [lambda x: x, lambda y: y**2]},

224

'problematic_object': complex_obj

225

}

226

227

results = {}

228

for name, obj in test_objects.items():

229

results[name] = comprehensive_pickle_test(obj, name)

230

231

print(f"\nSummary: {sum(results.values())}/{len(results)} objects can be pickled")

232

```

233

234

### Interactive Debugging Session

235

236

```python

237

import dill

238

239

def debug_pickling_issues(obj):

240

"""Interactive debugging for pickling issues."""

241

print("Starting pickling diagnosis...")

242

243

# Step 1: Basic test

244

if dill.pickles(obj):

245

print("✓ Object can be pickled successfully")

246

return True

247

248

print("✗ Object cannot be pickled")

249

250

# Step 2: Identify bad items

251

print("\nSearching for problematic items...")

252

bad_items = dill.baditems(obj)

253

254

if not bad_items:

255

print("No specific bad items found - issue may be with object structure")

256

return False

257

258

print(f"Found {len(bad_items)} problematic items:")

259

260

# Step 3: Categorize issues

261

by_type = {}

262

for item in bad_items:

263

item_type = type(item).__name__

264

if item_type not in by_type:

265

by_type[item_type] = []

266

by_type[item_type].append(item)

267

268

# Step 4: Provide solutions

269

for item_type, items in by_type.items():

270

print(f"\n{item_type} objects ({len(items)} found):")

271

for i, item in enumerate(items[:3]): # Show first 3

272

print(f" {i+1}. {repr(item)[:60]}...")

273

274

# Suggest solutions

275

if item_type == 'Lock':

276

print(" → Solution: Remove locks or replace with serializable alternatives")

277

elif item_type == 'TextIOWrapper':

278

print(" → Solution: Close files or use file paths instead of handles")

279

elif item_type == 'module':

280

print(" → Solution: Import modules by name rather than storing references")

281

else:

282

print(f" → Solution: Remove {item_type} objects or find serializable alternatives")

283

284

return False

285

286

# Usage

287

debug_pickling_issues(problematic_object)

288

```

289

290

## Advanced Diagnostic Techniques

291

292

### Depth-Based Analysis

293

294

```python

295

import dill

296

297

def analyze_by_depth(obj, max_depth=5):

298

"""Analyze object pickling issues by depth level."""

299

print("Depth-based analysis:")

300

print("-" * 30)

301

302

for depth in range(max_depth + 1):

303

bad_objects = dill.badobjects(obj, depth=depth, safe=True)

304

bad_types = dill.badtypes(obj, depth=depth, safe=True)

305

306

print(f"Depth {depth}:")

307

print(f" Bad objects: {len(bad_objects)}")

308

print(f" Bad types: {len(set(t.__name__ for t in bad_types))}")

309

310

if bad_objects:

311

# Show sample bad objects at this depth

312

sample = bad_objects[:2]

313

for obj in sample:

314

print(f" {type(obj).__name__}: {repr(obj)[:40]}...")

315

316

# Usage

317

analyze_by_depth(complex_nested_object)

318

```

319

320

### Custom Diagnostic Rules

321

322

```python

323

import dill

324

325

class PicklingDiagnostic:

326

"""Custom diagnostic tool for pickling analysis."""

327

328

def __init__(self):

329

self.rules = {

330

'file_handles': lambda obj: hasattr(obj, 'read') and hasattr(obj, 'write'),

331

'locks': lambda obj: hasattr(obj, 'acquire') and hasattr(obj, 'release'),

332

'generators': lambda obj: hasattr(obj, '__next__') and hasattr(obj, '__iter__'),

333

'lambda_functions': lambda obj: callable(obj) and obj.__name__ == '<lambda>',

334

}

335

336

def diagnose(self, obj):

337

"""Run custom diagnostic rules."""

338

issues = {}

339

340

# Test overall pickling

341

can_pickle = dill.pickles(obj, safe=True)

342

issues['can_pickle'] = can_pickle

343

344

if can_pickle:

345

return issues

346

347

# Run custom rules

348

bad_items = dill.baditems(obj, safe=True)

349

350

for rule_name, rule_func in self.rules.items():

351

matching_items = [item for item in bad_items if rule_func(item)]

352

if matching_items:

353

issues[rule_name] = matching_items

354

355

return issues

356

357

def report(self, obj, name="object"):

358

"""Generate diagnostic report."""

359

issues = self.diagnose(obj)

360

361

print(f"Diagnostic Report for {name}")

362

print("=" * 40)

363

364

if issues.get('can_pickle', False):

365

print("✓ Object can be pickled successfully")

366

return

367

368

print("✗ Object cannot be pickled")

369

print("\nIssues found:")

370

371

for issue_type, items in issues.items():

372

if issue_type == 'can_pickle':

373

continue

374

375

print(f"\n{issue_type.replace('_', ' ').title()}:")

376

for item in items[:3]: # Show first 3

377

print(f" - {type(item).__name__}: {repr(item)[:50]}...")

378

379

# Usage

380

diagnostic = PicklingDiagnostic()

381

diagnostic.report(complex_object, "MyComplexObject")

382

```

383

384

### Performance Impact Analysis

385

386

```python

387

import dill

388

import time

389

390

def performance_diagnostic(obj, name="object"):

391

"""Analyze performance impact of pickling."""

392

print(f"Performance analysis for {name}")

393

print("-" * 40)

394

395

# Test if object can be pickled

396

if not dill.pickles(obj, safe=True):

397

print("Object cannot be pickled - skipping performance test")

398

return

399

400

# Measure serialization time

401

start_time = time.time()

402

serialized = dill.dumps(obj)

403

serialize_time = time.time() - start_time

404

405

# Measure deserialization time

406

start_time = time.time()

407

dill.loads(serialized)

408

deserialize_time = time.time() - start_time

409

410

# Report results

411

print(f"Serialization time: {serialize_time:.4f} seconds")

412

print(f"Deserialization time: {deserialize_time:.4f} seconds")

413

print(f"Serialized size: {len(serialized):,} bytes")

414

print(f"Compression ratio: {len(str(obj).encode()) / len(serialized):.2f}x")

415

416

# Usage with different objects

417

performance_diagnostic(large_data_structure, "Large Data Structure")

418

performance_diagnostic(complex_function, "Complex Function")

419

performance_diagnostic(class_instance, "Class Instance")

420

```

421

422

## Integration with Development Workflow

423

424

### Pre-commit Pickling Validation

425

426

```python

427

import dill

428

import sys

429

430

def validate_pickling(modules_to_test):

431

"""Validate that key objects can be pickled before commit."""

432

print("Running pickling validation...")

433

434

failed_objects = []

435

436

for module_name in modules_to_test:

437

try:

438

module = __import__(module_name)

439

440

# Test key objects in module

441

for attr_name in dir(module):

442

if not attr_name.startswith('_'):

443

obj = getattr(module, attr_name)

444

445

if callable(obj) or hasattr(obj, '__dict__'):

446

if not dill.pickles(obj, safe=True):

447

failed_objects.append(f"{module_name}.{attr_name}")

448

449

except ImportError:

450

print(f"Could not import {module_name}")

451

452

if failed_objects:

453

print("❌ Pickling validation failed for:")

454

for obj in failed_objects:

455

print(f" - {obj}")

456

return False

457

else:

458

print("✓ All objects pass pickling validation")

459

return True

460

461

# Usage in CI/CD pipeline

462

if __name__ == "__main__":

463

modules = ["mypackage.core", "mypackage.utils", "mypackage.models"]

464

success = validate_pickling(modules)

465

sys.exit(0 if success else 1)

466

```