or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

customization.mdfactory-operations.mdfield-configuration.mdindex.mdpersistence.mdspecialized-factories.md

customization.mddocs/

0

# Customization

1

2

Extensible system for registering custom value generators, configuring factory behavior, and adapting polyfactory to specific types and use cases. The provider system allows fine-grained control over how values are generated for any type.

3

4

## Capabilities

5

6

### Provider Registration

7

8

Register custom value generators for specific types, overriding default generation behavior with domain-specific logic.

9

10

```python { .api }

11

@classmethod

12

def add_provider(cls, provider_type: Any, provider_function: Callable[[], Any]) -> None:

13

"""

14

Register a custom provider function for a specific type.

15

16

Parameters:

17

- provider_type: The type to register the provider for

18

- provider_function: Callable with no arguments that generates values for the type

19

"""

20

21

@classmethod

22

def get_provider_map(cls) -> dict[type, Callable[[], Any]]:

23

"""

24

Get the current mapping of types to provider functions.

25

26

Returns:

27

Dictionary mapping types to their provider functions

28

"""

29

```

30

31

**Usage Example:**

32

```python

33

from dataclasses import dataclass

34

from polyfactory.factories import DataclassFactory

35

from enum import Enum

36

import random

37

38

class Priority(Enum):

39

LOW = "low"

40

MEDIUM = "medium"

41

HIGH = "high"

42

43

@dataclass

44

class Task:

45

title: str

46

priority: Priority

47

estimated_hours: int

48

49

class TaskFactory(DataclassFactory[Task]):

50

__model__ = Task

51

52

# Register custom provider for Priority enum

53

@classmethod

54

def __init_subclass__(cls, **kwargs):

55

super().__init_subclass__(**kwargs)

56

cls.add_provider(Priority, lambda: random.choice(list(Priority)))

57

58

# Custom provider for estimated hours based on priority

59

def hours_provider():

60

# This would have access to other generated values in real implementation

61

return random.randint(1, 40)

62

63

cls.add_provider(int, hours_provider) # Override int generation for this factory

64

65

task = TaskFactory.build() # Uses custom Priority and hours logic

66

```

67

68

### Random Seed Control

69

70

Control randomization for reproducible test data generation across faker and random instances.

71

72

```python { .api }

73

@classmethod

74

def seed_random(cls, seed: int) -> None:

75

"""

76

Seed the random number generators for deterministic generation.

77

78

Parameters:

79

- seed: Integer seed value for reproducible random generation

80

"""

81

```

82

83

**Usage Example:**

84

```python

85

from polyfactory.factories import DataclassFactory

86

87

# Set seed for reproducible generation

88

UserFactory.seed_random(42)

89

90

# These will generate the same data every time

91

user1 = UserFactory.build()

92

user2 = UserFactory.build()

93

94

# Reset with same seed to get identical results

95

UserFactory.seed_random(42)

96

user3 = UserFactory.build() # Identical to user1

97

```

98

99

### Factory Configuration Attributes

100

101

Comprehensive set of configuration attributes that control factory behavior and generation patterns.

102

103

```python { .api }

104

class ConfigurableFactory(BaseFactory[T]):

105

# Core configuration

106

__model__: type # Required: Model type for the factory

107

__faker__: Faker # Faker instance for realistic data generation

108

__random__: Random # Random instance for deterministic generation

109

110

# Collection behavior

111

__randomize_collection_length__: bool = False # Randomize collection sizes

112

__min_collection_length__: int = 0 # Minimum collection size

113

__max_collection_length__: int = 5 # Maximum collection size

114

115

# Generation behavior

116

__allow_none_optionals__: bool = True # Allow None for optional fields

117

__use_defaults__: bool = True # Use model default values when available

118

__check_model__: bool = True # Validate generated instances

119

120

# Persistence handlers

121

__sync_persistence__: SyncPersistenceProtocol | None = None

122

__async_persistence__: AsyncPersistenceProtocol | None = None

123

124

# Factory registration

125

__set_as_default_factory_for_type__: bool = False # Register as default factory

126

```

127

128

**Configuration Examples:**

129

```python

130

from dataclasses import dataclass

131

from polyfactory.factories import DataclassFactory

132

from faker import Faker

133

134

@dataclass

135

class Product:

136

name: str

137

tags: list[str]

138

description: str | None = None

139

140

class ProductFactory(DataclassFactory[Product]):

141

__model__ = Product

142

143

# Custom faker instance with specific locale

144

__faker__ = Faker('es_ES') # Spanish locale

145

146

# Collection configuration

147

__randomize_collection_length__ = True

148

__min_collection_length__ = 2

149

__max_collection_length__ = 8

150

151

# Always include description (no None values)

152

__allow_none_optionals__ = False

153

154

# Enable model validation

155

__check_model__ = True

156

157

product = ProductFactory.build() # Spanish names, 2-8 tags, always has description

158

```

159

160

### Global Type Providers

161

162

Register providers that apply across all factories for common custom types.

163

164

```python

165

from polyfactory import BaseFactory

166

from decimal import Decimal

167

import random

168

169

# Global provider for Decimal type

170

BaseFactory.add_provider(

171

Decimal,

172

lambda: Decimal(str(round(random.uniform(0.01, 999.99), 2)))

173

)

174

175

# Now all factories will use this for Decimal fields

176

from dataclasses import dataclass

177

178

@dataclass

179

class Price:

180

amount: Decimal

181

currency: str

182

183

class PriceFactory(DataclassFactory[Price]):

184

__model__ = Price

185

186

price = PriceFactory.build() # Uses global Decimal provider

187

```

188

189

### Custom Factory Creation

190

191

Create factories dynamically for types without explicit factory class definition.

192

193

```python { .api }

194

@classmethod

195

def create_factory(

196

cls,

197

model: type,

198

**kwargs

199

) -> type[BaseFactory]:

200

"""

201

Dynamically create a factory class for a model type.

202

203

Parameters:

204

- model: The model type to create a factory for

205

- **kwargs: Configuration attributes for the factory class

206

207

Returns:

208

Factory class configured for the specified model

209

"""

210

```

211

212

**Usage Example:**

213

```python

214

from typing import TypedDict

215

216

class OrderDict(TypedDict):

217

id: int

218

total: float

219

items: list[str]

220

221

# Create factory dynamically with custom configuration

222

OrderFactory = BaseFactory.create_factory(

223

OrderDict,

224

__min_collection_length__=1,

225

__max_collection_length__=10,

226

__allow_none_optionals__=False

227

)

228

229

# Add custom provider to dynamic factory

230

OrderFactory.add_provider(

231

float,

232

lambda: round(random.uniform(10.0, 1000.0), 2)

233

)

234

235

order = OrderFactory.build()

236

```

237

238

### Type Support and Extensions

239

240

Check type support and extend polyfactory's capabilities for custom types.

241

242

```python { .api }

243

@classmethod

244

def is_supported_type(cls, value: Any) -> bool:

245

"""

246

Check if a type is supported for automatic generation.

247

248

Parameters:

249

- value: Type or value to check for support

250

251

Returns:

252

True if the type can be automatically generated, False otherwise

253

"""

254

```

255

256

**Usage Example:**

257

```python

258

from typing import NewType

259

from polyfactory import BaseFactory

260

261

# Custom type

262

UserId = NewType('UserId', int)

263

264

# Check if supported

265

if not BaseFactory.is_supported_type(UserId):

266

# Add provider for custom type

267

BaseFactory.add_provider(

268

UserId,

269

lambda: UserId(random.randint(1, 999999))

270

)

271

272

# Now UserId is supported

273

assert BaseFactory.is_supported_type(UserId)

274

```

275

276

### Advanced Customization Patterns

277

278

#### Factory Inheritance with Custom Behavior

279

280

```python

281

class BaseModelFactory(DataclassFactory[T]):

282

"""Base factory with common customizations."""

283

284

# Common configuration

285

__randomize_collection_length__ = True

286

__min_collection_length__ = 1

287

__max_collection_length__ = 3

288

__allow_none_optionals__ = False

289

290

@classmethod

291

def __init_subclass__(cls, **kwargs):

292

super().__init_subclass__(**kwargs)

293

294

# Add common providers to all subclasses

295

cls.add_provider(

296

str,

297

lambda: cls.__faker__.sentence(nb_words=3).rstrip('.')

298

)

299

300

@dataclass

301

class User:

302

name: str

303

tags: list[str]

304

305

class UserFactory(BaseModelFactory[User]):

306

__model__ = User

307

# Inherits all base customizations

308

309

user = UserFactory.build() # Uses inherited behavior

310

```

311

312

#### Context-Aware Providers

313

314

```python

315

class ContextAwareFactory(DataclassFactory[Model]):

316

_context = {}

317

318

@classmethod

319

def with_context(cls, **context):

320

"""Create factory instance with context."""

321

factory = type(cls.__name__, (cls,), {})

322

factory._context = context

323

return factory

324

325

@classmethod

326

def context_provider(cls, key: str, default_provider: Callable):

327

"""Provider that uses context if available."""

328

def provider():

329

if key in cls._context:

330

return cls._context[key]

331

return default_provider()

332

return provider

333

334

# Usage

335

@dataclass

336

class TestData:

337

environment: str

338

version: str

339

340

class TestDataFactory(ContextAwareFactory[TestData]):

341

__model__ = TestData

342

343

@classmethod

344

def __init_subclass__(cls, **kwargs):

345

super().__init_subclass__(**kwargs)

346

cls.add_provider(

347

str,

348

cls.context_provider('environment', lambda: 'development')

349

)

350

351

# Use with context

352

ProductionFactory = TestDataFactory.with_context(environment='production')

353

data = ProductionFactory.build() # environment will be 'production'

354

```

355

356

#### Conditional Generation

357

358

```python

359

class ConditionalFactory(DataclassFactory[Model]):

360

@classmethod

361

def build_with_condition(cls, condition: str, **kwargs):

362

"""Build instance with conditional logic."""

363

364

if condition == 'premium':

365

cls.add_provider(int, lambda: random.randint(100, 1000))

366

elif condition == 'basic':

367

cls.add_provider(int, lambda: random.randint(1, 100))

368

369

return cls.build(**kwargs)

370

371

# Usage

372

premium_user = UserFactory.build_with_condition('premium', name='VIP User')

373

basic_user = UserFactory.build_with_condition('basic', name='Regular User')

374

```