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

configuration.mddocs/

0

# PyProject Configuration

1

2

Poetry Core provides robust pyproject.toml parsing and management with full support for Poetry configuration sections and standard build system configuration. This handles both the `[tool.poetry]` section and the standard PEP 517 `[build-system]` configuration.

3

4

## Core Imports

5

6

```python

7

from poetry.core.pyproject.toml import PyProjectTOML

8

from poetry.core.pyproject.tables import BuildSystem

9

from poetry.core.pyproject.exceptions import PyProjectError

10

``` { .api }

11

12

## PyProjectTOML

13

14

Main class for handling pyproject.toml file reading and configuration management.

15

16

### PyProjectTOML.__init__

17

18

```python

19

class PyProjectTOML:

20

def __init__(self, path: Path) -> None:

21

"""

22

Initialize PyProject TOML handler.

23

24

Args:

25

path: Path to pyproject.toml file

26

27

Note:

28

File is loaded lazily on first access to data/configuration.

29

30

Example:

31

>>> from pathlib import Path

32

>>> pyproject = PyProjectTOML(Path("pyproject.toml"))

33

"""

34

``` { .api }

35

36

### Properties

37

38

#### path

39

40

```python

41

@property

42

def path(self) -> Path:

43

"""

44

Path to the pyproject.toml file.

45

46

Returns:

47

Path object pointing to the TOML file

48

49

Example:

50

>>> pyproject = PyProjectTOML(Path("pyproject.toml"))

51

>>> print(pyproject.path)

52

/path/to/project/pyproject.toml

53

"""

54

``` { .api }

55

56

#### data

57

58

```python

59

@property

60

def data(self) -> dict[str, Any]:

61

"""

62

Raw TOML data from the pyproject.toml file.

63

64

Returns:

65

Dictionary containing all TOML sections and data

66

67

Raises:

68

PyProjectError: If TOML file is malformed or cannot be parsed

69

70

Example:

71

>>> pyproject = PyProjectTOML(Path("pyproject.toml"))

72

>>> data = pyproject.data

73

>>> print(data.keys())

74

dict_keys(['build-system', 'tool', 'project'])

75

76

>>> # Access sections

77

>>> build_system = data.get('build-system', {})

78

>>> tool_section = data.get('tool', {})

79

"""

80

``` { .api }

81

82

#### poetry_config

83

84

```python

85

@property

86

def poetry_config(self) -> dict[str, Any]:

87

"""

88

Poetry configuration from [tool.poetry] section.

89

90

Returns:

91

Dictionary containing Poetry-specific configuration

92

93

Raises:

94

PyProjectError: If [tool.poetry] section is not found

95

96

Example:

97

>>> pyproject = PyProjectTOML(Path("pyproject.toml"))

98

>>> config = pyproject.poetry_config

99

>>> print(config['name'])

100

my-package

101

>>> print(config['version'])

102

1.0.0

103

>>> print(config.get('description', ''))

104

A sample package

105

"""

106

``` { .api }

107

108

#### build_system

109

110

```python

111

@property

112

def build_system(self) -> BuildSystem:

113

"""

114

Build system configuration from [build-system] section.

115

116

Returns:

117

BuildSystem object with build backend and requirements

118

119

Note:

120

If no [build-system] section exists, defaults to Poetry Core backend

121

122

Example:

123

>>> pyproject = PyProjectTOML(Path("pyproject.toml"))

124

>>> build_sys = pyproject.build_system

125

>>> print(build_sys.build_backend)

126

poetry.core.masonry.api

127

>>> print(build_sys.requires)

128

['poetry-core']

129

"""

130

``` { .api }

131

132

### Methods

133

134

#### is_poetry_project

135

136

```python

137

def is_poetry_project(self) -> bool:

138

"""

139

Check if project is a valid Poetry project.

140

141

Returns:

142

True if project has [tool.poetry] section or valid [project] metadata

143

144

Note:

145

A project is considered a Poetry project if:

146

1. It has a [tool.poetry] section, OR

147

2. It has [project] section with name and version (no dynamic fields)

148

149

Example:

150

>>> pyproject = PyProjectTOML(Path("pyproject.toml"))

151

>>> if pyproject.is_poetry_project():

152

... print("This is a Poetry project")

153

... else:

154

... print("Not a Poetry project")

155

"""

156

``` { .api }

157

158

#### save

159

160

```python

161

def save(self) -> None:

162

"""

163

Save changes to the pyproject.toml file.

164

165

Raises:

166

IOError: If file cannot be written

167

168

Note:

169

This writes the current data dictionary back to the file.

170

Use with caution as it overwrites the entire file.

171

172

Example:

173

>>> pyproject = PyProjectTOML(Path("pyproject.toml"))

174

>>> data = pyproject.data

175

>>> data['tool']['poetry']['version'] = '2.0.0'

176

>>> pyproject.save() # Write changes back

177

"""

178

``` { .api }

179

180

## BuildSystem

181

182

Represents the [build-system] table configuration according to PEP 517/518.

183

184

### BuildSystem.__init__

185

186

```python

187

class BuildSystem:

188

def __init__(

189

self,

190

build_backend: str | None = None,

191

requires: list[str] | None = None

192

) -> None:

193

"""

194

Create build system configuration.

195

196

Args:

197

build_backend: Build backend module path

198

requires: List of build requirements

199

200

Defaults:

201

build_backend: "setuptools.build_meta:__legacy__" if None

202

requires: ["setuptools", "wheel"] if None

203

204

Example:

205

>>> build_sys = BuildSystem(

206

... build_backend="poetry.core.masonry.api",

207

... requires=["poetry-core"]

208

... )

209

"""

210

``` { .api }

211

212

### Properties

213

214

#### build_backend

215

216

```python

217

@property

218

def build_backend(self) -> str:

219

"""

220

Build backend module path.

221

222

Returns:

223

Module path to PEP 517 build backend

224

225

Example:

226

>>> build_sys.build_backend

227

'poetry.core.masonry.api'

228

"""

229

``` { .api }

230

231

#### requires

232

233

```python

234

@property

235

def requires(self) -> list[str]:

236

"""

237

Build requirements list.

238

239

Returns:

240

List of PEP 508 requirement strings needed for building

241

242

Example:

243

>>> build_sys.requires

244

['poetry-core']

245

"""

246

``` { .api }

247

248

#### dependencies

249

250

```python

251

@property

252

def dependencies(self) -> list[Dependency]:

253

"""

254

Build dependencies as Dependency objects.

255

256

Returns:

257

List of Dependency objects parsed from requires list

258

259

Note:

260

Automatically handles PEP 508 strings, local files, and directories

261

262

Example:

263

>>> deps = build_sys.dependencies

264

>>> for dep in deps:

265

... print(f"{dep.name}: {dep.constraint}")

266

poetry-core: *

267

"""

268

``` { .api }

269

270

## Configuration Examples

271

272

### Loading and Inspecting Configuration

273

274

```python

275

from pathlib import Path

276

from poetry.core.pyproject.toml import PyProjectTOML

277

278

def inspect_pyproject(project_path: Path):

279

"""Inspect pyproject.toml configuration."""

280

281

pyproject_file = project_path / "pyproject.toml"

282

283

try:

284

pyproject = PyProjectTOML(pyproject_file)

285

286

# Check if it's a Poetry project

287

if not pyproject.is_poetry_project():

288

print("❌ Not a Poetry project")

289

return

290

291

print("βœ… Poetry project detected")

292

print(f"πŸ“ Config file: {pyproject.path}")

293

294

# Poetry configuration

295

config = pyproject.poetry_config

296

print(f"\nπŸ“¦ Package Information:")

297

print(f" Name: {config.get('name', 'Unknown')}")

298

print(f" Version: {config.get('version', 'Unknown')}")

299

print(f" Description: {config.get('description', 'No description')}")

300

301

# Authors

302

authors = config.get('authors', [])

303

if authors:

304

print(f" Authors: {', '.join(authors)}")

305

306

# Dependencies

307

dependencies = config.get('dependencies', {})

308

if dependencies:

309

print(f"\nπŸ”— Dependencies ({len(dependencies)}):")

310

for name, constraint in dependencies.items():

311

print(f" {name}: {constraint}")

312

313

# Development dependencies

314

group_deps = config.get('group', {})

315

if 'dev' in group_deps and 'dependencies' in group_deps['dev']:

316

dev_deps = group_deps['dev']['dependencies']

317

print(f"\nπŸ› οΈ Dev Dependencies ({len(dev_deps)}):")

318

for name, constraint in dev_deps.items():

319

print(f" {name}: {constraint}")

320

321

# Build system

322

build_sys = pyproject.build_system

323

print(f"\nπŸ—οΈ Build System:")

324

print(f" Backend: {build_sys.build_backend}")

325

print(f" Requires: {', '.join(build_sys.requires)}")

326

327

except Exception as e:

328

print(f"❌ Error reading configuration: {e}")

329

330

# Usage

331

inspect_pyproject(Path("./my-poetry-project"))

332

``` { .api }

333

334

### Creating Configuration Programmatically

335

336

```python

337

import toml

338

from pathlib import Path

339

from poetry.core.pyproject.toml import PyProjectTOML

340

341

def create_pyproject_config(project_dir: Path):

342

"""Create a new pyproject.toml configuration."""

343

344

config = {

345

"build-system": {

346

"requires": ["poetry-core"],

347

"build-backend": "poetry.core.masonry.api"

348

},

349

"tool": {

350

"poetry": {

351

"name": "my-new-package",

352

"version": "0.1.0",

353

"description": "A new Python package",

354

"authors": ["Your Name <you@example.com>"],

355

"readme": "README.md",

356

"packages": [{"include": "my_new_package"}],

357

"dependencies": {

358

"python": "^3.8"

359

},

360

"group": {

361

"dev": {

362

"dependencies": {

363

"pytest": "^7.0.0",

364

"black": "^22.0.0",

365

"isort": "^5.0.0"

366

}

367

}

368

}

369

}

370

}

371

}

372

373

# Write to file

374

pyproject_file = project_dir / "pyproject.toml"

375

with pyproject_file.open("w") as f:

376

toml.dump(config, f)

377

378

# Verify with PyProjectTOML

379

pyproject = PyProjectTOML(pyproject_file)

380

print(f"βœ… Created Poetry project: {pyproject.poetry_config['name']}")

381

382

return pyproject

383

384

# Usage

385

project = create_pyproject_config(Path("./new-project"))

386

``` { .api }

387

388

### Configuration Validation

389

390

```python

391

from poetry.core.factory import Factory

392

from poetry.core.pyproject.toml import PyProjectTOML

393

394

def validate_pyproject_config(pyproject_path: Path):

395

"""Validate Poetry configuration against schemas."""

396

397

try:

398

pyproject = PyProjectTOML(pyproject_path)

399

400

if not pyproject.is_poetry_project():

401

print("❌ Not a Poetry project")

402

return False

403

404

# Validate using Factory

405

validation_result = Factory.validate(pyproject.data)

406

407

# Report errors

408

if validation_result["errors"]:

409

print("❌ Configuration Errors:")

410

for error in validation_result["errors"]:

411

print(f" β€’ {error}")

412

413

# Report warnings

414

if validation_result["warnings"]:

415

print("⚠️ Configuration Warnings:")

416

for warning in validation_result["warnings"]:

417

print(f" β€’ {warning}")

418

419

# Overall status

420

is_valid = not validation_result["errors"]

421

if is_valid:

422

print("βœ… Configuration is valid")

423

else:

424

print("❌ Configuration has errors")

425

426

return is_valid

427

428

except Exception as e:

429

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

430

return False

431

432

# Usage

433

is_valid = validate_pyproject_config(Path("pyproject.toml"))

434

``` { .api }

435

436

### Working with Different Configuration Sections

437

438

```python

439

from poetry.core.pyproject.toml import PyProjectTOML

440

441

def explore_config_sections(pyproject_path: Path):

442

"""Explore different sections of pyproject.toml."""

443

444

pyproject = PyProjectTOML(pyproject_path)

445

data = pyproject.data

446

447

print("πŸ“‹ PyProject Configuration Sections:")

448

print("=" * 50)

449

450

# Build system section

451

if "build-system" in data:

452

build_sys = data["build-system"]

453

print("πŸ—οΈ [build-system]")

454

print(f" requires = {build_sys.get('requires', [])}")

455

print(f" build-backend = '{build_sys.get('build-backend', '')}'")

456

print()

457

458

# Project section (PEP 621)

459

if "project" in data:

460

project = data["project"]

461

print("πŸ“¦ [project]")

462

print(f" name = '{project.get('name', '')}'")

463

print(f" version = '{project.get('version', '')}'")

464

print(f" description = '{project.get('description', '')}'")

465

if "dependencies" in project:

466

print(f" dependencies = {project['dependencies']}")

467

print()

468

469

# Tool sections

470

if "tool" in data:

471

tool = data["tool"]

472

print("πŸ”§ [tool] sections:")

473

474

for tool_name in tool.keys():

475

print(f" β€’ tool.{tool_name}")

476

477

# Poetry-specific configuration

478

if "poetry" in tool:

479

poetry_config = tool["poetry"]

480

print(f"\n🎭 [tool.poetry]")

481

print(f" name = '{poetry_config.get('name', '')}'")

482

print(f" version = '{poetry_config.get('version', '')}'")

483

484

# Dependencies

485

if "dependencies" in poetry_config:

486

deps = poetry_config["dependencies"]

487

print(f" dependencies = {dict(list(deps.items())[:3])}...")

488

489

# Dependency groups

490

if "group" in poetry_config:

491

groups = poetry_config["group"]

492

print(f" dependency groups: {list(groups.keys())}")

493

494

# Scripts and entry points

495

if "scripts" in poetry_config:

496

scripts = poetry_config["scripts"]

497

print(f" scripts: {list(scripts.keys())}")

498

499

print("\n" + "=" * 50)

500

501

# Usage

502

explore_config_sections(Path("pyproject.toml"))

503

``` { .api }

504

505

### Dynamic Configuration Updates

506

507

```python

508

from poetry.core.pyproject.toml import PyProjectTOML

509

510

def update_pyproject_config(pyproject_path: Path):

511

"""Demonstrate dynamic configuration updates."""

512

513

pyproject = PyProjectTOML(pyproject_path)

514

515

# Get current data

516

data = pyproject.data

517

poetry_config = pyproject.poetry_config

518

519

print(f"Current version: {poetry_config.get('version')}")

520

521

# Update version

522

new_version = "2.0.0"

523

if "tool" not in data:

524

data["tool"] = {}

525

if "poetry" not in data["tool"]:

526

data["tool"]["poetry"] = {}

527

528

data["tool"]["poetry"]["version"] = new_version

529

530

# Add new dependency

531

if "dependencies" not in data["tool"]["poetry"]:

532

data["tool"]["poetry"]["dependencies"] = {}

533

534

data["tool"]["poetry"]["dependencies"]["requests"] = "^2.28.0"

535

536

# Add development dependency

537

if "group" not in data["tool"]["poetry"]:

538

data["tool"]["poetry"]["group"] = {}

539

if "dev" not in data["tool"]["poetry"]["group"]:

540

data["tool"]["poetry"]["group"]["dev"] = {"dependencies": {}}

541

542

data["tool"]["poetry"]["group"]["dev"]["dependencies"]["pytest"] = "^7.0.0"

543

544

# Update metadata

545

data["tool"]["poetry"]["description"] = "Updated package description"

546

data["tool"]["poetry"]["keywords"] = ["python", "package", "updated"]

547

548

print(f"βœ… Updated configuration:")

549

print(f" Version: {data['tool']['poetry']['version']}")

550

print(f" Description: {data['tool']['poetry']['description']}")

551

print(f" New dependencies: {list(data['tool']['poetry']['dependencies'].keys())}")

552

553

# Save changes (uncomment to actually save)

554

# pyproject.save()

555

# print("πŸ’Ύ Changes saved to pyproject.toml")

556

557

# Usage

558

update_pyproject_config(Path("pyproject.toml"))

559

``` { .api }

560

561

## Error Handling

562

563

### Configuration Error Handling

564

565

```python

566

from poetry.core.pyproject.toml import PyProjectTOML

567

from poetry.core.pyproject.exceptions import PyProjectError

568

569

def safe_config_loading(pyproject_path: Path):

570

"""Safely load configuration with comprehensive error handling."""

571

572

try:

573

# Check if file exists

574

if not pyproject_path.exists():

575

print(f"❌ File not found: {pyproject_path}")

576

return None

577

578

pyproject = PyProjectTOML(pyproject_path)

579

580

# Try to access data (triggers parsing)

581

try:

582

data = pyproject.data

583

print(f"βœ… Successfully loaded TOML data")

584

585

except PyProjectError as e:

586

print(f"❌ TOML parsing error: {e}")

587

return None

588

589

# Try to access Poetry config

590

try:

591

poetry_config = pyproject.poetry_config

592

print(f"βœ… Found Poetry configuration")

593

594

except PyProjectError as e:

595

print(f"⚠️ No Poetry configuration: {e}")

596

# Could still be a valid project with [project] section

597

598

# Try to access build system

599

try:

600

build_sys = pyproject.build_system

601

print(f"βœ… Build system: {build_sys.build_backend}")

602

603

except Exception as e:

604

print(f"⚠️ Build system error: {e}")

605

606

return pyproject

607

608

except Exception as e:

609

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

610

return None

611

612

def validate_required_fields(pyproject: PyProjectTOML):

613

"""Validate required configuration fields."""

614

615

try:

616

config = pyproject.poetry_config

617

618

# Required fields

619

required_fields = ["name", "version"]

620

missing_fields = []

621

622

for field in required_fields:

623

if field not in config:

624

missing_fields.append(field)

625

626

if missing_fields:

627

print(f"❌ Missing required fields: {missing_fields}")

628

return False

629

630

# Validate field formats

631

name = config["name"]

632

version = config["version"]

633

634

if not isinstance(name, str) or not name.strip():

635

print(f"❌ Invalid name: '{name}'")

636

return False

637

638

if not isinstance(version, str) or not version.strip():

639

print(f"❌ Invalid version: '{version}'")

640

return False

641

642

print(f"βœ… Required fields valid: {name} v{version}")

643

return True

644

645

except PyProjectError:

646

print("❌ Cannot validate - no Poetry configuration")

647

return False

648

649

# Usage

650

pyproject = safe_config_loading(Path("pyproject.toml"))

651

if pyproject:

652

validate_required_fields(pyproject)

653

``` { .api }

654

655

## Type Definitions

656

657

```python

658

from typing import Any, Dict

659

from pathlib import Path

660

661

# Configuration types

662

ConfigDict = Dict[str, Any]

663

TomlData = Dict[str, Any]

664

PoetryConfig = Dict[str, Any]

665

666

# Build system types

667

BuildBackend = str

668

BuildRequirements = List[str]

669

``` { .api }