or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-backend.mdbuilders.mdconfiguration.mdconstraints.mdfactory-core.mdindex.mdjson-validation.mdpackages.mdutilities.mdvcs-support.mdversion-system.md

builders.mddocs/

0

# Package Builders

1

2

Poetry Core provides a modern package building system supporting wheels, source distributions (sdists), and editable installs. The builders handle file collection, metadata generation, and package creation according to Python packaging standards.

3

4

## Core Imports

5

6

```python

7

from poetry.core.masonry.builders.builder import Builder

8

from poetry.core.masonry.builders.wheel import WheelBuilder

9

from poetry.core.masonry.builders.sdist import SdistBuilder

10

from poetry.core.masonry.metadata import Metadata

11

``` { .api }

12

13

## Base Builder Class

14

15

### Builder

16

17

Abstract base class for all package builders providing common functionality.

18

19

```python

20

class Builder:

21

"""

22

Abstract base class for package builders.

23

24

Provides common functionality for file discovery, exclusion handling,

25

and metadata generation across different package formats.

26

"""

27

28

format: str | None = None # Format identifier ("wheel", "sdist", etc.)

29

30

def __init__(

31

self,

32

poetry: Poetry,

33

executable: Path | None = None,

34

config_settings: dict[str, Any] | None = None,

35

) -> None:

36

"""

37

Initialize builder.

38

39

Args:

40

poetry: Poetry instance representing the project

41

executable: Python executable to use (defaults to current)

42

config_settings: Build configuration settings

43

44

Raises:

45

RuntimeError: If project is not in package mode

46

47

Example:

48

>>> from poetry.core.factory import Factory

49

>>> poetry = Factory().create_poetry()

50

>>> builder = SdistBuilder(poetry)

51

"""

52

53

@property

54

def executable(self) -> Path:

55

"""Python executable used for building."""

56

57

@property

58

def default_target_dir(self) -> Path:

59

"""Default directory for build outputs (typically ./dist)."""

60

61

def build(self, target_dir: Path | None) -> Path:

62

"""

63

Build package to target directory.

64

65

Args:

66

target_dir: Directory to write package file

67

68

Returns:

69

Path to built package file

70

71

Note:

72

Must be implemented by subclasses

73

"""

74

raise NotImplementedError

75

76

def find_files_to_add(self) -> list[BuildIncludeFile]:

77

"""

78

Find all files to include in the package.

79

80

Returns:

81

List of files to add to package with their metadata

82

83

Note:

84

Handles package discovery, file includes/excludes,

85

and VCS integration for determining files.

86

"""

87

88

def find_excluded_files(self, fmt: str | None = None) -> set[str]:

89

"""

90

Find files excluded from packaging.

91

92

Args:

93

fmt: Format to check exclusions for

94

95

Returns:

96

Set of excluded file paths

97

98

Note:

99

Uses VCS ignore files, Poetry configuration excludes,

100

and format-specific exclusion rules.

101

"""

102

``` { .api }

103

104

## Wheel Builder

105

106

### WheelBuilder

107

108

Builds wheel packages according to PEP 427.

109

110

```python

111

class WheelBuilder(Builder):

112

"""

113

Wheel package builder implementing PEP 427.

114

115

Creates .whl files containing compiled Python packages

116

with proper metadata and installation support.

117

"""

118

119

format = "wheel"

120

121

def __init__(

122

self,

123

poetry: Poetry,

124

original: Path | None = None,

125

executable: Path | None = None,

126

editable: bool = False,

127

metadata_directory: Path | None = None,

128

config_settings: dict[str, Any] | None = None,

129

) -> None:

130

"""

131

Initialize wheel builder.

132

133

Args:

134

poetry: Poetry project instance

135

original: Original project path (for advanced scenarios)

136

executable: Python executable for building

137

editable: Whether to build editable wheel

138

metadata_directory: Pre-built metadata directory

139

config_settings: Build configuration settings

140

141

Example:

142

>>> builder = WheelBuilder(poetry, editable=True)

143

>>> builder = WheelBuilder(poetry, config_settings={"--build-option": ["--plat-name", "linux_x86_64"]})

144

"""

145

``` { .api }

146

147

### Class Methods

148

149

#### make_in

150

151

```python

152

@classmethod

153

def make_in(

154

cls,

155

poetry: Poetry,

156

directory: Path | None = None,

157

original: Path | None = None,

158

executable: Path | None = None,

159

editable: bool = False,

160

metadata_directory: Path | None = None,

161

config_settings: dict[str, Any] | None = None,

162

) -> str:

163

"""

164

Build wheel in specified directory (class method).

165

166

Args:

167

poetry: Poetry project instance

168

directory: Target directory for wheel file

169

original: Original project path

170

executable: Python executable for building

171

editable: Whether to build editable wheel

172

metadata_directory: Pre-built metadata directory

173

config_settings: Build configuration settings

174

175

Returns:

176

Filename of built wheel

177

178

Example:

179

>>> filename = WheelBuilder.make_in(poetry, Path("./dist"))

180

>>> print(f"Built: {filename}")

181

Built: mypackage-1.0.0-py3-none-any.whl

182

183

>>> # Editable wheel

184

>>> filename = WheelBuilder.make_in(poetry, Path("./dist"), editable=True)

185

186

>>> # With configuration

187

>>> filename = WheelBuilder.make_in(

188

... poetry,

189

... Path("./dist"),

190

... config_settings={"--build-option": ["--verbose"]}

191

... )

192

"""

193

``` { .api }

194

195

#### make

196

197

```python

198

@classmethod

199

def make(cls, poetry: Poetry, executable: Path | None = None) -> None:

200

"""

201

Build wheel in default location (./dist).

202

203

Args:

204

poetry: Poetry project instance

205

executable: Python executable for building

206

207

Example:

208

>>> WheelBuilder.make(poetry)

209

# Creates wheel in ./dist/ directory

210

"""

211

``` { .api }

212

213

### Properties

214

215

```python

216

@property

217

def wheel_filename(self) -> str:

218

"""

219

Generated wheel filename.

220

221

Returns:

222

Wheel filename following PEP 427 naming convention

223

Format: {name}-{version}-{python tag}-{abi tag}-{platform tag}.whl

224

225

Example:

226

>>> builder.wheel_filename

227

'mypackage-1.0.0-py3-none-any.whl'

228

"""

229

230

@property

231

def tag(self) -> packaging.tags.Tag:

232

"""

233

Wheel compatibility tag.

234

235

Returns:

236

Tag object describing Python/ABI/platform compatibility

237

"""

238

239

@property

240

def supports_tags(self) -> list[packaging.tags.Tag]:

241

"""List of all compatible tags for this wheel."""

242

``` { .api }

243

244

### Methods

245

246

```python

247

def build(self, target_dir: Path | None = None) -> Path:

248

"""

249

Build wheel package.

250

251

Args:

252

target_dir: Directory to write wheel file

253

254

Returns:

255

Path to built wheel file

256

257

Example:

258

>>> wheel_path = builder.build(Path("./dist"))

259

>>> print(f"Wheel created: {wheel_path}")

260

"""

261

262

def prepare_metadata(self, metadata_dir: Path) -> Path:

263

"""

264

Prepare wheel metadata without building full wheel.

265

266

Args:

267

metadata_dir: Directory to write metadata

268

269

Returns:

270

Path to .dist-info directory containing metadata

271

272

Note:

273

Used by PEP 517 prepare_metadata_for_build_wheel hook

274

for faster installation planning.

275

"""

276

``` { .api }

277

278

## Source Distribution Builder

279

280

### SdistBuilder

281

282

Builds source distribution packages according to PEP 518.

283

284

```python

285

class SdistBuilder(Builder):

286

"""

287

Source distribution builder implementing PEP 518.

288

289

Creates .tar.gz files containing source code and metadata

290

for distribution and installation from source.

291

"""

292

293

format = "sdist"

294

295

def __init__(

296

self,

297

poetry: Poetry,

298

executable: Path | None = None,

299

config_settings: dict[str, Any] | None = None,

300

) -> None:

301

"""

302

Initialize sdist builder.

303

304

Args:

305

poetry: Poetry project instance

306

executable: Python executable for building

307

config_settings: Build configuration settings

308

309

Example:

310

>>> builder = SdistBuilder(poetry)

311

>>> builder = SdistBuilder(poetry, config_settings={"--formats": ["gztar"]})

312

"""

313

``` { .api }

314

315

### Methods

316

317

```python

318

def build(self, target_dir: Path | None = None) -> Path:

319

"""

320

Build source distribution package.

321

322

Args:

323

target_dir: Directory to write sdist file

324

325

Returns:

326

Path to built sdist file (.tar.gz)

327

328

Example:

329

>>> sdist_path = builder.build(Path("./dist"))

330

>>> print(f"Sdist created: {sdist_path}")

331

Sdist created: ./dist/mypackage-1.0.0.tar.gz

332

"""

333

334

@property

335

def sdist_filename(self) -> str:

336

"""

337

Generated sdist filename.

338

339

Returns:

340

Sdist filename in format: {name}-{version}.tar.gz

341

342

Example:

343

>>> builder.sdist_filename

344

'mypackage-1.0.0.tar.gz'

345

"""

346

``` { .api }

347

348

## Metadata Handling

349

350

### Metadata

351

352

Handles package metadata generation for distributions.

353

354

```python

355

class Metadata:

356

"""

357

Package metadata generator for distributions.

358

359

Creates standard metadata files (METADATA, WHEEL, entry_points.txt)

360

according to packaging specifications.

361

"""

362

363

@classmethod

364

def from_package(cls, package: ProjectPackage) -> Metadata:

365

"""

366

Create metadata from package information.

367

368

Args:

369

package: Project package instance

370

371

Returns:

372

Metadata instance ready for distribution generation

373

"""

374

375

def write_to_directory(

376

self,

377

directory: Path,

378

fmt: str | None = None

379

) -> None:

380

"""

381

Write metadata files to directory.

382

383

Args:

384

directory: Target directory (typically .dist-info or .egg-info)

385

fmt: Format context ("wheel" or "sdist")

386

387

Note:

388

Creates standard metadata files:

389

- METADATA (core metadata)

390

- WHEEL (wheel-specific, for wheels only)

391

- entry_points.txt (if entry points defined)

392

- RECORD (for wheels, file hashes and sizes)

393

"""

394

``` { .api }

395

396

## Build Configuration

397

398

### Configuration Options

399

400

```python

401

# Common config_settings for builders

402

config_settings = {

403

# Build options

404

"--build-option": ["--verbose", "--plat-name", "linux_x86_64"],

405

406

# Global options

407

"--global-option": ["--quiet"],

408

409

# Format-specific options

410

"--formats": ["gztar"], # For sdist

411

412

# Local version label

413

"local-version": "dev123",

414

415

# Environment variables

416

"env": {

417

"POETRY_CORE_DEBUG": "1",

418

"MAKEFLAGS": "-j4"

419

}

420

}

421

``` { .api }

422

423

## Usage Examples

424

425

### Basic Package Building

426

427

```python

428

from pathlib import Path

429

from poetry.core.factory import Factory

430

from poetry.core.masonry.builders.wheel import WheelBuilder

431

from poetry.core.masonry.builders.sdist import SdistBuilder

432

433

def build_project(project_path: Path, output_dir: Path):

434

"""Build both wheel and sdist for a project."""

435

436

# Create Poetry instance

437

factory = Factory()

438

poetry = factory.create_poetry(project_path)

439

440

# Create output directory

441

output_dir.mkdir(exist_ok=True, parents=True)

442

443

print(f"Building {poetry.package.name} v{poetry.package.version}")

444

445

try:

446

# Build wheel

447

print("Building wheel...")

448

wheel_builder = WheelBuilder(poetry)

449

wheel_path = wheel_builder.build(output_dir)

450

print(f"βœ… Wheel: {wheel_path.name}")

451

452

# Build source distribution

453

print("Building sdist...")

454

sdist_builder = SdistBuilder(poetry)

455

sdist_path = sdist_builder.build(output_dir)

456

print(f"βœ… Sdist: {sdist_path.name}")

457

458

return wheel_path, sdist_path

459

460

except Exception as e:

461

print(f"❌ Build failed: {e}")

462

return None, None

463

464

# Usage

465

wheel, sdist = build_project(Path("./my-project"), Path("./dist"))

466

``` { .api }

467

468

### Advanced Wheel Building

469

470

```python

471

from poetry.core.masonry.builders.wheel import WheelBuilder

472

473

def build_specialized_wheels(poetry):

474

"""Build wheels with different configurations."""

475

476

dist_dir = Path("./dist")

477

dist_dir.mkdir(exist_ok=True)

478

479

# Regular wheel

480

print("Building regular wheel...")

481

regular_wheel = WheelBuilder.make_in(poetry, dist_dir)

482

print(f"Regular wheel: {regular_wheel}")

483

484

# Editable wheel (for development)

485

print("Building editable wheel...")

486

editable_wheel = WheelBuilder.make_in(

487

poetry,

488

dist_dir,

489

editable=True

490

)

491

print(f"Editable wheel: {editable_wheel}")

492

493

# Platform-specific wheel

494

print("Building platform-specific wheel...")

495

platform_config = {

496

"--build-option": ["--plat-name", "linux_x86_64"]

497

}

498

platform_wheel = WheelBuilder.make_in(

499

poetry,

500

dist_dir,

501

config_settings=platform_config

502

)

503

print(f"Platform wheel: {platform_wheel}")

504

505

# Development version wheel

506

print("Building development wheel...")

507

dev_config = {

508

"local-version": f"dev{datetime.now().strftime('%Y%m%d')}"

509

}

510

dev_wheel = WheelBuilder.make_in(

511

poetry,

512

dist_dir,

513

config_settings=dev_config

514

)

515

print(f"Dev wheel: {dev_wheel}")

516

517

# Usage

518

build_specialized_wheels(poetry)

519

``` { .api }

520

521

### Metadata Preparation

522

523

```python

524

from pathlib import Path

525

from poetry.core.masonry.builders.wheel import WheelBuilder

526

527

def prepare_metadata_only(poetry, metadata_dir: Path):

528

"""Prepare wheel metadata without building full wheel."""

529

530

metadata_dir.mkdir(exist_ok=True, parents=True)

531

532

# Create wheel builder

533

builder = WheelBuilder(poetry)

534

535

# Prepare metadata

536

dist_info_dir = builder.prepare_metadata(metadata_dir)

537

538

print(f"Metadata prepared in: {dist_info_dir}")

539

540

# List metadata files

541

print("Metadata files:")

542

for file in dist_info_dir.iterdir():

543

print(f" {file.name}")

544

545

# Read core metadata

546

metadata_file = dist_info_dir / "METADATA"

547

if metadata_file.exists():

548

print(f"\nCore metadata preview:")

549

print(metadata_file.read_text()[:500] + "...")

550

551

return dist_info_dir

552

553

# Usage

554

metadata_dir = prepare_metadata_only(poetry, Path("./metadata"))

555

``` { .api }

556

557

### Custom Build Process

558

559

```python

560

from poetry.core.masonry.builders.wheel import WheelBuilder

561

from poetry.core.masonry.builders.sdist import SdistBuilder

562

563

class CustomBuilder:

564

"""Custom builder with additional processing."""

565

566

def __init__(self, poetry):

567

self.poetry = poetry

568

569

def build_with_checks(self, target_dir: Path):

570

"""Build packages with pre/post checks."""

571

572

# Pre-build validation

573

print("πŸ” Pre-build validation...")

574

if not self._validate_project():

575

print("❌ Validation failed")

576

return

577

578

# Build packages

579

print("πŸ—οΈ Building packages...")

580

results = {}

581

582

try:

583

# Build wheel

584

wheel_builder = WheelBuilder(self.poetry)

585

wheel_path = wheel_builder.build(target_dir)

586

results['wheel'] = wheel_path

587

print(f"βœ… Wheel: {wheel_path.name}")

588

589

# Build sdist

590

sdist_builder = SdistBuilder(self.poetry)

591

sdist_path = sdist_builder.build(target_dir)

592

results['sdist'] = sdist_path

593

print(f"βœ… Sdist: {sdist_path.name}")

594

595

# Post-build verification

596

print("πŸ” Post-build verification...")

597

if self._verify_builds(results):

598

print("βœ… Build verification passed")

599

else:

600

print("⚠️ Build verification issues found")

601

602

return results

603

604

except Exception as e:

605

print(f"❌ Build failed: {e}")

606

return None

607

608

def _validate_project(self) -> bool:

609

"""Validate project before building."""

610

package = self.poetry.package

611

612

# Check required metadata

613

if not package.name or not package.version:

614

print("Missing name or version")

615

return False

616

617

# Check for README

618

if not package.readmes:

619

print("⚠️ No README file found")

620

621

# Check for license

622

if not package.license:

623

print("⚠️ No license specified")

624

625

return True

626

627

def _verify_builds(self, results: dict) -> bool:

628

"""Verify built packages."""

629

issues = []

630

631

for build_type, path in results.items():

632

if not path.exists():

633

issues.append(f"{build_type} file not found: {path}")

634

continue

635

636

# Check file size

637

size = path.stat().st_size

638

if size < 1024: # Less than 1KB seems suspicious

639

issues.append(f"{build_type} seems too small: {size} bytes")

640

641

if issues:

642

for issue in issues:

643

print(f"⚠️ {issue}")

644

return False

645

646

return True

647

648

# Usage

649

custom_builder = CustomBuilder(poetry)

650

results = custom_builder.build_with_checks(Path("./dist"))

651

``` { .api }

652

653

### Build Monitoring and Progress

654

655

```python

656

import time

657

from pathlib import Path

658

from poetry.core.masonry.builders.wheel import WheelBuilder

659

660

def build_with_progress(poetry, target_dir: Path):

661

"""Build with progress monitoring."""

662

663

print(f"🎯 Target directory: {target_dir}")

664

target_dir.mkdir(exist_ok=True, parents=True)

665

666

# Track build time

667

start_time = time.time()

668

669

try:

670

print("πŸ“¦ Initializing wheel builder...")

671

builder = WheelBuilder(poetry)

672

673

print("πŸ“ Package information:")

674

print(f" Name: {poetry.package.name}")

675

print(f" Version: {poetry.package.version}")

676

print(f" Dependencies: {len(poetry.package.requires)}")

677

678

print("πŸ” Discovering files...")

679

files = builder.find_files_to_add()

680

print(f" Found {len(files)} files to include")

681

682

print("🚫 Finding excluded files...")

683

excluded = builder.find_excluded_files()

684

print(f" Excluding {len(excluded)} files")

685

686

print("πŸ—οΈ Building wheel...")

687

wheel_path = builder.build(target_dir)

688

689

# Build statistics

690

build_time = time.time() - start_time

691

wheel_size = wheel_path.stat().st_size

692

693

print("βœ… Build completed!")

694

print(f" Wheel: {wheel_path.name}")

695

print(f" Size: {wheel_size:,} bytes ({wheel_size/1024:.1f} KB)")

696

print(f" Time: {build_time:.2f} seconds")

697

698

return wheel_path

699

700

except Exception as e:

701

build_time = time.time() - start_time

702

print(f"❌ Build failed after {build_time:.2f} seconds: {e}")

703

raise

704

705

# Usage

706

wheel_path = build_with_progress(poetry, Path("./dist"))

707

``` { .api }

708

709

## Error Handling

710

711

### Build Error Handling

712

713

```python

714

from poetry.core.masonry.builders.wheel import WheelBuilder

715

from poetry.core.masonry.builders.sdist import SdistBuilder

716

717

def safe_build_packages(poetry, target_dir: Path):

718

"""Build packages with comprehensive error handling."""

719

720

results = {"success": [], "failed": []}

721

722

builders = [

723

("wheel", WheelBuilder),

724

("sdist", SdistBuilder)

725

]

726

727

for build_type, builder_class in builders:

728

try:

729

print(f"Building {build_type}...")

730

731

builder = builder_class(poetry)

732

package_path = builder.build(target_dir)

733

734

results["success"].append({

735

"type": build_type,

736

"path": package_path,

737

"size": package_path.stat().st_size

738

})

739

740

print(f"βœ… {build_type.title()}: {package_path.name}")

741

742

except RuntimeError as e:

743

if "non-package mode" in str(e):

744

print(f"❌ Cannot build {build_type}: Project not in package mode")

745

results["failed"].append({"type": build_type, "error": "non-package mode"})

746

else:

747

print(f"❌ {build_type.title()} build failed: {e}")

748

results["failed"].append({"type": build_type, "error": str(e)})

749

750

except PermissionError as e:

751

print(f"❌ Permission error building {build_type}: {e}")

752

results["failed"].append({"type": build_type, "error": f"permission: {e}"})

753

754

except OSError as e:

755

print(f"❌ OS error building {build_type}: {e}")

756

results["failed"].append({"type": build_type, "error": f"os: {e}"})

757

758

except Exception as e:

759

print(f"❌ Unexpected error building {build_type}: {e}")

760

results["failed"].append({"type": build_type, "error": f"unexpected: {e}"})

761

762

# Summary

763

print(f"\nπŸ“Š Build Summary:")

764

print(f" Successful: {len(results['success'])}")

765

print(f" Failed: {len(results['failed'])}")

766

767

if results["success"]:

768

print(f" Built packages:")

769

for pkg in results["success"]:

770

print(f" {pkg['type']}: {pkg['path'].name} ({pkg['size']:,} bytes)")

771

772

return results

773

774

# Usage

775

results = safe_build_packages(poetry, Path("./dist"))

776

``` { .api }

777

778

## Type Definitions

779

780

```python

781

from typing import Any, Dict, List, Tuple

782

from pathlib import Path

783

784

# Build configuration types

785

BuildConfig = Dict[str, Any]

786

ConfigSettings = Dict[str, Any] | None

787

788

# File handling types

789

BuildIncludeFile = Any # Internal build file representation

790

ExcludedFiles = set[str]

791

792

# Builder result types

793

BuildResult = Path

794

WheelTag = str

795

MetadataPath = Path

796

``` { .api }