or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-integration.mdbuiltin-methods.mdcore-operations.mddata-models.mdexceptions.mdindex.mdmethod-system.mdversioningit-class.md

build-integration.mddocs/

0

# Build Integration

1

2

Integration with build systems including setuptools command classes, onbuild hooks, and file providers for inserting version information into build artifacts. This system allows versioningit to modify files during the build process.

3

4

## Capabilities

5

6

### Setuptools Command Classes

7

8

Custom setuptools command classes that run the onbuild step during sdist and wheel building.

9

10

```python { .api }

11

def get_cmdclasses(

12

bases: Optional[dict[str, type[Command]]] = None

13

) -> dict[str, type[Command]]:

14

"""

15

Return a dict of custom setuptools Command classes that run the onbuild

16

step when building an sdist or wheel.

17

18

Parameters:

19

- bases: Optional dict of alternative base classes for customization

20

21

Returns:

22

dict[str, type[Command]]: Dict containing "sdist" and "build_py" command classes

23

"""

24

```

25

26

### Onbuild Execution

27

28

Run the onbuild step for inserting version information into build artifacts.

29

30

```python { .api }

31

def run_onbuild(

32

*,

33

build_dir: str | Path,

34

is_source: bool,

35

template_fields: dict[str, Any],

36

project_dir: str | Path = os.curdir,

37

config: Optional[dict] = None,

38

) -> None:

39

"""

40

Run the onbuild step for the given setuptools project.

41

42

Parameters:

43

- build_dir: Directory containing the in-progress build

44

- is_source: True for sdist (preserves source paths), False for wheel (uses install paths)

45

- template_fields: Dict of fields for template substitution

46

- project_dir: Path to project root (default: current directory)

47

- config: Configuration dict or None to read from configuration file

48

49

Raises:

50

- NoConfigFileError: if config is None and no configuration file exists

51

- NoConfigSectionError: if configuration file has no versioningit section

52

- ConfigError: if configuration values are invalid

53

- MethodError: if a method returns wrong type

54

"""

55

56

def get_template_fields_from_distribution(

57

dist: Distribution,

58

) -> Optional[dict[str, Any]]:

59

"""

60

Extract template fields stashed on setuptools Distribution by versioningit's

61

setuptools hook, for passing to the onbuild step.

62

63

Parameters:

64

- dist: setuptools Distribution object

65

66

Returns:

67

Optional[dict[str, Any]]: Template fields or None if building from sdist

68

"""

69

```

70

71

### File Provider System

72

73

Abstract interfaces for accessing and modifying files during the build process.

74

75

```python { .api }

76

class OnbuildFileProvider(ABC):

77

"""

78

Abstract base class for accessing files that are about to be included

79

in an sdist or wheel currently being built.

80

"""

81

82

@abstractmethod

83

def get_file(

84

self, source_path: str | PurePath, install_path: str | PurePath, is_source: bool

85

) -> OnbuildFile:

86

"""

87

Get an object for reading & writing a file in the project being built.

88

89

Parameters:

90

- source_path: Path relative to project root

91

- install_path: Path when installed (for wheels)

92

- is_source: True for sdist, False for wheel

93

94

Returns:

95

OnbuildFile: File access object

96

"""

97

98

class OnbuildFile(ABC):

99

"""

100

Abstract base class for opening a file in a project currently being built.

101

"""

102

103

@abstractmethod

104

def open(

105

self,

106

mode: str = "r",

107

encoding: str | None = None,

108

errors: str | None = None,

109

newline: str | None = None,

110

) -> IO:

111

"""

112

Open the associated file. Mode must be "r", "w", "a", "rb", "br",

113

"wb", "bw", "ab", or "ba".

114

"""

115

```

116

117

### Setuptools File Provider

118

119

Implementation for setuptools builds that operates on temporary build directories.

120

121

```python { .api }

122

@dataclass

123

class SetuptoolsFileProvider(OnbuildFileProvider):

124

"""

125

OnbuildFileProvider implementation for setuptools builds.

126

Operates directly on the temporary directory containing build files.

127

"""

128

129

build_dir: Path

130

"""The setuptools-managed temporary directory containing build files."""

131

132

modified: set[PurePath]

133

"""Set of file paths that have been opened for writing or appending."""

134

135

def get_file(

136

self, source_path: str | PurePath, install_path: str | PurePath, is_source: bool

137

) -> SetuptoolsOnbuildFile: ...

138

139

@dataclass

140

class SetuptoolsOnbuildFile(OnbuildFile):

141

"""File access implementation for setuptools builds."""

142

143

provider: SetuptoolsFileProvider

144

source_path: PurePath

145

install_path: PurePath

146

is_source: bool

147

```

148

149

### Hatch File Provider

150

151

Implementation for Hatch builds that uses temporary directories and forced inclusion.

152

153

```python { .api }

154

@dataclass

155

class HatchFileProvider(OnbuildFileProvider):

156

"""

157

OnbuildFileProvider implementation for Hatch builds.

158

Creates modified files in temporary directory for forced inclusion.

159

"""

160

161

src_dir: Path

162

"""The root of the project directory."""

163

164

tmp_dir: Path

165

"""Temporary directory for creating modified files."""

166

167

modified: set[PurePath]

168

"""Set of file paths created under the temporary directory."""

169

170

def get_file(

171

self, source_path: str | PurePath, install_path: str | PurePath, is_source: bool

172

) -> HatchOnbuildFile: ...

173

174

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

175

"""

176

Get mapping of temporary files to their target paths for forced inclusion.

177

"""

178

179

@dataclass

180

class HatchOnbuildFile(OnbuildFile):

181

"""File access implementation for Hatch builds."""

182

183

provider: HatchFileProvider

184

source_path: PurePath

185

install_path: PurePath

186

is_source: bool

187

```

188

189

## Usage Examples

190

191

### Setuptools Integration

192

193

```python

194

# setup.py

195

from setuptools import setup

196

from versioningit import get_cmdclasses

197

198

setup(

199

name="mypackage",

200

cmdclass=get_cmdclasses(),

201

# ... other setup parameters

202

)

203

```

204

205

```python

206

# pyproject.toml

207

[build-system]

208

requires = ["setuptools", "versioningit"]

209

build-backend = "setuptools.build_meta"

210

211

[project]

212

dynamic = ["version"]

213

214

[tool.setuptools.dynamic]

215

version = {attr = "versioningit.get_version"}

216

217

[tool.versioningit]

218

# ... configuration

219

220

[tool.versioningit.onbuild]

221

method = "replace-version"

222

source-file = "src/mypackage/__init__.py"

223

build-file = "mypackage/__init__.py"

224

```

225

226

### Custom Command Classes

227

228

```python

229

from setuptools import setup

230

from setuptools.command.build_py import build_py

231

from versioningit import get_cmdclasses

232

233

class CustomBuildPy(build_py):

234

def run(self):

235

# Custom build logic

236

super().run()

237

238

# Use custom base classes

239

cmdclasses = get_cmdclasses({"build_py": CustomBuildPy})

240

241

setup(

242

name="mypackage",

243

cmdclass=cmdclasses,

244

)

245

```

246

247

### Manual Onbuild Execution

248

249

```python

250

from pathlib import Path

251

from versioningit import run_onbuild, get_template_fields_from_distribution

252

253

def custom_build_command(self):

254

# Get template fields from distribution

255

template_fields = get_template_fields_from_distribution(self.distribution)

256

257

if template_fields is not None:

258

# Run onbuild step

259

run_onbuild(

260

build_dir=self.build_lib,

261

is_source=False, # Building wheel

262

template_fields=template_fields,

263

project_dir=Path().resolve()

264

)

265

```

266

267

### Custom File Provider

268

269

```python

270

from versioningit.onbuild import OnbuildFileProvider, OnbuildFile

271

from pathlib import Path

272

273

class CustomFileProvider(OnbuildFileProvider):

274

def __init__(self, build_dir: Path):

275

self.build_dir = build_dir

276

277

def get_file(self, source_path, install_path, is_source):

278

return CustomOnbuildFile(

279

self, source_path, install_path, is_source

280

)

281

282

class CustomOnbuildFile(OnbuildFile):

283

def __init__(self, provider, source_path, install_path, is_source):

284

self.provider = provider

285

self.source_path = source_path

286

self.install_path = install_path

287

self.is_source = is_source

288

289

def open(self, mode="r", encoding=None, errors=None, newline=None):

290

path = self.source_path if self.is_source else self.install_path

291

full_path = self.provider.build_dir / path

292

return full_path.open(mode=mode, encoding=encoding, errors=errors, newline=newline)

293

```

294

295

### Onbuild Method Implementation

296

297

```python

298

def custom_onbuild_method(

299

*,

300

file_provider: OnbuildFileProvider,

301

is_source: bool,

302

template_fields: dict[str, Any],

303

params: dict[str, Any],

304

) -> None:

305

"""Custom onbuild method example."""

306

307

source_file = params["source-file"]

308

build_file = params["build-file"]

309

310

# Get file handle

311

file = file_provider.get_file(source_file, build_file, is_source)

312

313

# Read current content

314

with file.open("r", encoding="utf-8") as fp:

315

content = fp.read()

316

317

# Modify content with template fields

318

new_content = content.format(**template_fields)

319

320

# Write back

321

with file.open("w", encoding="utf-8") as fp:

322

fp.write(new_content)

323

```

324

325

### Template Fields Usage

326

327

```python

328

from versioningit import Versioningit

329

330

vgit = Versioningit.from_project_dir()

331

report = vgit.run()

332

333

# Template fields available for onbuild

334

fields = report.template_fields

335

336

# Common substitutions in onbuild

337

version_line = '__version__ = "{version}"'.format(**fields)

338

build_info = """

339

__version__ = "{version}"

340

__version_tuple__ = {version_tuple}

341

__build_date__ = "{build_date}"

342

__git_revision__ = "{rev}"

343

""".format(**fields)

344

```

345

346

### Error Handling in Build Integration

347

348

```python

349

from versioningit import get_cmdclasses, run_onbuild

350

from versioningit.errors import ConfigError, MethodError

351

352

try:

353

cmdclasses = get_cmdclasses()

354

except Exception as e:

355

print(f"Failed to get command classes: {e}")

356

cmdclasses = {}

357

358

# In build command

359

try:

360

run_onbuild(

361

build_dir=build_dir,

362

is_source=False,

363

template_fields=template_fields

364

)

365

except ConfigError as e:

366

print(f"Configuration error in onbuild: {e}")

367

except MethodError as e:

368

print(f"Method error in onbuild: {e}")

369

```