mafw.devtools.pyversions.sync
Structure-aware pyproject.toml synchronization service.
This module implements PyprojectSyncService, the component that bridges
the pure Python version policy core and the on-disk pyproject.toml. It uses
tomlkit so that comments, whitespace, array formatting and key ordering
are preserved, mutates only the managed derived locations in place (never by
whole-file string replacement), writes atomically so a failure leaves the file
byte-for-byte unchanged, and offers a shared --dry-run driver that renders a
unified diff without touching the file.
The managed derived locations and their canonical sources are:
TOML location |
Canonical source |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
base of |
|
|
|
|
|
|
Added in version 2.4.
- author:
Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)
Classes
|
A single managed derived-location modification, used for reporting. |
|
Load, transform, synchronize and persist |
|
The result of running a full operation through the service. |
|
The outcome of a synchronization pass. |
- class mafw.devtools.pyversions.sync.DerivedChange(location: str, previous: str, new: str)[source]
Bases:
objectA single managed derived-location modification, used for reporting.
- Variables:
location – Human-readable TOML key path that changed.
previous – The previous value, rendered as a string.
new – The new value, rendered as a string.
- class mafw.devtools.pyversions.sync.PyprojectSyncService(path: Path)[source]
Bases:
objectLoad, transform, synchronize and persist
pyproject.toml.- Parameters:
path (Path) – Path to the
pyproject.tomlfile to manage.
- static _assign_array(container: Any, key: str, values: list[str]) None[source]
Replace the string items of a TOML array while preserving its style.
Reusing the existing
tomlkit.items.Array(rather than assigning a plain Python list) keeps the array’s multiline-or-single-line layout and surrounding whitespace intact, which is what keeps the diff minimal.
- static _is_free_threaded_row(versions: list[str]) bool[source]
Whether a matrix row is the dedicated free-threaded row (
X.Ytonly).
- static _is_version_classifier(classifier: str) bool[source]
Whether classifier is a per-minor-version Python classifier.
- static _matrix_rows(doc: TOMLDocument, env: str) Any | None[source]
Return the
matrixarray-of-tables for an environment, orNone.
- static _record(report: SyncReport, location: str, previous: Any, new: Any) None[source]
Record a change only when the rendered value actually differs.
- static _sync_env_python(doc: TOMLDocument, report: SyncReport, *, env: str, desired: str) None[source]
Synchronize a scalar
pythonkey of an environment (nogil/gil).
- static _write_canonical(doc: TOMLDocument, cfg: PythonConfig) None[source]
Write the canonical
[tool.mafw]keys from cfg into doc.
- static render(doc: TOMLDocument) str[source]
Serialize a tomlkit document back to text, preserving formatting.
- _rebuild_classifiers(existing: list[str], non_version: list[str], desired_versions: list[str]) list[str][source]
Rebuild the classifier list with managed version entries resynchronised.
- _sync_classifiers(doc: TOMLDocument, cfg: PythonConfig, report: SyncReport) None[source]
Rewrite the per-version Python classifiers, keeping all other entries.
- _sync_experimental_matrix(doc: TOMLDocument, cfg: PythonConfig, report: SyncReport) None[source]
Create or update the dedicated
experimentalenvironment matrix.The environment is created on demand so that experimental versions have a home that never expands the mandatory matrices.
- _sync_hatch_test_matrix(doc: TOMLDocument, cfg: PythonConfig, report: SyncReport) None[source]
Synchronize the standard and free-threaded
hatch-testmatrix rows.
- _sync_pre_push(doc: TOMLDocument, cfg: PythonConfig, report: SyncReport, *, previous_default: str) None[source]
Rewrite managed pre-push commands, leaving pins and unknowns untouched.
- _sync_simple_matrix(doc: TOMLDocument, cfg: PythonConfig, report: SyncReport, *, env: str, desired: list[str]) None[source]
Synchronize the single
pythonmatrix row of a simple environment.
- check() SyncReport[source]
Compute the inconsistencies between canonical config and derived state.
This is the read-only dual of
synchronize(): it loads the document, validates the canonical configuration, then computes what a synchronization would change. Every would-be change is an existing inconsistency. The document on disk is never modified.- Returns:
A report whose
changeslist enumerates the inconsistencies (empty when the configuration is fully consistent).- Raises:
DevtoolsError – If the file is missing, unparsable, or the canonical configuration is invalid.
- diff(before: str, after: str) str[source]
Return a unified diff between two renderings of the document.
- load() tuple[TOMLDocument, PythonConfig][source]
Parse the document and read the canonical configuration.
- Returns:
The parsed tomlkit document and the (unvalidated) configuration.
- Return type:
tuple[tomlkit.TOMLDocument, PythonConfig]
- Raises:
DevtoolsError – If the file is missing or cannot be parsed.
- run_operation(transform: Callable[[PythonConfig], PythonConfig], *, dry_run: bool) SyncOutcome[source]
Load, transform, synchronize and (optionally) persist the document.
This is the shared driver behind every modifying command. Because dry-run and real runs share the same load → transform → validate → synchronize pipeline, a dry-run reports exactly the same validation errors and the same diff a real run would produce — it simply does not write.
- Parameters:
transform – Maps the current canonical configuration to the desired one. For
syncthis is the identity; for the other commands it is aVersionManageroperation.dry_run – If
True, compute and return the diff without writing.
- Returns:
The operation outcome.
- Raises:
DevtoolsError – On parse errors, invalid canonical configuration, rejected transforms, or write failures.
- synchronize(doc: TOMLDocument, cfg: PythonConfig, *, previous: PythonConfig | None = None) SyncReport[source]
Update every managed derived location in doc to match cfg.
Mutates the document in place using structured tomlkit assignment so that unrelated content, comments and formatting survive. Returns a report of the per-location previous → new changes and of any pre-push command that could not be classified (and was therefore left untouched).
- Parameters:
doc – The tomlkit document to mutate.
cfg – The validated canonical configuration to project.
previous – The configuration before the transform, used to detect which stable selector managed pre-push commands currently carry. When omitted, cfg is used (appropriate for a pure
sync).
- Returns:
The change report.
- write_atomic(text: str) None[source]
Write text to
pyproject.tomlatomically.The content is first written to a temporary file in the same directory and then moved into place with
os.replace, which is atomic on the same filesystem. Any failure before the replacement leaves the original file byte-for-byte unchanged.- Parameters:
text – The full new file content.
- Raises:
DevtoolsError – If writing or replacing the file fails.
- class mafw.devtools.pyversions.sync.SyncOutcome(report: SyncReport, diff: str, written: bool)[source]
Bases:
objectThe result of running a full operation through the service.
- Variables:
report – The per-location change report.
diff – The unified diff of
pyproject.toml(empty if nothing changed).written – Whether the file was actually written (
Falsefor a dry-run or a no-op).
- class mafw.devtools.pyversions.sync.SyncReport(changes: list[~mafw.devtools.pyversions.sync.DerivedChange] = <factory>, skipped: list[str] = <factory>, notices: list[str] = <factory>)[source]
Bases:
objectThe outcome of a synchronization pass.
- Variables:
changes – The managed locations that were modified.
skipped – Locations that could not be classified and were left untouched.
notices – Informational messages for the operator about structural changes that are not simple value edits (for example the removal of an environment table).
- property modified: bool
Whether any managed location was modified.
- mafw.devtools.pyversions.sync._CLASSIFIER_PREFIX = 'Programming Language :: Python :: '
Prefix of the per-version Python classifiers.