# 90. Reading PEPs

# 90. Reading PEPs

A Python Enhancement Proposal, or PEP, is a design document for a significant change to Python. PEPs describe language changes, standard library changes, process rules, compatibility policy, governance, release schedules, and implementation plans.

For CPython internals work, PEPs matter because many implementation choices exist to satisfy a design accepted years earlier. Reading only the C code often shows what CPython does. Reading the PEP explains why it does it.

## 90.1 What a PEP Is

A PEP is a structured proposal.

It may describe:

| PEP kind | Purpose |
|---|---|
| Standards Track | New language feature, library feature, or interoperability standard |
| Informational | Design explanation, guideline, or background |
| Process | Governance, release, compatibility, or workflow rule |

A PEP usually contains:

```text
title
author
status
type
created date
abstract
motivation
rationale
specification
backward compatibility
reference implementation
rejected ideas
open issues
references
```

Not every PEP has every section. Older PEPs can be less uniform.

## 90.2 Why PEPs Matter for CPython Internals

A CPython implementation often follows constraints that are not obvious from code alone.

Examples:

```text
why pattern matching has specific binding rules
why async functions create coroutine objects
why dictionaries preserve insertion order
why annotations changed evaluation rules
why subinterpreters need isolated state
why C API compatibility is conservative
```

The code implements decisions. The PEP records the design argument.

When changing CPython, read the relevant PEP before assuming the implementation can be simplified.

## 90.3 PEP Status

A PEP has a status.

Common statuses include:

| Status | Meaning |
|---|---|
| Draft | Still being developed |
| Accepted | Approved for implementation |
| Final | Implemented or complete |
| Deferred | Postponed |
| Rejected | Declined |
| Withdrawn | Removed by author |
| Superseded | Replaced by another PEP |
| Active | Ongoing process PEP |

For internals work, Final and Accepted PEPs are usually the most important.

Rejected PEPs are also useful because they explain design alternatives that Python deliberately avoided.

## 90.4 Read the Header First

Start with the header.

Example fields:

```text
PEP: 572
Title: Assignment Expressions
Author: ...
Status: Final
Type: Standards Track
Created: ...
Python-Version: 3.8
```

The header answers:

```text
what feature this is
whether the proposal is active
which version it targets
who wrote it
whether it is language-level, informational, or process-level
```

Do not treat a Draft PEP as current Python behavior. Do not treat a Rejected PEP as design authority except for historical context.

## 90.5 Read Motivation Before Specification

The motivation explains the problem.

The specification explains the chosen design.

Read them in that order.

If you read only the specification, you may understand the rule but miss the reason. If you read only the motivation, you may understand the goal but miss the exact behavior CPython must implement.

Example pattern:

```text
Motivation
    why the old behavior was insufficient

Rationale
    why this design was chosen

Specification
    exact behavior to implement

Rejected ideas
    alternatives deliberately avoided
```

For implementation work, the specification is binding. The rationale helps avoid accidental redesign.

## 90.6 Separate Language Semantics From Implementation Strategy

Many PEPs specify Python behavior without requiring a particular implementation.

Example:

```text
language rule
    a match statement binds names according to defined pattern rules

implementation choice
    CPython compiles match statements into particular bytecode sequences
```

The PEP constrains the behavior. CPython may choose the internal representation.

When editing internals, preserve language semantics even if you change:

```text
AST representation
compiler passes
bytecode layout
runtime helper functions
cache structure
```

Tests should usually target the semantic rule, not the current implementation detail.

## 90.7 Find the Relevant PEP

Use the feature name, version, or subsystem.

Examples:

| Topic | Likely PEP area |
|---|---|
| Assignment expressions | PEP 572 |
| Positional-only parameters | PEP 570 |
| Structural pattern matching | PEP 634, 635, 636 |
| Exception groups | PEP 654 |
| Type hinting | PEP 484 and later typing PEPs |
| Module state in extensions | PEP 3121, PEP 489 |
| Stable ABI | PEP 384 |
| Per-interpreter GIL | PEP 684 |
| Free-threading | PEP 703 |
| Python release cycle | PEP 602 |
| Deprecation policy | Relevant process PEPs and devguide |

For modern changes, also read the linked issue, pull request, and discussion when available.

## 90.8 Standards Track PEPs

Standards Track PEPs are most relevant to implementation.

They often define:

```text
syntax
runtime behavior
new APIs
C API changes
standard library additions
compatibility guarantees
migration path
```

When implementing or modifying a Standards Track feature, check:

```text
grammar changes
AST changes
compiler changes
bytecode behavior
runtime helpers
documentation
tests
C API if exposed
```

A language PEP often touches the whole source-to-execution pipeline.

## 90.9 Informational PEPs

Informational PEPs explain a design, convention, or ecosystem practice.

They may not directly require code changes, but they provide context.

Examples of informational concerns:

```text
style guidance
packaging conventions
interoperability norms
security context
historical explanation
```

For CPython internals, informational PEPs are useful when a behavior exists for ecosystem compatibility rather than pure implementation convenience.

## 90.10 Process PEPs

Process PEPs define how the project operates.

They may cover:

```text
governance
release cadence
deprecation policy
feature acceptance
backporting
version numbering
maintenance branches
```

Process PEPs matter when deciding whether a change belongs in:

```text
main branch only
a maintenance branch
a security branch
documentation only
a future version
```

They also affect whether a change needs a PEP at all.

## 90.11 Reading a PEP for Implementation

When reading a PEP as an implementer, extract the exact constraints.

Use this checklist:

```text
What user-visible behavior is required?
What syntax or API changes are specified?
What errors must be raised?
What compatibility constraints exist?
What edge cases are explicitly mentioned?
Which alternatives were rejected?
What tests should exist?
What documentation should change?
```

Then map those constraints to CPython subsystems:

| PEP concern | CPython area |
|---|---|
| Syntax | `Grammar/`, parser, AST |
| Static scoping | symbol table |
| Runtime execution | bytecode, evaluation loop |
| Object behavior | `Objects/` |
| Library API | `Lib/`, `Modules/` |
| C API | `Include/`, `Objects/`, `Doc/c-api/` |
| Import behavior | `Lib/importlib/`, `Python/import.c` |
| Documentation | `Doc/` |
| Tests | `Lib/test/` |

## 90.12 Reading Rejected Ideas

Rejected ideas are not filler.

They explain designs Python chose not to adopt.

This helps when you are tempted to "simplify" behavior.

Example reasons ideas get rejected:

```text
ambiguous syntax
too much runtime cost
breaks existing code
inconsistent with data model
hard to teach
hard to optimize
bad interaction with existing tools
C API compatibility burden
```

Rejected ideas also help you answer code review questions. Often a reviewer will ask why a simpler alternative was not chosen. The PEP may already answer it.

## 90.13 Reading Backward Compatibility Sections

Backward compatibility sections are critical.

They describe:

```text
source compatibility
binary compatibility
runtime behavior changes
deprecation path
warnings
migration strategy
```

For CPython, compatibility has several layers:

| Compatibility layer | Example |
|---|---|
| Python source | Existing Python programs continue to run |
| Runtime behavior | Existing semantics remain stable |
| C API source | Extension code still compiles |
| ABI | Existing extension binaries keep loading |
| Standard library | Existing imports and functions remain available |
| Tooling | Debuggers, profilers, linters, and type checkers can adapt |

A patch that ignores compatibility can be technically clean but unacceptable.

## 90.14 Reading the Reference Implementation

Some PEPs link to a reference implementation.

Read it carefully, but do not assume it exactly matches the final merged version.

A reference implementation may be:

```text
prototype-quality
outdated
partial
changed during review
superseded by later commits
```

Use it to understand the intended architecture, then compare with current CPython source.

## 90.15 Match PEP Text Against Current Code

A PEP may be older than the current implementation.

The final code may differ due to:

```text
review changes
bug fixes
performance work
later PEPs
backward compatibility discoveries
implementation constraints
```

Therefore, read both:

```text
PEP
current docs
current tests
current source
```

If they conflict, current language reference and tests usually reflect current behavior, but a serious conflict may indicate outdated documentation or an implementation bug.

## 90.16 PEPs and Tests

Tests should encode the accepted behavior.

When implementing a PEP, tests should cover:

```text
normal cases
edge cases
syntax errors
runtime errors
interactions with existing features
documentation examples
backward compatibility cases
```

For syntax features, include invalid syntax tests.

For runtime features, include error-path tests.

For C API features, include ownership and failure behavior where possible.

## 90.17 PEPs and Documentation

A PEP is not a replacement for documentation.

A PEP explains a change proposal. Documentation explains the finished behavior to users.

After a PEP is implemented, update:

```text
language reference
library reference
C API reference
tutorial if needed
What's New
docstrings if relevant
```

Do not require users to read the PEP to understand the feature.

## 90.18 PEPs and Code Review

PEPs are useful in code review because they provide an accepted design baseline.

A good review comment might say:

```text
The PEP specifies that this error must be raised during compilation, not execution. This path currently raises at runtime.
```

or:

```text
The rejected ideas section explicitly avoids this implicit conversion.
```

Use PEPs to clarify constraints, not to shut down discussion. Later bugs and implementation details may require careful interpretation.

## 90.19 When a Change Needs a PEP

A change may need a PEP when it affects:

```text
Python syntax
core language semantics
major standard library design
public C API design
backward compatibility at scale
release policy
governance
large ecosystem behavior
```

A change probably does not need a PEP when it is:

```text
small bug fix
internal refactor
test improvement
documentation clarification
minor performance improvement
private API cleanup
```

When unsure, inspect similar historical changes and project guidance.

## 90.20 Important PEP Families for CPython Internals

Some clusters of PEPs are especially important.

| Area | PEP themes |
|---|---|
| Syntax and compiler | assignment expressions, pattern matching, exception groups |
| Object model | descriptors, metaclasses, data model changes |
| Imports | import hooks, module specs, namespace packages |
| C API | stable ABI, multi-phase init, module state |
| Typing | annotations, generics, postponed evaluation |
| Concurrency | subinterpreters, per-interpreter GIL, free-threading |
| Packaging | wheels, metadata, build systems |
| Release process | annual releases, support windows |
| Governance | steering council and decision process |

A CPython internals reader should recognize which PEP family a subsystem belongs to.

## 90.21 Common Mistakes When Reading PEPs

| Mistake | Better approach |
|---|---|
| Reading a Draft as final behavior | Check status first |
| Ignoring rejected ideas | Use them to understand design boundaries |
| Treating implementation notes as language law | Separate semantics from implementation |
| Reading only the abstract | Read motivation, specification, compatibility |
| Ignoring later PEPs | Check whether the PEP was superseded or amended |
| Using PEP as user docs | Update proper documentation |
| Assuming current code exactly matches original PEP | Compare against source and tests |

## 90.22 Practical Reading Workflow

For a CPython change:

```text
1. Identify the feature or subsystem.
2. Find relevant PEPs.
3. Check each PEP status.
4. Read the abstract and motivation.
5. Read the specification closely.
6. Read backward compatibility notes.
7. Read rejected ideas.
8. Compare with current docs.
9. Compare with current tests.
10. Compare with current source.
11. Implement or review against the accepted behavior.
```

For a bug fix, this workflow may take minutes. For a language change, it may define the whole project plan.

## 90.23 Core Principle

A PEP is design memory.

The CPython source records the implementation. The test suite records expected behavior. The documentation explains the public contract. The PEP records why the contract exists and which alternatives were considered. Serious CPython work uses all four.
