0
# Build System Integration
1
2
setuptools-scm provides seamless integration with setuptools, modern build systems, and packaging tools through entry points, hooks, and configuration. This enables automatic version inference and SCM-managed file inclusion in Python packages.
3
4
```python
5
from pathlib import Path
6
from typing import Any, Sequence
7
from os import PathLike
8
9
# Type Aliases (from setuptools_scm)
10
PathT = PathLike[str] | str
11
```
12
13
## Capabilities
14
15
### File Discovery
16
17
Functions for finding and listing SCM-managed files for inclusion in source distributions.
18
19
```python { .api }
20
def find_files(path: PathT = "") -> list[str]:
21
"""
22
Find SCM-managed files for setuptools integration.
23
24
Parameters:
25
- path: Root path to search for files (default: current directory)
26
27
Returns:
28
List of file paths managed by SCM
29
"""
30
```
31
32
### Version File Generation
33
34
Functions for writing version information to files during build or development.
35
36
```python { .api }
37
def dump_version(
38
root: PathT,
39
version: str,
40
write_to: PathT,
41
template: str | None = None,
42
scm_version: ScmVersion | None = None
43
) -> None:
44
"""
45
Write version information to a file (soft deprecated).
46
47
Parameters:
48
- root: Repository root directory
49
- version: Version string to write
50
- write_to: Path to write version file to
51
- template: Template for version file content (uses default if None)
52
- scm_version: ScmVersion object for additional metadata
53
"""
54
55
def write_version_to_path(
56
target: Path,
57
template: str | None = None,
58
version: str,
59
scm_version: ScmVersion | None = None
60
) -> None:
61
"""
62
Write version to specific path with template.
63
64
Parameters:
65
- target: Target file path
66
- template: Template for file content
67
- version: Version string
68
- scm_version: ScmVersion object for metadata
69
"""
70
```
71
72
### SCM File Finders
73
74
Specialized file finders for different SCM systems, accessible via entry points.
75
76
```python { .api }
77
# Git file finders
78
def git_find_files(path: str) -> list[str]:
79
"""Find files managed by Git"""
80
81
def git_archive_find_files(path: str) -> list[str]:
82
"""Find files from Git archive metadata"""
83
84
# Mercurial file finders
85
def hg_find_files(path: str) -> list[str]:
86
"""Find files managed by Mercurial"""
87
88
def hg_archive_find_files(path: str) -> list[str]:
89
"""Find files from Mercurial archive metadata"""
90
```
91
92
### Setuptools Hooks
93
94
Integration points for setuptools to automatically infer versions and find files.
95
96
```python { .api }
97
def version_keyword(dist, keyword, value):
98
"""Handle use_scm_version keyword in setup.py (legacy)"""
99
100
def infer_version(dist):
101
"""Automatically infer version for setuptools during build"""
102
```
103
104
### Utility Functions
105
106
Helper functions for parsing and processing integration data.
107
108
```python { .api }
109
def data_from_mime(path: str, content: str | None = None) -> dict[str, str]:
110
"""
111
Return mapping from MIME/pseudo-MIME content.
112
113
Parameters:
114
- path: File path
115
- content: File content (reads from path if None)
116
117
Returns:
118
Dictionary mapping parsed from MIME-like content
119
"""
120
```
121
122
## Entry Point System
123
124
setuptools-scm uses Python's entry point system to provide extensible plugin architecture:
125
126
### SCM Parsers
127
128
```python
129
# Entry point group: "setuptools_scm.parse_scm"
130
".git" = "setuptools_scm.git:parse"
131
".hg" = "setuptools_scm.hg:parse"
132
133
# Entry point group: "setuptools_scm.parse_scm_fallback"
134
".git_archival.txt" = "setuptools_scm.git:parse_archival"
135
".hg_archival.txt" = "setuptools_scm.hg:parse_archival"
136
"PKG-INFO" = "setuptools_scm.fallbacks:parse_pkginfo"
137
"pyproject.toml" = "setuptools_scm.fallbacks:fallback_version"
138
"setup.py" = "setuptools_scm.fallbacks:fallback_version"
139
```
140
141
### File Finders
142
143
```python
144
# Entry point group: "setuptools_scm.files_command"
145
".git" = "setuptools_scm._file_finders.git:git_find_files"
146
".hg" = "setuptools_scm._file_finders.hg:hg_find_files"
147
148
# Entry point group: "setuptools_scm.files_command_fallback"
149
".git_archival.txt" = "setuptools_scm._file_finders.git:git_archive_find_files"
150
".hg_archival.txt" = "setuptools_scm._file_finders.hg:hg_archive_find_files"
151
```
152
153
### Setuptools Integration
154
155
```python
156
# Entry point group: "distutils.setup_keywords"
157
"use_scm_version" = "setuptools_scm._integration.setuptools:version_keyword"
158
159
# Entry point group: "setuptools.file_finders"
160
"setuptools_scm" = "setuptools_scm._file_finders:find_files"
161
162
# Entry point group: "setuptools.finalize_distribution_options"
163
"setuptools_scm" = "setuptools_scm._integration.setuptools:infer_version"
164
```
165
166
## Usage Examples
167
168
### pyproject.toml Configuration
169
170
Modern Python packaging with PEP 518/621 support:
171
172
```toml
173
[build-system]
174
requires = ["setuptools>=64", "setuptools-scm>=8"]
175
build-backend = "setuptools.build_meta"
176
177
[project]
178
name = "mypackage"
179
dynamic = ["version"]
180
dependencies = ["requests", "click"]
181
182
[tool.setuptools_scm]
183
version_file = "src/mypackage/_version.py"
184
version_file_template = '''
185
# File generated by setuptools-scm
186
__version__ = "{version}"
187
__version_tuple__ = {version_tuple}
188
'''
189
```
190
191
### Version File Generation
192
193
```python
194
# Configuration with version file
195
from setuptools_scm import get_version
196
197
version = get_version(
198
write_to="src/mypackage/_version.py",
199
write_to_template='''
200
__version__ = "{version}"
201
__version_tuple__ = {version_tuple}
202
'''
203
)
204
205
# The generated file will contain:
206
# __version__ = "1.2.3.dev4+g1234567.d20231201"
207
# __version_tuple__ = ('1', '2', '3', 'dev4', 'g1234567', 'd20231201')
208
```
209
210
### Legacy setup.py Integration
211
212
```python
213
# setup.py (legacy approach)
214
from setuptools import setup
215
216
setup(
217
name="mypackage",
218
use_scm_version=True,
219
setup_requires=["setuptools-scm"],
220
# ... other setup parameters
221
)
222
223
# With custom configuration
224
setup(
225
name="mypackage",
226
use_scm_version={
227
"version_scheme": "python-simplified-semver",
228
"local_scheme": "no-local-version",
229
"write_to": "mypackage/_version.py"
230
},
231
setup_requires=["setuptools-scm"],
232
)
233
```
234
235
### Build Tool Integration
236
237
```bash
238
# Using build (PEP 517)
239
python -m build
240
241
# Using pip
242
pip install -e .
243
244
# Using setuptools directly
245
python setup.py sdist bdist_wheel
246
```
247
248
All these tools automatically pick up setuptools-scm configuration and use it for version determination.
249
250
### File Finder Usage
251
252
```python
253
from setuptools_scm._file_finders import find_files
254
255
# Find all SCM-managed files
256
files = find_files(".")
257
print("SCM-managed files:", files)
258
259
# This is used internally by setuptools to include files in sdist
260
```
261
262
### Custom Entry Points
263
264
You can extend setuptools-scm with custom entry points:
265
266
```toml
267
# In your package's pyproject.toml
268
[project.entry-points."setuptools_scm.version_scheme"]
269
"my-custom-scheme" = "mypackage.scm:my_version_scheme"
270
271
[project.entry-points."setuptools_scm.local_scheme"]
272
"my-local-scheme" = "mypackage.scm:my_local_scheme"
273
274
[project.entry-points."setuptools_scm.parse_scm"]
275
".myvcm" = "mypackage.scm:parse_my_vcm"
276
```
277
278
```python
279
# mypackage/scm.py
280
def my_version_scheme(version):
281
"""Custom version scheme"""
282
return f"custom-{version.tag}"
283
284
def my_local_scheme(version):
285
"""Custom local scheme"""
286
return f"+build{version.distance}" if version.distance else ""
287
288
def parse_my_vcm(root, config):
289
"""Custom VCS parser"""
290
# Implementation for custom version control system
291
pass
292
```
293
294
### CI/CD Integration Examples
295
296
#### GitHub Actions
297
298
```yaml
299
name: Build and Release
300
on: [push, pull_request]
301
302
jobs:
303
build:
304
runs-on: ubuntu-latest
305
steps:
306
- uses: actions/checkout@v3
307
with:
308
fetch-depth: 0 # Required for setuptools-scm
309
310
- name: Set up Python
311
uses: actions/setup-python@v4
312
with:
313
python-version: "3.11"
314
315
- name: Install dependencies
316
run: |
317
pip install build setuptools-scm
318
319
- name: Get version
320
run: |
321
VERSION=$(python -m setuptools_scm)
322
echo "VERSION=$VERSION" >> $GITHUB_ENV
323
echo "Building version: $VERSION"
324
325
- name: Build package
326
run: python -m build
327
```
328
329
#### GitLab CI
330
331
```yaml
332
build:
333
stage: build
334
script:
335
- pip install build setuptools-scm
336
- VERSION=$(python -m setuptools_scm --strip-dev)
337
- echo "Building version $VERSION"
338
- python -m build
339
artifacts:
340
paths:
341
- dist/
342
```
343
344
### Docker Integration
345
346
```dockerfile
347
FROM python:3.11-slim
348
349
# Install git for setuptools-scm
350
RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
351
352
COPY . /app
353
WORKDIR /app
354
355
# setuptools-scm will automatically determine version
356
RUN pip install -e .
357
358
# Version information available at runtime
359
RUN python -c "import mypackage; print(mypackage.__version__)"
360
```
361
362
### Runtime Version Access
363
364
```python
365
# In your package's __init__.py
366
from importlib.metadata import version, PackageNotFoundError
367
368
try:
369
__version__ = version("mypackage")
370
except PackageNotFoundError:
371
# Development installation
372
from setuptools_scm import get_version
373
__version__ = get_version(root="..")
374
```
375
376
Or with generated version file:
377
378
```python
379
# In your package's __init__.py
380
try:
381
from ._version import __version__
382
except ImportError:
383
# Fallback for development
384
from setuptools_scm import get_version
385
__version__ = get_version(root="..")
386
```
387
388
## Template Formats
389
390
### Python Version File Template
391
392
```python
393
# Default template for .py files
394
TEMPLATE_PY = '''
395
# file generated by setuptools-scm
396
# don't change, don't track in version control
397
398
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
399
400
__version__ = version = {version!r}
401
__version_tuple__ = version_tuple = {version_tuple!r}
402
'''
403
```
404
405
### Text File Template
406
407
```python
408
# Default template for .txt files
409
TEMPLATE_TXT = "{version}"
410
```
411
412
### Custom Templates
413
414
```python
415
# Custom template example
416
custom_template = '''
417
"""Version information for {dist_name}"""
418
VERSION = "{version}"
419
BUILD_DATE = "{build_date}"
420
COMMIT = "{node}"
421
DIRTY = {dirty}
422
'''
423
424
version = get_version(
425
write_to="mypackage/_version.py",
426
write_to_template=custom_template
427
)
428
```