or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-system.mdcontainer-management.mdframework-integrations.mdindex.mdprovider-system.mdscope-lifecycle.mdtype-markers.mdvalidation-configuration.md

validation-configuration.mddocs/

0

# Validation and Configuration

1

2

Comprehensive validation system for dependency graphs with configurable validation rules and error detection. The validation system ensures dependency graph integrity and helps catch configuration errors early.

3

4

## Capabilities

5

6

### Validation Settings

7

8

Configuration class for controlling dependency graph validation behavior with granular control over different types of checks.

9

10

```python { .api }

11

class ValidationSettings:

12

"""Configuration for dependency graph validation"""

13

14

nothing_overridden: bool = False

15

"""

16

Check that override=True is used consistently.

17

When True, validates that dependencies marked with override=True

18

actually override existing registrations.

19

"""

20

21

implicit_override: bool = False

22

"""

23

Check for implicit overrides (same dependency registered multiple times).

24

When True, validates that duplicate registrations are intentional

25

by requiring explicit override=True.

26

"""

27

28

nothing_decorated: bool = True

29

"""

30

Check that decorator pattern is used correctly.

31

When True, validates that decorators actually decorate existing dependencies.

32

"""

33

34

def __init__(

35

self,

36

*,

37

nothing_overridden: bool = False,

38

implicit_override: bool = False,

39

nothing_decorated: bool = True

40

): ...

41

```

42

43

**Usage Examples:**

44

45

```python

46

from dishka import ValidationSettings, make_container

47

48

# Default validation (lenient)

49

default_settings = ValidationSettings()

50

container = make_container(provider, validation_settings=default_settings)

51

52

# Custom validation settings

53

custom_settings = ValidationSettings(

54

nothing_overridden=True, # Require explicit overrides

55

implicit_override=True, # Catch duplicate registrations

56

nothing_decorated=False # Allow decorators without existing dependencies

57

)

58

container = make_container(provider, validation_settings=custom_settings)

59

60

# Individual setting adjustments

61

settings = ValidationSettings()

62

settings.nothing_overridden = True # Enable override validation

63

```

64

65

### Strict Validation

66

67

Predefined strict validation configuration with all checks enabled for development and testing environments.

68

69

```python { .api }

70

STRICT_VALIDATION: ValidationSettings

71

"""

72

Strict validation settings with all checks enabled.

73

Equivalent to ValidationSettings(

74

nothing_overridden=True,

75

implicit_override=True,

76

nothing_decorated=True

77

)

78

"""

79

80

DEFAULT_VALIDATION: ValidationSettings

81

"""

82

Default validation settings used when no validation_settings specified.

83

Equivalent to ValidationSettings(

84

nothing_overridden=False,

85

implicit_override=False,

86

nothing_decorated=True

87

)

88

"""

89

```

90

91

**Usage Example:**

92

93

```python

94

from dishka import STRICT_VALIDATION, make_container

95

96

# Use strict validation for development

97

container = make_container(

98

provider,

99

validation_settings=STRICT_VALIDATION,

100

skip_validation=False # Ensure validation runs

101

)

102

103

# Strict validation will catch:

104

# - Overrides without override=True

105

# - Duplicate registrations without explicit override

106

# - Decorators without existing dependencies

107

```

108

109

### Container Validation Options

110

111

Container creation functions support validation configuration and can skip validation entirely for performance.

112

113

```python { .api }

114

def make_container(

115

*providers: BaseProvider,

116

skip_validation: bool = False,

117

validation_settings: ValidationSettings = DEFAULT_VALIDATION,

118

**kwargs

119

) -> Container:

120

"""

121

Parameters:

122

- skip_validation: Skip all dependency graph validation

123

- validation_settings: Configuration for validation rules

124

"""

125

126

def make_async_container(

127

*providers: BaseProvider,

128

skip_validation: bool = False,

129

validation_settings: ValidationSettings = DEFAULT_VALIDATION,

130

**kwargs

131

) -> AsyncContainer:

132

"""

133

Parameters:

134

- skip_validation: Skip all dependency graph validation

135

- validation_settings: Configuration for validation rules

136

"""

137

```

138

139

**Validation Examples:**

140

141

```python

142

# Skip validation for performance (production)

143

fast_container = make_container(

144

provider,

145

skip_validation=True # No validation overhead

146

)

147

148

# Enable validation with custom settings (development)

149

dev_container = make_container(

150

provider,

151

skip_validation=False,

152

validation_settings=STRICT_VALIDATION

153

)

154

155

# Default validation (moderate checking)

156

container = make_container(provider) # Uses DEFAULT_VALIDATION

157

```

158

159

### Override Validation

160

161

Validation for explicit override usage to prevent accidental duplicate registrations.

162

163

**Override Rules:**

164

165

1. `override=False` (default): Registration fails if dependency already exists

166

2. `override=True`: Registration replaces existing dependency

167

3. `nothing_overridden=True`: Validates that `override=True` actually overrides something

168

169

**Valid Override Usage:**

170

171

```python

172

from dishka import Provider

173

174

provider = Provider()

175

176

# Initial registration

177

provider.provide(PostgreSQLDatabase, provides=Database)

178

179

# Explicit override

180

provider.provide(

181

MySQLDatabase,

182

provides=Database,

183

override=True # Required to replace existing registration

184

)

185

186

# This works with validation

187

container = make_container(

188

provider,

189

validation_settings=ValidationSettings(nothing_overridden=True)

190

)

191

```

192

193

**Invalid Override Usage:**

194

195

```python

196

provider = Provider()

197

198

# Override without existing registration

199

provider.provide(

200

Database,

201

override=True # Nothing to override!

202

)

203

204

# This fails with nothing_overridden=True

205

try:

206

container = make_container(

207

provider,

208

validation_settings=ValidationSettings(nothing_overridden=True)

209

)

210

except ValidationError as e:

211

print(f"Override validation failed: {e}")

212

```

213

214

### Implicit Override Detection

215

216

Detection of duplicate registrations that may be unintentional.

217

218

**Implicit Override Rules:**

219

220

When `implicit_override=True`:

221

- Duplicate registrations without `override=True` raise validation errors

222

- Helps catch accidental duplicate registrations

223

- Enforces explicit intent for dependency replacement

224

225

**Valid Explicit Overrides:**

226

227

```python

228

provider = Provider()

229

230

# Initial registration

231

provider.provide(InMemoryCache, provides=CacheService)

232

233

# Explicit override (valid)

234

provider.provide(

235

RedisCache,

236

provides=CacheService,

237

override=True # Explicit intent to replace

238

)

239

240

# Validation passes

241

container = make_container(

242

provider,

243

validation_settings=ValidationSettings(implicit_override=True)

244

)

245

```

246

247

**Invalid Implicit Overrides:**

248

249

```python

250

provider = Provider()

251

252

# Initial registration

253

provider.provide(InMemoryCache, provides=CacheService)

254

255

# Implicit override (invalid with implicit_override=True)

256

provider.provide(RedisCache, provides=CacheService) # Missing override=True

257

258

# This fails validation

259

try:

260

container = make_container(

261

provider,

262

validation_settings=ValidationSettings(implicit_override=True)

263

)

264

except ValidationError as e:

265

print(f"Implicit override detected: {e}")

266

```

267

268

### Decorator Validation

269

270

Validation for decorator pattern usage to ensure decorators have dependencies to decorate.

271

272

**Decorator Rules:**

273

274

When `nothing_decorated=True`:

275

- Decorators must decorate existing dependencies

276

- Prevents decorators that have nothing to decorate

277

- Ensures decorator pattern is used correctly

278

279

**Valid Decorator Usage:**

280

281

```python

282

from dishka import Provider, provide, decorate

283

284

provider = Provider()

285

286

# Base dependency

287

@provider.provide

288

def database() -> Database:

289

return PostgreSQLDatabase()

290

291

# Decorator for existing dependency (valid)

292

@provider.decorate(provides=Database)

293

def add_logging(db: Database) -> Database:

294

return LoggingDatabase(db)

295

296

# Validation passes

297

container = make_container(

298

provider,

299

validation_settings=ValidationSettings(nothing_decorated=True)

300

)

301

```

302

303

**Invalid Decorator Usage:**

304

305

```python

306

provider = Provider()

307

308

# Decorator without base dependency (invalid)

309

@provider.decorate(provides=Database)

310

def add_logging(db: Database) -> Database:

311

return LoggingDatabase(db) # Nothing to decorate!

312

313

# This fails validation

314

try:

315

container = make_container(

316

provider,

317

validation_settings=ValidationSettings(nothing_decorated=True)

318

)

319

except ValidationError as e:

320

print(f"Decorator validation failed: {e}")

321

```

322

323

### Validation Errors

324

325

Exception classes for different types of validation failures.

326

327

```python { .api }

328

class ValidationError(DishkaError):

329

"""Base class for validation errors"""

330

331

class GraphMissingFactoryError(ValidationError):

332

"""Dependency required but no factory found"""

333

334

class DependencyCycleError(ValidationError):

335

"""Circular dependency detected in graph"""

336

337

class InvalidGraphError(ValidationError):

338

"""General dependency graph validation failure"""

339

340

class UnsupportedFactoryError(ValidationError):

341

"""Factory type not supported by container"""

342

```

343

344

**Error Handling:**

345

346

```python

347

from dishka import ValidationError, make_container

348

349

try:

350

container = make_container(

351

provider,

352

validation_settings=STRICT_VALIDATION

353

)

354

except ValidationError as e:

355

print(f"Validation failed: {e}")

356

# Handle validation error - fix provider configuration

357

except DependencyCycleError as e:

358

print(f"Circular dependency: {e}")

359

# Handle circular dependency - restructure dependencies

360

```

361

362

### Performance Considerations

363

364

Validation impact on container creation and runtime performance.

365

366

**Validation Overhead:**

367

368

```python

369

import time

370

from dishka import make_container

371

372

# Measure validation overhead

373

start = time.time()

374

container_with_validation = make_container(

375

provider,

376

skip_validation=False,

377

validation_settings=STRICT_VALIDATION

378

)

379

validation_time = time.time() - start

380

381

start = time.time()

382

container_without_validation = make_container(

383

provider,

384

skip_validation=True

385

)

386

no_validation_time = time.time() - start

387

388

print(f"With validation: {validation_time:.3f}s")

389

print(f"Without validation: {no_validation_time:.3f}s")

390

```

391

392

**Production Recommendations:**

393

394

```python

395

# Development: Use strict validation

396

if DEBUG:

397

container = make_container(

398

provider,

399

validation_settings=STRICT_VALIDATION

400

)

401

else:

402

# Production: Skip validation for performance

403

container = make_container(

404

provider,

405

skip_validation=True

406

)

407

```

408

409

### Custom Validation Rules

410

411

While Dishka doesn't provide custom validation rule APIs, you can implement validation logic in providers.

412

413

**Provider-Level Validation:**

414

415

```python

416

class ValidatingProvider(Provider):

417

def __init__(self, **kwargs):

418

super().__init__(**kwargs)

419

self._validate_configuration()

420

421

def _validate_configuration(self):

422

"""Custom provider validation logic"""

423

# Check provider-specific rules

424

dependencies = self.get_dependencies()

425

426

# Example: Ensure all database dependencies have proper scope

427

for key, source in dependencies.items():

428

if "Database" in str(key.type_hint):

429

if source.scope != Scope.APP:

430

raise ValueError(f"Database {key} must use APP scope")

431

432

@provide(scope=Scope.APP)

433

def database(self) -> Database:

434

return PostgreSQLDatabase()

435

```

436

437

### Validation Best Practices

438

439

Recommended practices for using validation effectively.

440

441

**1. Development vs Production:**

442

443

```python

444

# Use strict validation in development

445

DEV_SETTINGS = STRICT_VALIDATION

446

447

# Use minimal validation in production

448

PROD_SETTINGS = ValidationSettings(

449

nothing_overridden=False, # Allow flexibility

450

implicit_override=False, # Performance

451

nothing_decorated=True # Basic safety

452

)

453

454

settings = DEV_SETTINGS if DEBUG else PROD_SETTINGS

455

container = make_container(provider, validation_settings=settings)

456

```

457

458

**2. Incremental Validation:**

459

460

```python

461

# Start with lenient settings and gradually increase strictness

462

settings = ValidationSettings(

463

nothing_overridden=True, # Start with override validation

464

implicit_override=False, # Add later when codebase is clean

465

nothing_decorated=True # Basic decorator validation

466

)

467

```

468

469

**3. CI/CD Integration:**

470

471

```python

472

# Always use strict validation in tests

473

def test_container_creation():

474

"""Ensure container can be created with strict validation"""

475

container = make_container(

476

test_provider,

477

validation_settings=STRICT_VALIDATION

478

)

479

assert container is not None

480

```

481

482

**4. Error Reporting:**

483

484

```python

485

def create_container_with_detailed_errors(provider):

486

"""Helper that provides detailed validation error information"""

487

try:

488

return make_container(

489

provider,

490

validation_settings=STRICT_VALIDATION

491

)

492

except ValidationError as e:

493

print(f"Dependency validation failed:")

494

print(f"Error: {e}")

495

print(f"Provider: {provider}")

496

print("Check your dependency registrations and fix the issues above.")

497

raise

498

```