mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Update some of changed libs and tests from 3.14.5 -> 3.14.6 (part 2) (#8085)
This commit is contained in:
1 parent
404ee2a1f6
commit
057e968385
22 files changed
+832
-267
No files matched your search
Vendored
+3
-3
@@ -391,18 +391,18 @@ class Morsel(dict):
|
||||
return '<%s: %s>' % (self.__class__.__name__, self.OutputString())
|
||||
|
||||
def js_output(self, attrs=None):
|
||||
import base64
|
||||
import urllib.parse
|
||||
# Print javascript
|
||||
output_string = self.OutputString(attrs)
|
||||
if _has_control_character(output_string):
|
||||
raise CookieError("Control characters are not allowed in cookies")
|
||||
# Base64-encode value to avoid template
|
||||
# injection in cookie values.
|
||||
output_encoded = base64.b64encode(output_string.encode('utf-8')).decode("ascii")
|
||||
output_encoded = urllib.parse.quote(output_string, safe='', encoding='utf-8')
|
||||
return """
|
||||
<script type="text/javascript">
|
||||
<!-- begin hiding
|
||||
document.cookie = atob(\"%s\");
|
||||
document.cookie = decodeURIComponent(\"%s\");
|
||||
// end hiding -->
|
||||
</script>
|
||||
""" % (output_encoded,)
|
||||
|
||||
Vendored
+1
-1
@@ -706,7 +706,7 @@ class IMAP4:
|
||||
"""
|
||||
typ, dat = self._simple_command('LOGIN', user, self._quote(password))
|
||||
if typ != 'OK':
|
||||
raise self.error(dat[-1])
|
||||
raise self.error(dat[-1].decode('UTF-8', 'replace'))
|
||||
self.state = 'AUTH'
|
||||
return typ, dat
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -143,8 +143,8 @@ def dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True,
|
||||
|
||||
If ``indent`` is a non-negative integer, then JSON array elements and
|
||||
object members will be pretty-printed with that indent level. An indent
|
||||
level of 0 will only insert newlines. ``None`` is the most compact
|
||||
representation.
|
||||
level of 0 will only insert newlines. ``None`` is the default and gives
|
||||
a representation with no newlines inserted.
|
||||
|
||||
If specified, ``separators`` should be an ``(item_separator,
|
||||
key_separator)`` tuple. The default is ``(', ', ': ')`` if *indent* is
|
||||
@@ -207,8 +207,8 @@ def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True,
|
||||
|
||||
If ``indent`` is a non-negative integer, then JSON array elements and
|
||||
object members will be pretty-printed with that indent level. An indent
|
||||
level of 0 will only insert newlines. ``None`` is the most compact
|
||||
representation.
|
||||
level of 0 will only insert newlines. ``None`` is the default and gives
|
||||
a representation with no newlines inserted.
|
||||
|
||||
If specified, ``separators`` should be an ``(item_separator,
|
||||
key_separator)`` tuple. The default is ``(', ', ': ')`` if *indent* is
|
||||
|
||||
Vendored
+2
-1
@@ -88,7 +88,8 @@ def main():
|
||||
infile = open(options.infile, encoding='utf-8')
|
||||
try:
|
||||
if options.json_lines:
|
||||
objs = (json.loads(line) for line in infile)
|
||||
lines = infile.readlines()
|
||||
objs = (json.loads(line) for line in lines)
|
||||
else:
|
||||
objs = (json.load(infile),)
|
||||
finally:
|
||||
|
||||
Vendored
+346
-131
@@ -1496,8 +1496,8 @@ locale_alias = {
|
||||
# This maps Windows language identifiers to locale strings.
|
||||
#
|
||||
# This list has been updated from
|
||||
# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_238z.asp
|
||||
# to include every locale up to Windows Vista.
|
||||
# https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/70feba9f-294e-491e-b6eb-56532684c37f
|
||||
# to include every locale up to protocol revision 16.0 (2024-04-23).
|
||||
#
|
||||
# NOTE: this mapping is incomplete. If your language is missing, please
|
||||
# submit a bug report as detailed in the Python devguide at:
|
||||
@@ -1507,10 +1507,15 @@ locale_alias = {
|
||||
#
|
||||
|
||||
windows_locale = {
|
||||
0x0436: "af_ZA", # Afrikaans
|
||||
0x041c: "sq_AL", # Albanian
|
||||
0x0484: "gsw_FR",# Alsatian - France
|
||||
0x0036: "af", # Afrikaans
|
||||
0x0436: "af_ZA", # Afrikaans - South Africa
|
||||
0x001c: "sq", # Albanian
|
||||
0x041c: "sq_AL", # Albanian - Albania
|
||||
0x0084: "gsw", # Alsatian
|
||||
0x0484: "gsw_FR", # Alsatian - France
|
||||
0x005e: "am", # Amharic
|
||||
0x045e: "am_ET", # Amharic - Ethiopia
|
||||
0x0001: "ar", # Arabic
|
||||
0x0401: "ar_SA", # Arabic - Saudi Arabia
|
||||
0x0801: "ar_IQ", # Arabic - Iraq
|
||||
0x0c01: "ar_EG", # Arabic - Egypt
|
||||
@@ -1524,39 +1529,72 @@ windows_locale = {
|
||||
0x2c01: "ar_JO", # Arabic - Jordan
|
||||
0x3001: "ar_LB", # Arabic - Lebanon
|
||||
0x3401: "ar_KW", # Arabic - Kuwait
|
||||
0x3801: "ar_AE", # Arabic - United Arab Emirates
|
||||
0x3801: "ar_AE", # Arabic - U.A.E.
|
||||
0x3c01: "ar_BH", # Arabic - Bahrain
|
||||
0x4001: "ar_QA", # Arabic - Qatar
|
||||
0x042b: "hy_AM", # Armenian
|
||||
0x002b: "hy", # Armenian
|
||||
0x042b: "hy_AM", # Armenian - Armenia
|
||||
0x004d: "as", # Assamese
|
||||
0x044d: "as_IN", # Assamese - India
|
||||
0x042c: "az_AZ", # Azeri - Latin
|
||||
0x082c: "az_AZ", # Azeri - Cyrillic
|
||||
0x046d: "ba_RU", # Bashkir
|
||||
0x042d: "eu_ES", # Basque - Russia
|
||||
0x0423: "be_BY", # Belarusian
|
||||
0x0445: "bn_IN", # Begali
|
||||
0x201a: "bs_BA", # Bosnian - Cyrillic
|
||||
0x141a: "bs_BA", # Bosnian - Latin
|
||||
0x002c: "az", # Azerbaijani (Latin)
|
||||
0x742c: "az", # Azerbaijani (Cyrillic)
|
||||
0x782c: "az", # Azerbaijani (Latin)
|
||||
0x042c: "az_AZ", # Azerbaijani (Latin) - Azerbaijan
|
||||
0x0045: "bn", # Bangla
|
||||
0x0445: "bn_IN", # Bangla - India
|
||||
0x0845: "bn_BD", # Bangla - Bangladesh
|
||||
0x006d: "ba", # Bashkir
|
||||
0x046d: "ba_RU", # Bashkir - Russia
|
||||
0x002d: "eu", # Basque
|
||||
0x042d: "eu_ES", # Basque - Spain
|
||||
0x0023: "be", # Belarusian
|
||||
0x0423: "be_BY", # Belarusian - Belarus
|
||||
0x641a: "bs", # Bosnian (Cyrillic)
|
||||
0x681a: "bs", # Bosnian (Latin)
|
||||
0x141a: "bs_BA", # Bosnian (Latin) - Bosnia and Herzegovina
|
||||
0x201a: "bs_BA", # Bosnian (Cyrillic) - Bosnia and Herzegovina
|
||||
0x781a: "bs", # Bosnian (Latin)
|
||||
0x007e: "br", # Breton
|
||||
0x047e: "br_FR", # Breton - France
|
||||
0x0402: "bg_BG", # Bulgarian
|
||||
# 0x0455: "my_MM", # Burmese - Not supported
|
||||
0x0403: "ca_ES", # Catalan
|
||||
0x0004: "zh_CHS",# Chinese - Simplified
|
||||
0x0404: "zh_TW", # Chinese - Taiwan
|
||||
0x0804: "zh_CN", # Chinese - PRC
|
||||
0x0c04: "zh_HK", # Chinese - Hong Kong S.A.R.
|
||||
0x1004: "zh_SG", # Chinese - Singapore
|
||||
0x1404: "zh_MO", # Chinese - Macao S.A.R.
|
||||
0x7c04: "zh_CHT",# Chinese - Traditional
|
||||
0x0002: "bg", # Bulgarian
|
||||
0x0402: "bg_BG", # Bulgarian - Bulgaria
|
||||
0x0055: "my", # Burmese
|
||||
0x0455: "my_MM", # Burmese - Myanmar
|
||||
0x0003: "ca", # Catalan
|
||||
0x0403: "ca_ES", # Catalan - Spain
|
||||
0x0803: "ca_ES", # Valencian - Spain
|
||||
0x0092: "ku", # Central Kurdish
|
||||
0x7c92: "ku", # Central Kurdish
|
||||
0x0492: "ku_IQ", # Central Kurdish - Iraq
|
||||
0x005c: "chr", # Cherokee
|
||||
0x7c5c: "chr", # Cherokee
|
||||
0x045c: "chr_US", # Cherokee - United States
|
||||
0x0004: "zh", # Chinese (Simplified)
|
||||
0x7804: "zh", # Chinese (Simplified)
|
||||
0x7c04: "zh", # Chinese (Traditional)
|
||||
0x0404: "zh_TW", # Chinese (Traditional) - Taiwan
|
||||
0x0804: "zh_CN", # Chinese (Simplified) - People's Republic of China
|
||||
0x0c04: "zh_HK", # Chinese (Traditional) - Hong Kong S.A.R.
|
||||
0x1004: "zh_SG", # Chinese (Simplified) - Singapore
|
||||
0x1404: "zh_MO", # Chinese (Traditional) - Macao S.A.R.
|
||||
0x0083: "co", # Corsican
|
||||
0x0483: "co_FR", # Corsican - France
|
||||
0x041a: "hr_HR", # Croatian
|
||||
0x101a: "hr_BA", # Croatian - Bosnia
|
||||
0x0405: "cs_CZ", # Czech
|
||||
0x0406: "da_DK", # Danish
|
||||
0x048c: "gbz_AF",# Dari - Afghanistan
|
||||
0x0465: "div_MV",# Divehi - Maldives
|
||||
0x0413: "nl_NL", # Dutch - The Netherlands
|
||||
0x001a: "hr", # Croatian
|
||||
0x041a: "hr_HR", # Croatian - Croatia
|
||||
0x101a: "hr_BA", # Croatian (Latin) - Bosnia and Herzegovina
|
||||
0x0005: "cs", # Czech
|
||||
0x0405: "cs_CZ", # Czech - Czech Republic
|
||||
0x0006: "da", # Danish
|
||||
0x0406: "da_DK", # Danish - Denmark
|
||||
0x008c: "prs", # Dari
|
||||
0x048c: "prs_AF", # Dari - Afghanistan
|
||||
0x0065: "dv", # Divehi
|
||||
0x0465: "dv_MV", # Divehi - Maldives
|
||||
0x0013: "nl", # Dutch
|
||||
0x0413: "nl_NL", # Dutch - Netherlands
|
||||
0x0813: "nl_BE", # Dutch - Belgium
|
||||
0x0c51: "dz_BT", # Dzongkha - Bhutan
|
||||
0x0009: "en", # English
|
||||
0x0409: "en_US", # English - United States
|
||||
0x0809: "en_GB", # English - United Kingdom
|
||||
0x0c09: "en_AU", # English - Australia
|
||||
@@ -1564,122 +1602,248 @@ windows_locale = {
|
||||
0x1409: "en_NZ", # English - New Zealand
|
||||
0x1809: "en_IE", # English - Ireland
|
||||
0x1c09: "en_ZA", # English - South Africa
|
||||
0x2009: "en_JA", # English - Jamaica
|
||||
0x2409: "en_CB", # English - Caribbean
|
||||
0x2009: "en_JM", # English - Jamaica
|
||||
0x2809: "en_BZ", # English - Belize
|
||||
0x2c09: "en_TT", # English - Trinidad
|
||||
0x2c09: "en_TT", # English - Trinidad and Tobago
|
||||
0x3009: "en_ZW", # English - Zimbabwe
|
||||
0x3409: "en_PH", # English - Philippines
|
||||
0x3409: "en_PH", # English - Republic of the Philippines
|
||||
0x3c09: "en_HK", # English - Hong Kong
|
||||
0x4009: "en_IN", # English - India
|
||||
0x4409: "en_MY", # English - Malaysia
|
||||
0x4809: "en_IN", # English - Singapore
|
||||
0x0425: "et_EE", # Estonian
|
||||
0x0438: "fo_FO", # Faroese
|
||||
0x0464: "fil_PH",# Filipino
|
||||
0x040b: "fi_FI", # Finnish
|
||||
0x4809: "en_SG", # English - Singapore
|
||||
0x4c09: "en_AE", # English - United Arab Emirates
|
||||
0x0025: "et", # Estonian
|
||||
0x0425: "et_EE", # Estonian - Estonia
|
||||
0x0038: "fo", # Faroese
|
||||
0x0438: "fo_FO", # Faroese - Faroe Islands
|
||||
0x0064: "fil", # Filipino
|
||||
0x0464: "fil_PH", # Filipino - Philippines
|
||||
0x000b: "fi", # Finnish
|
||||
0x040b: "fi_FI", # Finnish - Finland
|
||||
0x000c: "fr", # French
|
||||
0x040c: "fr_FR", # French - France
|
||||
0x080c: "fr_BE", # French - Belgium
|
||||
0x0c0c: "fr_CA", # French - Canada
|
||||
0x100c: "fr_CH", # French - Switzerland
|
||||
0x140c: "fr_LU", # French - Luxembourg
|
||||
0x180c: "fr_MC", # French - Monaco
|
||||
0x180c: "fr_MC", # French - Principality of Monaco
|
||||
0x1c0c: "fr_029", # French - Caribbean
|
||||
0x200c: "fr_RE", # French - Reunion
|
||||
0x240c: "fr_CD", # French - Congo, DRC
|
||||
0x280c: "fr_SN", # French - Senegal
|
||||
0x2c0c: "fr_CM", # French - Cameroon
|
||||
0x300c: "fr_CI", # French - Côte d'Ivoire
|
||||
0x340c: "fr_ML", # French - Mali
|
||||
0x380c: "fr_MA", # French - Morocco
|
||||
0x3c0c: "fr_HT", # French - Haiti
|
||||
0x0062: "fy", # Frisian
|
||||
0x0462: "fy_NL", # Frisian - Netherlands
|
||||
0x0456: "gl_ES", # Galician
|
||||
0x0437: "ka_GE", # Georgian
|
||||
0x0067: "ff", # Fulah
|
||||
0x7c67: "ff", # Fulah (Latin)
|
||||
0x0467: "ff_NG",
|
||||
0x0867: "ff_SN", # Fulah - Senegal
|
||||
0x0056: "gl", # Galician
|
||||
0x0456: "gl_ES", # Galician - Spain
|
||||
0x0037: "ka", # Georgian
|
||||
0x0437: "ka_GE", # Georgian - Georgia
|
||||
0x0007: "de", # German
|
||||
0x0407: "de_DE", # German - Germany
|
||||
0x0807: "de_CH", # German - Switzerland
|
||||
0x0c07: "de_AT", # German - Austria
|
||||
0x1007: "de_LU", # German - Luxembourg
|
||||
0x1407: "de_LI", # German - Liechtenstein
|
||||
0x0408: "el_GR", # Greek
|
||||
0x0008: "el", # Greek
|
||||
0x0408: "el_GR", # Greek - Greece
|
||||
0x006f: "kl", # Greenlandic
|
||||
0x046f: "kl_GL", # Greenlandic - Greenland
|
||||
0x0447: "gu_IN", # Gujarati
|
||||
0x0468: "ha_NG", # Hausa - Latin
|
||||
0x040d: "he_IL", # Hebrew
|
||||
0x0439: "hi_IN", # Hindi
|
||||
0x040e: "hu_HU", # Hungarian
|
||||
0x040f: "is_IS", # Icelandic
|
||||
0x0421: "id_ID", # Indonesian
|
||||
0x045d: "iu_CA", # Inuktitut - Syllabics
|
||||
0x085d: "iu_CA", # Inuktitut - Latin
|
||||
0x0074: "gn", # Guarani
|
||||
0x0474: "gn_PY", # Guarani - Paraguay
|
||||
0x0047: "gu", # Gujarati
|
||||
0x0447: "gu_IN", # Gujarati - India
|
||||
0x0068: "ha", # Hausa (Latin)
|
||||
0x7c68: "ha", # Hausa (Latin)
|
||||
0x0468: "ha_NG", # Hausa (Latin) - Nigeria
|
||||
0x0075: "haw", # Hawaiian
|
||||
0x0475: "haw_US", # Hawaiian - United States
|
||||
0x000d: "he", # Hebrew
|
||||
0x040d: "he_IL", # Hebrew - Israel
|
||||
0x0039: "hi", # Hindi
|
||||
0x0439: "hi_IN", # Hindi - India
|
||||
0x000e: "hu", # Hungarian
|
||||
0x040e: "hu_HU", # Hungarian - Hungary
|
||||
0x000f: "is", # Icelandic
|
||||
0x040f: "is_IS", # Icelandic - Iceland
|
||||
0x0070: "ig", # Igbo
|
||||
0x0470: "ig_NG", # Igbo - Nigeria
|
||||
0x0021: "id", # Indonesian
|
||||
0x0421: "id_ID", # Indonesian - Indonesia
|
||||
0x005d: "iu", # Inuktitut (Latin)
|
||||
0x785d: "iu", # Inuktitut (Syllabics)
|
||||
0x7c5d: "iu", # Inuktitut (Latin)
|
||||
0x045d: "iu_CA", # Inuktitut (Syllabics) - Canada
|
||||
0x085d: "iu_CA", # Inuktitut (Latin) - Canada
|
||||
0x003c: "ga", # Irish
|
||||
0x083c: "ga_IE", # Irish - Ireland
|
||||
0x0010: "it", # Italian
|
||||
0x0410: "it_IT", # Italian - Italy
|
||||
0x0810: "it_CH", # Italian - Switzerland
|
||||
0x0411: "ja_JP", # Japanese
|
||||
0x0011: "ja", # Japanese
|
||||
0x0411: "ja_JP", # Japanese - Japan
|
||||
0x004b: "kn", # Kannada
|
||||
0x044b: "kn_IN", # Kannada - India
|
||||
0x043f: "kk_KZ", # Kazakh
|
||||
0x0453: "kh_KH", # Khmer - Cambodia
|
||||
0x0486: "qut_GT",# K'iche - Guatemala
|
||||
0x0471: "kr_NG", # Kanuri (Latin) - Nigeria
|
||||
0x0060: "ks", # Kashmiri
|
||||
0x0460: "ks", # Kashmiri - Perso_Arabic
|
||||
0x0860: "ks_IN", # Kashmiri (Devanagari) - India
|
||||
0x003f: "kk", # Kazakh
|
||||
0x043f: "kk_KZ", # Kazakh - Kazakhstan
|
||||
0x0053: "km", # Khmer
|
||||
0x0453: "km_KH", # Khmer - Cambodia
|
||||
0x0087: "rw", # Kinyarwanda
|
||||
0x0487: "rw_RW", # Kinyarwanda - Rwanda
|
||||
0x0457: "kok_IN",# Konkani
|
||||
0x0412: "ko_KR", # Korean
|
||||
0x0440: "ky_KG", # Kyrgyz
|
||||
0x0454: "lo_LA", # Lao - Lao PDR
|
||||
0x0426: "lv_LV", # Latvian
|
||||
0x0427: "lt_LT", # Lithuanian
|
||||
0x082e: "dsb_DE",# Lower Sorbian - Germany
|
||||
0x046e: "lb_LU", # Luxembourgish
|
||||
0x042f: "mk_MK", # FYROM Macedonian
|
||||
0x0041: "sw", # Kiswahili
|
||||
0x0441: "sw_KE", # Kiswahili - Kenya
|
||||
0x0057: "kok", # Konkani
|
||||
0x0457: "kok_IN", # Konkani - India
|
||||
0x0012: "ko", # Korean
|
||||
0x0412: "ko_KR", # Korean - Korea
|
||||
0x0040: "ky", # Kyrgyz
|
||||
0x0440: "ky_KG", # Kyrgyz - Kyrgyzstan
|
||||
0x0054: "lo", # Lao
|
||||
0x0454: "lo_LA", # Lao - Lao P.D.R.
|
||||
0x0476: "la_VA", # Latin - Vatican City
|
||||
0x0026: "lv", # Latvian
|
||||
0x0426: "lv_LV", # Latvian - Latvia
|
||||
0x0027: "lt", # Lithuanian
|
||||
0x0427: "lt_LT", # Lithuanian - Lithuania
|
||||
0x7c2e: "dsb", # Lower Sorbian
|
||||
0x082e: "dsb_DE", # Lower Sorbian - Germany
|
||||
0x006e: "lb", # Luxembourgish
|
||||
0x046e: "lb_LU", # Luxembourgish - Luxembourg
|
||||
0x002f: "mk", # Macedonian
|
||||
0x042f: "mk_MK", # Macedonian - North Macedonia
|
||||
0x003e: "ms", # Malay
|
||||
0x043e: "ms_MY", # Malay - Malaysia
|
||||
0x083e: "ms_BN", # Malay - Brunei Darussalam
|
||||
0x004c: "ml", # Malayalam
|
||||
0x044c: "ml_IN", # Malayalam - India
|
||||
0x043a: "mt_MT", # Maltese
|
||||
0x0481: "mi_NZ", # Maori
|
||||
0x047a: "arn_CL",# Mapudungun
|
||||
0x044e: "mr_IN", # Marathi
|
||||
0x047c: "moh_CA",# Mohawk - Canada
|
||||
0x0450: "mn_MN", # Mongolian - Cyrillic
|
||||
0x0850: "mn_CN", # Mongolian - PRC
|
||||
0x0461: "ne_NP", # Nepali
|
||||
0x0414: "nb_NO", # Norwegian - Bokmal
|
||||
0x0814: "nn_NO", # Norwegian - Nynorsk
|
||||
0x003a: "mt", # Maltese
|
||||
0x043a: "mt_MT", # Maltese - Malta
|
||||
0x0081: "mi", # Maori
|
||||
0x0481: "mi_NZ", # Maori - New Zealand
|
||||
0x007a: "arn", # Mapudungun
|
||||
0x047a: "arn_CL", # Mapudungun - Chile
|
||||
0x004e: "mr", # Marathi
|
||||
0x044e: "mr_IN", # Marathi - India
|
||||
0x007c: "moh", # Mohawk
|
||||
0x047c: "moh_CA", # Mohawk - Canada
|
||||
0x0050: "mn", # Mongolian (Cyrillic)
|
||||
0x7850: "mn", # Mongolian (Cyrillic)
|
||||
0x7c50: "mn", # Mongolian (Traditional Mongolian)
|
||||
0x0450: "mn_MN", # Mongolian (Cyrillic) - Mongolia
|
||||
0x0c50: "mn_MN", # Mongolian (Traditional Mongolian) - Mongolia
|
||||
0x0061: "ne", # Nepali
|
||||
0x0461: "ne_NP", # Nepali - Nepal
|
||||
0x0861: "ne_IN", # Nepali - India
|
||||
0x0014: "no", # Norwegian (Bokmal)
|
||||
0x0414: "nb_NO", # Norwegian (Bokmal) - Norway
|
||||
0x0814: "nn_NO", # Norwegian (Nynorsk) - Norway
|
||||
0x7814: "nn", # Norwegian (Nynorsk)
|
||||
0x7c14: "nb", # Norwegian (Bokmal)
|
||||
0x0082: "oc", # Occitan
|
||||
0x0482: "oc_FR", # Occitan - France
|
||||
0x0448: "or_IN", # Oriya - India
|
||||
0x0048: "or", # Odia
|
||||
0x0448: "or_IN", # Odia - India
|
||||
0x0072: "om", # Oromo
|
||||
0x0472: "om_ET", # Oromo - Ethiopia
|
||||
0x0063: "ps", # Pashto
|
||||
0x0463: "ps_AF", # Pashto - Afghanistan
|
||||
0x0429: "fa_IR", # Persian
|
||||
0x0415: "pl_PL", # Polish
|
||||
0x0029: "fa", # Persian
|
||||
0x0429: "fa_IR", # Persian - Iran
|
||||
0x0015: "pl", # Polish
|
||||
0x0415: "pl_PL", # Polish - Poland
|
||||
0x0016: "pt", # Portuguese
|
||||
0x0416: "pt_BR", # Portuguese - Brazil
|
||||
0x0816: "pt_PT", # Portuguese - Portugal
|
||||
0x0446: "pa_IN", # Punjabi
|
||||
0x046b: "quz_BO",# Quechua (Bolivia)
|
||||
0x086b: "quz_EC",# Quechua (Ecuador)
|
||||
0x0c6b: "quz_PE",# Quechua (Peru)
|
||||
0x0046: "pa", # Punjabi
|
||||
0x7c46: "pa", # Punjabi
|
||||
0x0446: "pa_IN", # Punjabi - India
|
||||
0x0846: "pa_PK", # Punjabi - Islamic Republic of Pakistan
|
||||
0x006b: "quz", # Quechua
|
||||
0x046b: "quz_BO", # Quechua - Bolivia
|
||||
0x086b: "quz_EC", # Quechua - Ecuador
|
||||
0x0c6b: "quz_PE", # Quechua - Peru
|
||||
0x0018: "ro", # Romanian
|
||||
0x0418: "ro_RO", # Romanian - Romania
|
||||
0x0417: "rm_CH", # Romansh
|
||||
0x0419: "ru_RU", # Russian
|
||||
0x243b: "smn_FI",# Sami Finland
|
||||
0x103b: "smj_NO",# Sami Norway
|
||||
0x143b: "smj_SE",# Sami Sweden
|
||||
0x043b: "se_NO", # Sami Northern Norway
|
||||
0x083b: "se_SE", # Sami Northern Sweden
|
||||
0x0c3b: "se_FI", # Sami Northern Finland
|
||||
0x203b: "sms_FI",# Sami Skolt
|
||||
0x183b: "sma_NO",# Sami Southern Norway
|
||||
0x1c3b: "sma_SE",# Sami Southern Sweden
|
||||
0x044f: "sa_IN", # Sanskrit
|
||||
0x0c1a: "sr_SP", # Serbian - Cyrillic
|
||||
0x1c1a: "sr_BA", # Serbian - Bosnia Cyrillic
|
||||
0x081a: "sr_SP", # Serbian - Latin
|
||||
0x181a: "sr_BA", # Serbian - Bosnia Latin
|
||||
0x0818: "ro_MD", # Romanian - Moldova
|
||||
0x0017: "rm", # Romansh
|
||||
0x0417: "rm_CH", # Romansh - Switzerland
|
||||
0x0019: "ru", # Russian
|
||||
0x0419: "ru_RU", # Russian - Russia
|
||||
0x0819: "ru_MD", # Russian - Moldova
|
||||
0x0085: "sah", # Sakha
|
||||
0x0485: "sah_RU", # Sakha - Russia
|
||||
0x003b: "se", # Sami (Northern)
|
||||
0x043b: "se_NO", # Sami (Northern) - Norway
|
||||
0x083b: "se_SE", # Sami (Northern) - Sweden
|
||||
0x0c3b: "se_FI", # Sami (Northern) - Finland
|
||||
0x7c3b: "smj", # Sami (Lule)
|
||||
0x103b: "smj_NO", # Sami (Lule) - Norway
|
||||
0x143b: "smj_SE", # Sami (Lule) - Sweden
|
||||
0x783b: "sma", # Sami (Southern)
|
||||
0x183b: "sma_NO", # Sami (Southern) - Norway
|
||||
0x1c3b: "sma_SE", # Sami (Southern) - Sweden
|
||||
0x743b: "sms", # Sami (Skolt)
|
||||
0x203b: "sms_FI", # Sami (Skolt) - Finland
|
||||
0x703b: "smn", # Sami (Inari)
|
||||
0x243b: "smn_FI", # Sami (Inari) - Finland
|
||||
0x004f: "sa", # Sanskrit
|
||||
0x044f: "sa_IN", # Sanskrit - India
|
||||
0x0091: "gd", # Scottish Gaelic
|
||||
0x0491: "gd_GB", # Scottish Gaelic - United Kingdom
|
||||
0x6c1a: "sr", # Serbian (Cyrillic)
|
||||
0x701a: "sr", # Serbian (Latin)
|
||||
0x7c1a: "sr", # Serbian (Latin)
|
||||
0x081a: "sr_CS", # Serbian (Latin) - Serbia and Montenegro (Former)
|
||||
0x0c1a: "sr_CS", # Serbian (Cyrillic) - Serbia and Montenegro (Former)
|
||||
0x181a: "sr_BA", # Serbian (Latin) - Bosnia and Herzegovina
|
||||
0x1c1a: "sr_BA", # Serbian (Cyrillic) - Bosnia and Herzegovina
|
||||
0x241a: "sr_RS", # Serbian (Latin) - Serbia
|
||||
0x281a: "sr_RS", # Serbian (Cyrillic) - Serbia
|
||||
0x2c1a: "sr_ME", # Serbian (Latin) - Montenegro
|
||||
0x301a: "sr_ME", # Serbian (Cyrillic) - Montenegro
|
||||
0x006c: "nso", # Sesotho sa Leboa
|
||||
0x046c: "nso_ZA", # Sesotho sa Leboa - South Africa
|
||||
0x0032: "tn", # Setswana
|
||||
0x0432: "tn_ZA", # Setswana - South Africa
|
||||
0x0832: "tn_BW", # Setswana - Botswana
|
||||
0x0059: "sd", # Sindhi
|
||||
0x7c59: "sd", # Sindhi
|
||||
0x0859: "sd_PK", # Sindhi - Islamic Republic of Pakistan
|
||||
0x005b: "si", # Sinhala
|
||||
0x045b: "si_LK", # Sinhala - Sri Lanka
|
||||
0x046c: "ns_ZA", # Northern Sotho
|
||||
0x0432: "tn_ZA", # Setswana - Southern Africa
|
||||
0x041b: "sk_SK", # Slovak
|
||||
0x0424: "sl_SI", # Slovenian
|
||||
0x001b: "sk", # Slovak
|
||||
0x041b: "sk_SK", # Slovak - Slovakia
|
||||
0x0024: "sl", # Slovenian
|
||||
0x0424: "sl_SI", # Slovenian - Slovenia
|
||||
0x0477: "so_SO", # Somali - Somalia
|
||||
0x0030: "st", # Sotho
|
||||
0x0430: "st_ZA", # Sotho - South Africa
|
||||
0x000a: "es", # Spanish
|
||||
0x040a: "es_ES", # Spanish - Spain
|
||||
0x080a: "es_MX", # Spanish - Mexico
|
||||
0x0c0a: "es_ES", # Spanish - Spain (Modern)
|
||||
0x0c0a: "es_ES", # Spanish - Spain
|
||||
0x100a: "es_GT", # Spanish - Guatemala
|
||||
0x140a: "es_CR", # Spanish - Costa Rica
|
||||
0x180a: "es_PA", # Spanish - Panama
|
||||
0x1c0a: "es_DO", # Spanish - Dominican Republic
|
||||
0x200a: "es_VE", # Spanish - Venezuela
|
||||
0x200a: "es_VE", # Spanish - Bolivarian Republic of Venezuela
|
||||
0x240a: "es_CO", # Spanish - Colombia
|
||||
0x280a: "es_PE", # Spanish - Peru
|
||||
0x2c0a: "es_AR", # Spanish - Argentina
|
||||
0x300a: "es_EC", # Spanish - Ecuador
|
||||
0x340a: "es_CL", # Spanish - Chile
|
||||
0x380a: "es_UR", # Spanish - Uruguay
|
||||
0x380a: "es_UY", # Spanish - Uruguay
|
||||
0x3c0a: "es_PY", # Spanish - Paraguay
|
||||
0x400a: "es_BO", # Spanish - Bolivia
|
||||
0x440a: "es_SV", # Spanish - El Salvador
|
||||
@@ -1687,36 +1851,87 @@ windows_locale = {
|
||||
0x4c0a: "es_NI", # Spanish - Nicaragua
|
||||
0x500a: "es_PR", # Spanish - Puerto Rico
|
||||
0x540a: "es_US", # Spanish - United States
|
||||
# 0x0430: "", # Sutu - Not supported
|
||||
0x0441: "sw_KE", # Swahili
|
||||
0x5c0a: "es_CU", # Spanish - Cuba
|
||||
0x001d: "sv", # Swedish
|
||||
0x041d: "sv_SE", # Swedish - Sweden
|
||||
0x081d: "sv_FI", # Swedish - Finland
|
||||
0x045a: "syr_SY",# Syriac
|
||||
0x0428: "tg_TJ", # Tajik - Cyrillic
|
||||
0x085f: "tmz_DZ",# Tamazight - Latin
|
||||
0x0449: "ta_IN", # Tamil
|
||||
0x0444: "tt_RU", # Tatar
|
||||
0x044a: "te_IN", # Telugu
|
||||
0x041e: "th_TH", # Thai
|
||||
0x0851: "bo_BT", # Tibetan - Bhutan
|
||||
0x0451: "bo_CN", # Tibetan - PRC
|
||||
0x041f: "tr_TR", # Turkish
|
||||
0x0442: "tk_TM", # Turkmen - Cyrillic
|
||||
0x0480: "ug_CN", # Uighur - Arabic
|
||||
0x0422: "uk_UA", # Ukrainian
|
||||
0x042e: "wen_DE",# Upper Sorbian - Germany
|
||||
0x0420: "ur_PK", # Urdu
|
||||
0x005a: "syr", # Syriac
|
||||
0x045a: "syr_SY", # Syriac - Syria
|
||||
0x0028: "tg", # Tajik (Cyrillic)
|
||||
0x7c28: "tg", # Tajik (Cyrillic)
|
||||
0x0428: "tg_TJ", # Tajik (Cyrillic) - Tajikistan
|
||||
0x005f: "tzm", # Tamazight (Latin)
|
||||
0x785f: "tzm",
|
||||
0x7c5f: "tzm", # Tamazight (Latin)
|
||||
0x085f: "tzm_DZ", # Tamazight (Latin) - Algeria
|
||||
0x045f: "tzm_MA", # Central Atlas Tamazight (Arabic) - Morocco
|
||||
0x105f: "tzm_MA",
|
||||
0x0049: "ta", # Tamil
|
||||
0x0449: "ta_IN", # Tamil - India
|
||||
0x0849: "ta_LK", # Tamil - Sri Lanka
|
||||
0x0044: "tt", # Tatar
|
||||
0x0444: "tt_RU", # Tatar - Russia
|
||||
0x004a: "te", # Telugu
|
||||
0x044a: "te_IN", # Telugu - India
|
||||
0x001e: "th", # Thai
|
||||
0x041e: "th_TH", # Thai - Thailand
|
||||
0x0051: "bo", # Tibetan
|
||||
0x0451: "bo_CN", # Tibetan - People's Republic of China
|
||||
0x0073: "ti", # Tigrinya
|
||||
0x0473: "ti_ET", # Tigrinya - Ethiopia
|
||||
0x0873: "ti_ER", # Tigrinya - Eritrea
|
||||
0x0031: "ts", # Tsonga
|
||||
0x0431: "ts_ZA", # Tsonga - South Africa
|
||||
0x001f: "tr", # Turkish
|
||||
0x041f: "tr_TR", # Turkish - Turkey
|
||||
0x0042: "tk", # Turkmen
|
||||
0x0442: "tk_TM", # Turkmen - Turkmenistan
|
||||
0x0022: "uk", # Ukrainian
|
||||
0x0422: "uk_UA", # Ukrainian - Ukraine
|
||||
0x002e: "hsb", # Upper Sorbian
|
||||
0x042e: "hsb_DE", # Upper Sorbian - Germany
|
||||
0x0020: "ur", # Urdu
|
||||
0x0420: "ur_PK", # Urdu - Islamic Republic of Pakistan
|
||||
0x0820: "ur_IN", # Urdu - India
|
||||
0x0443: "uz_UZ", # Uzbek - Latin
|
||||
0x0843: "uz_UZ", # Uzbek - Cyrillic
|
||||
0x042a: "vi_VN", # Vietnamese
|
||||
0x0452: "cy_GB", # Welsh
|
||||
0x0080: "ug", # Uyghur
|
||||
0x0480: "ug_CN", # Uyghur - People's Republic of China
|
||||
0x0043: "uz", # Uzbek (Latin)
|
||||
0x7843: "uz", # Uzbek (Cyrillic)
|
||||
0x7c43: "uz", # Uzbek (Latin)
|
||||
0x0443: "uz_UZ", # Uzbek (Latin) - Uzbekistan
|
||||
0x0033: "ve", # Venda
|
||||
0x0433: "ve_ZA", # Venda - South Africa
|
||||
0x002a: "vi", # Vietnamese
|
||||
0x042a: "vi_VN", # Vietnamese - Vietnam
|
||||
0x0052: "cy", # Welsh
|
||||
0x0452: "cy_GB", # Welsh - United Kingdom
|
||||
0x0088: "wo", # Wolof
|
||||
0x0488: "wo_SN", # Wolof - Senegal
|
||||
0x0034: "xh", # Xhosa
|
||||
0x0434: "xh_ZA", # Xhosa - South Africa
|
||||
0x0485: "sah_RU",# Yakut - Cyrillic
|
||||
0x0478: "ii_CN", # Yi - PRC
|
||||
0x0078: "ii", # Yi
|
||||
0x0478: "ii_CN", # Yi - People's Republic of China
|
||||
0x043d: "yi_001", # Yiddish - World
|
||||
0x006a: "yo", # Yoruba
|
||||
0x046a: "yo_NG", # Yoruba - Nigeria
|
||||
0x0435: "zu_ZA", # Zulu
|
||||
0x0035: "zu", # Zulu
|
||||
0x0435: "zu_ZA", # Zulu - South Africa
|
||||
0x0086: "qut",
|
||||
|
||||
# 0x0001007f: "x-IV-mathan", # math alphanumeric sorting
|
||||
0x00010407: "de_DE",
|
||||
0x0001040e: "hu_HU",
|
||||
0x00010437: "ka_GE",
|
||||
0x00020804: "zh_CN",
|
||||
0x00021004: "zh_SG",
|
||||
0x00021404: "zh_MO",
|
||||
0x00030404: "zh_TW",
|
||||
0x00040404: "zh_TW",
|
||||
0x00040411: "ja_JP",
|
||||
0x00040c04: "zh_HK",
|
||||
0x00041404: "zh_MO",
|
||||
0x00050804: "zh_CN",
|
||||
0x00051004: "zh_SG",
|
||||
}
|
||||
|
||||
def _print_locale():
|
||||
|
||||
Vendored
+9
-7
@@ -152,12 +152,14 @@ def splitdrive(p):
|
||||
It is always true that:
|
||||
result[0] + result[1] == p
|
||||
|
||||
If the path contained a drive letter, drive_or_unc will contain everything
|
||||
up to and including the colon. e.g. splitdrive("c:/dir") returns ("c:", "/dir")
|
||||
If the path contained a drive letter, drive_or_unc will contain
|
||||
everything up to and including the colon. e.g. splitdrive("c:/dir")
|
||||
returns ("c:", "/dir")
|
||||
|
||||
If the path contained a UNC path, the drive_or_unc will contain the host name
|
||||
and share up to but not including the fourth directory separator character.
|
||||
e.g. splitdrive("//host/computer/dir") returns ("//host/computer", "/dir")
|
||||
If the path contained a UNC path, the drive_or_unc will contain the
|
||||
host name and share up to but not including the fourth directory
|
||||
separator character. e.g. splitdrive("//host/computer/dir") returns
|
||||
("//host/computer", "/dir")
|
||||
|
||||
Paths cannot contain both a drive letter and a UNC path.
|
||||
|
||||
@@ -222,8 +224,8 @@ except ImportError:
|
||||
def split(p):
|
||||
"""Split a pathname.
|
||||
|
||||
Return tuple (head, tail) where tail is everything after the final slash.
|
||||
Either part may be empty."""
|
||||
Return tuple (head, tail) where tail is everything after the final
|
||||
slash. Either part may be empty."""
|
||||
p = os.fspath(p)
|
||||
seps = _get_bothseps(p)
|
||||
d, r, p = splitroot(p)
|
||||
|
||||
@@ -211,11 +211,11 @@ SEEK_END = 2
|
||||
def makedirs(name, mode=0o777, exist_ok=False):
|
||||
"""makedirs(name [, mode=0o777][, exist_ok=False])
|
||||
|
||||
Super-mkdir; create a leaf directory and all intermediate ones. Works like
|
||||
mkdir, except that any intermediate path segment (not just the rightmost)
|
||||
will be created if it does not exist. If the target directory already
|
||||
exists, raise an OSError if exist_ok is False. Otherwise no exception is
|
||||
raised. This is recursive.
|
||||
Super-mkdir; create a leaf directory and all intermediate ones. Works
|
||||
like mkdir, except that any intermediate path segment (not just the
|
||||
rightmost) will be created if it does not exist. If the target
|
||||
directory already exists, raise an OSError if exist_ok is False.
|
||||
Otherwise no exception is raised. This is recursive.
|
||||
|
||||
"""
|
||||
head, tail = path.split(name)
|
||||
@@ -303,12 +303,12 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
|
||||
dirpath, dirnames, filenames
|
||||
|
||||
dirpath is a string, the path to the directory. dirnames is a list of
|
||||
the names of the subdirectories in dirpath (including symlinks to directories,
|
||||
and excluding '.' and '..').
|
||||
the names of the subdirectories in dirpath (including symlinks to
|
||||
directories, and excluding '.' and '..').
|
||||
filenames is a list of the names of the non-directory files in dirpath.
|
||||
Note that the names in the lists are just names, with no path components.
|
||||
To get a full path (which begins with top) to a file or directory in
|
||||
dirpath, do os.path.join(dirpath, name).
|
||||
Note that the names in the lists are just names, with no path
|
||||
components. To get a full path (which begins with top) to a file or
|
||||
directory in dirpath, do os.path.join(dirpath, name).
|
||||
|
||||
If optional arg 'topdown' is true or not specified, the triple for a
|
||||
directory is generated before the triples for any of its subdirectories
|
||||
@@ -318,13 +318,13 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
|
||||
|
||||
When topdown is true, the caller can modify the dirnames list in-place
|
||||
(e.g., via del or slice assignment), and walk will only recurse into the
|
||||
subdirectories whose names remain in dirnames; this can be used to prune the
|
||||
search, or to impose a specific order of visiting. Modifying dirnames when
|
||||
topdown is false has no effect on the behavior of os.walk(), since the
|
||||
directories in dirnames have already been generated by the time dirnames
|
||||
itself is generated. No matter the value of topdown, the list of
|
||||
subdirectories is retrieved before the tuples for the directory and its
|
||||
subdirectories are generated.
|
||||
subdirectories whose names remain in dirnames; this can be used to prune
|
||||
the search, or to impose a specific order of visiting. Modifying
|
||||
dirnames when topdown is false has no effect on the behavior of
|
||||
os.walk(), since the directories in dirnames have already been generated
|
||||
by the time dirnames itself is generated. No matter the value of
|
||||
topdown, the list of subdirectories is retrieved before the tuples for
|
||||
the directory and its subdirectories are generated.
|
||||
|
||||
By default errors from the os.scandir() call are ignored. If
|
||||
optional arg 'onerror' is specified, it should be a function; it
|
||||
@@ -449,9 +449,9 @@ if {open, stat} <= supports_dir_fd and {scandir, stat} <= supports_fd:
|
||||
The advantage of fwalk() over walk() is that it's safe against symlink
|
||||
races (when follow_symlinks is False).
|
||||
|
||||
If dir_fd is not None, it should be a file descriptor open to a directory,
|
||||
and top should be relative; top will then be relative to that directory.
|
||||
(dir_fd is always supported for fwalk.)
|
||||
If dir_fd is not None, it should be a file descriptor open to
|
||||
a directory, and top should be relative; top will then be relative to
|
||||
that directory. (dir_fd is always supported for fwalk.)
|
||||
|
||||
Caution:
|
||||
Since fwalk() yields file descriptors, those are only valid until the
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Autogenerated by Sphinx on Sun May 10 13:21:26 2026
|
||||
# Autogenerated by Sphinx on Wed Jun 10 13:03:46 2026
|
||||
# as part of the release process.
|
||||
|
||||
module_docs = {
|
||||
|
||||
Vendored
+43
-13
@@ -1,4 +1,4 @@
|
||||
# Autogenerated by Sphinx on Sun May 10 13:21:26 2026
|
||||
# Autogenerated by Sphinx on Wed Jun 10 13:03:46 2026
|
||||
# as part of the release process.
|
||||
|
||||
topics = {
|
||||
@@ -2227,9 +2227,9 @@ Added in version 3.10.
|
||||
The match statement is used for pattern matching. Syntax:
|
||||
|
||||
match_stmt: 'match' subject_expr ":" NEWLINE INDENT case_block+ DEDENT
|
||||
subject_expr: `!star_named_expression` "," `!star_named_expressions`?
|
||||
| `!named_expression`
|
||||
case_block: 'case' patterns [guard] ":" `!block`
|
||||
subject_expr: flexible_expression "," [flexible_expression_list [',']]
|
||||
| assignment_expression
|
||||
case_block: 'case' patterns [guard] ":" suite
|
||||
|
||||
Note:
|
||||
|
||||
@@ -2320,7 +2320,7 @@ section.
|
||||
Guards
|
||||
------
|
||||
|
||||
guard: "if" `!named_expression`
|
||||
guard: "if" assignment_expression
|
||||
|
||||
A "guard" (which is part of the "case") must succeed for code inside
|
||||
the "case" block to execute. It takes the form: "if" followed by an
|
||||
@@ -5772,7 +5772,8 @@ number respectively. It can be one of the following:
|
||||
| | is not supported. |
|
||||
+-----------+------------------------------------------------------------+
|
||||
|
||||
For a locale aware separator, use the "'n'" presentation type instead.
|
||||
For a locale-aware separator, use the "'n'" float presentation type or
|
||||
integer presentation type instead.
|
||||
|
||||
Changed in version 3.1: Added the "','" option (see also **PEP 378**).
|
||||
|
||||
@@ -5818,7 +5819,10 @@ The available integer presentation types are:
|
||||
+-----------+------------------------------------------------------------+
|
||||
| "'n'" | Number. This is the same as "'d'", except that it uses the |
|
||||
| | current locale setting to insert the appropriate digit |
|
||||
| | group separators. |
|
||||
| | group separators. Note that the default locale is not the |
|
||||
| | system locale. Depending on your use case, you may wish to |
|
||||
| | set "LC_NUMERIC" with "locale.setlocale()" before using |
|
||||
| | "'n'". |
|
||||
+-----------+------------------------------------------------------------+
|
||||
| None | The same as "'d'". |
|
||||
+-----------+------------------------------------------------------------+
|
||||
@@ -5892,7 +5896,10 @@ The available presentation types for "float" and "Decimal" values are:
|
||||
+-----------+------------------------------------------------------------+
|
||||
| "'n'" | Number. This is the same as "'g'", except that it uses the |
|
||||
| | current locale setting to insert the appropriate digit |
|
||||
| | group separators for the integral part of a number. |
|
||||
| | group separators for the integral part of a number. Note |
|
||||
| | that the default locale is not the system locale. |
|
||||
| | Depending on your use case, you may wish to set |
|
||||
| | "LC_NUMERIC" with "locale.setlocale()" before using "'n'". |
|
||||
+-----------+------------------------------------------------------------+
|
||||
| "'%'" | Percentage. Multiplies the number by 100 and displays in |
|
||||
| | fixed ("'f'") format, followed by a percent sign. |
|
||||
@@ -10198,9 +10205,22 @@ str.isdigit()
|
||||
decimal characters and digits that need special handling, such as
|
||||
the compatibility superscript digits. This covers digits which
|
||||
cannot be used to form numbers in base 10, like the Kharosthi
|
||||
numbers. Formally, a digit is a character that has the property
|
||||
numbers. Formally, a digit is a character that has the property
|
||||
value Numeric_Type=Digit or Numeric_Type=Decimal.
|
||||
|
||||
For example:
|
||||
|
||||
>>> '0123456789'.isdigit()
|
||||
True
|
||||
>>> '٠١٢٣٤٥٦٧٨٩'.isdigit() # Arabic-Indic digits zero to nine
|
||||
True
|
||||
>>> '⅕'.isdigit() # Vulgar fraction one fifth
|
||||
False
|
||||
>>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric()
|
||||
(False, True, True)
|
||||
|
||||
See also "isdecimal()" and "isnumeric()".
|
||||
|
||||
str.isidentifier()
|
||||
|
||||
Return "True" if the string is a valid identifier according to the
|
||||
@@ -10236,15 +10256,14 @@ str.isnumeric()
|
||||
|
||||
>>> '0123456789'.isnumeric()
|
||||
True
|
||||
>>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-indic digit zero to nine
|
||||
>>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-Indic digits zero to nine
|
||||
True
|
||||
>>> '⅕'.isnumeric() # Vulgar fraction one fifth
|
||||
True
|
||||
>>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric()
|
||||
(False, True, True)
|
||||
|
||||
See also "isdecimal()" and "isdigit()". Numeric characters are a
|
||||
superset of decimal numbers.
|
||||
See also "isdecimal()" and "isdigit()".
|
||||
|
||||
str.isprintable()
|
||||
|
||||
@@ -10626,7 +10645,7 @@ str.split(sep=None, maxsplit=-1)
|
||||
>>> " foo ".split(maxsplit=0)
|
||||
['foo ']
|
||||
|
||||
See also "join()".
|
||||
See also "join()" and "rsplit()".
|
||||
|
||||
str.splitlines(keepends=False)
|
||||
|
||||
@@ -10716,6 +10735,8 @@ str.strip(chars=None, /)
|
||||
not a prefix or suffix; rather, all combinations of its values are
|
||||
stripped.
|
||||
|
||||
Whitespace characters are defined by "str.isspace()".
|
||||
|
||||
For example:
|
||||
|
||||
>>> ' spacious '.strip()
|
||||
@@ -13311,6 +13332,9 @@ class dict(iterable, /, **kwargs)
|
||||
insertion order. This behavior was an implementation detail of
|
||||
CPython from 3.6.
|
||||
|
||||
Dictionaries are generic over two types, signifying (respectively)
|
||||
the types of the dictionary’s keys and values.
|
||||
|
||||
These are the operations that dictionaries support (and therefore,
|
||||
custom mapping types should support too):
|
||||
|
||||
@@ -14015,6 +14039,8 @@ class list(iterable=(), /)
|
||||
Many other operations also produce lists, including the "sorted()"
|
||||
built-in.
|
||||
|
||||
Lists are generic over the types of their items.
|
||||
|
||||
Lists implement all of the common and mutable sequence operations.
|
||||
Lists also provide the following additional method:
|
||||
|
||||
@@ -14105,6 +14131,10 @@ class tuple(iterable=(), /)
|
||||
|
||||
Tuples implement all of the common sequence operations.
|
||||
|
||||
Tuples are generic over the types of their contents. For more
|
||||
information, refer to the typing documentation on annotating
|
||||
tuples.
|
||||
|
||||
For heterogeneous collections of data where access by name is clearer
|
||||
than access by index, "collections.namedtuple()" may be a more
|
||||
appropriate choice than a simple tuple object.
|
||||
|
||||
Vendored
+9
-8
@@ -34,6 +34,7 @@ import builtins
|
||||
import inspect
|
||||
import keyword
|
||||
import re
|
||||
import types
|
||||
import __main__
|
||||
import warnings
|
||||
|
||||
@@ -178,14 +179,14 @@ class Completer:
|
||||
if (word[:n] == attr and
|
||||
not (noprefix and word[:n+1] == noprefix)):
|
||||
match = "%s.%s" % (expr, word)
|
||||
if isinstance(getattr(type(thisobject), word, None),
|
||||
property):
|
||||
# bpo-44752: thisobject.word is a method decorated by
|
||||
# `@property`. What follows applies a postfix if
|
||||
# thisobject.word is callable, but know we know that
|
||||
# this is not callable (because it is a property).
|
||||
# Also, getattr(thisobject, word) will evaluate the
|
||||
# property method, which is not desirable.
|
||||
|
||||
class_attr = getattr(type(thisobject), word, None)
|
||||
if isinstance(
|
||||
class_attr,
|
||||
(property, types.GetSetDescriptorType, types.MemberDescriptorType)
|
||||
) or (hasattr(class_attr, '__get__') and not callable(class_attr)):
|
||||
# Avoid evaluating descriptors, which could run
|
||||
# arbitrary code or raise exceptions.
|
||||
matches.append(match)
|
||||
continue
|
||||
if (value := getattr(thisobject, word, None)) is not None:
|
||||
|
||||
Vendored
+10
-6
@@ -885,10 +885,14 @@ def move(src, dst, copy_function=copy2):
|
||||
If dst already exists but is not a directory, it may be overwritten
|
||||
depending on os.rename() semantics.
|
||||
|
||||
If the destination is on our current filesystem, then rename() is used.
|
||||
Otherwise, src is copied to the destination and then removed. Symlinks are
|
||||
recreated under the new name if os.rename() fails because of cross
|
||||
filesystem renames.
|
||||
os.rename() is preferably used if the source and destination are on the
|
||||
same filesystem. In case os.rename() fails due to OSError (e.g. the user
|
||||
has write permission to *dst* file but not to its parent directory),
|
||||
this method falls back to using *copy_function* silently.
|
||||
Symlinks are also recreated under the new name if os.rename() fails
|
||||
because of cross filesystem renames.
|
||||
|
||||
It's recommended to use os.rename() if atomic move is strictly required.
|
||||
|
||||
The optional `copy_function` argument is a callable that will be used
|
||||
to copy the source or it will be delegated to `copytree`.
|
||||
@@ -940,8 +944,8 @@ def move(src, dst, copy_function=copy2):
|
||||
return real_dst
|
||||
|
||||
def _destinsrc(src, dst):
|
||||
src = os.path.abspath(src)
|
||||
dst = os.path.abspath(dst)
|
||||
src = os.path.realpath(src)
|
||||
dst = os.path.realpath(dst)
|
||||
if not src.endswith(os.path.sep):
|
||||
src += os.path.sep
|
||||
if not dst.endswith(os.path.sep):
|
||||
|
||||
Vendored
+32
-19
@@ -498,7 +498,7 @@ class _Stream:
|
||||
|
||||
if flag & 4:
|
||||
xlen = ord(self.__read(1)) + 256 * ord(self.__read(1))
|
||||
self.read(xlen)
|
||||
self.__read(xlen)
|
||||
if flag & 8:
|
||||
while True:
|
||||
s = self.__read(1)
|
||||
@@ -830,16 +830,22 @@ def _get_filtered_attrs(member, dest_path, for_data=True):
|
||||
if member.islnk() or member.issym():
|
||||
if os.path.isabs(member.linkname):
|
||||
raise AbsoluteLinkError(member)
|
||||
# A link member that resolves to the destination directory itself
|
||||
# would replace it with a (sym)link, redirecting the destination
|
||||
# for all subsequent members.
|
||||
if target_path == dest_path:
|
||||
raise OutsideDestinationError(member, target_path)
|
||||
normalized = os.path.normpath(member.linkname)
|
||||
if normalized != member.linkname:
|
||||
new_attrs['linkname'] = normalized
|
||||
if member.issym():
|
||||
target_path = os.path.join(dest_path,
|
||||
os.path.dirname(name),
|
||||
member.linkname)
|
||||
# The symlink is created at `name` with trailing separators
|
||||
# stripped, so its target is relative to the directory
|
||||
# containing that path.
|
||||
link_dir = os.path.dirname(name.rstrip('/' + os.sep))
|
||||
target_path = os.path.join(dest_path, link_dir, normalized)
|
||||
else:
|
||||
target_path = os.path.join(dest_path,
|
||||
member.linkname)
|
||||
target_path = os.path.join(dest_path, normalized)
|
||||
target_path = os.path.realpath(target_path,
|
||||
strict=os.path.ALLOW_MISSING)
|
||||
if os.path.commonpath([target_path, dest_path]) != dest_path:
|
||||
@@ -893,11 +899,14 @@ class TarInfo(object):
|
||||
size = 'Size in bytes.',
|
||||
mtime = 'Time of last modification.',
|
||||
chksum = 'Header checksum.',
|
||||
type = ('File type. type is usually one of these constants: '
|
||||
'REGTYPE, AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, '
|
||||
'CONTTYPE, CHRTYPE, BLKTYPE, GNUTYPE_SPARSE.'),
|
||||
type = ('File type. type is usually one of these constants: '
|
||||
'REGTYPE,\n'
|
||||
'AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, '
|
||||
'CONTTYPE, CHRTYPE,\n'
|
||||
'BLKTYPE, GNUTYPE_SPARSE.'),
|
||||
linkname = ('Name of the target file name, which is only present '
|
||||
'in TarInfo objects of type LNKTYPE and SYMTYPE.'),
|
||||
'in TarInfo\n'
|
||||
'objects of type LNKTYPE and SYMTYPE.'),
|
||||
uname = 'User name.',
|
||||
gname = 'Group name.',
|
||||
devmajor = 'Device major number.',
|
||||
@@ -905,7 +914,8 @@ class TarInfo(object):
|
||||
offset = 'The tar header starts here.',
|
||||
offset_data = "The file's data starts here.",
|
||||
pax_headers = ('A dictionary containing key-value pairs of an '
|
||||
'associated pax extended header.'),
|
||||
'associated pax\n'
|
||||
'extended header.'),
|
||||
sparse = 'Sparse member information.',
|
||||
_tarfile = None,
|
||||
_sparse_structs = None,
|
||||
@@ -2267,10 +2277,11 @@ class TarFile(object):
|
||||
return tarinfo
|
||||
|
||||
def list(self, verbose=True, *, members=None):
|
||||
"""Print a table of contents to sys.stdout. If 'verbose' is False, only
|
||||
the names of the members are printed. If it is True, an 'ls -l'-like
|
||||
output is produced. 'members' is optional and must be a subset of the
|
||||
list returned by getmembers().
|
||||
"""Print a table of contents to sys.stdout.
|
||||
|
||||
If 'verbose' is False, only the names of the members are printed.
|
||||
If it is True, an 'ls -l'-like output is produced. 'members' is
|
||||
optional and must be a subset of the list returned by getmembers().
|
||||
"""
|
||||
# Convert tarinfo type to stat type.
|
||||
type2mode = {REGTYPE: stat.S_IFREG, SYMTYPE: stat.S_IFLNK,
|
||||
@@ -2361,10 +2372,12 @@ class TarFile(object):
|
||||
self.addfile(tarinfo)
|
||||
|
||||
def addfile(self, tarinfo, fileobj=None):
|
||||
"""Add the TarInfo object 'tarinfo' to the archive. If 'tarinfo' represents
|
||||
a non zero-size regular file, the 'fileobj' argument should be a binary file,
|
||||
and tarinfo.size bytes are read from it and added to the archive.
|
||||
You can create TarInfo objects directly, or by using gettarinfo().
|
||||
"""Add the TarInfo object 'tarinfo' to the archive.
|
||||
|
||||
If 'tarinfo' represents a non zero-size regular file, the 'fileobj'
|
||||
argument should be a binary file, and tarinfo.size bytes are read
|
||||
from it and added to the archive. You can create TarInfo objects
|
||||
directly, or by using gettarinfo().
|
||||
"""
|
||||
self._check("awx")
|
||||
|
||||
|
||||
Vendored
+30
@@ -7313,6 +7313,36 @@ class ExtensionModuleTests(unittest.TestCase):
|
||||
self.assertEqual(out, b"a" * 8)
|
||||
self.assertEqual(err, b"")
|
||||
|
||||
@support.cpython_only
|
||||
@support.subTests(("setup", "call"), [
|
||||
("obj = _datetime.timedelta", "obj(seconds=2)"),
|
||||
("obj = _datetime.timedelta(seconds=2)", "obj.total_seconds()"),
|
||||
("obj = _datetime.date(2026, 6, 7)", "obj.isocalendar()"),
|
||||
])
|
||||
def test_static_datetime_types_outlive_collected_module(self, setup, call):
|
||||
# gh-151039: This code used to crash
|
||||
script = f"""if True:
|
||||
import sys, gc
|
||||
import _datetime
|
||||
|
||||
{setup} # static C type, survives the module
|
||||
del sys.modules['_datetime']
|
||||
del _datetime
|
||||
sys.modules['_datetime'] = None # block re-import
|
||||
gc.collect() # module object is collected
|
||||
|
||||
try:
|
||||
{call} # used to be a segmentation fault
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("ImportError not raised")
|
||||
"""
|
||||
rc, out, err = script_helper.assert_python_ok("-c", script)
|
||||
self.assertEqual(rc, 0)
|
||||
self.assertEqual(out, b'')
|
||||
self.assertEqual(err, b'')
|
||||
|
||||
|
||||
def load_tests(loader, standard_tests, pattern):
|
||||
standard_tests.addTest(ZoneInfoCompleteTest())
|
||||
|
||||
Vendored
+15
@@ -3227,3 +3227,18 @@ def control_characters_c0() -> list[str]:
|
||||
C0 control characters defined as the byte range 0x00-0x1F, and 0x7F.
|
||||
"""
|
||||
return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]
|
||||
|
||||
|
||||
STATUS_DLL_INIT_FAILED = 0xC0000142
|
||||
def skip_on_low_desktop_heap_memory_subprocess(returncode):
|
||||
if sys.platform not in ('win32', 'cygwin'):
|
||||
return
|
||||
# On Windows, STATUS_DLL_INIT_FAILED is a generic error code that could
|
||||
# come from any of the DLLs being loaded when a new Python process is
|
||||
# created. In practice, it's likely a memory allocation failure in the
|
||||
# desktop heap memory which caused the DLL init failure, especially on
|
||||
# process created with CREATE_NEW_CONSOLE creation flag. See the article:
|
||||
# https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory
|
||||
if returncode == STATUS_DLL_INIT_FAILED:
|
||||
raise unittest.SkipTest('gh-150436: DLL init failed, likely because '
|
||||
'of low desktop heap memory')
|
||||
Vendored
+16
-15
@@ -1,11 +1,11 @@
|
||||
# Simple test suite for http/cookies.py
|
||||
import base64
|
||||
import copy
|
||||
import unittest
|
||||
import doctest
|
||||
from http import cookies
|
||||
import pickle
|
||||
from test import support
|
||||
import urllib.parse
|
||||
|
||||
|
||||
class CookieTests(unittest.TestCase):
|
||||
@@ -131,8 +131,8 @@ class CookieTests(unittest.TestCase):
|
||||
|
||||
@support.requires_resource('cpu')
|
||||
def test_unquote_large(self):
|
||||
# n = 10**6
|
||||
n = 10**4 # XXX: RUSTPYTHON; This takes more than 10 minutes to run. lower to 4
|
||||
n = 10**6
|
||||
n = 10**4 # TODO: RUSTPYTHON; This takes more than 10 minutes to run. lower to 4
|
||||
for encoded in r'\\', r'\134':
|
||||
with self.subTest(encoded):
|
||||
data = 'a="b=' + encoded*n + ';"'
|
||||
@@ -153,19 +153,19 @@ class CookieTests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(C.output(['path']),
|
||||
'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme')
|
||||
cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme; Version=1').decode('ascii')
|
||||
cookie_encoded = urllib.parse.quote('Customer="WILE_E_COYOTE"; Path=/acme; Version=1', safe='', encoding='utf-8')
|
||||
self.assertEqual(C.js_output(), fr"""
|
||||
<script type="text/javascript">
|
||||
<!-- begin hiding
|
||||
document.cookie = atob("{cookie_encoded}");
|
||||
document.cookie = decodeURIComponent("{cookie_encoded}");
|
||||
// end hiding -->
|
||||
</script>
|
||||
""")
|
||||
cookie_encoded = base64.b64encode(b'Customer="WILE_E_COYOTE"; Path=/acme').decode('ascii')
|
||||
cookie_encoded = urllib.parse.quote('Customer="WILE_E_COYOTE"; Path=/acme', safe='', encoding='utf-8')
|
||||
self.assertEqual(C.js_output(['path']), fr"""
|
||||
<script type="text/javascript">
|
||||
<!-- begin hiding
|
||||
document.cookie = atob("{cookie_encoded}");
|
||||
document.cookie = decodeURIComponent("{cookie_encoded}");
|
||||
// end hiding -->
|
||||
</script>
|
||||
""")
|
||||
@@ -270,19 +270,19 @@ class CookieTests(unittest.TestCase):
|
||||
|
||||
self.assertEqual(C.output(['path']),
|
||||
'Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme')
|
||||
expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1').decode('ascii')
|
||||
expected_encoded_cookie = urllib.parse.quote('Customer=\"WILE_E_COYOTE\"; Path=/acme; Version=1', safe='', encoding='utf-8')
|
||||
self.assertEqual(C.js_output(), fr"""
|
||||
<script type="text/javascript">
|
||||
<!-- begin hiding
|
||||
document.cookie = atob("{expected_encoded_cookie}");
|
||||
document.cookie = decodeURIComponent("{expected_encoded_cookie}");
|
||||
// end hiding -->
|
||||
</script>
|
||||
""")
|
||||
expected_encoded_cookie = base64.b64encode(b'Customer=\"WILE_E_COYOTE\"; Path=/acme').decode('ascii')
|
||||
expected_encoded_cookie = urllib.parse.quote('Customer=\"WILE_E_COYOTE\"; Path=/acme', safe='', encoding='utf-8')
|
||||
self.assertEqual(C.js_output(['path']), fr"""
|
||||
<script type="text/javascript">
|
||||
<!-- begin hiding
|
||||
document.cookie = atob("{expected_encoded_cookie}");
|
||||
document.cookie = decodeURIComponent("{expected_encoded_cookie}");
|
||||
// end hiding -->
|
||||
</script>
|
||||
""")
|
||||
@@ -373,13 +373,14 @@ class MorselTests(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
M.output(),
|
||||
"Set-Cookie: %s=%s; Path=/foo" % (i, "%s_coded_val" % i))
|
||||
expected_encoded_cookie = base64.b64encode(
|
||||
("%s=%s; Path=/foo" % (i, "%s_coded_val" % i)).encode("ascii")
|
||||
).decode('ascii')
|
||||
expected_encoded_cookie = urllib.parse.quote(
|
||||
"%s=%s; Path=/foo" % (i, "%s_coded_val" % i),
|
||||
safe='', encoding='utf-8',
|
||||
)
|
||||
expected_js_output = """
|
||||
<script type="text/javascript">
|
||||
<!-- begin hiding
|
||||
document.cookie = atob("%s");
|
||||
document.cookie = decodeURIComponent("%s");
|
||||
// end hiding -->
|
||||
</script>
|
||||
""" % (expected_encoded_cookie,)
|
||||
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
{"ingredients":["frog", "water", "chocolate", "glucose"]}
|
||||
{"ingredients":["chocolate","steel bolts"]}
|
||||
Vendored
+63
@@ -1,4 +1,5 @@
|
||||
from test.test_json import CTest
|
||||
from test.support import gc_collect
|
||||
|
||||
import unittest # XXX: RUSTPYTHON; importing to be able to skip tests
|
||||
|
||||
@@ -117,3 +118,65 @@ class TestEncode(CTest):
|
||||
self.assertEqual(enc(['spam', {'ham': 'eggs'}], 3)[0], expected2)
|
||||
self.assertRaises(TypeError, enc, ['spam', {'ham': 'eggs'}], 3.0)
|
||||
self.assertRaises(TypeError, enc, ['spam', {'ham': 'eggs'}])
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: 'NoneType' object is not callable
|
||||
def test_mutate_dict_items_during_encode(self):
|
||||
# gh-142831: Clearing the items list via a re-entrant key encoder
|
||||
# must not cause a use-after-free. BadDict.items() returns a
|
||||
# mutable list; encode_str clears it while iterating.
|
||||
items = None
|
||||
|
||||
class BadDict(dict):
|
||||
def items(self):
|
||||
nonlocal items
|
||||
items = [("boom", object())]
|
||||
return items
|
||||
|
||||
cleared = False
|
||||
def encode_str(obj):
|
||||
nonlocal items, cleared
|
||||
if items is not None:
|
||||
items.clear()
|
||||
items = None
|
||||
cleared = True
|
||||
gc_collect()
|
||||
return '"x"'
|
||||
|
||||
encoder = self.json.encoder.c_make_encoder(
|
||||
None, lambda o: "null",
|
||||
encode_str, None,
|
||||
": ", ", ", False,
|
||||
False, True
|
||||
)
|
||||
|
||||
# Must not crash (use-after-free under ASan before fix)
|
||||
encoder(BadDict(real=1), 0)
|
||||
self.assertTrue(cleared)
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: 'NoneType' object is not callable
|
||||
def test_mutate_list_during_encode(self):
|
||||
# gh-142831: Clearing a list mid-iteration via the default
|
||||
# callback must not cause a use-after-free.
|
||||
call_count = 0
|
||||
lst = [object() for _ in range(10)]
|
||||
|
||||
def default(obj):
|
||||
nonlocal call_count
|
||||
call_count += 1
|
||||
if call_count == 3:
|
||||
lst.clear()
|
||||
gc_collect()
|
||||
return None
|
||||
|
||||
encoder = self.json.encoder.c_make_encoder(
|
||||
None, default,
|
||||
self.json.encoder.c_encode_basestring, None,
|
||||
": ", ", ", False,
|
||||
False, True
|
||||
)
|
||||
|
||||
# Must not crash (use-after-free under ASan before fix)
|
||||
encoder(lst, 0)
|
||||
# Verify the mutation path was actually hit and the loop
|
||||
# stopped iterating after the list was cleared.
|
||||
self.assertEqual(call_count, 3)
|
||||
Vendored
+9
@@ -1,4 +1,5 @@
|
||||
import errno
|
||||
import pathlib
|
||||
import os
|
||||
import sys
|
||||
import textwrap
|
||||
@@ -157,6 +158,14 @@ class TestMain(unittest.TestCase):
|
||||
self.assertEqual(process.stdout, self.jsonlines_expect)
|
||||
self.assertEqual(process.stderr, '')
|
||||
|
||||
@force_not_colorized
|
||||
def test_jsonlines_from_file(self):
|
||||
jsonl = pathlib.Path(__file__).parent / 'json_lines.jsonl'
|
||||
args = sys.executable, '-m', self.module, '--json-lines', jsonl
|
||||
process = subprocess.run(args, capture_output=True, text=True, check=True)
|
||||
self.assertEqual(process.stdout, self.jsonlines_expect)
|
||||
self.assertEqual(process.stderr, '')
|
||||
|
||||
def test_help_flag(self):
|
||||
rc, out, err = assert_python_ok('-m', self.module, '-h',
|
||||
PYTHON_COLORS='0')
|
||||
|
||||
Vendored
-2
@@ -4043,7 +4043,6 @@ class TestSendfile(unittest.IsolatedAsyncioTestCase):
|
||||
@requires_headers_trailers
|
||||
@requires_32b
|
||||
async def test_headers_overflow_32bits(self):
|
||||
self.server.handler_instance.accumulate = False
|
||||
with self.assertRaises(OSError) as cm:
|
||||
await self.async_sendfile(self.sockno, self.fileno, 0, 0,
|
||||
headers=[b"x" * 2**16] * 2**15)
|
||||
@@ -4052,7 +4051,6 @@ class TestSendfile(unittest.IsolatedAsyncioTestCase):
|
||||
@requires_headers_trailers
|
||||
@requires_32b
|
||||
async def test_trailers_overflow_32bits(self):
|
||||
self.server.handler_instance.accumulate = False
|
||||
with self.assertRaises(OSError) as cm:
|
||||
await self.async_sendfile(self.sockno, self.fileno, 0, 0,
|
||||
trailers=[b"x" * 2**16] * 2**15)
|
||||
|
||||
Vendored
+52
@@ -1,6 +1,7 @@
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
import builtins
|
||||
import types
|
||||
import rlcompleter
|
||||
from test.support import MISSING_C_DOCSTRINGS
|
||||
|
||||
@@ -136,6 +137,57 @@ class TestRlcompleter(unittest.TestCase):
|
||||
self.assertEqual(completer.complete('f.b', 0), 'f.bar')
|
||||
self.assertFalse(f.property_called)
|
||||
|
||||
def test_released_memoryview_completion_works(self):
|
||||
mv = memoryview(b"abc")
|
||||
mv.release()
|
||||
|
||||
self.assertIsInstance(type(mv).shape, types.GetSetDescriptorType)
|
||||
self.assertIsInstance(type(mv).strides, types.GetSetDescriptorType)
|
||||
|
||||
completer = rlcompleter.Completer(dict(mv=mv))
|
||||
matches = completer.attr_matches('mv.')
|
||||
|
||||
# These are getset descriptors on memoryview and should be completed
|
||||
# without evaluating the released-memoryview getters.
|
||||
self.assertIn('mv.shape', matches)
|
||||
self.assertIn('mv.strides', matches)
|
||||
|
||||
def test_member_descriptor_not_evaluated(self):
|
||||
class Foo:
|
||||
__slots__ = ("boom",)
|
||||
boom_accesses = 0
|
||||
|
||||
def __getattribute__(self, name):
|
||||
if name == "boom":
|
||||
type(self).boom_accesses += 1
|
||||
raise RuntimeError("boom access should be skipped")
|
||||
return super().__getattribute__(name)
|
||||
|
||||
self.assertIsInstance(Foo.boom, types.MemberDescriptorType)
|
||||
|
||||
completer = rlcompleter.Completer(dict(f=Foo()))
|
||||
matches = completer.attr_matches('f.')
|
||||
self.assertIn('f.boom', matches)
|
||||
self.assertEqual(Foo.boom_accesses, 0)
|
||||
|
||||
def test_raising_descriptor_completion_works(self):
|
||||
class ExplodingDescriptor:
|
||||
def __init__(self):
|
||||
self.instance_get_calls = 0
|
||||
|
||||
def __get__(self, obj, owner):
|
||||
if obj is None:
|
||||
return self
|
||||
self.instance_get_calls += 1
|
||||
raise RuntimeError("descriptor getter exploded")
|
||||
|
||||
class Foo:
|
||||
boom = ExplodingDescriptor()
|
||||
|
||||
completer = rlcompleter.Completer(dict(f=Foo()))
|
||||
matches = completer.attr_matches('f.')
|
||||
self.assertIn('f.boom', matches)
|
||||
self.assertEqual(Foo.boom.instance_get_calls, 0)
|
||||
|
||||
def test_uncreated_attr(self):
|
||||
# Attributes like properties and slots should be completed even when
|
||||
|
||||
Vendored
+17
@@ -2888,6 +2888,23 @@ class TestMove(BaseTest, unittest.TestCase):
|
||||
finally:
|
||||
os_helper.rmtree(TESTFN)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_destinsrc_symlink_bypass(self):
|
||||
tmp = self.mkdtemp()
|
||||
src = os.path.join(tmp, 'src')
|
||||
os.makedirs(src)
|
||||
# tmp/link -> tmp (one level up)
|
||||
link = os.path.join(tmp, 'link')
|
||||
os.symlink(tmp, link)
|
||||
# raw path: tmp/link/src/sub - no src prefix in string space
|
||||
# real path: tmp/src/sub - physically inside src
|
||||
dst = os.path.join(link, 'src', 'sub')
|
||||
self.assertTrue(
|
||||
shutil._destinsrc(src, dst),
|
||||
msg='_destinsrc failed to detect dst inside src via symlink '
|
||||
'(dst=%s, src=%s)' % (dst, src),
|
||||
)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
@mock_rename
|
||||
def test_move_file_symlink(self):
|
||||
|
||||
Vendored
+148
-36
@@ -892,10 +892,39 @@ class MiscReadTestBase(CommonReadTest):
|
||||
self._assert_on_file_content(hardlink_filepath, sha256_regtype)
|
||||
|
||||
|
||||
class GzipReadTestBase:
|
||||
|
||||
def test_read_with_extra_field(self):
|
||||
with open(self.tarname, 'rb') as f:
|
||||
data = bytearray(f.read())
|
||||
flags = data[3]
|
||||
self.assertEqual(flags, 8)
|
||||
data[3] = flags | 4
|
||||
data[10:10] = b'\x05\x00extra'
|
||||
with open(tmpname, 'wb') as f:
|
||||
f.write(data)
|
||||
print(self.mode)
|
||||
with tarfile.open(tmpname, mode=self.mode):
|
||||
pass
|
||||
|
||||
def test_read_with_file_comment(self):
|
||||
with open(self.tarname, 'rb') as f:
|
||||
data = bytearray(f.read())
|
||||
flags = data[3]
|
||||
self.assertEqual(flags, 8)
|
||||
data[3] = flags | 16
|
||||
i = data.index(0, 10) + 1
|
||||
data[i:i] = b'comment\x00'
|
||||
with open(tmpname, 'wb') as f:
|
||||
f.write(data)
|
||||
with tarfile.open(tmpname, mode=self.mode):
|
||||
pass
|
||||
|
||||
|
||||
class MiscReadTest(MiscReadTestBase, unittest.TestCase):
|
||||
test_fail_comp = None
|
||||
|
||||
class GzipMiscReadTest(GzipTest, MiscReadTestBase, unittest.TestCase):
|
||||
class GzipMiscReadTest(GzipTest, GzipReadTestBase, MiscReadTestBase, unittest.TestCase):
|
||||
pass
|
||||
|
||||
class Bz2MiscReadTest(Bz2Test, MiscReadTestBase, unittest.TestCase):
|
||||
@@ -969,7 +998,7 @@ class StreamReadTest(CommonReadTest, unittest.TestCase):
|
||||
finally:
|
||||
tar1.close()
|
||||
|
||||
class GzipStreamReadTest(GzipTest, StreamReadTest):
|
||||
class GzipStreamReadTest(GzipTest, GzipReadTestBase, StreamReadTest):
|
||||
pass
|
||||
|
||||
class Bz2StreamReadTest(Bz2Test, StreamReadTest):
|
||||
@@ -3682,6 +3711,39 @@ class TestExtractionFilters(unittest.TestCase):
|
||||
# The destination for the extraction, within `outerdir`
|
||||
destdir = outerdir / 'dest'
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# Posix and Windows have different pathname resolution:
|
||||
# either symlink or a '..' component resolve first.
|
||||
# Let's see which we are on.
|
||||
if os_helper.can_symlink():
|
||||
testpath = os.path.join(TEMPDIR, 'resolution_test')
|
||||
os.mkdir(testpath)
|
||||
|
||||
# testpath/current links to `.` which is all of:
|
||||
# - `testpath`
|
||||
# - `testpath/current`
|
||||
# - `testpath/current/current`
|
||||
# - etc.
|
||||
os.symlink('.', os.path.join(testpath, 'current'))
|
||||
|
||||
# we'll test where `testpath/current/../file` ends up
|
||||
with open(os.path.join(testpath, 'current', '..', 'file'), 'w'):
|
||||
pass
|
||||
|
||||
if os.path.exists(os.path.join(testpath, 'file')):
|
||||
# Windows collapses 'current\..' to '.' first, leaving
|
||||
# 'testpath\file'
|
||||
cls.dotdot_resolves_early = True
|
||||
elif os.path.exists(os.path.join(testpath, '..', 'file')):
|
||||
# Posix resolves 'current' to '.' first, leaving
|
||||
# 'testpath/../file'
|
||||
cls.dotdot_resolves_early = False
|
||||
else:
|
||||
raise AssertionError('Could not determine link resolution')
|
||||
else:
|
||||
cls.dotdot_resolves_early = False
|
||||
|
||||
@contextmanager
|
||||
def check_context(self, tar, filter, *, check_flag=True):
|
||||
"""Extracts `tar` to `self.destdir` and allows checking the result
|
||||
@@ -3853,10 +3915,19 @@ class TestExtractionFilters(unittest.TestCase):
|
||||
+ "which is outside the destination")
|
||||
|
||||
with self.check_context(arc.open(), 'data'):
|
||||
self.expect_exception(
|
||||
tarfile.LinkOutsideDestinationError,
|
||||
"""'parent' would link to ['"].*outerdir['"], """
|
||||
+ "which is outside the destination")
|
||||
if self.dotdot_resolves_early:
|
||||
# 'current/../..' normalises to '..', which is rejected.
|
||||
self.expect_exception(
|
||||
tarfile.LinkOutsideDestinationError,
|
||||
"""'parent' would link to ['"].*outerdir['"], """
|
||||
+ "which is outside the destination")
|
||||
else:
|
||||
# 'current/..' normalises to '.'; the rewritten link is
|
||||
# created and 'parent/evil' lands harmlessly inside the
|
||||
# destination.
|
||||
self.expect_file('current', symlink_to='.')
|
||||
self.expect_file('parent', symlink_to='.')
|
||||
self.expect_file('evil')
|
||||
|
||||
else:
|
||||
# No symlink support. The symlinks are ignored.
|
||||
@@ -3946,35 +4017,6 @@ class TestExtractionFilters(unittest.TestCase):
|
||||
# Test interplaying symlinks
|
||||
# Inspired by 'dirsymlink2b' in jwilk/traversal-archives
|
||||
|
||||
# Posix and Windows have different pathname resolution:
|
||||
# either symlink or a '..' component resolve first.
|
||||
# Let's see which we are on.
|
||||
if os_helper.can_symlink():
|
||||
testpath = os.path.join(TEMPDIR, 'resolution_test')
|
||||
os.mkdir(testpath)
|
||||
|
||||
# testpath/current links to `.` which is all of:
|
||||
# - `testpath`
|
||||
# - `testpath/current`
|
||||
# - `testpath/current/current`
|
||||
# - etc.
|
||||
os.symlink('.', os.path.join(testpath, 'current'))
|
||||
|
||||
# we'll test where `testpath/current/../file` ends up
|
||||
with open(os.path.join(testpath, 'current', '..', 'file'), 'w'):
|
||||
pass
|
||||
|
||||
if os.path.exists(os.path.join(testpath, 'file')):
|
||||
# Windows collapses 'current\..' to '.' first, leaving
|
||||
# 'testpath\file'
|
||||
dotdot_resolves_early = True
|
||||
elif os.path.exists(os.path.join(testpath, '..', 'file')):
|
||||
# Posix resolves 'current' to '.' first, leaving
|
||||
# 'testpath/../file'
|
||||
dotdot_resolves_early = False
|
||||
else:
|
||||
raise AssertionError('Could not determine link resolution')
|
||||
|
||||
with ArchiveMaker() as arc:
|
||||
|
||||
# `current` links to `.` which is both the destination directory
|
||||
@@ -4010,7 +4052,7 @@ class TestExtractionFilters(unittest.TestCase):
|
||||
|
||||
with self.check_context(arc.open(), 'data'):
|
||||
if os_helper.can_symlink():
|
||||
if dotdot_resolves_early:
|
||||
if self.dotdot_resolves_early:
|
||||
# Fail when extracting a file outside destination
|
||||
self.expect_exception(
|
||||
tarfile.OutsideDestinationError,
|
||||
@@ -4130,6 +4172,76 @@ class TestExtractionFilters(unittest.TestCase):
|
||||
+ """['"].*moo['"], which is outside the """
|
||||
+ "destination")
|
||||
|
||||
@symlink_test
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_normpath_realpath_mismatch(self):
|
||||
# The link-target check must validate the value that will actually
|
||||
# be written to disk (the normalised linkname), not the original.
|
||||
# Here 'a' is a symlink to a deep nonexistent path, so realpath()
|
||||
# of 'a/../../...' stays inside the destination while normpath()
|
||||
# collapses 'a/..' lexically and escapes.
|
||||
depth = len(self.destdir.parts) + 5
|
||||
deep = '/'.join(f'p{i}' for i in range(depth))
|
||||
sneaky = 'a/' + '../' * depth + 'flag'
|
||||
for kind in 'symlink_to', 'hardlink_to':
|
||||
with self.subTest(kind):
|
||||
with ArchiveMaker() as arc:
|
||||
arc.add('a', symlink_to=deep)
|
||||
arc.add('escape', **{kind: sneaky})
|
||||
with self.check_context(arc.open(), 'data'):
|
||||
self.expect_exception(
|
||||
tarfile.LinkOutsideDestinationError)
|
||||
|
||||
@symlink_test
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_symlink_trailing_slash(self):
|
||||
# A trailing slash on a symlink member's name must not cause the
|
||||
# link target to be resolved relative to the wrong directory.
|
||||
with ArchiveMaker() as arc:
|
||||
t = tarfile.TarInfo('x/')
|
||||
t.type = tarfile.SYMTYPE
|
||||
t.linkname = '..'
|
||||
arc.tar_w.addfile(t)
|
||||
arc.add('x/escaped', content='hi')
|
||||
|
||||
with self.check_context(arc.open(), 'data'):
|
||||
self.expect_exception(tarfile.LinkOutsideDestinationError)
|
||||
|
||||
@symlink_test
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_link_at_destination(self):
|
||||
# A link member whose name resolves to the destination directory
|
||||
# itself must be rejected: otherwise the destination is replaced
|
||||
# by a symlink and later members can be redirected through it.
|
||||
for name in '', '.', './':
|
||||
with ArchiveMaker() as arc:
|
||||
t = tarfile.TarInfo(name)
|
||||
t.type = tarfile.SYMTYPE
|
||||
t.linkname = '.'
|
||||
arc.tar_w.addfile(t)
|
||||
|
||||
with self.check_context(arc.open(), 'data'):
|
||||
self.expect_exception(tarfile.OutsideDestinationError)
|
||||
|
||||
@symlink_test
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_empty_name_symlink_chain(self):
|
||||
# Regression test for a chain of empty-named symlinks that
|
||||
# incrementally redirects the destination outwards.
|
||||
with ArchiveMaker() as arc:
|
||||
for name, target in [('', ''), ('a/', '..'),
|
||||
('', 'dummy'), ('', 'a'),
|
||||
('b/', '..'),
|
||||
('', 'dummy'), ('', 'a/b')]:
|
||||
t = tarfile.TarInfo(name)
|
||||
t.type = tarfile.SYMTYPE
|
||||
t.linkname = target
|
||||
arc.tar_w.addfile(t)
|
||||
arc.add('escaped', content='hi')
|
||||
|
||||
with self.check_context(arc.open(), 'data'):
|
||||
self.expect_exception(tarfile.FilterError)
|
||||
|
||||
@symlink_test
|
||||
def test_deep_symlink(self):
|
||||
# Test that symlinks and hardlinks inside a directory
|
||||
|
||||
Reference in new issue
Block a user