← Back to PR Bug Fix Database
7
High
PR-pip-13922

Fix: Use locale.getencoding() on Python 3.11+ to avoid DeprecationWarning

HighRepo: pypa/pipDate: June 25, 2026
PR FixpipBug FixEdge Case

// The Bug

Fixed pypa/pip#13922 — 11 line bug-fix replacing deprecated locale.getpreferredencoding() with locale.getencoding() on Python 3.11+.

Repository
pypa/pip
Issue
Status
PR-submitted
Fix Scope
11 lines changed in `src/pip/_internal/configuration.py`
Description
Use `locale.getencoding()` on Python 3.11+ to avoid DeprecationWarning from `locale.getpreferredencoding()`.

// Root Cause

Python 3.11 deprecated `locale.getpreferredencoding()` with `do_setlocale=False` in favor of the more explicit `locale.getencoding()`. Pip's `Configuration` class and `parse_reqfile` helper both called the deprecated function to determine the system locale encoding when reading config files and requirement files.

The deprecation produces a `DeprecationWarning` at runtime. While the warning is silent by default in CPython, it surfaces in CI pipelines running with `-W error` or `-X dev` mode — breaking builds that treat warnings as errors. The fix is a version-gated switch: use `locale.getencoding()` on Python 3.11+ and fall back to the deprecated path on older interpreters.

### Fix Location

The change touches three distinct sites in `src/pip/_internal/configuration.py`:

1. **`Configuration.__init__`** — reading pip config files with locale-aware encoding
2. **`_decode_req_file`** — decoding requirement file contents when the default encoding fails
3. **Test mocks** — updating the test suite to patch both `getpreferredencoding` and `getencoding`

### Why It Was Missed

The deprecation entered in Python 3.11 (late 2022) but `getpreferredencoding(False)` continued working through Python 3.13 with only a warning. Most test environments ran on Python 3.12+ without `-W error`, so the deprecation flew under the radar. It surfaced only when users upgraded CI runners to Python 3.13 with strict warning policies.

// The Fix

Diff showing the exact changes made to fix the bug.

@@ -293,7 +293,10 @@ class Configuration:
         if os.path.exists(fname):
-            locale_encoding = locale.getpreferredencoding(False)
+            if sys.version_info >= (3, 11):
+                locale_encoding = locale.getencoding()
+            else:
+                locale_encoding = locale.getpreferredencoding(False)

// Pattern & Takeaways

**Pattern**: Version-gated API migration when a language deprecates a commonly-used standard library function. The fix pattern generalizes to any Python project using `locale.getpreferredencoding()` or similar deprecated stdlib interfaces.

**Key insight**: When a stdlib function enters deprecation, the safest migration path uses a version gate with a fallback. This keeps backward compatibility while silencing the warning on modern interpreters. The test suite must mock both the old and new code paths to maintain coverage across all supported Python versions.

**Code review checklist for stdlib deprecation fixes:**
1. Identify all call sites — a single deprecation can appear in multiple functions within the same module
2. Mock both the old and new APIs in tests — otherwise CI passes on 3.12 but breaks on 3.9
3. Verify the fallback path — `locale.getencoding()` can return `None` on some systems, so handle that case explicitly