team-10/venv/Lib/site-packages/validators/country.py
2025-08-02 02:00:33 +02:00

355 lines
15 KiB
Python

"""Country."""
# local
from validators.utils import validator
# fmt: off
_alpha3_to_alpha2 = {
# A
"ABW": "AW", "AFG": "AF", "AGO": "AO", "AIA": "AI", "ALB": "AL", "AND": "AD", "ANT": "AN",
"ARE": "AE", "ARG": "AR", "ARM": "AM", "ASM": "AS", "ATA": "AQ", "ATF": "TF", "ATG": "AG",
"AUS": "AU", "AUT": "AT", "AZE": "AZ",
# B
"BDI": "BI", "BEL": "BE", "BEN": "BJ", "BFA": "BF", "BGD": "BD", "BGR": "BG", "BHR": "BH",
"BHS": "BS", "BIH": "BA", "BLR": "BY", "BLZ": "BZ", "BMU": "BM", "BOL": "BO", "BRA": "BR",
"BRB": "BB", "BRN": "BN", "BTN": "BT", "BVT": "BV", "BWA": "BW",
# C
"CAF": "CF", "CAN": "CA", "CCK": "CC", "CHE": "CH", "CHL": "CL", "CHN": "CN", "CMR": "CM",
"COD": "CD", "COG": "CG", "COK": "CK", "COL": "CO", "COM": "KM", "CPV": "CV", "CRI": "CR",
"CUB": "CU", "CXR": "CX", "CYM": "KY", "CYP": "CY", "CZE": "CZ",
# D
"DEU": "DE", "DJI": "DJ", "DMA": "DM", "DNK": "DK", "DOM": "DO", "DZA": "DZ",
# E
"ECU": "EC", "EGY": "EG", "ERI": "ER", "ESH": "EH", "ESP": "ES", "EST": "EE", "ETH": "ET",
# F
"FIN": "FI", "FJI": "FJ", "FLK": "FK", "FRA": "FR", "FRO": "FO", "FSM": "FM",
# G
"GAB": "GA", "GBR": "GB", "GEO": "GE", "GGY": "GG", "GHA": "GH", "GIB": "GI", "GIN": "GN",
"GLP": "GP", "GMB": "GM", "GNB": "GW", "GNQ": "GQ", "GRC": "GR", "GRD": "GD", "GRL": "GL",
"GTM": "GT", "GUF": "GF", "GUM": "GU", "GUY": "GY",
# H
"HKG": "HK", "HMD": "HM", "HND": "HN", "HRV": "HR", "HTI": "HT", "HUN": "HU",
# I
"IDN": "ID", "IMN": "IM", "IND": "IN", "IOT": "IO", "IRL": "IE", "IRN": "IR", "IRQ": "IQ",
"ISL": "IS", "ISR": "IL", "ITA": "IT",
# J
"JAM": "JM", "JEY": "JE", "JOR": "JO", "JPN": "JP",
# K
"KAZ": "KZ", "KEN": "KE", "KGZ": "KG", "KHM": "KH", "KIR": "KI", "KNA": "KN", "KOR": "KR",
"KWT": "KW",
# L
"LAO": "LA", "LBN": "LB", "LBR": "LR", "LBY": "LY", "LCA": "LC", "LIE": "LI", "LKA": "LK",
"LSO": "LS", "LTU": "LT", "LUX": "LU", "LVA": "LV",
# M
"MAC": "MO", "MAR": "MA", "MCO": "MC", "MDA": "MD", "MDG": "MG", "MDV": "MV", "MEX": "MX",
"MHL": "MH", "MKD": "MK", "MLI": "ML", "MLT": "MT", "MMR": "MM", "MNE": "ME", "MNG": "MN",
"MNP": "MP", "MOZ": "MZ", "MRT": "MR", "MSR": "MS", "MTQ": "MQ", "MUS": "MU", "MWI": "MW",
"MYS": "MY", "MYT": "YT",
# N
"NAM": "NA", "NCL": "NC", "NER": "NE", "NFK": "NF", "NGA": "NG", "NIC": "NI", "NIU": "NU",
"NLD": "NL", "NOR": "NO", "NPL": "NP", "NRU": "NR", "NZL": "NZ",
# O
"OMN": "OM",
# P
"PAK": "PK", "PAN": "PA", "PCN": "PN", "PER": "PE", "PHL": "PH", "PLW": "PW", "PNG": "PG",
"POL": "PL", "PRI": "PR", "PRK": "KP", "PRT": "PT", "PRY": "PY", "PSE": "PS", "PYF": "PF",
# Q
"QAT": "QA",
# R
"REU": "RE", "ROU": "RO", "RUS": "RU", "RWA": "RW",
# S
"SAU": "SA", "SDN": "SD", "SEN": "SN", "SGP": "SG", "SGS": "GS", "SHN": "SH", "SJM": "SJ",
"SLB": "SB", "SLE": "SL", "SLV": "SV", "SMR": "SM", "SOM": "SO", "SPM": "PM", "SRB": "RS",
"STP": "ST", "SUR": "SR", "SVK": "SK", "SVN": "SI", "SWE": "SE", "SWZ": "SZ", "SYC": "SC",
"SYR": "SY",
# T
"TCA": "TC", "TCD": "TD", "TGO": "TG", "THA": "TH", "TJK": "TJ", "TKL": "TK", "TKM": "TM",
"TLS": "TL", "TON": "TO", "TTO": "TT", "TUN": "TN", "TUR": "TR", "TUV": "TV", "TWN": "TW",
"TZA": "TZ",
# U
"UGA": "UG", "UKR": "UA", "UMI": "UM", "URY": "UY", "USA": "US", "UZB": "UZ",
# V
"VAT": "VA", "VCT": "VC", "VEN": "VE", "VGB": "VG", "VIR": "VI", "VNM": "VN", "VUT": "VU",
# W
"WLF": "WF", "WSM": "WS",
# Y
"YEM": "YE",
# Z
"ZAF": "ZA", "ZMB": "ZM", "ZWE": "ZW",
}
_calling_codes = {
# A
"ABW": "+297", "AFG": "+93", "AGO": "+244", "AIA": "+1-264", "ALB": "+355", "AND": "+376",
"ANT": "+599", "ARE": "+971", "ARG": "+54", "ARM": "+374", "ASM": "+1-684", "ATA": "+672",
"ATG": "+1-268", "AUS": "+61", "AUT": "+43", "AZE": "+994",
# B
"BDI": "+257", "BEL": "+32", "BEN": "+229", "BFA": "+226", "BGD": "+880", "BGR": "+359",
"BHR": "+973", "BHS": "+1-242", "BIH": "+387", "BLR": "+375", "BLZ": "+501",
"BMU": "+1-441", "BOL": "+591", "BRA": "+55", "BRB": "+1-246", "BRN": "+673", "BTN": "+975",
"BWA": "+267",
# C
"CAF": "+236", "CAN": "+1", "CCK": "+61", "CHE": "+41", "CHL": "+56", "CHN": "+86",
"CMR": "+237", "COD": "+243", "COG": "+242", "COK": "+682", "COL": "+57", "COM": "+269",
"CPV": "+238", "CRI": "+506", "CUB": "+53", "CXR": "+61", "CYM": "+1-345", "CYP": "+357",
"CZE": "+420",
# D
"DEU": "+49", "DJI": "+253", "DMA": "+1-767", "DNK": "+45", "DOM": "+1-809", "DZA": "+213",
# E
"ECU": "+593", "EGY": "+20", "ERI": "+291", "ESH": "+212", "ESP": "+34", "EST": "+372",
"ETH": "+251",
# F
"FIN": "+358", "FJI": "+679", "FLK": "+500", "FRA": "+33", "FRO": "+298", "FSM": "+691",
# G
"GAB": "+241", "GBR": "+44", "GEO": "+995", "GGY": "+44-1481", "GHA": "+233", "GIB": "+350",
"GIN": "+224", "GLP": "+590", "GMB": "+220", "GNB": "+245", "GNQ": "+240", "GRC": "+30",
"GRD": "+1-473", "GRL": "+299", "GTM": "+502", "GUF": "+594", "GUM": "+1-671",
"GUY": "+592",
# H
"HKG": "+852", "HMD": "+672", "HND": "+504", "HRV": "+385", "HTI": "+509", "HUN": "+36",
# I
"IDN": "+62", "IMN": "+44-1624", "IND": "+91", "IOT": "+246", "IRL": "+353", "IRN": "+98",
"IRQ": "+964", "ISL": "+354", "ISR": "+972", "ITA": "+39",
# J
"JAM": "+1-876", "JEY": "+44-1534", "JOR": "+962", "JPN": "+81",
# K
"KAZ": "+7", "KEN": "+254", "KGZ": "+996", "KHM": "+855", "KIR": "+686", "KNA": "+1-869",
"KOR": "+82", "KWT": "+965",
# L
"LAO": "+856", "LBN": "+961", "LBR": "+231", "LBY": "+218", "LCA": "+1-758", "LIE": "+423",
"LKA": "+94", "LSO": "+266", "LTU": "+370", "LUX": "+352", "LVA": "+371",
# M
"MAC": "+853", "MAR": "+212", "MCO": "+377", "MDA": "+373", "MDG": "+261", "MDV": "+960",
"MEX": "+52", "MHL": "+692", "MKD": "+389", "MLI": "+223", "MLT": "+356", "MMR": "+95",
"MNE": "+382", "MNG": "+976", "MNP": "+1-670", "MOZ": "+258", "MRT": "+222",
"MSR": "+1-664", "MTQ": "+596", "MUS": "+230", "MWI": "+265", "MYS": "+60", "MYT": "+262",
# N
"NAM": "+264", "NCL": "+687", "NER": "+227", "NFK": "+672", "NGA": "+234", "NIC": "+505",
"NIU": "+683", "NLD": "+31", "NOR": "+47", "NPL": "+977", "NRU": "+674", "NZL": "+64",
# O
"OMN": "+968",
# P
"PAK": "+92", "PAN": "+507", "PCN": "+64", "PER": "+51", "PHL": "+63", "PLW": "+680",
"PNG": "+675", "POL": "+48", "PRI": "+1-787", "PRK": "+850", "PRT": "+351", "PRY": "+595",
"PSE": "+970", "PYF": "+689",
# Q
"QAT": "+974",
# R
"REU": "+262", "ROU": "+40", "RUS": "+7", "RWA": "+250",
# S
"SAU": "+966", "SDN": "+249", "SEN": "+221", "SGP": "+65", "SHN": "+290", "SJM": "+47",
"SLB": "+677", "SLE": "+232", "SLV": "+503", "SMR": "+378", "SOM": "+252", "SPM": "+508",
"SRB": "+381", "STP": "+239", "SUR": "+597", "SVK": "+421", "SVN": "+386", "SWE": "+46",
"SWZ": "+268", "SYC": "+248", "SYR": "+963",
# T
"TCA": "+1-649", "TCD": "+235", "TGO": "+228", "THA": "+66", "TJK": "+992", "TKL": "+690",
"TKM": "+993", "TLS": "+670", "TON": "+676", "TTO": "+1-868", "TUN": "+216", "TUR": "+90",
"TUV": "+688", "TWN": "+886", "TZA": "+255",
# U
"UGA": "+256", "UKR": "+380", "UMI": "+1", "URY": "+598", "USA": "+1", "UZB": "+998",
# V
"VAT": "+379", "VCT": "+1-784", "VEN": "+58", "VGB": "+1-284", "VIR": "+1-340",
"VNM": "+84", "VUT": "+678",
# W
"WLF": "+681", "WSM": "+685",
# Y
"YEM": "+967",
# Z
"ZAF": "+27", "ZMB": "+260", "ZWE": "+263"
}
_numeric = {
"004", "008", "010", "012", "016", "020", "024", "028", "031", "032",
"036", "040", "044", "048", "050", "051", "052", "056", "060", "064",
"068", "070", "072", "074", "076", "084", "086", "090", "092", "096",
"100", "104", "108", "112", "116", "120", "124", "132", "136", "140",
"144", "148", "152", "156", "158", "162", "166", "170", "174", "175",
"178", "180", "184", "188", "191", "192", "196", "203", "204", "208",
"212", "214", "218", "222", "226", "231", "232", "233", "234", "238",
"239", "242", "246", "248", "250", "254", "258", "260", "262", "266",
"268", "270", "275", "276", "288", "292", "296", "300", "304", "308",
"312", "316", "320", "324", "328", "332", "334", "340", "344", "348",
"352", "356", "360", "364", "368", "372", "376", "380", "384", "388",
"392", "398", "400", "404", "408", "410", "414", "417", "418", "422",
"426", "428", "430", "434", "438", "440", "442", "446", "450", "454",
"458", "462", "466", "470", "474", "478", "480", "484", "492", "496",
"498", "499", "500", "504", "508", "512", "516", "520", "524", "528",
"531", "533", "534", "535", "540", "548", "554", "558", "562", "566",
"570", "574", "578", "580", "581", "583", "584", "585", "586", "591",
"598", "600", "604", "608", "612", "616", "620", "624", "626", "630",
"634", "638", "642", "643", "646", "652", "654", "659", "660", "662",
"663", "666", "670", "674", "678", "682", "686", "688", "690", "694",
"702", "703", "704", "705", "706", "710", "716", "724", "728", "729",
"732", "740", "744", "748", "752", "756", "760", "762", "764", "768",
"772", "776", "780", "784", "788", "792", "795", "796", "798", "800",
"804", "807", "818", "826", "831", "832", "833", "834", "840", "850",
"854", "858", "860", "862", "876", "882", "887", "894",
}
_currency_iso4217 = {
# https://en.wikipedia.org/wiki/ISO_4217
"AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN",
"BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN",
"BWP", "BYN", "BZD",
"CAD", "CDF", "CHE", "CHF", "CHW", "CKD", "CLF", "CLP", "CNY", "COP", "CRC", "CUC", "CUP",
"CVE", "CZK",
"DJF", "DKK", "DOP", "DZD",
"EGP", "ERN", "ETB", "EUR",
"FJD", "FKP",
"GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD",
"HKD", "HNL", "HRK", "HTG", "HUF",
"IDR", "IEP", "ILS", "INR", "IQD", "IRR", "ISK",
"JMD", "JOD", "JPY",
"KES", "KGS", "KHR", "KID", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT",
"LAK", "LBP", "LKR", "LRD", "LSL", "LYD",
"MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRU", "MUR", "MVR",
"MWK", "MXN", "MYR", "MZN",
"NAD", "NGN", "NIO", "NOK", "NPR", "NZD",
"OMR",
"PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG",
"QAR",
"RON", "RSD", "RUB", "RWF",
"SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS",
"SRD", "SSP", "STN", "SVC", "SYP", "SZL",
"THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS",
"UAH", "UGX", "USD", "UYU", "UZS",
"VED", "VES", "VND", "VUV",
"WST",
"XAF", "XCD", "XDR", "XOF", "XPF",
"YER",
"ZAR", "ZMW", "ZWL"
}
_currency_symbols = {
# https://en.wikipedia.org/wiki/Currency_sign_(generic)
"؋", "฿", "", "", "¢", "$", "", "֏", "", "ƒ", "", "", "", "", "", "£", "", "", "",
"", "", "", "", "", "", "", "", "रू", "රු", "", "", "", "Rs", "", "" "", "",
"", "", "¥", "", "", "¤"
}
# fmt: on
def _get_code_type(format_type: str):
"""Returns the type of country code."""
if format_type.isdecimal():
return "numeric"
if format_type.isalpha():
if len(format_type) == 2:
return "alpha2"
if len(format_type) == 3:
return "alpha3"
return "invalid"
@validator
def calling_code(value: str, /):
"""Validates given calling code.
This performs country's calling code validation.
Examples:
>>> calling_code('+91')
True
>>> calling_code('-31')
ValidationError(func=calling_code, args={'value': '-31'})
Args:
value:
Country's calling code string to validate.
Returns:
(Literal[True]): If `value` is a valid calling code.
(ValidationError): If `value` is an invalid calling code.
"""
if not value:
return False
return value in set(_calling_codes.values())
@validator
def country_code(value: str, /, *, iso_format: str = "auto", ignore_case: bool = False):
"""Validates given country code.
This performs a case-sensitive [ISO 3166][1] country code validation.
[1]: https://www.iso.org/iso-3166-country-codes.html
Examples:
>>> country_code('GB', iso_format='alpha3')
ValidationError(func=country_code, args={'value': 'GB', 'iso_format': 'alpha3'})
>>> country_code('USA')
True
>>> country_code('840', iso_format='numeric')
True
>>> country_code('iN', iso_format='alpha2')
ValidationError(func=country_code, args={'value': 'iN', 'iso_format': 'alpha2'})
>>> country_code('ZWE', iso_format='alpha3')
True
Args:
value:
Country code string to validate.
iso_format:
ISO format to be used. Available options are:
`auto`, `alpha2`, `alpha3` and `numeric`.
ignore_case:
Enable/Disable case-sensitive matching.
Returns:
(Literal[True]): If `value` is a valid country code.
(ValidationError): If `value` is an invalid country code.
"""
if not value:
return False
if not (1 < len(value) < 4):
return False
if iso_format == "auto" and (iso_format := _get_code_type(value)) == "invalid":
return False
if iso_format == "alpha2":
return (
value.upper() in set(_alpha3_to_alpha2.values())
if ignore_case
else value in set(_alpha3_to_alpha2.values())
)
if iso_format == "alpha3":
return value.upper() in _alpha3_to_alpha2 if ignore_case else value in _alpha3_to_alpha2
return value in _numeric if iso_format == "numeric" else False
@validator
def currency(value: str, /, *, skip_symbols: bool = True, ignore_case: bool = False):
"""Validates given currency code.
This performs [ISO 4217][1] currency code/symbol validation.
[1]: https://www.iso.org/iso-4217-currency-codes.html
Examples:
>>> currency('USD')
True
>>> currency('ZWX')
ValidationError(func=currency, args={'value': 'ZWX'})
Args:
value:
Currency code/symbol string to validate.
skip_symbols:
Skip currency symbol validation.
ignore_case:
Enable/Disable case-sensitive matching.
Returns:
(Literal[True]): If `value` is a valid currency code.
(ValidationError): If `value` is an invalid currency code.
"""
if not value:
return False
if not skip_symbols and value in _currency_symbols:
return True
if len(value) != 3:
return False
return value.upper() in _currency_iso4217 if ignore_case else value in _currency_iso4217