or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-serialization.mdfield-configuration.mdglobal-configuration.mdindex.mdundefined-parameters.md

undefined-parameters.mddocs/

0

# Undefined Parameter Handling

1

2

Strategies for handling JSON fields that don't correspond to dataclass fields during deserialization. The library provides three approaches: raising exceptions, ignoring extra fields, or capturing them in a designated catch-all field.

3

4

## Capabilities

5

6

### Undefined Behavior Enum

7

8

The `Undefined` enum defines the available strategies for handling undefined parameters.

9

10

```python { .api }

11

class Undefined(Enum):

12

"""

13

Enumeration of strategies for handling undefined parameters during deserialization.

14

"""

15

INCLUDE = ... # Store undefined parameters in a CatchAll field

16

RAISE = ... # Raise UndefinedParameterError for any undefined parameters

17

EXCLUDE = ... # Ignore undefined parameters silently

18

```

19

20

Usage example:

21

22

```python

23

from dataclasses import dataclass

24

from dataclasses_json import dataclass_json, Undefined

25

26

@dataclass_json(undefined=Undefined.EXCLUDE)

27

@dataclass

28

class Person:

29

name: str

30

age: int

31

32

# JSON with extra field - will be ignored

33

json_data = '{"name": "Alice", "age": 30, "extra_field": "ignored"}'

34

person = Person.from_json(json_data) # Works fine, extra_field ignored

35

```

36

37

### CatchAll Field Type

38

39

The `CatchAll` type annotation designates a field to receive undefined parameters when using `Undefined.INCLUDE`.

40

41

```python { .api }

42

# Type variable for catch-all fields (bound to Mapping)

43

CatchAllVar = TypeVar("CatchAllVar", bound=Mapping)

44

CatchAll = Optional[CatchAllVar]

45

```

46

47

Usage example:

48

49

```python

50

from dataclasses import dataclass, field

51

from dataclasses_json import dataclass_json, Undefined, CatchAll

52

53

@dataclass_json(undefined=Undefined.INCLUDE)

54

@dataclass

55

class FlexibleData:

56

name: str

57

age: int

58

# This field will receive all undefined parameters

59

extra_data: CatchAll = field(default_factory=dict)

60

61

# JSON with extra fields

62

json_data = '{"name": "Bob", "age": 25, "city": "NYC", "country": "USA"}'

63

data = FlexibleData.from_json(json_data)

64

65

print(data.name) # "Bob"

66

print(data.age) # 25

67

print(data.extra_data) # {"city": "NYC", "country": "USA"}

68

```

69

70

### Undefined Parameter Exception

71

72

Exception raised when undefined parameters are encountered with `Undefined.RAISE` strategy.

73

74

```python { .api }

75

class UndefinedParameterError(Exception):

76

"""

77

Raised when undefined parameters are encountered and the current

78

undefined parameter handling strategy is set to RAISE.

79

80

Inherits from marshmallow.exceptions.ValidationError for consistency

81

with the validation system.

82

"""

83

```

84

85

Usage example:

86

87

```python

88

from dataclasses import dataclass

89

from dataclasses_json import dataclass_json, Undefined, UndefinedParameterError

90

91

@dataclass_json(undefined=Undefined.RAISE)

92

@dataclass

93

class StrictData:

94

name: str

95

age: int

96

97

try:

98

# This will raise an exception due to extra field

99

json_data = '{"name": "Charlie", "age": 35, "invalid_field": "error"}'

100

data = StrictData.from_json(json_data)

101

except UndefinedParameterError as e:

102

print(f"Undefined parameter error: {e}")

103

```

104

105

## Undefined Handling Strategies

106

107

### EXCLUDE Strategy (Default)

108

109

Silently ignores any fields in the JSON that don't correspond to dataclass fields.

110

111

```python

112

@dataclass_json(undefined=Undefined.EXCLUDE)

113

@dataclass

114

class Product:

115

name: str

116

price: float

117

118

# Extra fields are ignored

119

json_data = '{"name": "Widget", "price": 19.99, "discontinued": true, "vendor": "ACME"}'

120

product = Product.from_json(json_data)

121

# Only name and price are used, other fields ignored

122

```

123

124

Benefits:

125

- Robust against API changes that add new fields

126

- Simple and predictable behavior

127

- No additional storage overhead

128

129

Use cases:

130

- Consuming third-party APIs that may add fields

131

- Backward compatibility when removing fields from dataclass

132

- Simple data models where extra data isn't needed

133

134

### RAISE Strategy

135

136

Throws `UndefinedParameterError` for any undefined fields, ensuring strict data validation.

137

138

```python

139

@dataclass_json(undefined=Undefined.RAISE)

140

@dataclass

141

class StrictConfig:

142

host: str

143

port: int

144

ssl_enabled: bool

145

146

# This will raise an exception

147

try:

148

json_data = '{"host": "localhost", "port": 8080, "ssl_enabled": true, "timeout": 30}'

149

config = StrictConfig.from_json(json_data)

150

except UndefinedParameterError:

151

print("Strict validation failed - unexpected field found")

152

```

153

154

Benefits:

155

- Catches data model mismatches early

156

- Ensures complete control over data structure

157

- Helps identify API contract violations

158

159

Use cases:

160

- Configuration files where unexpected fields indicate errors

161

- Internal APIs with strict contracts

162

- Data validation scenarios requiring complete control

163

164

### INCLUDE Strategy

165

166

Captures undefined parameters in a designated `CatchAll` field for later processing or storage.

167

168

```python

169

@dataclass_json(undefined=Undefined.INCLUDE)

170

@dataclass

171

class ExtensibleRecord:

172

id: str

173

name: str

174

# All undefined fields stored here

175

metadata: CatchAll = field(default_factory=dict)

176

177

json_data = '{"id": "123", "name": "Test", "tags": ["a", "b"], "priority": "high"}'

178

record = ExtensibleRecord.from_json(json_data)

179

180

print(record.id) # "123"

181

print(record.name) # "Test"

182

print(record.metadata) # {"tags": ["a", "b"], "priority": "high"}

183

184

# Can access undefined data

185

print(record.metadata.get('priority')) # "high"

186

```

187

188

Benefits:

189

- Preserves all data from JSON input

190

- Allows processing of dynamic or unknown fields

191

- Enables round-trip serialization without data loss

192

193

Use cases:

194

- Document stores with flexible schemas

195

- Plugin systems with dynamic configuration

196

- Data migration scenarios

197

- APIs with optional extension fields

198

199

## Advanced Usage Patterns

200

201

### Per-Field Undefined Handling

202

203

You can specify undefined behavior at the field level using the `config` function:

204

205

```python

206

from dataclasses import dataclass, field

207

from dataclasses_json import dataclass_json, config, Undefined

208

209

@dataclass_json

210

@dataclass

211

class MixedHandling:

212

name: str

213

# This field has custom undefined handling

214

settings: dict = field(metadata=config(undefined=Undefined.RAISE))

215

```

216

217

### Multiple CatchAll Fields

218

219

Only one `CatchAll` field is allowed per dataclass. Attempting to define multiple will raise an error:

220

221

```python

222

@dataclass_json(undefined=Undefined.INCLUDE)

223

@dataclass

224

class InvalidMultipleCatchAll:

225

name: str

226

catch_all_1: CatchAll = field(default_factory=dict)

227

catch_all_2: CatchAll = field(default_factory=dict) # Error!

228

```

229

230

### CatchAll Field Validation

231

232

The CatchAll field must be properly typed and have a default:

233

234

```python

235

@dataclass_json(undefined=Undefined.INCLUDE)

236

@dataclass

237

class ValidCatchAll:

238

name: str

239

# Correct: Optional dict with default

240

extra: CatchAll = field(default_factory=dict)

241

242

@dataclass_json(undefined=Undefined.INCLUDE)

243

@dataclass

244

class InvalidCatchAll:

245

name: str

246

# Error: Missing default value

247

extra: CatchAll

248

```

249

250

### Combining with Schema Validation

251

252

Undefined parameter handling works seamlessly with marshmallow schema validation:

253

254

```python

255

@dataclass_json(undefined=Undefined.INCLUDE)

256

@dataclass

257

class ValidatedFlexible:

258

name: str = field(metadata=config(mm_field=fields.String(required=True)))

259

age: int = field(metadata=config(mm_field=fields.Integer(validate=lambda x: x >= 0)))

260

extra: CatchAll = field(default_factory=dict)

261

262

# Schema validation still applies to defined fields

263

schema = ValidatedFlexible.schema()

264

try:

265

# This will fail validation (negative age)

266

result = schema.loads('{"name": "Test", "age": -5, "city": "NYC"}')

267

except ValidationError:

268

print("Validation failed for defined fields")

269

```

270

271

### Serialization Behavior

272

273

When serializing back to JSON, the behavior depends on the strategy used during deserialization:

274

275

```python

276

@dataclass_json(undefined=Undefined.INCLUDE)

277

@dataclass

278

class RoundTrip:

279

name: str

280

extra: CatchAll = field(default_factory=dict)

281

282

# Original JSON

283

original = '{"name": "Test", "city": "NYC", "tags": ["a", "b"]}'

284

obj = RoundTrip.from_json(original)

285

286

# Serialization includes captured fields

287

serialized = obj.to_json()

288

# Contains: {"name": "Test", "city": "NYC", "tags": ["a", "b"]}

289

290

# Round-trip preservation

291

restored = RoundTrip.from_json(serialized)

292

assert restored.extra == {"city": "NYC", "tags": ["a", "b"]}

293

```