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_GetItemreturns 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
- Write the C implementation in the appropriate file (e.g.,
Python/bltinmodule.cfor builtins). - 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.
- Add the function to the module’s method table.
- Write tests in
Lib/test/. - 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:
- Contribute consistently for 1-2 years.
- Demonstrate good judgement in reviews and discussions.
- An existing core developer nominates you.
- 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 level | Recommended areas |
|---|---|
| Beginner | Documentation fixes, test additions, issue triage |
| Intermediate | Stdlib bug fixes, Lib/ module improvements, typing stubs |
| Advanced | C extension fixes, performance optimizations, new PEP implementations |
| Expert | Interpreter 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
| Benefit | Cost |
|---|---|
| Massive impact — changes reach millions | Slow review cycles (weeks to months for complex changes) |
| Deep understanding of Python internals | Steep learning curve for C-level work |
| Strong open-source resume signal | Backwards-compatibility constraints limit creativity |
| Mentorship from world-class developers | Consensus-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.
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.