Path: blob/main/Modules/_decimal/tests/formathelper.py
12 views
#1# Copyright (c) 2008-2012 Stefan Krah. All rights reserved.2#3# Redistribution and use in source and binary forms, with or without4# modification, are permitted provided that the following conditions5# are met:6#7# 1. Redistributions of source code must retain the above copyright8# notice, this list of conditions and the following disclaimer.9#10# 2. Redistributions in binary form must reproduce the above copyright11# notice, this list of conditions and the following disclaimer in the12# documentation and/or other materials provided with the distribution.13#14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND15# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24# SUCH DAMAGE.25#262728# Generate PEP-3101 format strings.293031import os, sys, locale, random32import platform, subprocess33from test.support.import_helper import import_fresh_module34from shutil import which3536C = import_fresh_module('decimal', fresh=['_decimal'])37P = import_fresh_module('decimal', blocked=['_decimal'])383940windows_lang_strings = [41"chinese", "chinese-simplified", "chinese-traditional", "czech", "danish",42"dutch", "belgian", "english", "australian", "canadian", "english-nz",43"english-uk", "english-us", "finnish", "french", "french-belgian",44"french-canadian", "french-swiss", "german", "german-austrian",45"german-swiss", "greek", "hungarian", "icelandic", "italian", "italian-swiss",46"japanese", "korean", "norwegian", "norwegian-bokmal", "norwegian-nynorsk",47"polish", "portuguese", "portuguese-brazil", "russian", "slovak", "spanish",48"spanish-mexican", "spanish-modern", "swedish", "turkish",49]5051preferred_encoding = {52'cs_CZ': 'ISO8859-2',53'cs_CZ.iso88592': 'ISO8859-2',54'czech': 'ISO8859-2',55'eesti': 'ISO8859-1',56'estonian': 'ISO8859-1',57'et_EE': 'ISO8859-15',58'et_EE.ISO-8859-15': 'ISO8859-15',59'et_EE.iso885915': 'ISO8859-15',60'et_EE.iso88591': 'ISO8859-1',61'fi_FI.iso88591': 'ISO8859-1',62'fi_FI': 'ISO8859-15',63'fi_FI@euro': 'ISO8859-15',64'fi_FI.iso885915@euro': 'ISO8859-15',65'finnish': 'ISO8859-1',66'lv_LV': 'ISO8859-13',67'lv_LV.iso885913': 'ISO8859-13',68'nb_NO': 'ISO8859-1',69'nb_NO.iso88591': 'ISO8859-1',70'bokmal': 'ISO8859-1',71'nn_NO': 'ISO8859-1',72'nn_NO.iso88591': 'ISO8859-1',73'no_NO': 'ISO8859-1',74'norwegian': 'ISO8859-1',75'nynorsk': 'ISO8859-1',76'ru_RU': 'ISO8859-5',77'ru_RU.iso88595': 'ISO8859-5',78'russian': 'ISO8859-5',79'ru_RU.KOI8-R': 'KOI8-R',80'ru_RU.koi8r': 'KOI8-R',81'ru_RU.CP1251': 'CP1251',82'ru_RU.cp1251': 'CP1251',83'sk_SK': 'ISO8859-2',84'sk_SK.iso88592': 'ISO8859-2',85'slovak': 'ISO8859-2',86'sv_FI': 'ISO8859-1',87'sv_FI.iso88591': 'ISO8859-1',88'sv_FI@euro': 'ISO8859-15',89'sv_FI.iso885915@euro': 'ISO8859-15',90'uk_UA': 'KOI8-U',91'uk_UA.koi8u': 'KOI8-U'92}9394integers = [95"",96"1",97"12",98"123",99"1234",100"12345",101"123456",102"1234567",103"12345678",104"123456789",105"1234567890",106"12345678901",107"123456789012",108"1234567890123",109"12345678901234",110"123456789012345",111"1234567890123456",112"12345678901234567",113"123456789012345678",114"1234567890123456789",115"12345678901234567890",116"123456789012345678901",117"1234567890123456789012",118]119120numbers = [121"0", "-0", "+0",122"0.0", "-0.0", "+0.0",123"0e0", "-0e0", "+0e0",124".0", "-.0",125".1", "-.1",126"1.1", "-1.1",127"1e1", "-1e1"128]129130# Get the list of available locales.131if platform.system() == 'Windows':132locale_list = windows_lang_strings133else:134locale_list = ['C']135if os.path.isfile("/var/lib/locales/supported.d/local"):136# On Ubuntu, `locale -a` gives the wrong case for some locales,137# so we get the correct names directly:138with open("/var/lib/locales/supported.d/local") as f:139locale_list = [loc.split()[0] for loc in f.readlines() \140if not loc.startswith('#')]141elif which('locale'):142locale_list = subprocess.Popen(["locale", "-a"],143stdout=subprocess.PIPE).communicate()[0]144try:145locale_list = locale_list.decode()146except UnicodeDecodeError:147# Some distributions insist on using latin-1 characters148# in their locale names.149locale_list = locale_list.decode('latin-1')150locale_list = locale_list.split('\n')151try:152locale_list.remove('')153except ValueError:154pass155156# Debian157if os.path.isfile("/etc/locale.alias"):158with open("/etc/locale.alias") as f:159while 1:160try:161line = f.readline()162except UnicodeDecodeError:163continue164if line == "":165break166if line.startswith('#'):167continue168x = line.split()169if len(x) == 2:170if x[0] in locale_list:171locale_list.remove(x[0])172173# FreeBSD174if platform.system() == 'FreeBSD':175# http://www.freebsd.org/cgi/query-pr.cgi?pr=142173176# en_GB.US-ASCII has 163 as the currency symbol.177for loc in ['it_CH.ISO8859-1', 'it_CH.ISO8859-15', 'it_CH.UTF-8',178'it_IT.ISO8859-1', 'it_IT.ISO8859-15', 'it_IT.UTF-8',179'sl_SI.ISO8859-2', 'sl_SI.UTF-8',180'en_GB.US-ASCII']:181try:182locale_list.remove(loc)183except ValueError:184pass185186# Print a testcase in the format of the IBM tests (for runtest.c):187def get_preferred_encoding():188loc = locale.setlocale(locale.LC_CTYPE)189if loc in preferred_encoding:190return preferred_encoding[loc]191else:192return locale.getpreferredencoding()193194def printit(testno, s, fmt, encoding=None):195if not encoding:196encoding = get_preferred_encoding()197try:198result = format(P.Decimal(s), fmt)199fmt = str(fmt.encode(encoding))[2:-1]200result = str(result.encode(encoding))[2:-1]201if "'" in result:202sys.stdout.write("xfmt%d format %s '%s' -> \"%s\"\n"203% (testno, s, fmt, result))204else:205sys.stdout.write("xfmt%d format %s '%s' -> '%s'\n"206% (testno, s, fmt, result))207except Exception as err:208sys.stderr.write("%s %s %s\n" % (err, s, fmt))209210211# Check if an integer can be converted to a valid fill character.212def check_fillchar(i):213try:214c = chr(i)215c.encode('utf-8').decode()216format(P.Decimal(0), c + '<19g')217return c218except:219return None220221# Generate all unicode characters that are accepted as222# fill characters by decimal.py.223def all_fillchars():224for i in range(0, 0x110002):225c = check_fillchar(i)226if c: yield c227228# Return random fill character.229def rand_fillchar():230while 1:231i = random.randrange(0, 0x110002)232c = check_fillchar(i)233if c: return c234235# Generate random format strings236# [[fill]align][sign][#][0][width][.precision][type]237def rand_format(fill, typespec='EeGgFfn%'):238active = sorted(random.sample(range(7), random.randrange(8)))239have_align = 0240s = ''241for elem in active:242if elem == 0: # fill+align243s += fill244s += random.choice('<>=^')245have_align = 1246elif elem == 1: # sign247s += random.choice('+- ')248elif elem == 2 and not have_align: # zeropad249s += '0'250elif elem == 3: # width251s += str(random.randrange(1, 100))252elif elem == 4: # thousands separator253s += ','254elif elem == 5: # prec255s += '.'256s += str(random.randrange(100))257elif elem == 6:258if 4 in active: c = typespec.replace('n', '')259else: c = typespec260s += random.choice(c)261return s262263# Partially brute force all possible format strings containing a thousands264# separator. Fall back to random where the runtime would become excessive.265# [[fill]align][sign][#][0][width][,][.precision][type]266def all_format_sep():267for align in ('', '<', '>', '=', '^'):268for fill in ('', 'x'):269if align == '': fill = ''270for sign in ('', '+', '-', ' '):271for zeropad in ('', '0'):272if align != '': zeropad = ''273for width in ['']+[str(y) for y in range(1, 15)]+['101']:274for prec in ['']+['.'+str(y) for y in range(15)]:275# for type in ('', 'E', 'e', 'G', 'g', 'F', 'f', '%'):276type = random.choice(('', 'E', 'e', 'G', 'g', 'F', 'f', '%'))277yield ''.join((fill, align, sign, zeropad, width, ',', prec, type))278279# Partially brute force all possible format strings with an 'n' specifier.280# [[fill]align][sign][#][0][width][,][.precision][type]281def all_format_loc():282for align in ('', '<', '>', '=', '^'):283for fill in ('', 'x'):284if align == '': fill = ''285for sign in ('', '+', '-', ' '):286for zeropad in ('', '0'):287if align != '': zeropad = ''288for width in ['']+[str(y) for y in range(1, 20)]+['101']:289for prec in ['']+['.'+str(y) for y in range(1, 20)]:290yield ''.join((fill, align, sign, zeropad, width, prec, 'n'))291292# Generate random format strings with a unicode fill character293# [[fill]align][sign][#][0][width][,][.precision][type]294def randfill(fill):295active = sorted(random.sample(range(5), random.randrange(6)))296s = ''297s += str(fill)298s += random.choice('<>=^')299for elem in active:300if elem == 0: # sign301s += random.choice('+- ')302elif elem == 1: # width303s += str(random.randrange(1, 100))304elif elem == 2: # thousands separator305s += ','306elif elem == 3: # prec307s += '.'308s += str(random.randrange(100))309elif elem == 4:310if 2 in active: c = 'EeGgFf%'311else: c = 'EeGgFfn%'312s += random.choice(c)313return s314315# Generate random format strings with random locale setting316# [[fill]align][sign][#][0][width][,][.precision][type]317def rand_locale():318try:319loc = random.choice(locale_list)320locale.setlocale(locale.LC_ALL, loc)321except locale.Error as err:322pass323active = sorted(random.sample(range(5), random.randrange(6)))324s = ''325have_align = 0326for elem in active:327if elem == 0: # fill+align328s += chr(random.randrange(32, 128))329s += random.choice('<>=^')330have_align = 1331elif elem == 1: # sign332s += random.choice('+- ')333elif elem == 2 and not have_align: # zeropad334s += '0'335elif elem == 3: # width336s += str(random.randrange(1, 100))337elif elem == 4: # prec338s += '.'339s += str(random.randrange(100))340s += 'n'341return s342343344