Reference configs

python/cpython: NEWS entry names, before a pull request

CPython's release notes go in Misc/NEWS.d/next/, named like 2026-05-07-12-00-00.gh-issue-1234.abc.rst. The blurb tool writes that name, and the bedevere bot checks it on each pull request. One filename_regex rule checks it before there is one. This config was written to test alint; CPython doesn't use alint.

What alint found

.alint.yml
- id: cpython-gitattributes-generated-resolve
  # fixed here: (?m), so ^ starts every line; and only entries with a
  # slash, since .gitattributes matches a bare name at any depth
  kind: registry_paths_resolve
  source: ".gitattributes"
  extract:
    regex: '(?m)^([^#\s\[]\S*/\S*)\s+.*\bgenerated\b'
  base: "."
  entries_are_globs: true
  expect: file
  level: error

✗ error cpython-gitattributes-generated-resolve

.gitattributes still marks Include/token.h and Include/internal/pycore_opcode.h as generated, and neither file exists: token.h became Include/internal/pycore_token.h. Lib/test/certdata/*.0 matches nothing either, because the .0 files are in certdata/capath/.

The config

The config extends oss-baseline, python, ci/github-actions, hygiene/no-tracked-artifacts and tooling/editorconfig. Its own rules check the NEWS entries, the line endings .gitattributes sets, the generated files and SBOMs, and the version numbers in configure.ac and Include/patchlevel.h. make regen-all, Ruff, Black, sphinx-lint, actionlint and zizmor run from command rules.

.alint.yml
- id: cpython-news-entry-filename
  # fixed here: bedevere's pattern, which also takes bpo- numbers
  kind: filename_regex
  paths:
    include: ["Misc/NEWS.d/next/*/*.rst"]
    exclude: ["Misc/NEWS.d/next/*/README.rst"]
  pattern: '^\d{4}-\d{2}-\d{2}(-\d{2}-\d{2}-\d{2})?\.(bpo|gh-issue)-\d+(,\d+)*\.[A-Za-z0-9_=-]+\.rst$'
  level: error

blurb's format, date to nonce, as bedevere checks it, in all 11 sections. Two more rules check each section's README and reject section names with spaces, as a pre-commit hook does.

.alint.yml
- id: cpython-version-minor-coherent
  kind: cross_file_value_equals
  source:
    file: "Include/patchlevel.h"
    extract: { regex: '#define PY_MINOR_VERSION\s+(\d+)' }
  targets:
    - file: "configure.ac"
      extract: { regex: 'm4_define\(\[PYTHON_VERSION\],\s*\[\d+\.(\d+)\]\)' }
  level: error

The minor version is written in both Include/patchlevel.h and configure.ac; this rule keeps them equal. A second rule does the same for the major version.

.alint.yml
- id: cpython-regen-all-fresh
  kind: command_idempotent
  command: ["make", "-j4", "regen-all"]
  timeout: 900
  level: error

Regenerating needs CPython's own build, so this rule runs make regen-all and fails when the tree would change.

What stays outside alint

The C API checks and anything that compares a change with its base stay with CPython's tools:

  • smelly, stable_abi and check-c-globals, which read the symbols libpython exports or parse C;
  • Argument Clinic's checksums, which need Clinic's own algorithm;
  • patchcheck, which compares a change with its base branch, and the ensurepip check, which downloads wheels.