or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

base-types.mdboolean-types.mddatetime-types.mddict-types.mdindex.mdinspection-types.mdnumeric-types.mdother-types.mdsequence-types.mdstring-types.md

sequence-types.mddocs/

0

# Sequence Types

1

2

List, tuple, and general sequence validation with support for partial matching, order constraints, containment checking, and length validation. These types enable flexible validation of sequential data structures with various matching strategies.

3

4

## Capabilities

5

6

### HasLen

7

8

Length validation for any object that supports the `len()` function, with support for exact length, minimum length, or length ranges.

9

10

```python { .api }

11

class HasLen(DirtyEquals):

12

"""

13

Length checking for any object supporting len().

14

15

Validates that an object has a specific length, minimum length,

16

or length within a specified range.

17

"""

18

19

def __init__(self, min_length: int, max_length: Optional[int] = None):

20

"""

21

Initialize length checker (overloaded constructor).

22

23

Can be called as:

24

- HasLen(exact_length) - exact length match

25

- HasLen(min_length, max_length) - length range

26

27

Args:

28

min_length: Minimum length (or exact if max_length is None)

29

max_length: Maximum length (None for exact match)

30

"""

31

32

def equals(self, other: Any) -> bool:

33

"""

34

Check if object length matches constraints.

35

36

Args:

37

other: Object to check length of (must support len())

38

39

Returns:

40

bool: True if length satisfies constraints

41

"""

42

```

43

44

#### Usage Examples

45

46

```python

47

from dirty_equals import HasLen

48

49

# Exact length checking

50

assert [1, 2, 3] == HasLen(3)

51

assert "hello" == HasLen(5)

52

assert {"a": 1, "b": 2} == HasLen(2)

53

54

# Length range checking

55

assert [1, 2, 3, 4] == HasLen(2, 5) # Between 2 and 5 items

56

assert "hello world" == HasLen(5, 15) # Between 5 and 15 characters

57

58

# Minimum length (no maximum)

59

assert [1, 2, 3, 4, 5] == HasLen(3, None) # At least 3 items

60

61

# API response validation

62

api_results = {

63

'users': [{'id': 1}, {'id': 2}, {'id': 3}],

64

'message': 'Success',

65

'errors': []

66

}

67

68

assert api_results == {

69

'users': HasLen(1, 10), # 1-10 users expected

70

'message': HasLen(1, 100), # Non-empty message

71

'errors': HasLen(0) # No errors

72

}

73

74

# Form validation

75

form_data = {

76

'username': 'john_doe',

77

'password': 'secret123',

78

'tags': ['python', 'web', 'api']

79

}

80

81

assert form_data == {

82

'username': HasLen(3, 20), # Username length constraints

83

'password': HasLen(8), # Exact password length

84

'tags': HasLen(1, 5) # 1-5 tags allowed

85

}

86

87

# Database query results

88

query_results = [

89

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

90

{'id': 2, 'name': 'Bob'}

91

]

92

93

assert query_results == HasLen(2) # Expecting exactly 2 results

94

95

# File content validation

96

file_lines = ['line 1', 'line 2', 'line 3', 'line 4']

97

assert file_lines == HasLen(1, 100) # File should have content but not be huge

98

```

99

100

### Contains

101

102

Containment checking that validates whether one or more values are present in a collection using Python's `in` operator.

103

104

```python { .api }

105

class Contains(DirtyEquals):

106

"""

107

Containment checking using 'in' operator.

108

109

Validates that all specified values are contained

110

within the target collection.

111

"""

112

113

def __init__(self, contained_value: Any, *more_contained_values: Any):

114

"""

115

Initialize containment checker.

116

117

Args:

118

contained_value: First value that must be contained

119

*more_contained_values: Additional values that must be contained

120

"""

121

122

def equals(self, other: Any) -> bool:

123

"""

124

Check if all specified values are contained in other.

125

126

Args:

127

other: Collection to check containment in

128

129

Returns:

130

bool: True if all values are contained in other

131

"""

132

```

133

134

#### Usage Examples

135

136

```python

137

from dirty_equals import Contains

138

139

# Basic containment checking

140

assert [1, 2, 3, 4, 5] == Contains(3)

141

assert "hello world" == Contains("world")

142

assert {"a": 1, "b": 2, "c": 3} == Contains("b")

143

144

# Multiple values must all be contained

145

assert [1, 2, 3, 4, 5] == Contains(2, 4, 5)

146

assert "hello world" == Contains("hello", "world")

147

assert {"a": 1, "b": 2, "c": 3} == Contains("a", "c")

148

149

# String containment

150

text = "The quick brown fox jumps over the lazy dog"

151

assert text == Contains("quick", "fox", "lazy")

152

assert text == Contains("brown")

153

154

# List containment

155

shopping_list = ['bread', 'milk', 'eggs', 'cheese', 'butter']

156

assert shopping_list == Contains('milk', 'eggs')

157

assert shopping_list == Contains('bread')

158

159

# Dict key containment

160

config = {

161

'database_url': 'postgresql://localhost/db',

162

'secret_key': 'super-secret',

163

'debug': True,

164

'port': 5000

165

}

166

167

assert config == Contains('database_url', 'secret_key')

168

assert config == Contains('debug')

169

170

# API response validation

171

api_response = {

172

'data': [

173

{'id': 1, 'name': 'Alice', 'roles': ['admin', 'user']},

174

{'id': 2, 'name': 'Bob', 'roles': ['user', 'moderator']}

175

]

176

}

177

178

# Check that admin role exists somewhere

179

user_roles = api_response['data'][0]['roles']

180

assert user_roles == Contains('admin')

181

182

# Check for required permissions

183

required_permissions = ['read', 'write', 'delete', 'admin']

184

user_permissions = ['read', 'write', 'admin', 'moderate', 'create']

185

assert user_permissions == Contains('read', 'write', 'admin')

186

187

# Tag validation

188

blog_post = {

189

'title': 'Python Tips',

190

'content': '...',

191

'tags': ['python', 'programming', 'tutorial', 'beginner']

192

}

193

194

# Must contain essential tags

195

assert blog_post['tags'] == Contains('python', 'programming')

196

197

# Search results validation

198

search_results = [

199

'python-guide.pdf',

200

'advanced-python-tricks.txt',

201

'python-best-practices.md',

202

'django-tutorial.html'

203

]

204

205

# Must contain files with 'python' in name

206

filenames_with_python = [f for f in search_results if 'python' in f]

207

assert filenames_with_python == Contains('python-guide.pdf', 'advanced-python-tricks.txt')

208

209

# Set operations

210

available_features = {'auth', 'logging', 'caching', 'monitoring', 'backup'}

211

required_features = {'auth', 'logging'}

212

213

for feature in required_features:

214

assert available_features == Contains(feature)

215

```

216

217

### IsListOrTuple

218

219

Base class for list and tuple validation with flexible matching strategies including item validation, position constraints, order checking, and length validation.

220

221

```python { .api }

222

class IsListOrTuple(DirtyEquals):

223

"""

224

List/tuple comparison with flexible matching constraints.

225

226

Supports item validation, position-specific checks, order enforcement,

227

and length constraints for both lists and tuples.

228

"""

229

230

def __init__(

231

self,

232

*items: Any,

233

positions: Optional[Dict[int, Any]] = None,

234

check_order: bool = True,

235

length: Optional[int] = None

236

):

237

"""

238

Initialize list/tuple validator.

239

240

Args:

241

*items: Expected items (order matters if check_order=True)

242

positions: Dict mapping positions to expected values

243

check_order: Whether to enforce item order

244

length: Expected exact length

245

"""

246

247

allowed_type: ClassVar[Tuple[type, ...]] = (list, tuple)

248

249

def equals(self, other: Any) -> bool:

250

"""

251

Check if sequence matches constraints.

252

253

Args:

254

other: List or tuple to validate

255

256

Returns:

257

bool: True if sequence satisfies all constraints

258

"""

259

```

260

261

#### Usage Examples

262

263

```python

264

from dirty_equals import IsListOrTuple, IsPositive, IsStr

265

266

# Basic sequence matching - exact order

267

assert [1, 2, 3] == IsListOrTuple(1, 2, 3)

268

assert (1, 2, 3) == IsListOrTuple(1, 2, 3)

269

270

# With validators

271

assert ['hello', 42, True] == IsListOrTuple(IsStr, IsPositive, bool)

272

273

# Position-specific validation

274

data = [10, 'name', 3.14, True, 'end']

275

assert data == IsListOrTuple(

276

positions={

277

0: IsPositive, # First item must be positive

278

1: IsStr, # Second item must be string

279

2: float, # Third item must be float

280

4: 'end' # Last item must be 'end'

281

}

282

)

283

284

# Ignore order - just check that items exist somewhere

285

unordered_list = [3, 1, 2]

286

assert unordered_list == IsListOrTuple(1, 2, 3, check_order=False)

287

288

# Length validation

289

assert [1, 2, 3, 4, 5] == IsListOrTuple(length=5)

290

assert ('a', 'b') == IsListOrTuple(length=2)

291

292

# Combined constraints

293

api_response = ['success', 200, {'data': 'result'}, True]

294

assert api_response == IsListOrTuple(

295

'success', # First item exact match

296

IsPositive, # Second item positive number

297

dict, # Third item is dict

298

bool, # Fourth item is boolean

299

length=4 # Exactly 4 items

300

)

301

302

# Flexible API result validation

303

results = [

304

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

305

{'id': 2, 'name': 'Bob'},

306

{'id': 3, 'name': 'Charlie'}

307

]

308

309

# Check specific positions and overall structure

310

assert results == IsListOrTuple(

311

positions={

312

0: {'id': 1, 'name': IsStr}, # First user

313

2: {'id': IsPositive, 'name': 'Charlie'} # Last user

314

},

315

length=3

316

)

317

318

# Configuration tuple validation

319

config_tuple = ('production', 8080, True, '/var/log/app.log')

320

assert config_tuple == IsListOrTuple(

321

IsStr, # Environment name

322

IsPositive, # Port number

323

bool, # Debug flag

324

IsStr, # Log file path

325

check_order=True,

326

length=4

327

)

328

```

329

330

### IsList

331

332

List-specific validation that inherits all functionality from IsListOrTuple but restricts validation to list objects only.

333

334

```python { .api }

335

class IsList(IsListOrTuple):

336

"""

337

List-specific comparison with constraints.

338

339

Inherits all functionality from IsListOrTuple but only

340

accepts list objects, not tuples.

341

"""

342

343

allowed_type: ClassVar[type] = list

344

```

345

346

#### Usage Examples

347

348

```python

349

from dirty_equals import IsList, IsPositive, IsStr

350

351

# Basic list validation

352

assert [1, 2, 3] == IsList(1, 2, 3)

353

assert ['a', 'b', 'c'] == IsList('a', 'b', 'c')

354

355

# Tuples won't match

356

# assert (1, 2, 3) == IsList(1, 2, 3) # Would fail

357

358

# API response list validation

359

user_list = [

360

{'id': 1, 'name': 'Alice', 'active': True},

361

{'id': 2, 'name': 'Bob', 'active': False}

362

]

363

364

assert user_list == IsList(

365

{'id': IsPositive, 'name': IsStr, 'active': bool},

366

{'id': IsPositive, 'name': IsStr, 'active': bool}

367

)

368

369

# Dynamic list validation

370

numbers = [1, 2, 3, 4, 5]

371

assert numbers == IsList(*range(1, 6)) # Unpack range

372

373

# Shopping cart validation

374

cart_items = [

375

{'product_id': 101, 'quantity': 2, 'price': 29.99},

376

{'product_id': 202, 'quantity': 1, 'price': 15.50},

377

{'product_id': 303, 'quantity': 3, 'price': 8.75}

378

]

379

380

cart_item_schema = {

381

'product_id': IsPositive,

382

'quantity': IsPositive,

383

'price': IsPositive

384

}

385

386

assert cart_items == IsList(

387

cart_item_schema,

388

cart_item_schema,

389

cart_item_schema,

390

length=3

391

)

392

393

# Log entries validation

394

log_entries = [

395

'INFO: Application started',

396

'DEBUG: Loading configuration',

397

'ERROR: Database connection failed'

398

]

399

400

assert log_entries == IsList(

401

positions={

402

0: IsStr, # Any string for first entry

403

2: Contains('ERROR') # Last entry must contain ERROR

404

},

405

length=3

406

)

407

408

# Nested list validation

409

matrix = [

410

[1, 2, 3],

411

[4, 5, 6],

412

[7, 8, 9]

413

]

414

415

row_pattern = IsList(IsPositive, IsPositive, IsPositive)

416

assert matrix == IsList(row_pattern, row_pattern, row_pattern)

417

418

# File processing results

419

processed_files = [

420

'document1.txt',

421

'image2.jpg',

422

'data3.csv',

423

'config4.json'

424

]

425

426

assert processed_files == IsList(

427

Contains('.txt'),

428

Contains('.jpg'),

429

Contains('.csv'),

430

Contains('.json'),

431

check_order=False # Files might be processed in any order

432

)

433

```

434

435

### IsTuple

436

437

Tuple-specific validation that inherits all functionality from IsListOrTuple but restricts validation to tuple objects only.

438

439

```python { .api }

440

class IsTuple(IsListOrTuple):

441

"""

442

Tuple-specific comparison with constraints.

443

444

Inherits all functionality from IsListOrTuple but only

445

accepts tuple objects, not lists.

446

"""

447

448

allowed_type: ClassVar[type] = tuple

449

```

450

451

#### Usage Examples

452

453

```python

454

from dirty_equals import IsTuple, IsPositive, IsStr

455

456

# Basic tuple validation

457

assert (1, 2, 3) == IsTuple(1, 2, 3)

458

assert ('a', 'b', 'c') == IsTuple('a', 'b', 'c')

459

460

# Lists won't match

461

# assert [1, 2, 3] == IsTuple(1, 2, 3) # Would fail

462

463

# Named tuple-like validation

464

person_tuple = ('John Doe', 25, 'Engineer', True)

465

assert person_tuple == IsTuple(

466

IsStr, # Name

467

IsPositive, # Age

468

IsStr, # Job title

469

bool # Active status

470

)

471

472

# Coordinate validation

473

point_2d = (3.14, 2.71)

474

point_3d = (1.0, 2.0, 3.0)

475

476

assert point_2d == IsTuple(float, float)

477

assert point_3d == IsTuple(float, float, float)

478

479

# Database record as tuple

480

db_record = (123, 'Alice Johnson', 'alice@example.com', '2023-01-15')

481

assert db_record == IsTuple(

482

IsPositive, # ID

483

IsStr, # Name

484

Contains('@'), # Email

485

IsStr, # Date string

486

length=4

487

)

488

489

# Function return value validation

490

def get_user_info(user_id):

491

return (user_id, 'John Doe', 'john@example.com', True)

492

493

result = get_user_info(123)

494

assert result == IsTuple(

495

123, # Expected user ID

496

IsStr, # Name

497

IsStr, # Email

498

True # Active status

499

)

500

501

# Configuration tuple with position validation

502

config = ('production', 443, True, 30, '/var/log/')

503

assert config == IsTuple(

504

positions={

505

0: 'production', # Environment

506

1: IsPositive, # Port

507

2: True, # SSL enabled

508

3: IsPositive, # Timeout

509

4: Contains('/') # Log directory

510

},

511

length=5

512

)

513

514

# API response tuple format

515

api_result = ('success', 200, {'user_id': 123}, None)

516

assert api_result == IsTuple(

517

'success', # Status

518

200, # HTTP code

519

dict, # Data payload

520

None, # Error (should be None for success)

521

check_order=True,

522

length=4

523

)

524

525

# Mathematical vector validation

526

vector = (1.0, 0.0, -1.0, 2.5)

527

assert vector == IsTuple(

528

float, float, float, float, # All components must be floats

529

length=4

530

)

531

532

# RGB color tuple

533

rgb_color = (255, 128, 0)

534

assert rgb_color == IsTuple(

535

positions={

536

0: IsRange(0, 255), # Red component

537

1: IsRange(0, 255), # Green component

538

2: IsRange(0, 255) # Blue component

539

},

540

length=3

541

)

542

```

543

544

## Type Definitions

545

546

```python { .api }

547

from typing import Any, ClassVar, Dict, Optional, Tuple, Union

548

549

# All sequence types inherit from DirtyEquals

550

# IsListOrTuple is the base class for IsList and IsTuple

551

# They work with Python's standard list and tuple types

552

```