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/__init__.py +14 -0
- amati/_resolve_forward_references.py +185 -0
- amati/amati.py +143 -0
- amati/data/http-status-codes.json +1 -0
- amati/data/iso9110.json +1 -0
- amati/data/media-types.json +1 -0
- amati/data/schemes.json +1 -0
- amati/data/spdx-licences.json +1 -0
- amati/data/tlds.json +1 -0
- amati/exceptions.py +26 -0
- amati/fields/__init__.py +15 -0
- amati/fields/_custom_types.py +71 -0
- amati/fields/commonmark.py +9 -0
- amati/fields/email.py +27 -0
- amati/fields/http_status_codes.py +95 -0
- amati/fields/iso9110.py +61 -0
- amati/fields/json.py +13 -0
- amati/fields/media.py +100 -0
- amati/fields/oas.py +79 -0
- amati/fields/spdx_licences.py +92 -0
- amati/fields/uri.py +342 -0
- amati/file_handler.py +155 -0
- amati/grammars/oas.py +45 -0
- amati/grammars/rfc6901.py +26 -0
- amati/grammars/rfc7159.py +65 -0
- amati/logging.py +57 -0
- amati/model_validators.py +438 -0
- amati/references.py +33 -0
- amati/validators/__init__.py +0 -0
- amati/validators/generic.py +133 -0
- amati/validators/oas304.py +1031 -0
- amati/validators/oas311.py +615 -0
- amati-0.1.0.dist-info/METADATA +89 -0
- amati-0.1.0.dist-info/RECORD +37 -0
- amati-0.1.0.dist-info/WHEEL +4 -0
- amati-0.1.0.dist-info/entry_points.txt +2 -0
- amati-0.1.0.dist-info/licenses/LICENSE +21 -0
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
|
amati/fields/__init__.py
ADDED
@@ -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)
|
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
|
amati/fields/iso9110.py
ADDED
@@ -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
|
+
)
|