or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-factories.mddeclarations.mdhelpers-and-utilities.mdindex.mdorm-integration.md

declarations.mddocs/

0

# Attribute Declarations

1

2

Comprehensive declaration types for generating dynamic attribute values in factories. These declarations enable sophisticated test data generation with sequences, lazy evaluation, faker integration, conditional logic, and complex object relationships.

3

4

## Capabilities

5

6

### Basic Attribute Declarations

7

8

Core declarations for computing attribute values using functions and external data.

9

10

```python { .api }

11

class LazyFunction:

12

"""

13

Computed by calling function without arguments each time.

14

15

Args:

16

function: Callable that returns the attribute value

17

"""

18

def __init__(self, function): ...

19

20

class LazyAttribute:

21

"""

22

Computed using function that receives the current instance being built.

23

24

Args:

25

function: Callable that takes the instance and returns attribute value

26

"""

27

def __init__(self, function): ...

28

29

class SelfAttribute:

30

"""

31

Copy values from other fields, supports dot notation and parent access.

32

33

Args:

34

attribute_name (str): Name of attribute to copy (supports 'field', 'sub.field', '..parent.field')

35

default: Default value if attribute not found

36

"""

37

def __init__(self, attribute_name, default=UNSPECIFIED): ...

38

```

39

40

#### Usage Examples

41

42

```python

43

class UserFactory(Factory):

44

class Meta:

45

model = User

46

47

# LazyFunction - called fresh each time

48

created_at = LazyFunction(lambda: timezone.now())

49

uuid = LazyFunction(lambda: str(uuid.uuid4()))

50

51

# LazyAttribute - receives the current instance

52

email = LazyAttribute(lambda obj: f'{obj.username}@example.com')

53

display_name = LazyAttribute(lambda obj: f'{obj.first_name} {obj.last_name}')

54

55

# SelfAttribute - copy from other fields

56

username = 'john_doe'

57

login_name = SelfAttribute('username')

58

backup_email = SelfAttribute('email', default='fallback@example.com')

59

```

60

61

### Sequence and Iterator Declarations

62

63

Declarations for generating unique, sequential, or cyclic values.

64

65

```python { .api }

66

class Sequence:

67

"""

68

Generate increasing unique values using sequence counter.

69

70

Args:

71

function: Callable that takes sequence number (int) and returns value

72

"""

73

def __init__(self, function): ...

74

75

class LazyAttributeSequence:

76

"""

77

Combination of LazyAttribute and Sequence - receives instance and sequence number.

78

79

Args:

80

function: Callable that takes (instance, sequence_number) and returns value

81

"""

82

def __init__(self, function): ...

83

84

class Iterator:

85

"""

86

Fill value using iterator values, with optional cycling and getter function.

87

88

Args:

89

iterator: Iterable to get values from

90

cycle (bool): Whether to cycle through values when exhausted

91

getter: Optional function to extract values from iterator items

92

"""

93

def __init__(self, iterator, cycle=True, getter=None): ...

94

95

def reset(self):

96

"""Reset internal iterator to beginning."""

97

```

98

99

#### Usage Examples

100

101

```python

102

class UserFactory(Factory):

103

class Meta:

104

model = User

105

106

# Simple sequence

107

email = Sequence(lambda n: f'user{n}@example.com')

108

109

# LazyAttributeSequence - instance + sequence

110

username = LazyAttributeSequence(lambda obj, n: f'{obj.first_name.lower()}_{n}')

111

112

# Iterator with cycling

113

department = Iterator(['Engineering', 'Sales', 'Marketing'])

114

115

# Iterator with getter function

116

priority = Iterator([

117

{'name': 'High', 'value': 1},

118

{'name': 'Medium', 'value': 2},

119

{'name': 'Low', 'value': 3}

120

], getter=lambda item: item['value'])

121

122

# Non-cycling iterator

123

one_time_code = Iterator(['ABC123', 'DEF456', 'GHI789'], cycle=False)

124

```

125

126

### Faker Integration

127

128

Integration with the Faker library for generating realistic fake data.

129

130

```python { .api }

131

class Faker:

132

"""

133

Wrapper for faker library values with locale support and custom providers.

134

135

Args:

136

provider (str): Faker provider name (e.g., 'name', 'email', 'address')

137

locale (str, optional): Locale for this faker instance

138

**kwargs: Additional arguments passed to the faker provider

139

"""

140

def __init__(self, provider, locale=None, **kwargs): ...

141

142

def generate(self, extra_kwargs=None):

143

"""Generate fake value with optional extra parameters."""

144

145

@classmethod

146

def override_default_locale(cls, locale):

147

"""Context manager for temporarily overriding default locale."""

148

149

@classmethod

150

def add_provider(cls, provider, locale=None):

151

"""Add custom faker provider."""

152

```

153

154

#### Usage Examples

155

156

```python

157

class UserFactory(Factory):

158

class Meta:

159

model = User

160

161

# Basic faker usage

162

first_name = Faker('first_name')

163

last_name = Faker('last_name')

164

email = Faker('email')

165

166

# Faker with parameters

167

birthdate = Faker('date_of_birth', minimum_age=18, maximum_age=65)

168

bio = Faker('text', max_nb_chars=200)

169

170

# Locale-specific faker

171

phone = Faker('phone_number', locale='en_US')

172

173

# Using context manager for locale

174

with Faker.override_default_locale('fr_FR'):

175

address = Faker('address')

176

177

# Custom provider example

178

from faker.providers import BaseProvider

179

180

class CustomProvider(BaseProvider):

181

def department_code(self):

182

return self.random_element(['ENG', 'SAL', 'MKT', 'HR'])

183

184

Faker.add_provider(CustomProvider)

185

186

class EmployeeFactory(Factory):

187

dept_code = Faker('department_code')

188

```

189

190

### Container and Complex Declarations

191

192

Declarations for working with containers and accessing factory context.

193

194

```python { .api }

195

class ContainerAttribute:

196

"""

197

Receives current instance and container chain for complex attribute computation.

198

199

Args:

200

function: Callable that takes (instance, containers) and returns value

201

strict (bool): Whether to enforce strict container access

202

"""

203

def __init__(self, function, strict=True): ...

204

```

205

206

#### Usage Examples

207

208

```python

209

class ProfileFactory(Factory):

210

class Meta:

211

model = Profile

212

213

# Access container chain (useful in SubFactory contexts)

214

user_id = ContainerAttribute(lambda obj, containers: containers[0].id if containers else None)

215

216

# Complex container logic

217

role = ContainerAttribute(

218

lambda obj, containers: 'admin' if containers and containers[0].is_staff else 'user'

219

)

220

```

221

222

### Factory Composition

223

224

Declarations for creating related objects and complex data structures.

225

226

```python { .api }

227

class SubFactory:

228

"""

229

Create related objects using another factory.

230

231

Args:

232

factory: Factory class or string path to factory

233

**defaults: Default values to pass to the sub-factory

234

"""

235

def __init__(self, factory, **defaults): ...

236

237

def get_factory(self):

238

"""Retrieve the wrapped factory class."""

239

240

class Dict:

241

"""

242

Fill dictionary with declarations.

243

244

Args:

245

params (dict): Dictionary of key-value pairs, values can be declarations

246

dict_factory (str): Factory to use for creating dictionary

247

"""

248

def __init__(self, params, dict_factory='factory.DictFactory'): ...

249

250

class List:

251

"""

252

Fill list with declarations.

253

254

Args:

255

params (list): List of values, can include declarations

256

list_factory (str): Factory to use for creating list

257

"""

258

def __init__(self, params, list_factory='factory.ListFactory'): ...

259

```

260

261

#### Usage Examples

262

263

```python

264

class UserFactory(Factory):

265

class Meta:

266

model = User

267

268

name = Faker('name')

269

email = Faker('email')

270

271

class PostFactory(Factory):

272

class Meta:

273

model = Post

274

275

title = Faker('sentence')

276

277

# SubFactory creates related User

278

author = SubFactory(UserFactory, name='Post Author')

279

280

# Dict with mixed static and dynamic values

281

metadata = Dict({

282

'views': 0,

283

'created_at': LazyFunction(lambda: timezone.now().isoformat()),

284

'tags': List([Faker('word'), Faker('word'), 'default-tag'])

285

})

286

287

# List of related objects

288

comments = List([

289

SubFactory('CommentFactory', content='First comment'),

290

SubFactory('CommentFactory', content='Second comment')

291

])

292

```

293

294

### Conditional Logic

295

296

Declarations for conditional attribute generation based on other values.

297

298

```python { .api }

299

class Maybe:

300

"""

301

Conditional declaration based on decider value.

302

303

Args:

304

decider (str or callable): Field name or function to evaluate condition

305

yes_declaration: Declaration to use when condition is truthy

306

no_declaration: Declaration to use when condition is falsy (defaults to SKIP)

307

"""

308

def __init__(self, decider, yes_declaration=SKIP, no_declaration=SKIP): ...

309

310

class Trait:

311

"""

312

Enable declarations based on boolean flag, used in Params section.

313

314

Args:

315

**overrides: Attribute overrides to apply when trait is enabled

316

"""

317

def __init__(self, **overrides): ...

318

```

319

320

#### Usage Examples

321

322

```python

323

class UserFactory(Factory):

324

class Meta:

325

model = User

326

327

name = Faker('name')

328

is_premium = Iterator([True, False])

329

330

# Maybe based on field value

331

premium_features = Maybe(

332

'is_premium',

333

yes_declaration=Dict({'advanced_analytics': True, 'priority_support': True}),

334

no_declaration=Dict({'basic_features': True})

335

)

336

337

# Maybe with function decider

338

account_type = Maybe(

339

lambda obj: obj.is_premium,

340

yes_declaration='Premium',

341

no_declaration='Basic'

342

)

343

344

class PostFactory(Factory):

345

class Meta:

346

model = Post

347

348

title = Faker('sentence')

349

status = 'draft'

350

351

class Params:

352

# Trait for published posts

353

published = Trait(

354

status='published',

355

published_at=LazyFunction(lambda: timezone.now()),

356

slug=LazyAttribute(lambda obj: slugify(obj.title))

357

)

358

359

# Usage: PostFactory(published=True) enables the published trait

360

published_post = PostFactory(published=True)

361

```

362

363

### Post-Generation Declarations

364

365

Declarations that execute after object creation for relationships and method calls.

366

367

```python { .api }

368

class PostGeneration:

369

"""

370

Call function after object generation.

371

372

Args:

373

function: Callable that takes (instance, create, extracted, **kwargs)

374

"""

375

def __init__(self, function): ...

376

377

class PostGenerationMethodCall:

378

"""

379

Call method on generated object after creation.

380

381

Args:

382

method_name (str): Name of method to call on the instance

383

*args: Positional arguments to pass to method

384

**kwargs: Keyword arguments to pass to method

385

"""

386

def __init__(self, method_name, *args, **kwargs): ...

387

388

class RelatedFactory:

389

"""

390

Create related object after main object generation.

391

392

Args:

393

factory: Factory class to use for creating related object

394

factory_related_name (str): Attribute name on related object to set main object

395

**defaults: Default values for related object factory

396

"""

397

def __init__(self, factory, factory_related_name='', **defaults): ...

398

399

class RelatedFactoryList:

400

"""

401

Create multiple related objects after main object generation.

402

403

Args:

404

factory: Factory class to use for creating related objects

405

factory_related_name (str): Attribute name on related objects to set main object

406

size (int): Number of related objects to create

407

**defaults: Default values for related object factory

408

"""

409

def __init__(self, factory, factory_related_name='', size=2, **defaults): ...

410

```

411

412

#### Usage Examples

413

414

```python

415

class UserFactory(Factory):

416

class Meta:

417

model = User

418

419

username = Faker('user_name')

420

email = Faker('email')

421

422

# PostGeneration for custom setup

423

setup_profile = PostGeneration(

424

lambda obj, create, extracted, **kwargs: obj.create_default_profile() if create else None

425

)

426

427

# PostGenerationMethodCall for method execution

428

set_password = PostGenerationMethodCall('set_password', 'default_password')

429

430

# RelatedFactory creates profile after user

431

profile = RelatedFactory('ProfileFactory', 'user')

432

433

class PostFactory(Factory):

434

class Meta:

435

model = Post

436

437

title = Faker('sentence')

438

author = SubFactory(UserFactory)

439

440

# RelatedFactoryList creates multiple comments

441

comments = RelatedFactoryList(

442

'CommentFactory',

443

'post',

444

size=3,

445

author=SubFactory(UserFactory)

446

)

447

448

# Usage with extracted values

449

user = UserFactory(set_password__password='custom_password')

450

```

451

452

## Special Values and Constants

453

454

```python { .api }

455

# Special marker for skipping fields

456

SKIP = object()

457

458

# Unspecified default marker

459

UNSPECIFIED = object()

460

```

461

462

## Declaration Wrapper Functions

463

464

Functional-style wrappers for creating declarations:

465

466

```python { .api }

467

def lazy_attribute(func):

468

"""Wrap function as LazyAttribute declaration."""

469

470

def sequence(func):

471

"""Wrap function as Sequence declaration."""

472

473

def lazy_attribute_sequence(func):

474

"""Wrap function as LazyAttributeSequence declaration."""

475

476

def container_attribute(func):

477

"""Wrap function as ContainerAttribute declaration (non-strict)."""

478

479

def post_generation(func):

480

"""Wrap function as PostGeneration declaration."""

481

```

482

483

#### Usage Examples

484

485

```python

486

# Using wrapper functions

487

@lazy_attribute

488

def full_name(obj):

489

return f'{obj.first_name} {obj.last_name}'

490

491

@sequence

492

def email(n):

493

return f'user{n}@example.com'

494

495

@post_generation

496

def send_welcome_email(obj, create, extracted, **kwargs):

497

if create:

498

obj.send_welcome_email()

499

500

class UserFactory(Factory):

501

class Meta:

502

model = User

503

504

first_name = Faker('first_name')

505

last_name = Faker('last_name')

506

full_name = full_name

507

email = email

508

send_welcome_email = send_welcome_email

509

```