amati 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
amati/data/tlds.json ADDED
@@ -0,0 +1 @@
1
+ [".aaa", ".aarp", ".abarth", ".abb", ".abbott", ".abbvie", ".abc", ".able", ".abogado", ".abudhabi", ".ac", ".academy", ".accenture", ".accountant", ".accountants", ".aco", ".active", ".actor", ".ad", ".adac", ".ads", ".adult", ".ae", ".aeg", ".aero", ".aetna", ".af", ".afamilycompany", ".afl", ".africa", ".ag", ".agakhan", ".agency", ".ai", ".aig", ".aigo", ".airbus", ".airforce", ".airtel", ".akdn", ".al", ".alfaromeo", ".alibaba", ".alipay", ".allfinanz", ".allstate", ".ally", ".alsace", ".alstom", ".am", ".amazon", ".americanexpress", ".americanfamily", ".amex", ".amfam", ".amica", ".amsterdam", ".an", ".analytics", ".android", ".anquan", ".anz", ".ao", ".aol", ".apartments", ".app", ".apple", ".aq", ".aquarelle", ".ar", ".arab", ".aramco", ".archi", ".army", ".arpa", ".art", ".arte", ".as", ".asda", ".asia", ".associates", ".at", ".athleta", ".attorney", ".au", ".auction", ".audi", ".audible", ".audio", ".auspost", ".author", ".auto", ".autos", ".avianca", ".aw", ".aws", ".ax", ".axa", ".az", ".azure", ".ba", ".baby", ".baidu", ".banamex", ".bananarepublic", ".band", ".bank", ".bar", ".barcelona", ".barclaycard", ".barclays", ".barefoot", ".bargains", ".baseball", ".basketball", ".bauhaus", ".bayern", ".bb", ".bbc", ".bbt", ".bbva", ".bcg", ".bcn", ".bd", ".be", ".beats", ".beauty", ".beer", ".bentley", ".berlin", ".best", ".bestbuy", ".bet", ".bf", ".bg", ".bh", ".bharti", ".bi", ".bible", ".bid", ".bike", ".bing", ".bingo", ".bio", ".biz", ".bj", ".bl", ".black", ".blackfriday", ".blanco", ".blockbuster", ".blog", ".bloomberg", ".blue", ".bm", ".bms", ".bmw", ".bn", ".bnl", ".bnpparibas", ".bo", ".boats", ".boehringer", ".bofa", ".bom", ".bond", ".boo", ".book", ".booking", ".boots", ".bosch", ".bostik", ".boston", ".bot", ".boutique", ".box", ".bq", ".br", ".bradesco", ".bridgestone", ".broadway", ".broker", ".brother", ".brussels", ".bs", ".bt", ".budapest", ".bugatti", ".build", ".builders", ".business", ".buy", ".buzz", ".bv", ".bw", ".by", ".bz", ".bzh", ".ca", ".cab", ".cafe", ".cal", ".call", ".calvinklein", ".cam", ".camera", ".camp", ".cancerresearch", ".canon", ".capetown", ".capital", ".capitalone", ".car", ".caravan", ".cards", ".care", ".career", ".careers", ".cars", ".cartier", ".casa", ".case", ".caseih", ".cash", ".casino", ".cat", ".catering", ".catholic", ".cba", ".cbn", ".cbre", ".cbs", ".cc", ".cd", ".ceb", ".center", ".ceo", ".cern", ".cf", ".cfa", ".cfd", ".cg", ".ch", ".chanel", ".channel", ".charity", ".chase", ".chat", ".cheap", ".chintai", ".chloe", ".christmas", ".chrome", ".chrysler", ".church", ".ci", ".cipriani", ".circle", ".cisco", ".citadel", ".citi", ".citic", ".city", ".cityeats", ".ck", ".cl", ".claims", ".cleaning", ".click", ".clinic", ".clinique", ".clothing", ".cloud", ".club", ".clubmed", ".cm", ".cn", ".co", ".coach", ".codes", ".coffee", ".college", ".cologne", ".com", ".comcast", ".commbank", ".community", ".company", ".compare", ".computer", ".comsec", ".condos", ".construction", ".consulting", ".contact", ".contractors", ".cooking", ".cookingchannel", ".cool", ".coop", ".corsica", ".country", ".coupon", ".coupons", ".courses", ".cpa", ".cr", ".credit", ".creditcard", ".creditunion", ".cricket", ".crown", ".crs", ".cruise", ".cruises", ".csc", ".cu", ".cuisinella", ".cv", ".cw", ".cx", ".cy", ".cymru", ".cyou", ".cz", ".dabur", ".dad", ".dance", ".data", ".date", ".dating", ".datsun", ".day", ".dclk", ".dds", ".de", ".deal", ".dealer", ".deals", ".degree", ".delivery", ".dell", ".deloitte", ".delta", ".democrat", ".dental", ".dentist", ".desi", ".design", ".dev", ".dhl", ".diamonds", ".diet", ".digital", ".direct", ".directory", ".discount", ".discover", ".dish", ".diy", ".dj", ".dk", ".dm", ".dnp", ".do", ".docs", ".doctor", ".dodge", ".dog", ".doha", ".domains", ".doosan", ".dot", ".download", ".drive", ".dtv", ".dubai", ".duck", ".dunlop", ".duns", ".dupont", ".durban", ".dvag", ".dvr", ".dz", ".earth", ".eat", ".ec", ".eco", ".edeka", ".edu", ".education", ".ee", ".eg", ".eh", ".email", ".emerck", ".energy", ".engineer", ".engineering", ".enterprises", ".epost", ".epson", ".equipment", ".er", ".ericsson", ".erni", ".es", ".esq", ".estate", ".esurance", ".et", ".etisalat", ".eu", ".eurovision", ".eus", ".events", ".everbank", ".exchange", ".expert", ".exposed", ".express", ".extraspace", ".fage", ".fail", ".fairwinds", ".faith", ".family", ".fan", ".fans", ".farm", ".farmers", ".fashion", ".fast", ".fedex", ".feedback", ".ferrari", ".ferrero", ".fi", ".fiat", ".fidelity", ".fido", ".film", ".final", ".finance", ".financial", ".fire", ".firestone", ".firmdale", ".fish", ".fishing", ".fit", ".fitness", ".fj", ".fk", ".flickr", ".flights", ".flir", ".florist", ".flowers", ".flsmidth", ".fly", ".fm", ".fo", ".foo", ".food", ".foodnetwork", ".football", ".ford", ".forex", ".forsale", ".forum", ".foundation", ".fox", ".fr", ".free", ".fresenius", ".frl", ".frogans", ".frontdoor", ".frontier", ".ftr", ".fujitsu", ".fujixerox", ".fun", ".fund", ".furniture", ".futbol", ".fyi", ".ga", ".gal", ".gallery", ".gallo", ".gallup", ".game", ".games", ".gap", ".garden", ".gay", ".gb", ".gbiz", ".gd", ".gdn", ".ge", ".gea", ".gent", ".genting", ".george", ".gf", ".gg", ".ggee", ".gh", ".gi", ".gift", ".gifts", ".gives", ".giving", ".gl", ".glade", ".glass", ".gle", ".global", ".globo", ".gm", ".gmail", ".gmbh", ".gmo", ".gmx", ".gn", ".godaddy", ".gold", ".goldpoint", ".golf", ".goo", ".goodhands", ".goodyear", ".goog", ".google", ".gop", ".got", ".gov", ".gp", ".gq", ".gr", ".grainger", ".graphics", ".gratis", ".green", ".gripe", ".grocery", ".group", ".gs", ".gt", ".gu", ".guardian", ".gucci", ".guge", ".guide", ".guitars", ".guru", ".gw", ".gy", ".hair", ".hamburg", ".hangout", ".haus", ".hbo", ".hdfc", ".hdfcbank", ".health", ".healthcare", ".help", ".helsinki", ".here", ".hermes", ".hgtv", ".hiphop", ".hisamitsu", ".hitachi", ".hiv", ".hk", ".hkt", ".hm", ".hn", ".hockey", ".holdings", ".holiday", ".homedepot", ".homegoods", ".homes", ".homesense", ".honda", ".honeywell", ".horse", ".hospital", ".host", ".hosting", ".hot", ".hoteles", ".hotels", ".hotmail", ".house", ".how", ".hr", ".hsbc", ".ht", ".htc", ".hu", ".hughes", ".hyatt", ".hyundai", ".ibm", ".icbc", ".ice", ".icu", ".id", ".ie", ".ieee", ".ifm", ".iinet", ".ikano", ".il", ".im", ".imamat", ".imdb", ".immo", ".immobilien", ".in", ".inc", ".industries", ".infiniti", ".info", ".ing", ".ink", ".institute", ".insurance", ".insure", ".int", ".intel", ".international", ".intuit", ".investments", ".io", ".ipiranga", ".iq", ".ir", ".irish", ".is", ".iselect", ".ismaili", ".ist", ".istanbul", ".it", ".itau", ".itv", ".iveco", ".iwc", ".jaguar", ".java", ".jcb", ".jcp", ".je", ".jeep", ".jetzt", ".jewelry", ".jio", ".jlc", ".jll", ".jm", ".jmp", ".jnj", ".jo", ".jobs", ".joburg", ".jot", ".joy", ".jp", ".jpmorgan", ".jprs", ".juegos", ".juniper", ".kaufen", ".kddi", ".ke", ".kerryhotels", ".kerrylogistics", ".kerryproperties", ".kfh", ".kg", ".kh", ".ki", ".kia", ".kids", ".kim", ".kinder", ".kindle", ".kitchen", ".kiwi", ".km", ".kn", ".koeln", ".komatsu", ".kosher", ".kp", ".kpmg", ".kpn", ".kr", ".krd", ".kred", ".kuokgroup", ".kw", ".ky", ".kyoto", ".kz", ".la", ".lacaixa", ".ladbrokes", ".lamborghini", ".lamer", ".lancaster", ".lancia", ".lancome", ".land", ".landrover", ".lanxess", ".lasalle", ".lat", ".latino", ".latrobe", ".law", ".lawyer", ".lb", ".lc", ".lds", ".lease", ".leclerc", ".lefrak", ".legal", ".lego", ".lexus", ".lgbt", ".li", ".liaison", ".lidl", ".life", ".lifeinsurance", ".lifestyle", ".lighting", ".like", ".lilly", ".limited", ".limo", ".lincoln", ".linde", ".link", ".lipsy", ".live", ".living", ".lixil", ".lk", ".llc", ".llp", ".loan", ".loans", ".locker", ".locus", ".loft", ".lol", ".london", ".lotte", ".lotto", ".love", ".lpl", ".lplfinancial", ".lr", ".ls", ".lt", ".ltd", ".ltda", ".lu", ".lundbeck", ".lupin", ".luxe", ".luxury", ".lv", ".ly", ".ma", ".macys", ".madrid", ".maif", ".maison", ".makeup", ".man", ".management", ".mango", ".map", ".market", ".marketing", ".markets", ".marriott", ".marshalls", ".maserati", ".mattel", ".mba", ".mc", ".mcd", ".mcdonalds", ".mckinsey", ".md", ".me", ".med", ".media", ".meet", ".melbourne", ".meme", ".memorial", ".men", ".menu", ".meo", ".merckmsd", ".metlife", ".mf", ".mg", ".mh", ".miami", ".microsoft", ".mil", ".mini", ".mint", ".mit", ".mitsubishi", ".mk", ".ml", ".mlb", ".mls", ".mm", ".mma", ".mn", ".mo", ".mobi", ".mobile", ".mobily", ".moda", ".moe", ".moi", ".mom", ".monash", ".money", ".monster", ".montblanc", ".mopar", ".mormon", ".mortgage", ".moscow", ".moto", ".motorcycles", ".mov", ".movie", ".movistar", ".mp", ".mq", ".mr", ".ms", ".msd", ".mt", ".mtn", ".mtpc", ".mtr", ".mu", ".museum", ".music", ".mutual", ".mutuelle", ".mv", ".mw", ".mx", ".my", ".mz", ".na", ".nab", ".nadex", ".nagoya", ".name", ".nationwide", ".natura", ".navy", ".nba", ".nc", ".ne", ".nec", ".net", ".netbank", ".netflix", ".network", ".neustar", ".new", ".newholland", ".news", ".next", ".nextdirect", ".nexus", ".nf", ".nfl", ".ng", ".ngo", ".nhk", ".ni", ".nico", ".nike", ".nikon", ".ninja", ".nissan", ".nissay", ".nl", ".no", ".nokia", ".northwesternmutual", ".norton", ".now", ".nowruz", ".nowtv", ".np", ".nr", ".nra", ".nrw", ".ntt", ".nu", ".nyc", ".nz", ".obi", ".observer", ".off", ".office", ".okinawa", ".olayan", ".olayangroup", ".oldnavy", ".ollo", ".om", ".omega", ".one", ".ong", ".onl", ".online", ".onyourside", ".ooo", ".open", ".oracle", ".orange", ".org", ".organic", ".orientexpress", ".origins", ".osaka", ".otsuka", ".ott", ".ovh", ".pa", ".page", ".pamperedchef", ".panasonic", ".panerai", ".paris", ".pars", ".partners", ".parts", ".party", ".passagens", ".pay", ".pccw", ".pe", ".pet", ".pf", ".pfizer", ".pg", ".ph", ".pharmacy", ".phd", ".philips", ".phone", ".photo", ".photography", ".photos", ".physio", ".piaget", ".pics", ".pictet", ".pictures", ".pid", ".pin", ".ping", ".pink", ".pioneer", ".pizza", ".pk", ".pl", ".place", ".play", ".playstation", ".plumbing", ".plus", ".pm", ".pn", ".pnc", ".pohl", ".poker", ".politie", ".porn", ".post", ".pr", ".pramerica", ".praxi", ".press", ".prime", ".pro", ".prod", ".productions", ".prof", ".progressive", ".promo", ".properties", ".property", ".protection", ".pru", ".prudential", ".ps", ".pt", ".pub", ".pw", ".pwc", ".py", ".qa", ".qpon", ".quebec", ".quest", ".qvc", ".racing", ".radio", ".raid", ".re", ".read", ".realestate", ".realtor", ".realty", ".recipes", ".red", ".redstone", ".redumbrella", ".rehab", ".reise", ".reisen", ".reit", ".reliance", ".ren", ".rent", ".rentals", ".repair", ".report", ".republican", ".rest", ".restaurant", ".review", ".reviews", ".rexroth", ".rich", ".richardli", ".ricoh", ".rightathome", ".ril", ".rio", ".rip", ".rmit", ".ro", ".rocher", ".rocks", ".rodeo", ".rogers", ".room", ".rs", ".rsvp", ".ru", ".rugby", ".ruhr", ".run", ".rw", ".rwe", ".ryukyu", ".sa", ".saarland", ".safe", ".safety", ".sakura", ".sale", ".salon", ".samsclub", ".samsung", ".sandvik", ".sandvikcoromant", ".sanofi", ".sap", ".sapo", ".sarl", ".sas", ".save", ".saxo", ".sb", ".sbi", ".sbs", ".sc", ".sca", ".scb", ".schaeffler", ".schmidt", ".scholarships", ".school", ".schule", ".schwarz", ".science", ".scjohnson", ".scor", ".scot", ".sd", ".se", ".search", ".seat", ".secure", ".security", ".seek", ".select", ".sener", ".services", ".ses", ".seven", ".sew", ".sex", ".sexy", ".sfr", ".sg", ".sh", ".shangrila", ".sharp", ".shaw", ".shell", ".shia", ".shiksha", ".shoes", ".shop", ".shopping", ".shouji", ".show", ".showtime", ".shriram", ".si", ".silk", ".sina", ".singles", ".site", ".sj", ".sk", ".ski", ".skin", ".sky", ".skype", ".sl", ".sling", ".sm", ".smart", ".smile", ".sn", ".sncf", ".so", ".soccer", ".social", ".softbank", ".software", ".sohu", ".solar", ".solutions", ".song", ".sony", ".soy", ".spa", ".space", ".spiegel", ".sport", ".spot", ".spreadbetting", ".sr", ".srl", ".srt", ".ss", ".st", ".stada", ".staples", ".star", ".starhub", ".statebank", ".statefarm", ".statoil", ".stc", ".stcgroup", ".stockholm", ".storage", ".store", ".stream", ".studio", ".study", ".style", ".su", ".sucks", ".supplies", ".supply", ".support", ".surf", ".surgery", ".suzuki", ".sv", ".swatch", ".swiftcover", ".swiss", ".sx", ".sy", ".sydney", ".symantec", ".systems", ".sz", ".tab", ".taipei", ".talk", ".taobao", ".target", ".tatamotors", ".tatar", ".tattoo", ".tax", ".taxi", ".tc", ".tci", ".td", ".tdk", ".team", ".tech", ".technology", ".tel", ".telecity", ".telefonica", ".temasek", ".tennis", ".teva", ".tf", ".tg", ".th", ".thd", ".theater", ".theatre", ".tiaa", ".tickets", ".tienda", ".tiffany", ".tips", ".tires", ".tirol", ".tj", ".tjmaxx", ".tjx", ".tk", ".tkmaxx", ".tl", ".tm", ".tmall", ".tn", ".to", ".today", ".tokyo", ".tools", ".top", ".toray", ".toshiba", ".total", ".tours", ".town", ".toyota", ".toys", ".tp", ".tr", ".trade", ".trading", ".training", ".travel", ".travelchannel", ".travelers", ".travelersinsurance", ".trust", ".trv", ".tt", ".tube", ".tui", ".tunes", ".tushu", ".tv", ".tvs", ".tw", ".tz", ".ua", ".ubank", ".ubs", ".uconnect", ".ug", ".uk", ".um", ".unicom", ".university", ".uno", ".uol", ".ups", ".us", ".uy", ".uz", ".va", ".vacations", ".vana", ".vanguard", ".vc", ".ve", ".vegas", ".ventures", ".verisign", ".versicherung", ".vet", ".vg", ".vi", ".viajes", ".video", ".vig", ".viking", ".villas", ".vin", ".vip", ".virgin", ".visa", ".vision", ".vista", ".vistaprint", ".viva", ".vivo", ".vlaanderen", ".vn", ".vodka", ".volkswagen", ".volvo", ".vote", ".voting", ".voto", ".voyage", ".vu", ".vuelos", ".wales", ".walmart", ".walter", ".wang", ".wanggou", ".warman", ".watch", ".watches", ".weather", ".weatherchannel", ".webcam", ".weber", ".website", ".wed", ".wedding", ".weibo", ".weir", ".wf", ".whoswho", ".wien", ".wiki", ".williamhill", ".win", ".windows", ".wine", ".winners", ".wme", ".wolterskluwer", ".woodside", ".work", ".works", ".world", ".wow", ".ws", ".wtc", ".wtf", ".xbox", ".xerox", ".xfinity", ".xihuan", ".xin", ".\u6d4b\u8bd5", ".\u0915\u0949\u092e", ".\u092a\u0930\u0940\u0915\u094d\u0937\u093e", ".\u30bb\u30fc\u30eb", ".\u4f5b\u5c71", ".\u0cad\u0cbe\u0cb0\u0ca4", ".\u6148\u5584", ".\u96c6\u56e2", ".\u5728\u7ebf", ".\ud55c\uad6d", ".\u0b2d\u0b3e\u0b30\u0b24", ".\u5927\u4f17\u6c7d\u8f66", ".\u70b9\u770b", ".\u0e04\u0e2d\u0e21", ".\u09ad\u09be\u09f0\u09a4", ".\u09ad\u09be\u09b0\u09a4", ".\u516b\u5366", "\u200f.\u05d9\u05e9\u05e8\u05d0\u05dc\u200e", "\u200f.\u0645\u0648\u0642\u0639\u200e", ".\u09ac\u09be\u0982\u09b2\u09be", ".\u516c\u76ca", ".\u516c\u53f8", ".\u9999\u683c\u91cc\u62c9", ".\u7f51\u7ad9", ".\u79fb\u52a8", ".\u6211\u7231\u4f60", ".\u043c\u043e\u0441\u043a\u0432\u0430", ".\u0438\u0441\u043f\u044b\u0442\u0430\u043d\u0438\u0435", ".\u049b\u0430\u0437", ".\u043a\u0430\u0442\u043e\u043b\u0438\u043a", ".\u043e\u043d\u043b\u0430\u0439\u043d", ".\u0441\u0430\u0439\u0442", ".\u8054\u901a", ".\u0441\u0440\u0431", ".\u0431\u0433", ".\u0431\u0435\u043b", "\u200f.\u05e7\u05d5\u05dd\u200e", ".\u65f6\u5c1a", ".\u5fae\u535a", ".\ud14c\uc2a4\ud2b8", ".\u6de1\u9a6c\u9521", ".\u30d5\u30a1\u30c3\u30b7\u30e7\u30f3", ".\u043e\u0440\u0433", ".\u0928\u0947\u091f", ".\u30b9\u30c8\u30a2", ".\u30a2\u30de\u30be\u30f3", ".\uc0bc\uc131", ".\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd", ".\u5546\u6807", ".\u5546\u5e97", ".\u5546\u57ce", ".\u0434\u0435\u0442\u0438", ".\u043c\u043a\u0434", "\u200f.\u05d8\u05e2\u05e1\u05d8\u200e", ".\u0435\u044e", ".\u30dd\u30a4\u30f3\u30c8", ".\u65b0\u95fb", ".\u5de5\u884c", ".\u5bb6\u96fb", "\u200f.\u0643\u0648\u0645\u200e", ".\u4e2d\u6587\u7f51", ".\u4e2d\u4fe1", ".\u4e2d\u56fd", ".\u4e2d\u570b", ".\u5a31\u4e50", ".\u8c37\u6b4c", ".\u0c2d\u0c3e\u0c30\u0c24\u0c4d", ".\u0dbd\u0d82\u0d9a\u0dcf", ".\u96fb\u8a0a\u76c8\u79d1", ".\u8d2d\u7269", ".\u6e2c\u8a66", ".\u30af\u30e9\u30a6\u30c9", ".\u0aad\u0abe\u0ab0\u0aa4", ".\u901a\u8ca9", ".\u092d\u093e\u0930\u0924\u092e\u094d", ".\u092d\u093e\u0930\u0924", ".\u092d\u093e\u0930\u094b\u0924", "\u200f.\u0622\u0632\u0645\u0627\u06cc\u0634\u06cc\u200e", ".\u0baa\u0bb0\u0bbf\u0b9f\u0bcd\u0b9a\u0bc8", ".\u7f51\u5e97", ".\u0938\u0902\u0917\u0920\u0928", ".\u9910\u5385", ".\u7f51\u7edc", ".\u043a\u043e\u043c", ".\u0443\u043a\u0440", ".\u9999\u6e2f", ".\u4e9a\u9a6c\u900a", ".\u8bfa\u57fa\u4e9a", ".\u98df\u54c1", ".\u03b4\u03bf\u03ba\u03b9\u03bc\u03ae", ".\u98de\u5229\u6d66", "\u200f.\u0625\u062e\u062a\u0628\u0627\u0631\u200e", ".\u53f0\u6e7e", ".\u53f0\u7063", ".\u624b\u8868", ".\u624b\u673a", ".\u043c\u043e\u043d", "\u200f.\u0627\u0644\u062c\u0632\u0627\u0626\u0631\u200e", "\u200f.\u0639\u0645\u0627\u0646\u200e", "\u200f.\u0627\u0631\u0627\u0645\u0643\u0648\u200e", "\u200f.\u0627\u06cc\u0631\u0627\u0646\u200e", "\u200f.\u0627\u0644\u0639\u0644\u064a\u0627\u0646\u200e", "\u200f.\u0627\u062a\u0635\u0627\u0644\u0627\u062a\u200e", "\u200f.\u0627\u0645\u0627\u0631\u0627\u062a\u200e", "\u200f.\u0628\u0627\u0632\u0627\u0631\u200e", "\u200f.\u0645\u0648\u0631\u064a\u062a\u0627\u0646\u064a\u0627\u200e", "\u200f.\u067e\u0627\u06a9\u0633\u062a\u0627\u0646\u200e", "\u200f.\u0627\u0644\u0627\u0631\u062f\u0646\u200e", "\u200f.\u0645\u0648\u0628\u0627\u064a\u0644\u064a\u200e", "\u200f.\u0628\u0627\u0631\u062a\u200e", "\u200f.\u0628\u06be\u0627\u0631\u062a\u200e", "\u200f.\u0627\u0644\u0645\u063a\u0631\u0628\u200e", "\u200f.\u0627\u0628\u0648\u0638\u0628\u064a\u200e", "\u200f.\u0627\u0644\u0628\u062d\u0631\u064a\u0646\u200e", "\u200f.\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629\u200e", "\u200f.\u0680\u0627\u0631\u062a\u200e", "\u200f.\u0643\u0627\u062b\u0648\u0644\u064a\u0643\u200e", "\u200f.\u0633\u0648\u062f\u0627\u0646\u200e", "\u200f.\u0647\u0645\u0631\u0627\u0647\u200e", "\u200f.\u0639\u0631\u0627\u0642\u200e", "\u200f.\u0645\u0644\u064a\u0633\u064a\u0627\u200e", ".\u6fb3\u9580", ".\ub2f7\ucef4", ".\u653f\u5e9c", "\u200f.\u0634\u0628\u0643\u0629\u200e", "\u200f.\u0628\u064a\u062a\u0643\u200e", "\u200f.\u0639\u0631\u0628\u200e", ".\u10d2\u10d4", ".\u673a\u6784", ".\u7ec4\u7ec7\u673a\u6784", ".\u5065\u5eb7", ".\u0e44\u0e17\u0e22", "\u200f.\u0633\u0648\u0631\u064a\u0629\u200e", ".\u62db\u8058", ".\u0440\u0443\u0441", ".\u0440\u0444", ".\u73e0\u5b9d", "\u200f.\u062a\u0648\u0646\u0633\u200e", ".\u5927\u62ff", ".\u0ea5\u0eb2\u0ea7", ".\u307f\u3093\u306a", ".\u30b0\u30fc\u30b0\u30eb", ".\u03b5\u03c5", ".\u03b5\u03bb", ".\u4e16\u754c", ".\u66f8\u7c4d", ".\u0d2d\u0d3e\u0d30\u0d24\u0d02", ".\u0a2d\u0a3e\u0a30\u0a24", ".\u7f51\u5740", ".\ub2f7\ub137", ".\u30b3\u30e0", ".\u5929\u4e3b\u6559", ".\u6e38\u620f", ".verm\u00f6gensberater", ".verm\u00f6gensberatung", ".\u4f01\u4e1a", ".\u4fe1\u606f", ".\u5609\u91cc\u5927\u9152\u5e97", ".\u5609\u91cc", "\u200f.\u0645\u0635\u0631\u200e", "\u200f.\u0642\u0637\u0631\u200e", ".\u5e7f\u4e1c", ".\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8", ".\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe", ".\u0570\u0561\u0575", ".\u65b0\u52a0\u5761", "\u200f.\u0641\u0644\u0633\u0637\u064a\u0646\u200e", ".\u30c6\u30b9\u30c8", ".\u653f\u52a1", ".xperia", ".xxx", ".xyz", ".yachts", ".yahoo", ".yamaxun", ".yandex", ".ye", ".yodobashi", ".yoga", ".yokohama", ".you", ".youtube", ".yt", ".yun", ".za", ".zappos", ".zara", ".zero", ".zip", ".zippo", ".zm", ".zone", ".zuerich", ".zw"]
amati/exceptions.py ADDED
@@ -0,0 +1,26 @@
1
+ """
2
+ Exceptions, declared here to not put in __init__
3
+ """
4
+
5
+ from typing import Optional
6
+
7
+ from amati.references import References
8
+
9
+
10
+ class AmatiValueError(ValueError):
11
+ """
12
+ Custom exception to allow adding of references to exceptions.
13
+
14
+
15
+ Attributes:
16
+ message (str): The explanation of why the exception was raised
17
+ authority (Optional[ReferenceModel]): The reference to the standard that
18
+ explains why the exception was raised
19
+
20
+ Inherits:
21
+ ValueError
22
+ """
23
+
24
+ def __init__(self, message: str, reference: Optional[References] = None):
25
+ self.message = message
26
+ self.reference = reference
@@ -0,0 +1,15 @@
1
+ """
2
+ Convenience, can import all types from one place
3
+ """
4
+
5
+ # Imports are here for convenience, they're not going to be used here
6
+ # pylint: disable=unused-import
7
+ # pyright: reportUnusedImport=false
8
+
9
+ from amati.fields._custom_types import Str
10
+ from amati.fields.email import Email
11
+ from amati.fields.http_status_codes import HTTPStatusCode
12
+ from amati.fields.iso9110 import HTTPAuthenticationScheme
13
+ from amati.fields.media import MediaType
14
+ from amati.fields.spdx_licences import SPDXURL, SPDXIdentifier
15
+ from amati.fields.uri import URI, Scheme, URIType, URIWithVariables
@@ -0,0 +1,71 @@
1
+ """Types for use across all fields"""
2
+
3
+ from typing import Any, Self
4
+
5
+ from pydantic import GetCoreSchemaHandler
6
+ from pydantic_core import core_schema
7
+
8
+
9
+ class Str(str):
10
+ """
11
+ A custom string subclass that can be used with Pydantic.
12
+
13
+ Str extends the built-in string type and implements the necessary methods for
14
+ Pydantic validation and schema generation. It allows for custom string validation
15
+ while maintaining compatibility with Pydantic's type system.
16
+
17
+ The primary goal behind Str is to allow logic in models to access metadata about
18
+ the string, created during class instantiation, but to still treat the string as a
19
+ string for the purposes of JSON/YAML parsing and serialisation.
20
+
21
+ Inherits:
22
+ str: Python's built-in string class
23
+ """
24
+
25
+ @classmethod
26
+ def __get_pydantic_core_schema__(
27
+ cls: type[Self], _source_type: Any, _handler: GetCoreSchemaHandler
28
+ ) -> core_schema.CoreSchema:
29
+ """
30
+ Define how Pydantic should handle this custom type.
31
+
32
+ This method is called by Pydantic during model creation to determine
33
+ how to validate and process fields of this type. It creates a chain
34
+ schema that first validates the input as a string, then applies
35
+ custom validation logic.
36
+
37
+ Args:
38
+ _source_type (Any): The source type annotation.
39
+ _handler (GetCoreSchemaHandler): Pydantic's schema handler.
40
+
41
+ Returns:
42
+ core_schema.CoreSchema: A schema defining how Pydantic should
43
+ process this type.
44
+ """
45
+ return core_schema.chain_schema(
46
+ [
47
+ # First validate as a string
48
+ core_schema.str_schema(),
49
+ # Then convert to our Test type and run validation
50
+ core_schema.no_info_plain_validator_function(cls.validate),
51
+ ]
52
+ )
53
+
54
+ @classmethod
55
+ def validate(cls: type[Self], value: str) -> Self:
56
+ """
57
+ Perform custom validation on the string value.
58
+
59
+ This method is called after the basic string validation has passed. It allows
60
+ implementing custom validation rules or transformations before returning an
61
+ instance of the _Str class or a subclass. It is expected that subclasses will
62
+ override validate() if necessary.
63
+
64
+ Args:
65
+ value (str): The string value to validate.
66
+
67
+ Returns:
68
+ Str: An instance of the _Str class containing the validated value.
69
+ """
70
+
71
+ return cls(value)
@@ -0,0 +1,9 @@
1
+ """
2
+ Convenience type so I can implement CommonMark validation later if it ever
3
+ feels necessary.
4
+
5
+ https://github.com/executablebooks/markdown-it-py looks to be the main
6
+ Python CommonMark parser
7
+ """
8
+
9
+ type CommonMark = str
amati/fields/email.py ADDED
@@ -0,0 +1,27 @@
1
+ """
2
+ Validates an email according to the RFC5322 ABNF grammar - §3:
3
+ """
4
+
5
+ from abnf import ParseError
6
+ from abnf.grammars import rfc5322
7
+
8
+ from amati import AmatiValueError, Reference
9
+ from amati.fields import Str as _Str
10
+
11
+ reference = Reference(
12
+ title="Internet Message Format",
13
+ url="https://www.rfc-editor.org/rfc/rfc5322#section-3",
14
+ section="Syntax",
15
+ )
16
+
17
+
18
+ class Email(_Str):
19
+
20
+ def __init__(self, value: str):
21
+
22
+ try:
23
+ rfc5322.Rule("address").parse_all(value)
24
+ except ParseError as e:
25
+ raise AmatiValueError(
26
+ message=f"{value} is not a valid email address", reference=reference
27
+ ) from e
@@ -0,0 +1,95 @@
1
+ """
2
+ Validates IANA HTTP status codes,
3
+
4
+ Note that the codes ^[1-5]XX$ are not valid HTTP status codes,
5
+ but are in common usage. They can be accessed separately via HTTPStatusCodeX,
6
+ or the numeric codes can be accessed via HTTPStatusCodeN.
7
+ """
8
+
9
+ import json
10
+ import pathlib
11
+ import re
12
+ from typing import Optional, Self
13
+
14
+ from amati import AmatiValueError, Reference
15
+ from amati.fields import Str as _Str
16
+
17
+ reference = Reference(
18
+ title="Hypertext Transfer Protocol (HTTP) Status Code Registry",
19
+ url="https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml",
20
+ )
21
+
22
+ DATA_DIRECTORY = pathlib.Path(__file__).parent.parent.resolve() / "data"
23
+
24
+ with open(DATA_DIRECTORY / "http-status-codes.json", "r", encoding="utf-8") as f:
25
+ HTTP_STATUS_CODES = json.loads(f.read())
26
+
27
+
28
+ class HTTPStatusCode(_Str):
29
+ """
30
+ A class representing an HTTP status code as defined in RFC 7231 and related RFCs.
31
+
32
+ This class validates and provides information about HTTP status codes, including
33
+ whether they are registered with IANA, assigned for use, or represent a status code
34
+ range (e.g., 4XX). It inherits from _Str to maintain compatibility with string
35
+ operations while adding HTTP-specific validation and metadata.
36
+
37
+ Attributes:
38
+ description (Optional[str]): The official description of the status code,
39
+ if registered.
40
+ is_registered (bool): Whether the status code is registered with IANA.
41
+ is_assigned (bool): Whether the status code is assigned for use
42
+ (not marked as 'Unassigned').
43
+ is_range (bool): Whether the status code represents a range (e.g., "2XX").
44
+ """
45
+
46
+ description: Optional[str] = None
47
+ is_registered: bool = False
48
+ is_assigned: bool = False
49
+ is_range: bool = False
50
+ _pattern = re.compile(r"^[1-5]XX$")
51
+
52
+ def __init__(self: Self, value: str):
53
+ """
54
+ Initialize an HTTPStatusCode object from a string or integer value.
55
+
56
+ Validates the input against known HTTP status codes and status code ranges.
57
+ Sets attributes indicating whether the code is registered, assigned, and/or
58
+ represents a range.
59
+
60
+ NB: OAS 3.1.1 states that:
61
+ > This field MUST be enclosed in quotation marks (for example, “200”)
62
+ > for compatibility between JSON and YAML.
63
+
64
+ Args:
65
+ value (str | int): A string or integer representing an HTTP status code
66
+ (e.g., "200", 404) or status code range (e.g., "4XX").
67
+
68
+ Raises:
69
+ AmatiValueError: If the provided value is not a valid HTTP status code or
70
+ status code range.
71
+ """
72
+
73
+ # Type-hinting that something should be a string is not enough
74
+ # double check that a string will be returned in the models.
75
+ if not isinstance(value, str): # type: ignore
76
+
77
+ type_ = type(value).__name__
78
+ raise AmatiValueError(
79
+ f"{value} of type {type_} cannot be a valid HTTP Status code."
80
+ )
81
+
82
+ candidate = str(value)
83
+
84
+ if candidate in HTTP_STATUS_CODES:
85
+ self.is_registered = True
86
+ self.description = HTTP_STATUS_CODES[candidate]
87
+ elif self._pattern.match(candidate):
88
+ self.is_range = True
89
+ else:
90
+ raise AmatiValueError(
91
+ f"{value} is not a valid HTTP Status Code", reference=reference
92
+ )
93
+
94
+ if self.description != "Unassigned":
95
+ self.is_assigned = True
@@ -0,0 +1,61 @@
1
+ """
2
+ HTTP Authentication Scheme validation module.
3
+
4
+ This module provides functionality for validating HTTP authentication schemes according
5
+ to the IANA registry defined in ISO9110. It includes constants, data loading utilities,
6
+ and a class for scheme validation.
7
+ """
8
+
9
+ import json
10
+ import pathlib
11
+
12
+ from amati import AmatiValueError, Reference
13
+ from amati.fields import Str as _Str
14
+
15
+ reference = Reference(
16
+ title="Hypertext Transfer Protocol (HTTP) Authentication Scheme Registry (ISO9110)",
17
+ url="https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml",
18
+ )
19
+
20
+
21
+ DATA_DIRECTORY = pathlib.Path(__file__).parent.parent.resolve() / "data"
22
+
23
+ with open(DATA_DIRECTORY / "iso9110.json", "r", encoding="utf-8") as f:
24
+ data = json.loads(f.read())
25
+
26
+
27
+ HTTP_AUTHENTICATION_SCHEMES: set[str] = set(
28
+ [x["Authentication Scheme Name"].lower() for x in data]
29
+ )
30
+
31
+
32
+ class HTTPAuthenticationScheme(_Str):
33
+ """
34
+ A class representing an HTTP authentication scheme as defined in ISO9110.
35
+
36
+ This class validates that a string value is a registered HTTP authentication scheme
37
+ according to the IANA registry. It inherits from _Str to maintain compatibility
38
+ with string operations while adding HTTP authentication-specific validation.
39
+
40
+ The validation is performed against the list of schemes loaded from the ISO9110
41
+ data file, which includes schemes like Basic, Bearer, Digest, etc.
42
+
43
+ Attributes:
44
+ Inherits all attributes from _Str
45
+
46
+ Example:
47
+ >>> scheme = HTTPAuthenticationScheme("Bearer")
48
+ >>> str(scheme)
49
+ 'Bearer'
50
+ >>> HTTPAuthenticationScheme("InvalidScheme")
51
+ Traceback (most recent call last):
52
+ amati.AmatiValueError: message
53
+ """
54
+
55
+ def __init__(self, value: str):
56
+
57
+ if value.lower() not in HTTP_AUTHENTICATION_SCHEMES:
58
+ raise AmatiValueError(
59
+ f"{value} is not a valid HTTP authentication schema.",
60
+ reference=reference,
61
+ )
amati/fields/json.py ADDED
@@ -0,0 +1,13 @@
1
+ """
2
+ Defines a JSON datatype
3
+ """
4
+
5
+ from types import NoneType
6
+
7
+ type JSONPrimitive = str | int | float | bool | NoneType
8
+ type JSONArray = list["JSONValue"]
9
+ type JSONObject = dict[str, "JSONValue"]
10
+ type JSONValue = JSONPrimitive | JSONArray | JSONObject
11
+
12
+ # Type alias for cleaner usage
13
+ type JSON = JSONValue
amati/fields/media.py ADDED
@@ -0,0 +1,100 @@
1
+ """
2
+ Validates a media type or media type range according to RFC7321
3
+ """
4
+
5
+ import json
6
+ import pathlib
7
+ from typing import Optional
8
+
9
+ from abnf import ParseError
10
+ from abnf.grammars import rfc7231
11
+
12
+ from amati import AmatiValueError, Reference
13
+ from amati.fields import Str as _Str
14
+
15
+ reference = Reference(
16
+ title="Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content",
17
+ url="https://datatracker.ietf.org/doc/html/rfc7231#appendix-D",
18
+ section="Appendix D",
19
+ )
20
+
21
+ DATA_DIRECTORY = pathlib.Path(__file__).parent.parent.resolve() / "data"
22
+
23
+ with open(DATA_DIRECTORY / "media-types.json", "r", encoding="utf-8") as f:
24
+ MEDIA_TYPES = json.loads(f.read())
25
+
26
+
27
+ class MediaType(_Str):
28
+ """
29
+ A class representing an HTTP media type as defined in RFC 7231.
30
+
31
+ This class parses and validates media type strings (e.g., "text/html", "image/png")
32
+ according to the RFC 7231 specification. It provides attributes for accessing the
33
+ components of a media type and methods for string representation.
34
+
35
+ Attributes:
36
+ type (str): The primary type component (e.g., "text", "image", "application").
37
+ subtype (str): The subtype component (e.g., "html", "png", "json").
38
+ parameter (Optional[str]): Optional parameters (e.g., "charset=utf-8").
39
+ is_registered (bool): Whether this is a registered IANA media type.
40
+ is_range (bool): Whether this is a media type range (contains wildcards).
41
+ """
42
+
43
+ type: str = ""
44
+ subtype: str = ""
45
+ parameter: Optional[str] = None
46
+ is_registered: bool = False
47
+ is_range: bool = False
48
+
49
+ def __init__(self, value: str):
50
+ """
51
+ Parses the input string according to RFC 7231 grammar rules for media types.
52
+ Sets the appropriate attributes based on the parsed components and determines
53
+ if the media type is registered and/or represents a range.
54
+
55
+ Args:
56
+ value (str): A string representing a media type (e.g., "text/html").
57
+
58
+ Raises:
59
+ AmatiValueError: If the input string is not a valid media type according to
60
+ RFC 7231.
61
+ """
62
+
63
+ try:
64
+ media_type = rfc7231.Rule("media-type").parse_all(value)
65
+
66
+ for node in media_type.children:
67
+ if node.name in self.__annotations__:
68
+ self.__dict__[node.name] = node.value
69
+
70
+ except ParseError as e:
71
+ raise AmatiValueError(
72
+ "Invalid media type or media type range", reference=reference
73
+ ) from e
74
+
75
+ if self.type in MEDIA_TYPES:
76
+
77
+ if self.subtype == "*":
78
+ self.is_range = True
79
+ self.is_registered = True
80
+
81
+ if self.subtype in MEDIA_TYPES[self.type]:
82
+ self.is_registered = True
83
+
84
+ if value == "*/*":
85
+ self.is_range = True
86
+ self.is_registered = True
87
+
88
+ def __str__(self) -> str:
89
+ """
90
+ Return the string representation of the media type.
91
+
92
+ Returns:
93
+ str: A properly formatted media type string
94
+ (e.g., "text/html; charset=utf-8").
95
+ """
96
+ parameter_string = ""
97
+ if self.parameter:
98
+ parameter_string = f"; {self.parameter}"
99
+
100
+ return f"{self.type}/{self.subtype}{parameter_string}"
amati/fields/oas.py ADDED
@@ -0,0 +1,79 @@
1
+ """
2
+ Fields from the OpenAPI Specification (OAS)
3
+ """
4
+
5
+ from typing import ClassVar
6
+
7
+ from abnf import ParseError
8
+
9
+ from amati import AmatiValueError, Reference
10
+ from amati.fields import Str as _Str
11
+ from amati.grammars import oas
12
+
13
+ OPENAPI_VERSIONS: list[str] = [
14
+ "3.0",
15
+ "3.0.0",
16
+ "3.0.1",
17
+ "3.0.2",
18
+ "3.0.3",
19
+ "3.0.4",
20
+ "3.1",
21
+ "3.1.0",
22
+ "3.1.1",
23
+ ]
24
+
25
+
26
+ class RuntimeExpression(_Str):
27
+ """
28
+ A class representing a runtime expression as defined in the OpenAPI Specification.
29
+ This class validates the runtime expression format according to the OpenAPI grammar.
30
+
31
+ It is validated against the ABNF grammar in the OpenAPI spec.
32
+ """
33
+
34
+ _reference: ClassVar[Reference] = Reference(
35
+ title="OpenAPI Specification v3.1.1",
36
+ section="Runtime Expressions",
37
+ url="https://spec.openapis.org/oas/v3.1.1.html#runtime-expressions",
38
+ )
39
+
40
+ def __init__(self, value: str):
41
+ """
42
+ Initialize a RunTimeExpression instance.
43
+
44
+ Args:
45
+ value: The runtime expression to validate
46
+ """
47
+
48
+ try:
49
+ oas.Rule("expression").parse_all(value)
50
+ except ParseError as e:
51
+ raise AmatiValueError(
52
+ f"{value} is not a valid runtime expression",
53
+ reference=self._reference,
54
+ ) from e
55
+
56
+
57
+ class OpenAPI(_Str):
58
+ """
59
+ Represents an OpenAPI version string.s
60
+ """
61
+
62
+ _reference: ClassVar[Reference] = Reference(
63
+ title="OpenAPI Initiative Publications",
64
+ url="https://spec.openapis.org/#openapi-specification",
65
+ section="OpenAPI Specification ",
66
+ )
67
+
68
+ def __init__(self, value: str):
69
+ """
70
+ Initialize an OpenAPI instance.
71
+
72
+ Args:
73
+ value: The OpenAPI version string to validate
74
+ """
75
+ if value not in OPENAPI_VERSIONS:
76
+ raise AmatiValueError(
77
+ f"{value} is not a valid OpenAPI version",
78
+ reference=self._reference,
79
+ )
@@ -0,0 +1,92 @@
1
+ """
2
+ Validates the idenfitier and licences from the System Package Data
3
+ Exchange (SPDX) licence list.
4
+ """
5
+
6
+ import json
7
+ import pathlib
8
+
9
+ from amati import AmatiValueError, Reference
10
+ from amati.fields import Str as _Str
11
+ from amati.fields.uri import URI
12
+
13
+ reference = Reference(
14
+ title="SPDX License List",
15
+ url="https://spdx.org/licenses/",
16
+ )
17
+
18
+
19
+ DATA_DIRECTORY = pathlib.Path(__file__).parent.parent.resolve() / "data"
20
+
21
+ with open(DATA_DIRECTORY / "spdx-licences.json", "r", encoding="utf-8") as f:
22
+ data = json.loads(f.read())
23
+
24
+ # `seeAlso` is the list of URLs associated with each licence
25
+ VALID_LICENCES: dict[str, list[str]] = {
26
+ licence["licenseId"]: licence["seeAlso"] for licence in data["licenses"]
27
+ }
28
+ VALID_URLS: list[str] = [url for urls in VALID_LICENCES.values() for url in urls]
29
+
30
+
31
+ class SPDXIdentifier(_Str):
32
+ """
33
+ A class representing a valid SPDX license identifier.
34
+
35
+ This class validates that a string value is a registered SPDX license identifier
36
+ according to the official SPDX license list. It inherits from _Str to maintain
37
+ compatibility with string operations while adding SPDX-specific validation.
38
+
39
+ SPDX identifiers are standardized short-form identifiers for open source licenses,
40
+ such as "MIT", "Apache-2.0", or "GPL-3.0-only".
41
+
42
+ Attributes:
43
+ Inherits all attributes from _Str
44
+
45
+ Example:
46
+ >>> license_id = SPDXIdentifier("MIT")
47
+ >>> str(license_id)
48
+ 'MIT'
49
+ >>> SPDXIdentifier("InvalidLicense")
50
+ Traceback (most recent call last):
51
+ amati.AmatiValueError: message
52
+ """
53
+
54
+ def __init__(self, value: str):
55
+
56
+ if value not in VALID_LICENCES:
57
+ raise AmatiValueError(
58
+ f"{value} is not a valid SPDX licence identifier", reference=reference
59
+ )
60
+
61
+
62
+ class SPDXURL(URI): # pylint: disable=invalid-name
63
+ """
64
+ A class representing a valid SPDX license URL.
65
+
66
+ This class validates that a URI is associated with an SPDX license in the official
67
+ SPDX license list. It inherits from URI to maintain compatibility with URI
68
+ validation and operations while adding SPDX-specific validation.
69
+
70
+ SPDX license URLs are the official reference URLs for licenses in the SPDX registry,
71
+ typically pointing to the canonical text of the license.
72
+
73
+ Attributes:
74
+ Inherits all attributes from URI
75
+
76
+ Example:
77
+ >>> license_url = SPDXURL("https://www.apache.org/licenses/LICENSE-2.0")
78
+ >>> license_url.scheme
79
+ 'https'
80
+ >>> SPDXURL("https://example.com")
81
+ Traceback (most recent call last):
82
+ amati.AmatiValueError: message
83
+ """
84
+
85
+ def __init__(self, value: str):
86
+
87
+ super().__init__(value)
88
+
89
+ if value not in VALID_URLS:
90
+ raise AmatiValueError(
91
+ f"{value} is not associated with any identifier.", reference=reference
92
+ )