mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
	
	
		
			345 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			345 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
|   | # | ||
|  | # Copyright (c) 2008-2012 Stefan Krah. All rights reserved. | ||
|  | # | ||
|  | # Redistribution and use in source and binary forms, with or without | ||
|  | # modification, are permitted provided that the following conditions | ||
|  | # are met: | ||
|  | # | ||
|  | # 1. Redistributions of source code must retain the above copyright | ||
|  | #    notice, this list of conditions and the following disclaimer. | ||
|  | # | ||
|  | # 2. Redistributions in binary form must reproduce the above copyright | ||
|  | #    notice, this list of conditions and the following disclaimer in the | ||
|  | #    documentation and/or other materials provided with the distribution. | ||
|  | # | ||
|  | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND | ||
|  | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
|  | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
|  | # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
|  | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
|  | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
|  | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
|  | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
|  | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
|  | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
|  | # SUCH DAMAGE. | ||
|  | # | ||
|  | 
 | ||
|  | 
 | ||
|  | # Generate PEP-3101 format strings. | ||
|  | 
 | ||
|  | 
 | ||
|  | import os, sys, locale, random | ||
|  | import platform, subprocess | ||
|  | from test.support import import_fresh_module | ||
|  | from distutils.spawn import find_executable | ||
|  | 
 | ||
|  | C = import_fresh_module('decimal', fresh=['_decimal']) | ||
|  | P = import_fresh_module('decimal', blocked=['_decimal']) | ||
|  | 
 | ||
|  | 
 | ||
|  | windows_lang_strings = [ | ||
|  |   "chinese", "chinese-simplified", "chinese-traditional", "czech", "danish", | ||
|  |   "dutch", "belgian", "english", "australian", "canadian", "english-nz", | ||
|  |   "english-uk", "english-us", "finnish", "french", "french-belgian", | ||
|  |   "french-canadian", "french-swiss", "german", "german-austrian", | ||
|  |   "german-swiss", "greek", "hungarian", "icelandic", "italian", "italian-swiss", | ||
|  |   "japanese", "korean", "norwegian", "norwegian-bokmal", "norwegian-nynorsk", | ||
|  |   "polish", "portuguese", "portuguese-brazil", "russian", "slovak", "spanish", | ||
|  |   "spanish-mexican", "spanish-modern", "swedish", "turkish", | ||
|  | ] | ||
|  | 
 | ||
|  | preferred_encoding = { | ||
|  |   'cs_CZ': 'ISO8859-2', | ||
|  |   'cs_CZ.iso88592': 'ISO8859-2', | ||
|  |   'czech': 'ISO8859-2', | ||
|  |   'eesti': 'ISO8859-1', | ||
|  |   'estonian': 'ISO8859-1', | ||
|  |   'et_EE': 'ISO8859-15', | ||
|  |   'et_EE.ISO-8859-15': 'ISO8859-15', | ||
|  |   'et_EE.iso885915': 'ISO8859-15', | ||
|  |   'et_EE.iso88591': 'ISO8859-1', | ||
|  |   'fi_FI.iso88591': 'ISO8859-1', | ||
|  |   'fi_FI': 'ISO8859-15', | ||
|  |   'fi_FI@euro': 'ISO8859-15', | ||
|  |   'fi_FI.iso885915@euro': 'ISO8859-15', | ||
|  |   'finnish': 'ISO8859-1', | ||
|  |   'lv_LV': 'ISO8859-13', | ||
|  |   'lv_LV.iso885913': 'ISO8859-13', | ||
|  |   'nb_NO': 'ISO8859-1', | ||
|  |   'nb_NO.iso88591': 'ISO8859-1', | ||
|  |   'bokmal': 'ISO8859-1', | ||
|  |   'nn_NO': 'ISO8859-1', | ||
|  |   'nn_NO.iso88591': 'ISO8859-1', | ||
|  |   'no_NO': 'ISO8859-1', | ||
|  |   'norwegian': 'ISO8859-1', | ||
|  |   'nynorsk': 'ISO8859-1', | ||
|  |   'ru_RU': 'ISO8859-5', | ||
|  |   'ru_RU.iso88595': 'ISO8859-5', | ||
|  |   'russian': 'ISO8859-5', | ||
|  |   'ru_RU.KOI8-R': 'KOI8-R', | ||
|  |   'ru_RU.koi8r': 'KOI8-R', | ||
|  |   'ru_RU.CP1251': 'CP1251', | ||
|  |   'ru_RU.cp1251': 'CP1251', | ||
|  |   'sk_SK': 'ISO8859-2', | ||
|  |   'sk_SK.iso88592': 'ISO8859-2', | ||
|  |   'slovak': 'ISO8859-2', | ||
|  |   'sv_FI': 'ISO8859-1', | ||
|  |   'sv_FI.iso88591': 'ISO8859-1', | ||
|  |   'sv_FI@euro': 'ISO8859-15', | ||
|  |   'sv_FI.iso885915@euro': 'ISO8859-15', | ||
|  |   'uk_UA': 'KOI8-U', | ||
|  |   'uk_UA.koi8u': 'KOI8-U' | ||
|  | } | ||
|  | 
 | ||
|  | integers = [ | ||
|  |   "", | ||
|  |   "1", | ||
|  |   "12", | ||
|  |   "123", | ||
|  |   "1234", | ||
|  |   "12345", | ||
|  |   "123456", | ||
|  |   "1234567", | ||
|  |   "12345678", | ||
|  |   "123456789", | ||
|  |   "1234567890", | ||
|  |   "12345678901", | ||
|  |   "123456789012", | ||
|  |   "1234567890123", | ||
|  |   "12345678901234", | ||
|  |   "123456789012345", | ||
|  |   "1234567890123456", | ||
|  |   "12345678901234567", | ||
|  |   "123456789012345678", | ||
|  |   "1234567890123456789", | ||
|  |   "12345678901234567890", | ||
|  |   "123456789012345678901", | ||
|  |   "1234567890123456789012", | ||
|  | ] | ||
|  | 
 | ||
|  | numbers = [ | ||
|  |   "0", "-0", "+0", | ||
|  |   "0.0", "-0.0", "+0.0", | ||
|  |   "0e0", "-0e0", "+0e0", | ||
|  |   ".0", "-.0", | ||
|  |   ".1", "-.1", | ||
|  |   "1.1", "-1.1", | ||
|  |   "1e1", "-1e1" | ||
|  | ] | ||
|  | 
 | ||
|  | # Get the list of available locales. | ||
|  | if platform.system() == 'Windows': | ||
|  |     locale_list = windows_lang_strings | ||
|  | else: | ||
|  |     locale_list = ['C'] | ||
|  |     if os.path.isfile("/var/lib/locales/supported.d/local"): | ||
|  |         # On Ubuntu, `locale -a` gives the wrong case for some locales, | ||
|  |         # so we get the correct names directly: | ||
|  |         with open("/var/lib/locales/supported.d/local") as f: | ||
|  |             locale_list = [loc.split()[0] for loc in f.readlines() \ | ||
|  |                            if not loc.startswith('#')] | ||
|  |     elif find_executable('locale'): | ||
|  |         locale_list = subprocess.Popen(["locale", "-a"], | ||
|  |                           stdout=subprocess.PIPE).communicate()[0] | ||
|  |         try: | ||
|  |             locale_list = locale_list.decode() | ||
|  |         except UnicodeDecodeError: | ||
|  |             # Some distributions insist on using latin-1 characters | ||
|  |             # in their locale names. | ||
|  |             locale_list = locale_list.decode('latin-1') | ||
|  |         locale_list = locale_list.split('\n') | ||
|  | try: | ||
|  |     locale_list.remove('') | ||
|  | except ValueError: | ||
|  |     pass | ||
|  | 
 | ||
|  | # Debian | ||
|  | if os.path.isfile("/etc/locale.alias"): | ||
|  |     with open("/etc/locale.alias") as f: | ||
|  |         while 1: | ||
|  |             try: | ||
|  |                 line = f.readline() | ||
|  |             except UnicodeDecodeError: | ||
|  |                 continue | ||
|  |             if line == "": | ||
|  |                 break | ||
|  |             if line.startswith('#'): | ||
|  |                 continue | ||
|  |             x = line.split() | ||
|  |             if len(x) == 2: | ||
|  |                 if x[0] in locale_list: | ||
|  |                     locale_list.remove(x[0]) | ||
|  | 
 | ||
|  | # FreeBSD | ||
|  | if platform.system() == 'FreeBSD': | ||
|  |     # http://www.freebsd.org/cgi/query-pr.cgi?pr=142173 | ||
|  |     # en_GB.US-ASCII has 163 as the currency symbol. | ||
|  |     for loc in ['it_CH.ISO8859-1', 'it_CH.ISO8859-15', 'it_CH.UTF-8', | ||
|  |                 'it_IT.ISO8859-1', 'it_IT.ISO8859-15', 'it_IT.UTF-8', | ||
|  |                 'sl_SI.ISO8859-2', 'sl_SI.UTF-8', | ||
|  |                 'en_GB.US-ASCII']: | ||
|  |         try: | ||
|  |             locale_list.remove(loc) | ||
|  |         except ValueError: | ||
|  |             pass | ||
|  | 
 | ||
|  | # Print a testcase in the format of the IBM tests (for runtest.c): | ||
|  | def get_preferred_encoding(): | ||
|  |     loc = locale.setlocale(locale.LC_CTYPE) | ||
|  |     if loc in preferred_encoding: | ||
|  |         return preferred_encoding[loc] | ||
|  |     else: | ||
|  |         return locale.getpreferredencoding() | ||
|  | 
 | ||
|  | def printit(testno, s, fmt, encoding=None): | ||
|  |     if not encoding: | ||
|  |         encoding = get_preferred_encoding() | ||
|  |     try: | ||
|  |         result = format(P.Decimal(s), fmt) | ||
|  |         fmt = str(fmt.encode(encoding))[2:-1] | ||
|  |         result = str(result.encode(encoding))[2:-1] | ||
|  |         if "'" in result: | ||
|  |             sys.stdout.write("xfmt%d  format  %s  '%s'  ->  \"%s\"\n" | ||
|  |                              % (testno, s, fmt, result)) | ||
|  |         else: | ||
|  |             sys.stdout.write("xfmt%d  format  %s  '%s'  ->  '%s'\n" | ||
|  |                              % (testno, s, fmt, result)) | ||
|  |     except Exception as err: | ||
|  |         sys.stderr.write("%s  %s  %s\n" % (err, s, fmt)) | ||
|  | 
 | ||
|  | 
 | ||
|  | # Check if an integer can be converted to a valid fill character. | ||
|  | def check_fillchar(i): | ||
|  |     try: | ||
|  |         c = chr(i) | ||
|  |         c.encode('utf-8').decode() | ||
|  |         format(P.Decimal(0), c + '<19g') | ||
|  |         if c in ("'", '"', '\\'): | ||
|  |             return None | ||
|  |         return c | ||
|  |     except: | ||
|  |         return None | ||
|  | 
 | ||
|  | # Generate all unicode characters that are accepted as | ||
|  | # fill characters by decimal.py. | ||
|  | def all_fillchars(): | ||
|  |     for i in range(32, 0x110002): | ||
|  |         c = check_fillchar(i) | ||
|  |         if c: yield c | ||
|  | 
 | ||
|  | # Return random fill character. | ||
|  | def rand_fillchar(): | ||
|  |     while 1: | ||
|  |         i = random.randrange(32, 0x110002) | ||
|  |         c = check_fillchar(i) | ||
|  |         if c: return c | ||
|  | 
 | ||
|  | # Generate random format strings | ||
|  | # [[fill]align][sign][#][0][width][.precision][type] | ||
|  | def rand_format(fill, typespec='EeGgFfn%'): | ||
|  |     active = sorted(random.sample(range(7), random.randrange(8))) | ||
|  |     have_align = 0 | ||
|  |     s = '' | ||
|  |     for elem in active: | ||
|  |         if elem == 0: # fill+align | ||
|  |             s += fill | ||
|  |             s += random.choice('<>=^') | ||
|  |             have_align = 1 | ||
|  |         elif elem == 1: # sign | ||
|  |             s += random.choice('+- ') | ||
|  |         elif elem == 2 and not have_align: # zeropad | ||
|  |             s += '0' | ||
|  |         elif elem == 3: # width | ||
|  |             s += str(random.randrange(1, 100)) | ||
|  |         elif elem == 4: # thousands separator | ||
|  |             s += ',' | ||
|  |         elif elem == 5: # prec | ||
|  |             s += '.' | ||
|  |             s += str(random.randrange(100)) | ||
|  |         elif elem == 6: | ||
|  |             if 4 in active: c = typespec.replace('n', '') | ||
|  |             else: c = typespec | ||
|  |             s += random.choice(c) | ||
|  |     return s | ||
|  | 
 | ||
|  | # Partially brute force all possible format strings containing a thousands | ||
|  | # separator. Fall back to random where the runtime would become excessive. | ||
|  | # [[fill]align][sign][#][0][width][,][.precision][type] | ||
|  | def all_format_sep(): | ||
|  |     for align in ('', '<', '>', '=', '^'): | ||
|  |         for fill in ('', 'x'): | ||
|  |             if align == '': fill = '' | ||
|  |             for sign in ('', '+', '-', ' '): | ||
|  |                 for zeropad in ('', '0'): | ||
|  |                     if align != '': zeropad = '' | ||
|  |                     for width in ['']+[str(y) for y in range(1, 15)]+['101']: | ||
|  |                         for prec in ['']+['.'+str(y) for y in range(15)]: | ||
|  |                             # for type in ('', 'E', 'e', 'G', 'g', 'F', 'f', '%'): | ||
|  |                             type = random.choice(('', 'E', 'e', 'G', 'g', 'F', 'f', '%')) | ||
|  |                             yield ''.join((fill, align, sign, zeropad, width, ',', prec, type)) | ||
|  | 
 | ||
|  | # Partially brute force all possible format strings with an 'n' specifier. | ||
|  | # [[fill]align][sign][#][0][width][,][.precision][type] | ||
|  | def all_format_loc(): | ||
|  |     for align in ('', '<', '>', '=', '^'): | ||
|  |         for fill in ('', 'x'): | ||
|  |             if align == '': fill = '' | ||
|  |             for sign in ('', '+', '-', ' '): | ||
|  |                 for zeropad in ('', '0'): | ||
|  |                     if align != '': zeropad = '' | ||
|  |                     for width in ['']+[str(y) for y in range(1, 20)]+['101']: | ||
|  |                         for prec in ['']+['.'+str(y) for y in range(1, 20)]: | ||
|  |                             yield ''.join((fill, align, sign, zeropad, width, prec, 'n')) | ||
|  | 
 | ||
|  | # Generate random format strings with a unicode fill character | ||
|  | # [[fill]align][sign][#][0][width][,][.precision][type] | ||
|  | def randfill(fill): | ||
|  |     active = sorted(random.sample(range(5), random.randrange(6))) | ||
|  |     s = '' | ||
|  |     s += str(fill) | ||
|  |     s += random.choice('<>=^') | ||
|  |     for elem in active: | ||
|  |         if elem == 0: # sign | ||
|  |             s += random.choice('+- ') | ||
|  |         elif elem == 1: # width | ||
|  |             s += str(random.randrange(1, 100)) | ||
|  |         elif elem == 2: # thousands separator | ||
|  |             s += ',' | ||
|  |         elif elem == 3: # prec | ||
|  |             s += '.' | ||
|  |             s += str(random.randrange(100)) | ||
|  |         elif elem == 4: | ||
|  |             if 2 in active: c = 'EeGgFf%' | ||
|  |             else: c = 'EeGgFfn%' | ||
|  |             s += random.choice(c) | ||
|  |     return s | ||
|  | 
 | ||
|  | # Generate random format strings with random locale setting | ||
|  | # [[fill]align][sign][#][0][width][,][.precision][type] | ||
|  | def rand_locale(): | ||
|  |     try: | ||
|  |         loc = random.choice(locale_list) | ||
|  |         locale.setlocale(locale.LC_ALL, loc) | ||
|  |     except locale.Error as err: | ||
|  |         pass | ||
|  |     active = sorted(random.sample(range(5), random.randrange(6))) | ||
|  |     s = '' | ||
|  |     have_align = 0 | ||
|  |     for elem in active: | ||
|  |         if elem == 0: # fill+align | ||
|  |             s += chr(random.randrange(32, 128)) | ||
|  |             s += random.choice('<>=^') | ||
|  |             have_align = 1 | ||
|  |         elif elem == 1: # sign | ||
|  |             s += random.choice('+- ') | ||
|  |         elif elem == 2 and not have_align: # zeropad | ||
|  |             s += '0' | ||
|  |         elif elem == 3: # width | ||
|  |             s += str(random.randrange(1, 100)) | ||
|  |         elif elem == 4: # prec | ||
|  |             s += '.' | ||
|  |             s += str(random.randrange(100)) | ||
|  |     s += 'n' | ||
|  |     return s |