28
28
"setlocale" , "resetlocale" , "localeconv" , "strcoll" , "strxfrm" ,
29
29
"str" , "atof" , "atoi" , "format" , "format_string" , "currency" ,
30
30
"normalize" , "LC_CTYPE" , "LC_COLLATE" , "LC_TIME" , "LC_MONETARY" ,
31
- "LC_NUMERIC" , "LC_ALL" , "CHAR_MAX" ]
31
+ "LC_NUMERIC" , "LC_ALL" , "CHAR_MAX" , "getencoding" ]
32
32
33
33
def _strcoll (a ,b ):
34
34
""" strcoll(string,string) -> int.
@@ -185,8 +185,14 @@ def _format(percent, value, grouping=False, monetary=False, *additional):
185
185
formatted = percent % ((value ,) + additional )
186
186
else :
187
187
formatted = percent % value
188
+ if percent [- 1 ] in 'eEfFgGdiu' :
189
+ formatted = _localize (formatted , grouping , monetary )
190
+ return formatted
191
+
192
+ # Transform formatted as locale number according to the locale settings
193
+ def _localize (formatted , grouping = False , monetary = False ):
188
194
# floats and decimal ints need special action!
189
- if percent [ - 1 ] in 'eEfFgG' :
195
+ if '.' in formatted :
190
196
seps = 0
191
197
parts = formatted .split ('.' )
192
198
if grouping :
@@ -196,7 +202,7 @@ def _format(percent, value, grouping=False, monetary=False, *additional):
196
202
formatted = decimal_point .join (parts )
197
203
if seps :
198
204
formatted = _strip_padding (formatted , seps )
199
- elif percent [ - 1 ] in 'diu' :
205
+ else :
200
206
seps = 0
201
207
if grouping :
202
208
formatted , seps = _group (formatted , monetary = monetary )
@@ -267,7 +273,7 @@ def currency(val, symbol=True, grouping=False, international=False):
267
273
raise ValueError ("Currency formatting is not possible using "
268
274
"the 'C' locale." )
269
275
270
- s = _format ( '%%.%if' % digits , abs (val ), grouping , monetary = True )
276
+ s = _localize ( f' { abs (val ):.{ digits }f } ' , grouping , monetary = True )
271
277
# '<' and '>' are markers if the sign must be inserted between symbol and value
272
278
s = '<' + s + '>'
273
279
@@ -279,6 +285,8 @@ def currency(val, symbol=True, grouping=False, international=False):
279
285
if precedes :
280
286
s = smb + (separated and ' ' or '' ) + s
281
287
else :
288
+ if international and smb [- 1 ] == ' ' :
289
+ smb = smb [:- 1 ]
282
290
s = s + (separated and ' ' or '' ) + smb
283
291
284
292
sign_pos = conv [val < 0 and 'n_sign_posn' or 'p_sign_posn' ]
@@ -321,6 +329,10 @@ def delocalize(string):
321
329
string = string .replace (dd , '.' )
322
330
return string
323
331
332
+ def localize (string , grouping = False , monetary = False ):
333
+ """Parses a string as locale number according to the locale settings."""
334
+ return _localize (string , grouping , monetary )
335
+
324
336
def atof (string , func = float ):
325
337
"Parses a string as a float according to the locale settings."
326
338
return func (delocalize (string ))
@@ -492,6 +504,10 @@ def _parse_localename(localename):
492
504
return tuple (code .split ('.' )[:2 ])
493
505
elif code == 'C' :
494
506
return None , None
507
+ elif code == 'UTF-8' :
508
+ # On macOS "LC_CTYPE=UTF-8" is a valid locale setting
509
+ # for getting UTF-8 handling for text.
510
+ return None , 'UTF-8'
495
511
raise ValueError ('unknown locale: %s' % localename )
496
512
497
513
def _build_localename (localetuple ):
@@ -539,6 +555,12 @@ def getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')):
539
555
540
556
"""
541
557
558
+ import warnings
559
+ warnings .warn (
560
+ "Use setlocale(), getencoding() and getlocale() instead" ,
561
+ DeprecationWarning , stacklevel = 2
562
+ )
563
+
542
564
try :
543
565
# check if it's supported by the _locale module
544
566
import _locale
@@ -611,55 +633,72 @@ def resetlocale(category=LC_ALL):
611
633
getdefaultlocale(). category defaults to LC_ALL.
612
634
613
635
"""
614
- _setlocale (category , _build_localename (getdefaultlocale ()))
636
+ import warnings
637
+ warnings .warn (
638
+ 'Use locale.setlocale(locale.LC_ALL, "") instead' ,
639
+ DeprecationWarning , stacklevel = 2
640
+ )
641
+
642
+ with warnings .catch_warnings ():
643
+ warnings .simplefilter ('ignore' , category = DeprecationWarning )
644
+ loc = getdefaultlocale ()
645
+
646
+ _setlocale (category , _build_localename (loc ))
647
+
648
+
649
+ try :
650
+ from _locale import getencoding
651
+ except ImportError :
652
+ def getencoding ():
653
+ if hasattr (sys , 'getandroidapilevel' ):
654
+ # On Android langinfo.h and CODESET are missing, and UTF-8 is
655
+ # always used in mbstowcs() and wcstombs().
656
+ return 'utf-8'
657
+ encoding = getdefaultlocale ()[1 ]
658
+ if encoding is None :
659
+ # LANG not set, default to UTF-8
660
+ encoding = 'utf-8'
661
+ return encoding
615
662
616
- if sys .platform .startswith ("win" ):
617
- # On Win32, this will return the ANSI code page
618
- def getpreferredencoding (do_setlocale = True ):
663
+ try :
664
+ CODESET
665
+ except NameError :
666
+ def getpreferredencoding (do_setlocale = True ):
619
667
"""Return the charset that the user is likely using."""
668
+ if sys .flags .warn_default_encoding :
669
+ import warnings
670
+ warnings .warn (
671
+ "UTF-8 Mode affects locale.getpreferredencoding(). Consider locale.getencoding() instead." ,
672
+ EncodingWarning , 2 )
620
673
if sys .flags .utf8_mode :
621
- return 'UTF-8'
622
- import _bootlocale
623
- return _bootlocale .getpreferredencoding (False )
674
+ return 'utf-8'
675
+ return getencoding ()
624
676
else :
625
677
# On Unix, if CODESET is available, use that.
626
- try :
627
- CODESET
628
- except NameError :
629
- if hasattr (sys , 'getandroidapilevel' ):
630
- # On Android langinfo.h and CODESET are missing, and UTF-8 is
631
- # always used in mbstowcs() and wcstombs().
632
- def getpreferredencoding (do_setlocale = True ):
633
- return 'UTF-8'
634
- else :
635
- # Fall back to parsing environment variables :-(
636
- def getpreferredencoding (do_setlocale = True ):
637
- """Return the charset that the user is likely using,
638
- by looking at environment variables."""
639
- if sys .flags .utf8_mode :
640
- return 'UTF-8'
641
- res = getdefaultlocale ()[1 ]
642
- if res is None :
643
- # LANG not set, default conservatively to ASCII
644
- res = 'ascii'
645
- return res
646
- else :
647
- def getpreferredencoding (do_setlocale = True ):
648
- """Return the charset that the user is likely using,
649
- according to the system configuration."""
650
- if sys .flags .utf8_mode :
651
- return 'UTF-8'
652
- import _bootlocale
653
- if do_setlocale :
654
- oldloc = setlocale (LC_CTYPE )
655
- try :
656
- setlocale (LC_CTYPE , "" )
657
- except Error :
658
- pass
659
- result = _bootlocale .getpreferredencoding (False )
660
- if do_setlocale :
661
- setlocale (LC_CTYPE , oldloc )
662
- return result
678
+ def getpreferredencoding (do_setlocale = True ):
679
+ """Return the charset that the user is likely using,
680
+ according to the system configuration."""
681
+
682
+ if sys .flags .warn_default_encoding :
683
+ import warnings
684
+ warnings .warn (
685
+ "UTF-8 Mode affects locale.getpreferredencoding(). Consider locale.getencoding() instead." ,
686
+ EncodingWarning , 2 )
687
+ if sys .flags .utf8_mode :
688
+ return 'utf-8'
689
+
690
+ if not do_setlocale :
691
+ return getencoding ()
692
+
693
+ old_loc = setlocale (LC_CTYPE )
694
+ try :
695
+ try :
696
+ setlocale (LC_CTYPE , "" )
697
+ except Error :
698
+ pass
699
+ return getencoding ()
700
+ finally :
701
+ setlocale (LC_CTYPE , old_loc )
663
702
664
703
665
704
### Database
@@ -734,6 +773,7 @@ def getpreferredencoding(do_setlocale = True):
734
773
for k , v in sorted (locale_encoding_alias .items ()):
735
774
k = k .replace ('_' , '' )
736
775
locale_encoding_alias .setdefault (k , v )
776
+ del k , v
737
777
738
778
#
739
779
# The locale_alias table maps lowercase alias names to C locale names
0 commit comments