11import re
2- from unicodedata import ucd_3_2_0 as unicodedata
2+ import os
3+ import unicodedata as unicodedata_current
4+ from unicodedata import ucd_3_2_0 as unicodedata_320
5+
6+ FILENAME = "Tools/unicode/data/rfc3454.txt"
7+ URL = "https://www.rfc-editor.org/rfc/rfc3454.txt"
38
49def gen_category (cats ):
510 for i in range (0 , 0x110000 ):
6- if unicodedata .category (chr (i )) in cats :
7- yield ( i )
11+ if unicodedata_320 .category (chr (i )) in cats :
12+ yield i
813
914def gen_bidirectional (cats ):
1015 for i in range (0 , 0x110000 ):
11- if unicodedata .bidirectional (chr (i )) in cats :
12- yield ( i )
16+ if unicodedata_320 .bidirectional (chr (i )) in cats :
17+ yield i
1318
1419def compact_set (l ):
1520 single = []
@@ -47,8 +52,16 @@ def compact_set(l):
4752
4853############## Read the tables in the RFC #######################
4954
50- with open ("rfc3454.txt" ) as f :
51- data = f .readlines ()
55+ try :
56+ data_file = open (FILENAME , encoding = 'utf-8' )
57+ except FileNotFoundError :
58+ import urllib .request
59+ os .makedirs (os .path .dirname (FILENAME ), exist_ok = True )
60+ urllib .request .urlretrieve (URL , filename = FILENAME )
61+ data_file = open (FILENAME , encoding = 'utf-8' )
62+
63+ with data_file :
64+ data = data_file .readlines ()
5265
5366tables = []
5467curname = None
@@ -116,10 +129,18 @@ def compact_set(l):
116129and mappings, for which a mapping function is provided.
117130\" \" \"
118131
119- from unicodedata import ucd_3_2_0 as unicodedata
132+ # This check asserts that mkstringprep.py has been run
133+ # when unicodedata is modified to ensure conformant behavior.
134+ import unicodedata
135+ """ )
136+
137+ print ("assert unicodedata.unidata_version == %r" % (unicodedata_current .unidata_version ,))
138+
139+ print ("""
140+ from unicodedata import ucd_3_2_0 as unicodedata_320
120141""" )
121142
122- print ("assert unicodedata .unidata_version == %r" % (unicodedata .unidata_version ,))
143+ print ("assert unicodedata_320 .unidata_version == %r" % (unicodedata_320 .unidata_version ,))
123144
124145# A.1 is the table of unassigned characters
125146# XXX Plane 15 PUA is listed as unassigned in Python.
@@ -139,7 +160,7 @@ def compact_set(l):
139160
140161print ("""
141162def in_table_a1(code):
142- if unicodedata .category(code) != 'Cn': return False
163+ if unicodedata_320 .category(code) != 'Cn': return False
143164 c = ord(code)
144165 if 0xFDD0 <= c < 0xFDF0: return False
145166 return (c & 0xFFFF) not in (0xFFFE, 0xFFFF)
@@ -172,21 +193,33 @@ def in_table_b1(code):
172193
173194# B.3 is mostly Python's .lower, except for a number
174195# of special cases, e.g. considering canonical forms.
196+ # To enforce Unicode 3.2.0 behavior of .lower instead of
197+ # whatever Unicode version is included with Python we
198+ # add unassigned or newly case-folding codepoints to
199+ # the exception map, too.
175200
176201b3_exceptions = {}
177202
178203for k ,v in table_b2 .items ():
179204 if list (map (ord , chr (k ).lower ())) != v :
180205 b3_exceptions [k ] = "" .join (map (chr ,v ))
206+ for cp in range (0x110000 ):
207+ ch = chr (cp )
208+ # Assigned in current Unicode version
209+ # and supports case folding, but not
210+ # explicitly in B.2 or B.3 tables.
211+ if (unicodedata_current .category (ch ) != "Cn"
212+ and ch .lower () != ch
213+ and cp not in table_b2
214+ and cp not in table_b3 ):
215+ b3_exceptions [cp ] = ch # Identity.
181216
182217b3 = sorted (b3_exceptions .items ())
183218
184219print ("""
185220b3_exceptions = {""" )
186221for i , kv in enumerate (b3 ):
187- print ("0x%x:%a," % kv , end = ' ' )
188- if i % 4 == 3 :
189- print ()
222+ print ("0x%x:%a," % kv , end = '\n ' if i % 4 == 3 else ' ' )
190223print ("}" )
191224
192225print ("""
@@ -207,9 +240,9 @@ def map_table_b3(code):
207240
208241def map_table_b2 (a ):
209242 al = map_table_b3 (a )
210- b = unicodedata .normalize ("NFKC" , al )
243+ b = unicodedata_320 .normalize ("NFKC" , al )
211244 bl = "" .join ([map_table_b3 (ch ) for ch in b ])
212- c = unicodedata .normalize ("NFKC" , bl )
245+ c = unicodedata_320 .normalize ("NFKC" , bl )
213246 if b != c :
214247 return c
215248 else :
@@ -226,9 +259,9 @@ def map_table_b2(a):
226259print ("""
227260def map_table_b2(a):
228261 al = map_table_b3(a)
229- b = unicodedata .normalize("NFKC", al)
262+ b = unicodedata_320 .normalize("NFKC", al)
230263 bl = "".join([map_table_b3(ch) for ch in b])
231- c = unicodedata .normalize("NFKC", bl)
264+ c = unicodedata_320 .normalize("NFKC", bl)
232265 if b != c:
233266 return c
234267 else:
@@ -251,16 +284,16 @@ def in_table_c11(code):
251284del tables [0 ]
252285assert name == "C.1.2"
253286
254- # table = set(table.keys())
255- # Zs = set(gen_category(["Zs"])) - {0x20}
256- # assert Zs == table
287+ table = set (table .keys ())
288+ Zs = set (gen_category (["Zs" ])) - {0x20 }
289+ assert Zs == table
257290
258291print ("""
259292def in_table_c12(code):
260- return unicodedata .category(code) == "Zs" and code != " "
293+ return unicodedata_320 .category(code) == "Zs" and code != " "
261294
262295def in_table_c11_c12(code):
263- return unicodedata .category(code) == "Zs"
296+ return unicodedata_320 .category(code) == "Zs"
264297""" )
265298
266299# C.2.1 ASCII control characters
@@ -275,7 +308,7 @@ def in_table_c11_c12(code):
275308
276309print ("""
277310def in_table_c21(code):
278- return ord(code) < 128 and unicodedata .category(code) == "Cc"
311+ return ord(code) < 128 and unicodedata_320 .category(code) == "Cc"
279312""" )
280313
281314# C.2.2 Non-ASCII control characters. It also includes
@@ -295,11 +328,11 @@ def in_table_c21(code):
295328def in_table_c22(code):
296329 c = ord(code)
297330 if c < 128: return False
298- if unicodedata .category(code) == "Cc": return True
331+ if unicodedata_320 .category(code) == "Cc": return True
299332 return c in c22_specials
300333
301334def in_table_c21_c22(code):
302- return unicodedata .category(code) == "Cc" or \\
335+ return unicodedata_320 .category(code) == "Cc" or \\
303336 ord(code) in c22_specials
304337""" )
305338
@@ -313,7 +346,7 @@ def in_table_c21_c22(code):
313346
314347print ("""
315348def in_table_c3(code):
316- return unicodedata .category(code) == "Co"
349+ return unicodedata_320 .category(code) == "Co"
317350""" )
318351
319352# C.4 Non-character code points, xFFFE, xFFFF
@@ -346,7 +379,7 @@ def in_table_c4(code):
346379
347380print ("""
348381def in_table_c5(code):
349- return unicodedata .category(code) == "Cs"
382+ return unicodedata_320 .category(code) == "Cs"
350383""" )
351384
352385# C.6 Inappropriate for plain text
@@ -411,7 +444,7 @@ def in_table_c9(code):
411444
412445print ("""
413446def in_table_d1(code):
414- return unicodedata .bidirectional(code) in ("R","AL")
447+ return unicodedata_320 .bidirectional(code) in ("R","AL")
415448""" )
416449
417450# D.2 Characters with bidirectional property "L"
@@ -424,5 +457,5 @@ def in_table_d1(code):
424457
425458print ("""
426459def in_table_d2(code):
427- return unicodedata .bidirectional(code) == "L"
428- """ )
460+ return unicodedata_320 .bidirectional(code) == "L"
461+ """ , end = "" )
0 commit comments