or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdindex.mdjson-processing.mdschema-building.mdspecial-values.mdurl-network.mdvalidation-serialization.md

special-values.mddocs/

0

# Special Values and Utilities

1

2

Sentinel values, utility classes, and helper functions for advanced validation scenarios and edge case handling. These utilities provide fine-grained control over validation behavior and enable sophisticated data processing patterns.

3

4

## Capabilities

5

6

### Sentinel Values

7

8

Special values that represent different states during validation and serialization.

9

10

```python { .api }

11

PydanticUndefined: PydanticUndefinedType

12

"""

13

Sentinel value representing undefined/missing values in Pydantic Core.

14

15

This is the primary sentinel value used internally by pydantic-core

16

to indicate when a value has not been provided or is undefined.

17

"""

18

19

class PydanticUndefinedType:

20

"""

21

Type class for the PydanticUndefined sentinel.

22

23

This type ensures PydanticUndefined has a unique type that can

24

be used in type annotations and isinstance checks.

25

"""

26

27

def __repr__(self) -> str:

28

return 'PydanticUndefined'

29

30

def __bool__(self) -> bool:

31

return False

32

33

MISSING: Sentinel

34

"""

35

Sentinel indicating a field value was not provided during validation.

36

37

Can be used as a default value alternative to None when None has

38

explicit meaning. During serialization, fields with MISSING are excluded.

39

"""

40

41

UNSET: Sentinel # Alias for MISSING

42

"""

43

Alternative name for MISSING sentinel value.

44

45

Provides a more explicit name when indicating that a field

46

has not been set or provided.

47

"""

48

```

49

50

### Utility Classes

51

52

Helper classes for advanced validation and data handling scenarios.

53

54

```python { .api }

55

class Some:

56

"""

57

Wrapper for optional values that distinguishes between None and undefined.

58

59

Useful when you need to differentiate between an explicit None value

60

and a missing/undefined value in validation contexts.

61

"""

62

63

def __init__(self, value):

64

"""

65

Create a Some wrapper around a value.

66

67

Args:

68

value: The value to wrap (can be None)

69

"""

70

self.value = value

71

72

def __repr__(self) -> str:

73

return f'Some({self.value!r})'

74

75

class ArgsKwargs:

76

"""

77

Container for function arguments and keyword arguments.

78

79

Used in advanced validation scenarios where you need to capture

80

and validate both positional and keyword arguments together.

81

"""

82

83

def __init__(self, args: tuple, kwargs: dict):

84

"""

85

Create an ArgsKwargs container.

86

87

Args:

88

args: Tuple of positional arguments

89

kwargs: Dictionary of keyword arguments

90

"""

91

self.args = args

92

self.kwargs = kwargs

93

94

def __repr__(self) -> str:

95

return f'ArgsKwargs({self.args!r}, {self.kwargs!r})'

96

```

97

98

### Marker Classes

99

100

Special marker classes used to control validation and serialization behavior.

101

102

```python { .api }

103

class PydanticOmit:

104

"""

105

Marker to omit fields during serialization.

106

107

When a field value is set to PydanticOmit (or a validator returns it),

108

the field will be excluded from serialization output.

109

"""

110

111

def __repr__(self) -> str:

112

return 'PydanticOmit'

113

114

class PydanticUseDefault:

115

"""

116

Marker to use default value during validation.

117

118

When a validator returns PydanticUseDefault, the validation process

119

will use the field's default value instead of the returned marker.

120

"""

121

122

def __repr__(self) -> str:

123

return 'PydanticUseDefault'

124

```

125

126

### Time and Timezone Utilities

127

128

```python { .api }

129

class TzInfo:

130

"""

131

Timezone information handling for datetime validation.

132

133

Provides timezone-aware datetime processing and validation

134

with support for various timezone representations.

135

"""

136

137

def __repr__(self) -> str:

138

return 'TzInfo(...)'

139

```

140

141

## Usage Examples

142

143

### Working with Sentinel Values

144

145

```python

146

from pydantic_core import SchemaValidator, MISSING, UNSET, PydanticUndefined

147

from pydantic_core.core_schema import dict_schema, str_schema, default_schema

148

149

# Schema with optional fields using sentinels

150

schema = dict_schema({

151

'name': str_schema(),

152

'nickname': default_schema(str_schema(), default=MISSING),

153

'email': default_schema(str_schema(), default=UNSET),

154

'phone': default_schema(str_schema(), default=PydanticUndefined)

155

})

156

157

validator = SchemaValidator(schema)

158

159

# Test data without optional fields

160

data = {'name': 'Alice'}

161

result = validator.validate_python(data)

162

163

print(f"Result: {result}")

164

print(f"Nickname: {result.get('nickname', 'NOT_FOUND')}")

165

print(f"Email: {result.get('email', 'NOT_FOUND')}")

166

print(f"Phone: {result.get('phone', 'NOT_FOUND')}")

167

168

# Check sentinel values

169

print(f"MISSING is UNSET: {MISSING is UNSET}") # True - they're aliases

170

print(f"MISSING == PydanticUndefined: {MISSING == PydanticUndefined}") # False

171

172

# Type checking

173

print(f"Type of PydanticUndefined: {type(PydanticUndefined)}")

174

print(f"isinstance(PydanticUndefined, PydanticUndefinedType): {isinstance(PydanticUndefined, type(PydanticUndefined))}")

175

```

176

177

### Using Some for Optional Values

178

179

```python

180

from pydantic_core import SchemaValidator, Some

181

from pydantic_core.core_schema import (

182

with_info_plain_validator_function,

183

union_schema,

184

none_schema,

185

str_schema

186

)

187

188

def validate_optional_with_some(value):

189

"""Validator that distinguishes None from missing."""

190

if isinstance(value, Some):

191

# Extract the wrapped value, even if it's None

192

return value.value

193

elif value is None:

194

# Explicit None

195

return None

196

else:

197

# Regular value

198

if not isinstance(value, str):

199

raise ValueError("Expected string or Some(value)")

200

return value

201

202

# Schema using Some

203

optional_schema = with_info_plain_validator_function(validate_optional_with_some)

204

validator = SchemaValidator(optional_schema)

205

206

# Test different values

207

test_values = [

208

"regular_string",

209

None,

210

Some("wrapped_string"),

211

Some(None), # Explicit None wrapped in Some

212

]

213

214

for value in test_values:

215

try:

216

result = validator.validate_python(value)

217

print(f"Input: {value} -> Output: {result}")

218

except Exception as e:

219

print(f"Input: {value} -> Error: {e}")

220

```

221

222

### Using ArgsKwargs for Function Validation

223

224

```python

225

from pydantic_core import SchemaValidator, ArgsKwargs

226

from pydantic_core.core_schema import (

227

with_info_plain_validator_function,

228

arguments_schema,

229

str_schema,

230

int_schema

231

)

232

233

def validate_function_call(value):

234

"""Validate function arguments structure."""

235

if isinstance(value, ArgsKwargs):

236

args, kwargs = value.args, value.kwargs

237

elif isinstance(value, dict) and 'args' in value and 'kwargs' in value:

238

args, kwargs = value['args'], value['kwargs']

239

else:

240

raise ValueError("Expected ArgsKwargs or dict with 'args' and 'kwargs'")

241

242

# Validate arguments

243

if len(args) < 1:

244

raise ValueError("At least one positional argument required")

245

246

if not isinstance(args[0], str):

247

raise ValueError("First argument must be a string")

248

249

# Return validated ArgsKwargs

250

return ArgsKwargs(args, kwargs)

251

252

# Create validator

253

func_validator = SchemaValidator(

254

with_info_plain_validator_function(validate_function_call)

255

)

256

257

# Test function call validation

258

test_calls = [

259

ArgsKwargs(("hello",), {"count": 3}),

260

{"args": ("world",), "kwargs": {"repeat": True}},

261

ArgsKwargs((), {"name": "test"}), # Invalid: no args

262

]

263

264

for call in test_calls:

265

try:

266

result = func_validator.validate_python(call)

267

print(f"Valid call: {result}")

268

print(f" Args: {result.args}")

269

print(f" Kwargs: {result.kwargs}")

270

except Exception as e:

271

print(f"Invalid call: {e}")

272

```

273

274

### Marker Classes for Serialization Control

275

276

```python

277

from pydantic_core import (

278

SchemaValidator,

279

SchemaSerializer,

280

PydanticOmit,

281

PydanticUseDefault

282

)

283

from pydantic_core.core_schema import (

284

dict_schema,

285

str_schema,

286

int_schema,

287

with_info_plain_validator_function,

288

default_schema

289

)

290

291

def process_field_value(value):

292

"""Validator that may omit fields or use defaults."""

293

if isinstance(value, str):

294

if value == "OMIT":

295

return PydanticOmit # This field will be excluded

296

elif value == "DEFAULT":

297

return PydanticUseDefault # Use the field's default value

298

elif value.startswith("PROCESS:"):

299

return value[8:] # Remove "PROCESS:" prefix

300

return value

301

302

# Schema with conditional processing

303

schema = dict_schema({

304

'id': int_schema(),

305

'name': with_info_plain_validator_function(process_field_value),

306

'description': default_schema(

307

with_info_plain_validator_function(process_field_value),

308

default="Default description"

309

),

310

'status': with_info_plain_validator_function(process_field_value)

311

})

312

313

validator = SchemaValidator(schema)

314

serializer = SchemaSerializer(schema)

315

316

# Test data with markers

317

test_data = {

318

'id': 123,

319

'name': 'PROCESS:Alice', # Will become 'Alice'

320

'description': 'DEFAULT', # Will use default value

321

'status': 'OMIT' # Will be omitted from output

322

}

323

324

# Validate

325

validated = validator.validate_python(test_data)

326

print(f"Validated: {validated}")

327

328

# Serialize - status should be omitted

329

serialized = serializer.to_python(validated)

330

print(f"Serialized: {serialized}")

331

332

# Check what fields are present

333

print(f"Fields in result: {list(serialized.keys())}")

334

print(f"Status omitted: {'status' not in serialized}")

335

```

336

337

### Advanced Sentinel Usage in Models

338

339

```python

340

from pydantic_core import SchemaValidator, SchemaSerializer, MISSING

341

from pydantic_core.core_schema import (

342

model_schema,

343

str_schema,

344

int_schema,

345

default_schema,

346

nullable_schema

347

)

348

349

# User model with various optional field types

350

user_schema = model_schema(

351

'User',

352

{

353

'id': int_schema(),

354

'name': str_schema(),

355

'email': nullable_schema(str_schema()), # Can be None

356

'phone': default_schema(str_schema(), default=MISSING), # Missing by default

357

'address': default_schema(nullable_schema(str_schema()), default=None), # None by default

358

}

359

)

360

361

validator = SchemaValidator(user_schema)

362

serializer = SchemaSerializer(user_schema)

363

364

# Test different scenarios

365

test_users = [

366

# Minimal user

367

{'id': 1, 'name': 'Alice', 'email': None},

368

369

# User with phone

370

{'id': 2, 'name': 'Bob', 'email': 'bob@example.com', 'phone': '123-456-7890'},

371

372

# User with all fields

373

{'id': 3, 'name': 'Charlie', 'email': 'charlie@example.com', 'phone': '098-765-4321', 'address': '123 Main St'},

374

]

375

376

for user_data in test_users:

377

print(f"\nInput: {user_data}")

378

379

# Validate

380

validated = validator.validate_python(user_data)

381

print(f"Validated: {validated}")

382

383

# Serialize excluding unset fields

384

serialized_exclude_unset = serializer.to_python(validated, exclude_unset=True)

385

print(f"Exclude unset: {serialized_exclude_unset}")

386

387

# Serialize excluding None values

388

serialized_exclude_none = serializer.to_python(validated, exclude_none=True)

389

print(f"Exclude None: {serialized_exclude_none}")

390

```

391

392

### Creating Custom Sentinel Values

393

394

```python

395

from typing_extensions import Sentinel

396

397

# Create custom sentinel values for specific use cases

398

REDACTED = Sentinel('REDACTED')

399

COMPUTED = Sentinel('COMPUTED')

400

INHERITED = Sentinel('INHERITED')

401

402

def process_config_value(value):

403

"""Process configuration values with custom sentinels."""

404

if value is REDACTED:

405

return "[REDACTED]"

406

elif value is COMPUTED:

407

return f"computed_value_{hash('config')}"

408

elif value is INHERITED:

409

return "inherited_from_parent"

410

else:

411

return value

412

413

# Example usage in configuration processing

414

config_data = {

415

'api_key': REDACTED,

416

'cache_size': COMPUTED,

417

'log_level': INHERITED,

418

'service_name': 'my-service'

419

}

420

421

processed_config = {

422

key: process_config_value(value)

423

for key, value in config_data.items()

424

}

425

426

print("Original config:")

427

for key, value in config_data.items():

428

print(f" {key}: {value}")

429

430

print("\nProcessed config:")

431

for key, value in processed_config.items():

432

print(f" {key}: {value}")

433

434

# Sentinel comparison

435

print(f"\nSentinel comparisons:")

436

print(f"REDACTED is REDACTED: {REDACTED is REDACTED}")

437

print(f"REDACTED == REDACTED: {REDACTED == REDACTED}")

438

print(f"REDACTED is COMPUTED: {REDACTED is COMPUTED}")

439

```