or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-configuration.mddata-filtering.mderror-handling.mdindex.mdrecord-modes.mdrequest-matching.mdrequest-response.mdserialization.mdtest-integration.md

serialization.mddocs/

0

# Serialization

1

2

Cassette serialization and deserialization support for YAML and JSON formats with extensible serializer registration. VCR.py provides flexible serialization options for storing recorded HTTP interactions.

3

4

## Capabilities

5

6

### YAML Serializer

7

8

Default serializer using YAML format for human-readable cassette files.

9

10

```python { .api }

11

# From vcr.serializers.yamlserializer module

12

13

def deserialize(cassette_string: str) -> dict:

14

"""

15

Deserialize YAML cassette data into Python dictionary.

16

17

Args:

18

cassette_string: YAML-formatted cassette data as string

19

20

Returns:

21

dict: Parsed cassette data with interactions and metadata

22

23

Raises:

24

yaml.YAMLError: If YAML parsing fails

25

"""

26

27

def serialize(cassette_dict: dict) -> str:

28

"""

29

Serialize cassette data dictionary to YAML format.

30

31

Args:

32

cassette_dict: Cassette data as Python dictionary

33

34

Returns:

35

str: YAML-formatted cassette data

36

37

Raises:

38

yaml.YAMLError: If YAML serialization fails

39

"""

40

```

41

42

### JSON Serializer

43

44

Alternative serializer using JSON format for compact cassette files.

45

46

```python { .api }

47

# From vcr.serializers.jsonserializer module

48

49

def deserialize(cassette_string: str) -> dict:

50

"""

51

Deserialize JSON cassette data into Python dictionary.

52

53

Args:

54

cassette_string: JSON-formatted cassette data as string

55

56

Returns:

57

dict: Parsed cassette data with interactions and metadata

58

59

Raises:

60

json.JSONDecodeError: If JSON parsing fails

61

"""

62

63

def serialize(cassette_dict: dict) -> str:

64

"""

65

Serialize cassette data dictionary to JSON format.

66

67

Args:

68

cassette_dict: Cassette data as Python dictionary

69

70

Returns:

71

str: JSON-formatted cassette data

72

73

Raises:

74

TypeError: If data contains non-JSON-serializable objects

75

"""

76

```

77

78

## Usage Examples

79

80

### Choosing Serialization Format

81

82

```python

83

import vcr

84

85

# Default YAML serialization (human-readable)

86

yaml_vcr = vcr.VCR(serializer='yaml')

87

88

@yaml_vcr.use_cassette('interactions.yaml')

89

def test_with_yaml():

90

response = requests.get('https://api.example.com/data')

91

# Creates interactions.yaml file

92

93

# JSON serialization (more compact)

94

json_vcr = vcr.VCR(serializer='json')

95

96

@json_vcr.use_cassette('interactions.json')

97

def test_with_json():

98

response = requests.get('https://api.example.com/data')

99

# Creates interactions.json file

100

```

101

102

### Per-Test Serializer Override

103

104

```python

105

base_vcr = vcr.VCR(serializer='yaml') # Default to YAML

106

107

# Override for specific test

108

@base_vcr.use_cassette('special.json', serializer='json')

109

def test_with_json_override():

110

response = requests.get('https://api.example.com/data')

111

# Uses JSON despite base VCR using YAML

112

```

113

114

### Custom Serializer Implementation

115

116

```python

117

import json

118

import gzip

119

import vcr

120

121

class CompressedJSONSerializer:

122

"""Custom serializer that compresses JSON data."""

123

124

@staticmethod

125

def serialize(cassette_dict):

126

"""Serialize and compress cassette data."""

127

json_data = json.dumps(cassette_dict, indent=2)

128

compressed_data = gzip.compress(json_data.encode('utf-8'))

129

return compressed_data

130

131

@staticmethod

132

def deserialize(cassette_string):

133

"""Decompress and deserialize cassette data."""

134

if isinstance(cassette_string, bytes):

135

decompressed_data = gzip.decompress(cassette_string)

136

json_data = decompressed_data.decode('utf-8')

137

else:

138

json_data = cassette_string

139

return json.loads(json_data)

140

141

# Register custom serializer

142

my_vcr = vcr.VCR()

143

my_vcr.register_serializer('compressed_json', CompressedJSONSerializer)

144

145

@my_vcr.use_cassette('compressed.cjson', serializer='compressed_json')

146

def test_with_compressed_json():

147

response = requests.get('https://api.example.com/data')

148

```

149

150

### Pretty-Printed JSON Serializer

151

152

```python

153

import json

154

155

class PrettyJSONSerializer:

156

"""JSON serializer with human-readable formatting."""

157

158

@staticmethod

159

def serialize(cassette_dict):

160

return json.dumps(

161

cassette_dict,

162

indent=2,

163

sort_keys=True,

164

separators=(',', ': ')

165

)

166

167

@staticmethod

168

def deserialize(cassette_string):

169

return json.loads(cassette_string)

170

171

my_vcr = vcr.VCR()

172

my_vcr.register_serializer('pretty_json', PrettyJSONSerializer)

173

```

174

175

### Binary-Safe Serializer

176

177

```python

178

import json

179

import base64

180

181

class BinarySafeJSONSerializer:

182

"""JSON serializer that handles binary data in responses."""

183

184

@staticmethod

185

def serialize(cassette_dict):

186

"""Serialize with binary data encoded as base64."""

187

# Deep copy to avoid modifying original

188

import copy

189

safe_dict = copy.deepcopy(cassette_dict)

190

191

# Encode binary response bodies

192

for interaction in safe_dict.get('interactions', []):

193

response = interaction.get('response', {})

194

body = response.get('body', {})

195

196

if isinstance(body.get('string'), bytes):

197

# Encode binary data as base64

198

body['string'] = base64.b64encode(body['string']).decode('ascii')

199

body['encoding'] = 'base64'

200

201

return json.dumps(safe_dict, indent=2)

202

203

@staticmethod

204

def deserialize(cassette_string):

205

"""Deserialize with base64 decoding of binary data."""

206

cassette_dict = json.loads(cassette_string)

207

208

# Decode binary response bodies

209

for interaction in cassette_dict.get('interactions', []):

210

response = interaction.get('response', {})

211

body = response.get('body', {})

212

213

if body.get('encoding') == 'base64':

214

# Decode base64 data back to bytes

215

body['string'] = base64.b64decode(body['string'].encode('ascii'))

216

del body['encoding']

217

218

return cassette_dict

219

220

my_vcr = vcr.VCR()

221

my_vcr.register_serializer('binary_safe_json', BinarySafeJSONSerializer)

222

```

223

224

## Cassette File Format

225

226

### YAML Cassette Structure

227

228

```yaml

229

interactions:

230

- request:

231

body: null

232

headers:

233

Accept:

234

- '*/*'

235

User-Agent:

236

- python-requests/2.28.1

237

method: GET

238

uri: https://api.example.com/data

239

response:

240

body:

241

string: '{"message": "Hello, World!"}'

242

headers:

243

Content-Type:

244

- application/json

245

Content-Length:

246

- '26'

247

status:

248

code: 200

249

message: OK

250

version: 1

251

```

252

253

### JSON Cassette Structure

254

255

```json

256

{

257

"interactions": [

258

{

259

"request": {

260

"body": null,

261

"headers": {

262

"Accept": ["*/*"],

263

"User-Agent": ["python-requests/2.28.1"]

264

},

265

"method": "GET",

266

"uri": "https://api.example.com/data"

267

},

268

"response": {

269

"body": {

270

"string": "{\"message\": \"Hello, World!\"}"

271

},

272

"headers": {

273

"Content-Type": ["application/json"],

274

"Content-Length": ["26"]

275

},

276

"status": {

277

"code": 200,

278

"message": "OK"

279

}

280

}

281

}

282

],

283

"version": 1

284

}

285

```

286

287

## Advanced Serialization Patterns

288

289

### Environment-Based Serializer Selection

290

291

```python

292

import os

293

import vcr

294

295

def get_serializer():

296

"""Choose serializer based on environment."""

297

serializer = os.getenv('VCR_SERIALIZER', 'yaml')

298

return serializer

299

300

my_vcr = vcr.VCR(serializer=get_serializer())

301

302

# Usage: VCR_SERIALIZER=json python test.py

303

```

304

305

### Conditional Serializer Features

306

307

```python

308

import json

309

import os

310

311

class SmartJSONSerializer:

312

"""JSON serializer with environment-based features."""

313

314

@staticmethod

315

def serialize(cassette_dict):

316

# Compact format in production, pretty format in development

317

if os.getenv('ENV') == 'production':

318

return json.dumps(cassette_dict, separators=(',', ':'))

319

else:

320

return json.dumps(cassette_dict, indent=2, sort_keys=True)

321

322

@staticmethod

323

def deserialize(cassette_string):

324

return json.loads(cassette_string)

325

```

326

327

### Versioned Serializer

328

329

```python

330

import json

331

332

class VersionedJSONSerializer:

333

"""JSON serializer that includes format version information."""

334

335

CURRENT_VERSION = 2

336

337

@staticmethod

338

def serialize(cassette_dict):

339

# Add version information

340

versioned_dict = {

341

'format_version': VersionedJSONSerializer.CURRENT_VERSION,

342

'data': cassette_dict

343

}

344

return json.dumps(versioned_dict, indent=2)

345

346

@staticmethod

347

def deserialize(cassette_string):

348

versioned_dict = json.loads(cassette_string)

349

350

# Handle different format versions

351

format_version = versioned_dict.get('format_version', 1)

352

353

if format_version == 1:

354

# Legacy format - data is at root level

355

return versioned_dict

356

elif format_version == 2:

357

# Current format - data is nested

358

return versioned_dict['data']

359

else:

360

raise ValueError(f"Unsupported cassette format version: {format_version}")

361

```

362

363

### Encrypted Serializer

364

365

```python

366

import json

367

import base64

368

from cryptography.fernet import Fernet

369

370

class EncryptedJSONSerializer:

371

"""JSON serializer with encryption for sensitive data."""

372

373

def __init__(self, encryption_key=None):

374

if encryption_key is None:

375

encryption_key = Fernet.generate_key()

376

self.cipher = Fernet(encryption_key)

377

378

def serialize(self, cassette_dict):

379

"""Encrypt and serialize cassette data."""

380

json_data = json.dumps(cassette_dict)

381

encrypted_data = self.cipher.encrypt(json_data.encode())

382

return base64.b64encode(encrypted_data).decode()

383

384

def deserialize(self, cassette_string):

385

"""Decrypt and deserialize cassette data."""

386

encrypted_data = base64.b64decode(cassette_string.encode())

387

decrypted_data = self.cipher.decrypt(encrypted_data)

388

return json.loads(decrypted_data.decode())

389

390

# Usage with encryption key from environment

391

import os

392

key = os.getenv('VCR_ENCRYPTION_KEY')

393

if key:

394

encrypted_serializer = EncryptedJSONSerializer(key.encode())

395

my_vcr = vcr.VCR()

396

my_vcr.register_serializer('encrypted', encrypted_serializer)

397

```

398

399

### Streaming Serializer for Large Cassettes

400

401

```python

402

import json

403

import ijson # For streaming JSON parsing

404

405

class StreamingJSONSerializer:

406

"""Serializer optimized for large cassette files."""

407

408

@staticmethod

409

def serialize(cassette_dict):

410

"""Standard JSON serialization."""

411

return json.dumps(cassette_dict)

412

413

@staticmethod

414

def deserialize(cassette_string):

415

"""Stream parsing for large JSON files."""

416

if len(cassette_string) > 10 * 1024 * 1024: # > 10MB

417

# Use streaming parser for large files

418

import io

419

stream = io.StringIO(cassette_string)

420

return ijson.parse(stream)

421

else:

422

# Use standard parser for smaller files

423

return json.loads(cassette_string)

424

```