or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-integration.mdcore-assertions.mdextensions.mdfilters.mdindex.mdmatchers.md

filters.mddocs/

0

# Filters

1

2

Property inclusion and exclusion system for controlling serialization scope in snapshots. Filters allow you to include or exclude specific properties from snapshot serialization, useful for ignoring dynamic fields, private data, or focusing on specific aspects of complex objects.

3

4

## Capabilities

5

6

### Property-Based Filtering

7

8

Filter properties by their names, supporting both inclusion and exclusion patterns.

9

10

```python { .api }

11

def props(*prop_names: str) -> PropertyFilter:

12

"""

13

Create filter that includes only specified property names.

14

15

Parameters:

16

- *included: Property names to include in serialization

17

18

Returns:

19

PropertyFilter: Function that returns True for included properties

20

"""

21

```

22

23

Usage examples:

24

25

```python

26

def test_include_specific_props(snapshot):

27

from syrupy.filters import props

28

29

user_data = {

30

"id": 123,

31

"name": "Alice",

32

"email": "alice@example.com",

33

"password_hash": "secret_hash_value",

34

"created_at": "2023-12-01T10:00:00Z",

35

"last_login": "2023-12-01T15:30:00Z",

36

"internal_id": "internal_abc123"

37

}

38

39

# Only include public fields in snapshot

40

assert user_data == snapshot(include=props("id", "name", "email"))

41

42

def test_exclude_sensitive_props(snapshot):

43

from syrupy.filters import props

44

45

config = {

46

"app_name": "MyApp",

47

"version": "1.0.0",

48

"database_url": "postgresql://localhost/mydb",

49

"secret_key": "super_secret_key_123",

50

"api_token": "token_abc123def456",

51

"debug": True

52

}

53

54

# Exclude sensitive configuration

55

assert config == snapshot(exclude=props("secret_key", "api_token", "database_url"))

56

57

def test_nested_object_filtering(snapshot):

58

from syrupy.filters import props

59

60

response = {

61

"user": {

62

"id": 123,

63

"name": "Alice",

64

"email": "alice@example.com",

65

"private_notes": "Internal notes",

66

"password_hash": "secret"

67

},

68

"session": {

69

"id": "sess_123",

70

"token": "secret_token",

71

"expires": "2023-12-01T16:00:00Z"

72

}

73

}

74

75

# Include only public user fields

76

# Note: This filters at each level independently

77

assert response == snapshot(include=props("user", "id", "name", "email", "session", "expires"))

78

```

79

80

### Path-Based Filtering

81

82

Filter properties using full path strings delimited with dots, allowing precise control over nested structures.

83

84

```python { .api }

85

def paths(*included: str) -> PropertyFilter:

86

"""

87

Create filter using full path strings for precise property targeting.

88

89

Parameters:

90

- *included: Dot-delimited path strings to include

91

92

Returns:

93

PropertyFilter: Function that returns True for included paths

94

"""

95

```

96

97

Usage examples:

98

99

```python

100

def test_precise_path_filtering(snapshot):

101

from syrupy.filters import paths

102

103

complex_data = {

104

"user": {

105

"profile": {

106

"name": "Alice",

107

"email": "alice@example.com",

108

"private_info": "secret"

109

},

110

"settings": {

111

"theme": "dark",

112

"notifications": True,

113

"private_key": "secret_key"

114

}

115

},

116

"metadata": {

117

"version": "1.0",

118

"debug_info": "internal_data"

119

}

120

}

121

122

# Include only specific nested paths

123

assert complex_data == snapshot(include=paths(

124

"user.profile.name",

125

"user.profile.email",

126

"user.settings.theme",

127

"metadata.version"

128

))

129

130

def test_exclude_specific_paths(snapshot):

131

from syrupy.filters import paths

132

133

api_response = {

134

"data": {

135

"users": [

136

{"id": 1, "name": "Alice", "internal_id": "int_123"},

137

{"id": 2, "name": "Bob", "internal_id": "int_456"}

138

]

139

},

140

"meta": {

141

"total_count": 2,

142

"request_id": "req_789",

143

"debug_trace": "trace_data"

144

}

145

}

146

147

# Exclude internal/debug paths

148

assert api_response == snapshot(exclude=paths(

149

"data.users.*.internal_id", # Exclude internal_id from all users

150

"meta.request_id",

151

"meta.debug_trace"

152

))

153

```

154

155

### Nested Path Inclusion

156

157

Advanced filtering that automatically includes parent paths when targeting nested properties.

158

159

```python { .api }

160

def paths_include(*path_parts: Union[Tuple[str, ...], List[str]]) -> PropertyFilter:

161

"""

162

Create include filter with automatic parent path inclusion.

163

164

When including a nested path, automatically includes all parent paths

165

necessary to reach the target property.

166

167

Parameters:

168

- *nested_paths: Dot-delimited paths to include with parents

169

170

Returns:

171

PropertyFilter: Function that includes paths and their parents

172

"""

173

```

174

175

Usage examples:

176

177

```python

178

def test_nested_path_inclusion(snapshot):

179

from syrupy.filters import paths_include

180

181

deep_structure = {

182

"level1": {

183

"level2": {

184

"level3": {

185

"target_field": "important_data",

186

"other_field": "not_needed"

187

},

188

"sibling": "also_not_needed"

189

},

190

"other_branch": "ignore_this"

191

},

192

"root_field": "ignore_this_too"

193

}

194

195

# Include only level1.level2.level3.target_field and necessary parents

196

# This automatically includes: level1, level1.level2, level1.level2.level3

197

assert deep_structure == snapshot(include=paths_include(

198

"level1.level2.level3.target_field"

199

))

200

201

def test_multiple_nested_inclusions(snapshot):

202

from syrupy.filters import paths_include

203

204

config = {

205

"database": {

206

"host": "localhost",

207

"port": 5432,

208

"credentials": {

209

"username": "admin",

210

"password": "secret"

211

}

212

},

213

"cache": {

214

"redis": {

215

"host": "cache-host",

216

"port": 6379

217

}

218

},

219

"logging": {

220

"level": "INFO",

221

"file": "/var/log/app.log"

222

}

223

}

224

225

# Include multiple nested paths - parents automatically included

226

assert config == snapshot(include=paths_include(

227

"database.host",

228

"database.port",

229

"cache.redis.host",

230

"logging.level"

231

))

232

```

233

234

### Combined Filter Usage

235

236

Using filters together with matchers and extensions for comprehensive snapshot control.

237

238

```python { .api }

239

# Filters can be combined with matchers and extensions

240

PropertyFilter = Callable[[PropertyName, PropertyPath], bool]

241

```

242

243

Usage examples:

244

245

```python

246

def test_filter_with_matcher(snapshot):

247

from syrupy.filters import props

248

from syrupy.matchers import path_type

249

250

user_activity = {

251

"user_id": 12345,

252

"username": "alice",

253

"last_login": "2023-12-01T10:30:00Z",

254

"login_count": 42,

255

"internal_tracking_id": "track_abc123",

256

"debug_info": {"trace": "internal_data"}

257

}

258

259

# Exclude internal fields AND replace dynamic values

260

assert user_activity == snapshot(

261

exclude=props("internal_tracking_id", "debug_info"),

262

matcher=path_type({

263

"user_id": (int, "<user_id>"),

264

"last_login": (str, "<timestamp>")

265

})

266

)

267

268

def test_filter_with_extension(snapshot):

269

from syrupy.filters import paths

270

from syrupy.extensions.json import JSONSnapshotExtension

271

272

api_data = {

273

"public_api": {

274

"users": [{"id": 1, "name": "Alice"}],

275

"total": 1

276

},

277

"internal_meta": {

278

"query_time": 0.05,

279

"cache_hit": True,

280

"debug_trace": "internal"

281

}

282

}

283

284

# Include only public API data and save as clean JSON

285

assert api_data == snapshot(

286

include=paths("public_api.users", "public_api.total")

287

).use_extension(JSONSnapshotExtension)

288

```

289

290

### Custom Filter Development

291

292

Create custom filter functions for specialized filtering needs.

293

294

```python { .api }

295

PropertyFilter = Callable[[PropertyName, PropertyPath], bool]

296

297

# PropertyPath structure for custom filters

298

PropertyName = Hashable

299

PropertyValueType = Type[SerializableData]

300

PropertyPathEntry = Tuple[PropertyName, PropertyValueType]

301

PropertyPath = Tuple[PropertyPathEntry, ...]

302

```

303

304

Usage examples:

305

306

```python

307

def test_custom_type_filter(snapshot):

308

def exclude_private_types(prop_name, path):

309

"""Exclude properties containing sensitive types"""

310

# Get the property value type from the path

311

if path and len(path) > 0:

312

prop_type = path[-1][1] # Last entry's type

313

314

# Exclude certain types

315

if prop_type in (type(lambda: None), type): # Functions and type objects

316

return False

317

318

# Exclude properties with "private" or "secret" in name

319

if isinstance(prop_name, str):

320

if "private" in prop_name.lower() or "secret" in prop_name.lower():

321

return False

322

323

return True # Include by default

324

325

test_data = {

326

"public_value": "visible",

327

"private_key": "hidden",

328

"secret_token": "hidden",

329

"normal_field": "visible",

330

"callback_func": lambda x: x, # Function type - excluded

331

"metadata": {"version": "1.0"}

332

}

333

334

assert test_data == snapshot(include=exclude_private_types)

335

336

def test_depth_based_filter(snapshot):

337

def limit_depth(prop_name, path):

338

"""Limit serialization depth to prevent infinite recursion"""

339

max_depth = 3

340

return len(path) <= max_depth

341

342

# Deeply nested structure

343

deep_data = {

344

"level1": {

345

"level2": {

346

"level3": {

347

"level4": "too deep - excluded",

348

"value": "included"

349

},

350

"value": "included"

351

},

352

"value": "included"

353

}

354

}

355

356

assert deep_data == snapshot(include=limit_depth)

357

358

def test_conditional_filter(snapshot):

359

def filter_by_value_type(prop_name, path):

360

"""Custom logic based on property name patterns"""

361

prop_str = str(prop_name)

362

363

# Include all numeric IDs

364

if prop_str.endswith("_id") or prop_str == "id":

365

return True

366

367

# Include all timestamps

368

if "time" in prop_str.lower() or "date" in prop_str.lower():

369

return True

370

371

# Include names and titles

372

if prop_str in ["name", "title", "description"]:

373

return True

374

375

# Exclude everything else

376

return False

377

378

mixed_data = {

379

"user_id": 123,

380

"name": "Alice",

381

"email": "alice@example.com", # Excluded

382

"created_time": "2023-12-01",

383

"password": "secret", # Excluded

384

"description": "User account"

385

}

386

387

assert mixed_data == snapshot(include=filter_by_value_type)

388

```