diff --git a/Misc/NEWS.d/next/Build/2026-09-07-15-13-19.gh-issue-155292._WNxL7.rst b/Misc/NEWS.d/next/Build/2026-09-07-15-13-19.gh-issue-155292._WNxL7.rst new file mode 100644 index 000000000000000..daa9746938d3b6b --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-09-07-15-13-19.gh-issue-155292._WNxL7.rst @@ -0,0 +1,3 @@ +In ``makeunicodedata.py``, the script for updating Unicode data, skip +generating ``stringprep.py`` if the current interpreter's Unicode data +version does not match the target version. diff --git a/Tools/unicode/makeunicodedata.py b/Tools/unicode/makeunicodedata.py index ab453686d4dfb1a..32019b35c9f62bf 100644 --- a/Tools/unicode/makeunicodedata.py +++ b/Tools/unicode/makeunicodedata.py @@ -40,6 +40,9 @@ SCRIPT = os.path.normpath(sys.argv[0]) VERSION = "3.3" +# Local cache location +DATA_DIR = os.path.join('Tools', 'unicode', 'data') + # The Unicode Database # -------------------- # When changing UCD version please update @@ -816,10 +819,31 @@ def makeunicodename(unicode, trace): def makestringprep(): FILE = "Lib/stringprep.py" + RFC_LOCAL = os.path.join(DATA_DIR, "rfc3454.txt") + RFC_URL = "https://www.rfc-editor.org/rfc/rfc3454.txt" + print("--- Preparing", FILE, "...") + # mkstringprep expects a local copy of RFC 3454. Download it now. + # (stringprep is used for URL handling, and if it's not matched + # with the compiled unicodedata, downloads would fail.) + if not os.path.exists(RFC_LOCAL): + download_data(RFC_LOCAL, RFC_URL) + MKSTRINGPREP = "Tools/unicode/mkstringprep.py" + # mkstringprep needs to be run with a Python version that has "its" + # unicode data, since it uses str.lower() and similar. + import unicodedata + if unicodedata.unidata_version != UNIDATA_VERSION: + print() + print("!! Skipping mkstringprep -- mimatched Unicode version !!") + print() + print("Please compile CPython with the updated Unicode database,") + print("then use that interpreter to run:") + print(f" python {MKSTRINGPREP} > {FILE}") + return + with open(FILE, "w") as f: f.truncate() subprocess.check_call([sys.executable, MKSTRINGPREP], stdout=f) @@ -929,19 +953,15 @@ class Difference(Exception):pass normalization_changes)) -DATA_DIR = os.path.join('Tools', 'unicode', 'data') - def open_data(template, version): local = os.path.join(DATA_DIR, template % ('-'+version,)) if not os.path.exists(local): - import urllib.request if version == '3.2.0': # irregular url structure url = ('https://www.unicode.org/Public/3.2-Update/'+template) % ('-'+version,) else: url = ('https://www.unicode.org/Public/%s/ucd/'+template) % (version, '') - os.makedirs(os.path.dirname(local), exist_ok=True) - urllib.request.urlretrieve(url, filename=local) + download_data(local, url) if local.endswith('.txt'): return open(local, encoding='utf-8') else: @@ -949,6 +969,13 @@ def open_data(template, version): return open(local, 'rb') +def download_data(local, url): + import urllib.request + os.makedirs(os.path.dirname(local), exist_ok=True) + print(f'Downloading {url} to {local}') + urllib.request.urlretrieve(url, filename=local) + + def expand_range(char_range: str) -> Iterator[int]: ''' Parses ranges of code points, as described in UAX #44: diff --git a/Tools/unicode/mkstringprep.py b/Tools/unicode/mkstringprep.py index 9740338fef9d3d4..60052aae3b62983 100644 --- a/Tools/unicode/mkstringprep.py +++ b/Tools/unicode/mkstringprep.py @@ -1,11 +1,7 @@ import re -import os import unicodedata as unicodedata_current from unicodedata import ucd_3_2_0 as unicodedata_320 -FILENAME = "Tools/unicode/data/rfc3454.txt" -URL = "https://www.rfc-editor.org/rfc/rfc3454.txt" - def gen_category(cats): for i in range(0, 0x110000): if unicodedata_320.category(chr(i)) in cats: @@ -52,15 +48,7 @@ def compact_set(l): ############## Read the tables in the RFC ####################### -try: - data_file = open(FILENAME, encoding='utf-8') -except FileNotFoundError: - import urllib.request - os.makedirs(os.path.dirname(FILENAME), exist_ok=True) - urllib.request.urlretrieve(URL, filename=FILENAME) - data_file = open(FILENAME, encoding='utf-8') - -with data_file: +with open("Tools/unicode/data/rfc3454.txt", encoding='utf-8') as data_file: data = data_file.readlines() tables = []