repomatic.metadata package¶
Repository and project metadata, split by concern.
The Metadata singleton in core
assembles the concern mixins: env (Actions environment), git
(commit ranges and per-commit matrices), project (pyproject.toml
and Sphinx reading) and matrix (job-matrix construction).
Submodules¶
repomatic.metadata.core module¶
Extract metadata from repository and Python projects to be used by GitHub workflows.
This module solves a fundamental limitation of GitHub Actions: a workflow run is
triggered by a singular event, which might encapsulate multiple commits. GitHub only
exposes github.event.head_commit (the most recent commit), but workflows often need
to process all commits in the push event.
This is critical for releases, where two commits are pushed together:
[changelog] Release vX.Y.Z— the release commit to be tagged and published[changelog] Post-release bump vX.Y.Z → vX.Y.Z— bumps version for the next dev cycle
Since github.event.head_commit only sees the post-release bump, this module extracts
the full commit range from the push event and identifies release commits that need
special handling (tagging, PyPI publishing, GitHub release creation).
Output shapes
Every key is printed to the environment file
as one key=value line. Values take three shapes:
is_python_project=true
doc_files="changelog.md" "readme.md" "docs/license.md"
new_commits_matrix={"commit": ["346ce66…", "6f27db4…"], "include": [{"commit": "346ce66…", "short_sha": "346ce66"}]}
A scalar prints bare. A list prints as space-joined, individually quoted items,
not a JSON array: workflow if: conditions test membership with a padded
contains() against that string. A matrix prints as inlined JSON for
fromJSON() to parse into a job matrix. See Metadata.format_github_value()
for the encoding, and Dialect for the other output formats.
The full key inventory is generated from this module rather than listed here, so
it cannot go stale: run repomatic metadata --list-keys, or read the rendered
table in the workflows documentation.
- repomatic.metadata.core.HEREDOC_FIELDS: Final[frozenset[str]] = frozenset({'release_notes', 'release_notes_with_admonition'})¶
Metadata fields that should always use heredoc format in GitHub Actions output.
Some fields may contain special characters (brackets, parentheses, emojis, or potential newlines) that can break GitHub Actions parsing when using simple
key=valueformat. These fields will use the heredoc delimiter format regardless of whether they currently contain multiple lines.
- class repomatic.metadata.core.Dialect(*values)[source]¶
Bases:
StrEnumOutput dialect for metadata serialization.
- github = 'github'¶
- github_json = 'github-json'¶
- json = 'json'¶
- repomatic.metadata.core.METADATA_KEYS_HEADER_DEFS: tuple[tuple[str, str], ...] = (('Key', 'key'), ('Description', 'description'))¶
Column definitions for the metadata keys reference table.
- repomatic.metadata.core.metadata_keys_reference()[source]¶
Build the metadata keys reference as table rows.
Returns a list of
(key, description)tuples for all keys produced byMetadata.dump(), including[tool.repomatic]config fields that are exposed as metadata outputs. Rows are unsorted: sorting is handled by the CLI’sSortByOption.
- repomatic.metadata.core.all_metadata_keys()[source]¶
Returns the set of all valid metadata key names.
- repomatic.metadata.core.METADATA_VALUE_OPTIONS: frozenset[str] = frozenset({'--format', '--output', '--sort-by', '-o'})¶
Options on the
metadatacommand consuming the token that follows them.Needed by
repomatic.lint_repo.check_metadata_keys()to tell a positional key from an option’s value while reading a workflow’srun:line. The command itself is not importable from there:repomatic.cli.mainreadssys.stdout.nameat import time, so importing it under a test that has replaced stdout raises.Listed here rather than derived, and pinned against the real command by repomatic’s own test suite, so an option added later cannot quietly turn its value into a token the lint reports as an unknown key.
- class repomatic.metadata.core.JSONMetadata(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)[source]¶
Bases:
JSONEncoderCustom JSON encoder for metadata serialization.
Constructor for JSONEncoder, with sensible defaults.
If skipkeys is false, then it is a TypeError to attempt encoding of keys that are not str, int, float, bool or None. If skipkeys is True, such items are simply skipped.
If ensure_ascii is true, the output is guaranteed to be str objects with all incoming non-ASCII and non-printable characters escaped. If ensure_ascii is false, the output can contain non-ASCII and non-printable characters.
If check_circular is true, then lists, dicts, and custom encoded objects will be checked for circular references during encoding to prevent an infinite recursion (which would cause an RecursionError). Otherwise, no such check takes place.
If allow_nan is true, then NaN, Infinity, and -Infinity will be encoded as such. This behavior is not JSON specification compliant, but is consistent with most JavaScript based encoders and decoders. Otherwise, it will be a ValueError to encode such floats.
If sort_keys is true, then the output of dictionaries will be sorted by key; this is useful for regression tests to ensure that JSON serializations can be compared on a day-to-day basis.
If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. None is the most compact representation.
If specified, separators should be an (item_separator, key_separator) tuple. The default is (’, ‘, ‘: ‘) if indent is
Noneand (‘,’, ‘: ‘) otherwise. To get the most compact JSON representation, you should specify (‘,’, ‘:’) to eliminate whitespace.If specified, default is a function that gets called for objects that can’t otherwise be serialized. It should return a JSON encodable version of the object or raise a
TypeError.- default(o)[source]¶
Implement this method in a subclass such that it returns a serializable object for
o, or calls the base implementation (to raise aTypeError).For example, to support arbitrary iterators, you could implement default like this:
def default(self, o): try: iterable = iter(o) except TypeError: pass else: return list(iterable) # Let the base class default method raise the TypeError return super().default(o)
- Return type:
- class repomatic.metadata.core.Metadata[source]¶
Bases:
EnvironmentMetadata,GitMetadata,MatrixMetadata,ProjectMetadataMetadata class.
Implemented as a singleton: every
Metadata()call returns the same instance within a process. This is safe because env vars and project files do not change during a single CLI invocation. Usereset()in test teardown to discard the cached instance between tests.- classmethod reset()[source]¶
Discard the singleton so the next call creates a fresh instance.
Intended for test teardown only. Production code should never call this.
- Return type:
- property github_event: dict[str, Any][source]¶
Load the GitHub event payload from
GITHUB_EVENT_PATH.GitHub Actions automatically sets
GITHUB_EVENT_PATHto a JSON file containing the complete webhook event payload.Delegates to
repomatic.github.actions.get_github_event(), the one loader of the payload: the two used to parse the file independently and disagree on whether a missing file was fatal. The tolerant contract wins (an unreadable payload degrades every consumer to its no-event behavior); only the CI-context warning lives here, since the shared loader serves non-CI callers too.
- property files: FileInventory[source]¶
What this repository holds on disk,
.gitignoreapplied.The inventory is its own concern (
repomatic.file_inventory): answering “which Markdown files are there” needs no CI context, no git history and nopyproject.toml. The group properties below forward to it so everymetadataoutput key keeps its name; a caller wanting the argument-taking lookups goes to the inventory itself.
- property release_notes: str | None[source]¶
Generate notes to be attached to the GitHub release.
Renders the
github-releasestemplate with changelog content for the version. The template is the single place that defines the release body layout.
- property release_notes_with_admonition: str | None[source]¶
Generate release notes with a pre-computed availability admonition.
Builds the same body as
release_notes, but injects a> [!NOTE]admonition linking to PyPI and GitHub even beforefix-changeloghas a chance to updatechangelog.md.The engine’s
create-releasejob bakes this body into the GitHub release at draft-creation time, so the admonition is present from the start. Doing it there (rather than editing the release from the caller’s fastpublish-pypilane) removes the cross-lane race where the edit ran beforecreate-releasehad created the release, and so silently dropped the admonition undercontinue-on-error. The bake is optimistic: it assumes the parallel PyPI upload succeeds, which it does on the normal path; a failed upload surfaces as a redpublish-pypijob, not as a wrong admonition the user must catch.Returns
Nonewhen the project is not on PyPI, has no changelog, or has no version to release, in which casecreate-releasefalls back to the plainrelease_notes.
- static format_github_value(value)[source]¶
Transform Python value to GitHub-friendly, JSON-like, console string.
Renders:
stras-isNoneinto empty stringboolinto lower-cased stringMatrixinto JSON stringIterableof mixed strings andPathinto a serialized space-separated string, wherePathitems are double-quotedother
Iterableinto a JSON string
Todo
Widen the JSON branch beyond an iterable of
dict[str, str], the only shape it asserts on today, when a metadata key needs a richer one.- Return type:
- dump_factories()[source]¶
Lazy value factories for every metadata key, in output order.
Each value is computed only when its key is included, so
keys=("is_python_project",)skipsnuitka_matrixand the git history walk it pulls in.Split out of
dump()so the key inventory is inspectable without computing anything:tests/test_metadata.pyasserts these names match_METADATA_KEY_DESCRIPTIONSplus_metadata_config_fields(), which is what keeps--list-keys,all_metadata_keys()and the emitted output from drifting apart.Derived from
_METADATA_KEY_DESCRIPTIONSrather than re-listing every key: most keys read the attribute of the same name, so only the handful whose value is not a plain attribute carry an explicit factory.
- dump(dialect=Dialect.github, keys=())[source]¶
Returns metadata in the specified format.
Defaults to GitHub dialect. When keys is non-empty, only the requested keys are computed and included in the output. Filtered-out keys are never accessed, so callers requesting a small subset avoid triggering expensive dependent computations (git history walks, file system scans, build matrix expansion). See
dump_factories().- Return type:
repomatic.metadata.env module¶
GitHub Actions environment accessors of Metadata.
Every property here reads the workflow-run environment (the event payload,
the GITHUB_* variables) and nothing else: no git, no pyproject.toml.
- class repomatic.metadata.env.EnvironmentMetadata[source]¶
Bases:
objectWorkflow-run environment: the event payload and
GITHUB_*variables.A concern mixin of
Metadata: never instantiated on its own, and reads sibling concerns throughself.- property event_type: WorkflowEvent | None[source]¶
Returns the type of event that triggered the workflow run.
Maps
event_name(theGITHUB_EVENT_NAMEvariable, set by GitHub Actions on every run) onto itsWorkflowEventmember, soscheduleandworkflow_dispatchruns resolve to their own event instead of falling in aNonehole that nulls every commit matrix.Caution
When
GITHUB_EVENT_NAMEis absent or unrecognized, falls back on the historical heuristic: a non-emptyGITHUB_BASE_REFmeans a pull request (only set for pull request events), a present-but-empty one means a push.
- property event_actor: str | None[source]¶
Returns the GitHub login of the user that triggered the workflow run.
- property event_sender_type: str | None[source]¶
Returns the type of the user that triggered the workflow run.
- property is_bot: bool[source]¶
Returns
Trueif the workflow was triggered by a bot or automated process.This is useful to only run some jobs on human-triggered events. Or skip jobs triggered by bots to avoid infinite loops.
The sender type covers every GitHub App, which is how Dependabot and Renovate author their pull requests today. The explicit login list is kept as a second signal for downstream repositories:
sender.typeis absent from the event payload outsidepushandpull_request(and empty when the payload cannot be read at all), and the login is then the only thing left to match on.The test is deliberately not
sender.type != "User", which would also classify anOrganizationsender as a bot.
- property head_branch: str | None[source]¶
Returns the head branch name for pull request events.
For pull request events, this is the source branch name (e.g.,
update-mailmap). For push events, returnsNonesince there’s no head branch concept.The branch name is extracted from the
GITHUB_HEAD_REFenvironment variable, which is only set for pull request events.
- property event_name: str | None[source]¶
Returns the name of the event that triggered the workflow.
Reads
GITHUB_EVENT_NAME. This is the raw event name ("push","pull_request","workflow_run"), whichevent_typeresolves to aWorkflowEventmember.
- property job_name: str | None[source]¶
Returns the ID of the current job in the workflow.
Reads
GITHUB_JOB.
- property ref_name: str | None[source]¶
Returns the short ref name of the branch or tag.
Reads
GITHUB_REF_NAME.
- property repo_name: str | None[source]¶
Returns the repository name without owner prefix.
Derived from
repo_slugby splitting on/.
- property is_awesome: bool[source]¶
Whether this is an awesome-list repository.
Detected by the
awesome-prefix on the repository name.
- property repo_owner: str | None[source]¶
Returns the repository owner.
Reads
GITHUB_REPOSITORY_OWNER, falling back to the owner component ofrepo_slug.
- property repo_slug: str | None[source]¶
Returns the
owner/nameslug for the current repository.Resolution order:
GITHUB_REPOSITORYenv var (CI),gh repo view(authenticated local), git remote URL parsing (offline fallback).
- property repo_url: str | None[source]¶
Returns the full URL to the repository.
Derived from
server_urlandrepo_slug.
- property run_id: str | None[source]¶
Returns the unique ID of the current workflow run.
Reads
GITHUB_RUN_ID.
- property run_number: str | None[source]¶
Returns the run number for the current workflow.
Reads
GITHUB_RUN_NUMBER.
- property server_url: str[source]¶
Returns the GitHub server URL.
Reads
GITHUB_SERVER_URL, defaulting tohttps://github.com.
- property sha: str | None[source]¶
Returns the commit SHA that triggered the workflow.
Reads
GITHUB_SHA.
- property triggering_actor: str | None[source]¶
Returns the login of the user that initiated the workflow run.
Reads
GITHUB_TRIGGERING_ACTOR. This differs fromevent_actor(GITHUB_ACTOR) when a workflow is re-run by a different user.
repomatic.metadata.git module¶
Git commit-range logic of Metadata.
Resolves the commit range an event bundles, the release commits inside it,
what those commits changed, and the per-commit matrices built by rewinding
the checkout. This is the one concern that can touch the repository state,
always restoring it (see _restored_worktree).
- class repomatic.metadata.git.GitMetadata[source]¶
Bases:
objectCommit ranges, changed files, and the per-commit matrices.
A concern mixin of
Metadata: never instantiated on its own, and reads sibling concerns throughself.- git_deepen(commit_hash, max_attempts=10, deepen_increment=50)[source]¶
Deepen a shallow clone until the provided
commit_hashis found.Progressively fetches more commits from the current repository until the specified commit is found or max attempts is reached.
Returns
Trueif the commit was found,Falseotherwise.- Return type:
- commit_matrix(commits)[source]¶
Pre-compute a matrix of commits.
Danger
This method temporarily modifies the state of the repository to compute version metadata from the past.
To prevent any loss of uncommitted data, it stashes local changes before its checkouts and restores the initial state however the scan exits, through
_restored_worktree().The list of commits is augmented with long and short SHA values, as well as current version. Most recent commit is first, oldest is last.
Returns a ready-to-use matrix structure:
{ "commit": [ "346ce664f055fbd042a25ee0b7e96702e95", "6f27db47612aaee06fdf08744b09a9f5f6c2", ], "include": [ { "commit": "346ce664f055fbd042a25ee0b7e96702e95", "short_sha": "346ce66", "current_version": "2.0.1", }, { "commit": "6f27db47612aaee06fdf08744b09a9f5f6c2", "short_sha": "6f27db4", "current_version": "2.0.0", }, ], }
- property changed_files: tuple[str, ...] | None[source]¶
Returns the list of files changed in the current event’s commit range.
Uses
git diff --name-onlybetween the start and end of the commit range. ReturnsNoneif no commit range is available (e.g., outside CI).
- property binary_affecting_paths: tuple[str, ...][source]¶
Path prefixes that affect compiled binaries for this project.
Combines the static
BINARY_AFFECTING_PATHS(common files likepyproject.toml,uv.lock,tests/) with project-specific source directories derived from[project.scripts]inpyproject.toml.For example, a project with
mpm = "meta_package_manager.__main__:main"addsmeta_package_manager/as an affecting path. This makes the check reusable across downstream repositories without hardcoding source directories.
- property head_commit_message: str[source]¶
Returns
github.event.head_commit.messagefrom the event payload.Set for
pushevents. Empty string for events that do not carry a head commit (pull_request,schedule,workflow_dispatch).
- property yaml_changed: bool[source]¶
Returns
Truewhen the current event’s commit range touches at least one YAML file.Lets per-job lint gates short-circuit on pushes / PRs that don’t touch YAML. Falls back to “repo contains any YAML file” when the commit range is unavailable (
workflow_dispatch), preserving the existing behavior of those manual runs.
- property zsh_changed: bool[source]¶
Returns
Truewhen the current event’s commit range touches at least one Zsh file.Falls back to “repo contains any Zsh file” when the commit range is unavailable.
- property workflows_changed: bool[source]¶
Returns
Truewhen the current event’s commit range touches at least one GitHub workflow file.Falls back to “repo contains any workflow file” when the commit range is unavailable.
- property skip_binary_build: bool[source]¶
Returns
Trueif binary builds should be skipped for this event.Binary builds are expensive and time-consuming. This property identifies contexts where the changes cannot possibly affect compiled binaries, allowing workflows to skip Nuitka compilation jobs.
Three mechanisms are checked:
Branch name — PRs from known non-code branches (documentation,
.mailmap,.gitignore, etc.) are skipped.Version-bump commit — Push events whose head commit is a user-initiated version bump (
Bump (major|minor) version to) are skipped: the bump merge changes only version strings anduv.lock, so the new binary differs from the previous one only in the baked-in version string. The[changelog] Post-release bumpprefix is deliberately not checked here: theprepare-releasemerge bundles the release commit with the post-release-bump commit, and the release commit must still produce its binary.Changed files — Push events where all changed files fall outside
binary_affecting_pathsare skipped. This avoids ~2h of Nuitka builds for documentation-only commits tomain.
- property commit_range: tuple[str | None, str] | None[source]¶
Range of commits bundled within the triggering event.
A workflow run is triggered by a singular event, which might encapsulate one or more commits. This means the workflow will only run once on the last commit, even if multiple new commits were pushed.
This is critical for releases where two commits are pushed together:
[changelog] Release vX.Y.Z— the release commit[changelog] Post-release bump vX.Y.Z → vX.Y.Z— the post-release bump
Without extracting the full commit range, the release commit would be missed since
github.event.head_commitonly exposes the post-release bump.This property also enables processing each commit individually when we want to keep a carefully constructed commit history. The typical example is a pull request that is merged upstream but we’d like to produce artifacts (builds, packages, etc.) for each individual commit.
The default
GITHUB_SHAenvironment variable is not enough as it only points to the last commit. We need to inspect the commit history to find all new ones. New commits need to be fetched differently inpushandpull_requestevents.See also
See also
Pull request events on GitHub are a bit complex, see: The Many SHAs of a GitHub Pull Request.
- property current_commit: Commit[source]¶
Returns the current
Commitobject.Raises if
HEADcannot be resolved (an empty repository), mirroring the previous behavior where traversing an empty history raised too.
- property current_commit_matrix: Matrix | None[source]¶
Pre-computed matrix with long and short SHA values of the current commit.
- property new_commits: tuple[Commit, ...] | None[source]¶
Returns list of all
Commitobjects bundled within the triggering event.This extracts all commits from the push event, not just
head_commit. For releases, this typically includes both the release commit and the post-release bump commit, allowing downstream jobs to process each one.Commits are returned in chronological order (oldest first, most recent last).
- property new_commits_matrix: Matrix | None[source]¶
Pre-computed matrix with long and short SHA values of new commits.
- property release_commits: tuple[Commit, ...] | None[source]¶
Returns list of
Commitobjects to be tagged within the triggering event.This filters
new_commitsto find release commits that need special handling: tagging, PyPI publishing, and GitHub release creation.This is essential because when a release is pushed,
github.event.head_commitonly exposes the post-release bump commit, not the release commit. By extracting all commits from the event (vianew_commits) and filtering for release commits here, we ensure the release workflow can properly identify and process the[changelog] Release vX.Y.Zcommit.We cannot identify a release commit based on the presence of a
vX.Y.Ztag alone. That’s because the tag is not present in theprepare-releasepull request produced by thechangelog.yamlworkflow. The tag is created later by therelease.yamlworkflow, when the pull request is merged tomain.Our best option is to identify a release based on the full commit message, using the template from the
changelog.yamlworkflow.
repomatic.metadata.matrix module¶
Job-matrix construction of Metadata.
Builds the Nuitka build matrix and the test matrices from the other
concerns’ facts, and applies the repository’s [tool.repomatic]
test-matrix configuration to them.
- class repomatic.metadata.matrix.MatrixMetadata[source]¶
Bases:
objectThe Nuitka build matrix and the test matrices.
A concern mixin of
Metadata: never instantiated on its own, and reads sibling concerns throughself.- property nuitka_matrix: Matrix | None[source]¶
Pre-compute a matrix for Nuitka compilation workflows.
Crosses three axes:
one commit per release commit (during a release) or per new commit (otherwise)
every
[project.scripts]entry pointevery build target of
NUITKA_BUILD_TARGETS(runner, platform, architecture, binary extension, and the glibc floor or minimum-OS version that target enforces), narrowed to the[tool.repomatic] nuitka.dev-targetscanary subset on an ordinary push (seedev_targets); release commits,scheduleandworkflow_dispatchruns keep the full roster
Each axis contributes an
includeentry carrying the extra parameters the compile job needs, keyed on the axis value that selects it: the target’s runner and floors, the entry point’s module and callable, and the commit’s short SHA and version. A final pass adds oneincludeentry per(os, entry_point, commit)triple naming thebin_namethe compiled artifact takes, since that name depends on all three at once.The matrix closes with
{"state": "stable"}, which the release workflow reads to decide whether a failing job blocks the release.Note
Every value comes from
NUITKA_BUILD_TARGETSand the project’s ownpyproject.toml, so no literal is repeated here: runrepomatic metadata nuitka_matrixagainst a project to see the matrix it computes, orrepomatic show-test-matrixfor the test one.Todo
Drop the per-entry-point
--python-flag=-mworkaround computed below, and compile a__main__.pyentry point through Nuitka’s own--main-entry-point, once Nuitka#3879 ships.
- property test_matrix: Matrix[source]¶
Full test matrix for non-PR events.
Combines all runner OS images and Python versions, excluding known incompatible combinations. Marks development Python versions as unstable so CI can use
continue-on-error, and adds released build flavors (free-threaded) as stable single-runner smoke tests. Per-project config from[tool.repomatic.test-matrix]is applied last.When
[tool.repomatic.test-matrix] full-includerows are configured, the matrix is emitted as a flat job list ({"include": [...]}) so each row is a standalone combination GitHub runs verbatim, rather than one that augments a base combo sharing itsosandpython-version.
- property test_matrix_pr: Matrix[source]¶
Reduced test matrix for pull requests.
Skips experimental Python versions and redundant architecture variants to reduce CI load on PRs. Per-project config excludes and includes from
[tool.repomatic.test-matrix]are applied, but variations are not (to keep the PR matrix small).
- property stale_test_matrix_excludes: list[tuple[dict[str, str], dict[str, str]]][source]¶
User
test-matrix.excludeentries matching no full-matrix axis value.An exclude naming a value absent from every axis (like a renamed runner) can never match a combination, so
Matrix.prune()drops it silently and its exclusion intent is lost. This drift is common after an upstream runner rename (such asmacos-15-intelbecomingmacos-26-intel). Thelint-repocheck surfaces these so the drift fails loudly instead of silently.The axes come from
_test_matrix_base, never from the emittedtest_matrix: afull-includematrix emits as a flat job list whoseall_variations()is empty, which would misreport every key of an entry as stale. Carrying the absent values in the result is what keeps the lint check from re-deriving them against the wrong matrix.- Returns:
(entry, absent_values)pairs in config order: each offending exclude with the key/value pairs no axis carries.
repomatic.metadata.project module¶
Python-project reading of Metadata.
Everything derived from pyproject.toml and the Sphinx configuration:
project identity, entry points, version state, and tool parameters.
- repomatic.metadata.project.is_version_bump_allowed(part)[source]¶
Check if a version bump of the specified part is allowed.
This prevents double version increments within a development cycle. A bump is blocked if the version has already been bumped (but not released) since the last tagged release.
For example: - Last release:
v5.0.1, current:5.0.2→ minor bump allowed - Last release:v5.0.1, current:5.1.0→ minor bump NOT allowed (bumped) - Last release:v5.0.1, current:6.0.0→ major bump NOT allowed (bumped)Note
When tags are not available (e.g., due to race conditions between workflows), this function falls back to parsing version from recent commit messages.
- class repomatic.metadata.project.ProjectMetadata[source]¶
Bases:
objectWhat
pyproject.tomland the Sphinx configuration declare.A concern mixin of
Metadata: never instantiated on its own, and reads sibling concerns throughself.- property is_python_project: bool[source]¶
Returns
Trueif repository is a Python project.Presence of a
pyproject.tomlfile that respects the standards is enough to consider the project as a Python one. Delegates torepomatic.pyproject.is_python_project()so the detection rule has a single source of truth.
- property is_python_package: bool[source]¶
Returns
Trueif the repository builds a distributable package.Strictly narrower than
is_python_project: a uv virtual project declares a[project]table to carry its dependencies, then opts out of being built with[tool.uv] package = false. Delegates torepomatic.pyproject.is_python_package(), the same predicatePACKAGE_ONLYresolves against, so the release lane and the checks that police it agree on who publishes.Prefer this over the truthiness of
package_namewhen gating anything about publishing.package_nameonly reports what [project] name says, which a virtual project still declares.
- property pyproject_toml: dict[str, Any][source]¶
Returns the raw parsed content of
pyproject.toml.Returns an empty dict if the file does not exist.
- property pyproject: StandardMetadata | None[source]¶
Returns metadata stored in the
pyproject.tomlfile.Returns
Noneif thepyproject.tomldoes not exists or does not respects the PEP standards.Warning
Some third-party apps have their configuration saved into
pyproject.tomlfile, but that does not means the project is a Python one. For that, thepyproject.tomlneeds to respect the PEPs.
- property config: Config[source]¶
Returns the
[tool.repomatic]section frompyproject.toml.Merges user configuration with defaults from
Config.
- property nuitka_entry_points: list[str][source]¶
Entry points selected for Nuitka binary compilation.
Reads
[tool.repomatic].nuitka.entry-pointsfrompyproject.toml. When empty (the default), deduplicates by callable target: keeps the first entry point for each uniquemodule:callablepair, so alias entry points (like bothmpmandmeta-package-managerpointing to the same function) don’t produce duplicate binaries. Unrecognized CLI IDs are logged as warnings and discarded.
- property dev_targets: set[str][source]¶
Nuitka build targets compiled on ordinary (non-release) pushes.
Reads
[tool.repomatic].nuitka.dev-targetsfrompyproject.toml. An empty list disables dev builds entirely. Seenuitka_dev_targetsfor the default and the canary rationale.Unrecognized target names are logged as warnings and discarded.
- property unstable_targets: set[str][source]¶
Nuitka build targets allowed to fail without blocking the release.
Reads
[tool.repomatic].nuitka.unstable-targetsfrompyproject.toml. Defaults to an empty set.Unrecognized target names are logged as warnings and discarded.
- property script_entries: list[tuple[str, str, str]][source]¶
Returns a list of tuples containing the script name, its module and callable.
Results are derived from the script entries of
pyproject.toml. So that:[project.scripts] mdedup = "mail_deduplicate.cli:mdedup" mpm = "meta_package_manager.__main__:main"
Will yields the following list:
( ("mdedup", "mail_deduplicate.cli", "mdedup"), ("mpm", "meta_package_manager.__main__", "main"), ..., )
Each entry is validated against PEP 621 and PyPI conventions:
The script name (the dict key) must be non-empty, contain at least one non-dot character, and match
[A-Za-z0-9._-]+. This mirrors the rule PyPI enforces on uploaded wheels and the check uv-build performs; rejecting names like../escape,nested/scriptor.here keeps them from flowing into the binary file path template{{cli_id}}-{{current_version}}-{{target}}.{{extension}}and from there into shell-quoted artifact names,chmod, and attestation commands in the release workflow.The script value must split on
:into exactly two non-empty parts (module:object). Malformed values raise a descriptiveValueErrorinstead of crashing with an unpacking error.
- property requires_python_floor: tuple[int, int] | None[source]¶
The project’s
requires-pythonlower bound, as(major, minor).The one reduction of the specifier to a floor, shared by
mypy_paramsand thelint-repoPython-consistency check so the two cannot disagree on which operators count as a bound.- Returns:
The first
>=/>bound’s release pair, orNonewhen the project declares norequires-pythonor no lower bound.
- property mypy_params: list[str] | None[source]¶
Generates
mypyparameters.Mypy needs to be fed with this parameter:
--python-version 3.x.Extracts the minimum Python version from the project’s
requires-pythonspecifier. Only takesmajor.minorinto account.
- static get_current_version()[source]¶
Returns the current version as managed by bump-my-version.
Same as calling the CLI:
$ bump-my-version show current_version
Reads
current_versionfrom the first TOML file found in the current working directory:.bumpversion.toml(top-level table) orpyproject.toml([tool.bumpversion]).
- property current_version: str | None[source]¶
Returns the current version.
Current version is fetched from the
bump-my-versionconfiguration file.During a release, two commits are bundled into a single push event:
[changelog] Release vX.Y.Z— freezes the version to the release number[changelog] Post-release bump vX.Y.Z → vX.Y.Z— bumps to the next dev version
In this situation, the current version returned is the one from the most recent commit (the post-release bump), which represents the next development version. Use
released_versionto get the version from the release commit.
- property released_version: str | None[source]¶
Returns the version of the release commit.
During a release push event, this extracts the version from the
[changelog] Release vX.Y.Zcommit, which is distinct fromcurrent_version(the post-release bump version). This is used for tagging, PyPI publishing, and GitHub release creation.Returns
Noneif no release commit is found in the current event.
- property minor_bump_allowed: bool[source]¶
Check if a minor version bump is allowed.
This prevents double version increments within a development cycle.