Contributing to CPython — Deep Dive

The CPython development model

CPython follows a time-based release cycle: a new minor version (3.x) ships every October, with alpha/beta/release-candidate milestones starting in April. The main branch always targets the next unreleased version. Bug fixes are backported to maintained branches (currently 3.11, 3.12, 3.13).

The governance model changed in 2019 after Guido van Rossum stepped down as BDFL. A five-person Steering Council, elected annually by core developers, now makes final decisions. Day-to-day work is self-organizing: contributors pick issues, core developers review and merge.

Building and testing CPython in depth

Configure options that matter

./configure \
  --with-pydebug \           # Debug build with assertions
  --with-address-sanitizer \  # Detect memory errors (ASan)
  --with-undefined-behavior-sanitizer \  # Detect UB (UBSan)
  --enable-optimizations      # PGO build (for benchmarking only)

Debug builds are 2-3× slower but catch bugs that release builds hide. ASan and UBSan are invaluable when working on C code — they turn subtle memory corruption into immediate crashes with stack traces.

Running the test suite

# Run all tests (slow — 30+ minutes)
./python -m test -j$(nproc)

# Run a single test module
./python -m test test_asyncio -v

# Run tests that match a pattern
./python -m test test_typing -k "test_generic"

# Run with coverage
./python -m test --coverage test_json

The full suite includes over 400 test modules. CI runs them on Linux, macOS, Windows, and several architectures (ARM, s390x). The Buildbot fleet at buildbot.python.org tests on exotic platforms that GitHub Actions does not cover.

Refleak testing

CPython tracks reference counts. A reference leak means an object’s refcount never reaches zero, causing a memory leak. Run refleak tests with:

./python -m test -R 3:3 test_json

This runs the test multiple times and checks that reference counts return to baseline. If your C code forgets a Py_DECREF, refleak testing will catch it.

Working with C code

The object model

Every Python object in CPython is a PyObject* with at least two fields:

typedef struct {
    Py_ssize_t ob_refcnt;   // reference count
    PyTypeObject *ob_type;   // pointer to the type object
} PyObject;

Container types (list, dict) add their own fields. Understanding this struct is the entry point to all C-level CPython work.

Reference counting discipline

The most common source of C-level bugs:

// WRONG — leaks the string object
PyObject *name = PyUnicode_FromString("hello");
PyList_Append(list, name);
// name's refcount is now 2 (creation + list), but we hold a reference we never release

// CORRECT
PyObject *name = PyUnicode_FromString("hello");
if (name == NULL) return NULL;  // always check for errors
PyList_Append(list, name);
Py_DECREF(name);  // release our reference; list still holds one

Rules of thumb:

  • Every Py*_New / Py*_From* returns a new reference — you own it, you must decref it.
  • PyList_GetItem returns a borrowed reference — do not decref it.
  • When in doubt, read the function’s documentation for “Return value: New reference” or “Borrowed reference.”

Adding a new built-in function

  1. Write the C implementation in the appropriate file (e.g., Python/bltinmodule.c for builtins).
  2. Use the Argument Clinic tool to generate argument parsing boilerplate:
/*[clinic input]
my_function
    value: object
    /
Do something useful.
[clinic start generated code]*/

Run make clinic to regenerate the parsing code. Argument Clinic ensures consistent error messages and signature introspection.

  1. Add the function to the module’s method table.
  2. Write tests in Lib/test/.
  3. Add documentation in Doc/library/.

The review and merge pipeline

Automated checks

Every PR triggers:

  • CI tests on Linux, macOS, Windows (GitHub Actions)
  • Lint checks via pre-commit (PEP 7 for C, PEP 8 for Python)
  • News entry check — blocks merge if Misc/NEWS.d/ fragment is missing
  • CLA check — blocks merge if contributor has not signed

Backporting

After merging to main, bug fixes need backporting. The miss-islington bot automates this: label the PR with needs backport to 3.12 and the bot creates a cherry-pick PR.

For complex backports where the bot fails, manually cherry-pick:

git checkout 3.12
git cherry-pick -x <commit-hash>
# Resolve conflicts if any
git push

Becoming a core developer

Core developer status is granted by the Steering Council based on a track record of high-quality contributions and constructive community participation. The typical path:

  1. Contribute consistently for 1-2 years.
  2. Demonstrate good judgement in reviews and discussions.
  3. An existing core developer nominates you.
  4. The Steering Council votes.

Core developers gain merge rights and voting rights in governance elections. The role carries responsibility: reviewing others’ PRs, mentoring newcomers, and participating in design discussions.

Contribution areas by skill level

Skill levelRecommended areas
BeginnerDocumentation fixes, test additions, issue triage
IntermediateStdlib bug fixes, Lib/ module improvements, typing stubs
AdvancedC extension fixes, performance optimizations, new PEP implementations
ExpertInterpreter core (eval loop, GC, compiler), free-threading work

The free-threading project (PEP 703, removing the GIL) is one of the most active areas in 2025-2026. Contributors with systems programming experience can make significant impact here.

Tools of the trade

python-dev and core-mentorship mailing lists — Announcements and discussions. The core-mentorship list is explicitly beginner-friendly.

discuss.python.org — The Discourse forum where PEPs are debated, ideas are proposed, and help is offered.

bedevere bot — Automates label management, CLA checks, and backport tracking on GitHub.

blurb — CLI tool for creating NEWS fragments in the correct format.

Argument Clinic — Code generator for C argument parsing. Saves hundreds of lines of boilerplate.

Tradeoffs of contributing

BenefitCost
Massive impact — changes reach millionsSlow review cycles (weeks to months for complex changes)
Deep understanding of Python internalsSteep learning curve for C-level work
Strong open-source resume signalBackwards-compatibility constraints limit creativity
Mentorship from world-class developersConsensus-driven process can feel frustrating

One thing to remember: CPython is one of the most impactful open-source projects you can contribute to. Start small — a documentation fix, a test case, a bug triage comment. Each contribution teaches you something about how the language you use every day actually works, and every merged PR makes Python better for everyone.

pythonopen-sourcecommunity

See Also

  • Python Pep Process Learn how new Python features go from someone's idea to something you can actually use in your code.
  • Python Python Enhancement Proposals History Travel through the story of Python's most important decisions — told through the documents that shaped the language.
  • Ci Cd Why big apps can ship updates every day without turning your phone into a glitchy mess — CI/CD is the behind-the-scenes quality gate and delivery truck.
  • Containerization Why does software that works on your computer break on everyone else's? Containers fix that — and they're why Netflix can deploy 100 updates a day without the site going down.
  • Python 310 New Features Python 3.10 gave programmers a shape-sorting machine, friendlier error messages, and cleaner ways to say 'this or that' in type hints.