From 1e6aa4b3a9247d7499c369e44e65f75ea7022022 Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Fri, 24 Jul 2026 13:18:10 +0000 Subject: [PATCH 1/5] Sample code for: Python 3.15 Preview: UTF-8 by Default --- python315-utf8-default/README.md | 3 +++ python315-utf8-default/app_v1.py | 6 ++++++ python315-utf8-default/app_v2.py | 4 ++++ python315-utf8-default/constants.py | 1 + python315-utf8-default/example_001.py | 5 +++++ python315-utf8-default/example_002.py | 3 +++ python315-utf8-default/example_004.py | 2 ++ python315-utf8-default/main.py | 3 +++ python315-utf8-default/textlib.py | 7 +++++++ 9 files changed, 34 insertions(+) create mode 100644 python315-utf8-default/README.md create mode 100644 python315-utf8-default/app_v1.py create mode 100644 python315-utf8-default/app_v2.py create mode 100644 python315-utf8-default/constants.py create mode 100644 python315-utf8-default/example_001.py create mode 100644 python315-utf8-default/example_002.py create mode 100644 python315-utf8-default/example_004.py create mode 100644 python315-utf8-default/main.py create mode 100644 python315-utf8-default/textlib.py diff --git a/python315-utf8-default/README.md b/python315-utf8-default/README.md new file mode 100644 index 0000000000..ff4e56e470 --- /dev/null +++ b/python315-utf8-default/README.md @@ -0,0 +1,3 @@ +# Python 3.15 Preview: UTF-8 by Default + +This folder provides the code examples for the Real Python tutorial [Python 3.15 Preview: UTF-8 by Default](https://realpython.com/python315-utf8-default/) diff --git a/python315-utf8-default/app_v1.py b/python315-utf8-default/app_v1.py new file mode 100644 index 0000000000..293e7c5191 --- /dev/null +++ b/python315-utf8-default/app_v1.py @@ -0,0 +1,6 @@ +import json + +with open("data.json") as f: + data = json.load(f) + +print(f"Loaded {len(data)} entries") diff --git a/python315-utf8-default/app_v2.py b/python315-utf8-default/app_v2.py new file mode 100644 index 0000000000..f296fe6b04 --- /dev/null +++ b/python315-utf8-default/app_v2.py @@ -0,0 +1,4 @@ +from constants import ENCODING + +with open("data.json", encoding=ENCODING) as f: + data = f.read() diff --git a/python315-utf8-default/constants.py b/python315-utf8-default/constants.py new file mode 100644 index 0000000000..008e45dad7 --- /dev/null +++ b/python315-utf8-default/constants.py @@ -0,0 +1 @@ +ENCODING = "utf-8" # Single source of truth for text I/O diff --git a/python315-utf8-default/example_001.py b/python315-utf8-default/example_001.py new file mode 100644 index 0000000000..62d8e79ae4 --- /dev/null +++ b/python315-utf8-default/example_001.py @@ -0,0 +1,5 @@ +with open("data.json", encoding="utf-8") as f: # Portable and unambiguous + data = f.read() + +with open("legacy.csv", encoding="locale") as f: # Intentional locale use + legacy = f.read() diff --git a/python315-utf8-default/example_002.py b/python315-utf8-default/example_002.py new file mode 100644 index 0000000000..0038a4a521 --- /dev/null +++ b/python315-utf8-default/example_002.py @@ -0,0 +1,3 @@ +import locale + +print(locale.getencoding()) # The real OS encoding, ignores UTF-8 Mode diff --git a/python315-utf8-default/example_004.py b/python315-utf8-default/example_004.py new file mode 100644 index 0000000000..b575dce912 --- /dev/null +++ b/python315-utf8-default/example_004.py @@ -0,0 +1,2 @@ +with open("legacy.csv", encoding="locale") as f: + legacy = f.read() diff --git a/python315-utf8-default/main.py b/python315-utf8-default/main.py new file mode 100644 index 0000000000..9b3a62bb9a --- /dev/null +++ b/python315-utf8-default/main.py @@ -0,0 +1,3 @@ +import textlib + +textlib.read_text("notes.txt") diff --git a/python315-utf8-default/textlib.py b/python315-utf8-default/textlib.py new file mode 100644 index 0000000000..6a93c71bd1 --- /dev/null +++ b/python315-utf8-default/textlib.py @@ -0,0 +1,7 @@ +import io + + +def read_text(path, encoding=None): + encoding = io.text_encoding(encoding) # Points at the caller + with open(path, encoding=encoding) as f: + return f.read() From a719168161af805fac6aee33e7fe1d35ab8b128f Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Fri, 24 Jul 2026 13:29:40 +0000 Subject: [PATCH 2/5] Rename example files descriptively and print entry count in app_v2 --- python315-utf8-default/app_v2.py | 2 ++ python315-utf8-default/{example_001.py => explicit_encoding.py} | 0 python315-utf8-default/{example_004.py => locale_encoding.py} | 0 python315-utf8-default/{example_002.py => os_encoding.py} | 0 4 files changed, 2 insertions(+) rename python315-utf8-default/{example_001.py => explicit_encoding.py} (100%) rename python315-utf8-default/{example_004.py => locale_encoding.py} (100%) rename python315-utf8-default/{example_002.py => os_encoding.py} (100%) diff --git a/python315-utf8-default/app_v2.py b/python315-utf8-default/app_v2.py index f296fe6b04..cd8f8c3b62 100644 --- a/python315-utf8-default/app_v2.py +++ b/python315-utf8-default/app_v2.py @@ -2,3 +2,5 @@ with open("data.json", encoding=ENCODING) as f: data = f.read() + +print(f"Loaded {len(data)} entries") diff --git a/python315-utf8-default/example_001.py b/python315-utf8-default/explicit_encoding.py similarity index 100% rename from python315-utf8-default/example_001.py rename to python315-utf8-default/explicit_encoding.py diff --git a/python315-utf8-default/example_004.py b/python315-utf8-default/locale_encoding.py similarity index 100% rename from python315-utf8-default/example_004.py rename to python315-utf8-default/locale_encoding.py diff --git a/python315-utf8-default/example_002.py b/python315-utf8-default/os_encoding.py similarity index 100% rename from python315-utf8-default/example_002.py rename to python315-utf8-default/os_encoding.py From 74a897f3ff825e03adaf1263be03e89f1578cfce Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Fri, 31 Jul 2026 10:25:24 +0000 Subject: [PATCH 3/5] Add data files read by the sample scripts Ship data.json, legacy.csv, and notes.txt so every script runs on first try instead of raising FileNotFoundError. Also align the os_encoding.py comment with the tutorial's lowercase "UTF-8 mode". --- python315-utf8-default/data.json | 1 + python315-utf8-default/legacy.csv | 4 ++++ python315-utf8-default/notes.txt | 1 + python315-utf8-default/os_encoding.py | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 python315-utf8-default/data.json create mode 100644 python315-utf8-default/legacy.csv create mode 100644 python315-utf8-default/notes.txt diff --git a/python315-utf8-default/data.json b/python315-utf8-default/data.json new file mode 100644 index 0000000000..2fd88d105c --- /dev/null +++ b/python315-utf8-default/data.json @@ -0,0 +1 @@ +{"café": "☕", "naïve": true} diff --git a/python315-utf8-default/legacy.csv b/python315-utf8-default/legacy.csv new file mode 100644 index 0000000000..5b68c933ed --- /dev/null +++ b/python315-utf8-default/legacy.csv @@ -0,0 +1,4 @@ +id,name,quantity +1,espresso,12 +2,americano,8 +3,macchiato,5 diff --git a/python315-utf8-default/notes.txt b/python315-utf8-default/notes.txt new file mode 100644 index 0000000000..7d19130a1f --- /dev/null +++ b/python315-utf8-default/notes.txt @@ -0,0 +1 @@ +Remember to pass an explicit encoding to every text-mode open() call. diff --git a/python315-utf8-default/os_encoding.py b/python315-utf8-default/os_encoding.py index 0038a4a521..1dd21ecc41 100644 --- a/python315-utf8-default/os_encoding.py +++ b/python315-utf8-default/os_encoding.py @@ -1,3 +1,3 @@ import locale -print(locale.getencoding()) # The real OS encoding, ignores UTF-8 Mode +print(locale.getencoding()) # The real OS encoding, ignores UTF-8 mode From 9d15c058ea566845692a15b7e3b376b7a156ebcb Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Fri, 31 Jul 2026 10:40:41 +0000 Subject: [PATCH 4/5] Keep app.py parsing JSON after adding the explicit encoding app_v2.py read the file as raw text, so len(data) counted characters and printed "Loaded 29 entries". Restore json.load() so the only difference from app_v1.py is the encoding argument, matching the tutorial. --- python315-utf8-default/app_v2.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python315-utf8-default/app_v2.py b/python315-utf8-default/app_v2.py index cd8f8c3b62..77592654be 100644 --- a/python315-utf8-default/app_v2.py +++ b/python315-utf8-default/app_v2.py @@ -1,6 +1,8 @@ +import json + from constants import ENCODING with open("data.json", encoding=ENCODING) as f: - data = f.read() + data = json.load(f) print(f"Loaded {len(data)} entries") From 13f5f6cf84ade627f7ceddd434155c5cf3320b3c Mon Sep 17 00:00:00 2001 From: Leodanis Pozo Ramos Date: Fri, 31 Jul 2026 10:43:25 +0000 Subject: [PATCH 5/5] Parse data.json with json.load() in explicit_encoding.py Keeps data.json handling consistent with app_v1.py and app_v2.py across the tutorial's examples. legacy.csv stays a raw read, since the point there is the locale sentinel rather than parsing. --- python315-utf8-default/explicit_encoding.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python315-utf8-default/explicit_encoding.py b/python315-utf8-default/explicit_encoding.py index 62d8e79ae4..969352b0ea 100644 --- a/python315-utf8-default/explicit_encoding.py +++ b/python315-utf8-default/explicit_encoding.py @@ -1,5 +1,7 @@ +import json + with open("data.json", encoding="utf-8") as f: # Portable and unambiguous - data = f.read() + data = json.load(f) with open("legacy.csv", encoding="locale") as f: # Intentional locale use legacy = f.read()