or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-backend.mdbuilders.mdcli.mdindex.mdmetadata.mdplugins.mdversion.md

metadata.mddocs/

0

# Metadata System

1

2

Project metadata parsing, validation, and core metadata generation following Python packaging standards. The metadata system handles project configuration, dependency management, and metadata validation.

3

4

## Capabilities

5

6

### Project Metadata

7

8

Core project metadata container that parses and validates project configuration.

9

10

```python { .api }

11

class ProjectMetadata(Generic[PluginManagerBound]):

12

def __init__(

13

self,

14

root: str,

15

plugin_manager: PluginManager | None = None,

16

config: dict | None = None

17

):

18

"""

19

Initialize project metadata.

20

21

Args:

22

root: Project root directory path

23

plugin_manager: Optional plugin manager instance

24

config: Optional metadata configuration override

25

"""

26

27

@property

28

def name(self) -> str:

29

"""Project name."""

30

31

@property

32

def version(self) -> str:

33

"""Project version."""

34

35

@property

36

def description(self) -> str:

37

"""Project description."""

38

39

@property

40

def readme(self) -> str | None:

41

"""Project readme content."""

42

43

@property

44

def authors(self) -> list[dict[str, str]]:

45

"""Project authors list."""

46

47

@property

48

def maintainers(self) -> list[dict[str, str]]:

49

"""Project maintainers list."""

50

51

@property

52

def license(self) -> str | None:

53

"""Project license."""

54

55

@property

56

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

57

"""Project keywords."""

58

59

@property

60

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

61

"""Project classifiers."""

62

63

@property

64

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

65

"""Project URLs."""

66

67

@property

68

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

69

"""Project runtime dependencies."""

70

71

@property

72

def optional_dependencies(self) -> dict[str, list[str]]:

73

"""Project optional dependencies (extras)."""

74

75

@property

76

def requires_python(self) -> str | None:

77

"""Required Python version specification."""

78

79

@property

80

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

81

"""List of dynamic metadata fields."""

82

```

83

84

### Build Metadata

85

86

Build-time metadata configuration and validation.

87

88

```python { .api }

89

class BuildMetadata:

90

def __init__(self, root: str, config: dict):

91

"""

92

Initialize build metadata.

93

94

Args:

95

root: Project root directory

96

config: Build metadata configuration

97

"""

98

99

@property

100

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

101

"""Build-time dependencies."""

102

103

@property

104

def build_backend(self) -> str:

105

"""Build backend specification."""

106

107

@property

108

def backend_path(self) -> list[str] | None:

109

"""Backend path specification."""

110

```

111

112

### Core Metadata

113

114

Core metadata following Python packaging standards (PEP 314, PEP 566, etc.).

115

116

```python { .api }

117

class CoreMetadata:

118

def __init__(self, metadata: ProjectMetadata, config: dict):

119

"""

120

Initialize core metadata.

121

122

Args:

123

metadata: Project metadata instance

124

config: Core metadata configuration

125

"""

126

127

def as_string(self) -> str:

128

"""

129

Generate core metadata as string.

130

131

Returns:

132

str: Core metadata in email header format

133

"""

134

135

def as_bytes(self) -> bytes:

136

"""

137

Generate core metadata as bytes.

138

139

Returns:

140

bytes: Core metadata in email header format

141

"""

142

```

143

144

### Hatch-Specific Metadata

145

146

Extended metadata configuration specific to Hatch projects.

147

148

```python { .api }

149

class HatchMetadata(Generic[PluginManagerBound]):

150

def __init__(

151

self,

152

root: str,

153

config: dict,

154

plugin_manager: PluginManager

155

):

156

"""

157

Initialize Hatch metadata.

158

159

Args:

160

root: Project root directory

161

config: Hatch metadata configuration

162

plugin_manager: Plugin manager instance

163

"""

164

165

@property

166

def version_config(self) -> HatchVersionConfig:

167

"""Version configuration."""

168

169

@property

170

def metadata_settings(self) -> HatchMetadataSettings:

171

"""Metadata settings."""

172

173

@property

174

def build_config(self) -> dict:

175

"""Build configuration."""

176

177

class HatchVersionConfig(Generic[PluginManagerBound]):

178

def __init__(

179

self,

180

root: str,

181

config: dict,

182

plugin_manager: PluginManager

183

):

184

"""

185

Initialize version configuration.

186

187

Args:

188

root: Project root directory

189

config: Version configuration

190

plugin_manager: Plugin manager instance

191

"""

192

193

@property

194

def source(self) -> str:

195

"""Version source plugin name."""

196

197

@property

198

def scheme(self) -> str:

199

"""Version scheme plugin name."""

200

201

@property

202

def source_config(self) -> dict:

203

"""Version source configuration."""

204

205

@property

206

def scheme_config(self) -> dict:

207

"""Version scheme configuration."""

208

209

class HatchMetadataSettings(Generic[PluginManagerBound]):

210

def __init__(

211

self,

212

root: str,

213

config: dict,

214

plugin_manager: PluginManager

215

):

216

"""

217

Initialize metadata settings.

218

219

Args:

220

root: Project root directory

221

config: Metadata settings configuration

222

plugin_manager: Plugin manager instance

223

"""

224

225

@property

226

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

227

"""Metadata hook configurations."""

228

```

229

230

## Metadata Parsing

231

232

### Configuration Sources

233

234

Hatchling reads metadata from multiple sources with precedence:

235

236

1. `pyproject.toml` - Primary configuration file

237

2. `setup.py` - Legacy setup script (limited support)

238

3. `setup.cfg` - Legacy configuration file (limited support)

239

240

### pyproject.toml Structure

241

242

```toml

243

[project]

244

name = "my-package"

245

version = "1.0.0"

246

description = "My package description"

247

readme = "README.md"

248

license = {text = "MIT"}

249

authors = [

250

{name = "Author Name", email = "author@example.com"}

251

]

252

dependencies = [

253

"requests>=2.25.0",

254

"click>=8.0.0"

255

]

256

optional-dependencies = {

257

dev = ["pytest", "black"],

258

docs = ["sphinx", "myst-parser"]

259

}

260

requires-python = ">=3.8"

261

keywords = ["example", "package"]

262

classifiers = [

263

"Development Status :: 4 - Beta",

264

"Programming Language :: Python :: 3"

265

]

266

267

[project.urls]

268

Homepage = "https://example.com"

269

Documentation = "https://example.com/docs"

270

Repository = "https://github.com/user/repo"

271

272

[project.scripts]

273

my-cli = "my_package.cli:main"

274

275

[project.gui-scripts]

276

my-gui = "my_package.gui:main"

277

278

[project.entry-points."my.group"]

279

plugin = "my_package.plugin:MyPlugin"

280

281

[build-system]

282

requires = ["hatchling"]

283

build-backend = "hatchling.build"

284

285

[tool.hatch.version]

286

source = "code"

287

path = "src/my_package/__about__.py"

288

289

[tool.hatch.build]

290

include = ["src/**/*.py"]

291

exclude = ["tests/"]

292

293

[tool.hatch.metadata]

294

allow-direct-references = true

295

```

296

297

## Metadata Validation

298

299

### Core Metadata Constructors

300

301

```python { .api }

302

def get_core_metadata_constructors() -> dict[str, Callable]:

303

"""

304

Get available core metadata constructor functions.

305

306

Returns:

307

dict: Mapping of version to constructor function

308

"""

309

```

310

311

### Dynamic Metadata

312

313

Some metadata fields can be marked as dynamic and resolved at build time:

314

315

```python

316

# Dynamic fields are resolved through plugins or build hooks

317

dynamic = ["version", "description", "dependencies"]

318

```

319

320

### Metadata Validation Rules

321

322

- Project name must be valid Python package name

323

- Version must follow PEP 440 specification

324

- Dependencies must use valid requirement specifications

325

- Classifiers must be from the official classifier list

326

- URLs must be valid URIs

327

328

## Usage Examples

329

330

### Basic Metadata Loading

331

332

```python

333

import os

334

from hatchling.metadata.core import ProjectMetadata

335

from hatchling.plugin.manager import PluginManager

336

337

# Load project metadata

338

root = os.getcwd()

339

metadata = ProjectMetadata(root)

340

341

# Access metadata properties

342

print(f"Name: {metadata.name}")

343

print(f"Version: {metadata.version}")

344

print(f"Description: {metadata.description}")

345

print(f"Dependencies: {metadata.dependencies}")

346

print(f"Optional dependencies: {metadata.optional_dependencies}")

347

```

348

349

### With Plugin Manager

350

351

```python

352

# Create plugin manager first

353

plugin_manager = PluginManager(metadata)

354

355

# Metadata with plugin support

356

metadata = ProjectMetadata(root, plugin_manager=plugin_manager)

357

358

# Access dynamic metadata resolved through plugins

359

print(f"Dynamic version: {metadata.version}")

360

```

361

362

### Core Metadata Generation

363

364

```python

365

from hatchling.metadata.core import CoreMetadata

366

367

# Generate core metadata

368

core_metadata = CoreMetadata(metadata, config={})

369

metadata_string = core_metadata.as_string()

370

371

# Write to METADATA file

372

with open("PKG-INFO", "w") as f:

373

f.write(metadata_string)

374

```

375

376

### Custom Metadata Configuration

377

378

```python

379

# Override metadata configuration

380

custom_config = {

381

"name": "custom-name",

382

"version": "2.0.0",

383

"dependencies": ["requests", "click"]

384

}

385

386

metadata = ProjectMetadata(root, config=custom_config)

387

```

388

389

### Accessing Hatch-Specific Metadata

390

391

```python

392

from hatchling.metadata.core import HatchMetadata

393

394

# Load Hatch-specific metadata

395

hatch_metadata = HatchMetadata(root, config, plugin_manager)

396

397

# Access version configuration

398

version_config = hatch_metadata.version_config

399

print(f"Version source: {version_config.source}")

400

print(f"Version scheme: {version_config.scheme}")

401

402

# Access metadata settings

403

metadata_settings = hatch_metadata.metadata_settings

404

print(f"Metadata hooks: {metadata_settings.hooks}")

405

```

406

407

## Error Handling

408

409

Common metadata errors and exceptions:

410

411

- `ValueError`: Invalid metadata values or configurations

412

- `FileNotFoundError`: Missing configuration files

413

- `KeyError`: Missing required metadata fields

414

- `TypeError`: Incorrect metadata field types

415

416

## Metadata Hooks

417

418

Custom metadata hooks can modify metadata at build time:

419

420

```python

421

from hatchling.metadata.plugin.interface import MetadataHookInterface

422

423

class CustomMetadataHook(MetadataHookInterface):

424

def update(self, metadata):

425

# Custom metadata modifications

426

metadata["custom_field"] = "custom_value"

427

```

428

429

## Integration with Build System

430

431

The metadata system integrates closely with the build system:

432

433

1. **Builder Configuration**: Metadata informs builder settings and dependencies

434

2. **Version Management**: Dynamic version resolution through version sources

435

3. **Dependency Resolution**: Build and runtime dependency specifications

436

4. **Distribution Metadata**: Core metadata generation for wheels and sdists

437

438

This metadata system provides the foundation for hatchling's standards-compliant packaging functionality while maintaining flexibility through its plugin architecture.